chore: 添加静态资源文件和版本配置文件
添加大量图片、字体、音频等静态资源文件,包括用户界面图片、模板文件和安装界面素材 添加系统版本配置文件(.version)和常量定义文件(.constant) 更新供应商依赖文件,包括Symfony VarDumper组件和相关许可证文件 添加验证码配置文件(captcha.php)和.gitignore规则
This commit is contained in:
392
app/services/activity/StoreActivityServices.php
Normal file
392
app/services/activity/StoreActivityServices.php
Normal file
@@ -0,0 +1,392 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity;
|
||||
|
||||
|
||||
use app\dao\activity\StoreActivityDao;
|
||||
use app\services\activity\seckill\StoreSeckillServices;
|
||||
use app\services\activity\seckill\StoreSeckillTimeServices;
|
||||
use app\services\BaseServices;
|
||||
use app\services\product\product\StoreDescriptionServices;
|
||||
use app\services\product\product\StoreProductServices;
|
||||
use app\services\product\sku\StoreProductAttrResultServices;
|
||||
use app\services\product\sku\StoreProductAttrServices;
|
||||
use app\services\product\sku\StoreProductAttrValueServices;
|
||||
use app\services\store\SystemStoreServices;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use crmeb\services\CacheService;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* 活动
|
||||
* Class StoreActivityServices
|
||||
* @package app\services\activity
|
||||
* @mixin StoreActivityDao
|
||||
*/
|
||||
class StoreActivityServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public array $typeName = [
|
||||
1 => '秒杀',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var StoreActivityDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreActivityDao $dao;
|
||||
|
||||
|
||||
/**
|
||||
* 活动列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function systemPage(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getList($where, '*', $page, $limit, ['seckill' => function ($query) {
|
||||
$query->field('id,activity_id');
|
||||
}]);
|
||||
$count = $this->dao->count($where);
|
||||
/** @var StoreSeckillTimeServices $seckillTimeServices */
|
||||
$seckillTimeServices = app()->make(StoreSeckillTimeServices::class);
|
||||
$timeList = $seckillTimeServices->time_list();
|
||||
if ($timeList) {
|
||||
$timeList = array_combine(array_column($timeList, 'id'), $timeList);
|
||||
}
|
||||
$ids = [];
|
||||
foreach ($list as &$item) {
|
||||
$item['product_count'] = count($item['seckill']);
|
||||
$item['time_id'] = is_string($item['time_id']) ? explode(',', $item['time_id']) : $item['time_id'];
|
||||
$item['time_list'] = [];
|
||||
foreach ($item['time_id'] as $time_id) {
|
||||
if (isset($timeList[$time_id])) $item['time_list'][] = $timeList[$time_id];
|
||||
}
|
||||
if ($item['status']) {
|
||||
if ($item['start_day'] > time()) {
|
||||
$item['start_name'] = '未开始';
|
||||
} else if (bcadd((string)$item['end_day'], '86400') < time()) {
|
||||
$item['start_name'] = '已结束';
|
||||
$ids[] = $item['id'];
|
||||
$item['status'] = 0;
|
||||
} else if (bcadd((string)$item['end_day'], '86400') > time() && $item['start_day'] < time()) {
|
||||
$item['start_name'] = '进行中';
|
||||
}
|
||||
} else {
|
||||
$item['start_name'] = '已结束';
|
||||
}
|
||||
switch ($item['type']) {
|
||||
case 1://秒杀
|
||||
$item['start_time'] = $item['start_time'] ? substr_replace($item['start_time'], ':', 2, 0) : '';
|
||||
$item['end_time'] = $item['start_time'] ? substr_replace($item['end_time'], ':', 2, 0) : '';
|
||||
break;
|
||||
}
|
||||
$item['start_day'] = date('Y-m-d', $item['start_day']);
|
||||
$item['end_day'] = date('Y-m-d', $item['end_day']);
|
||||
// $item['add_time'] = $item['add_time'] ? date('Y-m-d H:i:s', $item['add_time']) : '';
|
||||
}
|
||||
if ($where['type'] == 1) {
|
||||
$ids = array_unique($ids);
|
||||
$this->dao->update([['id', 'in', $ids]], ['status' => 0]);
|
||||
foreach($ids as $id) {
|
||||
/** @var StoreSeckillServices $storeSeckillServices */
|
||||
$storeSeckillServices = app()->make(StoreSeckillServices::class);
|
||||
$seckillIds = $storeSeckillServices->getActivitySeckillIds(['activity_id' => $id]);
|
||||
if (!empty($seckillIds)) {
|
||||
foreach ($seckillIds as $seckillId) {
|
||||
$storeSeckillServices->update($seckillId, ['status' => 0]);
|
||||
//修改状态同步缓存
|
||||
$this->cacheSaveValue($seckillId, 'status', 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一条活动信息
|
||||
* @param int $id
|
||||
* @param array $field
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getInfo(int $id, array $field = ['*'])
|
||||
{
|
||||
$info = $this->dao->get($id, $field);
|
||||
if (!$info) {
|
||||
throw new AdminException('数据不存在');
|
||||
}
|
||||
$info = $info->toArray();
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一条秒杀活动
|
||||
* @param int $id
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getSeckillInfo(int $id)
|
||||
{
|
||||
$info = $this->getInfo($id);
|
||||
/** @var StoreSeckillServices $seckillServices */
|
||||
$seckillServices = app()->make(StoreSeckillServices::class);
|
||||
$seckill = $seckillServices->getList(['activity_id' => $id, 'is_del' => 0], 0, 0, ['attrValue']);
|
||||
$info['section_data'] = [date('Y-m-d', $info['start_day']), date('Y-m-d', $info['end_day'])];
|
||||
$productList = [];
|
||||
if ($seckill) {
|
||||
/** @var StoreProductServices $productServices */
|
||||
$productServices = app()->make(StoreProductServices::class);
|
||||
$productList = $productServices->searchList(['id' => array_column($seckill, 'product_id'), 'is_del' => 0, 'is_verify' => 1]);
|
||||
$productList = $productList['list'] ?? [];
|
||||
$seckill = array_combine(array_column($seckill, 'product_id'), $seckill);
|
||||
//放入秒杀商品价格
|
||||
foreach ($productList as &$product) {
|
||||
$seckillInfo = $seckill[$product['id']] ?? [];
|
||||
$attrValue = $product['attrValue'] ?? [];
|
||||
if ($seckillInfo && $attrValue) {
|
||||
$product['status'] = $seckillInfo['status'];
|
||||
$seckillAttrValue = $seckillInfo['attrValue'] ?? [];
|
||||
if ($seckillAttrValue) {
|
||||
$seckillAttrValue = array_combine(array_column($seckillAttrValue, 'suk'), $seckillAttrValue);
|
||||
foreach ($attrValue as &$value) {
|
||||
$value['status'] = 0;
|
||||
if (isset($seckillAttrValue[$value['suk']])) {
|
||||
$value['status'] = 1;
|
||||
}
|
||||
$value['quota'] = $seckillAttrValue[$value['suk']]['quota'] ?? 0;
|
||||
$value['quota_show'] = $seckillAttrValue[$value['suk']]['quota_show'] ?? 0;
|
||||
$value['price'] = $seckillAttrValue[$value['suk']]['price'] ?? 0;
|
||||
$value['cost'] = $seckillAttrValue[$value['suk']]['cost'] ?? 0;
|
||||
$value['ot_price'] = $seckillAttrValue[$value['suk']]['ot_price'] ?? 0;
|
||||
}
|
||||
$product['attrValue'] = $attrValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$info['productList'] = $productList;
|
||||
//适用门店
|
||||
$info['stores'] = [];
|
||||
if (isset($info['applicable_type']) && ($info['applicable_type'] == 1 || ($info['applicable_type'] == 2 && isset($info['applicable_store_id']) && $info['applicable_store_id']))) {//查询门店信息
|
||||
$where = ['is_del' => 0];
|
||||
if ($info['applicable_type'] == 2) {
|
||||
$store_ids = is_array($info['applicable_store_id']) ? $info['applicable_store_id'] : explode(',', $info['applicable_store_id']);
|
||||
$where['id'] = $store_ids;
|
||||
}
|
||||
$field = ['id', 'name', 'phone', 'address', 'detailed_address', 'image', 'is_show', 'day_time', 'day_start', 'day_end'];
|
||||
/** @var SystemStoreServices $storeServices */
|
||||
$storeServices = app()->make(SystemStoreServices::class);
|
||||
$storeData = $storeServices->getStoreList($where, $field, '', '', 0, ['categoryName']);
|
||||
$info['stores'] = $storeData['list'] ?? [];
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 保存活动信息
|
||||
* @param int $id
|
||||
* @param array $data
|
||||
* @param array $expend
|
||||
* @param int $type
|
||||
* @return bool
|
||||
*/
|
||||
public function saveData(int $id, array $data, array $expend, int $type = 1)
|
||||
{
|
||||
if (!$data || !$expend) {
|
||||
throw new AdminException('缺少活动数据');
|
||||
}
|
||||
$section_data = $data['section_data'];
|
||||
$data['start_day'] = strtotime($section_data[0]);
|
||||
$data['end_day'] = strtotime($section_data[1]);
|
||||
unset($data['section_data']);
|
||||
$this->transaction(function () use ($id, $type, $data, $section_data, $expend) {
|
||||
if ($id) {
|
||||
$this->getInfo($id);
|
||||
$this->dao->update($id, $data);
|
||||
$this->clearAcivityAttr($id, array_column($data['seckill_ids'], 'id'), $type);
|
||||
} else {
|
||||
$data['add_time'] = time();
|
||||
$res = $this->dao->save($data);
|
||||
$id = (int)$res->id;
|
||||
}
|
||||
//处理活动商品
|
||||
switch ($type) {
|
||||
case 1:
|
||||
$data['section_data'] = $section_data;
|
||||
$this->saveActivitySeckill($id, $expend, $data);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存秒杀商品
|
||||
* @param int $id
|
||||
* @param array $data
|
||||
* @param array $activity_data
|
||||
* @return bool
|
||||
*/
|
||||
public function saveActivitySeckill(int $id, array $data, array $activity_data)
|
||||
{
|
||||
$productIds = array_column($data, 'id');
|
||||
/** @var StoreProductServices $productServices */
|
||||
$productServices = app()->make(StoreProductServices::class);
|
||||
$productList = $productServices->searchList(['id' => $productIds, 'is_del' => 0, 'is_verify' => 1]);
|
||||
$productList = $productList['list'] ?? [];
|
||||
//放入秒杀商品价格
|
||||
/** @var StoreSeckillServices $seckillServices */
|
||||
$seckillServices = app()->make(StoreSeckillServices::class);
|
||||
$data = array_combine($productIds, $data);
|
||||
foreach ($productList as &$product) {
|
||||
$attrInfo = $productServices->getProductRules((int)$product['id'], 0);
|
||||
$seckillData = [];
|
||||
$seckillData['activity_id'] = $id;
|
||||
$seckillData['product_id'] = $product['id'] ?? 0;
|
||||
$seckillData['title'] = $product['store_name'] ?? '';
|
||||
$seckillData['info'] = $product['store_info'] ?? '';
|
||||
$seckillData['unit_name'] = $product['unit_name'] ?? '';
|
||||
$seckillData['section_time'] = $activity_data['section_data'];
|
||||
$seckillData['images'] = $product['slider_image'] ?? '';
|
||||
$seckillData['description'] = $product['description'] ?? '';
|
||||
$seckillData['status'] = $data[$product['id']]['status'] ?? 1;
|
||||
$seckillData['time_id'] = $activity_data['time_id'] ?? [];
|
||||
$seckillData['num'] = $activity_data['num'] ?? 0;
|
||||
$seckillData['once_num'] = $activity_data['once_num'] ?? 0;
|
||||
$seckillData['delivery_type'] = $product['delivery_type'] ?? '';
|
||||
$seckillData['temp_id'] = $product['temp_id'];//运费设置
|
||||
$seckillData['freight'] = $product['freight'];//运费设置
|
||||
$seckillData['postage'] = $product['postage'];//邮费
|
||||
$seckillData['custom_form'] = $product['custom_form'];//自定义表单
|
||||
$seckillData['system_form_id'] = $product['system_form_id'];//系统表单ID
|
||||
$seckillData['product_type'] = $product['product_type'];//商品类型
|
||||
$seckillData['applicable_type'] = $activity_data['applicable_type'];//适用门店类型
|
||||
$seckillData['applicable_store_id'] = $activity_data['applicable_store_id'];//适用门店IDS
|
||||
$seckillData['is_commission'] = $activity_data['is_commission'];//适用门店IDS
|
||||
|
||||
$seckillData['items'] = $attrInfo['items'];
|
||||
$attrs = $attrInfo['attrs'] ?? [];
|
||||
if ($attrs) {
|
||||
$seckillAttrValue = $data[$product['id']]['attrValue'] ?? [];
|
||||
if (!$seckillAttrValue) {
|
||||
throw new AdminException('请选择商品规格');
|
||||
}
|
||||
foreach ($seckillAttrValue as $sattr) {
|
||||
if (!isset($sattr['status']) || !$sattr['status']) {//不参与的规格不验证
|
||||
continue;
|
||||
}
|
||||
if (!isset($sattr['price']) || !$sattr['price']) {
|
||||
throw new AdminException('请填写商品(' . $product['store_name'] . ')活动价');
|
||||
}
|
||||
// if (!isset($sattr['quota']) || !$sattr['quota']) {
|
||||
// throw new AdminException('请填写商品('.$product['store_name'] .')限量');
|
||||
// }
|
||||
}
|
||||
$seckillAttrValue = array_combine(array_column($seckillAttrValue, 'suk'), $seckillAttrValue);
|
||||
foreach ($attrs as $attr) {
|
||||
$sku = implode(',', $attr['detail']);
|
||||
if (!isset($seckillAttrValue[$sku])) {
|
||||
throw new AdminException('请重新选择商品规格');
|
||||
}
|
||||
if (!isset($seckillAttrValue[$sku]['status']) || !$seckillAttrValue[$sku]['status']) {
|
||||
continue;
|
||||
}
|
||||
if (($seckillAttrValue[$sku]['quota'] ?? 0) > $attr['stock']) {
|
||||
throw new AdminException('限量超过了商品库存');
|
||||
}
|
||||
$attr['quota'] = $attr['quota_show'] = $seckillAttrValue[$sku]['quota'] ?? 0;
|
||||
$attr['price'] = $seckillAttrValue[$sku]['price'] ?? 0;
|
||||
$attr['cost'] = $seckillAttrValue[$sku]['cost'] ?? 0;
|
||||
$attr['ot_price'] = $seckillAttrValue[$sku]['ot_price'] ?? 0;
|
||||
$seckillData['attrs'][] = $attr;
|
||||
}
|
||||
}
|
||||
$seckillId = $seckillServices->value(['activity_id' => $id, 'product_id' => $seckillData['product_id']], 'id') ?? 0;
|
||||
$seckillServices->saveData($seckillId, $seckillData);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空活动商品数据
|
||||
* @param int $id
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function clearAcivityAttr(int $id, array $productIds = [], int $type = 1)
|
||||
{
|
||||
/** @var StoreSeckillServices $seckillServices */
|
||||
$seckillServices = app()->make(StoreSeckillServices::class);
|
||||
$seckill = $seckillServices->getList(['activity_id' => $id, 'is_del' => 0]);
|
||||
$seckillIds = [];
|
||||
foreach ($seckill as $item) {
|
||||
if (!in_array($item['product_id'], $productIds)) {
|
||||
$seckillIds[] = $item['id'];
|
||||
}
|
||||
}
|
||||
if (count($seckillIds)) {
|
||||
/** @var StoreProductAttrResultServices $storeProductAttrResultServices */
|
||||
$storeProductAttrResultServices = app()->make(StoreProductAttrResultServices::class);
|
||||
/** @var StoreDescriptionServices $storeDescriptionServices */
|
||||
$storeDescriptionServices = app()->make(StoreDescriptionServices::class);
|
||||
/** @var StoreProductAttrServices $storeProductAttrServices */
|
||||
$storeProductAttrServices = app()->make(StoreProductAttrServices::class);
|
||||
/** @var StoreProductAttrValueServices $storeProductAttrValueServices */
|
||||
$storeProductAttrValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
$where = ['product_id' => $seckillIds, 'type' => $type];
|
||||
$storeProductAttrResultServices->delete($where);
|
||||
$storeDescriptionServices->delete($where);
|
||||
$storeProductAttrServices->delete($where);
|
||||
$storeProductAttrValueServices->delete($where);
|
||||
$seckillServices->delete(['activity_id' => $id, 'is_del' => 0]);
|
||||
$seckillServices->cacheDelByIds($seckillIds);
|
||||
$seckillServices->cacheTag()->clear();
|
||||
}
|
||||
CacheService::redisHandler('product_attr')->clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 判断时间段是否存在秒杀活动
|
||||
* @param array $where
|
||||
* @param int $type
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DbException
|
||||
*/
|
||||
public function existenceActivity(array $where, int $type = 1): bool
|
||||
{
|
||||
$where['is_del'] = 0;
|
||||
if (!isset($where['type'])) $where['type'] = $type;
|
||||
return $this->dao->checkActivity($where);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\activityBackground;
|
||||
|
||||
use app\dao\activity\promotions\StorePromotionsDao;
|
||||
use app\services\activity\promotions\StorePromotionsAuxiliaryServices;
|
||||
use app\services\BaseServices;
|
||||
use app\services\product\brand\StoreBrandServices;
|
||||
use app\services\product\category\StoreProductCategoryServices;
|
||||
use app\services\product\label\StoreProductLabelServices;
|
||||
use app\services\product\product\StoreProductRelationServices;
|
||||
use app\services\product\product\StoreProductServices;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use \crmeb\traits\OptionTrait;
|
||||
use think\annotation\Inject;
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\DbException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
|
||||
/**
|
||||
* 活动背景图
|
||||
* Class ActivityBackgroundServices
|
||||
* @package app\services\activity\activityBackground
|
||||
* @mixin StorePromotionsDao
|
||||
*/
|
||||
class ActivityBackgroundServices extends BaseServices
|
||||
{
|
||||
use OptionTrait;
|
||||
|
||||
/**
|
||||
* 活动类型
|
||||
* @var string[]
|
||||
*/
|
||||
protected array $promotionsType = [
|
||||
1 => '限时折扣',
|
||||
2 => '第N件N折',
|
||||
3 => '满减满折',
|
||||
4 => '满送',
|
||||
5 => '活动背景图',
|
||||
6 => '活动背景',
|
||||
];
|
||||
|
||||
/**
|
||||
* 参与活动商品类型
|
||||
* @var string[]
|
||||
*/
|
||||
protected array $productPartakeType = [
|
||||
1 => '全部商品',
|
||||
2 => '指定商品参与',
|
||||
3 => '指定商品不参与',
|
||||
4 => '指定品牌参与',
|
||||
5 => '指定商品标签参与',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var StorePromotionsDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StorePromotionsDao $dao;
|
||||
|
||||
/**
|
||||
* 后台获取活动背景图列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function systemPage(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getList($where, '*', $page, $limit);
|
||||
$count = 0;
|
||||
if ($list) {
|
||||
/** @var StoreProductServices $storeProductServices */
|
||||
$storeProductServices = app()->make(StoreProductServices::class);
|
||||
/** @var StoreProductRelationServices $storeProductRelationServices */
|
||||
$storeProductRelationServices = app()->make(StoreProductRelationServices::class);
|
||||
/** @var StorePromotionsAuxiliaryServices $promotionsAuxiliaryServices */
|
||||
$promotionsAuxiliaryServices = app()->make(StorePromotionsAuxiliaryServices::class);
|
||||
foreach ($list as &$item) {
|
||||
if ($item['status']) {
|
||||
if ($item['start_time'] > time()) {
|
||||
$item['start_status'] = 0;
|
||||
$item['start_name'] = '未开始';
|
||||
} else if ($item['stop_time'] < time()) {
|
||||
$item['start_name'] = '已结束';
|
||||
$item['start_status'] = -1;
|
||||
} else if ($item['stop_time'] > time() && $item['start_time'] < time()) {
|
||||
$item['start_name'] = '进行中';
|
||||
$item['start_status'] = 1;
|
||||
}
|
||||
} else {
|
||||
$item['start_status'] = -1;
|
||||
$item['start_name'] = '已结束';
|
||||
}
|
||||
$item['start_time'] = $item['start_time'] ? date('Y-m-d H:i:s', $item['start_time']) : '';
|
||||
$item['stop_time'] = $item['stop_time'] ? date('Y-m-d H:i:s', $item['stop_time']) : '';
|
||||
$promotionsAuxiliaryData = $promotionsAuxiliaryServices->getPromotionsAuxiliaryCache($item['id']);
|
||||
switch ($item['product_partake_type']) {
|
||||
case 1://所有商品
|
||||
$item['product_count'] = $storeProductServices->count(['is_show' => 1, 'is_del' => 0, 'is_verify' => 1]);
|
||||
break;
|
||||
case 2://选中商品参与
|
||||
$product_ids = $promotionsAuxiliaryData;
|
||||
$item['product_count'] = $product_ids ? $storeProductServices->count(['is_show' => 1, 'is_del' => 0, 'id' => $product_ids, 'is_verify' => 1]) : 0;
|
||||
break;
|
||||
case 3:
|
||||
$item['product_count'] = 0;
|
||||
break;
|
||||
case 4://品牌
|
||||
$product_ids = $promotionsAuxiliaryData ? $storeProductRelationServices->getIdsByWhere(['type' => 2, 'relation_id' => $promotionsAuxiliaryData]) : [];
|
||||
$item['product_count'] = $product_ids ? $storeProductServices->count(['is_show' => 1, 'is_del' => 0, 'id' => $product_ids, 'is_verify' => 1]) : 0;
|
||||
break;
|
||||
case 5://商品标签
|
||||
$product_ids = $promotionsAuxiliaryData ? $storeProductRelationServices->getIdsByWhere(['type' => 3, 'relation_id' => $promotionsAuxiliaryData]) : [];
|
||||
$item['product_count'] = $product_ids ? $storeProductServices->count(['is_show' => 1, 'is_del' => 0, 'id' => $product_ids, 'is_verify' => 1]) : 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$count = $this->dao->count($where);
|
||||
}
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取活动背景图想你去那个
|
||||
* @param int $id
|
||||
* @return array
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function getInfo(int $id)
|
||||
{
|
||||
$info = $this->dao->get($id, ['*'], ['products' => function ($query) {
|
||||
$query->field('promotions_id,product_id,unique')->with(['productInfo']);
|
||||
}, 'brands' => function ($query) {
|
||||
$query->field('promotions_id,brand_id')->with(['brandInfo' => function ($q) {
|
||||
$q->field('id,brand_name');
|
||||
}]);
|
||||
}, 'productLabels' => function ($query) {
|
||||
$query->field('promotions_id,store_label_id')->with(['productLabelInfo' => function ($q) {
|
||||
$q->field('id,label_name');
|
||||
}]);
|
||||
}]);
|
||||
if (!$info) {
|
||||
throw new AdminException('数据不存在');
|
||||
}
|
||||
$info = $info->toArray();
|
||||
$info['start_time'] = $info['start_time'] ? date('Y-m-d H:i:s', $info['start_time']) : '';
|
||||
$info['stop_time'] = $info['stop_time'] ? date('Y-m-d H:i:s', $info['stop_time']) : '';
|
||||
$products = [];
|
||||
if (isset($info['products']) && $info['products']) {
|
||||
foreach ($info['products'] as $item) {
|
||||
$product = is_object($item) ? $item->toArray() : $item;
|
||||
$product = array_merge($product, $product['productInfo'] ?? []);
|
||||
unset($product['productInfo']);
|
||||
$products[] = $product;
|
||||
}
|
||||
if ($products) {
|
||||
$cateIds = implode(',', array_column($products, 'cate_id'));
|
||||
/** @var StoreProductCategoryServices $categoryService */
|
||||
$categoryService = app()->make(StoreProductCategoryServices::class);
|
||||
$cateList = $categoryService->getCateParentAndChildName($cateIds);
|
||||
foreach ($products as $key => &$item) {
|
||||
$item['cate_name'] = '';
|
||||
if (isset($item['cate_id']) && $item['cate_id']) {
|
||||
$cate_ids = explode(',', $item['cate_id']);
|
||||
$cate_name = $categoryService->getCateName($cate_ids, $cateList);
|
||||
if ($cate_name) {
|
||||
$item['cate_name'] = is_array($cate_name) ? implode(',', $cate_name) : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$info['products'] = $products;
|
||||
$info['brand_id'] = isset($info['brands']) && $info['brands'] ? array_column($info['brands'], 'brand_id') : [];
|
||||
$info['store_label_id'] = [];
|
||||
if (isset($info['productLabels']) && $info['productLabels']) {
|
||||
foreach ($info['productLabels'] as $label) {
|
||||
if (isset($label['productLabelInfo']) && $label['productLabelInfo']) {
|
||||
$info['store_label_id'][] = $label['productLabelInfo'];
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($info['brands'], $info['productLabels']);
|
||||
return $info;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 保存活动背景图
|
||||
* @param int $id
|
||||
* @param array $data
|
||||
* @return bool
|
||||
*/
|
||||
public function saveData(int $id, array $data)
|
||||
{
|
||||
if (!$data['section_time'] || count($data['section_time']) != 2) {
|
||||
throw new AdminException('请选择活动时间');
|
||||
}
|
||||
[$start_time, $end_time] = $data['section_time'];
|
||||
if (strtotime($end_time) < time()) {
|
||||
throw new AdminException('活动结束时间不能小于当前时间');
|
||||
}
|
||||
if ($id) {
|
||||
$info = $this->dao->get((int)$id);
|
||||
if (!$info) {
|
||||
throw new AdminException('数据不存在');
|
||||
}
|
||||
}
|
||||
$data['start_time'] = strtotime($start_time);
|
||||
$data['stop_time'] = strtotime($end_time);
|
||||
$promotionsAuxiliaryData = [];
|
||||
switch ($data['product_partake_type']) {
|
||||
case 1://全部
|
||||
$data['product_id'] = [];
|
||||
break;
|
||||
case 2://指定ID参与
|
||||
case 3://指定ID不参与
|
||||
/** @var StoreProductServices $storeProductServices */
|
||||
$storeProductServices = app()->make(StoreProductServices::class);
|
||||
$count = $storeProductServices->count(['is_show' => 1, 'is_del' => 0, 'id' => $data['product_id']]);
|
||||
$productCount = count(array_unique($data['product_id']));
|
||||
if ($count != $productCount) {
|
||||
throw new AdminException('选择商品中有已下架或移入回收站');
|
||||
}
|
||||
$promotionsAuxiliaryData['product_id'] = $data['product_id'];
|
||||
break;
|
||||
case 4://指定品牌
|
||||
$data['brand_id'] = array_unique($data['brand_id']);
|
||||
/** @var StoreBrandServices $storeBrandServices */
|
||||
$storeBrandServices = app()->make(StoreBrandServices::class);
|
||||
$brandCount = $storeBrandServices->count(['is_show' => 1, 'is_del' => 0, 'id' => $data['brand_id']]);
|
||||
if (count($data['brand_id']) != $brandCount) {
|
||||
throw new AdminException('选择商品品牌中有已下架或删除的');
|
||||
}
|
||||
$promotionsAuxiliaryData['brand_id'] = $data['brand_id'];
|
||||
break;
|
||||
case 5://指定商品标签
|
||||
$data['store_label_id'] = array_unique($data['store_label_id']);
|
||||
/** @var StoreProductLabelServices $storeProductLabelServices */
|
||||
$storeProductLabelServices = app()->make(StoreProductLabelServices::class);
|
||||
$labelCount = $storeProductLabelServices->count(['id' => $data['store_label_id']]);
|
||||
if (count($data['store_label_id']) != $labelCount) {
|
||||
throw new ValidateException('选择商品标签中有已下架或删除的');
|
||||
}
|
||||
$promotionsAuxiliaryData['store_label_id'] = $data['store_label_id'];
|
||||
break;
|
||||
default:
|
||||
throw new ValidateException('暂不支持该类型商品');
|
||||
break;
|
||||
}
|
||||
unset($data['section_time'], $data['promotions']);
|
||||
$this->transaction(function () use ($id, $data, $promotionsAuxiliaryData) {
|
||||
$time = time();
|
||||
$data['update_time'] = $time;
|
||||
if ($id) {
|
||||
$this->dao->update($id, $data);
|
||||
} else {
|
||||
$data['add_time'] = $time;
|
||||
$res = $this->dao->save($data);
|
||||
$id = $res->id;
|
||||
}
|
||||
/** @var StorePromotionsAuxiliaryServices $storePromotionsAuxiliaryServices */
|
||||
$storePromotionsAuxiliaryServices = app()->make(StorePromotionsAuxiliaryServices::class);
|
||||
//保存关联数据
|
||||
$storePromotionsAuxiliaryServices->savePromotionsRelation((int)$id, (int)$data['product_partake_type'], $promotionsAuxiliaryData, [], [], false);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
284
app/services/activity/activityFrame/ActivityFrameServices.php
Normal file
284
app/services/activity/activityFrame/ActivityFrameServices.php
Normal file
@@ -0,0 +1,284 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\activityFrame;
|
||||
|
||||
use app\dao\activity\promotions\StorePromotionsDao;
|
||||
use app\services\activity\promotions\StorePromotionsAuxiliaryServices;
|
||||
use app\services\BaseServices;
|
||||
use app\services\product\brand\StoreBrandServices;
|
||||
use app\services\product\category\StoreProductCategoryServices;
|
||||
use app\services\product\label\StoreProductLabelServices;
|
||||
use app\services\product\product\StoreProductRelationServices;
|
||||
use app\services\product\product\StoreProductServices;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
use \crmeb\traits\OptionTrait;
|
||||
|
||||
|
||||
/**
|
||||
* 活动边框
|
||||
* Class ActivityFrameServices
|
||||
* @package app\services\activity\activityFrame
|
||||
* @mixin StorePromotionsDao
|
||||
*/
|
||||
class ActivityFrameServices extends BaseServices
|
||||
{
|
||||
use OptionTrait;
|
||||
|
||||
/**
|
||||
* 活动类型
|
||||
* @var string[]
|
||||
*/
|
||||
protected array $promotionsType = [
|
||||
1 => '限时折扣',
|
||||
2 => '第N件N折',
|
||||
3 => '满减满折',
|
||||
4 => '满送',
|
||||
5 => '活动边框',
|
||||
6 => '活动背景',
|
||||
];
|
||||
|
||||
/**
|
||||
* 参与活动商品类型
|
||||
* @var string[]
|
||||
*/
|
||||
protected array $productPartakeType = [
|
||||
1 => '全部商品',
|
||||
2 => '指定商品参与',
|
||||
3 => '指定商品不参与',
|
||||
4 => '指定品牌参与',
|
||||
5 => '指定商品标签参与',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var StorePromotionsDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StorePromotionsDao $dao;
|
||||
|
||||
/**
|
||||
* 后台获取活动边框列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function systemPage(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getList($where, '*', $page, $limit);
|
||||
$count = 0;
|
||||
if ($list) {
|
||||
/** @var StoreProductServices $storeProductServices */
|
||||
$storeProductServices = app()->make(StoreProductServices::class);
|
||||
/** @var StoreProductRelationServices $storeProductRelationServices */
|
||||
$storeProductRelationServices = app()->make(StoreProductRelationServices::class);
|
||||
/** @var StorePromotionsAuxiliaryServices $promotionsAuxiliaryServices */
|
||||
$promotionsAuxiliaryServices = app()->make(StorePromotionsAuxiliaryServices::class);
|
||||
foreach ($list as &$item) {
|
||||
if ($item['status']) {
|
||||
if ($item['start_time'] > time()) {
|
||||
$item['start_status'] = 0;
|
||||
$item['start_name'] = '未开始';
|
||||
} else if ($item['stop_time'] < time()) {
|
||||
$item['start_name'] = '已结束';
|
||||
$item['start_status'] = -1;
|
||||
} else if ($item['stop_time'] > time() && $item['start_time'] < time()) {
|
||||
$item['start_name'] = '进行中';
|
||||
$item['start_status'] = 1;
|
||||
}
|
||||
} else {
|
||||
$item['start_status'] = -1;
|
||||
$item['start_name'] = '已结束';
|
||||
}
|
||||
$item['start_time'] = $item['start_time'] ? date('Y-m-d H:i:s', $item['start_time']) : '';
|
||||
$item['stop_time'] = $item['stop_time'] ? date('Y-m-d H:i:s', $item['stop_time']) : '';
|
||||
$promotionsAuxiliaryData = $promotionsAuxiliaryServices->getPromotionsAuxiliaryCache($item['id']);
|
||||
switch ($item['product_partake_type']) {
|
||||
case 1://所有商品
|
||||
$item['product_count'] = $storeProductServices->count(['is_show' => 1, 'is_del' => 0, 'is_verify' => 1]);
|
||||
break;
|
||||
case 2://选中商品参与
|
||||
$product_ids = $promotionsAuxiliaryData;
|
||||
$item['product_count'] = $product_ids ? $storeProductServices->count(['is_show' => 1, 'is_del' => 0, 'id' => $product_ids, 'is_verify' => 1]) : 0;
|
||||
break;
|
||||
case 3:
|
||||
$item['product_count'] = 0;
|
||||
break;
|
||||
case 4://品牌
|
||||
$product_ids = $promotionsAuxiliaryData ? $storeProductRelationServices->getIdsByWhere(['type' => 2, 'relation_id' => $promotionsAuxiliaryData]) : [];
|
||||
$item['product_count'] = $product_ids ? $storeProductServices->count(['is_show' => 1, 'is_del' => 0, 'id' => $product_ids, 'is_verify' => 1]) : 0;
|
||||
break;
|
||||
case 5://商品标签
|
||||
$product_ids = $promotionsAuxiliaryData ? $storeProductRelationServices->getIdsByWhere(['type' => 3, 'relation_id' => $promotionsAuxiliaryData]) : [];
|
||||
$item['product_count'] = $product_ids ? $storeProductServices->count(['is_show' => 1, 'is_del' => 0, 'id' => $product_ids, 'is_verify' => 1]) : 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$count = $this->dao->count($where);
|
||||
}
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取活动边框想你去那个
|
||||
* @param int $id
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getInfo(int $id)
|
||||
{
|
||||
$info = $this->dao->get($id, ['*'], ['products' => function ($query) {
|
||||
$query->field('promotions_id,product_id,unique')->with(['productInfo']);
|
||||
}, 'brands' => function ($query) {
|
||||
$query->field('promotions_id,brand_id')->with(['brandInfo' => function ($q) {
|
||||
$q->field('id,brand_name');
|
||||
}]);
|
||||
}, 'productLabels' => function ($query) {
|
||||
$query->field('promotions_id,store_label_id')->with(['productLabelInfo' => function ($q) {
|
||||
$q->field('id,label_name');
|
||||
}]);
|
||||
}]);
|
||||
if (!$info) {
|
||||
throw new AdminException('数据不存在');
|
||||
}
|
||||
$info = $info->toArray();
|
||||
$info['start_time'] = $info['start_time'] ? date('Y-m-d H:i:s', $info['start_time']) : '';
|
||||
$info['stop_time'] = $info['stop_time'] ? date('Y-m-d H:i:s', $info['stop_time']) : '';
|
||||
$products = [];
|
||||
if (isset($info['products']) && $info['products']) {
|
||||
foreach ($info['products'] as $item) {
|
||||
$product = is_object($item) ? $item->toArray() : $item;
|
||||
$product = array_merge($product, $product['productInfo'] ?? []);
|
||||
unset($product['productInfo']);
|
||||
$products[] = $product;
|
||||
}
|
||||
if ($products) {
|
||||
$cateIds = implode(',', array_column($products, 'cate_id'));
|
||||
/** @var StoreProductCategoryServices $categoryService */
|
||||
$categoryService = app()->make(StoreProductCategoryServices::class);
|
||||
$cateList = $categoryService->getCateParentAndChildName($cateIds);
|
||||
foreach ($products as $key => &$item) {
|
||||
$item['cate_name'] = '';
|
||||
if (isset($item['cate_id']) && $item['cate_id']) {
|
||||
$cate_ids = explode(',', $item['cate_id']);
|
||||
$cate_name = $categoryService->getCateName($cate_ids, $cateList);
|
||||
if ($cate_name) {
|
||||
$item['cate_name'] = is_array($cate_name) ? implode(',', $cate_name) : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$info['products'] = $products;
|
||||
$info['brand_id'] = isset($info['brands']) && $info['brands'] ? array_column($info['brands'], 'brand_id') : [];
|
||||
$info['store_label_id'] = [];
|
||||
if (isset($info['productLabels']) && $info['productLabels']) {
|
||||
foreach ($info['productLabels'] as $label) {
|
||||
if (isset($label['productLabelInfo']) && $label['productLabelInfo']) {
|
||||
$info['store_label_id'][] = $label['productLabelInfo'];
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($info['brands'], $info['productLabels']);
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存活动边框
|
||||
* @param int $id
|
||||
* @param array $data
|
||||
* @return bool
|
||||
*/
|
||||
public function saveData(int $id, array $data)
|
||||
{
|
||||
if (!$data['section_time'] || count($data['section_time']) != 2) {
|
||||
throw new AdminException('请选择活动时间');
|
||||
}
|
||||
[$start_time, $end_time] = $data['section_time'];
|
||||
if (strtotime($end_time) < time()) {
|
||||
throw new AdminException('活动结束时间不能小于当前时间');
|
||||
}
|
||||
if ($id) {
|
||||
$info = $this->dao->get((int)$id);
|
||||
if (!$info) {
|
||||
throw new AdminException('数据不存在');
|
||||
}
|
||||
}
|
||||
$data['start_time'] = strtotime($start_time);
|
||||
$data['stop_time'] = strtotime($end_time);
|
||||
$promotionsAuxiliaryData = [];
|
||||
switch ($data['product_partake_type']) {
|
||||
case 1://全部
|
||||
$data['product_id'] = [];
|
||||
break;
|
||||
case 2://指定ID参与
|
||||
case 3://指定ID不参与
|
||||
/** @var StoreProductServices $storeProductServices */
|
||||
$storeProductServices = app()->make(StoreProductServices::class);
|
||||
$count = $storeProductServices->count(['is_show' => 1, 'is_del' => 0, 'id' => $data['product_id']]);
|
||||
$productCount = count(array_unique($data['product_id']));
|
||||
if ($count != $productCount) {
|
||||
throw new AdminException('选择商品中有已下架或移入回收站');
|
||||
}
|
||||
$promotionsAuxiliaryData['product_id'] = $data['product_id'];
|
||||
break;
|
||||
case 4://指定品牌
|
||||
$data['brand_id'] = array_unique($data['brand_id']);
|
||||
/** @var StoreBrandServices $storeBrandServices */
|
||||
$storeBrandServices = app()->make(StoreBrandServices::class);
|
||||
$brandCount = $storeBrandServices->count(['is_show' => 1, 'is_del' => 0, 'id' => $data['brand_id']]);
|
||||
if (count(array_unique($data['brand_id'])) != $brandCount) {
|
||||
throw new AdminException('选择商品品牌中有已下架或删除的');
|
||||
}
|
||||
$promotionsAuxiliaryData['brand_id'] = $data['brand_id'];
|
||||
break;
|
||||
case 5://指定商品标签
|
||||
$data['store_label_id'] = array_unique($data['store_label_id']);
|
||||
/** @var StoreProductLabelServices $storeProductLabelServices */
|
||||
$storeProductLabelServices = app()->make(StoreProductLabelServices::class);
|
||||
$labelCount = $storeProductLabelServices->count(['id' => $data['store_label_id']]);
|
||||
if (count(array_unique($data['store_label_id'])) != $labelCount) {
|
||||
throw new ValidateException('选择商品标签中有已下架或删除的');
|
||||
}
|
||||
$promotionsAuxiliaryData['store_label_id'] = $data['store_label_id'];
|
||||
break;
|
||||
default:
|
||||
throw new ValidateException('暂不支持该类型商品');
|
||||
break;
|
||||
}
|
||||
unset($data['section_time'], $data['promotions']);
|
||||
$this->transaction(function () use ($id, $data, $promotionsAuxiliaryData) {
|
||||
$time = time();
|
||||
$data['update_time'] = $time;
|
||||
if ($id) {
|
||||
$this->dao->update($id, $data);
|
||||
} else {
|
||||
$data['add_time'] = $time;
|
||||
$res = $this->dao->save($data);
|
||||
$id = $res->id;
|
||||
}
|
||||
/** @var StorePromotionsAuxiliaryServices $storePromotionsAuxiliaryServices */
|
||||
$storePromotionsAuxiliaryServices = app()->make(StorePromotionsAuxiliaryServices::class);
|
||||
//保存关联数据
|
||||
$storePromotionsAuxiliaryServices->savePromotionsRelation((int)$id, (int)$data['product_partake_type'], $promotionsAuxiliaryData, [], [], false);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
789
app/services/activity/bargain/StoreBargainServices.php
Normal file
789
app/services/activity/bargain/StoreBargainServices.php
Normal file
@@ -0,0 +1,789 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\bargain;
|
||||
|
||||
use app\dao\activity\bargain\StoreBargainDao;
|
||||
use app\jobs\activity\StoreBargainJob;
|
||||
use app\services\BaseServices;
|
||||
use app\services\order\StoreOrderServices;
|
||||
use app\services\other\QrcodeServices;
|
||||
use app\services\product\product\StoreDescriptionServices;
|
||||
use app\services\product\product\StoreProductServices;
|
||||
use app\services\product\sku\StoreProductAttrServices;
|
||||
use app\services\product\sku\StoreProductAttrValueServices;
|
||||
use app\services\user\UserServices;
|
||||
use app\jobs\product\ProductLogJob;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use crmeb\services\CacheService;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
/**
|
||||
* Class StoreBargainServices
|
||||
* @package app\services\activity\bargain
|
||||
* @mixin StoreBargainDao
|
||||
*/
|
||||
class StoreBargainServices extends BaseServices
|
||||
{
|
||||
|
||||
const DRNCCGFB = '$2y$10';
|
||||
|
||||
/**
|
||||
* 商品活动类型
|
||||
*/
|
||||
const TYPE = 3;
|
||||
|
||||
/**
|
||||
* @var StoreBargainDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreBargainDao $dao;
|
||||
|
||||
/**
|
||||
* @param array $productIds
|
||||
* @return mixed
|
||||
* @author 等风来
|
||||
* @email 136327134@qq.com
|
||||
* @date 2022/11/28
|
||||
*/
|
||||
public function getBargainIdsArrayCache(array $productIds)
|
||||
{
|
||||
return $this->dao->cacheTag()->remember(md5('Bargain_ids_' . json_encode($productIds)), function () use ($productIds) {
|
||||
return $this->dao->getBargainIdsArray($productIds, ['id']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断砍价商品是否开启
|
||||
* @param int $bargainId
|
||||
* @return int|string
|
||||
*/
|
||||
public function validBargain($bargainId = 0)
|
||||
{
|
||||
$where = [];
|
||||
$time = time();
|
||||
$where[] = ['is_del', '=', 0];
|
||||
$where[] = ['status', '=', 1];
|
||||
$where[] = ['start_time', '<', $time];
|
||||
$where[] = ['stop_time', '>', $time - 85400];
|
||||
if ($bargainId) $where[] = ['id', '=', $bargainId];
|
||||
return $this->dao->getCount($where);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取后台列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function getStoreBargainList(array $where)
|
||||
{
|
||||
$list = [];
|
||||
$count = 0;
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getList($where, $page, $limit);
|
||||
$count = $this->dao->count($where);
|
||||
if (empty($list)) return compact('list', 'count');
|
||||
/** @var StoreBargainUserServices $storeBargainUserServices */
|
||||
$storeBargainUserServices = app()->make(StoreBargainUserServices::class);
|
||||
$ids = array_column($list, 'id');
|
||||
$countAll = $storeBargainUserServices->getAllCount([['bargain_id', 'in', $ids]]);
|
||||
$countSuccess = $storeBargainUserServices->getAllCount([
|
||||
['status', '=', 3],
|
||||
['bargain_id', 'in', $ids]
|
||||
]);
|
||||
/** @var StoreBargainUserHelpServices $storeBargainUserHelpServices */
|
||||
$storeBargainUserHelpServices = app()->make(StoreBargainUserHelpServices::class);
|
||||
$countHelpAll = $storeBargainUserHelpServices->getHelpAllCount([['bargain_id', 'in', $ids]]);
|
||||
$ids = [];
|
||||
foreach ($list as &$item) {
|
||||
$item['count_people_all'] = $countAll[$item['id']] ?? 0;//参与人数
|
||||
$item['count_people_help'] = $countHelpAll[$item['id']] ?? 0;//帮忙砍价人数
|
||||
$item['count_people_success'] = $countSuccess[$item['id']] ?? 0;//砍价成功人数
|
||||
$item['stop_status'] = $item['stop_time'] < time() ? 1 : 0;
|
||||
if ($item['status']) {
|
||||
if ($item['start_time'] > time()) {
|
||||
$item['start_name'] = '未开始';
|
||||
} else if ($item['stop_time'] < time()) {
|
||||
$item['start_name'] = '已结束';
|
||||
$item['status'] = 0;
|
||||
$ids[] = $item['id'];
|
||||
} else if ($item['stop_time'] > time() && $item['start_time'] < time()) {
|
||||
$item['start_name'] = '进行中';
|
||||
}
|
||||
} else $item['start_name'] = '已结束';
|
||||
}
|
||||
foreach ($ids as $id) {
|
||||
$this->dao->update($id, ['status' => 0]);
|
||||
}
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存数据
|
||||
* @param int $id
|
||||
* @param array $data
|
||||
*/
|
||||
public function saveData(int $id, array $data)
|
||||
{
|
||||
/** @var StoreProductServices $storeProductServices */
|
||||
$storeProductServices = app()->make(StoreProductServices::class);
|
||||
$productInfo = $storeProductServices->getOne(['is_del' => 0, 'is_verify' => 1, 'id' => $data['product_id']]);
|
||||
if (!$productInfo) {
|
||||
throw new AdminException('原商品已移入回收站');
|
||||
}
|
||||
if ($productInfo['is_vip_product']) {
|
||||
throw new AdminException("【{$productInfo["store_name"]}】是svip专享");
|
||||
}
|
||||
if ($productInfo['is_presale_product']) {
|
||||
throw new AdminException("【{$productInfo["store_name"]}】是预售商品");
|
||||
}
|
||||
$data['product_type'] = $productInfo['product_type'];
|
||||
$data['type'] = $productInfo['type'] ?? 0;
|
||||
$data['relation_id'] = $productInfo['relation_id'] ?? 0;
|
||||
$custom_form = $productInfo['custom_form'] ?? [];
|
||||
$data['custom_form'] = is_array($custom_form) ? json_encode($custom_form) : $custom_form;
|
||||
$data['system_form_id'] = $productInfo['system_form_id'] ?? 0;
|
||||
$store_label_id = $productInfo['store_label_id'] ?? [];
|
||||
$data['store_label_id'] = is_array($store_label_id) ? implode(',', $store_label_id) : $store_label_id;
|
||||
$ensure_id = $productInfo['ensure_id'] ?? [];
|
||||
$data['ensure_id'] = is_array($ensure_id) ? implode(',', $ensure_id) : $ensure_id;
|
||||
$specs = $productInfo['specs'] ?? [];
|
||||
$data['specs'] = is_array($specs) ? json_encode($specs) : $specs;
|
||||
if ($data['product_type'] !== 0) {
|
||||
$data['delivery_type'] = 2;
|
||||
}
|
||||
if (in_array($data['product_type'], [1, 2, 3])) {
|
||||
$data['freight'] = 2;
|
||||
$data['temp_id'] = 0;
|
||||
$data['postage'] = 0;
|
||||
} else {
|
||||
if ($data['freight'] == 1) {
|
||||
$data['temp_id'] = 0;
|
||||
$data['postage'] = 0;
|
||||
} elseif ($data['freight'] == 2) {
|
||||
$data['temp_id'] = 0;
|
||||
} elseif ($data['freight'] == 3) {
|
||||
$data['postage'] = 0;
|
||||
}
|
||||
if ($data['freight'] == 2 && !$data['postage']) {
|
||||
throw new AdminException('请设置运费金额');
|
||||
}
|
||||
if ($data['freight'] == 3 && !$data['temp_id']) {
|
||||
throw new AdminException('请选择运费模版');
|
||||
}
|
||||
}
|
||||
$description = $data['description'];
|
||||
$detail = $data['attrs'];
|
||||
$items = $data['items'];
|
||||
$data['start_time'] = strtotime($data['section_time'][0]);
|
||||
$data['stop_time'] = strtotime($data['section_time'][1]);
|
||||
$data['image'] = $data['images'][0] ?? '';
|
||||
$data['images'] = json_encode($data['images']);
|
||||
$data['stock'] = $detail[0]['stock'];
|
||||
$data['quota'] = $detail[0]['quota'];
|
||||
$data['quota_show'] = $detail[0]['quota'];
|
||||
$data['price'] = $detail[0]['price'];
|
||||
$data['min_price'] = $detail[0]['min_price'];
|
||||
|
||||
if ($detail[0]['min_price'] < 0 || $detail[0]['price'] <= 0 || $detail[0]['min_price'] === '' || $detail[0]['price'] === '') throw new ValidateException('金额不能小于0');
|
||||
if ($detail[0]['min_price'] >= $detail[0]['price']) throw new ValidateException('砍价最低价不能大于或等于起始金额');
|
||||
if ($detail[0]['quota'] > $detail[0]['stock']) throw new ValidateException('限量不能超过商品库存');
|
||||
|
||||
//按照能砍掉的金额计算最大设置人数,并判断填写的砍价人数是否大于最大设置人数
|
||||
$bNum = bcmul(bcsub((string)$data['price'], (string)$data['min_price'], 2), '100');
|
||||
if ($data['people_num'] > $bNum) throw new ValidateException('商品砍去金额(每人最少0.01元)');
|
||||
|
||||
unset($data['section_time'], $data['description'], $data['attrs'], $data['items'], $detail[0]['min_price'], $detail[0]['_index'], $detail[0]['_rowKey']);
|
||||
/** @var StoreDescriptionServices $storeDescriptionServices */
|
||||
$storeDescriptionServices = app()->make(StoreDescriptionServices::class);
|
||||
/** @var StoreProductAttrServices $storeProductAttrServices */
|
||||
$storeProductAttrServices = app()->make(StoreProductAttrServices::class);
|
||||
$this->transaction(function () use ($id, $data, $description, $detail, $items, $storeDescriptionServices, $storeProductAttrServices) {
|
||||
if ($id) {
|
||||
$res = $this->dao->update($id, $data);
|
||||
if (!$res) throw new AdminException('修改失败');
|
||||
} else {
|
||||
$data['add_time'] = time();
|
||||
$res = $this->dao->save($data);
|
||||
if (!$res) throw new AdminException('添加失败');
|
||||
$id = (int)$res->id;
|
||||
}
|
||||
$storeDescriptionServices->saveDescription((int)$id, $description, 2);
|
||||
$storeProductAttrServices->setItem('store_product_id', $data['product_id']);
|
||||
$skuList = $storeProductAttrServices->validateProductAttr($items, $detail, (int)$id, 2);
|
||||
$storeProductAttrServices->reset();
|
||||
$valueGroup = $storeProductAttrServices->saveProductAttr($skuList, (int)$id, 2);
|
||||
|
||||
$res = true;
|
||||
foreach ($valueGroup as $item) {
|
||||
$res = $res && CacheService::setStock($item['unique'], (int)$item['quota_show'], 2);
|
||||
}
|
||||
if (!$res) {
|
||||
throw new AdminException('占用库存失败');
|
||||
}
|
||||
});
|
||||
|
||||
$this->dao->cacheTag()->clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取砍价详情
|
||||
* @param int $id
|
||||
* @return array|\think\Model|null
|
||||
*/
|
||||
public function getInfo(int $id)
|
||||
{
|
||||
$info = $this->dao->get($id);
|
||||
if ($info) {
|
||||
if ($info['start_time']) {
|
||||
$start_time = date('Y-m-d H:i:s', $info['start_time']);
|
||||
}
|
||||
if ($info['stop_time']) {
|
||||
$stop_time = date('Y-m-d H:i:s', $info['stop_time']);
|
||||
}
|
||||
if (isset($start_time) && isset($stop_time)) {
|
||||
$info['section_time'] = [$start_time, $stop_time];
|
||||
} else {
|
||||
$info['section_time'] = [];
|
||||
}
|
||||
unset($info['start_time'], $info['stop_time']);
|
||||
}
|
||||
|
||||
$info['give_integral'] = intval($info['give_integral']);
|
||||
$info['price'] = floatval($info['price']);
|
||||
$info['postage'] = floatval($info['postage']);
|
||||
$info['cost'] = floatval($info['cost']);
|
||||
$info['bargain_max_price'] = floatval($info['bargain_max_price']);
|
||||
$info['bargain_min_price'] = floatval($info['bargain_min_price']);
|
||||
$info['min_price'] = floatval($info['min_price']);
|
||||
$info['weight'] = floatval($info['weight']);
|
||||
$info['volume'] = floatval($info['volume']);
|
||||
if (!$info['delivery_type']) {
|
||||
$info['delivery_type'] = [1];
|
||||
}
|
||||
if ($info['postage']) {
|
||||
$info['freight'] = 2;
|
||||
} elseif ($info['temp_id']) {
|
||||
$info['freight'] = 3;
|
||||
} else {
|
||||
$info['freight'] = 1;
|
||||
}
|
||||
/** @var StoreDescriptionServices $storeDescriptionServices */
|
||||
$storeDescriptionServices = app()->make(StoreDescriptionServices::class);
|
||||
$info['description'] = $storeDescriptionServices->getDescription(['product_id' => $id, 'type' => 2]);
|
||||
/** @var StoreProductAttrValueServices $storeProductAttrValueServices */
|
||||
$storeProductAttrValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
$info['attrs'] = $storeProductAttrValueServices->attrList($id, $info['product_id'], 2);
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* 砍价列表
|
||||
* @return array
|
||||
* @throws \ReflectionException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getBargainList()
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$field = 'id,type,relation_id,product_id,product_type,price,min_price,image,title,info,sales,stock';
|
||||
$list = $this->dao->BargainList([], $field, $page, $limit);
|
||||
if ($list) {
|
||||
$bargainIds = array_column($list, 'id');
|
||||
/** @var StoreBargainUserHelpServices $bargainHelp */
|
||||
$bargainHelp = app()->make(StoreBargainUserHelpServices::class);
|
||||
$bargainPeople = $bargainHelp->getBargainPeople([['bargain_id', 'in', $bargainIds], ['type', '=', 1]], 'bargain_id,count(*) as people', 'bargain_id');
|
||||
foreach ($list as &$item) {
|
||||
$item['people'] = $bargainPeople[$item['id']]['people'] ?? 0;
|
||||
$item['price'] = floatval($item['price']);
|
||||
/** @var StoreProductServices $storeProductServices */
|
||||
$storeProductServices = app()->make(StoreProductServices::class);
|
||||
$item['brand_name'] = $storeProductServices->productIdByBrandName((int)$item['product_id']);
|
||||
}
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单条砍价
|
||||
* @param int $uid
|
||||
* @param int $id
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getBargain(int $uid, int $id)
|
||||
{
|
||||
$storeInfo = $this->dao->getOne(['id' => $id], '*,title as store_name', ['descriptions']);
|
||||
if (!$storeInfo) {
|
||||
throw new ValidateException('砍价商品不存在');
|
||||
}
|
||||
$storeInfo['time'] = time();
|
||||
// if ($storeInfo['stop_time'] < time()) {
|
||||
// throw new ValidateException('砍价已结束');
|
||||
// }
|
||||
//是否自己还能参与砍价
|
||||
$count = 0;
|
||||
$data = [];
|
||||
$data['bargainSumCount'] = 0;
|
||||
$data['userBargainStatus'] = 0;
|
||||
$userInfo = ['uid' => $uid, 'nickname' => '', 'avatar' => ''];
|
||||
if ($uid) {
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$user = $userServices->getUserCacheInfo($uid);
|
||||
if (!$user) {
|
||||
throw new ValidateException('用户信息获取失败或者登录失效');
|
||||
}
|
||||
$userInfo['nickname'] = $user['nickname'] ?? '';
|
||||
$userInfo['avatar'] = $user['avatar'] ?? '';
|
||||
/** @var StoreBargainUserServices $bargainUserServices */
|
||||
$bargainUserServices = app()->make(StoreBargainUserServices::class);
|
||||
$count = $bargainUserServices->count(['uid' => $uid, 'bargain_id' => $id]);
|
||||
/** @var StoreOrderServices $orderService */
|
||||
$orderService = app()->make(StoreOrderServices::class);
|
||||
$data['bargainSumCount'] = $orderService->count(['type' => 2, 'activity_id' => $id, 'uid' => $uid]);//只要用户生成订单,就算作用电一次砍价的机会
|
||||
/** @var StoreBargainUserServices $storeInfoUserService */
|
||||
$storeInfoUserService = app()->make(StoreBargainUserServices::class);
|
||||
$data['userBargainStatus'] = $storeInfoUserService->count(['bargain_id' => $id, 'uid' => $uid, 'is_del' => 0]);
|
||||
}
|
||||
$data['userInfo'] = $userInfo;
|
||||
$storeInfo['is_bargain'] = $count >= $storeInfo['num'];
|
||||
//品牌名称
|
||||
/** @var StoreProductServices $storeProductServices */
|
||||
$storeProductServices = app()->make(StoreProductServices::class);
|
||||
$storeInfo['brand_name'] = $storeProductServices->productIdByBrandName((int)$storeInfo['product_id']);
|
||||
/**
|
||||
* 判断配送方式
|
||||
*/
|
||||
$storeInfo['delivery_type'] = $storeProductServices->getDeliveryType($storeInfo['type'], $storeInfo['relation_id'], $storeInfo['delivery_type']);
|
||||
|
||||
/** @var StoreProductAttrServices $storeProductAttrServices */
|
||||
$storeProductAttrServices = app()->make(StoreProductAttrServices::class);
|
||||
[$productAttr, $productValue] = $storeProductAttrServices->getProductAttrDetail($id, $uid, 0, 2, $storeInfo['product_id']);
|
||||
foreach ($productValue as $v) {
|
||||
$storeInfo['attr'] = $v;
|
||||
}
|
||||
$data['bargain'] = get_thumb_water($storeInfo);
|
||||
$storeInfoNew = get_thumb_water($storeInfo, 'small');
|
||||
$data['bargain']['small_image'] = $storeInfoNew['image'];
|
||||
$data['site_name'] = sys_config('site_name');
|
||||
$data['share_qrcode'] = sys_config('share_qrcode', 0);
|
||||
|
||||
/** @var StoreOrderServices $orderServices */
|
||||
$orderServices = app()->make(StoreOrderServices::class);
|
||||
$data['payCount'] = $orderServices->count(['activity_id' => $id, 'type' => 2]);
|
||||
//浏览记录
|
||||
ProductLogJob::dispatch(['visit', ['uid' => $uid, 'id' => $id, 'product_id' => $storeInfo['product_id']], 'bargain']);
|
||||
//增加查看次数
|
||||
StoreBargainJob::dispatchDo('setBargainCount', [$id, 'look']);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证砍价是否能支付
|
||||
* @param int $bargainId
|
||||
* @param int $uid
|
||||
*/
|
||||
public function checkBargainUser(int $bargainId, int $uid)
|
||||
{
|
||||
/** @var StoreBargainUserServices $bargainUserServices */
|
||||
$bargainUserServices = app()->make(StoreBargainUserServices::class);
|
||||
$bargainUserInfo = $bargainUserServices->getOne(
|
||||
['uid' => $uid, 'bargain_id' => $bargainId, 'status' => 1, 'is_del' => 0],
|
||||
'id,bargain_price_min,bargain_price,status,price'
|
||||
);
|
||||
if (!$bargainUserInfo)
|
||||
throw new ValidateException('砍价失败');
|
||||
$bargainUserTableId = $bargainUserInfo['id'];
|
||||
if ($bargainUserInfo['bargain_price_min'] < bcsub((string)$bargainUserInfo['bargain_price'], (string)$bargainUserInfo['price'], 2)) {
|
||||
throw new ValidateException('砍价未成功');
|
||||
}
|
||||
if ($bargainUserInfo['status'] == 3)
|
||||
throw new ValidateException('砍价已支付');
|
||||
|
||||
/** @var StoreProductAttrValueServices $attrValueServices */
|
||||
$attrValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
$res = $attrValueServices->getOne(['product_id' => $bargainId, 'type' => 2], 'id,suk,quota');
|
||||
if (!$this->validBargain($bargainId) || !$res) {
|
||||
throw new ValidateException('该商品已下架或删除');
|
||||
}
|
||||
$StoreBargainInfo = $this->dao->get($bargainId, ['product_id']);
|
||||
if (1 > $res['quota']) {
|
||||
throw new ValidateException('该商品库存不足');
|
||||
}
|
||||
$product_stock = $attrValueServices->value(['product_id' => $StoreBargainInfo['product_id'], 'suk' => $res['suk'], 'type' => 0], 'stock');
|
||||
if ($product_stock < 1) {
|
||||
throw new ValidateException('该商品库存不足');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改砍价状态
|
||||
* @param int $bargainId
|
||||
* @param int $uid
|
||||
* @param int $bargainUserTableId
|
||||
* @return \crmeb\basic\BaseModel|false
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function setBargainUserStatus(int $bargainId, int $uid, int $bargainUserTableId = 0)
|
||||
{
|
||||
if (!$bargainId || !$uid) return false;
|
||||
if (!$bargainUserTableId) {
|
||||
/** @var StoreBargainUserServices $bargainUserServices */
|
||||
$bargainUserServices = app()->make(StoreBargainUserServices::class);
|
||||
$bargainUserInfo = $bargainUserServices->getOne(['uid' => $uid, 'bargain_id' => $bargainId, 'status' => 1, 'is_del' => 0], 'id');
|
||||
if (!$bargainUserInfo) {
|
||||
throw new ValidateException('砍价失败');
|
||||
}
|
||||
$bargainUserTableId = $bargainUserInfo['id'];
|
||||
}
|
||||
/** @var StoreBargainUserServices $bargainUserServices */
|
||||
$bargainUserServices = app()->make(StoreBargainUserServices::class);
|
||||
$bargainUser = $bargainUserServices->getOne(['id' => $bargainUserTableId, 'uid' => $uid, 'bargain_id' => $bargainId, 'status' => 1], 'price,bargain_price,bargain_price_min');
|
||||
if (!$bargainUser) {
|
||||
return false;
|
||||
}
|
||||
$userPrice = $bargainUser['price'];
|
||||
$price = bcsub($bargainUser['bargain_price'], $bargainUser['bargain_price_min'], 2);
|
||||
if (bcsub($price, $userPrice, 2) > 0) {
|
||||
return false;
|
||||
}
|
||||
return $bargainUserServices->updateBargainStatus($bargainUserTableId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 参与砍价
|
||||
* @param int $uid
|
||||
* @param int $bargainId
|
||||
* @return string
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException*@throws \ReflectionException
|
||||
*/
|
||||
public function setBargain(int $uid, int $bargainId)
|
||||
{
|
||||
$bargainInfo = $this->dao->validProduct($bargainId, 'id,num,min_price,price');
|
||||
if (!$bargainInfo) {
|
||||
throw new ValidateException('砍价已结束');
|
||||
}
|
||||
$bargainInfo = $bargainInfo->toArray();
|
||||
/** @var StoreBargainUserServices $bargainUserService */
|
||||
$bargainUserService = app()->make(StoreBargainUserServices::class);
|
||||
$count = $bargainUserService->count(['bargain_id' => $bargainId, 'uid' => $uid, 'is_del' => 0, 'status' => 1]);
|
||||
if ($count === false) {
|
||||
throw new ValidateException('参数错误');
|
||||
} elseif ($count) {
|
||||
return 'SUCCESSFUL';
|
||||
} else {
|
||||
$count = $bargainUserService->count(['uid' => $uid, 'bargain_id' => $bargainId, 'type' => 1]);
|
||||
if ($count >= $bargainInfo['num']) throw new ValidateException('您不能再发起此件商品砍价');
|
||||
$res = $bargainUserService->setBargain($bargainId, $uid, $bargainInfo);
|
||||
}
|
||||
if (!$res) {
|
||||
throw new ValidateException('参与失败');
|
||||
} else {
|
||||
return 'SUCCESS';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 帮助好友砍价
|
||||
* @param int $uid
|
||||
* @param int $bargainId
|
||||
* @param int $bargainUserUid
|
||||
* @return string
|
||||
* @throws \ReflectionException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function setHelpBargain(int $uid, int $bargainId, int $bargainUserUid)
|
||||
{
|
||||
$bargainInfo = $this->dao->validProduct($bargainId);
|
||||
if (!$bargainInfo) {
|
||||
throw new ValidateException('砍价已结束');
|
||||
}
|
||||
/** @var StoreBargainUserServices $bargainUserService */
|
||||
$bargainUserService = app()->make(StoreBargainUserServices::class);
|
||||
$bargainUserTableId = $bargainUserService->getBargainUserTableId($bargainId, $bargainUserUid);
|
||||
if (!$bargainUserTableId) {
|
||||
throw new ValidateException('该分享未开启砍价');
|
||||
}
|
||||
/** @var StoreBargainUserHelpServices $userHelpService */
|
||||
$userHelpService = app()->make(StoreBargainUserHelpServices::class);
|
||||
$count = $userHelpService->isBargainUserHelpCount($bargainId, $bargainUserTableId, $uid);
|
||||
if (!$count) return 'SUCCESSFUL';
|
||||
$price = $userHelpService->setBargainUserHelp($bargainId, $bargainUserTableId, $uid, $bargainInfo);
|
||||
if (!(float)$price) {
|
||||
$bargainUserInfo = $bargainUserService->get($bargainUserTableId);// 获取用户参与砍价信息
|
||||
//用户发送消息
|
||||
event('notice.notice', [['uid' => $bargainUserUid, 'bargainInfo' => $bargainInfo, 'bargainUserInfo' => $bargainUserInfo,], 'bargain_success']);
|
||||
}
|
||||
return 'SUCCESS';
|
||||
}
|
||||
|
||||
/**
|
||||
* 减库存加销量
|
||||
* @param int $num
|
||||
* @param int $bargainId
|
||||
* @param string $unique
|
||||
* @param int $store_id
|
||||
* @return bool
|
||||
*/
|
||||
public function decBargainStock(int $num, int $bargainId, string $unique, int $store_id = 0)
|
||||
{
|
||||
//平台商品ID
|
||||
$product_id = $this->dao->value(['id' => $bargainId], 'product_id');
|
||||
$res = false;
|
||||
if ($product_id) {
|
||||
if ($unique) {
|
||||
/** @var StoreProductAttrValueServices $skuValueServices */
|
||||
$skuValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
//减去砍价商品sku的库存增加销量
|
||||
$res = false !== $skuValueServices->decProductAttrStock($bargainId, $unique, $num, 2);
|
||||
|
||||
//砍价商品sku
|
||||
$suk = $skuValueServices->value(['unique' => $unique, 'product_id' => $bargainId, 'type' => 2], 'suk');
|
||||
//平台商品sku unique
|
||||
$productUnique = $skuValueServices->value(['suk' => $suk, 'product_id' => $product_id, 'type' => 0], 'unique');
|
||||
/** @var StoreProductServices $services */
|
||||
$services = app()->make(StoreProductServices::class);
|
||||
//商品库存
|
||||
$res = $res && $services->decProductStock($num, $product_id, (string)$productUnique);
|
||||
}
|
||||
//减去砍价商品的库存和销量
|
||||
$res = $res && false !== $this->dao->decStockIncSales(['id' => $bargainId, 'type' => 2], $num);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 减销量加库存
|
||||
* @param int $num
|
||||
* @param int $bargainId
|
||||
* @param string $unique
|
||||
* @param int $store_id
|
||||
* @return bool
|
||||
*/
|
||||
public function incBargainStock(int $num, int $bargainId, string $unique, int $store_id = 0)
|
||||
{
|
||||
$product_id = $this->dao->value(['id' => $bargainId], 'product_id');
|
||||
$res = false;
|
||||
if ($product_id) {
|
||||
if ($unique) {
|
||||
/** @var StoreProductAttrValueServices $skuValueServices */
|
||||
$skuValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
//减去砍价商品sku的销量,增加库存和限购数量
|
||||
$res = false !== $skuValueServices->incProductAttrStock($bargainId, $unique, $num, 2);
|
||||
|
||||
//砍价商品sku
|
||||
$suk = $skuValueServices->value(['unique' => $unique, 'product_id' => $bargainId, 'type' => 2], 'suk');
|
||||
//平台商品sku unique
|
||||
$productUnique = $skuValueServices->value(['suk' => $suk, 'product_id' => $product_id, 'type' => 0], 'unique');
|
||||
|
||||
/** @var StoreProductServices $services */
|
||||
$services = app()->make(StoreProductServices::class);
|
||||
//减掉普通商品的销量加库存
|
||||
$res = $res && $services->incProductStock($num, $product_id, (string)$productUnique);
|
||||
}
|
||||
//减去砍价商品的销量,增加库存
|
||||
$res = $res && false !== $this->dao->incStockDecSales(['id' => $bargainId, 'type' => 2], $num);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取砍价海报信息
|
||||
* @param int $bargainId
|
||||
* @param $user
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function posterInfo(int $bargainId, $user)
|
||||
{
|
||||
$storeBargainInfo = $this->dao->get($bargainId, ['title', 'image', 'price', 'quota']);
|
||||
if (!$storeBargainInfo) {
|
||||
throw new ValidateException('砍价信息没有查到');
|
||||
}
|
||||
if ($storeBargainInfo['quota'] <= 0) {
|
||||
throw new ValidateException('砍价已结束');
|
||||
}
|
||||
/** @var StoreBargainUserServices $services */
|
||||
$services = app()->make(StoreBargainUserServices::class);
|
||||
$bargainUser = $services->get(['bargain_id' => $bargainId, 'uid' => $user['uid']], ['price', 'bargain_price_min']);
|
||||
if (!$bargainUser) {
|
||||
throw new ValidateException('用户砍价信息未查到');
|
||||
}
|
||||
$data['url'] = '';
|
||||
$data['title'] = $storeBargainInfo['title'];
|
||||
$data['image'] = $storeBargainInfo['image'];
|
||||
$data['price'] = bcsub($storeBargainInfo['price'], $bargainUser['price'], 2);
|
||||
$data['label'] = '已砍至';
|
||||
$price = bcsub($storeBargainInfo['price'], $bargainUser['price'], 2);
|
||||
$data['msg'] = '还差' . (bcsub($price, $bargainUser['bargain_price_min'], 2)) . '元即可砍价成功';
|
||||
//只有在小程序端,才会生成二维码
|
||||
if (\request()->isRoutine()) {
|
||||
try {
|
||||
//小程序
|
||||
$name = $bargainId . '_' . $user['uid'] . '_' . $user['is_promoter'] . '_bargain_share_routine.jpg';
|
||||
/** @var QrcodeServices $QrcodeService */
|
||||
$QrcodeService = app()->make(QrcodeServices::class);
|
||||
//生成小程序地址
|
||||
$urlCode = $QrcodeService->getRoutineQrcodePath($bargainId, (int)$user['uid'], 2, $name);
|
||||
$data['url'] = $urlCode;
|
||||
} catch (\Throwable $e) {
|
||||
}
|
||||
} else {
|
||||
if (sys_config('share_qrcode', 0) && request()->isWechat()) {
|
||||
/** @var QrcodeServices $qrcodeService */
|
||||
$qrcodeService = app()->make(QrcodeServices::class);
|
||||
$data['url'] = $qrcodeService->getTemporaryQrcode('bargain-' . $bargainId . '-' . $user['uid'], $user['uid'])->url;
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证砍价下单库存限量
|
||||
* @param int $uid
|
||||
* @param int $bargainId
|
||||
* @param int $cartNum
|
||||
* @param string $unique
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function checkBargainStock(int $uid, int $bargainId, int $cartNum = 1, string $unique = '')
|
||||
{
|
||||
if (!$this->validBargain($bargainId)) {
|
||||
throw new ValidateException('该商品已下架或删除');
|
||||
}
|
||||
/** @var StoreProductAttrValueServices $attrValueServices */
|
||||
$attrValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
$attrInfo = $attrValueServices->getOne(['product_id' => $bargainId, 'type' => 2]);
|
||||
if (!$attrInfo || $attrInfo['product_id'] != $bargainId) {
|
||||
throw new ValidateException('请选择有效的商品属性');
|
||||
}
|
||||
$productInfo = $this->dao->get($bargainId, ['*', 'title as store_name']);
|
||||
/** @var StoreBargainUserServices $bargainUserService */
|
||||
$bargainUserService = app()->make(StoreBargainUserServices::class);
|
||||
$bargainUserInfo = $bargainUserService->getOne(['uid' => $uid, 'bargain_id' => $bargainId, 'status' => 1, 'is_del' => 0]);
|
||||
if (!$bargainUserInfo || $bargainUserInfo['bargain_price_min'] < bcsub((string)$bargainUserInfo['bargain_price'], (string)$bargainUserInfo['price'], 2)) {
|
||||
throw new ValidateException('砍价未成功');
|
||||
}
|
||||
$unique = $attrInfo['unique'];
|
||||
if ($cartNum > $attrInfo['quota']) {
|
||||
throw new ValidateException('该商品库存不足' . $cartNum);
|
||||
}
|
||||
return [$attrInfo, $unique, $productInfo, $bargainUserInfo];
|
||||
}
|
||||
|
||||
/**
|
||||
* 砍价统计
|
||||
* @param $id
|
||||
* @return array
|
||||
*/
|
||||
public function bargainStatistics(int $id)
|
||||
{
|
||||
/** @var StoreBargainUserServices $bargainUser */
|
||||
$bargainUser = app()->make(StoreBargainUserServices::class);
|
||||
/** @var StoreBargainUserHelpServices $bargainUserHelp */
|
||||
$bargainUserHelp = app()->make(StoreBargainUserHelpServices::class);
|
||||
/** @var StoreOrderServices $orderServices */
|
||||
$orderServices = app()->make(StoreOrderServices::class);
|
||||
$people_count = $bargainUserHelp->count(['bargain_id' => $id]);
|
||||
$spread_count = $bargainUserHelp->count(['bargain_id' => $id, 'type' => 0]);
|
||||
$start_count = $bargainUser->count(['bargain_id' => $id]);
|
||||
$success_count = $bargainUser->count(['bargain_id' => $id, 'status' => 3]);
|
||||
$pay_price = $orderServices->sum(['type' => 2, 'activity_id' => $id, 'paid' => 1], 'pay_price', true);
|
||||
$pay_count = $orderServices->count(['type' => 2, 'activity_id' => $id, 'paid' => 1]);
|
||||
$pay_rate = $start_count > 0 ? bcmul(bcdiv((string)$pay_count, (string)$start_count, 2), '100', 2) : 0;
|
||||
return compact('people_count', 'spread_count', 'start_count', 'success_count', 'pay_price', 'pay_count', 'pay_rate');
|
||||
}
|
||||
|
||||
/**
|
||||
* 砍价统计列表
|
||||
* @param $id
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function bargainStatisticsList(int $id, array $where = [])
|
||||
{
|
||||
/** @var StoreBargainUserServices $bargainUser */
|
||||
$bargainUser = app()->make(StoreBargainUserServices::class);
|
||||
$where['bargain_id'] = $id;
|
||||
return $bargainUser->bargainUserList($where);
|
||||
}
|
||||
|
||||
/**
|
||||
* 砍价统计订单
|
||||
* @param $id
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function bargainStatisticsOrder(int $id, array $where = [])
|
||||
{
|
||||
/** @var StoreOrderServices $orderServices */
|
||||
$orderServices = app()->make(StoreOrderServices::class);
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $orderServices->activityStatisticsOrder($id, 2, $where, $page, $limit);
|
||||
$where['type'] = 2;
|
||||
$where['activity_id'] = $id;
|
||||
$count = $orderServices->count($where);
|
||||
foreach ($list as &$item) {
|
||||
if ($item['is_del'] || $item['is_system_del']) {
|
||||
$item['status'] = '已删除';
|
||||
} else if ($item['paid'] == 0 && $item['status'] == 0) {
|
||||
$item['status'] = '待付款';
|
||||
} else if ($item['paid'] == 1 && $item['status'] == 4 && in_array($item['shipping_type'], [1, 3]) && $item['refund_status'] == 0) {
|
||||
$item['status'] = '部分发货';
|
||||
} else if ($item['paid'] == 1 && $item['refund_status'] == 2) {
|
||||
$item['status'] = '已退款';
|
||||
} else if ($item['paid'] == 1 && $item['status'] == 5 && $item['refund_status'] == 0) {
|
||||
$item['status'] = $item['shipping_type'] == 2 ? '部分核销' : '部分收货';
|
||||
$item['_status'] = 12;//已支付 部分核销
|
||||
} else if ($item['paid'] == 1 && $item['refund_status'] == 1) {
|
||||
$item['status'] = '申请退款';
|
||||
} else if ($item['paid'] == 1 && $item['refund_status'] == 4) {
|
||||
$item['status'] = '退款中';
|
||||
} else if ($item['paid'] == 1 && $item['status'] == 0 && in_array($item['shipping_type'], [1, 3]) && $item['refund_status'] == 0) {
|
||||
$item['status'] = '未发货';
|
||||
$item['_status'] = 2;//已支付 未发货
|
||||
} else if ($item['paid'] == 1 && in_array($item['status'], [0, 1]) && $item['shipping_type'] == 2 && $item['refund_status'] == 0) {
|
||||
$item['status'] = '未核销';
|
||||
} else if ($item['paid'] == 1 && in_array($item['status'], [1, 5]) && in_array($item['shipping_type'], [1, 3]) && $item['refund_status'] == 0) {
|
||||
$item['status'] = '待收货';
|
||||
} else if ($item['paid'] == 1 && $item['status'] == 2 && $item['refund_status'] == 0) {
|
||||
$item['status'] = '待评价';
|
||||
} else if ($item['paid'] == 1 && $item['status'] == 3 && $item['refund_status'] == 0) {
|
||||
$item['status'] = '已完成';
|
||||
} else if ($item['paid'] == 1 && $item['refund_status'] == 3) {
|
||||
$item['status'] = '部分退款';
|
||||
} else {
|
||||
$item['status'] = '未知';
|
||||
}
|
||||
$item['add_time'] = date('Y-m-d H:i:s', $item['add_time']);
|
||||
$item['pay_time'] = $item['pay_time'] ? date('Y-m-d H:i:s', $item['pay_time']) : '';
|
||||
}
|
||||
return compact('list', 'count');
|
||||
}
|
||||
}
|
||||
186
app/services/activity/bargain/StoreBargainUserHelpServices.php
Normal file
186
app/services/activity/bargain/StoreBargainUserHelpServices.php
Normal file
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\bargain;
|
||||
|
||||
use app\services\BaseServices;
|
||||
use app\dao\activity\bargain\StoreBargainUserHelpDao;
|
||||
use app\services\user\UserServices;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
/**
|
||||
* Class StoreBargainUserHelpServices
|
||||
* @package app\services\activity\bargain
|
||||
* @mixin StoreBargainUserHelpDao
|
||||
*/
|
||||
class StoreBargainUserHelpServices extends BaseServices
|
||||
{
|
||||
|
||||
const MHLJEWVH = 'xI/Rha';
|
||||
|
||||
/**
|
||||
* @var StoreBargainUserHelpDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreBargainUserHelpDao $dao;
|
||||
|
||||
|
||||
/**
|
||||
* 获取砍价帮列表
|
||||
* @param int $bid
|
||||
* @param int $page
|
||||
* @param int $limit
|
||||
* @return array
|
||||
*/
|
||||
public function getHelpList(int $bid, int $page = 0, int $limit = 0)
|
||||
{
|
||||
$list = $this->dao->getHelpList($bid, $page, $limit);
|
||||
return array_values($list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取砍价金额
|
||||
* @param int $uid
|
||||
* @param int $bargainId
|
||||
* @param int $bargainUserUid
|
||||
* @return array
|
||||
*/
|
||||
public function getPrice(int $uid, int $bargainId, int $bargainUserUid)
|
||||
{
|
||||
/** @var StoreBargainUserServices $bargainUserService */
|
||||
$bargainUserService = app()->make(StoreBargainUserServices::class);
|
||||
$bargainUserTable = $bargainUserService->get(['bargain_id' => $bargainId, 'uid' => $bargainUserUid, 'is_del' => 0], ['id', 'status', 'bargain_price_min', 'bargain_price', 'price']);// 获取用户参与砍价表编号
|
||||
if (!$bargainUserTable) {
|
||||
throw new ValidateException('砍价信息没有查询到');
|
||||
}
|
||||
if (bcsub($bargainUserTable['bargain_price'], $bargainUserTable['price'], 2) == $bargainUserTable['bargain_price_min']) {
|
||||
$status = true;
|
||||
} else {
|
||||
$status = false;
|
||||
}
|
||||
$price = $this->dao->value(['uid' => $uid, 'bargain_id' => $bargainId, 'bargain_user_id' => $bargainUserTable['id']], 'price');
|
||||
return ['price' => $price, 'status' => $status];
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否能砍价
|
||||
* @param $bargainId
|
||||
* @param $bargainUserTableId
|
||||
* @param $uid
|
||||
* @return bool
|
||||
*/
|
||||
public function isBargainUserHelpCount($bargainId, $bargainUserTableId, $uid)
|
||||
{
|
||||
$count = $this->dao->count(['bargain_id' => $bargainId, 'bargain_user_id' => $bargainUserTableId, 'uid' => $uid]);
|
||||
if (!$count) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 帮忙砍价
|
||||
* @param $bargainId
|
||||
* @param $bargainUserTableId
|
||||
* @param $uid
|
||||
* @param array $bargainInfo
|
||||
* @return string
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function setBargainUserHelp($bargainId, $bargainUserTableId, $uid, $bargainInfo = [])
|
||||
{
|
||||
if (!$bargainInfo) {
|
||||
/** @var StoreBargainServices $bargainService */
|
||||
$bargainService = app()->make(StoreBargainServices::class);
|
||||
$bargainInfo = $bargainService->get($bargainId);
|
||||
}
|
||||
/** @var StoreBargainUserServices $bargainUserService */
|
||||
$bargainUserService = app()->make(StoreBargainUserServices::class);
|
||||
[$coverPrice, $alreadyPrice, $surplusPrice, $pricePercent, $bargainUserInfo] = $bargainUserService->getSurplusPrice($bargainUserTableId);
|
||||
if (0.00 === (float)$surplusPrice) throw new ValidateException('砍价已经完成');
|
||||
|
||||
$data['uid'] = $uid;
|
||||
$data['bargain_id'] = $bargainId;
|
||||
$data['bargain_user_id'] = $bargainUserTableId;
|
||||
$data['add_time'] = time();
|
||||
if ($bargainUserInfo['uid'] == $uid) {
|
||||
$data['type'] = 1;
|
||||
} else {
|
||||
//帮砍次数限制
|
||||
$count = $this->dao->count(['uid' => $uid, 'bargain_id' => $bargainId, 'type' => 0]);
|
||||
if ($count >= $bargainInfo->bargain_num) throw new ValidateException('您不能再帮砍此件商品');
|
||||
$data['type'] = 0;
|
||||
}
|
||||
$people = $this->dao->count(['bargain_user_id' => $bargainUserTableId]);//已经参与砍价的人数
|
||||
$surplusPeople = $bargainInfo->people_num - $people;
|
||||
if ($surplusPeople == 1) {
|
||||
$data['price'] = $surplusPrice;
|
||||
} else {
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$userInfo = $userServices->get($uid);
|
||||
$data['price'] = $this->randomFloat($surplusPrice, $bargainInfo->people_num, $surplusPeople, $userInfo->add_time == $userInfo->last_time && !$this->dao->count(['uid' => $uid]));
|
||||
}
|
||||
$price = bcadd((string)$alreadyPrice, (string)$data['price'], 2);
|
||||
$bargainUserData['price'] = $price;
|
||||
$this->transaction(function () use ($bargainUserService, $bargainUserTableId, $bargainUserData, $data) {
|
||||
$res1 = $bargainUserService->update($bargainUserTableId, $bargainUserData);
|
||||
$res2 = $this->dao->save($data);
|
||||
$res = $res1 && $res2;
|
||||
if (!$res) throw new ValidateException('砍价失败');
|
||||
});
|
||||
return bcsub((string)$surplusPrice, (string)$data['price'], 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 随机金额
|
||||
* @param $price
|
||||
* @param $people
|
||||
* @param $type
|
||||
* @return string
|
||||
*/
|
||||
public function randomFloat($price, $sum_people, $people, $type = false)
|
||||
{
|
||||
$max_percent = bcmul((string)bcdiv((string)$people, (string)$sum_people, 2), '100', 0);
|
||||
$min_percent = bcmul((string)bcdiv((string)($people - 1), (string)$sum_people, 2), '100', 0);
|
||||
//按照人数计算保留金额
|
||||
$retainPrice = bcmul((string)$people, '0.01', 2);
|
||||
//实际剩余金额
|
||||
$price = bcsub((string)$price, $retainPrice, 2);
|
||||
//计算比例
|
||||
if ($type) {
|
||||
$percent = '0.5';
|
||||
} else {
|
||||
mt_srand();
|
||||
$percent = bcdiv((string)mt_rand(10, 30), '100', 2);
|
||||
}
|
||||
//实际砍掉金额
|
||||
$cutPrice = bcmul($price, $percent, 2);
|
||||
//如果计算出来为0,默认砍掉0.01
|
||||
return $cutPrice != '0.00' ? $cutPrice : '0.01';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取砍价商品已砍人数
|
||||
* @return array
|
||||
*/
|
||||
public function getNums()
|
||||
{
|
||||
$nums = $this->dao->getNums();
|
||||
$dat = [];
|
||||
foreach ($nums as $item) {
|
||||
$dat[$item['bargain_user_id']] = $item['num'];
|
||||
}
|
||||
return $dat;
|
||||
}
|
||||
}
|
||||
231
app/services/activity/bargain/StoreBargainUserServices.php
Normal file
231
app/services/activity/bargain/StoreBargainUserServices.php
Normal file
@@ -0,0 +1,231 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\bargain;
|
||||
|
||||
|
||||
use app\services\BaseServices;
|
||||
use app\dao\activity\bargain\StoreBargainUserDao;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
/**
|
||||
* Class StoreBargainUserServices
|
||||
* @package app\services\activity\bargain
|
||||
* @mixin StoreBargainUserDao
|
||||
*/
|
||||
class StoreBargainUserServices extends BaseServices
|
||||
{
|
||||
|
||||
const EPTQRWNF = 'qbhzEE';
|
||||
|
||||
/**
|
||||
* @var StoreBargainUserDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreBargainUserDao $dao;
|
||||
|
||||
/**
|
||||
* 获取砍价
|
||||
* @param int $uid
|
||||
* @param int $bargainId
|
||||
* @param int $bargainUserUid
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function helpCount(int $uid, int $bargainId, int $bargainUserUid)
|
||||
{
|
||||
$data = [
|
||||
'userBargainStatus' => false,
|
||||
'count' => 0,
|
||||
'price' => 0,
|
||||
'status' => 0,
|
||||
'alreadyPrice' => 0,
|
||||
'pricePercent' => 0,
|
||||
];
|
||||
$bargainUserTableId = $this->dao->value(['bargain_id' => $bargainId, 'uid' => $bargainUserUid, 'is_del' => 0, 'status' => 1]);// 获取用户参与砍价表编号
|
||||
if ($bargainUserTableId) {
|
||||
$data['userBargainStatus'] = $this->isBargainUserHelpCount($bargainId, $uid, $bargainUserTableId);
|
||||
/** @var StoreBargainUserHelpServices $helpService */
|
||||
$helpService = app()->make(StoreBargainUserHelpServices::class);
|
||||
$count = $helpService->count(['bargain_user_id' => $bargainUserTableId, 'bargain_id' => $bargainId]);// 获取砍价帮总人数
|
||||
[$coverprice, $alreadyPrice, $price, $pricePercent] = $this->getSurplusPrice($bargainUserTableId);
|
||||
$data['count'] = $count;
|
||||
$data['price'] = $price;
|
||||
$data['status'] = $this->dao->value(['id' => $bargainUserTableId], 'status') ?? 0;
|
||||
$data['alreadyPrice'] = $alreadyPrice;
|
||||
$data['pricePercent'] = $pricePercent > 10 ? $pricePercent : 10;
|
||||
} else {
|
||||
/** @var StoreBargainServices $bargainService */
|
||||
$bargainService = app()->make(StoreBargainServices::class);
|
||||
$data['count'] = 0;
|
||||
$data['price'] = $bargainService->value(['id' => $bargainId], 'price - min_price');
|
||||
$data['status'] = $this->dao->value(['id' => $bargainUserTableId], 'status') ?? 0;
|
||||
$data['alreadyPrice'] = 0;
|
||||
$data['pricePercent'] = 0;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取砍价状态
|
||||
* @param int $bargainId
|
||||
* @param int $bargainUserUid
|
||||
* @param int $bargainUserHelpUid
|
||||
* @param $bargainUserTableId
|
||||
* @return bool
|
||||
*/
|
||||
public function isBargainUserHelpCount($bargainId, $bargainUserHelpUid, $bargainUserTableId)
|
||||
{
|
||||
/** @var StoreBargainUserHelpServices $userHelp */
|
||||
$userHelp = app()->make(StoreBargainUserHelpServices::class);
|
||||
$count = $userHelp->count(['bargain_id' => $bargainId, 'bargain_user_id' => $bargainUserTableId, 'uid' => $bargainUserHelpUid]);
|
||||
if (!$count) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取砍价剩余金额 或者 砍价百分比
|
||||
* @param $bargainUserTableId
|
||||
* @return array|float|int
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getSurplusPrice($bargainUserTableId)
|
||||
{
|
||||
$bargainUserInfo = $this->dao->get($bargainUserTableId);
|
||||
$coverPrice = $alreadyPrice = $surplusPrice = 0;
|
||||
$pricePercent = 100;
|
||||
if ($bargainUserInfo) {
|
||||
// 获取用户可以砍掉的金额 好友砍价之后获取砍价金额
|
||||
$coverPrice = (float)bcsub((string)$bargainUserInfo['bargain_price'], (string)$bargainUserInfo['bargain_price_min'], 2);
|
||||
// 用户已经砍掉的价格 好友砍价之后获取用户已经砍掉的价格
|
||||
$alreadyPrice = $this->dao->value(['id' => $bargainUserTableId], 'price');
|
||||
// 用户剩余要砍掉的价格
|
||||
$surplusPrice = (float)bcsub((string)$coverPrice, (string)$alreadyPrice, 2);
|
||||
if ($alreadyPrice) {//进度条百分比
|
||||
$pricePercent = (int)bcmul((string)bcdiv((string)$alreadyPrice, (string)$coverPrice, 2), '100', 0);
|
||||
}
|
||||
}
|
||||
return [$coverPrice, $alreadyPrice, $surplusPrice, $pricePercent, $bargainUserInfo];
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加砍价信息
|
||||
* @param int $bargainId
|
||||
* @param int $bargainUserUid
|
||||
* @param array $bargainInfo
|
||||
* @return mixed
|
||||
*/
|
||||
public function setBargain(int $bargainId, int $bargainUserUid, array $bargainInfo)
|
||||
{
|
||||
$data['bargain_id'] = $bargainId;
|
||||
$data['uid'] = $bargainUserUid;
|
||||
$data['bargain_price_min'] = $bargainInfo['min_price'];
|
||||
$data['bargain_price'] = $bargainInfo['price'];
|
||||
$data['price'] = 0;
|
||||
$data['status'] = 1;
|
||||
$data['is_del'] = 0;
|
||||
$data['add_time'] = time();
|
||||
return $this->dao->save($data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 修改砍价状态
|
||||
* @param $uid
|
||||
* @return bool
|
||||
*/
|
||||
public function editBargainUserStatus($uid)
|
||||
{
|
||||
$currentBargain = $this->dao->getColumn(['uid' => $uid, 'is_del' => 0, 'status' => 1], 'bargain_id');
|
||||
/** @var StoreBargainServices $bargainService */
|
||||
$bargainService = app()->make(StoreBargainServices::class);
|
||||
$bargainProduct = $bargainService->validWhere()->column('id');
|
||||
$closeBargain = [];
|
||||
foreach ($currentBargain as $key => &$item) {
|
||||
if (!in_array($item, $bargainProduct)) {
|
||||
$closeBargain[] = $item;
|
||||
}
|
||||
}// 获取已经结束的砍价商品
|
||||
if (count($closeBargain)) $this->dao->update([['uid', '=', $uid], ['status', '=', 1], ['bargain_id', 'in', implode(',', $closeBargain)]], ['status' => 2]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取用户的砍价商品
|
||||
* @param int $bargainUserUid $bargainUserUid 开启砍价用户编号
|
||||
* @return array
|
||||
*/
|
||||
public function getBargainUserAll(int $bargainUserUid)
|
||||
{
|
||||
if (!$bargainUserUid) return [];
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->userAll($bargainUserUid, $page, $limit);
|
||||
foreach ($list as &$item) {
|
||||
$item['residue_price'] = bcsub((string)$item['bargain_price'], (string)$item['price'], 2);
|
||||
$item['add_time'] = $item['add_time'] ? date('Y-m-d H:i:s', $item['add_time']) : '';
|
||||
[$coverprice, $alreadyPrice, $price, $pricePercent] = $this->getSurplusPrice((int)$item['id']);
|
||||
$item['pay_status'] = $price <= 0 && $item['status'] != 3;
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消砍价
|
||||
* @param $bargainId
|
||||
* @param $uid
|
||||
* @return mixed
|
||||
*/
|
||||
public function cancelBargain($bargainId, $uid)
|
||||
{
|
||||
$status = $this->dao->getBargainUserStatus($bargainId, $uid);
|
||||
if ($status != 1) throw new ValidateException('状态错误');
|
||||
$id = $this->dao->value(['bargain_id' => $bargainId, 'uid' => $uid, 'is_del' => 0], 'id');
|
||||
|
||||
return $this->dao->update($id, ['is_del' => 1, 'status' => 2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 砍价列表
|
||||
* @param $where
|
||||
* @return array
|
||||
*/
|
||||
public function bargainUserList($where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->bargainUserList($where, $page, $limit);
|
||||
$count = $this->dao->count($where);
|
||||
/** @var StoreBargainUserHelpServices $bargainUserHelpService */
|
||||
$bargainUserHelpService = app()->make(StoreBargainUserHelpServices::class);
|
||||
$nums = $bargainUserHelpService->getNums();
|
||||
$time = time();
|
||||
foreach ($list as &$item) {
|
||||
$item['num'] = $item['people_num'] - ($nums[$item['id']] ?? 0);
|
||||
$item['already_num'] = $nums[$item['id']] ?? 0;
|
||||
$item['now_price'] = bcsub((string)$item['bargain_price'], (string)$item['price'], 2);
|
||||
$item['add_time'] = $item['add_time'] ? date('Y-m-d H:i:s', (int)$item['add_time']) : '';
|
||||
if ($item['status'] == 1 && isset($item['datatime']) && $item['datatime'] && $item['datatime'] < $time) {//进行中 验证时间是否结束
|
||||
$item['status'] = 2;
|
||||
}
|
||||
if (isset($item['datatime']) && $item['datatime']) {
|
||||
$item['datatime'] = date('Y-m-d H:i:s', (int)$item['datatime']);
|
||||
} else {
|
||||
$item['datatime'] = '';
|
||||
}
|
||||
}
|
||||
return compact('list', 'count');
|
||||
}
|
||||
}
|
||||
133
app/services/activity/card/CardBatchServices.php
Normal file
133
app/services/activity/card/CardBatchServices.php
Normal file
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\card;
|
||||
|
||||
use app\dao\activity\card\CardBatchDao;
|
||||
use app\services\BaseServices;
|
||||
use think\annotation\Inject;
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\DbException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
|
||||
|
||||
/**
|
||||
* 卡次表
|
||||
* Class CardBatchServices
|
||||
* @package app\services\activity\card
|
||||
* @mixin CardBatchDao
|
||||
*/
|
||||
class CardBatchServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var CardBatchDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected CardBatchDao $dao;
|
||||
|
||||
/**
|
||||
* 获取列表和总数
|
||||
*
|
||||
* 该方法主要用于根据给定的条件获取数据列表和总记录数
|
||||
* 它封装了分页逻辑和数据获取逻辑,以简化调用
|
||||
*
|
||||
* @param array $where 查询条件数组
|
||||
* @return array 包含数据列表和总记录数的数组
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function getList(array $where): array
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$where['is_del'] = 0;
|
||||
$list = $this->dao->selectList($where, '*', $page, $limit, 'add_time desc', true);
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存数据方法
|
||||
*
|
||||
* 该方法用于处理数据的保存操作,根据提供的标识$id判断是更新现有记录还是创建新记录
|
||||
* 使用事务确保数据一致性,在更新或创建过程中,涉及的操作要么全部完成,要么全部不完成
|
||||
*
|
||||
* @param int $id 要更新的记录的标识,如果为0则表示创建新记录
|
||||
* @param array $data 要保存的数据数组,包含需要更新或插入的字段和值
|
||||
*
|
||||
*/
|
||||
public function saveData(array $data): bool
|
||||
{
|
||||
// 使用事务处理数据保存操作,确保数据的一致性和完整性
|
||||
return $this->transaction(function () use ($data) {
|
||||
// 如果$id不存在,则创建新记录,并在成功后处理相关的卡片信息
|
||||
$saveData = $data;
|
||||
// $saveData['total_num'] = pow(10, $data['total_num']);
|
||||
unset($saveData['pwd_type'], $saveData['pwd_num']);
|
||||
$saveData['add_time'] = time();
|
||||
$res = $this->dao->save($saveData);
|
||||
$data['batch_id'] = $res->id;
|
||||
// 调用CardCodeServices服务的addCard方法,为新创建的记录添加卡片信息
|
||||
app()->make(CardCodeServices::class)->addCard($data);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定ID的批次记录
|
||||
* @param int $id
|
||||
* @return mixed
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/9 15:48
|
||||
*/
|
||||
public function del(int $id)
|
||||
{
|
||||
return $this->transaction(function () use ($id) {
|
||||
$this->update($id, ['is_del' => 1]);
|
||||
app()->make(CardCodeServices::class)->delete(['batch_id' => $id, 'card_id' => 0]);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取卡密批次树形结构列表
|
||||
* @return array
|
||||
*/
|
||||
public function getTree()
|
||||
{
|
||||
$list = $this->search(['is_del' => 0])->field('id,name,total_num,used_num')->select()->toArray();
|
||||
foreach ($list as &$item) {
|
||||
$item['remain_num'] = $item['total_num'] - $item['used_num'];
|
||||
$item['remain_num'] = max($item['remain_num'], 0);
|
||||
unset($item['total_num'], $item['used_num']);
|
||||
}
|
||||
unset($item);
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分配卡密码并更新使用数量
|
||||
* @param int $id 批次ID
|
||||
* @return bool
|
||||
*/
|
||||
public function allocationCode($id)
|
||||
{
|
||||
$info = $this->dao->get($id);
|
||||
if (!$info) {
|
||||
return true;
|
||||
}
|
||||
$used_num = app()->make(CardCodeServices::class)->search(['batch_id' => $id])->where('status', '<>', 0)->count();
|
||||
$info->used_num = $used_num;
|
||||
$info->save();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
377
app/services/activity/card/CardCodeServices.php
Normal file
377
app/services/activity/card/CardCodeServices.php
Normal file
@@ -0,0 +1,377 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\card;
|
||||
|
||||
use app\dao\activity\card\CardCodeDao;
|
||||
use app\jobs\activity\card\CardJob;
|
||||
use app\services\BaseServices;
|
||||
use app\services\order\StoreCartServices;
|
||||
use app\services\user\UserMoneyServices;
|
||||
use app\services\user\UserServices;
|
||||
use crmeb\services\FormBuilder as Form;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
use think\facade\Route as Url;
|
||||
|
||||
|
||||
/**
|
||||
* 卡密
|
||||
* Class CardCodeServices
|
||||
* @package app\services\activity\card
|
||||
* @mixin CardCodeDao
|
||||
*/
|
||||
class CardCodeServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var CardCodeDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected CardCodeDao $dao;
|
||||
|
||||
/**
|
||||
* 获取卡密列表
|
||||
* @param array $where 查询条件
|
||||
* @return array
|
||||
*/
|
||||
public function getList($where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$count = $this->dao->count($where);
|
||||
$list = $this->dao->getList($where, $page, $limit);
|
||||
if (!$list) {
|
||||
return [];
|
||||
}
|
||||
$uids = array_unique(array_column($list, 'uid'));
|
||||
$card_ids = array_unique(array_column($list, 'card_id'));
|
||||
$batch_ids = array_unique(array_column($list, 'batch_id'));
|
||||
$userList = app()->make(UserServices::class)->search(['uid' => $uids])->column('nickname', 'uid');
|
||||
$cardList = app()->make(CardGiftServices::class)->search(['id' => $card_ids])->column('name', 'id');
|
||||
$batchList = app()->make(CardBatchServices::class)->search(['id' => $batch_ids])->column('name', 'id');
|
||||
|
||||
foreach ($list as &$item) {
|
||||
$item['nickname'] = $userList[$item['uid']] ?? '';
|
||||
$item['card_name'] = $cardList[$item['card_id']] ?? '';
|
||||
$item['batch_name'] = $batchList[$item['batch_id']] ?? '';
|
||||
}
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加卡信息
|
||||
*
|
||||
* 该方法用于批量添加卡号和密码信息到数据库中。它接受一个包含批次ID、卡的数量、卡号前缀和后缀、
|
||||
* 以及密码类型和长度的数组作为参数。方法首先校验输入数据的合法性,然后生成指定数量的卡号和密码,
|
||||
* 并将它们批量插入到数据库中。
|
||||
* @param array $data 包含批次ID、总数量、卡号前缀和后缀、密码类型和长度的数据数组
|
||||
* @return true
|
||||
* @throws \Random\RandomException
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/9 11:30
|
||||
*/
|
||||
public function addCard(array $data): bool
|
||||
{
|
||||
// 参数校验优化:明确判断是否存在且大于0
|
||||
if (!isset($data['batch_id']) || (int)$data['batch_id'] <= 0) {
|
||||
throw new ValidateException('批次ID必须为正整数');
|
||||
}
|
||||
if (!isset($data['total_num']) || (int)$data['total_num'] <= 0) {
|
||||
throw new ValidateException('数量必须为正整数');
|
||||
}
|
||||
|
||||
// 校验 card_prefix 和 card_suffix 是否存在
|
||||
if (!isset($data['card_prefix'])) {
|
||||
$data['card_prefix'] = '';
|
||||
}
|
||||
if (!isset($data['card_suffix'])) {
|
||||
$data['card_suffix'] = '';
|
||||
}
|
||||
|
||||
// // 控制最大生成数量,防止内存溢出
|
||||
// $maxGenerateLimit = 100000; // 示例限制为10万张卡
|
||||
|
||||
// if ($length > 8 || pow(10, $length) > $maxGenerateLimit) {
|
||||
// throw new ValidateException("生成数量超出限制");
|
||||
// }
|
||||
|
||||
// 密码相关参数校验
|
||||
if (!isset($data['pwd_type']) || !isset($data['pwd_num'])) {
|
||||
throw new ValidateException('密码类型或长度缺失');
|
||||
}
|
||||
|
||||
$max = (int)$data['total_num'];
|
||||
$length = (int)strlen((string)$data['total_num']);
|
||||
$insertData = [];
|
||||
|
||||
for ($i = 1; $i <= $max; $i++) {
|
||||
$num = str_pad((string)$i, $length, '0', STR_PAD_LEFT);
|
||||
$insertData[] = [
|
||||
'card_number' => $data['card_prefix'] . $num . $data['card_suffix'],
|
||||
'card_pwd' => $this->generatePassword((array)$data['pwd_type'], (int)$data['pwd_num']),
|
||||
'batch_id' => $data['batch_id'],
|
||||
'add_time' => time(),
|
||||
];
|
||||
|
||||
// 每满100条插入一次并清空缓存
|
||||
if (count($insertData) >= 1000) {
|
||||
$this->dao->saveAll($insertData);
|
||||
$insertData = [];
|
||||
}
|
||||
}
|
||||
|
||||
// 插入剩余数据
|
||||
if (!empty($insertData)) {
|
||||
$this->dao->saveAll($insertData);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成指定类型的随机密码
|
||||
*
|
||||
* @param array $types 密码包含的字符类型,1代表数字,2代表小写字母,3代表大写字母,默认包含所有类型
|
||||
* @param int $num 密码的长度,默认为10
|
||||
* @return string 生成的密码字符串
|
||||
* @throws ValidateException 如果密码长度小于等于0或密码类型不在允许范围内,则抛出异常
|
||||
*/
|
||||
public function generatePassword(array $types = [1, 2, 3], int $num = 10): string
|
||||
{
|
||||
// 参数校验
|
||||
if ($num <= 0) {
|
||||
throw new ValidateException('密码长度必须大于0');
|
||||
}
|
||||
|
||||
$validTypes = [1, 2, 3];
|
||||
foreach ($types as $type) {
|
||||
if (!is_int($type) || !in_array($type, $validTypes, true)) {
|
||||
throw new ValidateException('密码类型必须是 1、2 或 3');
|
||||
}
|
||||
}
|
||||
|
||||
// 定义每种类型的字符集合
|
||||
$typeMap = [
|
||||
1 => '0123456789',
|
||||
2 => 'abcdefghijklmnopqrstuvwxyz',
|
||||
3 => 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
||||
];
|
||||
|
||||
// 根据选择的类型构建字符池
|
||||
$charPool = '';
|
||||
foreach ($types as $type) {
|
||||
$charPool .= $typeMap[$type];
|
||||
}
|
||||
|
||||
// 确保字符池不为空
|
||||
if ($charPool === '') {
|
||||
throw new ValidateException('至少选择一种密码类型');
|
||||
}
|
||||
|
||||
// 初始化密码字符串和字符池长度
|
||||
$password = '';
|
||||
$poolLength = strlen($charPool) - 1;
|
||||
|
||||
// 生成指定长度的密码
|
||||
for ($i = 0; $i < $num; $i++) {
|
||||
$randomIndex = random_int(0, $poolLength);
|
||||
$password .= $charPool[$randomIndex];
|
||||
}
|
||||
|
||||
return $password;
|
||||
}
|
||||
|
||||
/**
|
||||
* 备注
|
||||
* @param int $id
|
||||
* @return mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/6/5 16:48
|
||||
*/
|
||||
public function formRemark(int $id)
|
||||
{
|
||||
$card = $this->dao->get($id);
|
||||
if (!$card) {
|
||||
throw new ValidateException('数据不存在');
|
||||
}
|
||||
$field[] = Form::input('remark', '备注', $card['remark'] ?? '')->required();
|
||||
return create_form('备注', $field, Url::buildUrl('/marketing/card/code/remark/' . $id), 'POST');
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证礼品卡
|
||||
* @param string $card_number
|
||||
* @param string $card_pwd
|
||||
* @return mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/6/5 16:49
|
||||
*/
|
||||
public function verifyGiftCode($card_number, $card_pwd)
|
||||
{
|
||||
$info = $this->dao->get(['card_number' => $card_number, 'card_pwd' => $card_pwd]);
|
||||
if (!$info) {
|
||||
throw new ValidateException('礼品卡卡号或密码错误');
|
||||
}
|
||||
if ($info['status'] != 2) {
|
||||
throw new ValidateException('礼品卡已被使用');
|
||||
}
|
||||
if (!$info['card_id']) {
|
||||
throw new ValidateException('礼品卡未绑定');
|
||||
}
|
||||
$giftInfo = app()->make(CardGiftServices::class)->getInfo($info['card_id']);
|
||||
if (!$giftInfo) {
|
||||
throw new ValidateException('礼品卡不存在');
|
||||
}
|
||||
if ($giftInfo['status'] != 1) {
|
||||
throw new ValidateException('礼品卡已失效');
|
||||
}
|
||||
if ($giftInfo['valid_type'] == 2 && ($giftInfo['start_time'] > time() || $giftInfo['end_time'] < time())) {
|
||||
throw new ValidateException('请在有效期内激活~');
|
||||
}
|
||||
return $giftInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用
|
||||
* @param string $card_number
|
||||
* @param string $card_pwd
|
||||
* @param array $product
|
||||
* @param int $uid
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/6/5 16:49
|
||||
*/
|
||||
public function receiveGiftCode(string $card_number, string $card_pwd, array $product, int $uid)
|
||||
{
|
||||
$giftInfo = $this->verifyGiftCode($card_number, $card_pwd);
|
||||
$info = $this->dao->get(['card_number' => $card_number, 'card_pwd' => $card_pwd]);
|
||||
if ($giftInfo['type'] == 1) {
|
||||
$data = $this->transaction(function () use ($card_number, $card_pwd, $uid, $giftInfo, $info) {
|
||||
//兑换余额
|
||||
$userMoneyServices = app()->make(UserMoneyServices::class);
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$user = $userServices->get($uid);
|
||||
$edit['now_money'] = bcadd($user['now_money'], $giftInfo['balance'], 2);
|
||||
$res = $userServices->update($uid, $edit);
|
||||
$res = $res && $userMoneyServices->income('card_add_money', $user['uid'], $giftInfo['balance'], $edit['now_money'], $info['id']);
|
||||
//修改卡密状态
|
||||
if ($res) {
|
||||
$info->uid = $uid;
|
||||
$info->status = 1;
|
||||
$info->active_time = time();
|
||||
$res = $info->save();
|
||||
}
|
||||
return !!$res;
|
||||
});
|
||||
} else {
|
||||
//验证商品
|
||||
if (!$giftInfo['product']) {
|
||||
throw new ValidateException('礼品卡未绑定商品');
|
||||
}
|
||||
if ($giftInfo['exchange_type'] == 1) {
|
||||
//固定
|
||||
$product_list = $giftInfo['product'];
|
||||
} else {
|
||||
//任选
|
||||
$uniques = array_column($giftInfo['product'], 'unique');
|
||||
foreach ($product as $item) {
|
||||
if (!in_array($item['unique'], $uniques)) {
|
||||
throw new ValidateException('礼品卡商品不匹配');
|
||||
}
|
||||
}
|
||||
$product_list = $product;
|
||||
}
|
||||
$storeCartServices = app()->make(StoreCartServices::class);
|
||||
$cartList = [];
|
||||
foreach ($product_list as $item) {
|
||||
if ($item['limit_num'] > 0) {
|
||||
[$cartIds, $cartNum] = $storeCartServices->setCart($uid, $item['product_id'], $item['limit_num'], $item['unique'], 9, true, $info['id']);
|
||||
$cartList[] = ['cartId' => $cartIds, 'cartNum' => $cartNum];
|
||||
}
|
||||
}
|
||||
$data = $cartList;
|
||||
}
|
||||
//校验卡密使用数量
|
||||
CardJob::dispatchDo('allocationCardGift', [$giftInfo['id']]);
|
||||
return ['type' => $giftInfo['type'], 'data' => $data];
|
||||
}
|
||||
|
||||
/**
|
||||
* 卡密使用
|
||||
* @param array $order
|
||||
* @return true
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/24 10:57
|
||||
*/
|
||||
public function useCode(array $order)
|
||||
{
|
||||
$info = $this->dao->get($order['activity_id']);
|
||||
if (!$info) {
|
||||
throw new ValidateException('礼品卡数据不存在');
|
||||
}
|
||||
if ($info['status'] != 2) {
|
||||
throw new ValidateException('礼品卡已被使用');
|
||||
}
|
||||
//修改卡密状态
|
||||
$info->uid = $order['uid'];
|
||||
$info->status = 1;
|
||||
$info->active_time = time();
|
||||
$res = $info->save();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 过期
|
||||
* @return true
|
||||
* @throws \ReflectionException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/6/5 17:14
|
||||
*/
|
||||
public function expireCode()
|
||||
{
|
||||
$list = $this->dao->search(['status' => 2])->where('end_time', '<>', 0)->where('end_time', '<', time())->order('id asc')->select()->toArray();
|
||||
if (!$list) {
|
||||
return true;
|
||||
}
|
||||
$updateData = [
|
||||
'status' => 3,
|
||||
];
|
||||
foreach ($list as $k => $item) {
|
||||
$ids[] = $item['id'];
|
||||
// 每满100条插入一次并清空缓存
|
||||
if (count($ids) >= 500) {
|
||||
$this->dao->batchUpdate($ids, $updateData);
|
||||
$ids = [];
|
||||
}
|
||||
}
|
||||
if (count($ids)) {
|
||||
$this->dao->batchUpdate($ids, $updateData);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
34
app/services/activity/card/CardGiftAuxiliaryServices.php
Normal file
34
app/services/activity/card/CardGiftAuxiliaryServices.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\card;
|
||||
|
||||
use app\dao\activity\card\CardGiftAuxiliaryDao;
|
||||
use app\services\BaseServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
|
||||
/**
|
||||
* 礼品卡
|
||||
* Class CardGiftAuxiliaryServices
|
||||
* @package app\services\activity\card
|
||||
* @mixin CardGiftAuxiliaryDao
|
||||
*/
|
||||
class CardGiftAuxiliaryServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var CardGiftAuxiliaryDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected CardGiftAuxiliaryDao $dao;
|
||||
}
|
||||
59
app/services/activity/card/CardGiftRecordServices.php
Normal file
59
app/services/activity/card/CardGiftRecordServices.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\card;
|
||||
|
||||
use app\dao\activity\card\CardGiftRecordDao;
|
||||
use app\services\BaseServices;
|
||||
use app\services\system\admin\SystemAdminServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
|
||||
/**
|
||||
* 礼品卡
|
||||
* Class CardGiftServices
|
||||
* @package app\services\activity\card
|
||||
* @mixin CardGiftRecordDao
|
||||
*/
|
||||
class CardGiftRecordServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var CardGiftRecordDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected CardGiftRecordDao $dao;
|
||||
|
||||
/**
|
||||
* 列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/12 09:37
|
||||
*/
|
||||
public function getList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$where['is_del'] = 0;
|
||||
$list = $this->dao->getList($where, '*', $page, $limit, 'add_time desc');
|
||||
$count = $this->dao->count($where);
|
||||
$adminIds = array_column($list, 'admin_id');
|
||||
$batchList = app()->make(SystemAdminServices::class)->search(['id' => $adminIds])->column('real_name', 'id');
|
||||
foreach ($list as &$item) {
|
||||
$item['admin_name'] = $batchList[$item['admin_id']] ?? '';
|
||||
}
|
||||
return compact('list', 'count');
|
||||
}
|
||||
}
|
||||
441
app/services/activity/card/CardGiftServices.php
Normal file
441
app/services/activity/card/CardGiftServices.php
Normal file
@@ -0,0 +1,441 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\card;
|
||||
|
||||
use app\dao\activity\card\CardGiftDao;
|
||||
use app\jobs\activity\card\CardJob;
|
||||
use app\services\BaseServices;
|
||||
use app\services\product\product\StoreDescriptionServices;
|
||||
use app\services\product\product\StoreProductServices;
|
||||
use app\services\product\sku\StoreProductAttrValueServices;
|
||||
use crmeb\services\FormBuilder as Form;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
use think\facade\Route as Url;
|
||||
|
||||
|
||||
/**
|
||||
* 礼品卡
|
||||
* Class CardGiftServices
|
||||
* @package app\services\activity\card
|
||||
* @mixin CardGiftDao
|
||||
*/
|
||||
class CardGiftServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var CardGiftDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected CardGiftDao $dao;
|
||||
|
||||
/**
|
||||
* 列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/12 09:37
|
||||
*/
|
||||
public function getList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$where['is_del'] = 0;
|
||||
$list = $this->dao->getList($where, '*', $page, $limit, 'sort desc,add_time desc');
|
||||
$count = $this->dao->count($where);
|
||||
$bIds = array_column($list, 'batch_id');
|
||||
$batchList = app()->make(CardBatchServices::class)->search(['id', $bIds])->column('name', 'id');
|
||||
foreach ($list as &$item) {
|
||||
$item['batch_name'] = $batchList[$item['batch_id']] ?? '';
|
||||
$item['fixed_time'] = [
|
||||
$item['start_time'] ? date('Y-m-d H:i:s', $item['start_time']) : '',
|
||||
$item['end_time'] ? date('Y-m-d H:i:s', $item['end_time']) : '',
|
||||
];
|
||||
}
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加
|
||||
* @param array $data
|
||||
* @param int $id
|
||||
* @return true
|
||||
* @throws \ReflectionException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/12 09:46
|
||||
*/
|
||||
public function saveData(array $data, int $id = 0, int $admin_id = 0)
|
||||
{
|
||||
if ($id && !$info = $this->dao->get($id)) {
|
||||
throw new ValidateException('礼品卡不存在');
|
||||
}
|
||||
//验证卡密未使用的数量是否超过礼品卡填写的总量
|
||||
if (!$id) {
|
||||
$codeCount = app()->make(CardCodeServices::class)->count(['batch_id' => $data['batch_id'], 'status' => 0, 'card_id' => 0]);
|
||||
if ($codeCount < $data['total_num']) {
|
||||
throw new ValidateException('卡密未使用的数量不能超过礼品卡填写的总量');
|
||||
}
|
||||
}
|
||||
|
||||
if ($data['valid_type'] == 2) {
|
||||
$data['start_time'] = isset($data['fixed_time'][0]) ? strtotime($data['fixed_time'][0]) : 0;
|
||||
$data['end_time'] = isset($data['fixed_time'][1]) ? strtotime($data['fixed_time'][1]) : 0;
|
||||
}
|
||||
unset($data['fixed_time']);
|
||||
$this->transaction(function () use ($id, $data, $admin_id) {
|
||||
$product = $data['product'];
|
||||
$description = $data['description'];
|
||||
unset($data['product'], $data['description']);
|
||||
$data['add_time'] = time();
|
||||
if ($id) {
|
||||
$this->dao->update($id, $data);
|
||||
} else {
|
||||
$res = $this->dao->save($data);
|
||||
$id = $res->id;
|
||||
//修改卡密
|
||||
$this->saveCode($id, $data, $admin_id);
|
||||
|
||||
}
|
||||
app()->make(StoreDescriptionServices::class)->saveDescription($id, $description, 5);
|
||||
//保存礼品卡商品
|
||||
$this->saveProduct($id, $product);
|
||||
return true;
|
||||
});
|
||||
$batch_id = $id ? $info['batch_id'] : $data['batch_id'];
|
||||
//校验卡密使用数量
|
||||
CardJob::dispatchDo('allocationCode', [$batch_id]);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改卡密
|
||||
* @param int $id
|
||||
* @param array $data
|
||||
* @return true
|
||||
* @throws \ReflectionException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/12 09:46
|
||||
*/
|
||||
public function saveCode(int $id, array $data, int $admin_id = 0)
|
||||
{
|
||||
$cardCodeServices = app()->make(CardCodeServices::class);
|
||||
$list = $cardCodeServices->search(['batch_id' => $data['batch_id'], 'status' => 0, 'card_id' => 0])->order('id asc')->limit($data['total_num'])->select()->toArray();
|
||||
if (!$list) {
|
||||
throw new ValidateException('没有可操作的卡密');
|
||||
}
|
||||
$ids = [];
|
||||
$updateData = [
|
||||
'type' => $data['type'],
|
||||
'end_time' => $data['end_time'] ?? 0,
|
||||
'card_id' => $id,
|
||||
'status' => 2,
|
||||
];
|
||||
$str = '';
|
||||
$i = $list[0]['id'];
|
||||
$status = true;
|
||||
foreach ($list as $k => $item) {
|
||||
if ($k == 0) {
|
||||
$str .= $item['card_number'] . '--';
|
||||
} elseif ($k == count($list) - 1) {
|
||||
//获取列表最后一条数据
|
||||
$str .= $item['card_number'];
|
||||
} else {
|
||||
if ($item['id'] != $i) {
|
||||
if ($status) {
|
||||
$str .= $item['card_number'] . ',';
|
||||
$status = false;
|
||||
} else {
|
||||
$str .= $item['card_number'] . '--';
|
||||
$status = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
$i = $item['id'] + 1;
|
||||
$ids[] = $item['id'];
|
||||
// 每满100条插入一次并清空缓存
|
||||
if (count($ids) >= 500) {
|
||||
$cardCodeServices->batchUpdate($ids, $updateData);
|
||||
$ids = [];
|
||||
}
|
||||
}
|
||||
if (count($ids)) {
|
||||
$cardCodeServices->batchUpdate($ids, $updateData);
|
||||
}
|
||||
app()->make(CardGiftRecordServices::class)->save([
|
||||
'gift_id' => $id,
|
||||
'record' => $str,
|
||||
'num' => count($list),
|
||||
'pm' => 1,
|
||||
'add_time' => time(),
|
||||
'admin_id' => $admin_id
|
||||
]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增商品
|
||||
* @param int $id
|
||||
* @param array $productData
|
||||
* @return true
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/12 09:45
|
||||
*/
|
||||
public function saveProduct(int $id, array $productData)
|
||||
{
|
||||
$auxiliary = app()->make(CardGiftAuxiliaryServices::class);
|
||||
$auxiliary->delete(['gift_id' => $id]);
|
||||
$saveData = [];
|
||||
foreach ($productData as $product) {
|
||||
$saveData[] = [
|
||||
'gift_id' => $id,
|
||||
'product_id' => $product['product_id'] ?? 0,
|
||||
'limit_num' => $product['limit_num'] ?? 0,
|
||||
'unique' => $product['unique'] ?? '',
|
||||
];
|
||||
}
|
||||
if (count($saveData)) {
|
||||
$auxiliary->saveAll($saveData);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加卡密表单
|
||||
* @param int $id
|
||||
* @return mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/12 15:41
|
||||
*/
|
||||
public function otherForm(int $id)
|
||||
{
|
||||
$info = $this->dao->get($id);
|
||||
if (!$info) {
|
||||
throw new ValidateException('礼品卡不存在');
|
||||
}
|
||||
$info = $info->toArray();
|
||||
$batchInfo = app()->make(CardBatchServices::class)->get($info['batch_id']);
|
||||
$remain_num = $batchInfo['total_num'] - $batchInfo['used_num'];
|
||||
$remain_num = max($remain_num, 0);
|
||||
$batchName = $batchInfo['name'] . "({$remain_num})";
|
||||
$field[] = Form::input('batch_name', '卡号批次', $batchName)->disabled(true);
|
||||
$field[] = Form::radio('type', '修改数量', $formData['status'] ?? 1)->options([
|
||||
['label' => '增加', 'value' => 1],
|
||||
['label' => '减少', 'value' => 2],
|
||||
]);
|
||||
$field[] = Form::number('number', '数量', 0)->min(0);
|
||||
return create_form('修改数量', $field, Url::buildUrl('/marketing/card/gift/update_other/' . $id), 'POST');
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加卡密提交
|
||||
* @param int $id
|
||||
* @param int $type
|
||||
* @param int $number
|
||||
* @return true
|
||||
* @throws \ReflectionException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/12 15:42
|
||||
*/
|
||||
public function updateOther(int $id, int $type, int $number, int $admin_id)
|
||||
{
|
||||
$info = $this->dao->get($id);
|
||||
if (!$info) {
|
||||
throw new ValidateException('礼品卡不存在');
|
||||
}
|
||||
if ($type == 1) {
|
||||
$total_num = $info->total_num + $number;
|
||||
//增加
|
||||
$count = app()->make(CardCodeServices::class)->count(['batch_id' => $info['batch_id'], 'status' => 0, 'card_id' => 0]);
|
||||
if ($count < $number) {
|
||||
throw new ValidateException('卡密不足');
|
||||
}
|
||||
$this->saveCode($id, ['total_num' => $number, 'batch_id' => $info['batch_id'], 'type' => $info['type']], $admin_id);
|
||||
} else {
|
||||
$total_num = $info->total_num - $number;
|
||||
//减少
|
||||
$count = app()->make(CardCodeServices::class)->count(['batch_id' => $info['batch_id'], 'status' => 2, 'card_id' => $id]);
|
||||
if ($count < $number) {
|
||||
throw new ValidateException('未卡密不足,无法减少,未使用卡密:' . $count);
|
||||
}
|
||||
$cardCodeServices = app()->make(CardCodeServices::class);
|
||||
$list = $cardCodeServices->search(['batch_id' => $info['batch_id'], 'status' => 2, 'card_id' => $id])->order('id asc')->limit($number)->select()->toArray();
|
||||
if (!$list) {
|
||||
throw new ValidateException('没有可操作的卡密');
|
||||
}
|
||||
$ids = [];
|
||||
$updateData = [
|
||||
'type' => 0,
|
||||
'card_id' => 0,
|
||||
'end_time' => 0,
|
||||
'status' => 0,
|
||||
];
|
||||
|
||||
$str = '';
|
||||
$i = $list[0]['id'];
|
||||
$status = true;
|
||||
|
||||
foreach ($list as $k => $item) {
|
||||
//检查 id 是否间断, 如果有给$str追加
|
||||
if ($k == 0) {
|
||||
$str .= $item['card_number'] . '--';
|
||||
} elseif ($k == count($list) - 1) {
|
||||
//获取列表最后一条数据
|
||||
$str .= $item['card_number'];
|
||||
} else {
|
||||
if ($item['id'] != $i) {
|
||||
if ($status) {
|
||||
$str .= $item['card_number'] . ',';
|
||||
$status = false;
|
||||
} else {
|
||||
$str .= $item['card_number'] . '--';
|
||||
$status = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
$i = $item['id'] + 1;
|
||||
$ids[] = $item['id'];
|
||||
// 每满100条插入一次并清空缓存
|
||||
if (count($ids) >= 500) {
|
||||
$cardCodeServices->batchUpdate($ids, $updateData);
|
||||
$ids = [];
|
||||
}
|
||||
}
|
||||
if (count($ids)) {
|
||||
$cardCodeServices->batchUpdate($ids, $updateData);
|
||||
}
|
||||
app()->make(CardGiftRecordServices::class)->save([
|
||||
'gift_id' => $id,
|
||||
'record' => $str,
|
||||
'num' => count($list),
|
||||
'pm' => 2,
|
||||
'add_time' => time(),
|
||||
'admin_id' => $admin_id
|
||||
]);
|
||||
}
|
||||
$info->total_num = $total_num;
|
||||
$info->save();
|
||||
//校验卡密使用数量
|
||||
CardJob::dispatchDo('allocationCode', [$info['batch_id']]);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 详情
|
||||
* @param $id
|
||||
* @return array
|
||||
* @throws \ReflectionException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/12 15:42
|
||||
*/
|
||||
public function getInfo($id)
|
||||
{
|
||||
$info = $this->dao->get($id);
|
||||
if (!$info) {
|
||||
throw new ValidateException('礼品卡不存在');
|
||||
}
|
||||
$info = $info->toArray();
|
||||
$auxiliaryList = app()->make(CardGiftAuxiliaryServices::class)->search(['gift_id' => $id])->select()->toArray();
|
||||
$info['product'] = [];
|
||||
$info['description'] = app()->make(StoreDescriptionServices::class)->getDescription(['product_id' => $id, 'type' => 5]);
|
||||
$info['fixed_time'] = [
|
||||
$info['start_time'] ? date('Y-m-d H:i:s', $info['start_time']) : '',
|
||||
$info['end_time'] ? date('Y-m-d H:i:s', $info['end_time']) : '',
|
||||
];
|
||||
if (!$auxiliaryList) {
|
||||
return $info;
|
||||
}
|
||||
$productIds = array_unique(array_column($auxiliaryList, 'product_id'));
|
||||
$uniques = array_unique(array_column($auxiliaryList, 'unique'));
|
||||
$productList = app()->make(StoreProductServices::class)->search(['id' => $productIds])->column('store_name', 'id');
|
||||
$uniqueList = app()->make(StoreProductAttrValueServices::class)->search(['unique' => $uniques])->column('unique,suk,stock,price,image', 'unique');
|
||||
foreach ($auxiliaryList as &$item) {
|
||||
$item['store_name'] = $productList[$item['product_id']] ?? '';
|
||||
$item['suk'] = $uniqueList[$item['unique']]['suk'] ?? '';
|
||||
$item['stock'] = $uniqueList[$item['unique']]['stock'] ?? '';
|
||||
$item['price'] = $uniqueList[$item['unique']]['price'] ?? '';
|
||||
$item['image'] = $uniqueList[$item['unique']]['image'] ?? '';
|
||||
}
|
||||
$info['product'] = $auxiliaryList;
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param $id
|
||||
* @return mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/12 09:45
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
//删除礼品卡,
|
||||
//删除礼品卡商品
|
||||
//删除未使用的礼品卡卡密
|
||||
|
||||
$info = $this->dao->get($id);
|
||||
if (!$info) {
|
||||
throw new ValidateException('礼品卡不存在');
|
||||
}
|
||||
return $this->transaction(function () use ($id, $info) {
|
||||
$res = $this->dao->update($id, ['is_del' => 1]);
|
||||
$res = $res && app()->make(CardGiftAuxiliaryServices::class)->delete(['gift_id' => $id]);
|
||||
$res = $res && app()->make(CardCodeServices::class)->update(['card_id' => $id, 'status' => 2], ['type' => 0, 'status' => 0, 'card_id' => 0]);
|
||||
return !!$res;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取卡礼品树形结构列表
|
||||
* @return array
|
||||
*/
|
||||
public function getTree()
|
||||
{
|
||||
return $this->search(['is_del' => 0])->field('id,name')->order('sort desc,add_time desc')->select()->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用数量矫正
|
||||
* @return
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/24 10:47
|
||||
*/
|
||||
public function allocationCardGift($id)
|
||||
{
|
||||
$info = $this->dao->get($id);
|
||||
$used_num = app()->make(CardCodeServices::class)->search(['card_id' => $id, 'status' => 1])->count();
|
||||
$info->used_num = $used_num;
|
||||
$info->save();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
703
app/services/activity/combination/StoreCombinationServices.php
Normal file
703
app/services/activity/combination/StoreCombinationServices.php
Normal file
@@ -0,0 +1,703 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\combination;
|
||||
|
||||
use app\services\BaseServices;
|
||||
use app\dao\activity\combination\StoreCombinationDao;
|
||||
use app\services\diy\DiyServices;
|
||||
use app\services\order\StoreOrderServices;
|
||||
use app\services\product\ensure\StoreProductEnsureServices;
|
||||
use app\services\product\label\StoreProductLabelServices;
|
||||
use app\services\product\product\StoreDescriptionServices;
|
||||
use app\services\user\UserRelationServices;
|
||||
use app\services\product\product\StoreProductReplyServices;
|
||||
use app\services\product\product\StoreProductServices;
|
||||
use app\services\product\sku\StoreProductAttrServices;
|
||||
use app\services\product\sku\StoreProductAttrValueServices;
|
||||
use app\jobs\product\ProductLogJob;
|
||||
use app\services\user\UserServices;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use crmeb\services\CacheService;
|
||||
use crmeb\services\SystemConfigService;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
/**
|
||||
* 拼团商品
|
||||
* Class StoreCombinationServices
|
||||
* @package app\services\activity\combination
|
||||
* @mixin StoreCombinationDao
|
||||
*/
|
||||
class StoreCombinationServices extends BaseServices
|
||||
{
|
||||
const THODLCEG = 'ykGUKB';
|
||||
|
||||
/**
|
||||
* 商品活动类型
|
||||
*/
|
||||
const TYPE = 2;
|
||||
|
||||
/**
|
||||
* @var StoreCombinationDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreCombinationDao $dao;
|
||||
|
||||
/**
|
||||
* 获取指定条件下的条数
|
||||
* @param array $where
|
||||
*/
|
||||
public function getCount(array $where)
|
||||
{
|
||||
$this->dao->count($where);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $productIds
|
||||
* @return mixed
|
||||
* @author 等风来
|
||||
* @email 136327134@qq.com
|
||||
* @date 2022/11/28
|
||||
*/
|
||||
public function getPinkIdsArrayCache(array $productIds)
|
||||
{
|
||||
return $this->dao->cacheTag()->remember(md5('pink_ids_' . json_encode($productIds)), function () use ($productIds) {
|
||||
return $this->dao->getPinkIdsArray($productIds, ['id']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取是否有拼团商品
|
||||
* */
|
||||
public function validCombination()
|
||||
{
|
||||
return $this->dao->count([
|
||||
'is_del' => 0,
|
||||
'is_show' => 1,
|
||||
'pinkIngTime' => true
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼团商品添加
|
||||
* @param int $id
|
||||
* @param array $data
|
||||
*/
|
||||
public function saveData(int $id, array $data)
|
||||
{
|
||||
/** @var StoreProductServices $storeProductServices */
|
||||
$storeProductServices = app()->make(StoreProductServices::class);
|
||||
$productInfo = $storeProductServices->getOne(['is_del' => 0, 'is_verify' => 1, 'id' => $data['product_id']]);
|
||||
if (!$productInfo) {
|
||||
throw new AdminException('原商品已移入回收站');
|
||||
}
|
||||
if ($productInfo['is_vip_product']) {
|
||||
throw new AdminException("【{$productInfo["store_name"]}】是svip专享");
|
||||
}
|
||||
if ($productInfo['is_presale_product']) {
|
||||
throw new AdminException("【{$productInfo["store_name"]}】是预售商品");
|
||||
}
|
||||
$data['product_type'] = $productInfo['product_type'];
|
||||
$data['type'] = $productInfo['type'] ?? 0;
|
||||
$data['relation_id'] = $productInfo['relation_id'] ?? 0;
|
||||
$custom_form = $productInfo['custom_form'] ?? [];
|
||||
$data['custom_form'] = is_array($custom_form) ? json_encode($custom_form) : $custom_form;
|
||||
$data['system_form_id'] = $productInfo['system_form_id'] ?? 0;
|
||||
$store_label_id = $productInfo['store_label_id'] ?? [];
|
||||
$data['store_label_id'] = is_array($store_label_id) ? implode(',', $store_label_id) : $store_label_id;
|
||||
$ensure_id = $productInfo['ensure_id'] ?? [];
|
||||
$data['ensure_id'] = is_array($ensure_id) ? implode(',', $ensure_id) : $ensure_id;
|
||||
$specs = $productInfo['specs'] ?? [];
|
||||
$data['specs'] = is_array($specs) ? json_encode($specs) : $specs;
|
||||
if ($data['product_type'] !== 0) {
|
||||
$data['delivery_type'] = 2;
|
||||
}
|
||||
if (in_array($data['product_type'], [1, 2, 3])) {
|
||||
$data['freight'] = 2;
|
||||
$data['temp_id'] = 0;
|
||||
$data['postage'] = 0;
|
||||
} else {
|
||||
if ($data['freight'] == 1) {
|
||||
$data['temp_id'] = 0;
|
||||
$data['postage'] = 0;
|
||||
} elseif ($data['freight'] == 2) {
|
||||
$data['temp_id'] = 0;
|
||||
} elseif ($data['freight'] == 3) {
|
||||
$data['postage'] = 0;
|
||||
}
|
||||
if ($data['freight'] == 2 && !$data['postage']) {
|
||||
throw new AdminException('请设置运费金额');
|
||||
}
|
||||
if ($data['freight'] == 3 && !$data['temp_id']) {
|
||||
throw new AdminException('请选择运费模版');
|
||||
}
|
||||
}
|
||||
$description = $data['description'];
|
||||
$detail = $data['attrs'];
|
||||
$items = $data['items'];
|
||||
$data['start_time'] = strtotime($data['section_time'][0]);
|
||||
$data['stop_time'] = strtotime($data['section_time'][1]);
|
||||
if ($data['stop_time'] < strtotime(date('Y-m-d', time()))) throw new AdminException('结束时间不能小于今天');
|
||||
$data['image'] = $data['images'][0] ?? '';
|
||||
$data['images'] = json_encode($data['images']);
|
||||
$data['price'] = min(array_column($detail, 'price'));
|
||||
$data['quota'] = $data['quota_show'] = array_sum(array_column($detail, 'quota'));
|
||||
if ($data['quota'] > $productInfo['stock']) {
|
||||
throw new ValidateException('限量不能超过商品库存');
|
||||
}
|
||||
$data['stock'] = array_sum(array_column($detail, 'stock'));
|
||||
unset($data['section_time'], $data['description'], $data['attrs'], $data['items']);
|
||||
/** @var StoreDescriptionServices $storeDescriptionServices */
|
||||
$storeDescriptionServices = app()->make(StoreDescriptionServices::class);
|
||||
/** @var StoreProductAttrServices $storeProductAttrServices */
|
||||
$storeProductAttrServices = app()->make(StoreProductAttrServices::class);
|
||||
|
||||
$this->transaction(function () use ($id, $data, $description, $detail, $items, $storeDescriptionServices, $storeProductAttrServices) {
|
||||
if ($id) {
|
||||
$res = $this->dao->update($id, $data);
|
||||
if (!$res) throw new AdminException('修改失败');
|
||||
} else {
|
||||
$data['add_time'] = time();
|
||||
$res = $this->dao->save($data);
|
||||
if (!$res) throw new AdminException('添加失败');
|
||||
$id = (int)$res->id;
|
||||
}
|
||||
$storeDescriptionServices->saveDescription((int)$id, $description, 3);
|
||||
$storeProductAttrServices->setItem('store_product_id', $data['product_id']);
|
||||
$skuList = $storeProductAttrServices->validateProductAttr($items, $detail, (int)$id, 3);
|
||||
$storeProductAttrServices->reset();
|
||||
$valueGroup = $storeProductAttrServices->saveProductAttr($skuList, (int)$id, 3);
|
||||
|
||||
$res = true;
|
||||
foreach ($valueGroup as $item) {
|
||||
$res = $res && CacheService::setStock($item['unique'], (int)$item['quota_show'], 3);
|
||||
}
|
||||
if (!$res) {
|
||||
throw new AdminException('占用库存失败');
|
||||
}
|
||||
});
|
||||
|
||||
$this->dao->cacheTag()->clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼团列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function systemPage(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getList($where, $page, $limit);
|
||||
$count = $this->dao->count($where);
|
||||
/** @var StorePinkServices $storePinkServices */
|
||||
$storePinkServices = app()->make(StorePinkServices::class);
|
||||
$countAll = $storePinkServices->getPinkCount([]);
|
||||
$countTeam = $storePinkServices->getPinkCount(['k_id' => 0, 'status' => 2]);
|
||||
$countPeople = $storePinkServices->getPinkCount(['k_id' => 0]);
|
||||
$ids = [];
|
||||
foreach ($list as &$item) {
|
||||
$item['count_people'] = $countPeople[$item['id']] ?? 0;//拼团数量
|
||||
$item['count_people_all'] = $countAll[$item['id']] ?? 0;//参与人数
|
||||
$item['count_people_pink'] = $countTeam[$item['id']] ?? 0;//成团数量
|
||||
$item['stop_status'] = $item['stop_time'] < time() ? 1 : 0;
|
||||
if ($item['is_show']) {
|
||||
if ($item['start_time'] > time()) {
|
||||
$item['start_name'] = '未开始';
|
||||
} else if ($item['stop_time'] < time()) {
|
||||
$item['start_name'] = '已结束';
|
||||
$item['is_show'] = 0;
|
||||
$ids[] = $item['id'];
|
||||
} else if ($item['stop_time'] > time() && $item['start_time'] < time()) {
|
||||
$item['start_name'] = '进行中';
|
||||
}
|
||||
} else {
|
||||
$item['start_name'] = '已结束';
|
||||
}
|
||||
}
|
||||
foreach ($ids as $id) {
|
||||
$this->dao->update($id, ['is_show' => 0]);
|
||||
app()->make(StorePinkServices::class)->update(['cid' => $id, 'status' => 1], ['stop_time' => time()]);
|
||||
}
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取详情
|
||||
* @param int $id
|
||||
* @return array|\think\Model|null
|
||||
*/
|
||||
public function getInfo(int $id)
|
||||
{
|
||||
$info = $this->dao->get($id);
|
||||
if (!$info) {
|
||||
throw new ValidateException('查看的商品不存在!');
|
||||
}
|
||||
if ($info->is_del) {
|
||||
throw new ValidateException('您查看的团团商品已被删除!');
|
||||
}
|
||||
if ($info['start_time'])
|
||||
$start_time = date('Y-m-d H:i:s', $info['start_time']);
|
||||
|
||||
if ($info['stop_time'])
|
||||
$stop_time = date('Y-m-d H:i:s', $info['stop_time']);
|
||||
if (isset($start_time) && isset($stop_time))
|
||||
$info['section_time'] = [$start_time, $stop_time];
|
||||
else
|
||||
$info['section_time'] = [];
|
||||
unset($info['start_time'], $info['stop_time']);
|
||||
$info['price'] = floatval($info['price']);
|
||||
$info['postage'] = floatval($info['postage']);
|
||||
$info['weight'] = floatval($info['weight']);
|
||||
$info['volume'] = floatval($info['volume']);
|
||||
if (!$info['delivery_type']) {
|
||||
$info['delivery_type'] = [1];
|
||||
}
|
||||
if ($info['postage']) {
|
||||
$info['freight'] = 2;
|
||||
} elseif ($info['temp_id']) {
|
||||
$info['freight'] = 3;
|
||||
} else {
|
||||
$info['freight'] = 1;
|
||||
}
|
||||
/** @var StoreDescriptionServices $storeDescriptionServices */
|
||||
$storeDescriptionServices = app()->make(StoreDescriptionServices::class);
|
||||
$info['description'] = $storeDescriptionServices->getDescription(['product_id' => $id, 'type' => 3]);
|
||||
/** @var StoreProductAttrValueServices $storeProductAttrValueServices */
|
||||
$storeProductAttrValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
$info['attrs'] = $storeProductAttrValueServices->attrList($id, $info['product_id'], 3);
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据id获取拼团数据列表
|
||||
* @return array
|
||||
* @throws \ReflectionException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getCombinationList()
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
/** @var StoreProductServices $storeProductServices */
|
||||
$storeProductServices = app()->make(StoreProductServices::class);
|
||||
|
||||
$field = 'id,title,image,price,product_id,people,quota,quota_show,stock';
|
||||
$list = $this->dao->combinationList(['is_del' => 0, 'is_show' => 1, 'pinkIngTime' => true, 'storeProductId' => true], $field, $page, $limit);
|
||||
foreach ($list as &$item) {
|
||||
$item['image'] = set_file_url($item['image']);
|
||||
$item['price'] = floatval($item['price']);
|
||||
$item['product_price'] = floatval($item['product_price']);
|
||||
$item['pink_count'] = max((int)bcsub((string)$item['quota_show'], (string)$item['quota'], 0), 0);
|
||||
$item['brand_name'] = $storeProductServices->productIdByBrandName((int)$item['product_id']);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼团商品详情
|
||||
* @param int $uid
|
||||
* @param int $id
|
||||
* @return array
|
||||
* @throws \Throwable
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function combinationDetail(int $uid, int $id)
|
||||
{
|
||||
$storeInfo = $this->dao->cacheTag()->remember('' . $id, function () use ($id) {
|
||||
$storeInfo = $this->dao->getOne(['id' => $id], '*,title as store_name', ['descriptions', 'total']);
|
||||
if (!$storeInfo) {
|
||||
throw new ValidateException('商品不存在');
|
||||
} else {
|
||||
$storeInfo = $storeInfo->toArray();
|
||||
}
|
||||
return $storeInfo;
|
||||
}, 600);
|
||||
/** @var DiyServices $diyServices */
|
||||
$diyServices = app()->make(DiyServices::class);
|
||||
$infoDiy = $diyServices->getProductDetailDiy();
|
||||
//diy控制参数
|
||||
if (!isset($infoDiy['showService']) || in_array(3, $infoDiy['showService'])) {
|
||||
$storeInfo['specs'] = [];
|
||||
}
|
||||
$configData = SystemConfigService::more(['site_url', 'routine_contact_type', 'site_name', 'share_qrcode', 'store_self_mention', 'store_func_status', 'product_poster_title']);
|
||||
$siteUrl = $configData['site_url'] ?? '';
|
||||
$storeInfo['image'] = set_file_url($storeInfo['image'], $siteUrl);
|
||||
$storeInfo['image_base'] = set_file_url($storeInfo['image'], $siteUrl);
|
||||
$storeInfo['sale_stock'] = 0;
|
||||
if ($storeInfo['stock'] > 0) $storeInfo['sale_stock'] = 1;
|
||||
|
||||
//品牌名称
|
||||
/** @var StoreProductServices $storeProductServices */
|
||||
$storeProductServices = app()->make(StoreProductServices::class);
|
||||
$productInfo = $storeProductServices->getCacheProductInfo((int)$storeInfo['product_id']);
|
||||
$storeInfo['brand_name'] = $storeProductServices->productIdByBrandName((int)$storeInfo['product_id'], $productInfo);
|
||||
$delivery_type = $storeInfo['delivery_type'] ?? $productInfo['delivery_type'];
|
||||
$storeInfo['delivery_type'] = is_string($delivery_type) ? explode(',', $delivery_type) : $delivery_type;
|
||||
$storeInfo['product_show'] = $productInfo['is_show']; // 商品是否上架
|
||||
/**
|
||||
* 判断配送方式
|
||||
*/
|
||||
$storeInfo['delivery_type'] = $storeProductServices->getDeliveryType($storeInfo['type'], $storeInfo['relation_id'], $storeInfo['delivery_type']);
|
||||
$storeInfo['store_label'] = $storeInfo['ensure'] = [];
|
||||
if ($storeInfo['store_label_id']) {
|
||||
/** @var StoreProductLabelServices $storeProductLabelServices */
|
||||
$storeProductLabelServices = app()->make(StoreProductLabelServices::class);
|
||||
$storeInfo['store_label'] = $storeProductLabelServices->getLabelCache($storeInfo['store_label_id'], ['id', 'label_name', 'style_type', 'color', 'bg_color', 'border_color', 'icon']);
|
||||
}
|
||||
if ($storeInfo['ensure_id'] && isset($infoDiy['showService']) && in_array(2, $infoDiy['showService'])) {
|
||||
/** @var StoreProductEnsureServices $storeProductEnsureServices */
|
||||
$storeProductEnsureServices = app()->make(StoreProductEnsureServices::class);
|
||||
$storeInfo['ensure'] = $storeProductEnsureServices->getEnsurCache($storeInfo['ensure_id'], ['id', 'name', 'image', 'desc']);
|
||||
}
|
||||
|
||||
/** @var UserRelationServices $userRelationServices */
|
||||
$userRelationServices = app()->make(UserRelationServices::class);
|
||||
$storeInfo['userCollect'] = $userRelationServices->isProductRelationCache(['uid' => $uid, 'relation_id' => $storeInfo['product_id'], 'type' => 'collect', 'category' => UserRelationServices::CATEGORY_PRODUCT]);
|
||||
$storeInfo['userLike'] = 0;
|
||||
|
||||
|
||||
$storeInfo['small_image'] = get_thumb_water($storeInfo['image']);
|
||||
$data['storeInfo'] = $storeInfo;
|
||||
|
||||
/** @var StorePinkServices $pinkService */
|
||||
$pinkService = app()->make(StorePinkServices::class);
|
||||
[$pink, $pindAll] = $pinkService->getPinkList($id, true, 1);//拼团进行中列表
|
||||
$data['pink_ok_list'] = $pinkService->getPinkOkList($uid);
|
||||
$data['pink_ok_sum'] = $pinkService->getPinkOkSumTotalNum();
|
||||
$data['pink'] = $pink;
|
||||
$data['pindAll'] = $pindAll;
|
||||
|
||||
/** @var StoreOrderServices $storeOrderServices */
|
||||
$storeOrderServices = app()->make(StoreOrderServices::class);
|
||||
$data['buy_num'] = $storeOrderServices->getBuyCount($uid, 3, $id);
|
||||
|
||||
$data['reply'] = [];
|
||||
$data['replyChance'] = $data['replyCount'] = 0;
|
||||
if (isset($infoDiy['showReply']) && $infoDiy['showReply']) {
|
||||
/** @var StoreProductReplyServices $storeProductReplyService */
|
||||
$storeProductReplyService = app()->make(StoreProductReplyServices::class);
|
||||
$reply = $storeProductReplyService->getRecProductReplyCache($storeInfo['product_id'], (int)($infoDiy['replyNum'] ?? 1));
|
||||
$data['reply'] = $reply ? get_thumb_water($reply, 'small', ['pics']) : [];
|
||||
[$replyCount, $goodReply, $replyChance] = $storeProductReplyService->getProductReplyData((int)$storeInfo['product_id']);
|
||||
$data['replyChance'] = $replyChance;
|
||||
$data['replyCount'] = $replyCount;
|
||||
}
|
||||
/** @var StoreProductAttrServices $storeProductAttrServices */
|
||||
$storeProductAttrServices = app()->make(StoreProductAttrServices::class);
|
||||
[$productAttr, $productValue] = $storeProductAttrServices->getProductAttrDetailCache($id, $uid, 0, 3, $storeInfo['product_id'], $productInfo);
|
||||
$data['productAttr'] = $productAttr;
|
||||
$data['productValue'] = $productValue;
|
||||
$data['routine_contact_type'] = sys_config('routine_contact_type', 0);
|
||||
$data['store_func_status'] = (int)($configData['store_func_status'] ?? 1);//门店是否开启
|
||||
$data['store_self_mention'] = $data['store_func_status'] ? (int)($configData['store_self_mention'] ?? 0) : 0;//门店自提是否开启
|
||||
$data['site_name'] = sys_config('site_name');
|
||||
$data['share_qrcode'] = sys_config('share_qrcode', 0);
|
||||
$data['product_poster_title'] = $configData['product_poster_title'] ?? '';
|
||||
//浏览记录
|
||||
ProductLogJob::dispatch(['visit', ['uid' => $uid, 'id' => $id, 'product_id' => $storeInfo['product_id']], 'combination']);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改销量和库存
|
||||
* @param int $num
|
||||
* @param int $CombinationId
|
||||
* @param string $unique
|
||||
* @param int $store_id
|
||||
* @return bool
|
||||
*/
|
||||
public function decCombinationStock(int $num, int $CombinationId, string $unique, int $store_id = 0)
|
||||
{
|
||||
$product_id = $this->dao->value(['id' => $CombinationId], 'product_id');
|
||||
$res = false;
|
||||
if ($product_id) {
|
||||
if ($unique) {
|
||||
/** @var StoreProductAttrValueServices $skuValueServices */
|
||||
$skuValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
//减去拼团商品的sku库存增加销量
|
||||
$res = false !== $skuValueServices->decProductAttrStock($CombinationId, $unique, $num, 3);
|
||||
|
||||
//拼团商品sku
|
||||
$sku = $skuValueServices->value(['product_id' => $CombinationId, 'unique' => $unique, 'type' => 3], 'suk');
|
||||
//平台普通商品sku unique
|
||||
$productUnique = $skuValueServices->value(['suk' => $sku, 'product_id' => $product_id, 'type' => 0], 'unique');
|
||||
/** @var StoreProductServices $services */
|
||||
$services = app()->make(StoreProductServices::class);
|
||||
//商品库存
|
||||
$res = $res && $services->decProductStock($num, $product_id, (string)$productUnique);
|
||||
}
|
||||
$res = $res && false !== $this->dao->decStockIncSales(['id' => $CombinationId, 'type' => 3], $num);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加库存减销量
|
||||
* @param int $num
|
||||
* @param int $CombinationId
|
||||
* @param string $unique
|
||||
* @param int $store_id
|
||||
* @return bool
|
||||
*/
|
||||
public function incCombinationStock(int $num, int $CombinationId, string $unique, int $store_id = 0)
|
||||
{
|
||||
$product_id = $this->dao->value(['id' => $CombinationId], 'product_id');
|
||||
$res = false;
|
||||
if ($product_id) {
|
||||
if ($unique) {
|
||||
/** @var StoreProductAttrValueServices $skuValueServices */
|
||||
$skuValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
//增加拼团商品的sku库存,减去销量
|
||||
$res = false !== $skuValueServices->incProductAttrStock($CombinationId, $unique, $num, 3);
|
||||
|
||||
//拼团商品sku
|
||||
$suk = $skuValueServices->value(['unique' => $unique, 'product_id' => $CombinationId, 'type' => 3], 'suk');
|
||||
//平台商品sku unique
|
||||
$productUnique = $skuValueServices->value(['suk' => $suk, 'product_id' => $product_id, 'type' => 0], 'unique');
|
||||
/** @var StoreProductServices $services */
|
||||
$services = app()->make(StoreProductServices::class);
|
||||
//增加普通商品库存
|
||||
$res = $res && $services->incProductStock($num, $product_id, (string)$productUnique);
|
||||
}
|
||||
//增加拼团库存
|
||||
$res = $res && false !== $this->dao->incStockDecSales(['id' => $CombinationId, 'type' => 3], $num);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一条拼团数据
|
||||
* @param $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCombinationOne($id, $field = '*')
|
||||
{
|
||||
return $this->dao->validProduct($id, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取拼团详情
|
||||
* @param int $uid
|
||||
* @param int $id
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getPinkInfo(int $uid, int $id)
|
||||
{
|
||||
$is_ok = 0;//判断拼团是否完成
|
||||
$userBool = 0;//判断当前用户是否在团内 0未在 1在
|
||||
$pinkBool = 0;//判断拼团是否成功 0未在 1在
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$user = $userServices->getUserCacheInfo($uid);
|
||||
if (!$user) {
|
||||
throw new ValidateException('用户不存在');
|
||||
}
|
||||
/** @var StorePinkServices $pinkService */
|
||||
$pinkService = app()->make(StorePinkServices::class);
|
||||
$pink = $pinkService->getPinkUserOne($id);
|
||||
if (!$pink) throw new ValidateException('参数错误');
|
||||
$pink = $pink->toArray();
|
||||
if (isset($pink['is_refund']) && $pink['is_refund']) {
|
||||
if ($pink['is_refund'] != $pink['id']) {
|
||||
$id = $pink['is_refund'];
|
||||
return $this->getPinkInfo($uid, $id);
|
||||
} else {
|
||||
throw new ValidateException('订单已退款');
|
||||
}
|
||||
}
|
||||
[$pinkAll, $pinkT, $count, $idAll, $uidAll] = $pinkService->getPinkMemberAndPinkK($pink);
|
||||
if ($pinkT['status'] == 2) {
|
||||
$pinkBool = 1;
|
||||
$is_ok = 1;
|
||||
} else if ($pinkT['status'] == 3) {
|
||||
$pinkBool = -1;
|
||||
$is_ok = 0;
|
||||
} else {
|
||||
if ($count < 1) {//组团完成
|
||||
$is_ok = 1;
|
||||
$pinkBool = $pinkService->pinkComplete($uidAll, $idAll, $user['uid'], $pinkT);
|
||||
} else {
|
||||
$pinkBool = $pinkService->pinkFail($pinkAll, $pinkT, $pinkBool);
|
||||
}
|
||||
//更新pinkT 数据 可能成功或失败
|
||||
$pinkT = $pinkService->getPinkUserOne($pinkT['id']);
|
||||
}
|
||||
if (!empty($pinkAll)) {
|
||||
foreach ($pinkAll as $v) {
|
||||
if ($v['uid'] == $user['uid']) $userBool = 1;
|
||||
}
|
||||
}
|
||||
if ($pinkT['uid'] == $user['uid']) $userBool = 1;
|
||||
$combinationOne = $this->getCombinationOne($pink['cid']);
|
||||
if (!$combinationOne) {
|
||||
throw new ValidateException('拼团不存在或已下架,请手动申请退款!');
|
||||
}
|
||||
$combinationOne = $combinationOne->hidden(['mer_id', 'images', 'attr', 'info', 'sort', 'sales', 'stock', 'add_time', 'is_host', 'is_show', 'is_del', 'combination', 'mer_use', 'is_postage', 'postage', 'start_time', 'stop_time', 'cost', 'browse'])->toArray();
|
||||
$combinationOne['pink_count'] = max((int)bcsub((string)$combinationOne['quota_show'], (string)$combinationOne['quota'], 0), 0);
|
||||
|
||||
$data['userInfo']['uid'] = $user['uid'];
|
||||
$data['userInfo']['nickname'] = $user['nickname'];
|
||||
$data['userInfo']['avatar'] = $user['avatar'];
|
||||
$data['is_ok'] = $is_ok;
|
||||
$data['userBool'] = $userBool;
|
||||
$data['pinkBool'] = $pinkBool;
|
||||
$delivery_type = $combinationOne['delivery_type'] ?? [];
|
||||
$combinationOne['delivery_type'] = is_string($delivery_type) ? explode(',', $delivery_type) : $delivery_type;
|
||||
$data['store_combination'] = $combinationOne;
|
||||
$data['pinkT'] = $pinkT;
|
||||
$data['pinkAll'] = $pinkAll;
|
||||
$data['count'] = $count <= 0 ? 0 : $count;
|
||||
$data['store_combination_host'] = $this->dao->getCombinationHost();
|
||||
foreach ($data['store_combination_host'] as &$item) {
|
||||
$item['pink_count'] = max((int)bcsub((string)$item['quota_show'], (string)$item['quota'], 0), 0);
|
||||
}
|
||||
$data['current_pink_order'] = $pinkService->getCurrentPink($id, $user['uid']);
|
||||
|
||||
/** @var StoreProductAttrServices $storeProductAttrServices */
|
||||
$storeProductAttrServices = app()->make(StoreProductAttrServices::class);
|
||||
/** @var StoreProductAttrValueServices $storeProductAttrValueServices */
|
||||
$storeProductAttrValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
|
||||
[$productAttr, $productValue] = $storeProductAttrServices->getProductAttrDetail($combinationOne['id'], $user['uid'], 0, 3, $combinationOne['product_id']);
|
||||
foreach ($productValue as $k => $v) {
|
||||
$productValue[$k]['product_stock'] = $storeProductAttrValueServices->value(['product_id' => $combinationOne['product_id'], 'suk' => $v['suk'], 'type' => 0], 'stock');
|
||||
}
|
||||
$data['store_combination']['productAttr'] = $productAttr;
|
||||
$data['store_combination']['productValue'] = $productValue;
|
||||
$data['store_func_status'] = (int)(sys_config('store_func_status', 1));
|
||||
$data['store_self_mention'] = $data['store_func_status'] ? (int)(sys_config('store_self_mention', 0)) : 0;//门店自提是否开启
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证拼团下单库存限量
|
||||
* @param int $uid
|
||||
* @param int $combinationId
|
||||
* @param int $cartNum
|
||||
* @param string $unique
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function checkCombinationStock(int $uid, int $combinationId, int $cartNum = 1, string $unique = '')
|
||||
{
|
||||
/** @var StoreProductAttrValueServices $attrValueServices */
|
||||
$attrValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
if ($unique == '') {
|
||||
$unique = $attrValueServices->value(['product_id' => $combinationId, 'type' => 3], 'unique');
|
||||
}
|
||||
$attrInfo = $attrValueServices->getOne(['product_id' => $combinationId, 'unique' => $unique, 'type' => 3]);
|
||||
if (!$attrInfo || $attrInfo['product_id'] != $combinationId) {
|
||||
throw new ValidateException('请选择有效的商品属性');
|
||||
}
|
||||
$StoreCombinationInfo = $productInfo = $this->getCombinationOne($combinationId, '*,title as store_name');
|
||||
if (!$StoreCombinationInfo) {
|
||||
throw new ValidateException('该商品已下架或删除');
|
||||
}
|
||||
/** @var StoreOrderServices $orderServices */
|
||||
$orderServices = app()->make(StoreOrderServices::class);
|
||||
$userBuyCount = $orderServices->getBuyCount($uid, 3, $combinationId);
|
||||
if ($StoreCombinationInfo['once_num'] < $cartNum) {
|
||||
throw new ValidateException('每个订单限购' . $StoreCombinationInfo['once_num'] . '件');
|
||||
}
|
||||
if ($StoreCombinationInfo['num'] < ($userBuyCount + $cartNum)) {
|
||||
throw new ValidateException('每人总共限购' . $StoreCombinationInfo['num'] . '件');
|
||||
}
|
||||
|
||||
if ($cartNum > $attrInfo['quota']) {
|
||||
throw new ValidateException('该商品库存不足' . $cartNum);
|
||||
}
|
||||
return [$attrInfo, $unique, $productInfo];
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼团统计
|
||||
* @param $id
|
||||
* @return array
|
||||
*/
|
||||
public function combinationStatistics(int $id)
|
||||
{
|
||||
/** @var StorePinkServices $pinkServices */
|
||||
$pinkServices = app()->make(StorePinkServices::class);
|
||||
/** @var StoreOrderServices $orderServices */
|
||||
$orderServices = app()->make(StoreOrderServices::class);
|
||||
$people_count = $pinkServices->getDistinctCount([['cid', '=', $id]], 'uid', false);
|
||||
$spread_count = $pinkServices->getDistinctCount([['cid', '=', $id], ['k_id', '>', 0]], 'uid', false);
|
||||
$start_count = $pinkServices->count(['cid' => $id, 'k_id' => 0]);
|
||||
$success_count = $pinkServices->count(['cid' => $id, 'k_id' => 0, 'status' => 2]);
|
||||
$pay_price = $orderServices->sum(['type' => 3, 'activity_id' => $id, 'paid' => 1, 'pid' => [0, -1]], 'pay_price', true);
|
||||
$pay_count = $orderServices->getDistinctCount(['type' => 3, 'activity_id' => $id, 'paid' => 1, 'pid' => [0, -1]], 'uid');
|
||||
return compact('people_count', 'spread_count', 'start_count', 'success_count', 'pay_price', 'pay_count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼团订单
|
||||
* @param $id
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function combinationStatisticsOrder(int $id, array $where = [])
|
||||
{
|
||||
/** @var StoreOrderServices $orderServices */
|
||||
$orderServices = app()->make(StoreOrderServices::class);
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $orderServices->activityStatisticsOrder($id, 3, $where, $page, $limit);
|
||||
$where['type'] = 3;
|
||||
$where['activity_id'] = $id;
|
||||
$count = $orderServices->count($where);
|
||||
foreach ($list as &$item) {
|
||||
if ($item['is_del'] || $item['is_system_del']) {
|
||||
$item['status'] = '已删除';
|
||||
} else if ($item['paid'] == 0 && $item['status'] == 0) {
|
||||
$item['status'] = '待付款';
|
||||
} else if ($item['paid'] == 1 && $item['status'] == 4 && in_array($item['shipping_type'], [1, 3]) && $item['refund_status'] == 0) {
|
||||
$item['status'] = '部分发货';
|
||||
} else if ($item['paid'] == 1 && $item['refund_status'] == 2) {
|
||||
$item['status'] = '已退款';
|
||||
} else if ($item['paid'] == 1 && $item['status'] == 5 && $item['refund_status'] == 0) {
|
||||
$item['status'] = $item['shipping_type'] == 2 ? '部分核销' : '部分收货';
|
||||
$item['_status'] = 12;//已支付 部分核销
|
||||
} else if ($item['paid'] == 1 && $item['refund_status'] == 1) {
|
||||
$item['status'] = '申请退款';
|
||||
} else if ($item['paid'] == 1 && $item['refund_status'] == 4) {
|
||||
$item['status'] = '退款中';
|
||||
} else if ($item['paid'] == 1 && $item['status'] == 0 && in_array($item['shipping_type'], [1, 3]) && $item['refund_status'] == 0) {
|
||||
$item['status'] = '未发货';
|
||||
$item['_status'] = 2;//已支付 未发货
|
||||
} else if ($item['paid'] == 1 && in_array($item['status'], [0, 1]) && $item['shipping_type'] == 2 && $item['refund_status'] == 0) {
|
||||
$item['status'] = '未核销';
|
||||
} else if ($item['paid'] == 1 && in_array($item['status'], [1, 5]) && in_array($item['shipping_type'], [1, 3]) && $item['refund_status'] == 0) {
|
||||
$item['status'] = '待收货';
|
||||
} else if ($item['paid'] == 1 && $item['status'] == 2 && $item['refund_status'] == 0) {
|
||||
$item['status'] = '待评价';
|
||||
} else if ($item['paid'] == 1 && $item['status'] == 3 && $item['refund_status'] == 0) {
|
||||
$item['status'] = '已完成';
|
||||
} else if ($item['paid'] == 1 && $item['refund_status'] == 3) {
|
||||
$item['status'] = '部分退款';
|
||||
} else {
|
||||
$item['status'] = '未知';
|
||||
}
|
||||
$item['add_time'] = date('Y-m-d H:i:s', $item['add_time']);
|
||||
$item['pay_time'] = $item['pay_time'] ? date('Y-m-d H:i:s', $item['pay_time']) : '';
|
||||
}
|
||||
return compact('list', 'count');
|
||||
}
|
||||
}
|
||||
806
app/services/activity/combination/StorePinkServices.php
Normal file
806
app/services/activity/combination/StorePinkServices.php
Normal file
@@ -0,0 +1,806 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\combination;
|
||||
|
||||
use app\jobs\activity\pink\AuthPinkFail;
|
||||
use app\services\BaseServices;
|
||||
use app\dao\activity\combination\StorePinkDao;
|
||||
use app\services\order\StoreOrderRefundServices;
|
||||
use app\services\order\StoreOrderServices;
|
||||
use app\services\other\QrcodeServices;
|
||||
use app\services\user\UserServices;
|
||||
use app\jobs\activity\pink\PinkJob;
|
||||
use app\jobs\notice\template\RoutineTemplateJob;
|
||||
use crmeb\services\CacheService;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
/**
|
||||
* 拼团
|
||||
* Class StorePinkServices
|
||||
* @package app\services\activity\combination
|
||||
* @mixin StorePinkDao
|
||||
*/
|
||||
class StorePinkServices extends BaseServices
|
||||
{
|
||||
|
||||
const OXPJOHRW = '/G6B.Z';
|
||||
|
||||
/**
|
||||
* @var StorePinkDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StorePinkDao $dao;
|
||||
|
||||
/**
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function systemPage(array $where)
|
||||
{
|
||||
$where['k_id'] = 0;
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getList($where, $page, $limit);
|
||||
$time = time();
|
||||
foreach ($list as &$item) {
|
||||
$item['count_people'] = $this->dao->count(['k_id' => $item['id']]) + 1;
|
||||
//状态为进行中,实际已经结束的
|
||||
if ($item['status'] == 1 && $item['stop_time'] < $time) {
|
||||
$item['status'] = $item['count_people'] >= $item['people'] ? 2 : 3;
|
||||
}
|
||||
$item['_add_time'] = $item['add_time'] ? date('Y-m-d H:i:s', (int)$item['add_time']) : '';
|
||||
$item['_stop_time'] = $item['stop_time'] ? date('Y-m-d H:i:s', (int)$item['stop_time']) : '';
|
||||
}
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼团列表头部
|
||||
* @return array
|
||||
*/
|
||||
public function getStatistics()
|
||||
{
|
||||
$res = [
|
||||
['col' => 6, 'count' => $this->dao->count(), 'name' => '参与人数(人)', 'className' => 'ios-speedometer-outline'],
|
||||
['col' => 6, 'count' => $this->dao->count(['k_id' => 0, 'status' => 2]), 'name' => '成团数量(个)', 'className' => 'md-rose'],
|
||||
];
|
||||
return compact('res');
|
||||
}
|
||||
|
||||
/**
|
||||
* 参团人员
|
||||
* @param int $id
|
||||
* @return array
|
||||
*/
|
||||
public function getPinkMember(int $id)
|
||||
{
|
||||
return $this->dao->getList(['k_id' => $id, 'is_refund' => 0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼团退款
|
||||
* @param $id
|
||||
* @return bool
|
||||
*/
|
||||
public function setRefundPink($order)
|
||||
{
|
||||
$res = true;
|
||||
if ($order['pink_id']) {
|
||||
$id = $order['pink_id'];
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
//正在拼团 团长
|
||||
$count = $this->dao->getOne(['id' => $id, 'uid' => $order['uid']]);
|
||||
//正在拼团 团员
|
||||
$countY = $this->dao->getOne(['k_id' => $id, 'uid' => $order['uid']]);
|
||||
if (!$count && !$countY) {
|
||||
return $res;
|
||||
}
|
||||
if ($count) {//团长
|
||||
//判断团内是否还有其他人 如果有 团长为第二个进团的人
|
||||
$kCount = $this->dao->getPinking(['k_id' => $id]);
|
||||
if ($kCount) {
|
||||
$res11 = $this->dao->update($id, ['k_id' => $kCount['id']], 'k_id');
|
||||
$res12 = $this->dao->update($kCount['id'], ['stop_time' => $count['add_time'] + 86400]);
|
||||
$res1 = $res11 && $res12;
|
||||
$res2 = $this->dao->update($id, ['stop_time' => time() - 1, 'is_refund' => $kCount['id'], 'status' => 3]);
|
||||
} else {
|
||||
$res1 = true;
|
||||
$res2 = $this->dao->update($id, ['stop_time' => time() - 1, 'is_refund' => $id, 'status' => 3]);
|
||||
}
|
||||
//修改结束时间为前一秒
|
||||
$res = $res1 && $res2;
|
||||
} else if ($countY) {//团员
|
||||
$res = $this->dao->update($countY['id'], ['stop_time' => time() - 1, 'is_refund' => $id, 'status' => 3]);
|
||||
}
|
||||
if ($res) {
|
||||
CacheService::setStock(md5((string)$id), 1, 3, false);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼团详情查看拼团列表
|
||||
* @param int $id
|
||||
* @param bool $type
|
||||
* @param int $status
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getPinkList(int $id, bool $type, int $status = -1)
|
||||
{
|
||||
$where['cid'] = $id;
|
||||
$where['k_id'] = 0;
|
||||
$where['is_refund'] = 0;
|
||||
if ($status !== -1) {
|
||||
$where['status'] = $status;
|
||||
}
|
||||
$list = $this->dao->pinkList($where);
|
||||
$ids = array_column($list, 'id');
|
||||
$counts = $this->dao->getPinkPeopleCount($ids);
|
||||
if ($type) {
|
||||
$pinkAll = [];
|
||||
foreach ($list as &$v) {
|
||||
$v['count'] = $v['people'] - $counts[$v['id']];
|
||||
$v['h'] = date('H', (int)$v['stop_time']);
|
||||
$v['i'] = date('i', (int)$v['stop_time']);
|
||||
$v['s'] = date('s', (int)$v['stop_time']);
|
||||
$pinkAll[] = $v['id'];//开团团长ID
|
||||
$v['stop_time'] = (int)$v['stop_time'];
|
||||
}
|
||||
return [$list, $pinkAll];
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取成团列表信息
|
||||
* @param int $uid
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getPinkOkList(int $uid)
|
||||
{
|
||||
$list = $this->dao->successList($uid, 'id,nickname', 0, 100);
|
||||
$msg = [];
|
||||
foreach ($list as &$item) {
|
||||
if (isset($item['nickname'])) $msg[] = $item['nickname'] .= '拼团成功';
|
||||
}
|
||||
return $msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找拼团信息
|
||||
* @param $pink
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getPinkMemberAndPinkK($pink)
|
||||
{
|
||||
//查找拼团团员和团长
|
||||
if ($pink['k_id']) {
|
||||
$pinkAll = $this->dao->getPinkUserList(['k_id' => $pink['k_id'], 'is_refund' => 0]);
|
||||
$pinkT = $this->dao->getPinkUserOne($pink['k_id']);
|
||||
} else {
|
||||
$pinkAll = $this->dao->getPinkUserList(['k_id' => $pink['id'], 'is_refund' => 0]);
|
||||
$pinkT = $pink;
|
||||
}
|
||||
$count = count($pinkAll) + 1;
|
||||
$count = $pinkT['people'] - $count;
|
||||
$idAll = [];
|
||||
$uidAll = [];
|
||||
//收集拼团用户id和拼团id
|
||||
foreach ($pinkAll as $k => $v) {
|
||||
$idAll[$k] = $v['id'];
|
||||
$uidAll[$k] = $v['uid'];
|
||||
}
|
||||
$idAll[] = $pinkT['id'];
|
||||
$uidAll[] = $pinkT['uid'];
|
||||
return [$pinkAll, $pinkT, $count, $idAll, $uidAll];
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼团失败
|
||||
* @param $pinkAll
|
||||
* @param $pinkT
|
||||
* @param $pinkBool
|
||||
* @param bool $isRunErr
|
||||
* @param bool $isIds
|
||||
* @return array|int
|
||||
*/
|
||||
public function pinkFail($pinkAll, $pinkT, $pinkBool, $isRunErr = true, $isIds = false)
|
||||
{
|
||||
/** @var StoreOrderServices $orderService */
|
||||
$orderService = app()->make(StoreOrderServices::class);
|
||||
/** @var StoreOrderRefundServices $orderRefundService */
|
||||
$orderRefundService = app()->make(StoreOrderRefundServices::class);
|
||||
$pinkIds = [];
|
||||
try {
|
||||
if ($pinkT['stop_time'] < time()) {//拼团时间超时 退款
|
||||
$virtual = $this->virtualCombination($pinkT['id']);
|
||||
if ($virtual) return 1;
|
||||
$pinkBool = -1;
|
||||
$pinkAll[] = $pinkT;
|
||||
$oids = array_column($pinkAll, 'order_id_key');
|
||||
$orders = $orderService->getColumn([['id', 'in', $oids]], '*', 'id');
|
||||
$refundData = [
|
||||
'refund_reason' => '拼团时间超时',
|
||||
'refund_explain' => '拼团时间超时',
|
||||
'refund_img' => json_encode([]),
|
||||
];
|
||||
$refundeOrder = $orderRefundService->getColumn([
|
||||
['store_order_id', 'IN', $oids],
|
||||
['refund_type', 'in', [0, 1, 2, 4, 5]],
|
||||
['is_cancel', '=', 0],
|
||||
['is_del', '=', 0]
|
||||
], 'id,store_order_id', 'store_order_id');
|
||||
foreach ($pinkAll as $v) {
|
||||
if (isset($orders[$v['order_id_key']]) && $order = $orders[$v['order_id_key']]) {
|
||||
if (in_array($v['order_id_key'], $refundeOrder)) {
|
||||
continue;
|
||||
}
|
||||
$res1 = $res2 = true;
|
||||
try {
|
||||
//申请退款
|
||||
$refundId = $orderRefundService->applyRefund((int)$order['id'], (int)$order['uid'], $order, [], 1, (float)$order['pay_price'], $refundData);
|
||||
if ($refundId) {//申请退款成功,自动退款
|
||||
$refund_data = ['pay_price' => $order['pay_price'], 'refund_price' => $order['pay_price']];
|
||||
$res1 = $orderRefundService->agreeRefund((int)$refundId, $refund_data);
|
||||
|
||||
//修改退款单状态
|
||||
$res1 = $res1 && $orderRefundService->update((int)$refundId, ['refund_type' => 6, 'refunded_price' => $order['pay_price'], 'refunded_time' => time()]);
|
||||
//修改订单状态
|
||||
$res1 = $res1 && $orderService->update((int)$order['id'], ['refund_status' => 2, 'refund_type' => 6]);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
|
||||
}
|
||||
|
||||
$res2 = $this->dao->getCount([['uid', '=', $v['uid']], ['is_tpl', '=', 0], ['k_id|id', '=', $pinkT['id']]]);
|
||||
if ($res1 && $res2) {
|
||||
if ($isIds) $pinkIds[] = $v['id'];
|
||||
$this->orderPinkAfterNo($pinkT['uid'], $pinkT['id'], false, $orders[$v['order_id_key']]['is_channel']);
|
||||
} else {
|
||||
if ($isRunErr) return $pinkBool;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($isIds) return $pinkIds;
|
||||
} catch (\Exception $e) {
|
||||
\think\facade\Log::error('拼团超时处理失败,原因:' . $e->getMessage());
|
||||
}
|
||||
return $pinkBool;
|
||||
}
|
||||
|
||||
/**
|
||||
* 失败发送消息和修改状态
|
||||
* @param $uid
|
||||
* @param $pid
|
||||
* @param bool $isRemove
|
||||
* @param $channel
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function orderPinkAfterNo($uid, $pid, $isRemove = false, $channel = '')
|
||||
{
|
||||
$this->dao->update([['id|k_id', '=', $pid]], ['status' => 3, 'stop_time' => time()]);
|
||||
$pink = $this->dao->getOne([['id|k_id', '=', $pid], ['uid', '=', $uid]], '*', ['getProduct']);
|
||||
if ($isRemove) {
|
||||
event('notice.notice', [['uid' => $uid, 'pink' => $pink, 'user_type' => $channel], 'send_order_pink_clone']);
|
||||
} else {
|
||||
event('notice.notice', [['uid' => $uid, 'pink' => $pink, 'user_type' => $channel], 'send_order_pink_fial']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 判断拼团状态
|
||||
* @param $pinkId
|
||||
* @return bool
|
||||
*/
|
||||
public function isPinkStatus($pinkId)
|
||||
{
|
||||
if (!$pinkId) return false;
|
||||
$stopTime = $this->dao->value(['id' => $pinkId], 'stop_time');
|
||||
if ($stopTime < time()) return true; //拼团结束
|
||||
else return false;//拼团未结束
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取拼团order_id
|
||||
* @param int $id
|
||||
* @param int $uid
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCurrentPink(int $id, int $uid)
|
||||
{
|
||||
$oid = $this->dao->value(['id' => $id, 'uid' => $uid], 'order_id_key');
|
||||
if (!$oid) $oid = $this->dao->value(['k_id' => $id, 'uid' => $uid], 'order_id_key');
|
||||
/** @var StoreOrderServices $orderService */
|
||||
$orderService = app()->make(StoreOrderServices::class);
|
||||
return $orderService->value(['id' => $oid], 'order_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼团成功
|
||||
* @param $uidAll
|
||||
* @param $idAll
|
||||
* @param $uid
|
||||
* @param $pinkT
|
||||
* @return int
|
||||
*/
|
||||
public function pinkComplete($uidAll, $idAll, $uid, $pinkT)
|
||||
{
|
||||
$pinkBool = 6;
|
||||
try {
|
||||
if (!$this->dao->getCount([['id', 'in', $idAll], ['is_refund', '=', 1]])) {
|
||||
$this->dao->update([['id', 'in', $idAll]], ['stop_time' => time(), 'status' => 2]);
|
||||
if (in_array($uid, $uidAll)) {
|
||||
if ($this->dao->getCount([['uid', 'in', $uidAll], ['is_tpl', '=', 0], ['k_id|id', '=', $pinkT['id']]]))
|
||||
$this->orderPinkAfter($uidAll, $pinkT['id']);
|
||||
$pinkBool = 1;
|
||||
} else $pinkBool = 3;
|
||||
}
|
||||
return $pinkBool;
|
||||
} catch (\Exception $e) {
|
||||
return $pinkBool;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼团成功修改
|
||||
* @param $uidAll
|
||||
* @param $pid
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function orderPinkAfter($uidAll, $pid)
|
||||
{
|
||||
//发送消息之前去除虚拟用户
|
||||
foreach ($uidAll as $key => $uid) {
|
||||
if ($uid == 0) unset($uidAll[$key]);
|
||||
}
|
||||
/** @var StoreCombinationServices $storeCombinationServices */
|
||||
$storeCombinationServices = app()->make(StoreCombinationServices::class);
|
||||
$pinkInfo = $this->dao->get((int)$pid, ['cid', 'nickname', 'uid']);
|
||||
$title = $storeCombinationServices->value(['id' => $pinkInfo['cid']], 'title');
|
||||
$pinkList = $this->dao->getColumn([['id|k_id', '=', $pid], ['uid', '<>', 0]], '*', 'uid');
|
||||
$order_ids = array_column($pinkList, 'order_id');
|
||||
/** @var StoreOrderServices $orderService */
|
||||
$orderService = app()->make(StoreOrderServices::class);
|
||||
$order_channels = $orderService->getColumn([['order_id', 'in', $order_ids]], 'is_channel', 'order_id');
|
||||
if (!$pinkList) return false;
|
||||
foreach ($pinkList as $item) {
|
||||
//用户发送消息
|
||||
event('notice.notice', [
|
||||
[
|
||||
'list' => $item,
|
||||
'nickname' => $pinkInfo['nickname'],
|
||||
'title' => $title,
|
||||
'user_type' => $order_channels[$item['order_id']],
|
||||
'url' => '/pages/users/order_details/index?order_id=' . $item['order_id']
|
||||
], 'order_user_groups_success']);
|
||||
}
|
||||
$this->dao->update([['uid', 'in', $uidAll], ['id|k_id', '=', $pid]], ['is_tpl' => 1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建拼团
|
||||
* @param $order
|
||||
* @return mixed
|
||||
*/
|
||||
public function createPink(array $orderInfo)
|
||||
{
|
||||
/** @var StoreCombinationServices $services */
|
||||
$services = app()->make(StoreCombinationServices::class);
|
||||
$product = $services->getOne(['id' => $orderInfo['activity_id']], 'effective_time,title,people');
|
||||
if (!$product) {
|
||||
return false;
|
||||
}
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$userInfo = $userServices->get($orderInfo['uid']);
|
||||
if ($orderInfo['pink_id']) {
|
||||
//拼团存在
|
||||
$res = false;
|
||||
$pink['uid'] = $orderInfo['uid'];//用户id
|
||||
$pink['nickname'] = $userInfo['nickname'];
|
||||
$pink['avatar'] = $userInfo['avatar'];
|
||||
if ($this->isPinkBe($pink, $orderInfo['pink_id'])) return false;
|
||||
$pink['order_id'] = $orderInfo['order_id'];//订单id 生成
|
||||
$pink['order_id_key'] = $orderInfo['id'];//订单id 数据库id
|
||||
$pink['total_num'] = $orderInfo['total_num'];//购买个数
|
||||
$pink['total_price'] = $orderInfo['pay_price'];//总金额
|
||||
$pink['k_id'] = $orderInfo['pink_id'];//拼团id
|
||||
foreach ($orderInfo['cartInfo'] as $v) {
|
||||
$pink['cid'] = $v['activity_id'];//拼团商品id
|
||||
$pink['pid'] = $v['product_id'];//商品id
|
||||
$pink['people'] = $product['people'];//几人拼团
|
||||
$pink['price'] = $v['productInfo']['price'];//单价
|
||||
$pink['stop_time'] = 0;//结束时间
|
||||
$pink['add_time'] = time();//开团时间
|
||||
$res = $this->save($pink);
|
||||
}
|
||||
// 拼团团成功发送模板消息
|
||||
event('notice.notice', [['orderInfo' => $orderInfo, 'title' => $product['title'], 'pink' => $pink], 'can_pink_success']);
|
||||
//处理拼团完成
|
||||
[$pinkAll, $pinkT, $count, $idAll, $uidAll] = $this->getPinkMemberAndPinkK($pink);
|
||||
if ($pinkT['status'] == 1) {
|
||||
if (!$count)//组团完成
|
||||
$this->pinkComplete($uidAll, $idAll, $pink['uid'], $pinkT);
|
||||
else
|
||||
$this->pinkFail($pinkAll, $pinkT, 0);
|
||||
}
|
||||
|
||||
if ($res) return true;
|
||||
else return false;
|
||||
} else {
|
||||
//创建拼团
|
||||
$res = false;
|
||||
$pink['uid'] = $orderInfo['uid'];//用户id
|
||||
$pink['nickname'] = $userInfo['nickname'];
|
||||
$pink['avatar'] = $userInfo['avatar'];
|
||||
$pink['order_id'] = $orderInfo['order_id'];//订单id 生成
|
||||
$pink['order_id_key'] = $orderInfo['id'];//订单id 数据库id
|
||||
$pink['total_num'] = $orderInfo['total_num'];//购买个数
|
||||
$pink['total_price'] = $orderInfo['pay_price'];//总金额
|
||||
$pink['k_id'] = 0;//拼团id
|
||||
/** @var StoreOrderServices $orderServices */
|
||||
$orderServices = app()->make(StoreOrderServices::class);
|
||||
foreach ($orderInfo['cartInfo'] as $v) {
|
||||
$pink['cid'] = $v['activity_id'];//拼团商品id
|
||||
$pink['pid'] = $v['product_id'];//商品id
|
||||
$pink['people'] = $product['people'];//几人拼团
|
||||
$pink['price'] = $v['productInfo']['price'];//单价
|
||||
$pink['stop_time'] = time() + $product->effective_time * 3600;//结束时间
|
||||
$pink['add_time'] = time();//开团时间
|
||||
$res1 = $this->dao->save($pink);
|
||||
$res2 = $orderServices->update($orderInfo['id'], ['pink_id' => $res1['id']]);
|
||||
$res = $res1 && $res2;
|
||||
$pink['id'] = $res1['id'];
|
||||
}
|
||||
$number = (int)bcsub((string)$product['people'], '1', 0);
|
||||
if ($number) CacheService::setStock(md5((string)$pink['id']), $number, 3);
|
||||
|
||||
PinkJob::dispatchSece(($product->effective_time * 3600) + 60, [$pink['id']]);
|
||||
event('notice.notice', [['orderInfo' => $orderInfo, 'title' => $product['title'], 'pink' => $pink], 'open_pink_success']);
|
||||
if ($res) return true;
|
||||
else return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否拼团
|
||||
* @param array $data
|
||||
* @param int $id
|
||||
* @return int
|
||||
*/
|
||||
public function isPinkBe(array $data, int $id)
|
||||
{
|
||||
$data['id'] = $id;
|
||||
$count = $this->dao->getCount($data);
|
||||
if ($count) return $count;
|
||||
$data['k_id'] = $id;
|
||||
$count = $this->dao->getCount($data);
|
||||
if ($count) return $count;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 参加拼团成功发送模板消息
|
||||
* @param array $order
|
||||
* @param string $openid
|
||||
* @param string $title
|
||||
* @param $pink
|
||||
* @return mixed
|
||||
*/
|
||||
public function joinPinkSuccessSend(array $order, string $openid, string $title, $pink)
|
||||
{
|
||||
if ($order['is_channel'] == 1) {
|
||||
/** @var UserServices $services */
|
||||
$services = app()->make(UserServices::class);
|
||||
$nickname = $services->value(['uid' => $order['uid']], 'nickname');
|
||||
RoutineTemplateJob::dispatchDo('sendPinkSuccess', [$openid, $title, $nickname, $pink['add_time'], $pink['people'], '/pages/users/order_details/index?order_id=' . $pink['order_id']]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开团发送模板消息
|
||||
* @param array $order
|
||||
* @param string $openid
|
||||
* @param string $title
|
||||
* @param $pink
|
||||
* @return mixed
|
||||
*/
|
||||
public function pinkSuccessSend(array $order, string $openid, string $title, $pink)
|
||||
{
|
||||
if ($order['is_channel'] == 1) {
|
||||
/** @var UserServices $services */
|
||||
$services = app()->make(UserServices::class);
|
||||
$nickname = $services->value(['uid' => $order['uid']], 'nickname');
|
||||
RoutineTemplateJob::dispatchDo('sendPinkSuccess', [$openid, $title, $nickname, $pink['add_time'], $pink['people'], '/pages/users/order_details/index?order_id=' . $pink['order_id']]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消拼团
|
||||
* @param int $uid
|
||||
* @param int $cid
|
||||
* @param int $pink_id
|
||||
* @param null $nextPinkT
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function removePink(int $uid, int $cid, int $pink_id, $nextPinkT = null)
|
||||
{
|
||||
$pinkT = $this->dao->getOne([
|
||||
['uid', '=', $uid],
|
||||
['id', '=', $pink_id],
|
||||
['cid', '=', $cid],
|
||||
['k_id', '=', 0],
|
||||
['is_refund', '=', 0],
|
||||
['status', '=', 1],
|
||||
['stop_time', '>', time()],
|
||||
]);
|
||||
if (!$pinkT) throw new ValidateException('未查到拼团信息,无法取消');
|
||||
[$pinkAll, $pinkT, $count, $idAll, $uidAll] = $this->getPinkMemberAndPinkK($pinkT);
|
||||
if (count($pinkAll)) {
|
||||
$count = $pinkT['people'] - ($this->dao->count(['k_id' => $pink_id, 'is_refund' => 0]) + 1);
|
||||
if ($count) {
|
||||
//拼团未完成,拼团有成员取消开团取 紧跟团长后拼团的人
|
||||
if (isset($pinkAll[0])) $nextPinkT = $pinkAll[0];
|
||||
} else {
|
||||
//拼团完成
|
||||
$this->PinkComplete($uidAll, $idAll, $uid, $pinkT);
|
||||
throw new ValidateException('拼团已完成,无法取消');
|
||||
}
|
||||
}
|
||||
/** @var StoreOrderServices $orderService */
|
||||
$orderService = app()->make(StoreOrderServices::class);
|
||||
/** @var StoreOrderRefundServices $orderRefundService */
|
||||
$orderRefundService = app()->make(StoreOrderRefundServices::class);
|
||||
//取消开团
|
||||
$order = $orderService->get($pinkT['order_id_key']);
|
||||
$refundData = [
|
||||
'refund_reason' => '用户手动取消拼团',
|
||||
'refund_explain' => '用户手动取消拼团',
|
||||
'refund_img' => json_encode([]),
|
||||
];
|
||||
try {
|
||||
$res1 = $orderRefundService->applyRefund((int)$order['id'], (int)$order['uid'], $order, [], 1, (float)$order['pay_price'], $refundData);
|
||||
} catch (\Throwable $e) {
|
||||
$res1 = true;
|
||||
}
|
||||
$res2 = $this->dao->getCount([['uid', '=', $pinkT['uid']], ['k_id|id', '=', $pinkT['id']]]);
|
||||
if ($res1 && $res2) {
|
||||
$this->orderPinkAfterNo($pinkT['uid'], $pinkT['id'], true, $order->is_channel);
|
||||
}
|
||||
//当前团有人的时候
|
||||
if (is_array($nextPinkT)) {
|
||||
$this->dao->update($nextPinkT['id'], ['k_id' => 0, 'status' => 1, 'stop_time' => $pinkT['stop_time']]);
|
||||
$this->dao->update($pinkT['id'], ['k_id' => $nextPinkT['id']], 'k_id');
|
||||
$orderService->update($nextPinkT['order_id'], ['pink_id' => $nextPinkT['id']], 'order_id');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改到期的拼团状态
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* @throws \think\exception\DbException
|
||||
*/
|
||||
public function statusPink(int $page, int $limit)
|
||||
{
|
||||
$pinkListEnd = $this->dao->pinkListEnd()->page($page, $limit)->select()->toArray();
|
||||
foreach ($pinkListEnd as $key => $pink) {
|
||||
[$pinkAll, $pinkT, $count, $idAll, $uidAll] = $this->getPinkMemberAndPinkK($pink);
|
||||
$this->pinkFail($pinkAll, $pinkT, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 放入自动取消拼团队列
|
||||
*/
|
||||
public function useStatusPink()
|
||||
{
|
||||
$pinkEndCount = $this->dao->pinkListEnd()->count();
|
||||
if (!$pinkEndCount) {
|
||||
return;
|
||||
}
|
||||
$pages = ceil($pinkEndCount / 100);
|
||||
for ($i = 1; $i <= $pages; $i++) {
|
||||
AuthPinkFail::dispatch([$i, 100]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 拼团成功
|
||||
* @param array $pinkRegimental 成功的团长编号
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function successPinkEdit(array $pinkRegimental)
|
||||
{
|
||||
if (!count($pinkRegimental)) return true;
|
||||
foreach ($pinkRegimental as $key => &$item) {
|
||||
$pinkList = $this->dao->getColumn(['k_id' => $item], 'id', 'id');
|
||||
$pinkList[] = $item;
|
||||
$pinkList = implode(',', $pinkList);
|
||||
$this->dao->update([['id', 'in', $pinkList]], ['stop_time' => time(), 'status' => 2]);
|
||||
$pinkUidList = $this->dao->getColumn([['id', 'in', $pinkList], ['is_tpl', '=', 0]], 'uid', 'uid');
|
||||
if (count($pinkUidList)) $this->orderPinkAfter($pinkUidList, $item);//发送模板消息
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼团失败
|
||||
* @param array $pinkRegimental 失败的团长编号
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* @throws \think\exception\DbException
|
||||
*/
|
||||
public function failPinkEdit(array $pinkRegimental)
|
||||
{
|
||||
if (!count($pinkRegimental)) return true;
|
||||
foreach ($pinkRegimental as $key => &$item) {
|
||||
$pinkList = $this->dao->getColumn(['k_id' => $item], 'id', 'id');
|
||||
$pinkList[] = $item;
|
||||
$pinkList = implode(',', $pinkList);
|
||||
$refundPinkList = $this->dao->getColumn([['id', 'in', $pinkList]], 'order_id,uid', 'id');
|
||||
if ($refundPinkList) {
|
||||
/** @var StoreOrderRefundServices $orderRefundService */
|
||||
$orderRefundService = app()->make(StoreOrderRefundServices::class);
|
||||
$refundData = [
|
||||
'refund_reason' => '拼团时间超时',
|
||||
'refund_explain' => '拼团时间超时',
|
||||
'refund_img' => json_encode([]),
|
||||
];
|
||||
foreach ($refundPinkList as $key => &$order) {
|
||||
try {
|
||||
$orderRefundService->applyRefund((int)$order['id'], (int)$order['uid'], $order, [], 1, (float)$order['pay_price'], $refundData);//申请退款
|
||||
} catch (\Throwable $e) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->dao->update([['id', 'in', $pinkList]], ['status' => 3]);
|
||||
// $pinkUidList = $this->dao->getColumn([['id', 'in', $pinkList], ['is_tpl', '=', 0]], 'uid', 'uid');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 虚拟拼团
|
||||
* @param $pinkId
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function virtualCombination($pinkId)
|
||||
{
|
||||
$pinkInfo = $this->dao->get($pinkId);
|
||||
$people = $pinkInfo['people'];
|
||||
$count = $this->dao->count(['k_id' => $pinkId]) + 1;
|
||||
$percent1 = bcdiv((string)$count, (string)$people, 2) * 100;
|
||||
/** @var StoreCombinationServices $services */
|
||||
$services = app()->make(StoreCombinationServices::class);
|
||||
$percent2 = $services->value(['id' => $pinkInfo['cid']], 'virtual');
|
||||
if ($percent1 >= $percent2) {
|
||||
$time = time();
|
||||
$num = $people - $count;
|
||||
$data = [];
|
||||
mt_srand();
|
||||
for ($i = 0; $i < $num; $i++) {
|
||||
$data[$i]['uid'] = 0;
|
||||
$data[$i]['nickname'] = substr(md5(time() . rand(1000, 9999)), 0, 12);
|
||||
$data[$i]['avatar'] = sys_config('h5_avatar');
|
||||
$data[$i]['order_id'] = 0;
|
||||
$data[$i]['order_id_key'] = 0;
|
||||
$data[$i]['total_num'] = 0;
|
||||
$data[$i]['total_price'] = 0;
|
||||
$data[$i]['cid'] = $pinkInfo['cid'];
|
||||
$data[$i]['pid'] = $pinkInfo['pid'];
|
||||
$data[$i]['people'] = $people;
|
||||
$data[$i]['price'] = 0;
|
||||
$data[$i]['add_time'] = $time;
|
||||
$data[$i]['stop_time'] = $time;
|
||||
$data[$i]['k_id'] = $pinkInfo['id'];
|
||||
$data[$i]['is_tpl'] = 1;
|
||||
$data[$i]['is_refund'] = 0;
|
||||
$data[$i]['status'] = 2;
|
||||
$data[$i]['is_virtual'] = 1;
|
||||
}
|
||||
//添加虚拟团员
|
||||
$this->dao->saveAll($data);
|
||||
//更改团员状态为拼团成功
|
||||
$this->dao->update($pinkId, ['stop_time' => $time, 'status' => 2], 'k_id');
|
||||
//更改团长为拼团成功
|
||||
$this->dao->update($pinkId, ['stop_time' => $time, 'status' => 2]);
|
||||
$uidAll = $this->dao->getColumn([['id|k_id', '=', $pinkId]], 'uid');
|
||||
$this->orderPinkAfter($uidAll, $pinkId);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取拼团海报详情信息
|
||||
* @param int $id
|
||||
* @param $user
|
||||
* @return mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function posterInfo(int $id, $user)
|
||||
{
|
||||
$pinkInfo = $this->dao->get($id);
|
||||
/** @var StoreCombinationServices $combinationService */
|
||||
$combinationService = app()->make(StoreCombinationServices::class);
|
||||
$storeCombinationInfo = $combinationService->getOne(['id' => $pinkInfo['cid']], '*', ['getPrice']);
|
||||
$data['title'] = $storeCombinationInfo['title'];
|
||||
$data['url'] = '';
|
||||
$data['image'] = $storeCombinationInfo['image'];
|
||||
$data['price'] = $pinkInfo['price'];
|
||||
$data['label'] = $pinkInfo['people'] . '人团';
|
||||
if ($pinkInfo['k_id']) $pinkAll = $this->getPinkMember($pinkInfo['k_id']);
|
||||
else $pinkAll = $this->getPinkMember($pinkInfo['id']);
|
||||
$count = count($pinkAll);
|
||||
$data['msg'] = '划线价¥' . $storeCombinationInfo['product_price'] . ' 还差' . ($pinkInfo['people'] - $count) . '人拼团成功';
|
||||
|
||||
try {
|
||||
$uid = (int)$user['uid'];
|
||||
if (request()->isRoutine()) {
|
||||
//小程序
|
||||
$name = $id . '_' . $uid . '_' . $user['is_promoter'] . '_pink_share_routine.jpg';
|
||||
/** @var QrcodeServices $QrcodeService */
|
||||
$QrcodeService = app()->make(QrcodeServices::class);
|
||||
//生成小程序地址
|
||||
$urlCode = $QrcodeService->getRoutineQrcodePath($id, $uid, 31, $name);
|
||||
$data['url'] = $urlCode;
|
||||
} else {
|
||||
if (sys_config('share_qrcode', 0) && request()->isWechat()) {
|
||||
/** @var QrcodeServices $qrcodeService */
|
||||
$qrcodeService = app()->make(QrcodeServices::class);
|
||||
$data['url'] = $qrcodeService->getTemporaryQrcode('pink-' . $id . '-' . $uid, $uid)->url;
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
947
app/services/activity/coupon/StoreCouponIssueServices.php
Normal file
947
app/services/activity/coupon/StoreCouponIssueServices.php
Normal file
@@ -0,0 +1,947 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\coupon;
|
||||
|
||||
use app\services\BaseServices;
|
||||
use app\dao\activity\coupon\StoreCouponIssueDao;
|
||||
use app\services\order\StoreCartServices;
|
||||
use app\services\other\queue\QueueServices;
|
||||
use app\services\product\brand\StoreBrandServices;
|
||||
use app\services\product\category\StoreProductCategoryServices;
|
||||
use app\services\product\product\StoreProductServices;
|
||||
use app\services\user\member\MemberCardServices;
|
||||
use app\services\user\member\MemberRightServices;
|
||||
use app\services\user\UserServices;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use crmeb\services\FormBuilder;
|
||||
use crmeb\traits\OptionTrait;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class StoreCouponIssueServices
|
||||
* @package app\services\activity\coupon
|
||||
* @mixin StoreCouponIssueDao
|
||||
*/
|
||||
class StoreCouponIssueServices extends BaseServices
|
||||
{
|
||||
use OptionTrait;
|
||||
|
||||
public array $_couponType = [0 => "通用券", 1 => "品类券", 2 => '商品券', 3 => '品牌券'];
|
||||
|
||||
/**
|
||||
* @var StoreCouponIssueDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreCouponIssueDao $dao;
|
||||
|
||||
/**
|
||||
* 获取已发布列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getCouponIssueList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$where['is_del'] = 0;
|
||||
$list = $this->dao->getList($where, $page, $limit);
|
||||
foreach ($list as &$item) {
|
||||
if (!$item['coupon_time']) {
|
||||
$item['coupon_time'] = ceil(($item['end_use_time'] - $item['start_use_time']) / '86400');
|
||||
}
|
||||
$item['coupon_time'] = $item['coupon_time'] . '天';
|
||||
}
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会员优惠券列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getMemberCouponIssueList(array $where, int $page, int $limit, array $with = [])
|
||||
{
|
||||
return $this->dao->getValidList($where, '*', $page, $limit, $with);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增优惠券
|
||||
* @param $data
|
||||
* @return bool
|
||||
*/
|
||||
public function saveCoupon($data)
|
||||
{
|
||||
$data['start_use_time'] = strtotime((string)$data['start_use_time']);
|
||||
$data['end_use_time'] = strtotime((string)$data['end_use_time']);
|
||||
$data['start_time'] = strtotime((string)$data['start_time']);
|
||||
$data['end_time'] = strtotime((string)$data['end_time']);
|
||||
$data['title'] = $data['coupon_title'];
|
||||
$data['remain_count'] = $data['total_count'];
|
||||
$data['add_time'] = time();
|
||||
if ($data['id'] != 0) {
|
||||
$res = $this->dao->update($data['id'], $data);
|
||||
app()->make(StoreCouponUserServices::class)->update(
|
||||
['cid' => $data['id'], 'status' => 0],
|
||||
['coupon_title' => $data['coupon_title'], 'coupon_price' => $data['coupon_price']],
|
||||
);
|
||||
} else {
|
||||
$res = $this->dao->save($data);
|
||||
if ($data['product_id'] !== '' && $res) {
|
||||
$productIds = explode(',', $data['product_id']);
|
||||
$couponData = [];
|
||||
foreach ($productIds as $product_id) {
|
||||
$couponData[] = ['product_id' => $product_id, 'coupon_id' => $res->id];
|
||||
}
|
||||
/** @var StoreCouponProductServices $storeCouponProductService */
|
||||
$storeCouponProductService = app()->make(StoreCouponProductServices::class);
|
||||
$storeCouponProductService->saveAll($couponData);
|
||||
}
|
||||
}
|
||||
if (!$res) throw new AdminException('添加优惠券失败!');
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 修改状态
|
||||
* @param int $id
|
||||
* @return array
|
||||
* @throws \FormBuilder\Exception\FormBuilderException
|
||||
*/
|
||||
public function createForm(int $id)
|
||||
{
|
||||
$issueInfo = $this->dao->get($id);
|
||||
if (-1 == $issueInfo['status'] || 1 == $issueInfo['is_del']) throw new ValidateException('状态错误,无法修改');
|
||||
$f = [FormBuilder::radio('status', '是否开启', $issueInfo['status'])->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]])];
|
||||
return create_form('状态修改', $f, $this->url('/marketing/coupon/released/status/' . $id), 'PUT');
|
||||
}
|
||||
|
||||
/**
|
||||
* 领取记录
|
||||
* @param int $id
|
||||
* @return array
|
||||
*/
|
||||
public function issueLog(int $id)
|
||||
{
|
||||
$coupon = $this->dao->get($id);
|
||||
if (!$coupon) {
|
||||
throw new ValidateException('优惠券不存在');
|
||||
}
|
||||
if ($coupon['category'] != 2) {
|
||||
/** @var StoreCouponIssueUserServices $storeCouponIssueUserService */
|
||||
$storeCouponIssueUserService = app()->make(StoreCouponIssueUserServices::class);
|
||||
return $storeCouponIssueUserService->issueLog(['issue_coupon_id' => $id]);
|
||||
} else {//会员券
|
||||
/** @var StoreCouponUserServices $storeCouponUserService */
|
||||
$storeCouponUserService = app()->make(StoreCouponUserServices::class);
|
||||
return $storeCouponUserService->issueLog(['cid' => $id]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存赠送给用户优惠券
|
||||
* @param int $uid
|
||||
* @param array $couponList
|
||||
* @param string $type
|
||||
* @return array
|
||||
*/
|
||||
public function saveGiveCoupon(int $uid, array $couponList, string $type = 'get')
|
||||
{
|
||||
if (!$uid || !$couponList) {
|
||||
return [];
|
||||
}
|
||||
$couponData = [];
|
||||
$issueUserData = [];
|
||||
$time = time();
|
||||
/** @var StoreCouponIssueUserServices $issueUser */
|
||||
$issueUser = app()->make(StoreCouponIssueUserServices::class);
|
||||
foreach ($couponList as $item) {
|
||||
$data['cid'] = $item['id'];
|
||||
$data['uid'] = $uid;
|
||||
$data['coupon_title'] = $item['title'];
|
||||
$data['coupon_price'] = $item['coupon_price'];
|
||||
$data['use_min_price'] = $item['use_min_price'];
|
||||
if ($item['coupon_time']) {
|
||||
$data['add_time'] = $time;
|
||||
$data['end_time'] = $data['add_time'] + $item['coupon_time'] * 86400;
|
||||
} else {
|
||||
$data['add_time'] = $item['start_use_time'];
|
||||
$data['end_time'] = $item['end_use_time'];
|
||||
}
|
||||
$data['type'] = $type;
|
||||
$issue['uid'] = $uid;
|
||||
$issue['issue_coupon_id'] = $item['id'];
|
||||
$issue['add_time'] = $time;
|
||||
$issueUserData[] = $issue;
|
||||
$couponData[] = $data;
|
||||
if (!$item['is_permanent']) {
|
||||
$remain_count = $item['remain_count'] > 0 ? $item['remain_count'] - 1 : 0;
|
||||
$this->dao->update($item['id'], ['remain_count' => $remain_count]);
|
||||
}
|
||||
unset($data);
|
||||
unset($issue);
|
||||
}
|
||||
if ($couponData) {
|
||||
/** @var StoreCouponUserServices $storeCouponUser */
|
||||
$storeCouponUser = app()->make(StoreCouponUserServices::class);
|
||||
if (!$storeCouponUser->saveAll($couponData)) {
|
||||
throw new AdminException('发劵失败');
|
||||
}
|
||||
}
|
||||
if ($issueUserData) {
|
||||
if (!$issueUser->saveAll($issueUserData)) {
|
||||
throw new AdminException('发劵失败');
|
||||
}
|
||||
}
|
||||
return $couponData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新人礼赠送优惠券
|
||||
* @param int $uid
|
||||
*/
|
||||
public function newcomerGiveCoupon(int $uid)
|
||||
{
|
||||
if (!sys_config('newcomer_status')) {
|
||||
return false;
|
||||
}
|
||||
$status = sys_config('register_coupon_status');
|
||||
if (!$status) {//未开启
|
||||
return true;
|
||||
}
|
||||
$couponIds = sys_config('register_give_coupon', []);
|
||||
if (!$couponIds) {
|
||||
return true;
|
||||
}
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$userInfo = $userServices->getUserInfo($uid);
|
||||
if (!$userInfo) {
|
||||
return true;
|
||||
}
|
||||
$couponList = $this->dao->getGiveCoupon([['id', 'IN', $couponIds]]);
|
||||
if ($couponList) {
|
||||
$this->saveGiveCoupon($uid, $couponList, 'newcomer');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员卡激活赠送优惠券
|
||||
* @param int $uid
|
||||
*/
|
||||
public function levelGiveCoupon(int $uid)
|
||||
{
|
||||
$status = sys_config('level_activate_status');
|
||||
if (!$status) {//是否需要激活
|
||||
return true;
|
||||
}
|
||||
$status = sys_config('level_coupon_status');
|
||||
if (!$status) {//未开启
|
||||
return true;
|
||||
}
|
||||
$couponIds = sys_config('level_give_coupon', []);
|
||||
if (!$couponIds) {
|
||||
return true;
|
||||
}
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$userInfo = $userServices->getUserInfo($uid);
|
||||
if (!$userInfo) {
|
||||
return true;
|
||||
}
|
||||
$couponList = $this->dao->getGiveCoupon([['id', 'IN', $couponIds]]);
|
||||
if ($couponList) {
|
||||
$this->saveGiveCoupon($uid, $couponList, 'activate_level');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关注送优惠券
|
||||
* @param int $uid
|
||||
*/
|
||||
public function userFirstSubGiveCoupon(int $uid)
|
||||
{
|
||||
$couponList = $this->dao->getGiveCoupon(['receive_type' => 2]);
|
||||
if ($couponList) {
|
||||
$this->saveGiveCoupon($uid, $couponList, 'user_first');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 下单之后赠送
|
||||
* @param $uid
|
||||
*/
|
||||
public function orderPayGiveCoupon($uid, $coupon_issue_ids)
|
||||
{
|
||||
if (!$coupon_issue_ids) return [];
|
||||
$couponList = $this->dao->getGiveCoupon([['id', 'IN', $coupon_issue_ids]]);
|
||||
$couponData = [];
|
||||
if ($couponList) {
|
||||
$couponData = $this->saveGiveCoupon($uid, $couponList, 'order');
|
||||
}
|
||||
return $couponData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商品关联
|
||||
* @param int $uid
|
||||
* @param int $product_id
|
||||
* @param string $field
|
||||
* @param int $limit
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getProductCouponList(int $uid, int $product_id, string $field = '*', int $limit = 0)
|
||||
{
|
||||
if ($limit) {
|
||||
$page = 1;
|
||||
} else {
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
}
|
||||
/** @var StoreProductServices $storeProductService */
|
||||
$storeProductService = app()->make(StoreProductServices::class);
|
||||
/** @var StoreProductCategoryServices $storeCategoryService */
|
||||
$storeCategoryService = app()->make(StoreProductCategoryServices::class);
|
||||
|
||||
$productInfo = $storeProductService->getCacheProductInfo($product_id);
|
||||
$cateId = explode(',', $productInfo['cate_id']);
|
||||
$cateId = array_merge($cateId, $storeCategoryService->cateIdByPid($cateId));
|
||||
$cateId = array_diff($cateId, [0]);
|
||||
$brandIds = [];
|
||||
if ($productInfo['brand_id']) {
|
||||
/** @var StoreBrandServices $storeBrandServices */
|
||||
$storeBrandServices = app()->make(StoreBrandServices::class);
|
||||
$brandInfo = $storeBrandServices->get((int)$productInfo['brand_id'], ['id', 'pid']);
|
||||
if ($brandInfo) {
|
||||
$brandIds = $brandInfo->toArray();
|
||||
$brandIds = array_diff($brandIds, [0]);
|
||||
}
|
||||
}
|
||||
$where = ['product_id' => $productInfo['pid'] ?: $product_id, 'cate_id' => $cateId, 'brand_id' => $brandIds];
|
||||
$list = $this->dao->getIssueCouponListNew($uid, $where, $field, $page, $limit);
|
||||
|
||||
foreach ($list as &$item) {
|
||||
$item['coupon_price'] = floatval($item['coupon_price']);
|
||||
$item['use_min_price'] = floatval($item['use_min_price']);
|
||||
$item['is_use'] = $uid && isset($item['used']);
|
||||
$item['use_status'] = 1;
|
||||
if (isset($item['used']) && $item['used']) {
|
||||
$item['use_status'] = $uid && isset($item['used'][0]['status']) && $item['used'][0]['status'] == '未使用' ? 1 : 0;
|
||||
}
|
||||
$item['start_time'] = $item['start_time'] ? date('Y-m-d', $item['start_time']) : 0;
|
||||
$item['end_time'] = $item['end_time'] ? date('Y-m-d', $item['end_time']) : date('Y-m-d', time() + 86400);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取优惠券列表
|
||||
* @param int $uid
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getIssueCouponList(int $uid, array $where, string $field = '*', bool $is_product = false)
|
||||
{
|
||||
|
||||
/** @var StoreProductServices $storeProductService */
|
||||
$storeProductService = app()->make(StoreProductServices::class);
|
||||
/** @var StoreProductCategoryServices $storeCategoryService */
|
||||
$storeCategoryService = app()->make(StoreProductCategoryServices::class);
|
||||
/** @var StoreBrandServices $storeBrandServices */
|
||||
$storeBrandServices = app()->make(StoreBrandServices::class);
|
||||
$cateId = 0;
|
||||
$bandId = 0;
|
||||
$product_id = 0;
|
||||
$coupon_where = [];
|
||||
if ((int)$where['product_id']) {//存在商品
|
||||
$productInfo = $storeProductService->get((int)$where['product_id'], ['id,cate_id', 'brand_id']);
|
||||
$product_id = $where['product_id'];
|
||||
if ($productInfo) {
|
||||
$cateId = $productInfo['cate_id'];
|
||||
if ($cateId) {
|
||||
$cateId = explode(',', $cateId);
|
||||
$cateId = array_merge($cateId, $storeCategoryService->cateIdByPid($cateId));
|
||||
$cateId = array_diff($cateId, [0]);
|
||||
}
|
||||
if ($productInfo['brand_id']) {
|
||||
$brandInfo = $storeBrandServices->get((int)$productInfo['brand_id'], ['id', 'pid']);
|
||||
if ($brandInfo) {
|
||||
$bandId = $brandInfo->toArray();
|
||||
$bandId = array_diff($bandId, [0]);
|
||||
}
|
||||
}
|
||||
if ($where['type'] == 1) {
|
||||
$coupon_where['cate_id'] = $cateId;
|
||||
} elseif ($where['type'] == 2) {
|
||||
$coupon_where['product_id'] = $where['product_id'];
|
||||
} elseif ($where['type'] == 3) {
|
||||
$coupon_where['brand_id'] = $where['brand_id'];
|
||||
} else {
|
||||
$coupon_where = ['product_id' => $product_id, 'cate_id' => $cateId, 'brand_id' => $bandId];
|
||||
}
|
||||
}
|
||||
}
|
||||
$where = array_merge($where, $coupon_where);
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getIssueCouponListNew($uid, $where, $field, $page, $limit);
|
||||
if ($list) {
|
||||
$limit = 1;
|
||||
$field = ['id', 'image', 'store_name', 'price', 'IFNULL(sales,0) + IFNULL(ficti,0) as sales'];
|
||||
$categoryIds = array_unique(array_column($list, 'category_id'));
|
||||
$brandIds = array_unique(array_column($list, 'brand_id'));
|
||||
$category = $brands = [];
|
||||
if ($categoryIds) {
|
||||
$category = $storeCategoryService->getColumn([['id', 'IN', $categoryIds]], 'pid,cate_name', 'id');
|
||||
}
|
||||
if ($brandIds) {
|
||||
$brands = $storeBrandServices->getColumn([['id', 'IN', $brandIds]], 'id,pid', 'id');
|
||||
}
|
||||
foreach ($list as &$item) {
|
||||
$item['coupon_price'] = floatval($item['coupon_price']);
|
||||
$item['use_min_price'] = floatval($item['use_min_price']);
|
||||
$item['is_use'] = false;
|
||||
if ($uid && $item['used'] != null && count($item['used']) >= $item['receive_limit']) $item['is_use'] = true;
|
||||
$item['start_time'] = $item['end_time'] = '';
|
||||
if ($item['coupon_time']) {//领取几天内使用
|
||||
if (isset($item['used']['end_time']) && isset($item['used']['start_time'])) {
|
||||
$item['start_time'] = $item['used']['start_time'] ? date('Y/m/d', $item['used']['start_time']) : '';
|
||||
$item['end_time'] = $item['used']['end_time'] ? date('Y/m/d', $item['used']['end_time']) : '';
|
||||
}
|
||||
} else {//指定时间段使用
|
||||
$item['start_time'] = $item['start_use_time'] ? date('Y/m/d', $item['start_use_time']) : '';
|
||||
$item['end_time'] = $item['end_use_time'] ? date('Y/m/d', $item['end_use_time']) : '';
|
||||
}
|
||||
if (!$is_product) continue;
|
||||
$product_where = [];
|
||||
$product_where['is_show'] = 1;
|
||||
$product_where['is_del'] = 0;
|
||||
$product_where['is_verify'] = 1;
|
||||
$product_where['use_min_price'] = $item['use_min_price'];
|
||||
switch ($item['type']) {
|
||||
case 0:
|
||||
break;
|
||||
case 1://品类券
|
||||
$product_where['salesOrder'] = 'desc';
|
||||
$category_type = ($category[$item['category_id'] ?? 0]['pid'] ?? 0) == 0 ? 1 : 2;
|
||||
if ($category_type == 1) {
|
||||
$product_where['cid'] = $item['category_id'];
|
||||
} else {
|
||||
$product_where['sid'] = $item['category_id'];
|
||||
}
|
||||
break;
|
||||
case 2://商品劵
|
||||
$product_where['salesOrder'] = 'desc';
|
||||
$product_where['ids'] = $item['product_id'];
|
||||
break;
|
||||
case 3://品牌券
|
||||
$product_where['salesOrder'] = 'desc';
|
||||
$product_where['brand_id'] = $brands[$item['brand_id']] ?? [];
|
||||
break;
|
||||
default:
|
||||
$item['products'] = [];
|
||||
}
|
||||
$item['products'] = get_thumb_water($storeProductService->getSearchList($product_where, 0, $limit, $field, $item['type'] == 0 ? 'rand' : '', []));
|
||||
}
|
||||
}
|
||||
$data['list'] = $list;
|
||||
$data['count'] = $this->dao->getIssueCouponCount($where['product_id'], $cateId, $bandId);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 给用户发送优惠券
|
||||
* @param int $uid
|
||||
* @param int $id
|
||||
* @param bool $more
|
||||
* @param string $type
|
||||
* @return mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function issueUserCoupon(int $uid, int $id, bool $more = true, string $type = 'get')
|
||||
{
|
||||
if (!$uid || !$id) {
|
||||
throw new ValidateException('参数异常');
|
||||
}
|
||||
$issueCouponInfo = $this->dao->getInfo((int)$id);
|
||||
if (!$issueCouponInfo) {
|
||||
throw new ValidateException('领取的优惠劵已领完或已过期!');
|
||||
}
|
||||
if ($issueCouponInfo['remain_count'] <= 0 && !$issueCouponInfo['is_permanent']) {
|
||||
throw new ValidateException('抱歉优惠券已经领取完了!');
|
||||
}
|
||||
//领取付费会员券
|
||||
if ($issueCouponInfo['category'] == 2) {
|
||||
/** @var MemberRightServices $memberRightService */
|
||||
$memberRightService = app()->make(MemberRightServices::class);
|
||||
if (!$memberRightService->getMemberRightStatus("coupon")) {
|
||||
throw new ValidateException('暂时无法领取!');
|
||||
}
|
||||
$userServices = app()->make(UserServices::class);
|
||||
if (!$userServices->checkUserIsSvip($uid)) {
|
||||
throw new ValidateException('请先购买付费会员后领取!');
|
||||
}
|
||||
}
|
||||
/** @var StoreCouponIssueUserServices $issueUserService */
|
||||
$issueUserService = app()->make(StoreCouponIssueUserServices::class);
|
||||
/** @var StoreCouponUserServices $couponUserService */
|
||||
$couponUserService = app()->make(StoreCouponUserServices::class);
|
||||
//是否多次领取
|
||||
$receiveCount = $issueUserService->getCount(['uid' => $uid, 'issue_coupon_id' => $id]);
|
||||
if (!$more) {
|
||||
if ($receiveCount >= $issueCouponInfo['receive_limit']) {
|
||||
throw new ValidateException('已领取过该优惠劵!');
|
||||
}
|
||||
}
|
||||
return $this->transaction(function () use ($issueUserService, $uid, $id, $couponUserService, $issueCouponInfo, $type, $receiveCount) {
|
||||
$issueUserService->save(['uid' => $uid, 'issue_coupon_id' => $id, 'add_time' => time()]);
|
||||
$res = $couponUserService->addUserCoupon($uid, $issueCouponInfo, $type);
|
||||
if ($issueCouponInfo['total_count'] > 0) {
|
||||
$issueCouponInfo['remain_count'] -= 1;
|
||||
$issueCouponInfo->save();
|
||||
}
|
||||
$res['receive_count'] = $receiveCount + 1;
|
||||
return $res;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员发放优惠期券
|
||||
* @param $id
|
||||
* @param $uid
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function memberIssueUserCoupon($id, $uid)
|
||||
{
|
||||
$issueCouponInfo = $this->dao->getInfo((int)$id);
|
||||
if ($issueCouponInfo) {
|
||||
/** @var StoreCouponUserServices $couponUserService */
|
||||
$couponUserService = app()->make(StoreCouponUserServices::class);
|
||||
if ($issueCouponInfo->remain_count >= 0 || $issueCouponInfo->is_permanent) {
|
||||
$this->transaction(function () use ($uid, $id, $couponUserService, $issueCouponInfo) {
|
||||
$couponUserService->addMemberUserCoupon($uid, $issueCouponInfo, "send");
|
||||
// 如果会员劵需要限制数量时打开
|
||||
if ($issueCouponInfo['total_count'] > 0) {
|
||||
$issueCouponInfo['remain_count'] -= 1;
|
||||
$issueCouponInfo->save();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 后台发送优惠券
|
||||
* @param $coupon
|
||||
* @param $user
|
||||
* @return bool
|
||||
*/
|
||||
public function setCoupon($coupon, $user, $redisKey, $queueId, $is_single = false)
|
||||
{
|
||||
if ((!$redisKey || !$queueId || !$user) && !$is_single) return false;
|
||||
$data = [];
|
||||
$issueData = [];
|
||||
/** @var StoreCouponUserServices $storeCouponUser */
|
||||
$storeCouponUser = app()->make(StoreCouponUserServices::class);
|
||||
/** @var StoreCouponIssueUserServices $storeCouponIssueUser */
|
||||
$storeCouponIssueUser = app()->make(StoreCouponIssueUserServices::class);
|
||||
/** @var QueueServices $queueService */
|
||||
$queueService = app()->make(QueueServices::class);
|
||||
$i = 0;
|
||||
$time = time();
|
||||
$remainCount = 0;
|
||||
if (!$coupon['is_permanent']) {
|
||||
$count = count($user);
|
||||
$remain_count = $this->dao->value(['id' => $coupon['id']], 'remain_count');
|
||||
if ($remain_count < $count) {
|
||||
$user = array_slice($user, 0, $remain_count);
|
||||
} else {
|
||||
$remainCount = $remain_count - $count;
|
||||
}
|
||||
}
|
||||
foreach ($user as $k => $v) {
|
||||
$data[$i]['cid'] = $coupon['id'];
|
||||
$data[$i]['uid'] = $v;
|
||||
$data[$i]['coupon_title'] = $coupon['title'];
|
||||
$data[$i]['coupon_price'] = $coupon['coupon_price'];
|
||||
$data[$i]['use_min_price'] = $coupon['use_min_price'];
|
||||
$data[$i]['add_time'] = $time;
|
||||
if ($coupon['coupon_time']) {
|
||||
$data[$i]['start_time'] = $time;
|
||||
$data[$i]['end_time'] = $time + $coupon['coupon_time'] * 86400;
|
||||
} else {
|
||||
$data[$i]['start_time'] = $coupon['start_use_time'];
|
||||
$data[$i]['end_time'] = $coupon['end_use_time'];
|
||||
}
|
||||
$data[$i]['type'] = 'send';
|
||||
$issueData[$i]['uid'] = $v;
|
||||
$issueData[$i]['issue_coupon_id'] = $coupon['id'];
|
||||
$issueData[$i]['add_time'] = time();
|
||||
$i++;
|
||||
}
|
||||
$res = $this->transaction(function () use ($data, $issueData, $storeCouponUser, $storeCouponIssueUser) {
|
||||
$res1 = $res2 = true;
|
||||
if ($data) {
|
||||
$res1 = $storeCouponUser->saveAll($data);
|
||||
}
|
||||
if ($issueData) {
|
||||
$res2 = $storeCouponIssueUser->saveAll($issueData);
|
||||
}
|
||||
return $res1 && $res2;
|
||||
});
|
||||
if (!$res) {
|
||||
//发券失败后将队列状态置为失败
|
||||
$queueService->setQueueFail($queueId['id'], $redisKey);
|
||||
} else {
|
||||
if (!$coupon['is_permanent']) {
|
||||
$this->dao->update($coupon['id'], ['remain_count' => $remainCount]);
|
||||
}
|
||||
if ($is_single) return true;
|
||||
//发券成功的用户踢出集合
|
||||
$queueService->doSuccessSremRedis($user, $redisKey, $queueId['type']);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下单可使用的优惠券列表
|
||||
* @param int $uid
|
||||
* @param $cartId
|
||||
* @param bool $new
|
||||
* @param int $shipping_type
|
||||
* @return array
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function beUseableCouponList(int $uid, $cartId, bool $new, int $shipping_type = 1)
|
||||
{
|
||||
/** @var StoreCartServices $services */
|
||||
$services = app()->make(StoreCartServices::class);
|
||||
$cartGroup = $services->getUserProductCartListV1($uid, $cartId, $new, [], $shipping_type);
|
||||
if (isset($cartGroup['deduction']['activity_id']) && !$cartGroup['deduction']['activity_id'] && isset($cartGroup['deduction']['type']) && $cartGroup['deduction']['type'] != 6) {
|
||||
/** @var StoreCouponUserServices $coupServices */
|
||||
$coupServices = app()->make(StoreCouponUserServices::class);
|
||||
return $coupServices->getUseableCouponList($uid, $cartGroup);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**获取单个优惠券类型
|
||||
* @param array $where
|
||||
* @return mixed
|
||||
*/
|
||||
public function getOne(array $where)
|
||||
{
|
||||
if (!$where) throw new AdminException('参数缺失!');
|
||||
return $this->dao->getOne($where);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 俩时间相差月份
|
||||
* @param $date1
|
||||
* @param $date2
|
||||
* @return float|int
|
||||
*/
|
||||
public function getMonthNum($date1, $date2)
|
||||
{
|
||||
$date1_stamp = strtotime($date1);
|
||||
$date2_stamp = strtotime($date2);
|
||||
[$date_1['y'], $date_1['m']] = explode("-", date('Y-m', $date1_stamp));
|
||||
[$date_2['y'], $date_2['m']] = explode("-", date('Y-m', $date2_stamp));
|
||||
return abs($date_1['y'] - $date_2['y']) * 12 + $date_2['m'] - $date_1['m'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 给会员发放优惠券
|
||||
* @param $uid
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function sendMemberCoupon($uid, $couponId = 0)
|
||||
{
|
||||
if (!$uid) return false;
|
||||
/** @var UserServices $userService */
|
||||
$userService = app()->make(UserServices::class);
|
||||
/** @var StoreCouponUserServices $couponUserService */
|
||||
$couponUserService = app()->make(StoreCouponUserServices::class);
|
||||
/** @var MemberRightServices $memberRightService */
|
||||
$memberRightService = app()->make(MemberRightServices::class);
|
||||
/** @var MemberCardServices $memberCardService */
|
||||
$memberCardService = app()->make(MemberCardServices::class);
|
||||
//看付费会员是否开启
|
||||
$isOpenMember = $memberCardService->isOpenMemberCardCache();
|
||||
if (!$isOpenMember) return false;
|
||||
$userInfo = $userService->getUserCacheInfo((int)$uid);
|
||||
//看是否会员过期
|
||||
if ($userInfo['is_ever_level'] == 0 && $userInfo['is_money_level'] > 0 && $userInfo['overdue_time'] < time()) {
|
||||
return false;
|
||||
}
|
||||
//看是否开启会员送券
|
||||
$isSendCoupon = $memberRightService->getMemberRightStatus("coupon");
|
||||
if (!$isSendCoupon) return false;
|
||||
if ($userInfo && (($userInfo['is_money_level'] > 0) || $userInfo['is_ever_level'] == 1)) {
|
||||
$monthNum = $this->getMonthNum(date('Y-m-d H:i:s', time()), date('Y-m-d H:i:s', $userInfo['overdue_time']));
|
||||
if ($couponId) {//手动点击领取
|
||||
$couponWhere['id'] = $couponId;
|
||||
$couponInfo = $this->getMemberCouponIssueList($couponWhere, 0, 0);
|
||||
} else {//主动批量发放
|
||||
$couponWhere['status'] = 1;
|
||||
$couponWhere['category'] = 2;
|
||||
$couponWhere['is_del'] = 0;
|
||||
$couponInfo = $this->getMemberCouponIssueList($couponWhere, 0, 0);
|
||||
}
|
||||
if ($couponInfo) {
|
||||
$couponIds = array_column($couponInfo, 'id');
|
||||
$couponUserMonth = $couponUserService->memberCouponUserGroupBymonth(['uid' => $uid, 'couponIds' => $couponIds]);
|
||||
$getTime = array();
|
||||
if ($couponUserMonth) {
|
||||
$getTime = array_column($couponUserMonth, 'num', 'time');
|
||||
}
|
||||
// 判断这个月是否领取过,而且领全了
|
||||
//if (in_array(date('Y-m', time()), $getTime)) return false;
|
||||
$timeKey = date('Y-m', time());
|
||||
if (array_key_exists($timeKey, $getTime) && $getTime[$timeKey] == count($couponIds)) return false;
|
||||
//判断是否领完所有月份
|
||||
if (count($getTime) >= $monthNum && (array_key_exists($timeKey, $getTime) && $getTime[$timeKey] == count($couponIds)) && $userInfo['is_ever_level'] != 1 && $monthNum > 0) return false;
|
||||
foreach ($couponInfo as $cv) {
|
||||
//看之前是否手动领取过某一张,领取过就不再领取。
|
||||
if (!$couponUserService->getUserCounponByMonth(['uid' => $uid, 'cid' => $cv['id']])) {
|
||||
$this->memberIssueUserCoupon($cv['id'], $uid);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取今日新增优惠券
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getTodayCoupon(int $uid)
|
||||
{
|
||||
$receive_type = [1, 4];
|
||||
if ($uid) {//用户登录 && 不是付费会员
|
||||
/** @var UserServices $userService */
|
||||
$userService = app()->make(UserServices::class);
|
||||
if (!$userService->checkUserIsSvip($uid)) {
|
||||
$receive_type = [1];
|
||||
}
|
||||
}
|
||||
$list = $this->dao->getTodayCoupon($receive_type);
|
||||
foreach ($list as $key => &$item) {
|
||||
$item['start_time'] = $item['start_time'] ? date('Y-m-d', $item['start_time']) : 0;
|
||||
$item['end_time'] = $item['end_time'] ? date('Y-m-d', $item['end_time']) : 0;
|
||||
$item['coupon_price'] = floatval($item['coupon_price']);
|
||||
$item['use_min_price'] = floatval($item['use_min_price']);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取新人券
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getNewCoupon()
|
||||
{
|
||||
$list = $this->dao->getNewCoupon();
|
||||
foreach ($list as &$item) {
|
||||
$item['start_time'] = $item['start_time'] ? date('Y-m-d', $item['start_time']) : 0;
|
||||
$item['end_time'] = $item['end_time'] ? date('Y-m-d', $item['end_time']) : 0;
|
||||
$item['coupon_price'] = floatval($item['coupon_price']);
|
||||
$item['use_min_price'] = floatval($item['use_min_price']);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可以使用优惠券
|
||||
* @param int $uid
|
||||
* @param array $cartList
|
||||
* @param array $promotions
|
||||
* @param bool $isMax
|
||||
* @return array
|
||||
*/
|
||||
public function getCanUseCoupon(int $uid, array $cartList = [], array $promotions = [], bool $isMax = true)
|
||||
{
|
||||
$where = ['receive_type' => 1, 'category' => 1];
|
||||
//传入是付费会员 获取付费会员券
|
||||
$isVip = $this->getItem('isVip', 0);
|
||||
if ($uid && !$isVip) {
|
||||
/** @var UserServices $userService */
|
||||
$userService = app()->make(UserServices::class);
|
||||
$isVip = $userService->checkUserIsSvip($uid);
|
||||
}
|
||||
if ($isVip) {
|
||||
unset($where['category']);
|
||||
}
|
||||
/** @var StoreCouponUserServices $coupServices */
|
||||
$coupServices = app()->make(StoreCouponUserServices::class);
|
||||
//用户持有有效券
|
||||
$userCoupons = $coupServices->getUserAllCoupon($uid);
|
||||
if ($userCoupons) {
|
||||
$where['not_id'] = array_column($userCoupons, 'cid');
|
||||
}
|
||||
$counpons = $this->dao->getValidList($where, '*', 0, 0, ['used' => function ($query) use ($uid) {
|
||||
$query->where('uid', $uid);
|
||||
}]);
|
||||
//用户已经领取的 && 没有领取的
|
||||
$counpons = array_merge($counpons, $userCoupons);
|
||||
$result = [];
|
||||
if ($counpons) {
|
||||
$promotionsList = [];
|
||||
if ($promotions) {
|
||||
$promotionsList = array_combine(array_column($promotions, 'id'), $promotions);
|
||||
}
|
||||
$isOverlay = function ($cart) use ($promotionsList) {
|
||||
$productInfo = $cart['productInfo'] ?? [];
|
||||
if (!$productInfo) {
|
||||
return false;
|
||||
}
|
||||
if (isset($cart['promotions_id']) && $cart['promotions_id']) {
|
||||
foreach ($cart['promotions_id'] as $key => $promotions_id) {
|
||||
$promotions = $promotionsList[$promotions_id] ?? [];
|
||||
if ($promotions && $promotions['promotions_type'] != 4) {
|
||||
$overlay = is_string($promotions['overlay']) ? explode(',', $promotions['overlay']) : $promotions['overlay'];
|
||||
if (!in_array(5, $overlay)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
foreach ($counpons as $coupon) {
|
||||
if (isset($coupon['used']) && $coupon['used']) {//所有优惠券中 已经领取跳过
|
||||
continue;
|
||||
}
|
||||
$price = 0;
|
||||
$count = 0;
|
||||
if (isset($coupon['applicable_type'])) {//已经领取 有效优惠券
|
||||
$coupon['type'] = $coupon['applicable_type'];
|
||||
$coupon['used'] = ['id' => $coupon['id'], 'cid' => $coupon['cid']];
|
||||
}
|
||||
//&& in_array($promotions['promotions_type'], $overlay)
|
||||
switch ($coupon['type']) {
|
||||
case 0:
|
||||
foreach ($cartList as $cart) {
|
||||
if (!$isOverlay($cart)) continue;
|
||||
$price = bcadd((string)$price, (string)bcmul((string)$cart['truePrice'], (string)$cart['cart_num'], 2), 2);
|
||||
$count++;
|
||||
}
|
||||
break;
|
||||
case 1://品类券
|
||||
/** @var StoreProductCategoryServices $storeCategoryServices */
|
||||
$storeCategoryServices = app()->make(StoreProductCategoryServices::class);
|
||||
$cateGorys = $storeCategoryServices->getAllById((int)$coupon['category_id']);
|
||||
if ($cateGorys) {
|
||||
$cateIds = array_column($cateGorys, 'id');
|
||||
foreach ($cartList as $cart) {
|
||||
if (!$isOverlay($cart)) continue;
|
||||
if (isset($cart['productInfo']['cate_id']) && array_intersect(explode(',', $cart['productInfo']['cate_id']), $cateIds)) {
|
||||
$price = bcadd((string)$price, (string)bcmul((string)$cart['truePrice'], (string)$cart['cart_num'], 2), 2);
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
foreach ($cartList as $cart) {
|
||||
if (!$isOverlay($cart)) continue;
|
||||
if (isset($cart['product_id']) && in_array($cart['product_id'], explode(',', $coupon['product_id']))) {
|
||||
$price = bcadd((string)$price, (string)bcmul((string)$cart['truePrice'], (string)$cart['cart_num'], 2), 2);
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3://品牌券
|
||||
/** @var StoreBrandServices $storeBrandServices */
|
||||
$storeBrandServices = app()->make(StoreBrandServices::class);
|
||||
$brands = $storeBrandServices->getAllById((int)$coupon['brand_id']);
|
||||
if ($brands) {
|
||||
$brandIds = array_column($brands, 'id');
|
||||
foreach ($cartList as $cart) {
|
||||
if (!$isOverlay($cart)) continue;
|
||||
if (isset($cart['productInfo']['brand_id']) && in_array($cart['productInfo']['brand_id'], $brandIds)) {
|
||||
$price = bcadd((string)$price, (string)bcmul((string)$cart['truePrice'], (string)$cart['cart_num'], 2), 2);
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ($count && $coupon['use_min_price'] <= $price) {
|
||||
//满减券
|
||||
if ($coupon['coupon_type'] == 1) {
|
||||
$couponPrice = $coupon['coupon_price'] > $price ? $price : $coupon['coupon_price'];
|
||||
} else {
|
||||
if ($coupon['coupon_price'] <= 0) {//0折
|
||||
$couponPrice = $price;
|
||||
} else if ($coupon['coupon_price'] >= 100) {
|
||||
$couponPrice = 0;
|
||||
} else {
|
||||
$truePrice = (float)bcmul((string)$price, bcdiv((string)$coupon['coupon_price'], '100', 2), 2);
|
||||
$couponPrice = (float)bcsub((string)$price, (string)$truePrice, 2);
|
||||
}
|
||||
}
|
||||
$coupon['coupon_price'] = floatval($coupon['coupon_price']);
|
||||
$coupon['use_min_price'] = floatval($coupon['use_min_price']);
|
||||
$coupon['true_coupon_price'] = $couponPrice;
|
||||
$result[] = $coupon;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($result) {
|
||||
$trueCouponPrice = array_column($result, 'true_coupon_price');
|
||||
array_multisort($trueCouponPrice, SORT_DESC, $result);
|
||||
}
|
||||
//最优的一个
|
||||
if ($isMax) {
|
||||
$useCoupon = $result[0] ?? [];
|
||||
return $useCoupon;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\coupon;
|
||||
|
||||
use app\services\BaseServices;
|
||||
use app\dao\activity\coupon\StoreCouponIssueUserDao;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* Class StoreCouponIssueUserServices
|
||||
* @package app\services\activity\coupon
|
||||
* @mixin StoreCouponIssueUserDao
|
||||
*/
|
||||
class StoreCouponIssueUserServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var StoreCouponIssueUserDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreCouponIssueUserDao $dao;
|
||||
|
||||
/**
|
||||
* 获取列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function issueLog(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getList($where, $page, $limit);
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
}
|
||||
33
app/services/activity/coupon/StoreCouponProductServices.php
Normal file
33
app/services/activity/coupon/StoreCouponProductServices.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\coupon;
|
||||
|
||||
use app\services\BaseServices;
|
||||
use app\dao\activity\coupon\StoreCouponProductDao;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* Class StoreCouponProductServices
|
||||
* @package app\services\activity\coupon
|
||||
* @mixin StoreCouponProductDao
|
||||
*/
|
||||
class StoreCouponProductServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var StoreCouponProductDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreCouponProductDao $dao;
|
||||
|
||||
|
||||
}
|
||||
197
app/services/activity/coupon/StoreCouponService.php
Normal file
197
app/services/activity/coupon/StoreCouponService.php
Normal file
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\activity\coupon;
|
||||
|
||||
|
||||
use app\dao\activity\coupon\StoreCouponDao;
|
||||
use app\services\BaseServices;
|
||||
use app\services\product\category\StoreProductCategoryServices;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use crmeb\services\FormBuilder as Form;
|
||||
use think\annotation\Inject;
|
||||
use think\facade\Route as Url;
|
||||
|
||||
/**
|
||||
* Class StoreCouponService
|
||||
* @package app\services\activity\coupon
|
||||
* @mixin StoreCouponDao
|
||||
*/
|
||||
class StoreCouponService extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var StoreCouponDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreCouponDao $dao;
|
||||
|
||||
/**
|
||||
* 获取列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function getList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$where['is_del'] = 0;
|
||||
$list = $this->dao->getList($where, $page, $limit);
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加优惠券表单
|
||||
* @param int $type
|
||||
* @return array
|
||||
* @throws \FormBuilder\Exception\FormBuilderException
|
||||
*/
|
||||
public function createForm(int $type)
|
||||
{
|
||||
$f[] = Form::input('title', '优惠券名称');
|
||||
switch ($type) {
|
||||
case 1://品类券
|
||||
$options = function () {
|
||||
/** @var StoreProductCategoryServices $storeCategoryService */
|
||||
$storeCategoryService = app()->make(StoreProductCategoryServices::class);
|
||||
$list = $storeCategoryService->getTierList(1, 1);
|
||||
$menus = [];
|
||||
foreach (sort_list_tier($list) as $menu) {
|
||||
$menus[] = ['value' => $menu['id'], 'label' => $menu['html'] . $menu['cate_name'], 'disabled' => false];
|
||||
}
|
||||
|
||||
return $menus;
|
||||
};
|
||||
$f[] = Form::select('category_id', '选择品类')->setOptions(Form::setOptions($options))->filterable(1)->col(12);
|
||||
break;
|
||||
case 2://商品券
|
||||
$f[] = Form::frameImages('image', '商品', Url::buildUrl('admin/store.StoreProduct/index', array('fodder' => 'image', 'type' => 'many')))->icon('ios-add')->width('960px')->height('430px')->modal(['footer-hide' => true])->props(['srcKey' => 'image']);
|
||||
$f[] = Form::hidden('product_id', '');
|
||||
break;
|
||||
}
|
||||
$f[] = Form::number('coupon_price', '优惠券面值', 0)->min(0);
|
||||
$f[] = Form::number('use_min_price', '优惠券最低消费', 0)->min(0);
|
||||
$f[] = Form::number('coupon_time', '优惠券有效期限', 0)->min(0);
|
||||
$f[] = Form::number('sort', '排序', 1)->min(0);
|
||||
$f[] = Form::radio('status', '状态', 1)->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]]);
|
||||
$f[] = Form::hidden('type', $type);
|
||||
return create_form('添加优惠券', $f, Url::buildUrl('/marketing/coupon/save'), 'POST');
|
||||
}
|
||||
|
||||
/**
|
||||
* 优惠卷模板修改表单
|
||||
* @param int $id
|
||||
* @return array
|
||||
* @throws \FormBuilder\Exception\FormBuilderException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function createIssue(int $id)
|
||||
{
|
||||
$res = $this->dao->getOne(['id' => $id, 'status' => 1, 'is_del' => 0]);
|
||||
if (!$res) throw new AdminException('发布的优惠劵已失效或不存在!');
|
||||
$f = [];
|
||||
$f[] = Form::input('id', '优惠劵ID', $id)->disabled(1);
|
||||
$f[] = Form::input('coupon_title', '优惠劵名称', $res['title'])->disabled(1);
|
||||
$f[] = Form::dateTimeRange('range_date', '领取时间')->placeholder('不填为永久有效');
|
||||
$f[] = Form::radio('is_permanent', '是否限量', 1)->options([['label' => '不限量', 'value' => 1], ['label' => '限量', 'value' => 0]]);
|
||||
$f[] = Form::number('count', '发布数量', 0)->min(0)->placeholder('不填或填0,为不限量');
|
||||
$f[] = Form::radio('is_type', '优惠券类型', 0)->options([['label' => '普通券', 'value' => 0], ['label' => '赠送券', 'value' => 1], ['label' => '新人券', 'value' => 2]]);
|
||||
$f[] = Form::number('full_reduction', '满赠金额', 0)->min(0)->placeholder('赠送优惠券的最低消费金额');
|
||||
$f[] = Form::radio('status', '状态', 1)->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]]);
|
||||
return create_form('发布优惠券', $f, $this->url('/marketing/coupon/issue/' . $id), 'POST');
|
||||
}
|
||||
|
||||
/**
|
||||
* 发布优惠券
|
||||
* @param int $id
|
||||
* @param int $_id
|
||||
* @param string $coupon_title
|
||||
* @param array $rangeTime
|
||||
* @param int $count
|
||||
* @param int $status
|
||||
* @param int $is_permanent
|
||||
* @param float $full_reduction
|
||||
* @param int $is_give_subscribe
|
||||
* @param int $is_full_give
|
||||
* @param int $is_type
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function upIssue(int $id, int $_id, string $coupon_title, array $rangeTime, int $count, int $status, int $is_permanent, float $full_reduction, int $is_give_subscribe, int $is_full_give, int $is_type)
|
||||
{
|
||||
if ($is_type == 1) {
|
||||
$is_full_give = 1;
|
||||
} elseif ($is_type == 2) {
|
||||
$is_give_subscribe = 1;
|
||||
}
|
||||
if ($_id != $id) throw new AdminException('操作失败,信息不对称');
|
||||
if (!$count) $count = 0;
|
||||
$couponInfo = $this->dao->getOne(['id' => $id, 'status' => 1, 'is_del' => 0]);
|
||||
if (!$couponInfo) throw new AdminException('发布的优惠劵已失效或不存在!');
|
||||
if (count($rangeTime) != 2) throw new AdminException('请选择正确的时间区间');
|
||||
[$startTime, $endTime] = $rangeTime;
|
||||
if (!$startTime) $startTime = 0;
|
||||
if (!$endTime) $endTime = 0;
|
||||
if (!$startTime && $endTime) throw new AdminException('请选择正确的开始时间');
|
||||
if ($startTime && !$endTime) throw new AdminException('请选择正确的结束时间');
|
||||
$data['cid'] = $id;
|
||||
$data['coupon_title'] = $coupon_title;
|
||||
$data['start_time'] = strtotime($startTime);
|
||||
$data['end_time'] = strtotime($endTime);
|
||||
$data['total_count'] = $count;
|
||||
$data['remain_count'] = $count;
|
||||
$data['is_permanent'] = $is_permanent;
|
||||
$data['status'] = $status;
|
||||
$data['is_give_subscribe'] = $is_give_subscribe;
|
||||
$data['is_full_give'] = $is_full_give;
|
||||
$data['full_reduction'] = $full_reduction;
|
||||
$data['is_del'] = 0;
|
||||
$data['add_time'] = time();
|
||||
$data['title'] = $couponInfo['title'];
|
||||
$data['integral'] = $couponInfo['integral'];
|
||||
$data['coupon_price'] = $couponInfo['coupon_price'];
|
||||
$data['use_min_price'] = $couponInfo['use_min_price'];
|
||||
$data['coupon_time'] = $couponInfo['coupon_time'];
|
||||
$data['product_id'] = $couponInfo['product_id'];
|
||||
$data['category_id'] = $couponInfo['category_id'];
|
||||
$data['type'] = $couponInfo->getData('type');
|
||||
/** @var StoreCouponIssueServices $storeCouponIssueService */
|
||||
$storeCouponIssueService = app()->make(StoreCouponIssueServices::class);
|
||||
$res = $storeCouponIssueService->save($data);
|
||||
$productIds = explode(',', $data['product_id']);
|
||||
if (count($productIds)) {
|
||||
$couponData = [];
|
||||
foreach ($productIds as $product_id) {
|
||||
$couponData[] = ['product_id' => $product_id, 'coupon_id' => $res->id];
|
||||
}
|
||||
/** @var StoreCouponProductServices $storeCouponProductService */
|
||||
$storeCouponProductService = app()->make(StoreCouponProductServices::class);
|
||||
$storeCouponProductService->saveAll($couponData);
|
||||
}
|
||||
if (!$res) throw new AdminException('发布优惠劵失败!');
|
||||
}
|
||||
|
||||
/**
|
||||
* 优惠券失效
|
||||
* @param int $id
|
||||
*/
|
||||
public function invalid(int $id)
|
||||
{
|
||||
$res = $this->dao->update($id, ['status' => 0]);
|
||||
if (!$res) throw new AdminException('操作失败');
|
||||
/** @var StoreCouponIssueServices $storeCouponIssueService */
|
||||
$storeCouponIssueService = app()->make(StoreCouponIssueServices::class);
|
||||
$storeCouponIssueService->update($id, ['status' => -1], 'cid');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\activity\coupon;
|
||||
|
||||
|
||||
use app\dao\activity\coupon\StoreCouponUserCouponDao;
|
||||
use app\services\BaseServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* 根据下单金额获取用户能使用的优惠卷
|
||||
* Class StoreCouponUserCouponServices
|
||||
* @package app\services\activity\coupon
|
||||
* @mixin StoreCouponUserCouponDao
|
||||
*/
|
||||
class StoreCouponUserCouponServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var StoreCouponUserCouponDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreCouponUserCouponDao $dao;
|
||||
|
||||
}
|
||||
497
app/services/activity/coupon/StoreCouponUserServices.php
Normal file
497
app/services/activity/coupon/StoreCouponUserServices.php
Normal file
@@ -0,0 +1,497 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\coupon;
|
||||
|
||||
use app\services\activity\promotions\StorePromotionsServices;
|
||||
use app\services\BaseServices;
|
||||
use app\services\product\brand\StoreBrandServices;
|
||||
use app\services\user\UserServices;
|
||||
use app\dao\activity\coupon\StoreCouponUserDao;
|
||||
use app\services\product\category\StoreProductCategoryServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* Class StoreCouponUserServices
|
||||
* @package app\services\activity\coupon
|
||||
* @mixin StoreCouponUserDao
|
||||
*/
|
||||
class StoreCouponUserServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var StoreCouponUserDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreCouponUserDao $dao;
|
||||
|
||||
/**
|
||||
* 获取列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function issueLog(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getList($where, 'uid,add_time', ['userInfo'], $page, $limit);
|
||||
foreach ($list as &$item) {
|
||||
$item['add_time'] = date('Y-m-d H:i:s', $item['add_time']);
|
||||
}
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function systemPage(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getList($where, '*', ['issue'], $page, $limit);
|
||||
$count = 0;
|
||||
if ($list) {
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$userAll = $userServices->getColumn([['uid', 'IN', array_column($list, 'uid')]], 'uid,nickname', 'uid');
|
||||
foreach ($list as &$item) {
|
||||
$item['nickname'] = $userAll[$item['uid']]['nickname'] ?? '';
|
||||
}
|
||||
$count = $this->dao->count($where);
|
||||
}
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户优惠券
|
||||
* @param int $id
|
||||
* @param int $status
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getUserCouponList(int $id, int $status = -1)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$where = ['uid' => $id];
|
||||
if ($status != -1) $where['status'] = $status;
|
||||
$list = $this->dao->getList($where, '*', ['issue'], $page, $limit);
|
||||
foreach ($list as &$item) {
|
||||
$item['_add_time'] = date('Y-m-d H:i:s', $item['add_time']);
|
||||
$item['_end_time'] = date('Y-m-d H:i:s', $item['end_time']);
|
||||
if (!$item['coupon_time']) {
|
||||
$item['coupon_time'] = ceil(($item['end_use_time'] - $item['start_use_time']) / '86400');
|
||||
}
|
||||
}
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复优惠券
|
||||
* @param int $id
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function recoverCoupon(int $id)
|
||||
{
|
||||
$status = $this->dao->value(['id' => $id], 'status');
|
||||
if ($status) return $this->dao->update($id, ['status' => 0, 'use_time' => 0]);
|
||||
else return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 过期优惠卷失效
|
||||
*/
|
||||
public function checkInvalidCoupon($uid = 0)
|
||||
{
|
||||
$this->dao->update([['uid', '=', $uid], ['end_time', '<', time()], ['status', '=', '0']], ['status' => 2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户有效优惠劵数量
|
||||
* @param int $uid
|
||||
* @return int
|
||||
*/
|
||||
public function getUserValidCouponCount(int $uid)
|
||||
{
|
||||
$this->checkInvalidCoupon($uid);
|
||||
return $this->dao->getCount(['uid' => $uid, 'status' => 0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下单页面显示可用优惠券
|
||||
* @param $uid
|
||||
* @param $cartGroup
|
||||
* @param $price
|
||||
* @return array
|
||||
*/
|
||||
public function getUseableCouponList(int $uid, array $cartGroup)
|
||||
{
|
||||
$userCoupons = $this->dao->getUserAllCoupon($uid);
|
||||
$result = [];
|
||||
if ($userCoupons) {
|
||||
$cartInfo = $cartGroup['valid'];
|
||||
$promotions = $cartGroup['promotions'] ?? [];
|
||||
$promotionsList = [];
|
||||
if ($promotions) {
|
||||
$promotionsList = array_combine(array_column($promotions, 'id'), $promotions);
|
||||
}
|
||||
$isOverlay = function ($cart) use ($promotionsList) {
|
||||
$productInfo = $cart['productInfo'] ?? [];
|
||||
if (!$productInfo) {
|
||||
return false;
|
||||
}
|
||||
if (isset($cart['promotions_id']) && $cart['promotions_id']) {
|
||||
foreach ($cart['promotions_id'] as $key => $promotions_id) {
|
||||
$promotions = $promotionsList[$promotions_id] ?? [];
|
||||
if ($promotions && $promotions['promotions_type'] != 4) {
|
||||
$overlay = is_string($promotions['overlay']) ? explode(',', $promotions['overlay']) : $promotions['overlay'];
|
||||
if (!in_array(5, $overlay)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
/** @var StoreProductCategoryServices $storeCategoryServices */
|
||||
$storeCategoryServices = app()->make(StoreProductCategoryServices::class);
|
||||
/** @var StoreBrandServices $storeBrandServices */
|
||||
$storeBrandServices = app()->make(StoreBrandServices::class);
|
||||
foreach ($userCoupons as $coupon) {
|
||||
$price = 0;
|
||||
$count = 0;
|
||||
switch ($coupon['applicable_type']) {
|
||||
case 0:
|
||||
foreach ($cartInfo as $cart) {
|
||||
if (!$isOverlay($cart)) continue;
|
||||
$price = bcadd((string)$price, (string)bcmul((string)$cart['truePrice'], (string)$cart['cart_num'], 2), 2);
|
||||
$count++;
|
||||
}
|
||||
break;
|
||||
case 1://品类券
|
||||
$cateGorys = $storeCategoryServices->getAllById((int)$coupon['category_id']);
|
||||
if ($cateGorys) {
|
||||
$cateIds = array_column($cateGorys, 'id');
|
||||
foreach ($cartInfo as $cart) {
|
||||
if (!$isOverlay($cart)) continue;
|
||||
if (isset($cart['productInfo']['cate_id']) && array_intersect(explode(',', $cart['productInfo']['cate_id']), $cateIds)) {
|
||||
$price = bcadd((string)$price, (string)bcmul((string)$cart['truePrice'], (string)$cart['cart_num'], 2), 2);
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
foreach ($cartInfo as $cart) {
|
||||
if (!$isOverlay($cart)) continue;
|
||||
if (isset($cart['product_id']) && in_array($cart['product_id'], explode(',', $coupon['product_id']))) {
|
||||
$price = bcadd((string)$price, (string)bcmul((string)$cart['truePrice'], (string)$cart['cart_num'], 2), 2);
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3://品牌
|
||||
$brands = $storeBrandServices->getAllById((int)$coupon['brand_id']);
|
||||
if ($brands) {
|
||||
$brandIds = array_column($brands, 'id');
|
||||
foreach ($cartInfo as $cart) {
|
||||
if (!$isOverlay($cart)) continue;
|
||||
if (isset($cart['productInfo']['brand_id']) && in_array($cart['productInfo']['brand_id'], $brandIds)) {
|
||||
$price = bcadd((string)$price, (string)bcmul((string)$cart['truePrice'], (string)$cart['cart_num'], 2), 2);
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ($count && $coupon['use_min_price'] <= $price) {
|
||||
$coupon_data['id'] = $coupon['id'];
|
||||
$coupon_data['cid'] = $coupon['cid'];
|
||||
$coupon_data['type'] = $coupon['applicable_type'];
|
||||
$coupon_data['applicable_type'] = $coupon['applicable_type'];
|
||||
$coupon_data['receive_type'] = $coupon['receive_type'];
|
||||
$coupon_data['start_time'] = $coupon['start_time'] ? date('Y-m-d', $coupon['start_time']) : date('Y-m-d', $coupon['add_time']);
|
||||
$coupon_data['add_time'] = date('Y-m-d', $coupon['add_time']);
|
||||
$coupon_data['end_time'] = date('Y-m-d', $coupon['end_time']);
|
||||
$coupon_data['title'] = $coupon['coupon_title'];
|
||||
$coupon_data['use_min_price'] = floatval($coupon['use_min_price']);
|
||||
$coupon_data['coupon_type'] = $coupon['coupon_type'];
|
||||
$coupon_data['coupon_price'] = floatval($coupon['coupon_price']);
|
||||
$result[] = $coupon_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户领取优惠券
|
||||
* @param $uid
|
||||
* @param $issueCouponInfo
|
||||
* @param string $type
|
||||
* @return mixed
|
||||
*/
|
||||
public function addUserCoupon($uid, $issueCouponInfo, string $type = 'get')
|
||||
{
|
||||
$data = [];
|
||||
$data['cid'] = $issueCouponInfo['id'];
|
||||
$data['uid'] = $uid;
|
||||
$data['coupon_title'] = $issueCouponInfo['title'];
|
||||
$data['coupon_price'] = $issueCouponInfo['coupon_price'];
|
||||
$data['use_min_price'] = $issueCouponInfo['use_min_price'];
|
||||
$data['add_time'] = time();
|
||||
if ($issueCouponInfo['coupon_time']) {
|
||||
$data['start_time'] = $data['add_time'];
|
||||
$data['end_time'] = $data['add_time'] + $issueCouponInfo['coupon_time'] * 86400;
|
||||
} else {
|
||||
$data['start_time'] = $issueCouponInfo['start_use_time'];
|
||||
$data['end_time'] = $issueCouponInfo['end_use_time'];
|
||||
}
|
||||
$data['type'] = $type;
|
||||
return $this->dao->save($data);
|
||||
}
|
||||
|
||||
/**会员领取优惠券
|
||||
* @param $uid
|
||||
* @param $issueCouponInfo
|
||||
* @param string $type
|
||||
* @return mixed
|
||||
*/
|
||||
public function addMemberUserCoupon($uid, $issueCouponInfo, $type = 'get')
|
||||
{
|
||||
$data = [];
|
||||
$data['cid'] = $issueCouponInfo['id'];
|
||||
$data['uid'] = $uid;
|
||||
$data['coupon_title'] = $issueCouponInfo['title'];
|
||||
$data['coupon_price'] = $issueCouponInfo['coupon_price'];
|
||||
$data['use_min_price'] = $issueCouponInfo['use_min_price'];
|
||||
$data['add_time'] = time();
|
||||
$data['start_time'] = strtotime(date('Y-m-d 00:00:00', time()));
|
||||
$data['end_time'] = strtotime(date('Y-m-d 23:59:59', strtotime('+30 day')));
|
||||
$data['type'] = $type;
|
||||
return $this->dao->save($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户已领取的优惠卷
|
||||
* @param int $uid
|
||||
* @param $type
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getUserCounpon(int $uid, $types, $type)
|
||||
{
|
||||
$where = [];
|
||||
$where['uid'] = $uid;
|
||||
switch ($types) {
|
||||
case 1:
|
||||
$where['status'] = 1;
|
||||
break;
|
||||
case 2:
|
||||
$where['status'] = 2;
|
||||
break;
|
||||
default:
|
||||
$where['status'] = 0;
|
||||
break;
|
||||
}
|
||||
$where['issue_type'] = $type;
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getCouponListByOrder($where, 'status ASC,add_time DESC', $page, $limit);
|
||||
/** @var StoreProductCategoryServices $categoryServices */
|
||||
$categoryServices = app()->make(StoreProductCategoryServices::class);
|
||||
$category = $categoryServices->getColumn([], 'pid,cate_name', 'id');
|
||||
foreach ($list as &$item) {
|
||||
if ($item['category_id'] && isset($category[$item['category_id']])) {
|
||||
$item['category_type'] = $category[$item['category_id']]['pid'] == 0 ? 1 : 2;
|
||||
$item['category_name'] = $category[$item['category_id']]['cate_name'];
|
||||
} else {
|
||||
$item['category_type'] = '';
|
||||
$item['category_name'] = '';
|
||||
}
|
||||
}
|
||||
return $list ? $this->tidyCouponList($list) : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 我的优惠券数量
|
||||
* @param int $uid
|
||||
* @return array
|
||||
* @throws \think\db\exception\DbException
|
||||
*/
|
||||
public function getUserCounponNum(int $uid): array
|
||||
{
|
||||
$data['not_used'] = $this->dao->count(['uid' => $uid, 'status' => 0]); // 未使用
|
||||
$data['used'] = $this->dao->count(['uid' => $uid, 'status' => 1]);// 已使用
|
||||
$data['expired'] = $this->dao->count(['uid' => $uid, 'status' => 2]);// 已过期
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化优惠券
|
||||
* @param $couponList
|
||||
* @return mixed
|
||||
*/
|
||||
public function tidyCouponList($couponList)
|
||||
{
|
||||
$time = time();
|
||||
foreach ($couponList as &$coupon) {
|
||||
if ($coupon['status'] == '已使用') {
|
||||
$coupon['_type'] = 0;
|
||||
$coupon['_msg'] = '已使用';
|
||||
$coupon['pc_type'] = 0;
|
||||
$coupon['pc_msg'] = '已使用';
|
||||
} else if ($coupon['status'] == '已过期') {
|
||||
$coupon['is_fail'] = 1;
|
||||
$coupon['_type'] = 0;
|
||||
$coupon['_msg'] = '已过期';
|
||||
$coupon['pc_type'] = 0;
|
||||
$coupon['pc_msg'] = '已过期';
|
||||
} else if ($coupon['end_time'] < $time) {
|
||||
$coupon['is_fail'] = 1;
|
||||
$coupon['_type'] = 0;
|
||||
$coupon['_msg'] = '已过期';
|
||||
$coupon['pc_type'] = 0;
|
||||
$coupon['pc_msg'] = '已过期';
|
||||
} else if ($coupon['start_time'] > $time) {
|
||||
$coupon['_type'] = 0;
|
||||
$coupon['_msg'] = '未开始';
|
||||
$coupon['pc_type'] = 1;
|
||||
$coupon['pc_msg'] = '未开始';
|
||||
} else {
|
||||
if ($coupon['start_time'] + 3600 * 24 > $time) {
|
||||
$coupon['_type'] = 2;
|
||||
$coupon['_msg'] = '立即使用';
|
||||
$coupon['pc_type'] = 1;
|
||||
$coupon['pc_msg'] = '可使用';
|
||||
} else {
|
||||
$coupon['_type'] = 1;
|
||||
$coupon['_msg'] = '立即使用';
|
||||
$coupon['pc_type'] = 1;
|
||||
$coupon['pc_msg'] = '可使用';
|
||||
}
|
||||
}
|
||||
$coupon['add_time'] = $coupon['_add_time'] = $coupon['start_time'] ? date('Y/m/d', $coupon['start_time']) : date('Y/m/d', $coupon['add_time']);
|
||||
$coupon['end_time'] = $coupon['_end_time'] = date('Y/m/d', $coupon['end_time']);
|
||||
$coupon['use_min_price'] = floatval($coupon['use_min_price']);
|
||||
$coupon['coupon_price'] = floatval($coupon['coupon_price']);
|
||||
}
|
||||
return $couponList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会员优惠券列表
|
||||
* @param $uid
|
||||
* @return array|mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getMemberCoupon($uid)
|
||||
{
|
||||
if (!$uid) return [];
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
if (!$page && !$limit) {
|
||||
$page = 0;
|
||||
$limit = 4;
|
||||
}
|
||||
/** @var StoreCouponIssueServices $couponIssueService */
|
||||
$couponIssueService = app()->make(StoreCouponIssueServices::class);
|
||||
$couponWhere['category'] = 2;
|
||||
$couponInfo = $couponIssueService->getMemberCouponIssueList($couponWhere, $page, $limit, ['used' => function ($query) use ($uid) {
|
||||
$query->where('uid', $uid);
|
||||
}]);
|
||||
if ($couponInfo) {
|
||||
$time = time();
|
||||
foreach ($couponInfo as $k => &$coupon) {
|
||||
$coupon['type_name'] = $couponIssueService->_couponType[$coupon['type']];
|
||||
$coupon['is_use'] = $uid ? isset($coupon['used']) : false;
|
||||
$coupon['used'] = $coupon['used'][0] ?? [];
|
||||
if (isset($coupon['used']) && $coupon['used']) {
|
||||
if ($coupon['used']['status'] == '已使用') {
|
||||
$coupon['used']['_type'] = 0;
|
||||
$coupon['used']['_msg'] = '已使用';
|
||||
$coupon['used']['pc_type'] = 0;
|
||||
$coupon['used']['pc_msg'] = '已使用';
|
||||
} else if ($coupon['used']['status'] == '已过期') {
|
||||
$coupon['used']['is_fail'] = 1;
|
||||
$coupon['used']['_type'] = 0;
|
||||
$coupon['used']['_msg'] = '已过期';
|
||||
$coupon['used']['pc_type'] = 0;
|
||||
$coupon['used']['pc_msg'] = '已过期';
|
||||
} else if ($coupon['used']['end_time'] < $time) {
|
||||
$coupon['used']['is_fail'] = 1;
|
||||
$coupon['used']['_type'] = 0;
|
||||
$coupon['used']['_msg'] = '已过期';
|
||||
$coupon['used']['pc_type'] = 0;
|
||||
$coupon['used']['pc_msg'] = '已过期';
|
||||
} else if ($coupon['used']['start_time'] > $time) {
|
||||
$coupon['used']['_type'] = 0;
|
||||
$coupon['used']['_msg'] = '未开始';
|
||||
$coupon['used']['pc_type'] = 1;
|
||||
$coupon['used']['pc_msg'] = '未开始';
|
||||
} else {
|
||||
if ($coupon['used']['start_time'] + 3600 * 24 > $time) {
|
||||
$coupon['used']['_type'] = 2;
|
||||
$coupon['used']['_msg'] = '立即使用';
|
||||
$coupon['used']['pc_type'] = 1;
|
||||
$coupon['used']['pc_msg'] = '可使用';
|
||||
} else {
|
||||
$coupon['used']['_type'] = 1;
|
||||
$coupon['used']['_msg'] = '立即使用';
|
||||
$coupon['used']['pc_type'] = 1;
|
||||
$coupon['used']['pc_msg'] = '可使用';
|
||||
}
|
||||
}
|
||||
$coupon['used']['end_time'] = $coupon['used']['_end_time'] = date('Y/m/d', $coupon['used']['end_time']);
|
||||
$coupon['used']['_add_time'] = $coupon['used']['start_time'] ? date('Y/m/d', $coupon['used']['start_time']) : date('Y/m/d', $coupon['add_time']);
|
||||
}
|
||||
|
||||
$coupon['add_time'] = date('Y/m/d', $coupon['add_time']);
|
||||
$coupon['start_use_time'] = date('Y/m/d', $coupon['start_use_time']);
|
||||
$coupon['end_use_time'] = date('Y/m/d', $coupon['end_use_time']);
|
||||
$coupon['use_min_price'] = floatval($coupon['use_min_price']);
|
||||
$coupon['coupon_price'] = floatval($coupon['coupon_price']);
|
||||
}
|
||||
}
|
||||
return $couponInfo ?: [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 使用优惠券验证
|
||||
* @param int $couponId
|
||||
* @param int $uid
|
||||
* @param array $cartInfo
|
||||
* @param array $promotions
|
||||
* @return bool
|
||||
*/
|
||||
public function useCoupon(int $couponId, int $uid, array $cartInfo, array $promotions = [])
|
||||
{
|
||||
if (!$couponId || !$uid || !$cartInfo) {
|
||||
return true;
|
||||
}
|
||||
/** @var StorePromotionsServices $promotionsServices */
|
||||
$promotionsServices = app()->make(StorePromotionsServices::class);
|
||||
[$couponInfo, $couponPrice] = $promotionsServices->useCoupon($couponId, $uid, $cartInfo, $promotions);
|
||||
if ($couponInfo) {
|
||||
$this->dao->useCoupon($couponId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\activity\discounts;
|
||||
|
||||
use app\dao\activity\discounts\StoreDiscountsProductsDao;
|
||||
use app\services\BaseServices;
|
||||
use app\services\product\sku\StoreProductAttrResultServices;
|
||||
use app\services\product\sku\StoreProductAttrServices;
|
||||
use app\services\product\sku\StoreProductAttrValueServices;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
|
||||
/**
|
||||
* 优惠套餐商品
|
||||
* Class StoreDiscountsProductsServices
|
||||
* @package app\services\activity\discounts
|
||||
* @mixin StoreDiscountsProductsDao
|
||||
*/
|
||||
class StoreDiscountsProductsServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var StoreDiscountsProductsDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreDiscountsProductsDao $dao;
|
||||
|
||||
/**
|
||||
* 删除规格和优惠商品
|
||||
* @param $discount_id
|
||||
* @return mixed
|
||||
*/
|
||||
public function del($discount_id)
|
||||
{
|
||||
/** @var StoreProductAttrResultServices $storeProductAttrResultServices */
|
||||
$storeProductAttrResultServices = app()->make(StoreProductAttrResultServices::class);
|
||||
/** @var StoreProductAttrValueServices $storeProductAttrValueServices */
|
||||
$storeProductAttrValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
/** @var StoreProductAttrServices $storeProductAttrServices */
|
||||
$storeProductAttrServices = app()->make(StoreProductAttrServices::class);
|
||||
|
||||
$ids = $this->dao->getColumn(['discount_id' => $discount_id], 'id');
|
||||
|
||||
foreach ($ids as $id) {
|
||||
$storeProductAttrServices->del($id, 5);
|
||||
$storeProductAttrResultServices->del($id, 5);
|
||||
$storeProductAttrValueServices->del($id, 5);
|
||||
}
|
||||
return $this->dao->delete($discount_id, 'discount_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 下单|加入购物车验证套餐商品库存
|
||||
* @param int $uid
|
||||
* @param int $discount_product_id
|
||||
* @param int $cartNum
|
||||
* @param string $unique
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function checkDiscountsStock(int $uid, int $discount_product_id, int $cartNum = 1, string $unique = '')
|
||||
{
|
||||
$discountProductInfo = $this->dao->getDiscountProductInfo($discount_product_id, '*,title as store_name', ['product']);
|
||||
if (!$discountProductInfo) {
|
||||
throw new ValidateException('该商品已下架或删除');
|
||||
}
|
||||
$discountProductInfo['temp_id'] = $discountProductInfo['p_temp_id'] ?? 0;
|
||||
/** @var StoreProductAttrValueServices $attrValueServices */
|
||||
$attrValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
$attrInfo = $attrValueServices->getOne(['product_id' => $discount_product_id, 'unique' => $unique, 'type' => 5]);
|
||||
if (!$attrInfo || $attrInfo['product_id'] != $discount_product_id) {
|
||||
throw new ValidateException('请选择有效的商品属性');
|
||||
}
|
||||
return [$attrInfo, $unique, $discountProductInfo];
|
||||
}
|
||||
}
|
||||
448
app/services/activity/discounts/StoreDiscountsServices.php
Normal file
448
app/services/activity/discounts/StoreDiscountsServices.php
Normal file
@@ -0,0 +1,448 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\activity\discounts;
|
||||
|
||||
use app\dao\activity\discounts\StoreDiscountsDao;
|
||||
use app\services\BaseServices;
|
||||
use app\services\product\product\StoreProductServices;
|
||||
use app\services\product\sku\StoreProductAttrResultServices;
|
||||
use app\services\product\sku\StoreProductAttrServices;
|
||||
use app\services\product\sku\StoreProductAttrValueServices;
|
||||
use app\services\user\label\UserLabelServices;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use crmeb\services\CacheService;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* 优惠套餐
|
||||
* Class StoreDiscountsServices
|
||||
* @package app\services\activity\discounts
|
||||
* @mixin StoreDiscountsDao
|
||||
*/
|
||||
class StoreDiscountsServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* 商品活动类型
|
||||
*/
|
||||
const TYPE = 5;
|
||||
|
||||
/**
|
||||
* @var StoreDiscountsDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreDiscountsDao $dao;
|
||||
|
||||
/**
|
||||
* 保存数据
|
||||
* @param $data
|
||||
* @return mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function saveDiscounts($data)
|
||||
{
|
||||
if ($data['freight'] == 2 && !$data['postage']) {
|
||||
throw new AdminException('请设置运费金额');
|
||||
}
|
||||
if ($data['freight'] == 3 && !$data['temp_id']) {
|
||||
throw new AdminException('请选择运费模版');
|
||||
}
|
||||
/** @var StoreProductAttrServices $storeProductAttrServices */
|
||||
$storeProductAttrServices = app()->make(StoreProductAttrServices::class);
|
||||
/** @var StoreDiscountsProductsServices $storeDiscountsProductsServices */
|
||||
$storeDiscountsProductsServices = app()->make(StoreDiscountsProductsServices::class);
|
||||
return $this->transaction(function () use ($data, $storeProductAttrServices, $storeDiscountsProductsServices) {
|
||||
//添加优惠套餐
|
||||
$discountsData['title'] = $data['title'];
|
||||
$discountsData['image'] = $data['image'];
|
||||
$discountsData['type'] = $data['type'];
|
||||
$discountsData['is_limit'] = $data['is_limit'];
|
||||
$discountsData['limit_num'] = $data['is_limit'] ? $data['limit_num'] : 0;
|
||||
$discountsData['link_ids'] = implode(',', $data['link_ids']);
|
||||
$discountsData['is_time'] = $data['is_time'];
|
||||
$discountsData['start_time'] = $data['is_time'] ? strtotime($data['time'][0]) : 0;
|
||||
$discountsData['stop_time'] = $data['is_time'] ? strtotime($data['time'][1]) + 86399 : 0;
|
||||
$discountsData['sort'] = $data['sort'];
|
||||
$discountsData['add_time'] = time();
|
||||
$discountsData['free_shipping'] = $data['free_shipping'];
|
||||
$discountsData['status'] = $data['status'];
|
||||
$discountsData['freight'] = $data['freight'];
|
||||
$discountsData['postage'] = $data['postage'];
|
||||
$discountsData['custom_form'] = $data['custom_form'] ? json_encode($data['custom_form']) : '';
|
||||
$discountsData['system_form_id'] = $data['system_form_id'] ?? 0;
|
||||
$product_ids = [];
|
||||
foreach ($data['products'] as $product) {
|
||||
if ($product['type']) {
|
||||
$product_ids = [];
|
||||
$product_ids[] = $product['product_id'];
|
||||
break;
|
||||
} else {
|
||||
$product_ids[] = $product['product_id'];
|
||||
}
|
||||
}
|
||||
$discountsData['product_ids'] = implode(',', $product_ids);
|
||||
if ($data['id']) {
|
||||
unset($discountsData['add_time']);
|
||||
$this->dao->update($data['id'], $discountsData);
|
||||
$storeDiscountsProductsServices->del($data['id']);
|
||||
$discountsId = $data['id'];
|
||||
} else {
|
||||
$discountsId = $this->dao->save($discountsData)->id;
|
||||
}
|
||||
if (!$discountsId) throw new AdminException('添加失败');
|
||||
if ($discountsData['is_limit']) CacheService::setStock(md5($discountsId), (int)$discountsData['limit_num'], 5);
|
||||
//添加优惠套餐内商品
|
||||
/** @var StoreProductServices $productService */
|
||||
$productService = app()->make(StoreProductServices::class);
|
||||
foreach ($data['products'] as $item) {
|
||||
$stock = $productService->value(['id' => $item['product_id'], 'is_del' => 0, 'is_show' => 1], 'stock') ?? 0;
|
||||
if ((int)$stock <= 0) {
|
||||
throw new AdminException('商品库存不足,请选择其他商品');
|
||||
}
|
||||
$productData = [];
|
||||
$productData['discount_id'] = $discountsId;
|
||||
$productData['product_id'] = $item['product_id'];
|
||||
$productData['product_type'] = $item['product_type'] ?? 0;
|
||||
$productData['title'] = $item['store_name'];
|
||||
$productData['image'] = $item['image'];
|
||||
$productData['type'] = $item['type'];
|
||||
$productData['temp_id'] = $item['temp_id'];
|
||||
$discountsProducts = $storeDiscountsProductsServices->save($productData);
|
||||
$storeProductAttrServices->setItem('store_product_id', $item['product_id']);
|
||||
$skuList = $storeProductAttrServices->validateProductAttr($item['items'], $item['attr'], (int)$discountsProducts->id, 5);
|
||||
$storeProductAttrServices->reset();
|
||||
$valueGroup = $storeProductAttrServices->saveProductAttr($skuList, (int)$discountsProducts->id, 5);
|
||||
if (!$discountsProducts || !$valueGroup) throw new AdminException('添加失败');
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function getList($where = [])
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getList($where, ['products'], $page, $limit);
|
||||
$count = $this->dao->count($where + ['is_del' => 0]);
|
||||
$time = time();
|
||||
foreach ($list as &$item) {
|
||||
if (!$this->checkDiscount($item, 0) || ($item['stop_time'] && $item['stop_time'] < $time)) {
|
||||
$item['status'] = 0;
|
||||
$this->dao->update(['id' => $item['id']], ['status' => 0]);
|
||||
}
|
||||
$item['start_time'] = $item['start_time'] ? date('Y-m-d', $item['start_time']) : 0;
|
||||
$item['stop_time'] = $item['stop_time'] ? date('Y-m-d', $item['stop_time']) : 0;
|
||||
$item['add_time'] = date('Y-m-d H:i:s', $item['add_time']);
|
||||
}
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取详情
|
||||
* @param $id
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getInfo($id)
|
||||
{
|
||||
$discounts = $this->dao->get($id);
|
||||
if ($discounts) {
|
||||
$discounts = $discounts->toArray();
|
||||
} else {
|
||||
throw new AdminException('套餐商品未找到!');
|
||||
}
|
||||
/** @var StoreDiscountsProductsServices $discountsProducts */
|
||||
$discountsProducts = app()->make(StoreDiscountsProductsServices::class);
|
||||
/** @var UserLabelServices $userLabelServices */
|
||||
$userLabelServices = app()->make(UserLabelServices::class);
|
||||
$discounts['products'] = $discountsProducts->getList(['discount_id' => $discounts['id']]);
|
||||
foreach ($discounts['products'] as &$item) {
|
||||
/** @var StoreProductAttrResultServices $storeProductAttrResultServices */
|
||||
$storeProductAttrResultServices = app()->make(StoreProductAttrResultServices::class);
|
||||
$discountsResult = $storeProductAttrResultServices->value(['product_id' => $item['id'], 'type' => 5], 'result');
|
||||
$item['items'] = json_decode($discountsResult, true)['attr'];
|
||||
$item['attr'] = $this->getattr($item['items'], $item['id'], 5);
|
||||
$item['store_name'] = $item['title'];
|
||||
}
|
||||
if ($discounts['start_time']) {
|
||||
$discounts['time'] = [date('Y-m-d', $discounts['start_time']), date('Y-m-d', $discounts['stop_time'])];
|
||||
} else {
|
||||
$discounts['time'] = [];
|
||||
}
|
||||
$link_ids = explode(',', $discounts['link_ids']);
|
||||
$discounts['link_ids'] = $userLabelServices->getLabelList(['ids' => $link_ids], ['id', 'label_name']);
|
||||
return $discounts;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取规格
|
||||
* @param $attr
|
||||
* @param $id
|
||||
* @param $type
|
||||
* @return array
|
||||
*/
|
||||
public function getattr($attr, $id, $type)
|
||||
{
|
||||
/** @var StoreProductAttrValueServices $storeProductAttrValueServices */
|
||||
$storeProductAttrValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
foreach ($attr as $k=>$v){
|
||||
foreach ($v['detail'] as $key=>$item){
|
||||
if(isset($item['value'])){
|
||||
$attr[$k]['detail'][$key] = $item['value'];
|
||||
}
|
||||
}
|
||||
}
|
||||
$value = attr_format($attr)[1];
|
||||
$valueNew = [];
|
||||
$count = 0;
|
||||
foreach ($value as $key => $item) {
|
||||
$detail = $item['detail'];
|
||||
$suk = implode(',', $item['detail']);
|
||||
$sukValue = $storeProductAttrValueServices->getSkuArray(['product_id' => $id, 'type' => $type, 'suk' => $suk], 'bar_code,code,cost,price,ot_price,stock,image as pic,weight,volume,brokerage,brokerage_two,quota,quota_show', 'suk');
|
||||
if (count($sukValue)) {
|
||||
$valueNew[$count]['value'] = '';
|
||||
foreach (array_values($detail) as $k => $v) {
|
||||
$valueNew[$count]['value' . ($k + 1)] = $v;
|
||||
$valueNew[$count]['value'] .= $valueNew[$count]['value'] == '' ? $v : ',' . $v;
|
||||
}
|
||||
$valueNew[$count]['detail'] = $detail;
|
||||
$valueNew[$count]['pic'] = $sukValue[$suk]['pic'] ?? '';
|
||||
$valueNew[$count]['price'] = $sukValue[$suk]['price'] ? floatval($sukValue[$suk]['price']) : 0;
|
||||
$valueNew[$count]['cost'] = $sukValue[$suk]['cost'] ? floatval($sukValue[$suk]['cost']) : 0;
|
||||
$valueNew[$count]['ot_price'] = isset($sukValue[$suk]['ot_price']) ? floatval($sukValue[$suk]['ot_price']) : 0;
|
||||
$valueNew[$count]['stock'] = $sukValue[$suk]['stock'] ? intval($sukValue[$suk]['stock']) : 0;
|
||||
// $valueNew[$count]['quota'] = $sukValue[$suk]['quota'] ? intval($sukValue[$suk]['quota']) : 0;
|
||||
$valueNew[$count]['quota'] = isset($sukValue[$suk]['quota_show']) && $sukValue[$suk]['quota_show'] ? intval($sukValue[$suk]['quota_show']) : 0;
|
||||
$valueNew[$count]['bar_code'] = $sukValue[$suk]['bar_code'] ?? '';
|
||||
$valueNew[$count]['code'] = $sukValue[$suk]['code'] ?? '';
|
||||
$valueNew[$count]['weight'] = $sukValue[$suk]['weight'] ? floatval($sukValue[$suk]['weight']) : 0;
|
||||
$valueNew[$count]['volume'] = $sukValue[$suk]['volume'] ? floatval($sukValue[$suk]['volume']) : 0;
|
||||
$valueNew[$count]['brokerage'] = $sukValue[$suk]['brokerage'] ? floatval($sukValue[$suk]['brokerage']) : 0;
|
||||
$valueNew[$count]['brokerage_two'] = $sukValue[$suk]['brokerage_two'] ? floatval($sukValue[$suk]['brokerage_two']) : 0;
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
return $valueNew;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改状态
|
||||
* @param $id
|
||||
* @param $status
|
||||
* @return mixed
|
||||
*/
|
||||
public function setStatus($id, $status)
|
||||
{
|
||||
$discounts = $this->dao->get($id, ['*'], ['products']);
|
||||
if ($discounts) {
|
||||
$discounts = $discounts->toArray();
|
||||
} else {
|
||||
throw new AdminException('套餐商品未找到!');
|
||||
}
|
||||
//上架
|
||||
if ($status) {
|
||||
if ($discounts['stop_time'] && $discounts['stop_time'] < time()) {
|
||||
throw new AdminException('套餐活动已结束');
|
||||
}
|
||||
if (!$this->checkDiscount($discounts, 0)) {
|
||||
throw new AdminException('套餐内商品已下架或者库存不足');
|
||||
}
|
||||
}
|
||||
return $this->dao->update($id, ['status' => $status]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除商品
|
||||
* @param $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function del($id)
|
||||
{
|
||||
return $this->dao->update($id, ['is_del' => 1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取优惠套餐列表
|
||||
* @param int $product_id
|
||||
* @param int $uid
|
||||
* @param int $limit
|
||||
* @param string $field
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getDiscounts(int $product_id, int $uid, int $limit = 0, string $field = '*')
|
||||
{
|
||||
if ($limit) {
|
||||
$page = 0;
|
||||
} else {
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
}
|
||||
$list = $this->dao->getDiscounts($product_id, $field, $page, $limit);
|
||||
foreach ($list as $key => &$discounts) {
|
||||
$discounts = $this->checkDiscount($discounts, $uid);
|
||||
if (!$discounts) unset($list[$key]);
|
||||
$maxDiscountsPrice = 0;
|
||||
if (isset($discounts['products']) && $discounts['products']) {
|
||||
$oneProductMax = [];
|
||||
foreach ($discounts['products'] as $product) {
|
||||
$attrInfo = $product['productValue'] ?? [];
|
||||
if ($attrInfo) {
|
||||
$one = 0;
|
||||
foreach ($attrInfo as $attr) {
|
||||
$one = max($one, (float)bcsub((string)($attr['product_price'] ?? 0), (string)($attr['price'] ?? 0), 2));
|
||||
}
|
||||
$oneProductMax[] = $one;
|
||||
}
|
||||
}
|
||||
$maxDiscountsPrice = array_sum($oneProductMax);
|
||||
}
|
||||
$discounts['max_discounts_price'] = $maxDiscountsPrice;
|
||||
}
|
||||
return array_merge($list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 购买|退款处理套餐限量
|
||||
* @param int $discountId
|
||||
* @param bool $is_dec
|
||||
* @return bool
|
||||
*/
|
||||
public function changeDiscountLimit(int $discountId, bool $is_dec = true)
|
||||
{
|
||||
$is_limit = $this->dao->value(['id' => $discountId], 'is_limit');
|
||||
$res = true;
|
||||
//开启限量
|
||||
if ($is_limit) {
|
||||
if ($is_dec) $res = $res && $this->dao->decLimitNum($discountId);
|
||||
else $res = $res && $this->dao->incLimitNum($discountId);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 优惠套餐库存减少
|
||||
* @param int $num
|
||||
* @param int $discountId
|
||||
* @param int $discount_product_id
|
||||
* @param int $product_id
|
||||
* @param string $unique
|
||||
* @param int $store_id
|
||||
* @return bool
|
||||
*/
|
||||
public function decDiscountStock(int $num, int $discountId, int $discount_product_id, int $product_id, string $unique, int $store_id = 0)
|
||||
{
|
||||
if (!$discountId || !$discount_product_id || !$product_id) return false;
|
||||
$res = true;
|
||||
if ($unique) {
|
||||
/** @var StoreProductAttrValueServices $skuValueServices */
|
||||
$skuValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
//套餐商品sku
|
||||
$suk = $skuValueServices->value(['unique' => $unique, 'product_id' => $discount_product_id, 'type' => 5], 'suk');
|
||||
//平台商品sku unique
|
||||
$productUnique = $skuValueServices->value(['suk' => $suk, 'product_id' => $product_id, 'type' => 0], 'unique');
|
||||
/** @var StoreProductServices $services */
|
||||
$services = app()->make(StoreProductServices::class);
|
||||
//减去普通商品库存
|
||||
$res = false !== $services->decProductStock($num, $product_id, (string)$productUnique);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加库存减销量
|
||||
* @param int $num
|
||||
* @param int $discountId 套餐id
|
||||
* @param int $discount_product_id 套餐商品id
|
||||
* @param int $product_id 原商品ID
|
||||
* @param string $unique
|
||||
* @return bool
|
||||
*/
|
||||
public function incDiscountStock(int $num, int $discountId, int $discount_product_id, int $product_id, string $unique, int $store_id = 0)
|
||||
{
|
||||
if (!$discountId || !$discount_product_id || !$product_id) return false;
|
||||
$res = true;
|
||||
if ($unique) {
|
||||
/** @var StoreProductAttrValueServices $skuValueServices */
|
||||
$skuValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
//增加当前普通商品sku的库存,减去销量
|
||||
//套餐商品sku
|
||||
$suk = $skuValueServices->value(['unique' => $unique, 'product_id' => $discount_product_id, 'type' => 5], 'suk');
|
||||
//平台商品sku unique
|
||||
$productUnique = $skuValueServices->value(['suk' => $suk, 'product_id' => $product_id, 'type' => 0], 'unique');
|
||||
/** @var StoreProductServices $services */
|
||||
$services = app()->make(StoreProductServices::class);
|
||||
//增加普通商品库存
|
||||
$res = $res && $services->incProductStock($num, $product_id, (string)$productUnique);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断优惠套餐显示
|
||||
* @param $discount
|
||||
* @param $uid
|
||||
* @return false
|
||||
*/
|
||||
public function checkDiscount($discount, $uid)
|
||||
{
|
||||
$discount = is_object($discount) ? $discount->toArray() : $discount;
|
||||
if ($discount['is_limit'] && $discount['limit_num'] <= 0) return false;
|
||||
if (isset($discount['products']) && $discount['products']) {
|
||||
/** @var StoreProductServices $productService */
|
||||
$productService = app()->make(StoreProductServices::class);
|
||||
/** @var StoreProductAttrServices $storeProductAttrServices */
|
||||
$storeProductAttrServices = app()->make(StoreProductAttrServices::class);
|
||||
$minPrice = 0;
|
||||
foreach ($discount['products'] as $key => &$item) {
|
||||
$stock = $productService->value(['id' => $item['product_id'], 'is_del' => 0, 'is_show' => 1], 'stock') ?? 0;
|
||||
try {
|
||||
[$productAttr, $productValue] = $storeProductAttrServices->getProductAttrDetailCache($item['id'], $uid, 0, 5, $item['product_id']);
|
||||
} catch (\Throwable $e) {
|
||||
return false;
|
||||
}
|
||||
if ($discount['type']) {
|
||||
if ($item['type']) {
|
||||
if ($stock == 0) {
|
||||
return false;
|
||||
} else {
|
||||
if (!array_sum(array_column($productValue, 'product_stock'))) return false;
|
||||
}
|
||||
} else {
|
||||
if (!array_sum(array_column($productValue, 'product_stock'))) unset($discount['products'][$key]);
|
||||
}
|
||||
} else {
|
||||
if ($stock == 0) {
|
||||
return false;
|
||||
} else {
|
||||
if (!array_sum(array_column($productValue, 'product_stock'))) return false;
|
||||
}
|
||||
}
|
||||
$item['productAttr'] = $productAttr;
|
||||
$item['productValue'] = $productValue;
|
||||
$minPrice += min(array_column($productValue, 'price'));
|
||||
}
|
||||
if (!count($discount['products'])) return false;
|
||||
$discount['min_price'] = $minPrice;
|
||||
$discount['products'] = array_merge($discount['products']);
|
||||
}
|
||||
return $discount;
|
||||
}
|
||||
}
|
||||
938
app/services/activity/holiday/HolidayGiftPushServices.php
Normal file
938
app/services/activity/holiday/HolidayGiftPushServices.php
Normal file
@@ -0,0 +1,938 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\holiday;
|
||||
|
||||
use app\dao\activity\holiday\HolidayGiftPushDao;
|
||||
use app\jobs\activity\HolidayGiftJob;
|
||||
use app\services\activity\coupon\StoreCouponIssueServices;
|
||||
use app\services\BaseServices;
|
||||
use app\services\user\UserServices;
|
||||
use app\services\user\UserBillServices;
|
||||
use app\services\user\UserMoneyServices;
|
||||
use app\services\activity\coupon\CouponIssueServices;
|
||||
use app\services\message\NoticeService;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use crmeb\exceptions\ApiException;
|
||||
use think\exception\ValidateException;
|
||||
use think\facade\Log;
|
||||
|
||||
/**
|
||||
* 节日有礼推送记录服务
|
||||
* Class HolidayGiftPushServices
|
||||
* @package app\services\activity
|
||||
* @mixin HolidayGiftPushDao
|
||||
*/
|
||||
class HolidayGiftPushServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* 构造方法
|
||||
* HolidayGiftPushServices constructor.
|
||||
* @param HolidayGiftPushDao $dao
|
||||
*/
|
||||
public function __construct(HolidayGiftPushDao $dao)
|
||||
{
|
||||
$this->dao = $dao;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取节日有礼推送记录列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getHolidayGiftPushList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getHolidayGiftPushList($where, '*', $page, $limit);
|
||||
$count = $this->dao->count($where);
|
||||
|
||||
if ($list) {
|
||||
// 获取用户信息
|
||||
$uids = array_column($list, 'uid');
|
||||
/** @var UserServices $userService */
|
||||
$userService = app()->make(UserServices::class);
|
||||
$userInfos = $userService->getUserList(['uid' => $uids], 'uid,nickname,avatar,phone');
|
||||
$userInfos = array_combine(array_column($userInfos, 'uid'), $userInfos);
|
||||
|
||||
// 获取节日有礼活动信息
|
||||
$giftIds = array_column($list, 'gift_id');
|
||||
/** @var HolidayGiftServices $giftService */
|
||||
$giftService = app()->make(HolidayGiftServices::class);
|
||||
$giftInfos = $giftService->getHolidayGiftList(['id' => $giftIds])['list'];
|
||||
$giftInfos = array_combine(array_column($giftInfos, 'id'), $giftInfos);
|
||||
|
||||
foreach ($list as &$item) {
|
||||
$item['user_info'] = $userInfos[$item['uid']] ?? [];
|
||||
$item['gift_info'] = $giftInfos[$item['gift_id']] ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取节日有礼推送记录详情
|
||||
* @param int $id
|
||||
* @param string $field
|
||||
* @return array|\think\Model
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getHolidayGiftPushInfo(int $id, string $field = '*')
|
||||
{
|
||||
if (!$id) {
|
||||
throw new AdminException('参数错误');
|
||||
}
|
||||
$info = $this->dao->get($id, $field);
|
||||
if (!$info) {
|
||||
throw new AdminException('推送记录不存在');
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户的节日有礼推送记录
|
||||
* @param int $uid 用户ID
|
||||
* @param int $giftId 节日有礼活动ID,可选
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getUserPushRecord(int $uid, int $giftId = 0)
|
||||
{
|
||||
if (!$uid) {
|
||||
return [];
|
||||
}
|
||||
$where = ['uid' => $uid];
|
||||
if ($giftId) {
|
||||
$where['gift_id'] = $giftId;
|
||||
}
|
||||
return $this->dao->getHolidayGiftPushList($where);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户今日的节日有礼推送记录
|
||||
* @param int $uid 用户ID
|
||||
* @param int $giftId 节日有礼活动ID,可选
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getUserTodayPushRecord(int $uid, int $giftId = 0)
|
||||
{
|
||||
if (!$uid) {
|
||||
return [];
|
||||
}
|
||||
$where = [
|
||||
['uid', '=', $uid],
|
||||
['push_time', '>', strtotime(date('Y-m-d'))]
|
||||
];
|
||||
if ($giftId) {
|
||||
$where[] = ['gift_id', '=', $giftId];
|
||||
}
|
||||
return $this->dao->getHolidayGiftPushList($where);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户本周的节日有礼推送记录
|
||||
* @param int $uid 用户ID
|
||||
* @param int $giftId 节日有礼活动ID,可选
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getUserWeekPushRecord(int $uid, int $giftId = 0)
|
||||
{
|
||||
if (!$uid) {
|
||||
return [];
|
||||
}
|
||||
$weekStart = strtotime(date('Y-m-d', strtotime('this week Monday')));
|
||||
$where = [
|
||||
'uid' => $uid,
|
||||
'push_time' => ['>=', $weekStart]
|
||||
];
|
||||
if ($giftId) {
|
||||
$where['gift_id'] = $giftId;
|
||||
}
|
||||
return $this->dao->getHolidayGiftPushList($where);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户本月的节日有礼推送记录
|
||||
* @param int $uid 用户ID
|
||||
* @param int $giftId 节日有礼活动ID,可选
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getUserMonthPushRecord(int $uid, int $giftId = 0)
|
||||
{
|
||||
if (!$uid) {
|
||||
return [];
|
||||
}
|
||||
$monthStart = strtotime(date('Y-m-01'));
|
||||
$where = [
|
||||
'uid' => $uid,
|
||||
'push_time' => ['>=', $monthStart]
|
||||
];
|
||||
if ($giftId) {
|
||||
$where['gift_id'] = $giftId;
|
||||
}
|
||||
return $this->dao->getHolidayGiftPushList($where);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新节日有礼推送记录状态
|
||||
* @param int $id 记录ID
|
||||
* @param int $status 状态:0未读,1已读
|
||||
* @return mixed
|
||||
*/
|
||||
public function updatePushStatus(int $id, int $status)
|
||||
{
|
||||
if (!$id) {
|
||||
throw new AdminException('参数错误');
|
||||
}
|
||||
return $this->dao->update($id, ['status' => $status]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除节日有礼推送记录
|
||||
* @param int $id 记录ID
|
||||
* @return mixed
|
||||
*/
|
||||
public function deletePush(int $id)
|
||||
{
|
||||
if (!$id) {
|
||||
throw new AdminException('参数错误');
|
||||
}
|
||||
return $this->dao->update($id, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除节日有礼推送记录
|
||||
* @param array $ids 记录ID数组
|
||||
* @return mixed
|
||||
*/
|
||||
public function batchDeletePush(array $ids)
|
||||
{
|
||||
if (!$ids) {
|
||||
throw new AdminException('参数错误');
|
||||
}
|
||||
return $this->dao->batchUpdate($ids, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计节日有礼推送数据
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function getPushStatistics(array $where = [])
|
||||
{
|
||||
// 总推送人数
|
||||
$totalUsers = $this->dao->distinct(true)->field('uid')->where($where)->count();
|
||||
|
||||
// 总推送次数
|
||||
$totalPushes = $this->dao->count($where);
|
||||
|
||||
// 今日推送人数
|
||||
$todayWhere = $where;
|
||||
$todayWhere['push_time'] = ['>=', strtotime(date('Y-m-d'))];
|
||||
$todayUsers = $this->dao->distinct(true)->field('uid')->where($todayWhere)->count();
|
||||
|
||||
// 今日推送次数
|
||||
$todayPushes = $this->dao->count($todayWhere);
|
||||
|
||||
// 昨日推送人数
|
||||
$yesterdayStart = strtotime(date('Y-m-d', strtotime('-1 day')));
|
||||
$yesterdayEnd = strtotime(date('Y-m-d')) - 1;
|
||||
$yesterdayWhere = $where;
|
||||
$yesterdayWhere['push_time'] = ['between', [$yesterdayStart, $yesterdayEnd]];
|
||||
$yesterdayUsers = $this->dao->distinct(true)->field('uid')->where($yesterdayWhere)->count();
|
||||
|
||||
// 昨日推送次数
|
||||
$yesterdayPushes = $this->dao->count($yesterdayWhere);
|
||||
|
||||
// 本月推送人数
|
||||
$monthWhere = $where;
|
||||
$monthWhere['push_time'] = ['>=', strtotime(date('Y-m-01'))];
|
||||
$monthUsers = $this->dao->distinct(true)->field('uid')->where($monthWhere)->count();
|
||||
|
||||
// 本月推送次数
|
||||
$monthPushes = $this->dao->count($monthWhere);
|
||||
|
||||
// 按推送渠道统计
|
||||
$channelStats = [];
|
||||
$pushTypes = [1 => '短信', 2 => '公众号', 3 => '弹框广告'];
|
||||
foreach ($pushTypes as $type => $name) {
|
||||
$typeWhere = $where;
|
||||
$typeWhere['push_type'] = $type;
|
||||
$channelStats[$type] = [
|
||||
'name' => $name,
|
||||
'count' => $this->dao->count($typeWhere),
|
||||
'users' => $this->dao->distinct(true)->field('uid')->where($typeWhere)->count()
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'total_users' => $totalUsers,
|
||||
'total_pushes' => $totalPushes,
|
||||
'today_users' => $todayUsers,
|
||||
'today_pushes' => $todayPushes,
|
||||
'yesterday_users' => $yesterdayUsers,
|
||||
'yesterday_pushes' => $yesterdayPushes,
|
||||
'month_users' => $monthUsers,
|
||||
'month_pushes' => $monthPushes,
|
||||
'channel_stats' => $channelStats
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否可以推送节日有礼消息
|
||||
* @param int $uid 用户ID
|
||||
* @param array $giftInfo 节日有礼活动信息
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function checkUserCanPush(int $uid, array $giftInfo)
|
||||
{
|
||||
if (!$uid || !$giftInfo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取用户推送记录
|
||||
$pushRecords = $this->getUserPushRecord($uid, $giftInfo['id']);
|
||||
if (!$pushRecords) {
|
||||
return true; // 没有推送记录,可以推送
|
||||
}
|
||||
|
||||
// 根据推送频次检查是否可以推送
|
||||
switch ($giftInfo['push_frequency']) {
|
||||
case 1: // 永久一次
|
||||
return false; // 已经推送过,不能再推送
|
||||
|
||||
case 2: // 每次进入
|
||||
return true; // 每次都可以推送
|
||||
|
||||
case 3: // 每天
|
||||
// 检查今天是否已经推送过
|
||||
$todayRecords = $this->getUserTodayPushRecord($uid, $giftInfo['id']);
|
||||
return empty($todayRecords);
|
||||
|
||||
case 4: // 每月
|
||||
// 检查本月是否已经推送过
|
||||
$monthRecords = $this->getUserMonthPushRecord($uid, $giftInfo['id']);
|
||||
return empty($monthRecords);
|
||||
|
||||
case 5: // 每周
|
||||
// 检查今天是否是设置的星期几,以及本周是否已经推送过
|
||||
$weekDay = date('N'); // 1-7 表示周一到周日
|
||||
$weekDays = explode(',', $giftInfo['push_week_days']);
|
||||
if (!in_array($weekDay, $weekDays)) {
|
||||
return false; // 今天不是设置的星期几,不能推送
|
||||
}
|
||||
|
||||
// 检查本周是否已经推送过
|
||||
$weekRecords = $this->getUserWeekPushRecord($uid, $giftInfo['id']);
|
||||
return empty($weekRecords);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否在推送时段内
|
||||
* @param array $giftInfo 节日有礼活动信息
|
||||
* @return bool
|
||||
*/
|
||||
public function checkPushTimeRange(array $giftInfo)
|
||||
{
|
||||
// 如果是全时段,直接返回true
|
||||
if ($giftInfo['push_time_type'] == 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 指定时段,需要检查当前时间是否在时段内
|
||||
$now = date('H:i');
|
||||
$startTime = $giftInfo['push_start_time'];
|
||||
$endTime = $giftInfo['push_end_time'];
|
||||
|
||||
return $now >= $startTime && $now <= $endTime;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用户是否包邮,双倍积分
|
||||
* @return
|
||||
* User: liusl
|
||||
* DateTime: 2025/8/5 16:18
|
||||
*/
|
||||
public function receiveHolidayGift(int $uid, int $type)
|
||||
{
|
||||
//$type 1: 是否包邮 2: 双倍积分
|
||||
$holidayGiftRecordServices = app()->make(HolidayGiftRecordServices::class);
|
||||
//已经领取的活动
|
||||
$recordList = $holidayGiftRecordServices->selectList(['uid' => $uid]);
|
||||
if (!$recordList) {
|
||||
return false;
|
||||
}
|
||||
$recordList = $recordList->toArray();
|
||||
$integral_multiple = 0;
|
||||
foreach ($recordList as $record) {
|
||||
$giftInfo = json_decode($record['gift_content'], true);
|
||||
// 检查json_decode是否失败
|
||||
if ($giftInfo === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->checkAdvancePush($giftInfo, true, $uid)) {
|
||||
if ($type == 1) {
|
||||
// 检查是否包含包邮权益(类型5)
|
||||
if (isset($giftInfo['gift_type']) && in_array(5, $giftInfo['gift_type'])) {
|
||||
return true;
|
||||
}
|
||||
} elseif ($type == 2) {
|
||||
// 检查是否包含双倍积分权益(类型3)
|
||||
if (isset($giftInfo['gift_type']) && in_array(3, $giftInfo['gift_type']) && $giftInfo['integral_multiple']) {
|
||||
$integral_multiple = max($integral_multiple, (int)$giftInfo['integral_multiple']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 默认返回false
|
||||
return $type == 2 && $integral_multiple ? $integral_multiple : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否需要提前推送或当天推送
|
||||
* @param array $giftInfo 节日有礼活动信息
|
||||
* @return bool
|
||||
*/
|
||||
public function checkAdvancePush(array $giftInfo, bool $is_advance = false, int $uid = 0)
|
||||
{
|
||||
if ($giftInfo['task_type'] == 2) {
|
||||
// 根据活动日期类型检查
|
||||
switch ($giftInfo['activity_date_type']) {
|
||||
case 1: // 自定义日期
|
||||
return $this->checkCustomDateAdvancePush($giftInfo, $is_advance);
|
||||
case 2: // 每月
|
||||
return $this->checkMonthlyAdvancePush($giftInfo, $is_advance);
|
||||
case 3: // 每周
|
||||
return $this->checkWeeklyAdvancePush($giftInfo, $is_advance);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
//生日
|
||||
if ($giftInfo['task_type'] == 1) { // 生日任务
|
||||
$user = app()->make(UserServices::class)->getUserCacheInfo($uid);
|
||||
if(!$user['birthday']){
|
||||
return false;
|
||||
}
|
||||
$today = strtotime(date('Y-m-d'));
|
||||
$userBirthday = strtotime($user['birthday']);
|
||||
// 如果 is_advance 为 false,需要判断提前推送
|
||||
if (!$is_advance && $giftInfo['advance_push'] == 1 && $giftInfo['advance_days'] > 0) {
|
||||
$advanceDays = (int)$giftInfo['advance_days'];
|
||||
|
||||
//生日当天 - 提前推送
|
||||
if ($giftInfo['birthday_type'] == 1) {
|
||||
$thisYearBirthday = strtotime(date('Y') . '-' . date('m-d', $userBirthday));
|
||||
// 如果今年生日已过,计算明年生日
|
||||
if ($thisYearBirthday < $today) {
|
||||
$thisYearBirthday = strtotime((date('Y') + 1) . '-' . date('m-d', $userBirthday));
|
||||
}
|
||||
$advancePushDate = $thisYearBirthday - ($advanceDays * 24 * 60 * 60);
|
||||
if ($today < $advancePushDate || $today > $thisYearBirthday) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//生日当周 - 提前推送
|
||||
elseif ($giftInfo['birthday_type'] == 2) {
|
||||
$thisYearBirthday = strtotime(date('Y') . '-' . date('m-d', $userBirthday));
|
||||
if ($thisYearBirthday < $today) {
|
||||
$thisYearBirthday = strtotime((date('Y') + 1) . '-' . date('m-d', $userBirthday));
|
||||
}
|
||||
$birthdayWeekStart = strtotime('last monday', $thisYearBirthday);
|
||||
$birthdayWeekEnd = strtotime('next sunday', $birthdayWeekStart);
|
||||
$advancePushDate = $birthdayWeekStart - ($advanceDays * 24 * 60 * 60);
|
||||
if ($today < $advancePushDate || $today > $birthdayWeekEnd) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//生日当月 - 提前推送
|
||||
elseif ($giftInfo['birthday_type'] == 3) {
|
||||
$thisYearBirthday = strtotime(date('Y') . '-' . date('m-d', $userBirthday));
|
||||
if ($thisYearBirthday < $today) {
|
||||
$thisYearBirthday = strtotime((date('Y') + 1) . '-' . date('m-d', $userBirthday));
|
||||
}
|
||||
$birthdayMonth = date('Y-m', $thisYearBirthday);
|
||||
$monthStart = strtotime($birthdayMonth . '-01');
|
||||
$monthEnd = strtotime($birthdayMonth . '-' . date('t', $thisYearBirthday));
|
||||
$advancePushDate = $monthStart - ($advanceDays * 24 * 60 * 60);
|
||||
if ($today < $advancePushDate || $today > $monthEnd) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 原有逻辑:不提前推送
|
||||
$todayMd = date('m-d');
|
||||
$birthday = date('m-d', $userBirthday);
|
||||
//生日当天
|
||||
if ($giftInfo['birthday_type'] == 1) {
|
||||
if ($todayMd != $birthday) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//生日当周
|
||||
elseif ($giftInfo['birthday_type'] == 2) {
|
||||
$birthday = strtotime(date('Y').'-'.date('m-d', $userBirthday));
|
||||
$birthdayWeekStart = strtotime('last monday', $birthday);
|
||||
$birthdayWeekEnd = strtotime('next sunday', $birthdayWeekStart);
|
||||
$todayTimestamp = strtotime('today');
|
||||
if ($todayTimestamp <= $birthdayWeekStart || $todayTimestamp >= $birthdayWeekEnd) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//生日当月
|
||||
elseif ($giftInfo['birthday_type'] == 3) {
|
||||
if (date('m') != date('m', $userBirthday)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查自定义日期的提前推送
|
||||
* @param array $giftInfo 节日有礼活动信息
|
||||
* @return bool
|
||||
*/
|
||||
private function checkCustomDateAdvancePush(array $giftInfo, $is_advance = false)
|
||||
{
|
||||
$currentDate = strtotime(date('Y-m-d'));
|
||||
$startDate = $giftInfo['activity_start_date'];
|
||||
$endDate = $giftInfo['activity_end_date'];
|
||||
// 如果没有设置提前推送,检查是否在活动日期范围内
|
||||
if (empty($giftInfo['advance_push']) || empty($giftInfo['advance_days']) || $is_advance) {
|
||||
return $currentDate >= $startDate && $currentDate <= $endDate;
|
||||
}
|
||||
|
||||
// 计算提前推送日期
|
||||
$currentYear = date('Y');
|
||||
$startTimestamp = strtotime($currentYear . '-' . $startDate);
|
||||
$currentTimestamp = strtotime($currentYear . '-' . $currentDate);
|
||||
|
||||
// 如果开始日期已经过了今年,则计算明年的日期
|
||||
if ($startTimestamp < $currentTimestamp) {
|
||||
$startTimestamp = strtotime(($currentYear + 1) . '-' . $startDate);
|
||||
}
|
||||
|
||||
// 计算天数差
|
||||
$daysDiff = round(($startTimestamp - $currentTimestamp) / 86400);
|
||||
|
||||
// 检查是否符合提前推送天数或在活动期间
|
||||
return $daysDiff == $giftInfo['advance_days'] || ($currentDate >= $startDate && $currentDate <= $endDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查每月活动的推送
|
||||
* @param array $giftInfo 节日有礼活动信息
|
||||
* @return bool
|
||||
*/
|
||||
private function checkMonthlyAdvancePush(array $giftInfo, bool $is_advance = false)
|
||||
{
|
||||
$currentDay = (int)date('d');
|
||||
$monthDays = is_array($giftInfo['activity_month_days']) ? $giftInfo['activity_month_days'] : explode(',', $giftInfo['activity_month_days']);
|
||||
$monthDays = array_map('intval', $monthDays);
|
||||
|
||||
// 如果没有设置提前推送,检查今天是否是活动日期
|
||||
if (empty($giftInfo['advance_push']) || empty($giftInfo['advance_days']) || $is_advance) {
|
||||
return in_array($currentDay, $monthDays);
|
||||
}
|
||||
|
||||
// 检查是否有活动日期需要提前推送
|
||||
foreach ($monthDays as $day) {
|
||||
$daysDiff = $day - $currentDay;
|
||||
if ($daysDiff < 0) {
|
||||
// 如果活动日期已过,计算下个月的天数差
|
||||
$daysInMonth = (int)date('t');
|
||||
$daysDiff = $daysInMonth - $currentDay + $day;
|
||||
}
|
||||
|
||||
if ($daysDiff == $giftInfo['advance_days']) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查今天是否是活动日期
|
||||
return in_array($currentDay, $monthDays);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查每周活动的推送
|
||||
* @param array $giftInfo 节日有礼活动信息
|
||||
* @return bool
|
||||
*/
|
||||
private function checkWeeklyAdvancePush(array $giftInfo, bool $is_advance = false)
|
||||
{
|
||||
$currentWeekDay = (int)date('N'); // 1-7表示周一到周日
|
||||
$weekDays = is_array($giftInfo['activity_week_days']) ? $giftInfo['activity_week_days'] : explode(',', $giftInfo['activity_week_days']);
|
||||
$weekDays = array_map('intval', $weekDays);
|
||||
|
||||
// 如果没有设置提前推送,检查今天是否是活动日期
|
||||
if (empty($giftInfo['advance_push']) || empty($giftInfo['advance_days']) || $is_advance) {
|
||||
return in_array($currentWeekDay, $weekDays);
|
||||
}
|
||||
|
||||
// 检查是否有活动日期需要提前推送
|
||||
foreach ($weekDays as $weekDay) {
|
||||
$daysDiff = $weekDay - $currentWeekDay;
|
||||
if ($daysDiff < 0) {
|
||||
// 如果活动日期已过,计算下周的天数差
|
||||
$daysDiff = 7 + $daysDiff;
|
||||
}
|
||||
|
||||
if ($daysDiff == $giftInfo['advance_days']) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查今天是否是活动日期
|
||||
return in_array($currentWeekDay, $weekDays);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否符合节日有礼活动条件
|
||||
* @param int $uid 用户ID
|
||||
* @param array $giftInfo 节日有礼活动信息
|
||||
* @return bool
|
||||
*/
|
||||
public function checkUserCondition(int $uid, array $giftInfo)
|
||||
{
|
||||
/** @var HolidayGiftServices $giftService */
|
||||
$giftService = app()->make(HolidayGiftServices::class);
|
||||
return $giftService->checkUserCondition($uid, $giftInfo);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 保存用户节日有礼推送记录
|
||||
* @param array $ids 活动ID数组
|
||||
* @param int $uid 用户ID
|
||||
* @param array $data 附加数据
|
||||
* @return bool
|
||||
*/
|
||||
public function saveGiftPush(array $ids, int $uid, array $data = [])
|
||||
{
|
||||
if (!$ids) return true;
|
||||
$saveData = [];
|
||||
foreach ($ids as $id) {
|
||||
$data['gift_id'] = $id;
|
||||
$data['uid'] = $uid;
|
||||
$data['push_time'] = $data['add_time'] = time();
|
||||
$saveData[] = $data;
|
||||
}
|
||||
$this->dao->saveAll($saveData);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时任务处理节日有礼活动
|
||||
* 获取当前活动日期的活动,判断给用户赠送积分、余额等权益
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function handleHolidayGiftTask()
|
||||
{
|
||||
try {
|
||||
// 获取当前有效的节日有礼活动
|
||||
/** @var HolidayGiftServices $giftService */
|
||||
$giftService = app()->make(HolidayGiftServices::class);
|
||||
$activeGifts = $giftService->getActiveHolidayGifts();
|
||||
if (empty($activeGifts)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach ($activeGifts as $giftInfo) {
|
||||
// 获取符合条件的用户并执行推送
|
||||
$this->processGiftForUsers($giftInfo);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
// 记录错误日志
|
||||
Log::error('节日有礼定时任务执行失败: ' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 为符合条件的用户处理节日有礼
|
||||
* @param array $giftInfo 节日有礼活动信息
|
||||
* @return
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
private function processGiftForUsers(array $giftInfo)
|
||||
{
|
||||
/** @var UserServices $userService */
|
||||
$userService = app()->make(UserServices::class);
|
||||
/** @var HolidayGiftServices $giftService */
|
||||
$giftService = app()->make(HolidayGiftServices::class);
|
||||
|
||||
// 获取符合条件的用户
|
||||
$userIds = $this->getEligibleUsers($giftInfo);
|
||||
if (empty($userIds)) {
|
||||
return true;
|
||||
}
|
||||
$successCount = 0;
|
||||
$failCount = 0;
|
||||
|
||||
// 将用户处理任务分发到队列中,避免大量用户时的性能问题
|
||||
foreach ($userIds as $uid) {
|
||||
// try {
|
||||
// $this->grantUserBenefits($uid, $giftInfo);
|
||||
// $this->recordPushLog($uid, $giftInfo);
|
||||
// 分发到队列处理
|
||||
HolidayGiftJob::dispatch('doJob', [$uid, $giftInfo]);
|
||||
$successCount++;
|
||||
// } catch (\Exception $e) {
|
||||
// Log::error("用户{$uid}节日有礼队列分发失败: " . $e->getMessage());
|
||||
// $failCount++;
|
||||
// }
|
||||
}
|
||||
|
||||
// 记录处理结果日志
|
||||
Log::info("节日有礼活动[{$giftInfo['id']}]已分发到队列处理,总用户数:" . count($userIds) . ",成功分发:{$successCount}人,分发失败:{$failCount}人");
|
||||
|
||||
return [
|
||||
'dispatched' => $successCount,
|
||||
'dispatch_failed' => $failCount,
|
||||
'total' => count($userIds)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取符合条件的用户ID列表
|
||||
* @param array $giftInfo 节日有礼活动信息
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getEligibleUsers(array $giftInfo)
|
||||
{
|
||||
/** @var UserServices $userService */
|
||||
$userService = app()->make(UserServices::class);
|
||||
|
||||
$where = ['status' => 1, 'is_del' => 0];
|
||||
|
||||
// 如果是生日任务,需要特殊处理
|
||||
if ($giftInfo['task_type'] == 1) { // 生日任务
|
||||
$today = date('m-d');
|
||||
if ($giftInfo['birthday_type'] == 1) { // 阳历生日
|
||||
$where['birthday'] = ['like', '%' . $today];
|
||||
}
|
||||
}
|
||||
$query = $userService->search($where)
|
||||
->when($giftInfo['task_type'] == 2 && $giftInfo['push_user_type'] == 2, function ($query) use ($giftInfo) {
|
||||
//自定义活动和指定人群
|
||||
if ($giftInfo['condition_type'] == 1) {
|
||||
//满足任一条件
|
||||
} else {
|
||||
//满足全部条件
|
||||
$query->when($giftInfo['user_level'], function ($query) use ($giftInfo) {
|
||||
$query->whereIn('level', $giftInfo['user_level']);
|
||||
})->when($giftInfo['user_tag'], function ($query) use ($giftInfo) {
|
||||
//1等级会员,2付费会员,3推广员,4采购商
|
||||
if (in_array(1, $giftInfo['user_tag'])) {
|
||||
$query->where('level', '>', 0);
|
||||
}
|
||||
if (in_array(2, $giftInfo['user_tag'])) {
|
||||
$query->where(function ($query) {
|
||||
$query->where(function ($query) {
|
||||
$query->where('is_money_level', '>', 0)->where('overdue_time', '>', time());
|
||||
})->whereOr(function ($query) {
|
||||
$query->where('is_ever_level', '>', 0);
|
||||
});
|
||||
});
|
||||
}
|
||||
if (in_array(3, $giftInfo['user_tag'])) {
|
||||
$query->where('is_promoter', 1);
|
||||
}
|
||||
if (in_array(4, $giftInfo['user_tag'])) {
|
||||
$query->where('is_channel', 1);
|
||||
}
|
||||
})->when($giftInfo['user_label'], function ($query) use ($giftInfo) {
|
||||
$user_label = $giftInfo['user_label'];
|
||||
$query->whereIn('uid', function ($q) use ($user_label) {
|
||||
$q->name('user_label_relation')->whereIn('label_id', $user_label)->field('uid')->select();
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
$users = $query->field('uid')->select()->toArray();
|
||||
return array_column($users, 'uid');
|
||||
}
|
||||
|
||||
/**
|
||||
* 给用户赠送权益
|
||||
* @param int $uid 用户ID
|
||||
* @param array $giftInfo 节日有礼活动信息
|
||||
* @return array|bool
|
||||
*/
|
||||
public function grantUserBenefits(int $uid, array $giftInfo)
|
||||
{
|
||||
/** @var UserServices $userService */
|
||||
$userService = app()->make(UserServices::class);
|
||||
$grantResults = true;
|
||||
|
||||
Log::info("开始为用户{$uid}赠送节日有礼权益,活动ID:{$giftInfo['id']}");
|
||||
|
||||
// 赠送积分
|
||||
if (in_array(2, $giftInfo['gift_type'])) { // 积分
|
||||
if (!empty($giftInfo['integral'])) {
|
||||
$userInfo = $userService->getUserInfo($uid);
|
||||
if ($userInfo) {
|
||||
$newIntegral = bcadd((string)$userInfo['integral'], (string)$giftInfo['integral'], 0);
|
||||
/** @var UserBillServices $userBillService */
|
||||
$userBillService = app()->make(UserBillServices::class);
|
||||
$billResult = $userBillService->income('holiday_gift_integral', $uid, (int)$giftInfo['integral'], (int)$newIntegral, 0, 0, '节日有礼赠送积分');
|
||||
$updateResult = $userService->update($uid, ['integral' => $newIntegral]);
|
||||
$integralSuccess = $billResult && $updateResult;
|
||||
if ($integralSuccess) {
|
||||
Log::info("用户{$uid}积分赠送成功,赠送积分:{$giftInfo['integral']}");
|
||||
} else {
|
||||
Log::error("用户{$uid}积分赠送失败,赠送积分:{$giftInfo['integral']}");
|
||||
$grantResults = false;
|
||||
}
|
||||
} else {
|
||||
Log::error("用户{$uid}不存在,积分赠送失败");
|
||||
$grantResults = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 赠送余额
|
||||
if (in_array(4, $giftInfo['gift_type'])) { // 余额
|
||||
if (!empty($giftInfo['balance'])) {
|
||||
$userInfo = $userService->getUserInfo($uid);
|
||||
if ($userInfo) {
|
||||
$newMoney = bcadd((string)$userInfo['now_money'], (string)$giftInfo['balance'], 2);
|
||||
/** @var UserMoneyServices $userMoneyService */
|
||||
$userMoneyService = app()->make(UserMoneyServices::class);
|
||||
$billResult = $userMoneyService->income('holiday_gift_money', $uid, $giftInfo['balance'], $newMoney, 0, '', '节日有礼赠送余额');
|
||||
$updateResult = $userService->update($uid, ['now_money' => $newMoney]);
|
||||
$moneySuccess = $billResult && $updateResult;
|
||||
if ($moneySuccess) {
|
||||
Log::info("用户{$uid}余额赠送成功,赠送余额:{$giftInfo['balance']}");
|
||||
} else {
|
||||
Log::error("用户{$uid}余额赠送失败,赠送余额:{$giftInfo['balance']}");
|
||||
$grantResults = false;
|
||||
}
|
||||
} else {
|
||||
Log::error("用户{$uid}不存在,余额赠送失败");
|
||||
$grantResults = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 赠送优惠券
|
||||
if (in_array(1, $giftInfo['gift_type'])) {
|
||||
if (!empty($giftInfo['coupon_ids'])) {
|
||||
try {
|
||||
/** @var StoreCouponIssueServices $issueService */
|
||||
$issueService = app()->make(StoreCouponIssueServices::class);
|
||||
$couponList = $issueService->search([])->whereIn('id', $giftInfo['coupon_ids'])->select()->toArray();
|
||||
if ($couponList) {
|
||||
/** @var StoreCouponIssueServices $storeCouponIssueServices */
|
||||
$storeCouponIssueServices = app()->make(StoreCouponIssueServices::class);
|
||||
$couponSuccess = true;
|
||||
foreach ($couponList as $coupon) {
|
||||
$res = $storeCouponIssueServices->setCoupon($coupon, [$uid], '', '', true);
|
||||
if (!$res) {
|
||||
$couponSuccess = false;
|
||||
Log::error("用户{$uid}优惠券赠送失败,优惠券ID:{$coupon['id']}");
|
||||
}
|
||||
}
|
||||
if ($couponSuccess) {
|
||||
Log::info("用户{$uid}优惠券赠送成功,优惠券IDs:" . implode(',', $giftInfo['coupon_ids']));
|
||||
} else {
|
||||
$grantResults = false;
|
||||
}
|
||||
} else {
|
||||
Log::error("用户{$uid}优惠券赠送失败,未找到有效优惠券");
|
||||
$grantResults = false;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Log::error("用户{$uid}优惠券赠送异常:" . $e->getMessage());
|
||||
$grantResults = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($grantResults) {
|
||||
Log::info("用户{$uid}节日有礼权益赠送完成,活动ID:{$giftInfo['id']}");
|
||||
} else {
|
||||
Log::error("用户{$uid}节日有礼权益赠送失败,活动ID:{$giftInfo['id']}");
|
||||
}
|
||||
|
||||
return $grantResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录推送日志
|
||||
* @param int $uid 用户ID
|
||||
* @param array $giftInfo 节日有礼活动信息
|
||||
* @param array $grantResults 赠送结果详情
|
||||
* @return bool|\crmeb\basic\BaseModel|\think\Model
|
||||
*/
|
||||
public function recordPushLog(int $uid, array $giftInfo)
|
||||
{
|
||||
try {
|
||||
// 记录详细的礼品记录到 holiday_gift_record 表
|
||||
/** @var HolidayGiftRecordServices $recordService */
|
||||
$recordService = app()->make(HolidayGiftRecordServices::class);
|
||||
|
||||
$recordData = [
|
||||
'uid' => $uid,
|
||||
'gift_id' => $giftInfo['id'],
|
||||
'gift_type' => implode(',', $giftInfo['gift_type']),
|
||||
'gift_content' => json_encode($giftInfo),
|
||||
'receive_time' => time(),
|
||||
'add_time' => time()
|
||||
];
|
||||
$recordResult = $recordService->dao->save($recordData);
|
||||
|
||||
if (!$recordResult) {
|
||||
Log::error("节日有礼记录保存失败: 用户ID {$uid}, 活动ID {$giftInfo['id']}");
|
||||
return false;
|
||||
}
|
||||
|
||||
return $recordResult;
|
||||
} catch (\Exception $e) {
|
||||
Log::error("节日有礼记录保存异常: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
414
app/services/activity/holiday/HolidayGiftRecordServices.php
Normal file
414
app/services/activity/holiday/HolidayGiftRecordServices.php
Normal file
@@ -0,0 +1,414 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\holiday;
|
||||
|
||||
use app\dao\activity\holiday\HolidayGiftRecordDao;
|
||||
use app\services\BaseServices;
|
||||
use app\services\user\UserServices;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use crmeb\exceptions\ApiException;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
/**
|
||||
* 节日有礼领取记录服务
|
||||
* Class HolidayGiftRecordServices
|
||||
* @package app\services\activity
|
||||
* @mixin HolidayGiftRecordDao
|
||||
*/
|
||||
class HolidayGiftRecordServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* 构造方法
|
||||
* HolidayGiftRecordServices constructor.
|
||||
* @param HolidayGiftRecordDao $dao
|
||||
*/
|
||||
public function __construct(HolidayGiftRecordDao $dao)
|
||||
{
|
||||
$this->dao = $dao;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取节日有礼领取记录列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getHolidayGiftRecordList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getHolidayGiftRecordList($where, '*', $page, $limit);
|
||||
$count = $this->dao->count($where);
|
||||
|
||||
if ($list) {
|
||||
// 获取用户信息
|
||||
$uids = array_column($list, 'uid');
|
||||
/** @var UserServices $userService */
|
||||
$userService = app()->make(UserServices::class);
|
||||
$userInfos = $userService->getUserList(['uid' => $uids], 'uid,nickname,avatar,phone');
|
||||
$userInfos = array_combine(array_column($userInfos, 'uid'), $userInfos);
|
||||
|
||||
// 获取节日有礼活动信息
|
||||
$giftIds = array_column($list, 'gift_id');
|
||||
/** @var HolidayGiftServices $giftService */
|
||||
$giftService = app()->make(HolidayGiftServices::class);
|
||||
$giftInfos = $giftService->getHolidayGiftList(['id' => $giftIds])['list'];
|
||||
$giftInfos = array_combine(array_column($giftInfos, 'id'), $giftInfos);
|
||||
|
||||
foreach ($list as &$item) {
|
||||
$item['user_info'] = $userInfos[$item['uid']] ?? [];
|
||||
$item['gift_info'] = $giftInfos[$item['gift_id']] ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取节日有礼领取记录详情
|
||||
* @param int $id
|
||||
* @param string $field
|
||||
* @return array|\think\Model
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getHolidayGiftRecordInfo(int $id, string $field = '*')
|
||||
{
|
||||
if (!$id) {
|
||||
throw new AdminException('参数错误');
|
||||
}
|
||||
$info = $this->dao->get($id, $field);
|
||||
if (!$info) {
|
||||
throw new AdminException('领取记录不存在');
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户领取的节日有礼记录
|
||||
* @param int $uid 用户ID
|
||||
* @param int $giftId 节日有礼活动ID
|
||||
* @return array|\think\Model|null
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getUserGiftRecord(int $uid, int $giftId)
|
||||
{
|
||||
if (!$uid || !$giftId) {
|
||||
return null;
|
||||
}
|
||||
return $this->dao->getOne(['uid' => $uid, 'gift_id' => $giftId, 'is_del' => 0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户今日领取的节日有礼记录
|
||||
* @param int $uid 用户ID
|
||||
* @param int $giftId 节日有礼活动ID,可选
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getUserTodayGiftRecord(int $uid, int $giftId = 0)
|
||||
{
|
||||
if (!$uid) {
|
||||
return [];
|
||||
}
|
||||
$where = [
|
||||
'uid' => $uid,
|
||||
'is_del' => 0,
|
||||
'receive_time' => ['>=', strtotime(date('Y-m-d'))]
|
||||
];
|
||||
if ($giftId) {
|
||||
$where['gift_id'] = $giftId;
|
||||
}
|
||||
return $this->dao->getList($where);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户本周领取的节日有礼记录
|
||||
* @param int $uid 用户ID
|
||||
* @param int $giftId 节日有礼活动ID,可选
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getUserWeekGiftRecord(int $uid, int $giftId = 0)
|
||||
{
|
||||
if (!$uid) {
|
||||
return [];
|
||||
}
|
||||
$weekStart = strtotime(date('Y-m-d', strtotime('this week Monday')));
|
||||
$where = [
|
||||
'uid' => $uid,
|
||||
'is_del' => 0,
|
||||
'receive_time' => ['>=', $weekStart]
|
||||
];
|
||||
if ($giftId) {
|
||||
$where['gift_id'] = $giftId;
|
||||
}
|
||||
return $this->dao->getList($where);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户本月领取的节日有礼记录
|
||||
* @param int $uid 用户ID
|
||||
* @param int $giftId 节日有礼活动ID,可选
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getUserMonthGiftRecord(int $uid, int $giftId = 0)
|
||||
{
|
||||
if (!$uid) {
|
||||
return [];
|
||||
}
|
||||
$monthStart = strtotime(date('Y-m-01'));
|
||||
$where = [
|
||||
'uid' => $uid,
|
||||
'is_del' => 0,
|
||||
'receive_time' => ['>=', $monthStart]
|
||||
];
|
||||
if ($giftId) {
|
||||
$where['gift_id'] = $giftId;
|
||||
}
|
||||
return $this->dao->getList($where);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新节日有礼领取记录状态
|
||||
* @param int $id 记录ID
|
||||
* @param int $status 状态:0未使用,1已使用
|
||||
* @return mixed
|
||||
*/
|
||||
public function updateRecordStatus(int $id, int $status)
|
||||
{
|
||||
if (!$id) {
|
||||
throw new AdminException('参数错误');
|
||||
}
|
||||
$data = ['status' => $status];
|
||||
if ($status == 1) {
|
||||
$data['use_time'] = time();
|
||||
}
|
||||
return $this->dao->update($id, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除节日有礼领取记录
|
||||
* @param int $id 记录ID
|
||||
* @return mixed
|
||||
*/
|
||||
public function deleteRecord(int $id)
|
||||
{
|
||||
if (!$id) {
|
||||
throw new AdminException('参数错误');
|
||||
}
|
||||
return $this->dao->update($id, ['is_del' => 1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除节日有礼领取记录
|
||||
* @param array $ids 记录ID数组
|
||||
* @return mixed
|
||||
*/
|
||||
public function batchDeleteRecord(array $ids)
|
||||
{
|
||||
if (!$ids) {
|
||||
throw new AdminException('参数错误');
|
||||
}
|
||||
return $this->dao->batchUpdate($ids, ['is_del' => 1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计节日有礼领取数据
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function getRecordStatistics(array $where = [])
|
||||
{
|
||||
// 总领取人数
|
||||
$totalUsers = $this->dao->distinct(true)->field('uid')->where($where)->count();
|
||||
|
||||
// 总领取次数
|
||||
$totalRecords = $this->dao->count($where);
|
||||
|
||||
// 今日领取人数
|
||||
$todayWhere = $where;
|
||||
$todayWhere['receive_time'] = ['>=', strtotime(date('Y-m-d'))];
|
||||
$todayUsers = $this->dao->distinct(true)->field('uid')->where($todayWhere)->count();
|
||||
|
||||
// 今日领取次数
|
||||
$todayRecords = $this->dao->count($todayWhere);
|
||||
|
||||
// 昨日领取人数
|
||||
$yesterdayStart = strtotime(date('Y-m-d', strtotime('-1 day')));
|
||||
$yesterdayEnd = strtotime(date('Y-m-d')) - 1;
|
||||
$yesterdayWhere = $where;
|
||||
$yesterdayWhere['receive_time'] = ['between', [$yesterdayStart, $yesterdayEnd]];
|
||||
$yesterdayUsers = $this->dao->distinct(true)->field('uid')->where($yesterdayWhere)->count();
|
||||
|
||||
// 昨日领取次数
|
||||
$yesterdayRecords = $this->dao->count($yesterdayWhere);
|
||||
|
||||
// 本月领取人数
|
||||
$monthWhere = $where;
|
||||
$monthWhere['receive_time'] = ['>=', strtotime(date('Y-m-01'))];
|
||||
$monthUsers = $this->dao->distinct(true)->field('uid')->where($monthWhere)->count();
|
||||
|
||||
// 本月领取次数
|
||||
$monthRecords = $this->dao->count($monthWhere);
|
||||
|
||||
return [
|
||||
'total_users' => $totalUsers,
|
||||
'total_records' => $totalRecords,
|
||||
'today_users' => $todayUsers,
|
||||
'today_records' => $todayRecords,
|
||||
'yesterday_users' => $yesterdayUsers,
|
||||
'yesterday_records' => $yesterdayRecords,
|
||||
'month_users' => $monthUsers,
|
||||
'month_records' => $monthRecords
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户可用的多倍积分记录
|
||||
* @param int $uid 用户ID
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getUserAvailableMultipleIntegral(int $uid)
|
||||
{
|
||||
if (!$uid) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 查询用户领取的多倍积分记录,且未使用的
|
||||
$where = [
|
||||
'uid' => $uid,
|
||||
'is_del' => 0,
|
||||
'status' => 0,
|
||||
'gift_type' => ['like', '%3%'] // 包含多倍积分类型
|
||||
];
|
||||
|
||||
$list = $this->dao->getList($where);
|
||||
if (!$list) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$now = time();
|
||||
$result = [];
|
||||
|
||||
// 获取节日有礼活动信息
|
||||
$giftIds = array_column($list, 'gift_id');
|
||||
/** @var HolidayGiftServices $giftService */
|
||||
$giftService = app()->make(HolidayGiftServices::class);
|
||||
$giftInfos = $giftService->getHolidayGiftList(['id' => $giftIds])['list'];
|
||||
$giftInfos = array_combine(array_column($giftInfos, 'id'), $giftInfos);
|
||||
|
||||
foreach ($list as $item) {
|
||||
$giftInfo = $giftInfos[$item['gift_id']] ?? null;
|
||||
if (!$giftInfo) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查活动是否有效
|
||||
if ($giftInfo['status'] != 1 || $giftInfo['is_del'] == 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查活动时间(如果不是永久活动)
|
||||
if ((!isset($giftInfo['is_permanent']) || $giftInfo['is_permanent'] != 1) &&
|
||||
($now < $giftInfo['start_time'] || $now > $giftInfo['end_time'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 添加到结果中
|
||||
$result[] = [
|
||||
'record_id' => $item['id'],
|
||||
'gift_id' => $item['gift_id'],
|
||||
'gift_name' => $giftInfo['name'],
|
||||
'integral_multiple' => $giftInfo['integral_multiple'],
|
||||
'receive_time' => $item['receive_time'],
|
||||
'end_time' => $giftInfo['end_time']
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户可用的全场包邮记录
|
||||
* @param int $uid 用户ID
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getUserAvailableFreeShipping(int $uid)
|
||||
{
|
||||
if (!$uid) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 查询用户领取的全场包邮记录,且未使用的
|
||||
$where = [
|
||||
'uid' => $uid,
|
||||
'is_del' => 0,
|
||||
'status' => 0,
|
||||
'gift_type' => ['like', '%5%'] // 包含全场包邮类型
|
||||
];
|
||||
|
||||
$list = $this->dao->getList($where);
|
||||
if (!$list) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$now = time();
|
||||
$result = [];
|
||||
|
||||
// 获取节日有礼活动信息
|
||||
$giftIds = array_column($list, 'gift_id');
|
||||
/** @var HolidayGiftServices $giftService */
|
||||
$giftService = app()->make(HolidayGiftServices::class);
|
||||
$giftInfos = $giftService->getHolidayGiftList(['id' => $giftIds])['list'];
|
||||
$giftInfos = array_combine(array_column($giftInfos, 'id'), $giftInfos);
|
||||
|
||||
foreach ($list as $item) {
|
||||
$giftInfo = $giftInfos[$item['gift_id']] ?? null;
|
||||
if (!$giftInfo) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查活动是否有效
|
||||
if ($giftInfo['status'] != 1 || $giftInfo['is_del'] == 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查活动时间(如果不是永久活动)
|
||||
if ((!isset($giftInfo['is_permanent']) || $giftInfo['is_permanent'] != 1) &&
|
||||
($now < $giftInfo['start_time'] || $now > $giftInfo['end_time'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 添加到结果中
|
||||
$result[] = [
|
||||
'record_id' => $item['id'],
|
||||
'gift_id' => $item['gift_id'],
|
||||
'gift_name' => $giftInfo['name'],
|
||||
'receive_time' => $item['receive_time'],
|
||||
'end_time' => isset($giftInfo['is_permanent']) && $giftInfo['is_permanent'] == 1 ? 0 : $giftInfo['end_time']
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
747
app/services/activity/holiday/HolidayGiftServices.php
Normal file
747
app/services/activity/holiday/HolidayGiftServices.php
Normal file
@@ -0,0 +1,747 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\holiday;
|
||||
|
||||
use app\dao\activity\holiday\HolidayGiftDao;
|
||||
use app\model\activity\holiday\HolidayGift;
|
||||
use app\services\BaseServices;
|
||||
use app\services\product\product\StoreProductCouponServices;
|
||||
use app\services\user\label\UserLabelRelationServices;
|
||||
use app\services\user\label\UserLabelServices;
|
||||
use app\services\user\level\UserLevelServices;
|
||||
use app\services\user\UserServices;
|
||||
use app\services\activity\coupon\StoreCouponIssueServices;
|
||||
use app\services\activity\coupon\StoreCouponUserServices;
|
||||
use app\services\user\UserBillServices;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use crmeb\exceptions\ApiException;
|
||||
use think\exception\ValidateException;
|
||||
use think\facade\Db;
|
||||
|
||||
/**
|
||||
* 节日有礼服务
|
||||
* Class HolidayGiftServices
|
||||
* @package app\services\activity
|
||||
* @mixin HolidayGiftDao
|
||||
*/
|
||||
class HolidayGiftServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* 构造方法
|
||||
* HolidayGiftServices constructor.
|
||||
* @param HolidayGiftDao $dao
|
||||
*/
|
||||
public function __construct(HolidayGiftDao $dao)
|
||||
{
|
||||
$this->dao = $dao;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取节日有礼列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getHolidayGiftList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getHolidayGiftList($where, '*', $page, $limit);
|
||||
$count = $this->dao->count($where);
|
||||
foreach ($list as &$item) {
|
||||
$item['start_time'] = date('Y-m-d H:i:s', $item['start_time']);
|
||||
$item['end_time'] = date('Y-m-d H:i:s', $item['end_time']);
|
||||
// 使用辅助方法转换数值为文本描述
|
||||
$this->formatHolidayGiftData($item);
|
||||
}
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取节日有礼详情
|
||||
* @param int $id
|
||||
* @param string $field
|
||||
* @return array|\think\Model
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getHolidayGiftInfo(int $id, array $field = ['*'])
|
||||
{
|
||||
if (!$id) {
|
||||
throw new AdminException('参数错误');
|
||||
}
|
||||
$info = $this->dao->get($id, $field);
|
||||
if (!$info) {
|
||||
throw new AdminException('节日有礼不存在');
|
||||
}
|
||||
$info = $info->toArray();
|
||||
if ($info['is_permanent'] == 0) {
|
||||
$start_time = $info['start_time'] ? date('Y-m-d H:i:s', (int)$info['start_time']) : '';
|
||||
$end_time = $info['start_time'] ? date('Y-m-d H:i:s', (int)$info['end_time']) : '';
|
||||
$info['start_time'] = [$start_time, $end_time];
|
||||
}
|
||||
$info['activity_date'] = [];
|
||||
if ($info['activity_date_type'] == 1) {
|
||||
$activity_start_date = $info['activity_start_date'] ? date('Y-m-d H:i:s', (int)$info['activity_start_date']) : '';
|
||||
$activity_end_date = $info['activity_end_date'] ? date('Y-m-d H:i:s', (int)$info['activity_end_date']) : '';
|
||||
if ($activity_start_date && $activity_end_date) {
|
||||
$info['activity_date'] = [
|
||||
$activity_start_date,
|
||||
$activity_end_date
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$coupon_ids = $info['coupon_ids'];
|
||||
$user_label = $info['user_label'];
|
||||
if ($coupon_ids) {
|
||||
$info['coupon'] = app()->make(StoreCouponIssueServices::class)->search([])->whereIn('id', $coupon_ids)->field('id,coupon_title as title')->select()->toArray();
|
||||
}
|
||||
if ($user_label) {
|
||||
$info['label'] = app()->make(UserLabelServices::class)->search([])->whereIn('id', $user_label)->field('id,label_name')->select()->toArray();
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化节日有礼数据,添加文本描述
|
||||
* @param array &$data 节日有礼数据
|
||||
* @return void
|
||||
*/
|
||||
protected function formatHolidayGiftData(array &$data)
|
||||
{
|
||||
// 基本信息
|
||||
if (isset($data['task_type'])) {
|
||||
$data['task_type_text'] = HolidayGift::TASK_TYPE[$data['task_type']] ?? '';
|
||||
}
|
||||
if (isset($data['birthday_type'])) {
|
||||
$data['birthday_type_text'] = HolidayGift::BIRTHDAY_TYPE[$data['birthday_type']] ?? '';
|
||||
}
|
||||
if (isset($data['status'])) {
|
||||
$data['status_text'] = HolidayGift::STATUS[$data['status']] ?? '';
|
||||
}
|
||||
if (isset($data['is_permanent'])) {
|
||||
$data['is_permanent_text'] = HolidayGift::IS_PERMANENT[$data['is_permanent']] ?? '';
|
||||
}
|
||||
|
||||
// 推送相关
|
||||
if (isset($data['push_time_type'])) {
|
||||
$data['push_time_type_text'] = HolidayGift::PUSH_TIME_TYPE[$data['push_time_type']] ?? '';
|
||||
}
|
||||
if (isset($data['push_user_type'])) {
|
||||
$data['push_user_type_text'] = HolidayGift::PUSH_USER_TYPE[$data['push_user_type']] ?? '';
|
||||
}
|
||||
if (isset($data['push_frequency'])) {
|
||||
$data['push_frequency_text'] = HolidayGift::PUSH_FREQUENCY[$data['push_frequency']] ?? '';
|
||||
}
|
||||
if (isset($data['advance_push'])) {
|
||||
$data['advance_push_text'] = HolidayGift::ADVANCE_PUSH[$data['advance_push']] ?? '';
|
||||
}
|
||||
if (isset($data['push_status'])) {
|
||||
$data['push_status_text'] = HolidayGift::PUSH_STATUS[$data['push_status']] ?? '';
|
||||
}
|
||||
|
||||
// 条件和礼品相关
|
||||
if (isset($data['condition_type'])) {
|
||||
$data['condition_type_text'] = HolidayGift::CONDITION_TYPE[$data['condition_type']] ?? '';
|
||||
}
|
||||
if (isset($data['gift_type'])) {
|
||||
if (is_array($data['gift_type'])) {
|
||||
$data['gift_type_text'] = [];
|
||||
foreach ($data['gift_type'] as $type) {
|
||||
$data['gift_type_text'][] = HolidayGift::GIFT_TYPE[$type] ?? '';
|
||||
}
|
||||
} else {
|
||||
$data['gift_type_text'] = HolidayGift::GIFT_TYPE[$data['gift_type']] ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
// 渠道和页面相关
|
||||
if (isset($data['push_channel'])) {
|
||||
if (is_array($data['push_channel'])) {
|
||||
$data['push_channel_text'] = [];
|
||||
foreach ($data['push_channel'] as $channel) {
|
||||
$data['push_channel_text'][] = HolidayGift::PUSH_CHANNEL[$channel] ?? '';
|
||||
}
|
||||
} else {
|
||||
$data['push_channel_text'] = HolidayGift::PUSH_CHANNEL[$data['push_channel']] ?? '';
|
||||
}
|
||||
}
|
||||
if (isset($data['show_page'])) {
|
||||
if (is_array($data['show_page'])) {
|
||||
$data['show_page_text'] = [];
|
||||
foreach ($data['show_page'] as $page) {
|
||||
$data['show_page_text'][] = HolidayGift::SHOW_PAGE[$page] ?? '';
|
||||
}
|
||||
} else {
|
||||
$data['show_page_text'] = HolidayGift::SHOW_PAGE[$data['show_page']] ?? '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存节日有礼数据
|
||||
* @param array $data
|
||||
* @return mixed
|
||||
*/
|
||||
public function saveHolidayGift(array $data)
|
||||
{
|
||||
// 数据验证
|
||||
$this->checkHolidayGiftData($data);
|
||||
|
||||
$data['add_time'] = time();
|
||||
$data['update_time'] = time();
|
||||
return $this->dao->save($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新节日有礼数据
|
||||
* @param int $id
|
||||
* @param array $data
|
||||
* @return mixed
|
||||
*/
|
||||
public function updateHolidayGift(int $id, array $data)
|
||||
{
|
||||
// 数据验证
|
||||
$this->checkHolidayGiftData($data);
|
||||
|
||||
$data['update_time'] = time();
|
||||
|
||||
return $this->dao->update($id, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除节日有礼
|
||||
* @param int $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function deleteHolidayGift(int $id)
|
||||
{
|
||||
if (!$id) {
|
||||
throw new AdminException('参数错误');
|
||||
}
|
||||
return $this->dao->update($id, ['is_del' => 1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改节日有礼状态
|
||||
* @param int $id
|
||||
* @param int $status
|
||||
* @return mixed
|
||||
*/
|
||||
public function setStatus(int $id, int $status)
|
||||
{
|
||||
if (!$id) {
|
||||
throw new AdminException('参数错误');
|
||||
}
|
||||
return $this->dao->update($id, ['status' => $status]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证节日有礼数据
|
||||
* @param array $data
|
||||
* @return bool
|
||||
*/
|
||||
public function checkHolidayGiftData(array $data)
|
||||
{
|
||||
// 验证活动名称
|
||||
if (!isset($data['name']) || !$data['name']) {
|
||||
throw new AdminException('请输入活动名称');
|
||||
}
|
||||
|
||||
// 验证活动时间(如果不是永久活动)
|
||||
if (!isset($data['is_permanent']) || $data['is_permanent'] != 1) {
|
||||
if (!isset($data['start_time']) || !$data['start_time']) {
|
||||
throw new AdminException('请选择开始时间');
|
||||
}
|
||||
if (!isset($data['end_time']) || !$data['end_time']) {
|
||||
throw new AdminException('请选择结束时间');
|
||||
}
|
||||
if ($data['start_time'] >= $data['end_time']) {
|
||||
throw new AdminException('结束时间必须大于开始时间');
|
||||
}
|
||||
}
|
||||
|
||||
// 验证任务类型
|
||||
if (!isset($data['task_type']) || !in_array($data['task_type'], array_keys(HolidayGift::TASK_TYPE))) {
|
||||
throw new AdminException('请选择正确的任务类型');
|
||||
}
|
||||
// 根据任务类型验证相关数据
|
||||
if ($data['task_type'] == array_search('用户生日', HolidayGift::TASK_TYPE)) { // 用户生日
|
||||
if (!isset($data['birthday_type']) || !in_array((int)$data['birthday_type'], array_keys(HolidayGift::BIRTHDAY_TYPE))) {
|
||||
throw new AdminException('请选择正确的生日类型');
|
||||
}
|
||||
} else { // 活动日期
|
||||
// 验证活动日期类型
|
||||
if (!isset($data['activity_date_type']) || !in_array((int)$data['activity_date_type'], array_keys(HolidayGift::ACTIVITY_DATE_TYPE))) {
|
||||
throw new AdminException('请选择正确的活动日期类型');
|
||||
}
|
||||
|
||||
// 根据活动日期类型验证相关数据
|
||||
switch ($data['activity_date_type']) {
|
||||
case 1: // 自定义日期
|
||||
if (!isset($data['activity_start_date']) || !$data['activity_start_date']) {
|
||||
throw new AdminException('请选择活动开始日期');
|
||||
}
|
||||
if (!isset($data['activity_end_date']) || !$data['activity_end_date']) {
|
||||
throw new AdminException('请选择活动结束日期');
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // 每月
|
||||
if (!isset($data['activity_month_days']) || (is_array($data['activity_month_days']) && empty($data['activity_month_days'])) || !$data['activity_month_days']) {
|
||||
throw new AdminException('请选择每月活动日期');
|
||||
}
|
||||
// 验证月份日期范围 1-31
|
||||
$monthDays = is_array($data['activity_month_days']) ? $data['activity_month_days'] : explode(',', $data['activity_month_days']);
|
||||
foreach ($monthDays as $day) {
|
||||
if (!is_numeric($day) || $day < 1 || $day > 31) {
|
||||
throw new AdminException('每月活动日期必须在1-31之间');
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3: // 每周
|
||||
if (!isset($data['activity_week_days']) || (is_array($data['activity_week_days']) && empty($data['activity_week_days'])) || !$data['activity_week_days']) {
|
||||
throw new AdminException('请选择每周活动日期');
|
||||
}
|
||||
// 验证周几范围 1-7
|
||||
$weekDays = is_array($data['activity_week_days']) ? $data['activity_week_days'] : explode(',', $data['activity_week_days']);
|
||||
foreach ($weekDays as $day) {
|
||||
if (!is_numeric($day) || $day < 1 || $day > 7) {
|
||||
throw new AdminException('每周活动日期必须在1-7之间(1表示周一,7表示周日)');
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 验证提前推送
|
||||
if (isset($data['advance_push']) && $data['advance_push']) {
|
||||
if (!isset($data['advance_days']) || $data['advance_days'] <= 0) {
|
||||
throw new AdminException('请输入正确的提前推送天数');
|
||||
}
|
||||
}
|
||||
|
||||
// 验证推送时段
|
||||
if (isset($data['push_time_type']) && $data['push_time_type'] == array_search('指定时段', HolidayGift::PUSH_TIME_TYPE)) {
|
||||
if (!isset($data['push_start_time']) || !$data['push_start_time']) {
|
||||
throw new AdminException('请选择推送开始时间');
|
||||
}
|
||||
if (!isset($data['push_end_time']) || !$data['push_end_time']) {
|
||||
throw new AdminException('请选择推送结束时间');
|
||||
}
|
||||
// 验证时间格式 HH:mm:ss 或 HH:mm
|
||||
if (!preg_match('/^([0-1][0-9]|2[0-3]):([0-5][0-9])(:[0-5][0-9])?$/', $data['push_start_time']) ||
|
||||
!preg_match('/^([0-1][0-9]|2[0-3]):([0-5][0-9])(:[0-5][0-9])?$/', $data['push_end_time'])) {
|
||||
throw new AdminException('推送时间格式不正确,应为HH:mm:ss或HH:mm格式');
|
||||
}
|
||||
}
|
||||
|
||||
// 验证推送人群
|
||||
if (isset($data['push_user_type']) && $data['push_user_type'] == array_search('指定人群', HolidayGift::PUSH_USER_TYPE)) {
|
||||
if ((!isset($data['user_level']) || !$data['user_level']) &&
|
||||
(!isset($data['user_label']) || (is_array($data['user_label']) && empty($data['user_label'])) || !$data['user_label']) &&
|
||||
(!isset($data['user_tag']) || (is_array($data['user_tag']) && empty($data['user_tag'])) || !$data['user_tag'])) {
|
||||
throw new AdminException('请至少选择一种用户筛选条件');
|
||||
}
|
||||
}
|
||||
// 验证赠送内容
|
||||
// if (!isset($data['gift_type']) || !$data['gift_type']) {
|
||||
// throw new AdminException('请选择赠送内容');
|
||||
// }
|
||||
$giftTypes = is_array($data['gift_type']) ? $data['gift_type'] : explode(',', $data['gift_type']);
|
||||
foreach ($giftTypes as $type) {
|
||||
if ($type == array_search('优惠券', HolidayGift::GIFT_TYPE) && (!isset($data['coupon_ids']) || (is_array($data['coupon_ids']) && empty($data['coupon_ids'])) || !$data['coupon_ids'])) {
|
||||
throw new AdminException('请选择赠送的优惠券');
|
||||
}
|
||||
if ($type == array_search('积分', HolidayGift::GIFT_TYPE) && (!isset($data['integral']) || $data['integral'] <= 0)) {
|
||||
throw new AdminException('请输入正确的赠送积分数量');
|
||||
}
|
||||
if ($type == array_search('多倍积分', HolidayGift::GIFT_TYPE) && (!isset($data['integral_multiple']) || $data['integral_multiple'] <= 1)) {
|
||||
throw new AdminException('请输入正确的积分倍数,必须大于1');
|
||||
}
|
||||
if ($type == array_search('余额', HolidayGift::GIFT_TYPE) && (!isset($data['balance']) || $data['balance'] <= 0)) {
|
||||
throw new AdminException('请输入正确的赠送余额');
|
||||
}
|
||||
}
|
||||
|
||||
// 验证推送渠道
|
||||
if (!isset($data['push_channel']) || (is_array($data['push_channel']) && empty($data['push_channel'])) || !$data['push_channel']) {
|
||||
throw new AdminException('请选择推送渠道');
|
||||
}
|
||||
$pushChannels = is_array($data['push_channel']) ? $data['push_channel'] : explode(',', $data['push_channel']);
|
||||
foreach ($pushChannels as $channel) {
|
||||
if ($channel == array_search('公众号', HolidayGift::PUSH_CHANNEL) && (!isset($data['wechat_image']) || (is_array($data['wechat_image']) && empty($data['wechat_image'])) || !$data['wechat_image'])) {
|
||||
throw new AdminException('请上传公众号推送图片');
|
||||
}
|
||||
}
|
||||
|
||||
// 验证推送频次
|
||||
if (!isset($data['push_frequency']) || !in_array((int)$data['push_frequency'], array_keys(HolidayGift::PUSH_FREQUENCY))) {
|
||||
throw new AdminException('请选择正确的推送频次');
|
||||
}
|
||||
if ($data['push_frequency'] == array_search('每周', HolidayGift::PUSH_FREQUENCY) && (!isset($data['push_week_days']) || (is_array($data['push_week_days']) && empty($data['push_week_days'])) || !$data['push_week_days'])) {
|
||||
throw new AdminException('请选择每周推送的星期几');
|
||||
}
|
||||
|
||||
// 验证应用界面
|
||||
if (!isset($data['show_page']) || (is_array($data['show_page']) && empty($data['show_page'])) || !$data['show_page']) {
|
||||
throw new AdminException('请选择应用界面');
|
||||
}
|
||||
$showPages = is_array($data['show_page']) ? $data['show_page'] : explode(',', $data['show_page']);
|
||||
foreach ($showPages as $page) {
|
||||
if ($page == array_search('专题页面', HolidayGift::SHOW_PAGE) && (!isset($data['topic_ids']) || (is_array($data['topic_ids']) && empty($data['topic_ids'])) || !$data['topic_ids'])) {
|
||||
throw new AdminException('请选择专题页面');
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取活动中的节日有礼
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getActiveHolidayGift(array $where = [])
|
||||
{
|
||||
return $this->dao->getActiveHolidayGift($where);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户生日相关的节日有礼活动
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getBirthdayHolidayGift(array $where = [])
|
||||
{
|
||||
return $this->dao->getBirthdayHolidayGift($where);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取活动日期相关的节日有礼活动
|
||||
* @param string $date 日期,格式:MM-DD
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getCustomDateHolidayGift(string $date, array $where = [])
|
||||
{
|
||||
return $this->dao->getCustomDateHolidayGift($date, $where);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取每月活动日期相关的节日有礼活动
|
||||
* @param int $day 日期,1-31
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getMonthlyHolidayGift(int $day, array $where = [])
|
||||
{
|
||||
return $this->dao->getMonthlyHolidayGift($day, $where);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取每周活动日期相关的节日有礼活动
|
||||
* @param int $weekDay 周几,1-7表示周一到周日
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getWeeklyHolidayGift(int $weekDay, array $where = [])
|
||||
{
|
||||
return $this->dao->getWeeklyHolidayGift($weekDay, $where);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前日期相关的所有节日有礼活动
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getTodayHolidayGift(array $where = [])
|
||||
{
|
||||
$activities = [];
|
||||
$today = date('m-d'); // MM-DD格式
|
||||
$todayDay = (int)date('d'); // 当前日期
|
||||
$todayWeek = (int)date('N'); // 当前周几,1-7表示周一到周日
|
||||
|
||||
// 获取自定义日期活动
|
||||
$customDateActivities = $this->getCustomDateHolidayGift($today, $where);
|
||||
$activities = array_merge($activities, $customDateActivities);
|
||||
|
||||
// 获取每月活动
|
||||
$monthlyActivities = $this->getMonthlyHolidayGift($todayDay, $where);
|
||||
$activities = array_merge($activities, $monthlyActivities);
|
||||
|
||||
// 获取每周活动
|
||||
$weeklyActivities = $this->getWeeklyHolidayGift($todayWeek, $where);
|
||||
$activities = array_merge($activities, $weeklyActivities);
|
||||
|
||||
// 去重(根据ID)
|
||||
$uniqueActivities = [];
|
||||
$ids = [];
|
||||
foreach ($activities as $activity) {
|
||||
if (!in_array($activity['id'], $ids)) {
|
||||
$uniqueActivities[] = $activity;
|
||||
$ids[] = $activity['id'];
|
||||
}
|
||||
}
|
||||
|
||||
return $uniqueActivities;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检查用户是否符合节日有礼活动条件
|
||||
* @param int $uid 用户ID
|
||||
* @param array $giftInfo 节日有礼活动信息
|
||||
* @return bool
|
||||
*/
|
||||
public function checkUserCondition(int $uid, array $giftInfo)
|
||||
{
|
||||
|
||||
// 如果是全部人群,直接返回true
|
||||
if ($giftInfo['push_user_type'] == 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 指定人群,需要检查条件
|
||||
$isLevelMatch = $isLabelMatch = $isTagMatch = true;
|
||||
// 检查用户等级
|
||||
if (!empty($giftInfo['user_level'])) {
|
||||
$isLevelMatch = false;
|
||||
$userLevelService = app()->make(UserLevelServices::class);
|
||||
$userLevel = $userLevelService->getUserLevel($uid);
|
||||
if ($userLevel) {
|
||||
$levelIds = is_string($giftInfo['user_level']) ? explode(',', $giftInfo['user_level']) : $giftInfo['user_level'];
|
||||
$isLevelMatch = in_array($userLevel['level_id'], $levelIds);
|
||||
}
|
||||
}
|
||||
// 检查用户标签
|
||||
if (!empty($giftInfo['user_label'])) {
|
||||
$isLabelMatch = false;
|
||||
$userLabelRelationService = app()->make(UserLabelRelationServices::class);
|
||||
$userLabels = $userLabelRelationService->getUserLabels($uid);
|
||||
if ($userLabels) {
|
||||
$labelIds = is_string($giftInfo['user_label']) ? explode(',', $giftInfo['user_label']) : $giftInfo['user_label'];
|
||||
$isLabelMatch = (bool)empty(array_diff($labelIds, $userLabels));
|
||||
}
|
||||
}
|
||||
|
||||
// 检查客户身份
|
||||
if (!empty($giftInfo['user_tag'])) {
|
||||
$isTagMatch = false;
|
||||
$userService = app()->make(UserServices::class);
|
||||
$userTag = $userService->checkUserTag($uid);
|
||||
if ($userTag) {
|
||||
|
||||
$tagIds = is_string($giftInfo['user_tag']) ? explode(',', $giftInfo['user_tag']) : $giftInfo['user_tag'];
|
||||
$isTagMatch = (bool)empty(array_diff($tagIds, $userTag));
|
||||
}
|
||||
}
|
||||
// 根据条件满足类型返回结果
|
||||
if ($giftInfo['condition_type'] == 1) { // 满足任一条件
|
||||
return $isLevelMatch || $isLabelMatch || $isTagMatch;
|
||||
} else { // 满足全部条件
|
||||
return $isLevelMatch && $isLabelMatch && $isTagMatch;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查弹框广告是否符合节日有礼活动条件
|
||||
* @param int $uid 用户ID
|
||||
* @param array $giftInfo 节日有礼活动信息
|
||||
* @return bool
|
||||
*/
|
||||
public function checkPopupAdCondition(int $uid, array $giftInfo)
|
||||
{
|
||||
// 检查推送渠道是否包含弹框广告
|
||||
$pushChannels = is_array($giftInfo['push_channel']) ? $giftInfo['push_channel'] : explode(',', $giftInfo['push_channel']);
|
||||
$popupAdChannel = 3;
|
||||
if (!in_array($popupAdChannel, $pushChannels)) {
|
||||
return false;
|
||||
}
|
||||
// 根据推送频次检查是否可以推送
|
||||
/** @var HolidayGiftPushServices $pushService */
|
||||
$pushService = app()->make(HolidayGiftPushServices::class);
|
||||
switch ($giftInfo['push_frequency']) {
|
||||
case 1: // 永久一次
|
||||
// 检查是否已经推送过
|
||||
$pushRecord = $pushService->getUserPushRecord($uid, $giftInfo['id']);
|
||||
return empty($pushRecord);
|
||||
|
||||
case 2: // 每次进入
|
||||
return true; // 每次都可以推送
|
||||
|
||||
case 3: // 每天
|
||||
// 检查今天是否已经推送过
|
||||
$todayRecord = $pushService->getUserTodayPushRecord($uid, $giftInfo['id']);
|
||||
return empty($todayRecord);
|
||||
|
||||
case 4: // 每月
|
||||
// 检查本月是否已经推送过
|
||||
$monthRecord = $pushService->getUserMonthPushRecord($uid, $giftInfo['id']);
|
||||
return empty($monthRecord);
|
||||
|
||||
case 5: // 每周
|
||||
// 检查今天是否是设置的星期几
|
||||
$weekDay = date('N'); // 1-7 表示周一到周日
|
||||
$weekDays = explode(',', $giftInfo['push_week_days']);
|
||||
if (!in_array($weekDay, $weekDays)) {
|
||||
return false; // 今天不是设置的星期几,不能推送
|
||||
}
|
||||
|
||||
// 检查本周是否已经推送过
|
||||
$weekRecord = $pushService->getUserWeekPushRecord($uid, $giftInfo['id']);
|
||||
return empty($weekRecord);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否在推送时段内
|
||||
* @param array $giftInfo 节日有礼活动信息
|
||||
* @return bool
|
||||
*/
|
||||
public function checkPushTimeRange(array $giftInfo, int $uid = 0)
|
||||
{
|
||||
// 如果是全时段,直接返回true
|
||||
if ($giftInfo['push_time_type'] == 1) {
|
||||
return true;
|
||||
}
|
||||
// 指定时段,需要检查当前时间是否在时段内
|
||||
$now = date('H:i');
|
||||
$startTime = $giftInfo['push_start_time'];
|
||||
$endTime = $giftInfo['push_end_time'];
|
||||
|
||||
return $now >= $startTime && $now <= $endTime;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取当前有效的节日有礼活动
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getActiveHolidayGifts()
|
||||
{
|
||||
$currentTime = time();
|
||||
$where = [
|
||||
'status' => 1,
|
||||
'is_del' => 0,
|
||||
'is_valid' => 1,
|
||||
];
|
||||
$list = $this->dao->search($where)
|
||||
->select()
|
||||
->toArray();
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 推送节日有礼消息
|
||||
* @param int $uid 用户ID
|
||||
* @param array $giftInfo 节日有礼活动信息
|
||||
* @return bool
|
||||
*/
|
||||
public function pushHolidayGiftMessage(int $uid, array $giftInfo)
|
||||
{
|
||||
if (!$uid || !$giftInfo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
/** @var UserServices $userService */
|
||||
$userService = app()->make(UserServices::class);
|
||||
$userInfo = $userService->getUserInfo($uid);
|
||||
if (!$userInfo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 准备推送记录数据
|
||||
$pushData = [
|
||||
'gift_id' => $giftInfo['id'],
|
||||
'uid' => $uid,
|
||||
'push_time' => time(),
|
||||
'status' => 0,
|
||||
'add_time' => time()
|
||||
];
|
||||
|
||||
// 处理不同推送渠道
|
||||
$pushChannels = explode(',', $giftInfo['push_channel']);
|
||||
$pushSuccess = false;
|
||||
|
||||
/** @var HolidayGiftPushServices $pushService */
|
||||
$pushService = app()->make(HolidayGiftPushServices::class);
|
||||
/** @var NoticeServices $noticeService */
|
||||
$noticeService = app()->make(NoticeServices::class);
|
||||
|
||||
foreach ($pushChannels as $channel) {
|
||||
switch ($channel) {
|
||||
case 1: // 短信
|
||||
if (!empty($userInfo['phone'])) {
|
||||
$pushData['push_type'] = 1;
|
||||
$pushData['push_content'] = '尊敬的用户,您有一份节日礼物待领取,请登录APP查看。';
|
||||
|
||||
// 发送短信
|
||||
$noticeService->smsNotice($userInfo['phone'], ['gift_name' => $giftInfo['name']], 'HOLIDAY_GIFT');
|
||||
|
||||
$pushData['status'] = 1;
|
||||
$pushService->save($pushData);
|
||||
$pushSuccess = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // 公众号
|
||||
if (!empty($userInfo['openid'])) {
|
||||
$pushData['push_type'] = 2;
|
||||
$pushData['push_content'] = '尊敬的用户,您有一份节日礼物待领取,请登录APP查看。';
|
||||
|
||||
// 发送公众号消息
|
||||
$noticeService->wechatNotice($userInfo['openid'], 'HOLIDAY_GIFT', [
|
||||
'first' => '节日有礼提醒',
|
||||
'keyword1' => $giftInfo['name'],
|
||||
'keyword2' => date('Y-m-d H:i:s'),
|
||||
'remark' => '点击领取您的节日礼物'
|
||||
], '');
|
||||
|
||||
$pushData['status'] = 1;
|
||||
$pushService->save($pushData);
|
||||
$pushSuccess = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // 弹框广告
|
||||
$pushData['push_type'] = 3;
|
||||
$pushData['push_content'] = '弹框广告推送';
|
||||
$pushData['status'] = 1;
|
||||
$pushService->save($pushData);
|
||||
$pushSuccess = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $pushSuccess;
|
||||
}
|
||||
}
|
||||
120
app/services/activity/integral/StoreIntegralCategoryServices.php
Normal file
120
app/services/activity/integral/StoreIntegralCategoryServices.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\integral;
|
||||
|
||||
use app\dao\other\CategoryDao;
|
||||
use app\services\BaseServices;
|
||||
use app\services\other\CategoryServices;
|
||||
use crmeb\services\FormBuilder as Form;
|
||||
use think\annotation\Inject;
|
||||
use think\facade\Route as Url;
|
||||
|
||||
/**
|
||||
* 积分商品
|
||||
* Class StoreIntegralServices
|
||||
* @package app\services\activity\integral
|
||||
* @mixin CategoryDao
|
||||
*/
|
||||
class StoreIntegralCategoryServices extends BaseServices
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @var CategoryDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected CategoryDao $dao;
|
||||
|
||||
/**
|
||||
* 分类类型
|
||||
* @var int
|
||||
*/
|
||||
protected int $group = CategoryServices::INTEGRAL_CATEGORY_GROUP;
|
||||
|
||||
/**
|
||||
* 获取积分分类列表
|
||||
* @param array $where 查询条件
|
||||
* @return array
|
||||
*/
|
||||
public function getList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$count = $this->dao->count($where);
|
||||
$list = $this->dao->getCateList($where, $page, $limit);
|
||||
if ($list) {
|
||||
foreach ($list as &$item) {
|
||||
$item['add_time'] = $item['add_time'] ? date('Y-m-d H:i:s', $item['add_time']) : '';
|
||||
}
|
||||
}
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建新增表单
|
||||
* @return array
|
||||
* @throws \FormBuilder\Exception\FormBuilderException
|
||||
*/
|
||||
public function createForm()
|
||||
{
|
||||
return create_form('添加分类', $this->form(), Url::buildUrl('/marketing/integral/category'), 'POST');
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建编辑表单
|
||||
* @param $id
|
||||
* @return array
|
||||
* @throws \FormBuilder\Exception\FormBuilderException
|
||||
*/
|
||||
public function editForm(int $id)
|
||||
{
|
||||
$info = $this->dao->get($id);
|
||||
return create_form('编辑分类', $this->form($info), $this->url('/marketing/integral/category/' . $id), 'POST');
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成表单参数
|
||||
* @param array $info
|
||||
* @return array
|
||||
* @throws \FormBuilder\Exception\FormBuilderException
|
||||
*/
|
||||
public function form($info = [])
|
||||
{
|
||||
$f[] = Form::input('name', '分类名称:', $info['name'] ?? '')->maxlength(30)->required();
|
||||
$f[] = Form::number('integral_min', '最低积分:', (int)($info['integral_min'] ?? 0))->min(0);
|
||||
$f[] = Form::number('integral_max', '最高积分:', (int)($info['integral_max'] ?? 0))->min(0);
|
||||
$f[] = Form::radio('is_show', '状态:', $info['is_show'] ?? 1)->options([['label' => '显示', 'value' => 1], ['label' => '隐藏', 'value' => 0]]);
|
||||
$f[] = Form::number('sort', '排序:', (int)($info['sort'] ?? 0))->min(0);
|
||||
return $f;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取积分分类树形结构列表
|
||||
* @return array
|
||||
*/
|
||||
public function getTreeList()
|
||||
{
|
||||
$where = [
|
||||
'is_show' => 1,
|
||||
'group' => CategoryServices::INTEGRAL_CATEGORY_GROUP,
|
||||
];
|
||||
$list = $this->dao->search($where)->field(['name', 'integral_min', 'integral_max'])->order('sort DESC')->select()->toArray();
|
||||
$data = [];
|
||||
foreach ($list as $item) {
|
||||
$data[] = [
|
||||
'label' => $item['name'],
|
||||
'value' => "{$item['integral_min']}-{$item['integral_max']}"
|
||||
];
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
213
app/services/activity/integral/StoreIntegralOrderServices.php
Normal file
213
app/services/activity/integral/StoreIntegralOrderServices.php
Normal file
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\activity\integral;
|
||||
|
||||
|
||||
use app\dao\activity\integral\StoreIntegralOrderDao;
|
||||
use app\services\BaseServices;
|
||||
use app\services\user\UserServices;
|
||||
use app\services\user\UserBillServices;
|
||||
use crmeb\services\SystemConfigService;
|
||||
use crmeb\utils\Arr;
|
||||
use think\annotation\Inject;
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\DbException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
use think\facade\Log;
|
||||
|
||||
/**
|
||||
* Class StoreIntegralOrderServices
|
||||
* @package app\services\activity\integral
|
||||
* @mixin StoreIntegralOrderDao
|
||||
*/
|
||||
class StoreIntegralOrderServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var StoreIntegralOrderDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreIntegralOrderDao $dao;
|
||||
|
||||
/**
|
||||
* 获取列表
|
||||
* @param array $where
|
||||
* @param array $field
|
||||
* @param array $with
|
||||
* @return array
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function getOrderList(array $where, array $field = ['*'], array $with = [])
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$data = $this->dao->getOrderList($where, $field, $page, $limit, $with);
|
||||
$count = $this->dao->count($where);
|
||||
$data = $this->tidyOrderList($data);
|
||||
$batch_url = "file/upload/1";
|
||||
return compact('data', 'count', 'batch_url');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取导出数据
|
||||
* @param array $where
|
||||
* @param int $limit
|
||||
* @return array
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function getExportList(array $where, int $limit = 0)
|
||||
{
|
||||
if ($limit) {
|
||||
[$page] = $this->getPageValue();
|
||||
} else {
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
}
|
||||
$data = $this->dao->getOrderList($where, ['*'], $page, $limit);
|
||||
$data = $this->tidyOrderList($data);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 前端订单列表
|
||||
* @param array $where
|
||||
* @param array|string[] $field
|
||||
* @param array $with
|
||||
* @return array
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function getOrderApiList(array $where, array $field = ['*'], array $with = [])
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$data = $this->dao->getOrderList($where, $field, $page, $limit, $with);
|
||||
$data = $this->tidyOrderList($data);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单详情数据格式化
|
||||
* @param $order
|
||||
* @return mixed
|
||||
*/
|
||||
public function tidyOrder($order)
|
||||
{
|
||||
$order['_add_time'] = $order['add_time'] = date('Y-m-d H:i:s', $order['add_time']);
|
||||
if ($order['status'] == 1) {
|
||||
$order['status_name'] = '未发货';
|
||||
} else if ($order['status'] == 2) {
|
||||
$order['status_name'] = '待收货';
|
||||
} else if ($order['status'] == 3) {
|
||||
$order['status_name'] = '已完成';
|
||||
}
|
||||
return $order;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据转换
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function tidyOrderList(array $data)
|
||||
{
|
||||
foreach ($data as &$item) {
|
||||
$item['add_time'] = date('Y-m-d H:i:s', $item['add_time']);
|
||||
if (!$item['paid']) {
|
||||
$item['status_name'] = '待付款';
|
||||
} else if ($item['status'] == 1) {
|
||||
$item['status_name'] = '未发货';
|
||||
} else if ($item['status'] == 2) {
|
||||
$item['status_name'] = '待收货';
|
||||
} else if ($item['status'] == 3) {
|
||||
$item['status_name'] = '已完成';
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 未支付积分订单退积分
|
||||
* @return bool|void
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function rebatePointsOrders()
|
||||
{
|
||||
//废弃 积分订单合并入统一下单流程
|
||||
//先完成支付 后在支付积分
|
||||
return true;
|
||||
$where['is_del'] = 0;
|
||||
$where['is_system_del'] = 0;
|
||||
$where['paid'] = 0;
|
||||
$where['is_price'] = 1;
|
||||
$where['is_integral'] = 1;
|
||||
$list = $this->dao->getIntegralOrderList($where);
|
||||
//系统预设取消订单时间段
|
||||
$keyValue = ['rebate_points_orders_time', 'order_cancel_time'];
|
||||
//获取配置
|
||||
$systemValue = SystemConfigService::more($keyValue);
|
||||
//格式化数据
|
||||
$systemValue = Arr::setValeTime($keyValue, is_array($systemValue) ? $systemValue : []);
|
||||
$order_cancel_time = $systemValue['rebate_points_orders_time'] ?: $systemValue['order_cancel_time'];
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
/** @var UserBillServices $userBillServices */
|
||||
$userBillServices = app()->make(UserBillServices::class);
|
||||
$order_cancel_time = (int)bcmul((string)$order_cancel_time, '3600', 0);
|
||||
foreach ($list as $key => $item) {
|
||||
if (($item['add_time'] + $order_cancel_time) < time()) {
|
||||
try {
|
||||
$this->transaction(function () use ($item, $userServices, $userBillServices) {
|
||||
$user_integral = $userServices->value(['uid' => $item['uid']], 'integral');
|
||||
$res = $userServices->incUpdate(['uid' => $item['uid']], 'integral', (int)$item['integral']);
|
||||
$integral = bcadd((string)$user_integral, (string)$item['integral']);
|
||||
$res1 = $userBillServices->income('integral_refund', $item['uid'], (int)$item['integral'], (int)$integral, $item['id']);
|
||||
//修改订单状态
|
||||
$res = $res && $res1 && $this->dao->update($item['id'], ['is_del' => 1, 'is_system_del' => 1, 'mark' => '积分订单未支付已超过系统预设时间']);
|
||||
});
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('未支付积分订单退积分失败,失败原因:' . $e->getMessage(), $e->getTrace());
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*获取订单数量
|
||||
* @param array $where
|
||||
* @return mixed
|
||||
*/
|
||||
public function orderCount(array $where)
|
||||
{
|
||||
$where['type'] = 4;
|
||||
//全部订单
|
||||
$data['statusAll'] = (string)$this->dao->count($where + ['is_system_del' => 0]);
|
||||
//未发货
|
||||
$data['unshipped'] = (string)$this->dao->count($where + ['status' => 1, 'is_system_del' => 0]);
|
||||
//待收货
|
||||
$data['untake'] = (string)$this->dao->count($where + ['status' => 2, 'is_system_del' => 0]);
|
||||
//待评价
|
||||
// $data['unevaluate'] = (string)$this->dao->count(['status' => 3, 'time' => $where['time'], 'is_system_del' => 0]);
|
||||
//交易完成
|
||||
$data['complete'] = (string)$this->dao->count($where + ['status' => 3, 'is_system_del' => 0]);
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\activity\integral;
|
||||
|
||||
|
||||
use app\dao\activity\integral\StoreIntegralOrderStatusDao;
|
||||
use app\services\BaseServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* 订单状态
|
||||
* Class StoreIntegralOrderStatusServices
|
||||
* @package app\services\activity\integral
|
||||
* @mixin StoreIntegralOrderStatusDao
|
||||
*/
|
||||
class StoreIntegralOrderStatusServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var StoreIntegralOrderStatusDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreIntegralOrderStatusDao $dao;
|
||||
|
||||
/**
|
||||
* 订单状态分页
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getStatusList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getStatusList($where, $page, $limit);
|
||||
foreach ($list as &$item) {
|
||||
if (is_int($item['change_time'])) $item['change_time'] = date('Y-m-d H:i:s', $item['change_time']);
|
||||
}
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
}
|
||||
453
app/services/activity/integral/StoreIntegralServices.php
Normal file
453
app/services/activity/integral/StoreIntegralServices.php
Normal file
@@ -0,0 +1,453 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\integral;
|
||||
|
||||
use app\services\BaseServices;
|
||||
use app\dao\activity\integral\StoreIntegralDao;
|
||||
use app\services\diy\DiyServices;
|
||||
use app\services\order\StoreOrderServices;
|
||||
use app\services\product\ensure\StoreProductEnsureServices;
|
||||
use app\services\product\label\StoreProductLabelServices;
|
||||
use app\services\product\product\StoreDescriptionServices;
|
||||
use app\services\product\product\StoreProductServices;
|
||||
use app\services\product\sku\StoreProductAttrResultServices;
|
||||
use app\services\product\sku\StoreProductAttrServices;
|
||||
use app\services\product\sku\StoreProductAttrValueServices;
|
||||
use app\jobs\product\ProductLogJob;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use crmeb\services\CacheService;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
/**
|
||||
* 积分商品
|
||||
* Class StoreIntegralServices
|
||||
* @package app\services\activity\integral
|
||||
* @mixin StoreIntegralDao
|
||||
*/
|
||||
class StoreIntegralServices extends BaseServices
|
||||
{
|
||||
const THODLCEG = 'ykGUKB';
|
||||
|
||||
/**
|
||||
* 商品活动类型
|
||||
*/
|
||||
const TYPE = 4;
|
||||
|
||||
/**
|
||||
* @var StoreIntegralDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreIntegralDao $dao;
|
||||
|
||||
/**
|
||||
* 获取指定条件下的条数
|
||||
* @param array $where
|
||||
*/
|
||||
public function getCount(array $where)
|
||||
{
|
||||
$this->dao->count($where);
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分商品添加
|
||||
* @param int $id
|
||||
* @param array $data
|
||||
*/
|
||||
public function saveData(int $id, array $data)
|
||||
{
|
||||
if ($data['freight'] == 2 && !$data['postage']) {
|
||||
throw new AdminException('请设置运费金额');
|
||||
}
|
||||
if ($data['freight'] == 3 && !$data['temp_id']) {
|
||||
throw new AdminException('请选择运费模版');
|
||||
}
|
||||
/** @var StoreProductServices $storeProductServices */
|
||||
$storeProductServices = app()->make(StoreProductServices::class);
|
||||
$productInfo = $storeProductServices->getOne(['is_del' => 0, 'is_verify' => 1, 'id' => $data['product_id']]);
|
||||
if (!$productInfo) {
|
||||
throw new AdminException('原商品已移入回收站');
|
||||
}
|
||||
if ($productInfo['is_vip_product']) {
|
||||
throw new AdminException("【{$productInfo["store_name"]}】是svip专享");
|
||||
}
|
||||
if ($productInfo['is_presale_product']) {
|
||||
throw new AdminException("【{$productInfo["store_name"]}】是预售商品");
|
||||
}
|
||||
$data['delivery_type'] = $productInfo['delivery_type'];
|
||||
$data['product_type'] = $productInfo['product_type'];
|
||||
$data['type'] = $productInfo['type'] ?? 0;
|
||||
$data['relation_id'] = $productInfo['relation_id'] ?? 0;
|
||||
$custom_form = $productInfo['custom_form'] ?? [];
|
||||
$data['custom_form'] = is_array($custom_form) ? json_encode($custom_form) : $custom_form;
|
||||
$data['system_form_id'] = $productInfo['system_form_id'] ?? 0;
|
||||
$store_label_id = $productInfo['store_label_id'] ?? [];
|
||||
$data['store_label_id'] = is_array($store_label_id) ? implode(',', $store_label_id) : $store_label_id;
|
||||
$ensure_id = $productInfo['ensure_id'] ?? [];
|
||||
$data['ensure_id'] = is_array($ensure_id) ? implode(',', $ensure_id) : $ensure_id;
|
||||
$specs = $productInfo['specs'] ?? [];
|
||||
$data['specs'] = is_array($specs) ? json_encode($specs) : $specs;
|
||||
$description = $data['description'];
|
||||
$detail = $data['attrs'];
|
||||
if ($detail) {
|
||||
foreach ($detail as $attr) {
|
||||
if ($attr['quota'] > $attr['stock']) {
|
||||
throw new AdminException('限量超过了商品库存');
|
||||
}
|
||||
}
|
||||
}
|
||||
$items = $data['items'];
|
||||
if (!$data['image'] && count($data['images']) > 0) {
|
||||
$data['image'] = $data['images'][0];
|
||||
}
|
||||
$data['images'] = json_encode($data['images']);
|
||||
$integral_data = array_column($detail, 'integral', 'price');
|
||||
$data['integral'] = $integral_data ? (int)min($integral_data) : 0;
|
||||
$data['price'] = array_search($data['integral'], $integral_data);
|
||||
$data['quota'] = $data['quota_show'] = array_sum(array_column($detail, 'quota'));
|
||||
if ($data['quota'] > $storeProductServices->value(['id' => $data['product_id']], 'stock')) {
|
||||
throw new ValidateException('限量不能超过商品库存');
|
||||
}
|
||||
$data['stock'] = array_sum(array_column($detail, 'stock'));
|
||||
unset($data['section_time'], $data['description'], $data['attrs'], $data['items']);
|
||||
/** @var StoreDescriptionServices $storeDescriptionServices */
|
||||
$storeDescriptionServices = app()->make(StoreDescriptionServices::class);
|
||||
/** @var StoreProductAttrServices $storeProductAttrServices */
|
||||
$storeProductAttrServices = app()->make(StoreProductAttrServices::class);
|
||||
$this->transaction(function () use ($id, $data, $description, $detail, $items, $storeDescriptionServices, $storeProductAttrServices, $storeProductServices) {
|
||||
if ($id) {
|
||||
$res = $this->dao->update($id, $data);
|
||||
if (!$res) throw new AdminException('修改失败');
|
||||
} else {
|
||||
if (!$storeProductServices->getOne(['is_del' => 0, 'is_verify' => 1, 'id' => $data['product_id']])) {
|
||||
throw new AdminException('原商品已移入回收站');
|
||||
}
|
||||
$data['add_time'] = time();
|
||||
$res = $this->dao->save($data);
|
||||
if (!$res) throw new AdminException('添加失败');
|
||||
$id = (int)$res->id;
|
||||
}
|
||||
$storeDescriptionServices->saveDescription((int)$id, $description, 4);
|
||||
$storeProductAttrServices->setItem('store_product_id', $data['product_id']);
|
||||
$skuList = $storeProductAttrServices->validateProductAttr($items, $detail, (int)$id, 4);
|
||||
$storeProductAttrServices->reset();
|
||||
$valueGroup = $storeProductAttrServices->saveProductAttr($skuList, (int)$id, 4);
|
||||
|
||||
$res = true;
|
||||
foreach ($valueGroup as $item) {
|
||||
$res = $res && CacheService::setStock($item['unique'], (int)$item['quota_show'], 4);
|
||||
}
|
||||
if (!$res) {
|
||||
throw new AdminException('占用库存失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量添加商品
|
||||
* @param array $data
|
||||
*/
|
||||
public function saveBatchData(array $data)
|
||||
{
|
||||
/** @var StoreProductServices $service */
|
||||
$service = app()->make(StoreProductServices::class);
|
||||
/** @var StoreDescriptionServices $storeDescriptionServices */
|
||||
$storeDescriptionServices = app()->make(StoreDescriptionServices::class);
|
||||
/** @var StoreProductAttrResultServices $storeProductAttrResultServices */
|
||||
$storeProductAttrResultServices = app()->make(StoreProductAttrResultServices::class);
|
||||
if (!$data) {
|
||||
throw new ValidateException('请先添加产品!');
|
||||
}
|
||||
$attrs = [];
|
||||
foreach ($data['attrs'] as $k => $v) {
|
||||
$attrs[$v['product_id']][] = $v;
|
||||
}
|
||||
foreach ($attrs as $k => $v) {
|
||||
$productInfo = $service->getOne(['id' => $k]);
|
||||
$productInfo = is_object($productInfo) ? $productInfo->toArray() : [];
|
||||
if ($productInfo) {
|
||||
$product = [];
|
||||
$result = $storeProductAttrResultServices->getResult(['product_id' => $productInfo['id'], 'type' => 0]);
|
||||
$product['product_id'] = $productInfo['id'];
|
||||
$product['description'] = $storeDescriptionServices->getDescription(['product_id' => $productInfo['id'], 'type' => 0]);
|
||||
$product['attrs'] = $v;
|
||||
$product['items'] = $result['attr'];
|
||||
$product['is_show'] = isset($data['is_show']) ? $data['is_show'] : 0;
|
||||
$product['title'] = $productInfo['store_name'];
|
||||
$product['unit_name'] = $productInfo['unit_name'];
|
||||
$product['image'] = $productInfo['image'];
|
||||
$product['images'] = $productInfo['slider_image'];
|
||||
$product['num'] = 0;
|
||||
$product['is_host'] = 0;
|
||||
$product['once_num'] = 0;
|
||||
$product['sort'] = 0;
|
||||
$this->saveData(0, $product);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分商品列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function systemPage(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getList($where, $page, $limit);
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取详情
|
||||
* @param int $id
|
||||
* @return array|\think\Model|null
|
||||
*/
|
||||
public function getInfo(int $id)
|
||||
{
|
||||
$info = $this->dao->get($id);
|
||||
if (!$info) {
|
||||
throw new ValidateException('查看的商品不存在!');
|
||||
}
|
||||
if ($info->is_del) {
|
||||
throw new ValidateException('您查看的积分商品已被删除!');
|
||||
}
|
||||
$info['price'] = floatval($info['price']);
|
||||
/** @var StoreDescriptionServices $storeDescriptionServices */
|
||||
$storeDescriptionServices = app()->make(StoreDescriptionServices::class);
|
||||
$info['description'] = $storeDescriptionServices->getDescription(['product_id' => $id, 'type' => 4]);
|
||||
/** @var StoreProductAttrValueServices $storeProductAttrValueServices */
|
||||
$storeProductAttrValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
$info['attrs'] = $storeProductAttrValueServices->attrList($id, $info['product_id'], 4);
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分商品详情
|
||||
* @param int $uid
|
||||
* @param int $id
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function integralDetail(int $uid, int $id)
|
||||
{
|
||||
$storeInfo = $this->dao->getOne(['id' => $id], '*,title as store_name', ['getPrice']);
|
||||
if (!$storeInfo) {
|
||||
throw new ValidateException('商品不存在');
|
||||
} else {
|
||||
$storeInfo = $storeInfo->toArray();
|
||||
}
|
||||
/** @var DiyServices $diyServices */
|
||||
$diyServices = app()->make(DiyServices::class);
|
||||
$infoDiy = $diyServices->getProductDetailDiy();
|
||||
//diy控制参数
|
||||
if (!isset($infoDiy['showService']) || in_array(3, $infoDiy['showService'])) {
|
||||
$storeInfo['specs'] = [];
|
||||
}
|
||||
$siteUrl = sys_config('site_url');
|
||||
$storeInfo['store_name'] = $storeInfo['title'];
|
||||
$storeInfo['image'] = set_file_url($storeInfo['image'], $siteUrl);
|
||||
$storeInfo['image_base'] = set_file_url($storeInfo['image'], $siteUrl);
|
||||
$storeInfo['sale_stock'] = 0;
|
||||
if ($storeInfo['stock'] > 0) $storeInfo['sale_stock'] = 1;
|
||||
/** @var StoreDescriptionServices $storeDescriptionService */
|
||||
$storeDescriptionService = app()->make(StoreDescriptionServices::class);
|
||||
$storeInfo['description'] = $storeDescriptionService->getDescription(['product_id' => $id, 'type' => 4]);
|
||||
$storeInfo['store_label'] = $storeInfo['ensure'] = [];
|
||||
if ($storeInfo['store_label_id']) {
|
||||
/** @var StoreProductLabelServices $storeProductLabelServices */
|
||||
$storeProductLabelServices = app()->make(StoreProductLabelServices::class);
|
||||
$storeInfo['store_label'] = $storeProductLabelServices->getLabelCache($storeInfo['store_label_id'], ['id', 'label_name', 'style_type', 'color', 'bg_color', 'border_color', 'icon']);
|
||||
}
|
||||
if ($storeInfo['ensure_id'] && isset($infoDiy['showService']) && in_array(2, $infoDiy['showService'])) {
|
||||
/** @var StoreProductEnsureServices $storeProductEnsureServices */
|
||||
$storeProductEnsureServices = app()->make(StoreProductEnsureServices::class);
|
||||
$storeInfo['ensure'] = $storeProductEnsureServices->getEnsurCache($storeInfo['ensure_id'], ['id', 'name', 'image', 'desc']);
|
||||
}
|
||||
$storeInfo['small_image'] = get_thumb_water($storeInfo['image']);
|
||||
|
||||
/** @var StoreProductServices $storeProductServices */
|
||||
$storeProductServices = app()->make(StoreProductServices::class);
|
||||
$storeInfo['brand_name'] = $storeProductServices->productIdByBrandName((int)$storeInfo['product_id']);
|
||||
|
||||
$data['storeInfo'] = $storeInfo;
|
||||
|
||||
/** @var StoreProductAttrServices $storeProductAttrServices */
|
||||
$storeProductAttrServices = app()->make(StoreProductAttrServices::class);
|
||||
[$productAttr, $productValue] = $storeProductAttrServices->getProductAttrDetail($id, $uid, 0, 4, $storeInfo['product_id']);
|
||||
$data['productAttr'] = $productAttr;
|
||||
$data['productValue'] = $productValue;
|
||||
$data['site_name'] = sys_config('site_name');
|
||||
$data['share_qrcode'] = sys_config('share_qrcode', 0);
|
||||
$data['product_poster_title'] = sys_config('product_poster_title', '');
|
||||
|
||||
//浏览记录
|
||||
ProductLogJob::dispatch(['visit', ['uid' => $uid, 'id' => $id, 'product_id' => $storeInfo['product_id']], 'integral']);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改销量和库存
|
||||
* @param $num
|
||||
* @param $integralId
|
||||
* @return bool
|
||||
*/
|
||||
public function decIntegralStock(int $num, int $integralId, string $unique)
|
||||
{
|
||||
$product_id = $this->dao->value(['id' => $integralId], 'product_id');
|
||||
if ($unique) {
|
||||
/** @var StoreProductAttrValueServices $skuValueServices */
|
||||
$skuValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
//减去积分商品的sku库存增加销量
|
||||
$res = false !== $skuValueServices->decProductAttrStock($integralId, $unique, $num, 4);
|
||||
|
||||
//积分商品sku
|
||||
$suk = $skuValueServices->value(['unique' => $unique, 'product_id' => $integralId, 'type' => 4], 'suk');
|
||||
//平台商品sku unique
|
||||
$productUnique = $skuValueServices->value(['suk' => $suk, 'product_id' => $product_id, 'type' => 0], 'unique');
|
||||
/** @var StoreProductServices $services */
|
||||
$services = app()->make(StoreProductServices::class);
|
||||
//减去普通商品库存
|
||||
$res = $res && $services->decProductStock($num, $product_id, (string)$productUnique);
|
||||
}
|
||||
//减去积分商品库存
|
||||
$res = $res && false !== $this->dao->decStockIncSales(['id' => $integralId, 'type' => 4], $num);
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加库存减销量
|
||||
* @param int $num
|
||||
* @param int $integralId
|
||||
* @param string $unique
|
||||
* @param int $store_id
|
||||
* @return bool
|
||||
*/
|
||||
public function incIntegralStock(int $num, int $integralId, string $unique, int $store_id = 0)
|
||||
{
|
||||
$product_id = $this->dao->value(['id' => $integralId], 'product_id');
|
||||
$res = false;
|
||||
if ($product_id) {
|
||||
if ($unique) {
|
||||
/** @var StoreProductAttrValueServices $skuValueServices */
|
||||
$skuValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
//增加积分商品的sku库存,减去销量
|
||||
$res = false !== $skuValueServices->incProductAttrStock($integralId, $unique, $num, 4);
|
||||
|
||||
//积分商品sku
|
||||
$suk = $skuValueServices->value(['unique' => $unique, 'product_id' => $integralId, 'type' => 4], 'suk');
|
||||
//平台商品sku unique
|
||||
$productUnique = $skuValueServices->value(['suk' => $suk, 'product_id' => $product_id, 'type' => 0], 'unique');
|
||||
/** @var StoreProductServices $services */
|
||||
$services = app()->make(StoreProductServices::class);
|
||||
//增加普通商品库存
|
||||
$res = $res && $services->incProductStock($num, $product_id, (string)$productUnique);
|
||||
}
|
||||
//增加积分库存
|
||||
$res = $res && false !== $this->dao->incStockDecSales(['id' => $integralId, 'type' => 4], $num);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一条积分商品
|
||||
* @param $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function getIntegralOne($id)
|
||||
{
|
||||
return $this->dao->validProduct($id, '*');
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证积分商品下单库存限量
|
||||
* @param int $uid
|
||||
* @param int $integralId
|
||||
* @param int $num
|
||||
* @param string $unique
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function checkoutProductStock(int $uid, int $integralId, int $num = 1, string $unique = '')
|
||||
{
|
||||
/** @var StoreProductAttrValueServices $attrValueServices */
|
||||
$attrValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
if ($unique == '') {
|
||||
$unique = $attrValueServices->value(['product_id' => $integralId, 'type' => 4], 'unique');
|
||||
}
|
||||
$StoreIntegralInfo = $this->dao->validProduct($integralId, '*,title as store_name');
|
||||
if (!$StoreIntegralInfo) {
|
||||
throw new ValidateException('该商品已下架或删除');
|
||||
}
|
||||
/** @var StoreOrderServices $orderServices */
|
||||
$orderServices = app()->make(StoreOrderServices::class);
|
||||
$userBuyCount = $orderServices->getBuyCount($uid, 4, $integralId);
|
||||
if ($StoreIntegralInfo['once_num'] < $num && $StoreIntegralInfo['once_num'] != -1) {
|
||||
throw new ValidateException('每个订单限购' . $StoreIntegralInfo['once_num'] . '件');
|
||||
}
|
||||
if ($StoreIntegralInfo['num'] < ($userBuyCount + $num) && $StoreIntegralInfo['num'] != -1) {
|
||||
throw new ValidateException('每人总共限购' . $StoreIntegralInfo['num'] . '件');
|
||||
}
|
||||
$attrInfo = $attrValueServices->getOne(['product_id' => $integralId, 'unique' => $unique, 'type' => 4]);
|
||||
if ($num > $attrInfo['quota']) {
|
||||
throw new ValidateException('该商品库存不足' . $num);
|
||||
}
|
||||
$product_stock = $attrValueServices->value(['product_id' => $StoreIntegralInfo['product_id'], 'suk' => $attrInfo['suk'], 'type' => 0], 'stock');
|
||||
if ($product_stock < $num) {
|
||||
throw new ValidateException('该商品库存不足' . $num);
|
||||
}
|
||||
if (!CacheService::checkStock($unique, $num, 4)) {
|
||||
throw new ValidateException('该商品库存不足' . $num);
|
||||
}
|
||||
return [$attrInfo, $unique, $StoreIntegralInfo];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取推荐积分商品
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getIntegralList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getList($where, $page, $limit, 'id,product_id,image,title,integral,price,sales,stock');
|
||||
foreach ($list as &$item) {
|
||||
/** @var StoreProductServices $storeProductServices */
|
||||
$storeProductServices = app()->make(StoreProductServices::class);
|
||||
$item['brand_name'] = $storeProductServices->productIdByBrandName((int)$item['product_id']);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全部积分商品
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getAllIntegralList(array $where)
|
||||
{
|
||||
$list = $this->dao->getList($where, 0, 0, 'id,image,title,integral,price,sales');
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
230
app/services/activity/integral/UserPointServices.php
Normal file
230
app/services/activity/integral/UserPointServices.php
Normal file
@@ -0,0 +1,230 @@
|
||||
<?php
|
||||
|
||||
namespace app\services\activity\integral;
|
||||
|
||||
use app\dao\user\UserBillDao;
|
||||
use app\services\BaseServices;
|
||||
use app\services\order\StoreOrderServices;
|
||||
use app\services\user\UserServices;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use think\annotation\Inject;
|
||||
|
||||
class UserPointServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* UserBillServices constructor.
|
||||
* @param UserBillDao $dao
|
||||
*/
|
||||
#[Inject]
|
||||
protected UserBillDao $dao;
|
||||
|
||||
/**
|
||||
* 积分记录
|
||||
* @param $where
|
||||
* @return array
|
||||
*/
|
||||
public function pointRecord($where)
|
||||
{
|
||||
$where['category'] = 'integral';
|
||||
$status = [
|
||||
'invite_user' => '邀新奖励',
|
||||
'system_add' => '系统增加积分',
|
||||
'system_sub' => '系统减少积分',
|
||||
'gain' => '下单赠送积分',
|
||||
'product_gain' => '购买商品赠送积分',
|
||||
'deduction' => '下单积分抵扣',
|
||||
'lottery_use' => '参与抽奖使用积分',
|
||||
'lottery_add' => '抽奖中奖赠送积分',
|
||||
'order_deduction' => '扣除订单下单赠送积分',
|
||||
'storeIntegral_use' => '积分兑换商品',
|
||||
'pay_product_integral_back' => '返还下单使用积分',
|
||||
'sign' => '签到获得积分',
|
||||
];
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getList($where, '*', $page, $limit);
|
||||
//关联用户
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$uids = array_column($list, 'uid');
|
||||
$nicknameArr = $userServices->getColumn([['uid', 'in', $uids]], 'nickname', 'uid');
|
||||
//关联订单
|
||||
/** @var StoreOrderServices $orderServices */
|
||||
$orderServices = app()->make(StoreOrderServices::class);
|
||||
/** @var StoreIntegralOrderServices $integralOrderServices */
|
||||
$integralOrderServices = app()->make(StoreIntegralOrderServices::class);
|
||||
foreach ($list as &$item) {
|
||||
$item['nickname'] = $nicknameArr[$item['uid']] ?? '未知用户';
|
||||
if ($item['type'] == 'gain' || $item['type'] == 'deduction' || $item['type'] == 'product_deduction' || $item['type'] == 'pay_product_integral_back') {
|
||||
$item['relation'] = $orderServices->value(['id' => $item['link_id']], 'order_id');
|
||||
} elseif ($item['type'] == 'storeIntegral_use') {
|
||||
$item['relation'] = $integralOrderServices->value(['id' => $item['link_id']], 'order_id');
|
||||
} else {
|
||||
$item['relation'] = $status[$item['type']];
|
||||
}
|
||||
$item['type_name'] = $status[$item['type']];
|
||||
}
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count', 'status');
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分记录备注
|
||||
* @param $data
|
||||
* @return bool
|
||||
*/
|
||||
public function recordRemark($id, $mark)
|
||||
{
|
||||
if (!$id) throw new AdminException('缺少参数');
|
||||
if ($mark === '') throw new AdminException('请填写备注');
|
||||
if ($this->dao->update($id, ['mark' => $mark])) {
|
||||
return true;
|
||||
} else {
|
||||
throw new AdminException('备注失败');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单统计基础
|
||||
* @param $where
|
||||
* @return array
|
||||
*/
|
||||
public function getBasic($where)
|
||||
{
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$data['now_point'] = $userServices->sum(['status' => 1], 'integral', true);
|
||||
$data['all_point'] = $this->dao->sum(['category' => 'integral', 'pm' => 1, 'time' => $where['time']], 'number', true);
|
||||
$data['pay_point'] = $this->dao->sum(['category' => 'integral', 'pm' => 0, 'time' => $where['time']], 'number', true);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单趋势
|
||||
* @param $where
|
||||
* @return array
|
||||
*/
|
||||
public function getTrend($where)
|
||||
{
|
||||
$time = explode('-', $where['time']);
|
||||
if (count($time) != 2) throw new AdminException('数据错误');
|
||||
$dayCount = (strtotime($time[1]) - strtotime($time[0])) / 86400 + 1;
|
||||
$data = [];
|
||||
if ($dayCount == 1) {
|
||||
$data = $this->trend($time, 0);
|
||||
} elseif ($dayCount > 1 && $dayCount <= 31) {
|
||||
$data = $this->trend($time, 1);
|
||||
} elseif ($dayCount > 31 && $dayCount <= 92) {
|
||||
$data = $this->trend($time, 3);
|
||||
} elseif ($dayCount > 92) {
|
||||
$data = $this->trend($time, 30);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单趋势
|
||||
* @param $time
|
||||
* @param $num
|
||||
* @param false $excel
|
||||
* @return array
|
||||
*/
|
||||
public function trend($time, $num, $excel = false)
|
||||
{
|
||||
if ($num == 0) {
|
||||
$xAxis = ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23'];
|
||||
$timeType = '%H';
|
||||
} elseif ($num != 0) {
|
||||
$dt_start = strtotime($time[0]);
|
||||
$dt_end = strtotime($time[1]);
|
||||
while ($dt_start <= $dt_end) {
|
||||
if ($num == 30) {
|
||||
$xAxis[] = date('Y-m', $dt_start);
|
||||
$dt_start = strtotime("+1 month", $dt_start);
|
||||
$timeType = '%Y-%m';
|
||||
} else {
|
||||
$xAxis[] = date('m-d', $dt_start);
|
||||
$dt_start = strtotime("+$num day", $dt_start);
|
||||
$timeType = '%m-%d';
|
||||
}
|
||||
}
|
||||
}
|
||||
$point_add = array_column($this->dao->getPointTrend($time, $timeType, 'add_time', 'sum(number)', 'add'), 'num', 'days');
|
||||
$point_sub = array_column($this->dao->getPointTrend($time, $timeType, 'add_time', 'sum(number)', 'sub'), 'num', 'days');
|
||||
$data = $series = [];
|
||||
foreach ($xAxis as $item) {
|
||||
$data['积分积累'][] = isset($point_add[$item]) ? floatval($point_add[$item]) : 0;
|
||||
$data['积分消耗'][] = isset($point_sub[$item]) ? floatval($point_sub[$item]) : 0;
|
||||
}
|
||||
foreach ($data as $key => $item) {
|
||||
$series[] = [
|
||||
'name' => $key,
|
||||
'data' => $item,
|
||||
'type' => 'line',
|
||||
];
|
||||
}
|
||||
return compact('xAxis', 'series');
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单来源
|
||||
* @param $where
|
||||
* @return array
|
||||
*/
|
||||
public function getChannel($where)
|
||||
{
|
||||
$bing_xdata = ['订单赠送', '商品赠送', '后台赠送', '签到获得', '九宫格抽奖'];
|
||||
$color = ['#64a1f4', '#3edeb5', '#70869f', '#ffc653', '#fc7d6a'];
|
||||
$data = ['gain', 'gain', 'system_add', 'sign', 'lottery_add'];
|
||||
$bing_data = [];
|
||||
foreach ($data as $key => $item) {
|
||||
$bing_data[] = [
|
||||
'name' => $bing_xdata[$key],
|
||||
'value' => $this->dao->sum(['pm' => 1, 'type' => $item, 'category' => 'integral', 'time' => $where['time']], 'number', true),
|
||||
'itemStyle' => ['color' => $color[$key]]
|
||||
];
|
||||
}
|
||||
$list = [];
|
||||
$count = array_sum(array_column($bing_data, 'value'));
|
||||
foreach ($bing_data as $key => $item) {
|
||||
$list[] = [
|
||||
'name' => $item['name'],
|
||||
'value' => $item['value'],
|
||||
'percent' => $count != 0 ? bcmul((string)bcdiv((string)$item['value'], (string)$count, 4), '100', 1) : 0,
|
||||
];
|
||||
}
|
||||
array_multisort(array_column($list, 'value'), SORT_DESC, $list);
|
||||
return compact('bing_xdata', 'bing_data', 'list');
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单类型
|
||||
* @param $where
|
||||
* @return array
|
||||
*/
|
||||
public function getType($where)
|
||||
{
|
||||
$bing_xdata = ['订单抵扣', '九宫格抽奖', '后台减少', '退款退回', '兑换商品'];
|
||||
$color = ['#64a1f4', '#3edeb5', '#70869f', '#ffc653', '#fc7d6a'];
|
||||
$data = ['deduction', 'lottery_use', 'system_sub', 'pay_product_integral_back', 'storeIntegral_use'];
|
||||
$bing_data = [];
|
||||
foreach ($data as $key => $item) {
|
||||
$bing_data[] = [
|
||||
'name' => $bing_xdata[$key],
|
||||
'value' => $this->dao->sum(['type' => $item, 'category' => 'integral', 'time' => $where['time']], 'number', true),
|
||||
'itemStyle' => ['color' => $color[$key]]
|
||||
];
|
||||
}
|
||||
|
||||
$list = [];
|
||||
$count = array_sum(array_column($bing_data, 'value'));
|
||||
foreach ($bing_data as $key => $item) {
|
||||
$list[] = [
|
||||
'name' => $item['name'],
|
||||
'value' => $item['value'],
|
||||
'percent' => $count != 0 ? bcmul((string)bcdiv((string)$item['value'], (string)$count, 4), '100', 1) : 0,
|
||||
];
|
||||
}
|
||||
array_multisort(array_column($list, 'value'), SORT_DESC, $list);
|
||||
return compact('bing_xdata', 'bing_data', 'list');
|
||||
}
|
||||
}
|
||||
204
app/services/activity/live/LiveAnchorServices.php
Normal file
204
app/services/activity/live/LiveAnchorServices.php
Normal file
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\live;
|
||||
|
||||
|
||||
use app\dao\activity\live\LiveAnchorDao;
|
||||
use app\jobs\activity\AutoUpdateLiveJob;
|
||||
use app\services\BaseServices;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use crmeb\services\CacheService;
|
||||
use crmeb\services\FormBuilder as Form;
|
||||
use crmeb\services\wechat\MiniProgram;
|
||||
use FormBuilder\Factory\Iview;
|
||||
use think\annotation\Inject;
|
||||
use think\facade\Route as Url;
|
||||
|
||||
|
||||
/**
|
||||
* 主播
|
||||
* Class LiveAnchorServices
|
||||
* @package app\services\activity\live
|
||||
* @mixin LiveAnchorDao
|
||||
*/
|
||||
class LiveAnchorServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var LiveAnchorDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected LiveAnchorDao $dao;
|
||||
|
||||
/**
|
||||
* 获取某个主播
|
||||
* @param int $id
|
||||
* @return array|\think\Model|null
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getLiveAnchor(int $id)
|
||||
{
|
||||
return $this->dao->get($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取主播列表
|
||||
* @param array $where 查询条件
|
||||
* @return array
|
||||
*/
|
||||
public function getList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$where['is_del'] = 0;
|
||||
$list = $this->dao->getList($where, '*', $page, $limit);
|
||||
$count = $this->dao->count($where);
|
||||
return compact('count', 'list');
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加修改标签表单
|
||||
* @param int $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function add(int $id)
|
||||
{
|
||||
$anchor = $this->getLiveAnchor($id);
|
||||
$field = array();
|
||||
if (!$anchor) {
|
||||
$title = '添加主播';
|
||||
$field[] = Form::input('name', '主播名称:', '')->maxlength(20)->required('请填写名称');
|
||||
$field[] = Form::input('wechat', '主播微信号:', '')->maxlength(32)->required('请填写微信号');
|
||||
$field[] = Form::input('phone', '主播手机号:', '')->maxlength(20)->required('请填写手机号');
|
||||
$field[] = Form::frameImage('cover_img', '主播图像:', Url::buildUrl('admin/widget.images/index', array('fodder' => 'cover_img')), '')->icon('ios-add')->width('960px')->height('505px')->modal(['footer-hide' => true])->appendValidate(Iview::validateStr()->required()->message('请选择图像'));
|
||||
} else {
|
||||
$title = '修改主播';
|
||||
$field[] = Form::hidden('id', $anchor->getData('id'));
|
||||
$field[] = Form::input('name', '主播名称:', $anchor->getData('name'))->maxlength(20)->required('请填写名称');
|
||||
$field[] = Form::input('wechat', '主播微信号:', $anchor->getData('wechat'))->maxlength(32)->required('请填写微信号');
|
||||
$field[] = Form::input('phone', '主播手机号:', $anchor->getData('phone'))->maxlength(20)->required('请填写手机号');
|
||||
$field[] = Form::frameImage('cover_img', '主播图像:', Url::buildUrl('admin/widget.images/index', array('fodder' => 'cover_img')), $anchor->getData('cover_img'))->icon('ios-add')->width('960px')->height('505px')->modal(['footer-hide' => true])->appendValidate(Iview::validateStr()->required()->message('请选择图像'));
|
||||
}
|
||||
return create_form($title, $field, $this->url('/live/anchor/save'), 'POST');
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存标签表单数据
|
||||
* @param int $id
|
||||
* @param array $data
|
||||
* @return mixed
|
||||
*/
|
||||
public function save(int $id, array $data)
|
||||
{
|
||||
$liveAnchor = $this->dao->get(['wechat' => $data['wechat']]);
|
||||
if (!MiniProgram::getRoleList(2, 0, 30, $data['wechat'])) {
|
||||
return ['auth' => true];
|
||||
}
|
||||
if ($id) {
|
||||
if ($liveAnchor && $id != $liveAnchor['id']) {
|
||||
throw new AdminException('该主播已经存在');
|
||||
}
|
||||
if ($this->dao->update($id, $data)) {
|
||||
return true;
|
||||
} else {
|
||||
throw new AdminException('修改失败或者您没有修改什么!');
|
||||
}
|
||||
} else {
|
||||
unset($data['id']);
|
||||
if ($liveAnchor) {
|
||||
throw new AdminException('该主播已经存在');
|
||||
}
|
||||
if ($this->dao->save($data)) {
|
||||
return true;
|
||||
} else {
|
||||
throw new AdminException('添加失败!');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param $id
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function delAnchor(int $id)
|
||||
{
|
||||
if ($anchor = $this->getLiveAnchor($id)) {
|
||||
if (!$this->dao->update($id, ['is_del' => 1])) {
|
||||
throw new AdminException('删除失败,请稍候再试!');
|
||||
}
|
||||
/** @var LiveRoomServices $liveRoom */
|
||||
$liveRoom = app()->make(LiveRoomServices::class);
|
||||
$room = $liveRoom->get(['anchor_wechat' => $anchor['wechat'], 'is_del' => 0], ['id']);
|
||||
if ($room) {
|
||||
$liveRoom->delete((int)$room->id);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否显示
|
||||
* @param int $id
|
||||
* @param $is_show
|
||||
* @return mixed
|
||||
*/
|
||||
public function setShow(int $id, $is_show)
|
||||
{
|
||||
if (!$this->getLiveAnchor($id))
|
||||
throw new AdminException('数据不存在');
|
||||
if ($this->dao->update($id, ['is_show' => $is_show])) {
|
||||
return $is_show == 1 ? '显示成功' : '隐藏成功';
|
||||
} else {
|
||||
throw new AdminException($is_show == 1 ? '显示失败' : '隐藏失败');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步微信主播列表
|
||||
* @param bool $is_job 是否为定时任务调用
|
||||
* @return bool
|
||||
*/
|
||||
public function syncAnchor($is_job = false)
|
||||
{
|
||||
$key = md5('Live_sync_status');
|
||||
$res = CacheService::redisHandler()->get($key);
|
||||
if (!$res || $is_job) {
|
||||
$start = 0;
|
||||
$limit = 30;
|
||||
$data = $dataAll = [];
|
||||
$anchors = $this->dao->getColumn([], 'id,wechat', 'wechat');
|
||||
do {
|
||||
$wxAnchor = MiniProgram::getRoleList(2, $start, $limit);
|
||||
foreach ($wxAnchor as $anchor) {
|
||||
if (isset($anchors[$anchor['username']])) {
|
||||
$this->dao->update($anchors[$anchor['username']]['id'], ['cover_img' => $anchor['headingimg'], 'name' => $anchor['nickname']]);
|
||||
} else {
|
||||
$data['name'] = $anchor['nickname'];
|
||||
$data['wechat'] = $anchor['username'];
|
||||
$data['cover_img'] = $anchor['headingimg'];
|
||||
$data['add_time'] = $anchor['updateTimestamp'] ?? time();
|
||||
$dataAll[] = $data;
|
||||
}
|
||||
}
|
||||
$start++;
|
||||
} while (count($wxAnchor) >= $limit);
|
||||
if ($dataAll) {
|
||||
$this->dao->saveAll($dataAll);
|
||||
}
|
||||
if (!$is_job) AutoUpdateLiveJob::dispatchSece(120);
|
||||
CacheService::redisHandler()->set($key, 1, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
281
app/services/activity/live/LiveGoodsServices.php
Normal file
281
app/services/activity/live/LiveGoodsServices.php
Normal file
@@ -0,0 +1,281 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\live;
|
||||
|
||||
|
||||
use app\dao\activity\live\LiveGoodsDao;
|
||||
use app\services\BaseServices;
|
||||
use app\services\product\product\StoreProductServices;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use crmeb\services\DownloadImageService;
|
||||
use crmeb\services\wechat\MiniProgram;
|
||||
use crmeb\services\wechat\OfficialAccount;
|
||||
use think\annotation\Inject;
|
||||
use think\facade\Log;
|
||||
|
||||
/**
|
||||
* 直播商品
|
||||
* Class LiveGoodsServices
|
||||
* @package app\services\activity\live
|
||||
* @mixin LiveGoodsDao
|
||||
*/
|
||||
class LiveGoodsServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var LiveGoodsDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected LiveGoodsDao $dao;
|
||||
|
||||
/**
|
||||
* 获取直播商品列表
|
||||
* @param array $where 查询条件
|
||||
* @return array
|
||||
*/
|
||||
public function getList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$where['is_del'] = 0;
|
||||
$list = $this->dao->getList($where, '*', ['product'], $page, $limit);
|
||||
$count = $this->dao->count($where);
|
||||
return compact('count', 'list');
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建直播商品(验证商品有效性)
|
||||
* @param array $product_ids 商品ID数组
|
||||
* @return array
|
||||
* @throws AdminException
|
||||
*/
|
||||
public function create(array $product_ids)
|
||||
{
|
||||
/** @var StoreProductServices $product */
|
||||
$productServices = app()->make(StoreProductServices::class);
|
||||
$products = $productServices->getColumn([['id', 'IN', $product_ids], ['is_del', '=', 0], ['is_show', '=', 1]], 'id,image,store_name,price,price as cost_price,stock', 'id');
|
||||
if (count($product_ids) != count($products)) {
|
||||
throw new AdminException('已选商品中包括已下架或移入回收站商品');
|
||||
}
|
||||
$checkGoods = $this->dao->getCount([['product_id', 'IN', $product_ids], ['is_del', '=', 0], ['audit_status', '<>', 3]]);
|
||||
if ($checkGoods > 0) {
|
||||
throw new AdminException('其中有商品已经添加');
|
||||
}
|
||||
return array_merge($products);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return bool|mixed
|
||||
* @throws \EasyWeChat\Core\Exceptions\InvalidArgumentException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function add(array $goods_info)
|
||||
{
|
||||
$product_ids = array_column($goods_info, 'id');
|
||||
$this->create($product_ids);
|
||||
/** @var DownloadImageService $download */
|
||||
$download = app()->make(DownloadImageService::class);
|
||||
$dataAll = $data = [];
|
||||
$time = time();
|
||||
foreach ($goods_info as $product) {
|
||||
$data = [
|
||||
'product_id' => $product['id'],
|
||||
'name' => substrUTf8($product['store_name'], 12, 'UTF-8', ''),
|
||||
'cover_img' => $product['image'] ?? '',
|
||||
'price_type' => 1,
|
||||
'cost_price' => $product['cost_price'] ?? 0.00,
|
||||
'price' => $product['price'] ?? 0.00,
|
||||
'url' => 'pages/goods_details/index?id=' . $product['id'],
|
||||
'sort' => $product['sort'] ?? 0,
|
||||
'add_time' => $time
|
||||
];
|
||||
try {
|
||||
$path = root_path() . 'public' . $download->thumb(true)->downloadImage($data['cover_img'])['path'];
|
||||
$coverImgUrl = MiniProgram::temporaryUpload($path)['media_id'];
|
||||
@unlink($path);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('添加直播商品图片错误,原因:' . $e->getMessage());
|
||||
$coverImgUrl = $data['cover_img'];
|
||||
}
|
||||
$res = MiniProgram::addGoods($coverImgUrl, $data['name'], $data['price_type'], $data['url'], floatval($data['price']));
|
||||
$data['goods_id'] = $res['goodsId'];
|
||||
$data['audit_id'] = $res['auditId'];
|
||||
$data['audit_status'] = 1;
|
||||
$dataAll[] = $data;
|
||||
}
|
||||
if (!$goods = $this->dao->saveAll($dataAll)) {
|
||||
throw new AdminException('添加商品失败');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步商品
|
||||
* @return bool
|
||||
* @throws \EasyWeChat\Core\Exceptions\InvalidArgumentException
|
||||
*/
|
||||
public function syncGoods()
|
||||
{
|
||||
$liveGoods = $this->dao->getColumn([['goods_id', '>', 0]], '*', 'id');
|
||||
if ($liveGoods) {
|
||||
foreach ($liveGoods as $good) {
|
||||
$path = root_path() . 'public' . app()->make(DownloadImageService::class)->thumb(true)->downloadImage($good['cover_img'])['path'];
|
||||
$materialInfo = MiniProgram::temporaryUpload($path);
|
||||
$coverImgUrl = $materialInfo['media_id'];
|
||||
@unlink($path);
|
||||
$res = MiniProgram::addGoods($coverImgUrl, $good['name'], $good['price_type'], $good['url'], floatval($good['price']));
|
||||
$data['goods_id'] = $res['goodsId'];
|
||||
$data['audit_id'] = $res['auditId'];
|
||||
$data['audit_status'] = 1;
|
||||
if (!$this->dao->update($good['id'], $data, 'id')) {
|
||||
throw new AdminException('同步失败');
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信小程序创建直播商品
|
||||
* @param mixed $goods 商品信息
|
||||
* @return array
|
||||
* @throws AdminException
|
||||
*/
|
||||
public function wxCreate($goods)
|
||||
{
|
||||
if ($goods['goods_id'])
|
||||
throw new AdminException('商品已创建');
|
||||
|
||||
$goods = $goods->toArray();
|
||||
$path = root_path() . 'public' . app()->make(DownloadImageService::class)->thumb(true)->downloadImage($goods['cover_img'])['path'];
|
||||
|
||||
$url = 'pages/goods_details/index?id=' . $goods['product_id'];
|
||||
$coverImgUrl = MiniProgram::temporaryUpload($path)['media_id'];
|
||||
@unlink($path);
|
||||
return MiniProgram::addGoods($coverImgUrl, $goods['name'], 1, $url, floatval($goods['price']));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置直播商品显示状态
|
||||
* @param int $id 商品ID
|
||||
* @param int $is_show 显示状态
|
||||
* @return string
|
||||
* @throws AdminException
|
||||
*/
|
||||
public function isShow(int $id, $is_show)
|
||||
{
|
||||
$goods = $this->dao->get(['id' => $id, 'audit_status' => 2]);
|
||||
if (!$goods) {
|
||||
throw new AdminException('审核中或审核失败不允许此操作');
|
||||
}
|
||||
$this->dao->update($id, ['is_show' => $is_show]);
|
||||
return $is_show == 1 ? '显示成功' : '隐藏成功';
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新提交审核
|
||||
* @param int $id
|
||||
* @return mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function audit(int $id)
|
||||
{
|
||||
$goods = $this->dao->get($id);
|
||||
if (!$goods) {
|
||||
throw new AdminException('数据不存在');
|
||||
}
|
||||
if ($goods['audit_status'] != 0) {
|
||||
throw new AdminException('在审核中或已经审核通过');
|
||||
}
|
||||
if (!$this->dao->update($id, ['audit_status' => 1])) {
|
||||
throw new AdminException('修改审核状态失败');
|
||||
}
|
||||
return MiniProgram::auditGoods((int)$goods['good_id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤回审核
|
||||
* @param int $id
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function resetAudit(int $id)
|
||||
{
|
||||
$goods = $this->dao->get($id);
|
||||
if (!$goods) {
|
||||
throw new AdminException('数据不存在');
|
||||
}
|
||||
if ($goods['audit_status'] == 0) {
|
||||
return true;
|
||||
}
|
||||
if ($goods['audit_status'] != 1) {
|
||||
throw new AdminException('审核通过或失败');
|
||||
}
|
||||
if (!$this->dao->update($id, ['audit_status' => 0])) {
|
||||
throw new AdminException('修改审核状态失败');
|
||||
}
|
||||
return MiniProgram::resetauditGoods((int)$goods['good_id'], $goods['audit_id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除商品
|
||||
* @param int $id
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function delete(int $id)
|
||||
{
|
||||
$goods = $this->dao->get(['id' => $id, 'is_del' => 0]);
|
||||
if ($goods) {
|
||||
if (in_array($goods['audit_status'], [0, 1])) {
|
||||
throw new AdminException('商品审核中,无法删除');
|
||||
}
|
||||
if (!$this->dao->update($id, ['is_del' => 1])) {
|
||||
throw new AdminException('删除失败');
|
||||
}
|
||||
if (MiniProgram::deleteGoods((int)$goods->goods_id)) {
|
||||
/** @var LiveRoomGoodsServices $liveRoomGoods */
|
||||
$liveRoomGoods = app()->make(LiveRoomGoodsServices::class);
|
||||
$liveRoomGoods->delete(['live_goods_id' => $id]);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步直播商品审核状态
|
||||
* @return bool
|
||||
*/
|
||||
public function syncGoodStatus()
|
||||
{
|
||||
$goodsIds = $this->dao->goodsStatusAll();
|
||||
if (!count($goodsIds)) return true;
|
||||
$res = MiniProgram::getGooodsInfo(array_keys($goodsIds));
|
||||
foreach ($res as $item) {
|
||||
if (isset($goodsIds[$item['goods_id']]) && $item['audit_status'] != $goodsIds[$item['goods_id']]) {
|
||||
$data = ['audit_status' => $item['audit_status']];
|
||||
// 同步商品审核状态
|
||||
$this->dao->update((int)$goodsIds[$item['goods_id']]['id'], $data);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
33
app/services/activity/live/LiveRoomGoodsServices.php
Normal file
33
app/services/activity/live/LiveRoomGoodsServices.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\live;
|
||||
|
||||
|
||||
use app\dao\activity\live\LiveRoomGoodsDao;
|
||||
use app\services\BaseServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* 直播间关联商品
|
||||
* Class LiveRoomGoodsServices
|
||||
* @package app\services\activity\live
|
||||
* @mixin LiveRoomGoodsDao
|
||||
*/
|
||||
class LiveRoomGoodsServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var LiveRoomGoodsDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected LiveRoomGoodsDao $dao;
|
||||
}
|
||||
327
app/services/activity/live/LiveRoomServices.php
Normal file
327
app/services/activity/live/LiveRoomServices.php
Normal file
@@ -0,0 +1,327 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\live;
|
||||
|
||||
|
||||
use app\dao\activity\live\LiveRoomDao;
|
||||
use app\services\BaseServices;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use crmeb\services\DownloadImageService;
|
||||
use crmeb\services\wechat\MiniProgram;
|
||||
use think\annotation\Inject;
|
||||
use think\facade\Log;
|
||||
|
||||
/**
|
||||
* 直播间
|
||||
* Class LiveRoomServices
|
||||
* @package app\services\activity\live
|
||||
* @mixin LiveRoomDao
|
||||
*/
|
||||
class LiveRoomServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var LiveRoomDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected LiveRoomDao $dao;
|
||||
|
||||
/**
|
||||
* 获取直播间列表(后台)
|
||||
* @param array $where 查询条件
|
||||
* @return array
|
||||
*/
|
||||
public function getList(array $where)
|
||||
{
|
||||
$where['is_del'] = 0;
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getList($where, '*', [], $page, $limit);
|
||||
$count = $this->dao->count($where);
|
||||
return compact('count', 'list');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取直播间列表
|
||||
* @param array $where
|
||||
* @param int $limit
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function userList(array $where, int $limit = 0)
|
||||
{
|
||||
if ($limit) {
|
||||
$page = 0;
|
||||
} else {
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
}
|
||||
$where['is_show'] = 1;
|
||||
$where['is_del'] = 0;
|
||||
$list = $this->dao->getList($where, '*', ['roomGoods.goods', 'anchor'], $page, $limit);
|
||||
foreach ($list as &$item) {
|
||||
$item['roomid'] = $item['room_id'];
|
||||
$item['goods'] = [];
|
||||
$item['show_time'] = date('m/d H:i', strtotime($item['start_time']));
|
||||
if (isset($item['roomGoods']) && $item['roomGoods']) {
|
||||
$item['goods'] = array_column($item['roomGoods'], 'goods');
|
||||
}
|
||||
if (in_array($item['live_status'], [105, 106])) {
|
||||
$item['live_status'] = 101;
|
||||
}
|
||||
if (in_array($item['live_status'], [104, 107])) {
|
||||
$item['live_status'] = 103;
|
||||
}
|
||||
unset($item['roomGoods']);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取直播间回放列表
|
||||
* @param int $id 直播间ID
|
||||
* @return array
|
||||
*/
|
||||
public function getPlaybacks(int $id)
|
||||
{
|
||||
$room = $this->dao->get(['id' => $id, 'is_del' => 0]);
|
||||
if (!$room) {
|
||||
throw new AdminException('数据不存在');
|
||||
}
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
return MiniProgram::getLivePlayback($room['room_id'], $page, $limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加直播间
|
||||
* @param array $data 直播间数据
|
||||
* @return bool
|
||||
*/
|
||||
public function add(array $data)
|
||||
{
|
||||
/** @var LiveAnchorServices $anchorServices */
|
||||
$anchorServices = app()->make(LiveAnchorServices::class);
|
||||
$anchor = $anchorServices->get(['wechat' => $data['anchor_wechat']]);
|
||||
if (!$anchor) {
|
||||
throw new AdminException('该主播不存在');
|
||||
}
|
||||
$data['start_time'] = strtotime($data['start_time']);
|
||||
$data['end_time'] = strtotime($data['end_time']);
|
||||
$time = time() + 600;
|
||||
$time6 = time() + 180 * 24 * 3600;
|
||||
if ($data['start_time'] < $time || $data['start_time'] > $time6) {
|
||||
throw new AdminException('开播时间需要在当前时间的10分钟后 并且 开始时间不能在 6 个月后');
|
||||
}
|
||||
$t = $data['end_time'] - $data['start_time'];
|
||||
if ($t < 1800 || $t > 24 * 3600) {
|
||||
throw new AdminException('开播时间和结束时间间隔不得短于30分钟,不得超过24小时');
|
||||
}
|
||||
$data['anchor_name'] = $data['anchor_name'] ?? $anchor['name'];
|
||||
$data['add_time'] = time();
|
||||
$wxRoom = $this->wxCreate($data);
|
||||
$data['room_id'] = $wxRoom['roomId'];
|
||||
$data['status'] = 2;
|
||||
|
||||
if (!$this->dao->save($data)) {
|
||||
throw new AdminException('添加直播间数据失败');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 审核直播间
|
||||
* @param int $id 直播间ID
|
||||
* @param int $status 审核状态
|
||||
* @param string $msg 拒绝原因
|
||||
* @return void
|
||||
*/
|
||||
public function apply($id, $status, $msg = '')
|
||||
{
|
||||
$room = $this->dao->get($id);
|
||||
if (!$room) {
|
||||
throw new AdminException('数据不存在');
|
||||
}
|
||||
$room->status = $status;
|
||||
if ($status == -1)
|
||||
$room->error_msg = $msg;
|
||||
else {
|
||||
$room->room_id = $this->wxCreate($room)['roomId'];
|
||||
$room->status = 2;
|
||||
}
|
||||
$room->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建微信直播间
|
||||
* @param mixed $room 直播间数据
|
||||
* @return array
|
||||
*/
|
||||
public function wxCreate($room)
|
||||
{
|
||||
try {
|
||||
$coverImg = root_path() . 'public' . app()->make(DownloadImageService::class)->downloadImage($room['cover_img'])['path'];
|
||||
$shareImg = root_path() . 'public' . app()->make(DownloadImageService::class)->downloadImage($room['share_img'])['path'];
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('添加直播间封面图出错误,原因:' . $e->getMessage());
|
||||
$coverImg = root_path() . 'public' . $room['cover_img'];
|
||||
$shareImg = root_path() . 'public' . $room['share_img'];
|
||||
}
|
||||
$data = [
|
||||
'startTime' => is_string($room['start_time']) ? strtotime($room['start_time']) : $room['start_time'],
|
||||
'endTime' => is_string($room['end_time']) ? strtotime($room['end_time']) : $room['end_time'],
|
||||
'name' => $room['name'],
|
||||
'anchorName' => $room['anchor_name'],
|
||||
'anchorWechat' => $room['anchor_wechat'],
|
||||
'screenType' => $room['screen_type'],
|
||||
'closeGoods' => $room['close_goods'] == 1 ? 0 : 1,
|
||||
'closeLike' => $room['close_like'] == 1 ? 0 : 1,
|
||||
'closeComment' => $room['close_comment'] == 1 ? 0 : 1,
|
||||
'closeReplay' => $room['replay_status'] == 1 ? 0 : 1,
|
||||
'type' => $room['type'],
|
||||
'coverImg' => MiniProgram::temporaryUpload($coverImg)['media_id'],
|
||||
'shareImg' => MiniProgram::temporaryUpload($shareImg)['media_id'],
|
||||
'closeKf' => 1
|
||||
];
|
||||
$data['feedsImg'] = $data['coverImg'];
|
||||
@unlink($coverImg);
|
||||
@unlink($shareImg);
|
||||
return MiniProgram::createLiveRoom($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置直播间显示状态
|
||||
* @param int $id 直播间ID
|
||||
* @param int $is_show 显示状态
|
||||
* @return string
|
||||
*/
|
||||
public function isShow(int $id, $is_show)
|
||||
{
|
||||
$this->dao->update($id, ['is_show' => $is_show]);
|
||||
return $is_show == 1 ? '显示成功' : '隐藏成功';
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除直播间
|
||||
* @param int $id 直播间ID
|
||||
* @return bool
|
||||
*/
|
||||
public function delete(int $id)
|
||||
{
|
||||
$room = $this->dao->get(['id' => $id, 'is_del' => 0]);
|
||||
if ($room) {
|
||||
if (!$this->dao->update($id, ['is_del' => 1])) {
|
||||
throw new AdminException('删除失败');
|
||||
}
|
||||
/** @var LiveRoomGoodsServices $liveRoomGoods */
|
||||
$liveRoomGoods = app()->make(LiveRoomGoodsServices::class);
|
||||
$liveRoomGoods->delete(['live_room_id' => $id]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置直播间备注
|
||||
* @param int $id 直播间ID
|
||||
* @param string $mark 备注内容
|
||||
* @return bool
|
||||
*/
|
||||
public function mark($id, $mark)
|
||||
{
|
||||
return $this->dao->update($id, compact('mark'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 直播间添加商品
|
||||
* @param $room_id
|
||||
* @param array $ids
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function exportGoods(int $room_id, array $ids)
|
||||
{
|
||||
$liveGoodsServices = app()->make(LiveGoodsServices::class);
|
||||
if (count($ids) != count($goods = $liveGoodsServices->goodsList($ids)))
|
||||
throw new AdminException('请选择正确的直播商品');
|
||||
if (!$room = $this->dao->validRoom($room_id))
|
||||
throw new AdminException('直播间状态有误');
|
||||
$data = [];
|
||||
/** @var LiveRoomGoodsServices $liveRoomGoodsServices */
|
||||
$liveRoomGoodsServices = app()->make(LiveRoomGoodsServices::class);
|
||||
//查询已经关联的
|
||||
$roomGoods = $liveRoomGoodsServices->getColumn(['live_room_id' => $room_id], 'live_goods_id', 'Live_goods_id');
|
||||
$goods_ids = [];
|
||||
foreach ($goods as $key => $item) {
|
||||
if (isset($roomGoods[$item['id']])) {
|
||||
unset($goods[$key]);
|
||||
} else {
|
||||
$goods_ids[] = $item['goods_id'];
|
||||
$data[] = [
|
||||
'live_room_id' => $room_id,
|
||||
'live_goods_id' => $item['id']
|
||||
];
|
||||
}
|
||||
}
|
||||
if ($goods_ids) {
|
||||
$liveRoomGoodsServices->saveAll($data);
|
||||
return MiniProgram::roomAddGoods($room['room_id'], $goods_ids);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步直播间状态
|
||||
* @return bool
|
||||
*/
|
||||
public function syncRoomStatus()
|
||||
{
|
||||
$start = 0;
|
||||
$limit = 50;
|
||||
$data = $dataAll = [];
|
||||
$rooms = $this->dao->getColumn([], 'id,room_id,live_status', 'room_id');
|
||||
$roomIds = [];
|
||||
do {
|
||||
$wxRooms = MiniProgram::getLiveInfo($start, $limit);
|
||||
foreach ($wxRooms as $room) {
|
||||
if (in_array($room['roomid'], $roomIds)) {
|
||||
continue;
|
||||
}
|
||||
$roomIds[] = $room['roomid'];
|
||||
if ($rooms && isset($rooms[$room['roomid']])) {
|
||||
if ($room['live_status'] != $rooms[$room['roomid']]['live_status']) {
|
||||
$this->dao->update($rooms[$room['roomid']]['id'], ['live_status' => $room['live_status']]);
|
||||
}
|
||||
} else {
|
||||
$data['name'] = $room['name'];
|
||||
$data['room_id'] = $room['roomid'];
|
||||
$data['cover_img'] = $room['cover_img'];
|
||||
$data['share_img'] = $room['share_img'];
|
||||
$data['live_status'] = $room['live_status'];
|
||||
$data['start_time'] = $room['start_time'];
|
||||
$data['end_time'] = $room['end_time'];
|
||||
$data['anchor_name'] = $room['anchor_name'];
|
||||
$dataAll[] = $data;
|
||||
}
|
||||
}
|
||||
$start += $limit;
|
||||
} while (count($wxRooms) >= $limit);
|
||||
if ($dataAll) {
|
||||
$this->dao->saveAll($dataAll);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
362
app/services/activity/lottery/LuckLotteryRecordServices.php
Normal file
362
app/services/activity/lottery/LuckLotteryRecordServices.php
Normal file
@@ -0,0 +1,362 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\lottery;
|
||||
|
||||
use app\jobs\system\CapitalFlowJob;
|
||||
use app\services\BaseServices;
|
||||
use app\dao\activity\lottery\LuckLotteryRecordDao;
|
||||
use app\services\activity\coupon\StoreCouponIssueServices;
|
||||
use app\services\order\StoreOrderCreateServices;
|
||||
use app\services\user\UserBillServices;
|
||||
use app\services\user\UserMoneyServices;
|
||||
use app\services\user\UserServices;
|
||||
use app\services\wechat\WechatUserServices;
|
||||
use crmeb\services\wechat\Payment;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
use think\facade\Log;
|
||||
|
||||
/**
|
||||
* 抽奖记录
|
||||
* Class LuckLotteryRecordServices
|
||||
* @package app\services\activity\lottery
|
||||
* @mixin LuckLotteryRecordDao
|
||||
*/
|
||||
class LuckLotteryRecordServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var LuckLotteryRecordDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected LuckLotteryRecordDao $dao;
|
||||
|
||||
/**
|
||||
* 获取抽奖记录列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function getList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$where['not_type'] = 1;
|
||||
if (isset($where['factor']) && $where['factor']) {
|
||||
/** @var LuckLotteryServices $luckServices */
|
||||
$luckServices = app()->make(LuckLotteryServices::class);
|
||||
$where['lottery_id'] = $luckServices->value(['factor' => $where['factor'], 'status' => 1], 'id');
|
||||
if (!$where['lottery_id']) {
|
||||
$list = [];
|
||||
$count = 0;
|
||||
return compact('list', 'count');
|
||||
}
|
||||
unset($where['factor']);
|
||||
}
|
||||
$list = $this->dao->getList($where, '*', ['lottery', 'prize', 'user'], $page, $limit);
|
||||
$count = 0;
|
||||
if ($list) {
|
||||
$prizeType = app()->make(LuckPrizeServices::class)->prize_type;
|
||||
foreach ($list as &$item) {
|
||||
if (isset($item['prize_info']) && $item['prize_info']) {
|
||||
$prize = json_decode($item['prize_info'], true);
|
||||
} else {
|
||||
$prize = $item['prize'];
|
||||
}
|
||||
if (!$item['user']) {
|
||||
$item['user']['nickname'] = '用户已注销';
|
||||
$item['user']['real_name'] = '用户已注销';
|
||||
$item['user']['phone'] = '';
|
||||
$item['user']['uid'] = 0;
|
||||
$item['user']['delete_time'] = null;
|
||||
}
|
||||
$prize['type_name'] = $prizeType[$prize['type']] ?? '未知';
|
||||
$item['prize'] = $prize;
|
||||
$item['add_time'] = $item['add_time'] ? date('Y-m-d H:i:s', $item['add_time']) : '';
|
||||
}
|
||||
$count = $this->dao->count($where);
|
||||
}
|
||||
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取中奖记录
|
||||
* @param array $where
|
||||
* @param int $limit
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getWinList(array $where, int $limit = 10)
|
||||
{
|
||||
//去除未中奖的
|
||||
$where = $where + ['not_type' => 1];
|
||||
$list = $this->dao->getList($where, 'id,uid,prize_id,lottery_id,receive_time,prize_info,add_time', ['user', 'prize'], 0, $limit);
|
||||
foreach ($list as &$item) {
|
||||
if (isset($item['prize_info']) && $item['prize_info']) {
|
||||
$prize = json_decode($item['prize_info'], true);
|
||||
unset($item['prize_info']);
|
||||
} else {
|
||||
$prize = $item['prize'];
|
||||
}
|
||||
$item['prize'] = [
|
||||
'id' => $prize['id'] ?? 0,
|
||||
'type' => $prize['type'] ?? 1,
|
||||
'name' => $prize['name'] ?? '',
|
||||
'image' => $prize['image'] ?? '',
|
||||
'prompt' => $item['prompt'] ?? '',
|
||||
];
|
||||
$item['receive_time'] = $item['receive_time'] ? date('Y-m-d H:i:s', $item['receive_time']) : '';
|
||||
$item['add_time'] = $item['add_time'] ? date('Y-m-d H:i', $item['add_time']) : '';
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 参与抽奖数据统计
|
||||
* @param int $lottery_id
|
||||
* @return int[]
|
||||
*/
|
||||
public function getLotteryRecordData(int $lottery_id)
|
||||
{
|
||||
$data = ['all' => 0, 'people' => 0, 'win' => 0];
|
||||
if ($lottery_id) {
|
||||
$where = [['lottery_id', '=', $lottery_id]];
|
||||
$data['all'] = $this->dao->getCount($where);
|
||||
$data['people'] = $this->dao->getCount($where, 'uid');
|
||||
$data['win'] = $this->dao->getCount($where + [['type', '>', 1]], 'uid');
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入中奖纪录
|
||||
* @param int $uid
|
||||
* @param array $prize
|
||||
* @return mixed
|
||||
*/
|
||||
public function insertPrizeRecord(int $uid, array $prize, array $userInfo = [])
|
||||
{
|
||||
if (!$userInfo) {
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$userInfo = $userServices->getUserInfo($uid);
|
||||
}
|
||||
if (!$userInfo) {
|
||||
throw new ValidateException('用户不存在');
|
||||
}
|
||||
if (!$prize) {
|
||||
throw new ValidateException('奖品不存在');
|
||||
}
|
||||
$services = app()->make(StoreOrderCreateServices::class);
|
||||
$data = [];
|
||||
$data['uid'] = $uid;
|
||||
$data['order_id'] = $services->getNewOrderId('hb');
|
||||
$data['lottery_id'] = $prize['lottery_id'];
|
||||
$data['prize_id'] = $prize['id'];
|
||||
$data['type'] = $prize['type'];
|
||||
$data['prize_info'] = json_encode($prize);
|
||||
$data['add_time'] = time();
|
||||
if (!$res = $this->dao->save($data)) {
|
||||
throw new ValidateException('写入中奖记录失败');
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 领取奖品
|
||||
* @param int $uid
|
||||
* @param int $lottery_record_id
|
||||
* @param string $receive_info
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function receivePrize(int $uid, int $lottery_record_id, array $receive_info = [], string $channel_type = '')
|
||||
{
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$userInfo = $userServices->getUserCacheInfo($uid);
|
||||
if (!$userInfo) {
|
||||
throw new ValidateException('用户不存在');
|
||||
}
|
||||
$lotteryRecord = $this->dao->get($lottery_record_id, ['prize_id', 'lottery_id', 'id', 'is_receive', 'order_id'], ['prize']);
|
||||
if (!$lotteryRecord || !isset($lotteryRecord['prize'])) {
|
||||
throw new ValidateException('请继续参与活动抽奖');
|
||||
}
|
||||
if ($lotteryRecord['is_receive'] == 1) {
|
||||
throw new ValidateException('已经领取成功');
|
||||
}
|
||||
$data = ['is_receive' => 1, 'receive_time' => time(), 'receive_info' => $receive_info];
|
||||
if (isset($lotteryRecord['prize_info']) && $lotteryRecord['prize_info']) {
|
||||
$prize = json_decode($lotteryRecord['prize_info'], true);
|
||||
} else {
|
||||
$prize = $lotteryRecord['prize'];
|
||||
}
|
||||
$this->transaction(function () use ($uid, $userInfo, $lottery_record_id, $data, $prize, $userServices, $receive_info, $channel_type, $lotteryRecord) {
|
||||
//奖品类型1:未中奖2:积分3:余额4:红包5:优惠券6:站内商品7:等级经验8:用户等级 9:svip天数
|
||||
switch ($prize['type']) {
|
||||
case 1:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
break;
|
||||
case 2:
|
||||
/** @var UserBillServices $userBillServices */
|
||||
$userBillServices = app()->make(UserBillServices::class);
|
||||
$integral = bcadd((string)$userInfo['integral'], (string)$prize['num'], 0);
|
||||
$userBillServices->income('lottery_give_integral', $uid, (int)$prize['num'], (int)$integral, $prize['id']);
|
||||
$userServices->update($uid, ['integral' => $integral], 'uid');
|
||||
break;
|
||||
case 3:
|
||||
/** @var UserMoneyServices $userMoneyServices */
|
||||
$userMoneyServices = app()->make(UserMoneyServices::class);
|
||||
$now_money = bcadd((string)$userInfo['now_money'], (string)$prize['num'], 2);
|
||||
$userMoneyServices->income('lottery_give_money', $uid, $prize['num'], $now_money, $prize['id']);
|
||||
$userServices->update($uid, ['now_money' => $now_money], 'uid');
|
||||
break;
|
||||
case 4:
|
||||
$wechat_order_id = $lotteryRecord['order_id'];
|
||||
$transferDetailList = [
|
||||
[
|
||||
'info_type' => '活动名称',
|
||||
'info_content' => '抽奖红包'
|
||||
],
|
||||
[
|
||||
'info_type' => '奖励说明',
|
||||
'info_content' => '抽奖红包'
|
||||
],
|
||||
];
|
||||
$userName = $userInfo['real_name'] ?? '';
|
||||
$res = Payment::merchantPay($channel_type, $uid, $wechat_order_id, (string)$prize['num'], '抽奖中奖红包', $userName, $transferDetailList);
|
||||
if (sys_config('pay_wechat_type') == 1) {
|
||||
$data = array_merge($data, [
|
||||
'transfer_bill_no' => $res['transfer_bill_no'] ?? '',
|
||||
'wechat_state' => $res['state'] ?? '',
|
||||
'fail_reason' => $res['fail_reason'] ?? '',
|
||||
'package_info' => $res['package_info'] ?? ''
|
||||
]);
|
||||
event('notice.notice', [[
|
||||
'uid' => $uid,
|
||||
'extract_price' => $prize['num'],
|
||||
'type' => 2,
|
||||
'order_id' => $wechat_order_id
|
||||
], 'revenue_received']);
|
||||
}
|
||||
//记录资金流水
|
||||
CapitalFlowJob::dispatch([['order_id' => $wechat_order_id, 'store_id' => 0, 'uid' => $uid, 'price' => $prize['num'], 'pay_type' => 'weixin', 'nickname' => $userInfo['nickname'], 'phone' => $userInfo['phone']], 'luck']);
|
||||
break;
|
||||
case 5:
|
||||
/** @var StoreCouponIssueServices $couponIssueService */
|
||||
$couponIssueService = app()->make(StoreCouponIssueServices::class);
|
||||
try {
|
||||
$couponIssueService->issueUserCoupon($uid, (int)$prize['coupon_id'], true, 'luck_lottery');
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('抽奖领取优惠券失败,原因:' . $e->getMessage());
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if (!$receive_info['name'] || !$receive_info['phone'] || !$receive_info['address']) {
|
||||
throw new ValidateException('请输入收货人信息');
|
||||
}
|
||||
if (!check_phone($receive_info['phone'])) {
|
||||
throw new ValidateException('请输入正确的收货人电话');
|
||||
}
|
||||
break;
|
||||
}
|
||||
$this->dao->update($lottery_record_id, $data, 'id');
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发货、备注
|
||||
* @param int $lottery_record_id
|
||||
* @param array $data
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function setDeliver(int $lottery_record_id, array $data)
|
||||
{
|
||||
$lotteryRecord = $this->dao->get($lottery_record_id, ['deliver_info', 'type', 'id']);
|
||||
if (!$lotteryRecord) {
|
||||
throw new ValidateException('抽奖记录不存在');
|
||||
}
|
||||
$deliver_info = $lotteryRecord['deliver_info'];
|
||||
$edit = [];
|
||||
//备注
|
||||
if (!$data['deliver_name'] && !$data['deliver_number']) {
|
||||
$deliver_info['mark'] = $data['mark'];
|
||||
} else {
|
||||
if ($lotteryRecord['type'] != 6 && ($data['deliver_name'] || $data['deliver_number'])) {
|
||||
throw new ValidateException('该奖品不需要发货');
|
||||
}
|
||||
if ($lotteryRecord['type'] == 6 && (!$data['deliver_name'] || !$data['deliver_number'])) {
|
||||
throw new ValidateException('请选择快递公司或输入快递单号');
|
||||
}
|
||||
$deliver_info['deliver_name'] = $data['deliver_name'];
|
||||
$deliver_info['deliver_number'] = $data['deliver_number'];
|
||||
$edit['is_deliver'] = 1;
|
||||
$edit['deliver_time'] = time();
|
||||
}
|
||||
$edit['deliver_info'] = $deliver_info;
|
||||
if (!$this->dao->update($lottery_record_id, $edit, 'id')) {
|
||||
throw new ValidateException('处理失败');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取中奖记录
|
||||
* @param int $uid
|
||||
* @return array
|
||||
*/
|
||||
public function getRecord(int $uid, $where = [])
|
||||
{
|
||||
if (!$where) {
|
||||
$where['uid'] = $uid;
|
||||
$where['not_type'] = 1;
|
||||
}
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getList($where, '*', ['prize'], $page, $limit);
|
||||
foreach ($list as &$item) {
|
||||
if (isset($item['prize_info']) && $item['prize_info']) {
|
||||
$prize = $item['prize_info'] = json_decode($item['prize_info'], true);
|
||||
} else {
|
||||
$prize = $item['prize'];
|
||||
}
|
||||
$item['prize'] = $prize;
|
||||
$item['deliver_time'] = $item['deliver_time'] ? date('Y-m-d H:i:s', $item['deliver_time']) : '';
|
||||
$item['receive_time'] = $item['receive_time'] ? date('Y-m-d H:i:s', $item['receive_time']) : '';
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取抽奖次数
|
||||
* @param int $uid
|
||||
* @param int $lottery_id
|
||||
* @return array
|
||||
*/
|
||||
public function getLotteryNum(int $uid, int $lottery_id)
|
||||
{
|
||||
$where['uid'] = $uid;
|
||||
$where['lottery_id'] = $lottery_id;
|
||||
$now_day = strtotime(date('Y-m-d'));//今日
|
||||
$todayCount = $this->dao->getCount($where + ['add_time' => $now_day]);
|
||||
$totalCount = $this->dao->getCount($where);
|
||||
return compact('todayCount', 'totalCount');
|
||||
}
|
||||
}
|
||||
815
app/services/activity/lottery/LuckLotteryServices.php
Normal file
815
app/services/activity/lottery/LuckLotteryServices.php
Normal file
@@ -0,0 +1,815 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\lottery;
|
||||
|
||||
use app\services\BaseServices;
|
||||
use app\dao\activity\lottery\LuckLotteryDao;
|
||||
use app\services\activity\coupon\StoreCouponIssueServices;
|
||||
use app\services\product\product\StoreProductServices;
|
||||
use app\services\user\label\UserLabelServices;
|
||||
use app\services\user\UserBillServices;
|
||||
use app\services\user\label\UserLabelRelationServices;
|
||||
use app\services\user\UserMoneyServices;
|
||||
use app\services\user\UserServices;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use crmeb\services\CacheService;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class LuckLotteryServices
|
||||
* @package app\services\activity\lottery
|
||||
* @mixin LuckLotteryDao
|
||||
*/
|
||||
class LuckLotteryServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* 抽奖形式,奖品数量
|
||||
* @var int[]
|
||||
*/
|
||||
protected array $lottery_type = [
|
||||
'1' => 8 //九宫格
|
||||
];
|
||||
/**
|
||||
* 抽奖类型
|
||||
* @var string[]
|
||||
*/
|
||||
protected array $lottery_factor = [
|
||||
'1' => '积分抽奖',
|
||||
'2' => '余额抽奖',
|
||||
'3' => '订单支付',
|
||||
'4' => '订单评价',
|
||||
'5' => '关注公众号'
|
||||
];
|
||||
|
||||
/**
|
||||
* 抽奖次数缓存时间
|
||||
* @var int
|
||||
*/
|
||||
public int $luck_cache_time = 120;
|
||||
|
||||
/**
|
||||
* @var LuckLotteryDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected LuckLotteryDao $dao;
|
||||
|
||||
/**
|
||||
* 获取抽奖缓存
|
||||
* @param int $factor
|
||||
* @return mixed
|
||||
* @author 等风来
|
||||
* @email 136327134@qq.com
|
||||
* @date 2022/11/16
|
||||
*/
|
||||
public function getFactorLotteryCache(int $factor)
|
||||
{
|
||||
return $this->dao->cacheTag()->remember('' . $factor, function () use ($factor) {
|
||||
$lottery = $this->dao->getFactorLottery($factor);
|
||||
return $lottery ? $lottery->toArray() : null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取抽奖活动列表
|
||||
* @param array $where 查询条件
|
||||
* @return array
|
||||
*/
|
||||
public function getList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$where['is_del'] = 0;
|
||||
$list = $this->dao->getList($where, '*', ['prize'], $page, $limit);
|
||||
$lottery_factor = $this->lottery_factor;
|
||||
/** @var LuckLotteryRecordServices $luckLotteryRecordServices */
|
||||
$luckLotteryRecordServices = app()->make(LuckLotteryRecordServices::class);
|
||||
$ids = [];
|
||||
foreach ($list as &$item) {
|
||||
$item['lottery_type'] = $lottery_factor[$item['factor']] ?? '';
|
||||
$data = $luckLotteryRecordServices->getLotteryRecordData((int)$item['id']);
|
||||
$item['lottery_all'] = $data['all'] ?? 0;
|
||||
$item['lottery_people'] = $data['people'] ?? 0;
|
||||
$item['lottery_win'] = $data['win'] ?? 0;
|
||||
if ($item['status']) {
|
||||
if ($item['start_time'] == 0 && $item['end_time'] == 0) {
|
||||
$item['lottery_status'] = '进行中';
|
||||
} else {
|
||||
if ($item['start_time'] > time()) {
|
||||
$item['lottery_status'] = '未开始';
|
||||
} else if ($item['end_time'] < time()) {
|
||||
$item['lottery_status'] = '已结束';
|
||||
$item['status'] = 0;
|
||||
$ids[] = $item['id'];
|
||||
} else if ($item['end_time'] > time() && $item['start_time'] < time()) {
|
||||
$item['lottery_status'] = '进行中';
|
||||
}
|
||||
}
|
||||
} else $item['lottery_status'] = '已结束';
|
||||
$item['start_time'] = $item['start_time'] ? date('Y-m-d H:i:s', $item['start_time']) : '';
|
||||
$item['end_time'] = $item['end_time'] ? date('Y-m-d H:i:s', $item['end_time']) : '';
|
||||
if (!count($item['records'])) {
|
||||
$item['records_total_user'] = 0;
|
||||
$item['records_wins_user'] = 0;
|
||||
$item['records_total_num'] = 0;
|
||||
$item['records_wins_num'] = 0;
|
||||
} else {
|
||||
$item['records_total_user'] = $item['records'][0]['total_user'];
|
||||
$item['records_wins_user'] = $item['records'][0]['wins_user'];
|
||||
$item['records_total_num'] = $item['records'][0]['total_num'];
|
||||
$item['records_wins_num'] = $item['records'][0]['wins_num'];
|
||||
}
|
||||
}
|
||||
foreach ($ids as $id) {
|
||||
$this->setStatus((int)$id, 0);
|
||||
}
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取抽奖详情
|
||||
* @param int $id
|
||||
* @return array|\think\Model
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getlotteryInfo(int $id)
|
||||
{
|
||||
$lottery = $this->dao->getLottery($id, '*', ['prize']);
|
||||
if (!$lottery) {
|
||||
throw new ValidateException('活动不存在或已删除');
|
||||
}
|
||||
$lottery = $lottery->toArray();
|
||||
if (isset($lottery['prize']) && $lottery['prize']) {
|
||||
$products = $coupons = [];
|
||||
$product_ids = array_unique(array_column($lottery['prize'], 'product_id'));
|
||||
$coupon_ids = array_unique(array_column($lottery['prize'], 'coupon_id'));
|
||||
/** @var StoreProductServices $productServices */
|
||||
$productServices = app()->make(StoreProductServices::class);
|
||||
$products = $productServices->getColumn([['id', 'in', $product_ids]], 'id,store_name,image', 'id');
|
||||
/** @var StoreCouponIssueServices $couponServices */
|
||||
$couponServices = app()->make(StoreCouponIssueServices::class);
|
||||
$coupons = $couponServices->getColumn([['id', 'in', $coupon_ids]], 'id,coupon_title', 'id');
|
||||
foreach ($lottery['prize'] as &$prize) {
|
||||
$prize['coupon_title'] = $prize['goods_image'] = '';
|
||||
if ($prize['type'] == 6) {
|
||||
$prize['goods_image'] = $products[$prize['product_id']]['image'] ?? '';
|
||||
}
|
||||
if ($prize['type'] == 5) {
|
||||
$prize['coupon_title'] = $coupons[$prize['coupon_id']]['coupon_title'] ?? '';
|
||||
}
|
||||
}
|
||||
}
|
||||
return $lottery;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据类型获取数据
|
||||
* @param int $factor
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getlotteryFactorInfo(int $factor)
|
||||
{
|
||||
$lottery = $this->dao->getFactorLottery($factor, '*', ['prize'], false);
|
||||
if (!$lottery) {
|
||||
return [];
|
||||
}
|
||||
$lottery = $lottery->toArray();
|
||||
if (isset($lottery['prize']) && $lottery['prize']) {
|
||||
$products = $coupons = [];
|
||||
$product_ids = array_unique(array_column($lottery['prize'], 'product_id'));
|
||||
$coupon_ids = array_unique(array_column($lottery['prize'], 'coupon_id'));
|
||||
/** @var StoreProductServices $productServices */
|
||||
$productServices = app()->make(StoreProductServices::class);
|
||||
$products = $productServices->getColumn([['id', 'in', $product_ids]], 'id,store_name,image', 'id');
|
||||
/** @var StoreCouponIssueServices $couponServices */
|
||||
$couponServices = app()->make(StoreCouponIssueServices::class);
|
||||
$coupons = $couponServices->getColumn([['id', 'in', $coupon_ids]], 'id,coupon_title', 'id');
|
||||
foreach ($lottery['prize'] as &$prize) {
|
||||
$prize['coupon_title'] = $prize['goods_image'] = '';
|
||||
if ($prize['type'] == 6) {
|
||||
$prize['goods_image'] = $products[$prize['product_id']]['image'] ?? '';
|
||||
}
|
||||
if ($prize['type'] == 5) {
|
||||
$prize['coupon_title'] = $coupons[$prize['coupon_id']]['coupon_title'] ?? '';
|
||||
}
|
||||
}
|
||||
/** @var UserLabelServices $labelService */
|
||||
$labelService = app()->make(UserLabelServices::class);
|
||||
$lottery['user_label'] = $lottery['user_label'] ? $labelService->getColumn([
|
||||
['id', 'in', $lottery['user_label']],
|
||||
], 'id,label_name') : [];
|
||||
}
|
||||
return $lottery;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加抽奖活动以及奖品
|
||||
* @param array $data
|
||||
* @return mixed
|
||||
*/
|
||||
public function add(array $data)
|
||||
{
|
||||
$prizes = $data['prize'];
|
||||
$prize_num = $this->lottery_type[1];
|
||||
if (count($prizes) != $prize_num) {
|
||||
throw new ValidateException('请选择' . $prize_num . '个奖品');
|
||||
}
|
||||
if (array_sum(array_column($prizes, 'percent')) != 100) {
|
||||
throw new ValidateException('奖品概率和必须为100');
|
||||
}
|
||||
unset($data['prize']);
|
||||
$this->transaction(function () use ($data, $prizes) {
|
||||
$time = time();
|
||||
$data['add_time'] = $time;
|
||||
if (!$lottery = $this->dao->save($data)) {
|
||||
throw new ValidateException('添加抽奖活动失败');
|
||||
}
|
||||
if ($data['status']) {
|
||||
$this->setStatus((int)$lottery->id, $data['status']);
|
||||
}
|
||||
/** @var LuckPrizeServices $luckPrizeServices */
|
||||
$luckPrizeServices = app()->make(LuckPrizeServices::class);
|
||||
$sort = 1;
|
||||
foreach ($prizes as $prize) {
|
||||
$prize = $luckPrizeServices->checkPrizeData($prize);
|
||||
$prize['lottery_id'] = $lottery->id;
|
||||
unset($prize['id']);
|
||||
$prize['add_time'] = $time;
|
||||
$prize['sort'] = $sort;
|
||||
|
||||
$res = $luckPrizeServices->save($prize);
|
||||
if (!$res) {
|
||||
throw new ValidateException('添加抽奖奖品失败');
|
||||
}
|
||||
$sort++;
|
||||
//抽奖商品库存加入redis
|
||||
CacheService::setStock((string)$res->id, (int)$prize['total'], 6);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
$this->dao->cacheTag()->clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改抽奖活动以及奖品
|
||||
* @param int $id
|
||||
* @param array $data
|
||||
* @return mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function edit(int $id, array $data)
|
||||
{
|
||||
$lottery = $this->dao->getLottery($id);
|
||||
if (!$lottery) {
|
||||
throw new ValidateException('抽奖活动不存在');
|
||||
}
|
||||
$newPrizes = $data['prize'];
|
||||
if (array_sum(array_column($newPrizes, 'percent')) != 100) {
|
||||
throw new ValidateException('奖品概率和必须为100');
|
||||
}
|
||||
unset($data['prize'], $data['id']);
|
||||
$prize_num = $this->lottery_type[1];
|
||||
if (count($newPrizes) != $prize_num) {
|
||||
throw new ValidateException('请选择' . $prize_num . '个奖品');
|
||||
}
|
||||
/** @var LuckPrizeServices $luckPrizeServices */
|
||||
$luckPrizeServices = app()->make(LuckPrizeServices::class);
|
||||
$prizes = $luckPrizeServices->getLotteryPrizeList($id);
|
||||
$this->transaction(function () use ($id, $lottery, $data, $newPrizes, $prizes, $luckPrizeServices) {
|
||||
$updateIds = array_column($newPrizes, 'id');
|
||||
$oldIds = array_column($prizes, 'id');
|
||||
$delIds = array_merge(array_diff($oldIds, $updateIds));
|
||||
$insert = [];
|
||||
$time = time();
|
||||
$sort = 1;
|
||||
foreach ($newPrizes as $prize) {
|
||||
$prize = $luckPrizeServices->checkPrizeData($prize);
|
||||
$prize['sort'] = $sort;
|
||||
if (isset($prize['id']) && $prize['id']) {
|
||||
$prizeId = $prize['id'];
|
||||
if (!$prize['lottery_id']) {
|
||||
throw new ValidateException('缺少活动ID');
|
||||
}
|
||||
if (!$luckPrizeServices->update($prize['id'], $prize, 'id')) {
|
||||
throw new ValidateException('修改奖品失败');
|
||||
}
|
||||
} else {
|
||||
unset($prize['id']);
|
||||
$prize['lottery_id'] = $id;
|
||||
$prize['add_time'] = $time;
|
||||
$prize['sort'] = $sort;
|
||||
$res = $luckPrizeServices->save($prize);
|
||||
if (!$res) {
|
||||
throw new ValidateException('新增奖品失败');
|
||||
}
|
||||
$prizeId = $res->id;
|
||||
}
|
||||
$sort++;
|
||||
|
||||
//抽奖商品库存加入redis
|
||||
CacheService::setStock((string)$prizeId, (int)$prize['total'], 6);
|
||||
}
|
||||
if ($delIds) {
|
||||
if (!$luckPrizeServices->update([['id', 'in', $delIds]], ['is_del' => 1])) {
|
||||
throw new ValidateException('删除奖品失败');
|
||||
}
|
||||
}
|
||||
if (!$this->dao->update($id, $data)) {
|
||||
throw new ValidateException('修改失败');
|
||||
}
|
||||
//上架
|
||||
if (!$lottery['status'] && $data['status']) {
|
||||
$this->setStatus($id, $data['status']);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
$this->dao->cacheTag()->clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户某个抽奖活动剩余抽奖次数
|
||||
* @param int $uid
|
||||
* @param int $lottery_id
|
||||
* @param array $userInfo
|
||||
* @param array $lottery
|
||||
* @return false|float|int|mixed
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getLotteryNum(int $uid, int $lottery_id, array $userInfo = [], array $lottery = [])
|
||||
{
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
if (!$userInfo) {
|
||||
$userInfo = $userServices->getUserInfo($uid, ['integral', 'uid', 'now_money', 'spread_lottery']);
|
||||
}
|
||||
if (!$userInfo) {
|
||||
throw new ValidateException('用户不存在');
|
||||
}
|
||||
if (!$lottery) {
|
||||
$lottery = $this->dao->getLottery($lottery_id, '*', [], true);
|
||||
}
|
||||
if (!$lottery) {
|
||||
throw new ValidateException('该活动已经下架,请持续关注');
|
||||
}
|
||||
//抽奖类型:1:积分2:余额3:下单支付成功4:订单评价5:拉新人
|
||||
switch ($lottery['factor']) {
|
||||
case 1:
|
||||
$integral = $userInfo['integral'] - app()->make(UserBillServices::class)->getBillSum(['uid' => $uid, 'is_frozen' => 1]);
|
||||
return $userInfo['integral'] > 0 && $lottery['factor_num'] > 0 ? floor($integral / $lottery['factor_num']) : 0;
|
||||
break;
|
||||
case 2:
|
||||
return $userInfo['now_money'] > 0 && $lottery['factor_num'] > 0 ? floor($userInfo['now_money'] / $lottery['factor_num']) : 0;
|
||||
break;
|
||||
case 3:
|
||||
return $this->getCacheLotteryNum($uid, 'order');
|
||||
break;
|
||||
case 4:
|
||||
return $this->getCacheLotteryNum($uid, 'comment');
|
||||
break;
|
||||
case 5:
|
||||
return $userInfo['spread_lottery'] ?? 0;
|
||||
break;
|
||||
default:
|
||||
throw new ValidateException('暂未有该类型活动');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证用户抽奖资格(用户等级、付费会员、用户标签)
|
||||
* @param int $uid
|
||||
* @param int $lottery_id
|
||||
* @param array $userInfo
|
||||
* @param array $lottery
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function checkoutUserAuth(int $uid, int $lottery_id, array $userInfo = [], array $lottery = [])
|
||||
{
|
||||
if (!$userInfo) {
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$userInfo = $userServices->getUserCacheInfo($uid);
|
||||
}
|
||||
if (!$userInfo) {
|
||||
throw new ValidateException('用户不存在');
|
||||
}
|
||||
if (!$lottery) {
|
||||
$lottery = $this->dao->getLottery($lottery_id, '*', [], true);
|
||||
}
|
||||
if (!$lottery) {
|
||||
throw new ValidateException('该活动已经下架,请持续关注');
|
||||
}
|
||||
//部分用户参与
|
||||
if ($lottery['attends_user'] == 2) {
|
||||
//用户等级
|
||||
if ($lottery['user_level'] && !in_array($userInfo['level'], $lottery['user_level'])) {
|
||||
throw new ValidateException('您暂时无法参与该活动');
|
||||
}
|
||||
//用户标签
|
||||
if ($lottery['user_label']) {
|
||||
/** @var UserLabelRelationServices $userlableRelation */
|
||||
$userlableRelation = app()->make(UserLabelRelationServices::class);
|
||||
$user_labels = $userlableRelation->getUserLabels($uid);
|
||||
if (!array_intersect($lottery['user_label'], $user_labels)) {
|
||||
throw new ValidateException('您暂时无法参与该活动');
|
||||
}
|
||||
}
|
||||
//是否是付费会员
|
||||
if ($lottery['is_svip'] != -1) {
|
||||
if (($lottery['is_svip'] == 1 && $userInfo['is_money_level'] <= 0) || ($lottery['is_svip'] == 0 && $userInfo['is_money_level'] > 0)) {
|
||||
throw new ValidateException('您暂时无法参与该活动');
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 抽奖
|
||||
* @param int $uid
|
||||
* @param int $lottery_id
|
||||
* @return mixed
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function luckLottery(int $uid, int $lottery_id, string $channel_type = '')
|
||||
{
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$userInfo = $userServices->getUserInfo($uid);
|
||||
if (!$userInfo) {
|
||||
throw new ValidateException('用户不存在');
|
||||
}
|
||||
|
||||
$lottery = $this->dao->getLottery($lottery_id, '*', [], true);
|
||||
if (!$lottery) {
|
||||
throw new ValidateException('该活动已经下架,请持续关注');
|
||||
}
|
||||
$userInfo = $userInfo->toArray();
|
||||
$lottery = $lottery->toArray();
|
||||
//验证用户身份
|
||||
$this->checkoutUserAuth($uid, $lottery_id, $userInfo, $lottery);
|
||||
|
||||
/** @var LuckPrizeServices $lotteryPrizeServices */
|
||||
$lotteryPrizeServices = app()->make(LuckPrizeServices::class);
|
||||
$lotteryPrize = $lotteryPrizeServices->getPrizeList($lottery_id);
|
||||
if (!$lotteryPrize) {
|
||||
throw new ValidateException('该活动状态有误,请联系管理员');
|
||||
}
|
||||
if ($this->getLotteryNum($uid, $lottery_id, $userInfo, $lottery) < 1) {
|
||||
//抽奖类型:1:积分2:余额3:下单支付成功4:订单评价5:拉新人
|
||||
switch ($lottery['factor']) {
|
||||
case 1:
|
||||
throw new ValidateException('积分不足,没有更多抽奖次数');
|
||||
break;
|
||||
case 2:
|
||||
throw new ValidateException('余额不足,没有更多抽奖次数');
|
||||
break;
|
||||
case 3:
|
||||
throw new ValidateException('购买商品之后获得更多抽奖次数');
|
||||
break;
|
||||
case 4:
|
||||
throw new ValidateException('订单完成评价之后获得更多抽奖次数');
|
||||
break;
|
||||
case 5:
|
||||
throw new ValidateException('邀请更多好友获取抽奖次数');
|
||||
break;
|
||||
default:
|
||||
throw new ValidateException('暂未有该类型活动');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($lottery['factor'] == 1) {//积分抽奖
|
||||
/** @var LuckLotteryRecordServices $lotteryRecordServices */
|
||||
$lotteryRecordServices = app()->make(LuckLotteryRecordServices::class);
|
||||
$data = $lotteryRecordServices->getLotteryNum($uid, (int)$lottery['id']);
|
||||
$lotteryData['todayCount'] = (int)max(bcsub((string)$lottery['lottery_num'], (string)$data['todayCount'], 0), 0);
|
||||
$lotteryData['totalCount'] = (int)max(bcsub((string)$lottery['total_lottery_num'], (string)$data['totalCount'], 0), 0);
|
||||
if ($lotteryData['todayCount'] <= 0) {
|
||||
throw new ValidateException('本次活动当天抽奖次数已用完!');
|
||||
}
|
||||
if ($lotteryData['totalCount'] <= 0) {
|
||||
throw new ValidateException('本次活动总抽奖次数已用完!');
|
||||
}
|
||||
}
|
||||
|
||||
/** @var LuckPrizeServices $luckPrizeServices */
|
||||
$luckPrizeServices = app()->make(LuckPrizeServices::class);
|
||||
//随机抽奖
|
||||
$prize = $luckPrizeServices->getLuckPrize($lotteryPrize);
|
||||
if (!$prize) {
|
||||
throw new ValidateException('该活动状态有误,请联系管理员');
|
||||
}
|
||||
|
||||
return $this->transaction(function () use ($prize, $luckPrizeServices, $uid, $lotteryPrize, $userInfo, $lottery, $channel_type) {
|
||||
//中奖扣除积分、余额
|
||||
$this->lotteryFactor($uid, $userInfo, $lottery);
|
||||
//中奖减少奖品数量
|
||||
$luckPrizeServices->decPrizeNum($prize['id'], $prize);
|
||||
/** @var LuckLotteryRecordServices $lotteryRecordServices */
|
||||
$lotteryRecordServices = app()->make(LuckLotteryRecordServices::class);
|
||||
//中奖写入记录
|
||||
$record = $lotteryRecordServices->insertPrizeRecord($uid, $prize, $userInfo);
|
||||
//不是站内商品直接领奖
|
||||
if ($prize['type'] != 6) {
|
||||
$lotteryRecordServices->receivePrize($uid, (int)$record->id, [], $channel_type);
|
||||
}
|
||||
$prize['lottery_record_id'] = $record->id;
|
||||
return $prize;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 抽奖消耗扣除用户积分、余额等
|
||||
* @param int $uid
|
||||
* @param array $userInfo
|
||||
* @param array $lottery
|
||||
* @return bool
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||
*/
|
||||
public function lotteryFactor(int $uid, array $userInfo, array $lottery)
|
||||
{
|
||||
if (!$userInfo || !$lottery) {
|
||||
return true;
|
||||
}
|
||||
//抽奖类型:1:积分2:余额3:下单支付成功4:订单评价5:拉新人
|
||||
switch ($lottery['factor']) {
|
||||
case 1:
|
||||
if ($userInfo['integral'] > $lottery['factor_num']) {
|
||||
$integral = bcsub((string)$userInfo['integral'], (string)$lottery['factor_num'], 0);
|
||||
} else {
|
||||
$integral = 0;
|
||||
}
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
/** @var UserBillServices $userBillServices */
|
||||
$userBillServices = app()->make(UserBillServices::class);
|
||||
$userBillServices->income('lottery_use_integral', $uid, (int)$lottery['factor_num'], (int)$integral, $lottery['id']);
|
||||
if (!$userServices->update($uid, ['integral' => $integral], 'uid')) {
|
||||
throw new ValidateException('抽奖扣除用户积分失败');
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if ($userInfo['now_money'] >= $lottery['factor_num']) {
|
||||
$now_money = bcsub((string)$userInfo['now_money'], (string)$lottery['factor_num'], 2);
|
||||
} else {
|
||||
throw new ValidateException('抽奖失败,余额不足!');
|
||||
}
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
/** @var UserMoneyServices $userMoneyServices */
|
||||
$userMoneyServices = app()->make(UserMoneyServices::class);
|
||||
$userMoneyServices->income('lottery_use_money', $uid, $lottery['factor_num'], $now_money, $lottery['id']);
|
||||
if (!$userServices->update($uid, ['now_money' => $now_money], 'uid')) {
|
||||
throw new ValidateException('抽奖扣除用户余额失败');
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
//销毁抽奖次数缓存
|
||||
$this->delCacheLotteryNum($uid, $lottery['factor'] == 3 ? 'order' : 'comment');
|
||||
break;
|
||||
case 5:
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$spread_lottery = 0;
|
||||
if ($userInfo['spread_lottery'] > 1) {
|
||||
$spread_lottery = $userInfo['spread_lottery'] - 1;
|
||||
}
|
||||
if (!$userServices->update($uid, ['spread_lottery' => $spread_lottery], 'uid')) {
|
||||
throw new ValidateException('抽奖扣除用户推广获取抽奖次数失败');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ValidateException('暂未有该类型活动');
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param int $id
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function delLottery(int $id)
|
||||
{
|
||||
if ($lottery = $this->dao->getLottery($id)) {
|
||||
if (!$this->dao->update(['id' => $id], ['is_del' => 1])) {
|
||||
throw new AdminException('删除失败,请稍候重试');
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置抽奖活动状态
|
||||
* @param int $id
|
||||
* @param $status
|
||||
* @return false|mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function setStatus(int $id, $status)
|
||||
{
|
||||
if (!$id) return false;
|
||||
$lottery = $this->dao->getLottery($id, 'id,factor');
|
||||
if (!$lottery) {
|
||||
return false;
|
||||
}
|
||||
//每一种抽奖类型只有一个上架
|
||||
// if ($status) {
|
||||
// $this->dao->update(['factor' => $lottery['factor']], ['status' => 0]);
|
||||
// }
|
||||
return $this->dao->update($id, ['status' => $status], 'id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 下单支付、评论缓存抽奖次数
|
||||
* @param int $uid
|
||||
* @param string $type
|
||||
* @return bool
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||
*/
|
||||
public function setCacheLotteryNum(int $uid, string $type = 'order')
|
||||
{
|
||||
$factor = $type == 'order' ? 3 : 4;
|
||||
$lottery = $this->dao->getFactorLottery($factor, 'id,factor_num');
|
||||
if (!$lottery || !$lottery['factor_num']) {
|
||||
return true;
|
||||
}
|
||||
$key = 'user_' . $type . '_luck_lottery_' . $uid;
|
||||
$timeKey = 'expire_time_user_' . $type . '_luck_lottery_' . $uid;
|
||||
$cache = CacheService::redisHandler();
|
||||
// $num = (int)$this->getCacheLotteryNum($uid, $type);
|
||||
$cache->set($timeKey, bcadd((string)time(), (string)$this->luck_cache_time), bcadd('10', (string)$this->luck_cache_time));
|
||||
return $cache->set($key, $lottery['factor_num'], $this->luck_cache_time);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取抽奖到期时间
|
||||
* @param int $uid
|
||||
* @param string $type
|
||||
* @return int|mixed
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||
*/
|
||||
public function getCacheLotteryExpireTime(int $uid, string $type = 'order')
|
||||
{
|
||||
$timeKey = 'expire_time_user_' . $type . '_luck_lottery_' . $uid;
|
||||
$time = CacheService::redisHandler()->get($timeKey);
|
||||
return empty($time) ? 0 : $time;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取出下单支付、评论得到的抽奖此处
|
||||
* @param int $uid
|
||||
* @param string $type
|
||||
* @return int|mixed
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||
*/
|
||||
public function getCacheLotteryNum(int $uid, string $type = 'order')
|
||||
{
|
||||
$key = 'user_' . $type . '_luck_lottery_' . $uid;
|
||||
$num = CacheService::redisHandler()->get($key);
|
||||
return empty($num) ? 0 : $num;
|
||||
}
|
||||
|
||||
/**
|
||||
* 抽奖之后销毁缓存
|
||||
* @param int $uid
|
||||
* @param string $type
|
||||
* @return bool
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||
*/
|
||||
public function delCacheLotteryNum(int $uid, string $type = 'order')
|
||||
{
|
||||
$key = 'user_' . $type . '_luck_lottery_' . $uid;
|
||||
$timeKey = 'expire_time_user_' . $type . '_luck_lottery_' . $uid;
|
||||
$num = $this->getCacheLotteryNum($uid, $type);
|
||||
$cache = CacheService::redisHandler();
|
||||
if ($num > 1) {
|
||||
$cache->set($timeKey, bcadd((string)time(), (string)$this->luck_cache_time), bcadd('10', (string)$this->luck_cache_time));
|
||||
$cache->set($key, $num - 1, $this->luck_cache_time);
|
||||
} else {
|
||||
$cache->delete($timeKey);
|
||||
$cache->delete($key);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取抽奖列表以及正在使用的抽奖活动
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* @author wuhaotian
|
||||
* @email 442384644@qq.com
|
||||
* @date 2025/3/18
|
||||
*/
|
||||
public function factorList()
|
||||
{
|
||||
$list = $this->dao->selectList([
|
||||
['status', '=', 1],
|
||||
['is_del', '=', 0],
|
||||
['end_time', '>', time()],
|
||||
['start_time', '<', time()],
|
||||
], 'id,name,factor,is_use')->toArray();
|
||||
$data = [
|
||||
'info' => [
|
||||
'point' => '',
|
||||
'pay' => '',
|
||||
'evaluate' => '',
|
||||
'follow' => ''
|
||||
],
|
||||
'point' => [],
|
||||
'pay' => [],
|
||||
'evaluate' => [],
|
||||
'follow' => []
|
||||
];
|
||||
foreach ($list as $item) {
|
||||
if ($item['factor'] == 1) {
|
||||
$data['point'][] = $item;
|
||||
if ($data['info']['point'] == '') {
|
||||
$data['info']['point'] = $item['is_use'] ? $item['id'] : '';
|
||||
}
|
||||
} elseif ($item['factor'] == 3) {
|
||||
$data['pay'][] = $item;
|
||||
if ($data['info']['pay'] == '') {
|
||||
$data['info']['pay'] = $item['is_use'] ? $item['id'] : '';
|
||||
}
|
||||
} elseif ($item['factor'] == 4) {
|
||||
$data['evaluate'][] = $item;
|
||||
if ($data['info']['evaluate'] == '') {
|
||||
$data['info']['evaluate'] = $item['is_use'] ? $item['id'] : '';
|
||||
}
|
||||
} else {
|
||||
$data['follow'][] = $item;
|
||||
if ($data['info']['follow'] == '') {
|
||||
$data['info']['follow'] = $item['is_use'] ? $item['id'] : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 活动类型使用
|
||||
* @param $data
|
||||
* @return bool
|
||||
* @author wuhaotian
|
||||
* @email 442384644@qq.com
|
||||
* @date 2025/3/18
|
||||
*/
|
||||
public function factorUse($data)
|
||||
{
|
||||
$this->dao->update(['is_del' => 0], ['is_use' => 0]);
|
||||
if ($data['point']) {
|
||||
$this->dao->update(['factor' => 1, 'id' => $data['point']], ['is_use' => 1]);
|
||||
}
|
||||
if ($data['pay']) {
|
||||
$this->dao->update(['factor' => 3, 'id' => $data['pay']], ['is_use' => 1]);
|
||||
}
|
||||
if ($data['evaluate']) {
|
||||
$this->dao->update(['factor' => 4, 'id' => $data['evaluate']], ['is_use' => 1]);
|
||||
}
|
||||
if ($data['follow']) {
|
||||
$this->dao->update(['factor' => 5, 'id' => $data['follow']], ['is_use' => 1]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
273
app/services/activity/lottery/LuckPrizeServices.php
Normal file
273
app/services/activity/lottery/LuckPrizeServices.php
Normal file
@@ -0,0 +1,273 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\lottery;
|
||||
|
||||
use app\services\BaseServices;
|
||||
use app\dao\activity\lottery\LuckPrizeDao;
|
||||
use app\services\activity\coupon\StoreCouponIssueServices;
|
||||
use crmeb\services\CacheService;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class LuckPrizeServices
|
||||
* @package app\services\activity\lottery
|
||||
* @mixin LuckPrizeDao
|
||||
*/
|
||||
class LuckPrizeServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var array 1:未中奖2:积分3:余额4:红包5:优惠券6:站内商品7:等级经验8:用户等级 9:svip天数
|
||||
*/
|
||||
public array $prize_type = [
|
||||
'1' => '未中奖',
|
||||
'2' => '积分',
|
||||
'3' => '余额',
|
||||
'4' => '红包',
|
||||
'5' => '优惠券',
|
||||
'6' => '站内商品',
|
||||
'7' => '等级经验',
|
||||
'8' => '用户等级',
|
||||
'9' => 'svip天数'
|
||||
];
|
||||
|
||||
/**
|
||||
* 奖品数据字段
|
||||
* @var array
|
||||
*/
|
||||
public array $prize = [
|
||||
'id' => 0,
|
||||
'type' => 1,
|
||||
'lottery_id' => 0,
|
||||
'name' => '',
|
||||
'prompt' => '',
|
||||
'image' => '',
|
||||
'chance' => 0,
|
||||
'percent' => 0,
|
||||
'total' => 0,
|
||||
'coupon_id' => 0,
|
||||
'product_id' => 0,
|
||||
'unique' => '',
|
||||
'num' => 1,
|
||||
'sort' => 0,
|
||||
'status' => 1,
|
||||
'is_del' => 0,
|
||||
'add_time' => 0,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var LuckPrizeDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected LuckPrizeDao $dao;
|
||||
|
||||
/**
|
||||
* 奖品数据验证
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function checkPrizeData(array $data)
|
||||
{
|
||||
$data = array_merge($this->prize, array_intersect_key($data, $this->prize));
|
||||
if (!isset($data['name']) || !$data['name']) {
|
||||
throw new ValidateException('请填写奖品名称');
|
||||
}
|
||||
if (!isset($data['image']) || !$data['image']) {
|
||||
throw new ValidateException('请选择奖品图片');
|
||||
}
|
||||
if (!isset($data['chance'])) {
|
||||
throw new ValidateException('请填写奖品中奖权重');
|
||||
}
|
||||
if (!isset($data['type']) || !isset($this->prize_type[$data['type']])) {
|
||||
throw new ValidateException('请选择奖品类型');
|
||||
}
|
||||
if (in_array($data['type'], [2, 3, 4]) && (!isset($data['num']) || !$data['num'])) {
|
||||
$msg = '';
|
||||
switch ($data['type']) {
|
||||
case 2:
|
||||
$msg = '积分';
|
||||
break;
|
||||
case 3:
|
||||
$msg = '余额';
|
||||
break;
|
||||
case 4:
|
||||
$msg = '红包';
|
||||
break;
|
||||
}
|
||||
throw new ValidateException('请填写奖品赠送' . $msg . '数');
|
||||
}
|
||||
if ($data['type'] == 2) {
|
||||
$data['num'] = (int)$data['num'];
|
||||
}
|
||||
if ($data['type'] == 5 && (!isset($data['coupon_id']) || !$data['coupon_id'])) {
|
||||
throw new ValidateException('请选择优惠券');
|
||||
}
|
||||
if ($data['type'] == 6 && (!isset($data['product_id']) || !$data['product_id'])) {
|
||||
throw new ValidateException('请选择商品');
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改奖品
|
||||
* @param int $id
|
||||
* @param array $data
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function edit(int $id, array $data)
|
||||
{
|
||||
$this->checkPrizeData($data);
|
||||
$prize = $this->dao->get($id);
|
||||
if (!$prize) {
|
||||
throw new ValidateException('奖品不存在');
|
||||
}
|
||||
if (!$this->dao->update($id, $data, 'id')) {
|
||||
throw new ValidateException('修改失败');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某个抽奖活动的所有奖品
|
||||
* @param int $lottery_id
|
||||
* @param string $field
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getLotteryPrizeList(int $lottery_id, string $field = '*')
|
||||
{
|
||||
return $this->dao->getPrizeList($lottery_id, $field);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 随机奖品
|
||||
* @param array $data
|
||||
* @return array|mixed
|
||||
*/
|
||||
public function getLuckPrize(array $data)
|
||||
{
|
||||
$totalPercent = array_sum(array_column($data, 'percent')) * 100;
|
||||
$prize = [];
|
||||
if (!$data) return $prize;
|
||||
mt_srand();
|
||||
$random = mt_rand(1, (int)$totalPercent);
|
||||
$range = 0;
|
||||
$newPrize = array_combine(array_column($data, 'type'), $data);
|
||||
foreach ($data as $item) {
|
||||
// 转换百分比为千分位范围
|
||||
$range += $item['percent'] * 100; // 例如 12.34% -> 1234
|
||||
if ($random <= $range) {
|
||||
if (($item['sort'] != 1 && $item['total'] != -1 && $item['total'] <= 0)) {
|
||||
$prize = $newPrize[1] ?? [];
|
||||
} else {
|
||||
if (CacheService::checkStock((string)$item['id'], 1, 6)) {
|
||||
$prize = $item;
|
||||
} else {
|
||||
$prize = $newPrize[1] ?? [];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $prize;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// $prize = [];
|
||||
// if (!$data) return $prize;
|
||||
// $coupon = [];
|
||||
// $coupon_ids = array_unique(array_column($data, 'coupon_id'));
|
||||
// if ($coupon_ids) {
|
||||
// /** @var StoreCouponIssueServices $couponServices */
|
||||
// $couponServices = app()->make(StoreCouponIssueServices::class);
|
||||
// $coupon = $couponServices->getGiveCoupon([['id', 'IN', $coupon_ids]]);
|
||||
// if ($coupon) $coupon = array_combine(array_column($coupon, 'id'), $coupon);
|
||||
// }
|
||||
// $totalChance = 100;
|
||||
// $startChance = 0;
|
||||
// mt_srand();
|
||||
// $prizeChance = rand(0, $totalChance - 1);
|
||||
// $newPrize = array_combine(array_column($data, 'type'), $data);
|
||||
// foreach ($data as $item) {
|
||||
// $newStartChance = (int)bcadd((string)$item['chance'], (string)$startChance);
|
||||
// //随机数在这个基数端内 且该商品数量大于0 中奖
|
||||
// if ($prizeChance >= $startChance && $prizeChance < $newStartChance) {
|
||||
// //奖品权重<=0 || 随机到不是未中奖奖品-》设置了奖品数量-》数量不足时 返回未中奖奖品 || 抽到优惠券 数量不足
|
||||
// if ((int)$item['chance'] <= 0 ||
|
||||
// (
|
||||
// $item['type'] != 1 &&
|
||||
// $item['total'] != -1 &&
|
||||
// $item['total'] <= 0
|
||||
// )
|
||||
// ||
|
||||
// (
|
||||
// $item['coupon_id'] &&
|
||||
// $coupon &&
|
||||
// !isset($coupon[$item['coupon_id']])
|
||||
// )
|
||||
// ) {
|
||||
// $prize = $newPrize[1] ?? [];
|
||||
// } else {
|
||||
// if (CacheService::checkStock((string)$item['id'], 1, 6)) {
|
||||
// $prize = $item;
|
||||
// } else {
|
||||
// $prize = $newPrize[1] ?? [];
|
||||
// }
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
// $startChance = $newStartChance;
|
||||
// }
|
||||
// return $prize;
|
||||
}
|
||||
|
||||
/**
|
||||
* 中奖后减少奖品数量
|
||||
* @param int $id
|
||||
* @param array $prize
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function decPrizeNum(int $id, array $prize = [])
|
||||
{
|
||||
if (!$id) return false;
|
||||
if (!$prize) {
|
||||
$prize = $this->dao->get($id);
|
||||
}
|
||||
if (!$prize) {
|
||||
throw new ValidateException('该奖品不存在');
|
||||
}
|
||||
//不是未中奖奖品 减少奖品数量
|
||||
if ($prize['type'] != 1 && $prize['total'] >= 1) {
|
||||
$total = $prize['total'] - 1;
|
||||
if (!$this->dao->update($id, ['total' => $total], 'id')) {
|
||||
throw new ValidateException('抽奖减少奖品总数失败');
|
||||
}
|
||||
CacheService::popStock((string)$id, 1, 6);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
656
app/services/activity/newcomer/StoreNewcomerServices.php
Normal file
656
app/services/activity/newcomer/StoreNewcomerServices.php
Normal file
@@ -0,0 +1,656 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\newcomer;
|
||||
|
||||
use app\dao\activity\newcomer\StoreNewcomerDao;
|
||||
use app\jobs\product\ProductLogJob;
|
||||
use app\services\activity\coupon\StoreCouponIssueServices;
|
||||
use app\services\activity\coupon\StoreCouponUserServices;
|
||||
use app\services\BaseServices;
|
||||
use app\services\diy\DiyServices;
|
||||
use app\services\order\StoreOrderServices;
|
||||
use app\services\product\ensure\StoreProductEnsureServices;
|
||||
use app\services\product\label\StoreProductLabelServices;
|
||||
use app\services\product\product\StoreDescriptionServices;
|
||||
use app\services\product\product\StoreProductReplyServices;
|
||||
use app\services\product\product\StoreProductServices;
|
||||
use app\services\product\sku\StoreProductAttrServices;
|
||||
use app\services\product\sku\StoreProductAttrValueServices;
|
||||
use app\services\user\UserRelationServices;
|
||||
use app\services\user\UserServices;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use crmeb\services\SystemConfigService;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
/**
|
||||
* Class StoreNewcomerServices
|
||||
* @package app\services\activity\newcomer
|
||||
* @mixin StoreNewcomerDao
|
||||
*/
|
||||
class StoreNewcomerServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* 商品活动类型
|
||||
*/
|
||||
const TYPE = 7;
|
||||
|
||||
/**
|
||||
* @var StoreNewcomerDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreNewcomerDao $dao;
|
||||
|
||||
/**
|
||||
* 获取新人礼商品详情
|
||||
* @param int $id
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getInfo(int $id)
|
||||
{
|
||||
$info = $this->dao->get($id, ['*'], ['product']);
|
||||
$res = [];
|
||||
if ($info) {
|
||||
$res = $info->toArray();
|
||||
$product = $res['product'] ?? [];
|
||||
unset($res['product'], $product['id'], $product['price']);
|
||||
$res = array_merge($res, $product);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取新人专享商品
|
||||
* @param array $where
|
||||
* @param string $field
|
||||
* @param array $with
|
||||
* @param int $limit
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getCustomerProduct(array $where = [], string $field = '*', array $with = ['product', 'attrValue'])
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$where['is_del'] = 0;
|
||||
$list = $this->dao->getList($where, $field, $page, $limit, $with);
|
||||
$res = [];
|
||||
if ($list) {
|
||||
foreach ($list as &$item) {
|
||||
$product = $item['product'] ?? [];
|
||||
if ($product) {
|
||||
unset($item['product'], $product['id'], $product['price']);
|
||||
$item = array_merge($item, $product);
|
||||
$res[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存新人礼专属商品
|
||||
* @param $data
|
||||
* @return bool
|
||||
*/
|
||||
public function saveNewcomer($data)
|
||||
{
|
||||
$productIds = [];
|
||||
$oldProductIds = $this->dao->getColumn(['is_del' => 0], 'id,product_id');
|
||||
if ($oldProductIds) $oldProductIds = array_column($oldProductIds, 'product_id');
|
||||
if ($data) {
|
||||
$productIds = array_column($data, 'product_id');
|
||||
$this->transaction(function () use ($data) {
|
||||
foreach ($data as $product) {
|
||||
$this->saveData(0, $product);
|
||||
}
|
||||
});
|
||||
}
|
||||
$deleteIds = array_merge(array_diff($oldProductIds, $productIds));
|
||||
//清空现有新人礼商品
|
||||
if ($deleteIds) {
|
||||
$this->dao->update(['is_del' => 0, 'product_id' => $deleteIds], ['is_del' => 1, 'update_time' => time()]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存数据
|
||||
* @param int $id
|
||||
* @param array $info
|
||||
*/
|
||||
public function saveData(int $id, array $info)
|
||||
{
|
||||
if (!$info || !isset($info['product_id']) || !$info['product_id']) {
|
||||
throw new ValidateException('请重新选择新人专享商品');
|
||||
}
|
||||
$attr = $info['attr'];
|
||||
if ($attr) {
|
||||
foreach ($attr as $a) {
|
||||
if (!isset($a['unique']) || !isset($a['price'])) throw new ValidateException('请重新选择新人专享商品');
|
||||
if (!$a['price']) {
|
||||
throw new ValidateException('请填写商品专享价');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!$info['price']) {
|
||||
throw new ValidateException('请填写商品专享价');
|
||||
}
|
||||
}
|
||||
/** @var StoreProductServices $storeProductServices */
|
||||
$storeProductServices = app()->make(StoreProductServices::class);
|
||||
$productInfo = $storeProductServices->getOne(['is_show' => 1, 'is_del' => 0, 'is_verify' => 1, 'id' => $info['product_id']]);
|
||||
if (!$productInfo) {
|
||||
throw new AdminException('原商品已下架或移入回收站');
|
||||
}
|
||||
if ($productInfo['is_vip_product'] || $productInfo['is_presale_product']) {
|
||||
throw new AdminException('该商品是预售或svip专享');
|
||||
}
|
||||
if (!$id) {
|
||||
$newcomer = $this->dao->getOne(['product_id' => $info['product_id'], 'is_del' => 0]);
|
||||
$id = $newcomer['id'] ?? 0;
|
||||
}
|
||||
|
||||
$data = [];
|
||||
$data['product_id'] = $productInfo['id'];
|
||||
$data['type'] = $productInfo['type'] ?? 0;
|
||||
$data['product_type'] = $productInfo['product_type'];
|
||||
$data['relation_id'] = $productInfo['relation_id'] ?? 0;
|
||||
$data['price'] = $info['price'] ?? 0;
|
||||
|
||||
if ($attr) $data['price'] = min(array_column($attr, 'price'));
|
||||
|
||||
/** @var StoreProductAttrValueServices $productAttrValueServices */
|
||||
$productAttrValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
/** @var StoreProductAttrServices $productAttrServices */
|
||||
$productAttrServices = app()->make(StoreProductAttrServices::class);
|
||||
$attrValue = $productAttrValueServices->getList(['product_id' => $info['product_id'], 'type' => 0]);
|
||||
$skus = array_column($attr, 'unique');
|
||||
$attr = array_combine($skus, $attr);
|
||||
|
||||
$this->transaction(function () use ($id, $data, $attrValue, $skus, $attr, $productAttrValueServices, $productAttrServices) {
|
||||
$newcomerAttrValue = [];
|
||||
if ($id) {
|
||||
$data['update_time'] = time();
|
||||
$res = $this->dao->update($id, $data);
|
||||
$newcomerAttrValue = $productAttrValueServices->getList(['product_id' => $id, 'type' => 7]);
|
||||
if (!$res) throw new AdminException('修改失败');
|
||||
} else {
|
||||
$data['add_time'] = time();
|
||||
$res = $this->dao->save($data);
|
||||
if (!$res) throw new AdminException('添加失败');
|
||||
$id = (int)$res->id;
|
||||
}
|
||||
$detail = [];
|
||||
foreach ($attrValue as $item) {
|
||||
if (in_array($item['unique'], $skus)) {
|
||||
$item['product_id'] = $id;
|
||||
$item['type'] = 7;
|
||||
if (isset($attr[$item['unique']]['price'])) $item['price'] = $attr[$item['unique']]['price'];
|
||||
$item['unique'] = $productAttrServices->createAttrUnique((int)$id, $item['suk']);
|
||||
unset($item['id']);
|
||||
$detail[] = $item;
|
||||
}
|
||||
}
|
||||
if ($newcomerAttrValue) {
|
||||
foreach ($newcomerAttrValue as $item) {
|
||||
if (in_array($item['unique'], $skus)) {
|
||||
$item['product_id'] = $id;
|
||||
$item['type'] = 7;
|
||||
if (isset($attr[$item['unique']]['price'])) $item['price'] = $attr[$item['unique']]['price'];
|
||||
unset($item['id']);
|
||||
$detail[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
$productAttrValueServices->delete(['product_id' => $id, 'type' => 7]);
|
||||
if ($detail) $productAttrValueServices->saveAll($detail);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取新人专享商品详情
|
||||
* @param int $id
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function newcomerDetail(int $uid, int $id)
|
||||
{
|
||||
$storeInfo = $this->getInfo($id);
|
||||
if (!$storeInfo) {
|
||||
throw new ValidateException('新人商品已下架或删除');
|
||||
}
|
||||
/** @var DiyServices $diyServices */
|
||||
$diyServices = app()->make(DiyServices::class);
|
||||
$infoDiy = $diyServices->getProductDetailDiy();
|
||||
//diy控制参数
|
||||
if (!isset($infoDiy['showService']) || in_array(3, $infoDiy['showService'])) {
|
||||
$storeInfo['specs'] = [];
|
||||
}
|
||||
|
||||
$configData = SystemConfigService::more(['site_url', 'routine_contact_type', 'site_name', 'share_qrcode', 'store_self_mention', 'store_func_status', 'product_poster_title']);
|
||||
$siteUrl = $configData['site_url'] ?? '';
|
||||
$storeInfo['image'] = set_file_url($storeInfo['image'], $siteUrl);
|
||||
$storeInfo['image_base'] = set_file_url($storeInfo['image'], $siteUrl);
|
||||
/** @var StoreDescriptionServices $descriptionServices */
|
||||
$descriptionServices = app()->make(StoreDescriptionServices::class);
|
||||
$storeInfo['description'] = $descriptionServices->getDescription(['product_id' => $storeInfo['product_id']]);
|
||||
|
||||
//品牌名称
|
||||
/** @var StoreProductServices $storeProductServices */
|
||||
$storeProductServices = app()->make(StoreProductServices::class);
|
||||
$productInfo = $storeProductServices->get($storeInfo['product_id'], ['id', 'delivery_type', 'brand_id', 'sales', 'ficti']);
|
||||
$storeInfo['brand_name'] = $storeProductServices->productIdByBrandName((int)$storeInfo['product_id'], $productInfo);
|
||||
$delivery_type = $storeInfo['delivery_type'] ?? $productInfo['delivery_type'];
|
||||
$storeInfo['delivery_type'] = is_string($delivery_type) ? explode(',', $delivery_type) : $delivery_type;
|
||||
/**
|
||||
* 判断配送方式
|
||||
*/
|
||||
$storeInfo['delivery_type'] = $storeProductServices->getDeliveryType($storeInfo['type'], $storeInfo['relation_id'], $storeInfo['delivery_type']);
|
||||
$storeInfo['total'] = $productInfo['sales'] + $productInfo['ficti'];
|
||||
$storeInfo['store_label'] = $storeInfo['ensure'] = [];
|
||||
if ($storeInfo['store_label_id']) {
|
||||
/** @var StoreProductLabelServices $storeProductLabelServices */
|
||||
$storeProductLabelServices = app()->make(StoreProductLabelServices::class);
|
||||
$storeInfo['store_label'] = $storeProductLabelServices->getLabelCache($storeInfo['store_label_id'], ['id', 'label_name', 'style_type', 'color', 'bg_color', 'border_color', 'icon']);
|
||||
}
|
||||
if ($storeInfo['ensure_id'] && isset($infoDiy['showService']) && in_array(2, $infoDiy['showService'])) {
|
||||
/** @var StoreProductEnsureServices $storeProductEnsureServices */
|
||||
$storeProductEnsureServices = app()->make(StoreProductEnsureServices::class);
|
||||
$storeInfo['ensure'] = $storeProductEnsureServices->getEnsurCache($storeInfo['ensure_id'], ['id', 'name', 'image', 'desc']);
|
||||
}
|
||||
/** @var StoreOrderServices $storeOrderServices */
|
||||
$storeOrderServices = app()->make(StoreOrderServices::class);
|
||||
$data['buy_num'] = $storeOrderServices->getBuyCount($uid, 7, $id);
|
||||
|
||||
/** @var UserRelationServices $userRelationServices */
|
||||
$userRelationServices = app()->make(UserRelationServices::class);
|
||||
$storeInfo['userCollect'] = $userRelationServices->isProductRelationCache(['uid' => $uid, 'relation_id' => $storeInfo['product_id'], 'type' => 'collect', 'category' => UserRelationServices::CATEGORY_PRODUCT]);
|
||||
$storeInfo['userLike'] = 0;
|
||||
|
||||
$storeInfo['uid'] = $uid;
|
||||
|
||||
//商品详情
|
||||
$storeInfo['small_image'] = get_thumb_water($storeInfo['image']);
|
||||
$data['storeInfo'] = $storeInfo;
|
||||
|
||||
$data['reply'] = [];
|
||||
$data['replyChance'] = $data['replyCount'] = 0;
|
||||
if (isset($infoDiy['showReply']) && $infoDiy['showReply']) {
|
||||
/** @var StoreProductReplyServices $storeProductReplyService */
|
||||
$storeProductReplyService = app()->make(StoreProductReplyServices::class);
|
||||
$reply = $storeProductReplyService->getRecProductReply($storeInfo['product_id'], (int)($infoDiy['replyNum'] ?? 1));
|
||||
$data['reply'] = $reply ? get_thumb_water($reply, 'small', ['pics']) : [];
|
||||
[$replyCount, $goodReply, $replyChance] = $storeProductReplyService->getProductReplyData((int)$storeInfo['product_id']);
|
||||
$data['replyChance'] = $replyChance;
|
||||
$data['replyCount'] = $replyCount;
|
||||
}
|
||||
|
||||
/** @var StoreProductAttrServices $storeProductAttrServices */
|
||||
$storeProductAttrServices = app()->make(StoreProductAttrServices::class);
|
||||
[$productAttr, $productValue] = $storeProductAttrServices->getProductAttrDetail($id, $uid, 0, 7, $storeInfo['product_id']);
|
||||
$data['productAttr'] = $productAttr;
|
||||
$data['productValue'] = $productValue;
|
||||
$data['routine_contact_type'] = $configData['routine_contact_type'] ?? 0;
|
||||
$data['store_func_status'] = (int)($configData['store_func_status'] ?? 1);//门店是否开启
|
||||
$data['store_self_mention'] = $data['store_func_status'] ? (int)($configData['store_self_mention'] ?? 0) : 0;//门店自提是否开启
|
||||
$data['site_name'] = $configData['site_name'] ?? '';
|
||||
$data['share_qrcode'] = $configData['share_qrcode'] ?? 0;
|
||||
$data['product_poster_title'] = $configData['product_poster_title'] ?? '';
|
||||
//浏览记录
|
||||
ProductLogJob::dispatch(['visit', ['uid' => $uid, 'id' => $id, 'product_id' => $storeInfo['product_id']], 'newcomer']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 修改秒杀库存
|
||||
* @param int $num
|
||||
* @param int $newcomerId
|
||||
* @param string $unique
|
||||
* @param int $store_id
|
||||
* @return bool
|
||||
*/
|
||||
public function decNewcomerStock(int $num, int $newcomerId, string $unique = '', int $store_id = 0)
|
||||
{
|
||||
$product_id = $this->dao->value(['id' => $newcomerId], 'product_id');
|
||||
if ($product_id && $unique) {
|
||||
/** @var StoreProductAttrValueServices $skuValueServices */
|
||||
$skuValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
//新人商品sku
|
||||
$suk = $skuValueServices->value(['unique' => $unique, 'product_id' => $newcomerId, 'type' => 7], 'suk');
|
||||
//平台普通商品sku unique
|
||||
$productUnique = $skuValueServices->value(['suk' => $suk, 'product_id' => $product_id, 'type' => 0], 'unique');
|
||||
/** @var StoreProductServices $services */
|
||||
$services = app()->make(StoreProductServices::class);
|
||||
//减去普通商品库存
|
||||
$res = false !== $services->decProductStock($num, $product_id, (string)$productUnique);
|
||||
} else {
|
||||
$res = false;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加库存减销量
|
||||
* @param int $num
|
||||
* @param int $newcomerId
|
||||
* @param string $unique
|
||||
* @param int $store_id
|
||||
* @return bool
|
||||
*/
|
||||
public function incNewcomerStock(int $num, int $newcomerId, string $unique = '', int $store_id = 0)
|
||||
{
|
||||
$product_id = $this->dao->value(['id' => $newcomerId], 'product_id');
|
||||
if ($product_id && $unique) {
|
||||
/** @var StoreProductAttrValueServices $skuValueServices */
|
||||
$skuValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
//新人商品sku
|
||||
$suk = $skuValueServices->value(['unique' => $unique, 'product_id' => $newcomerId, 'type' => 7], 'suk');
|
||||
//平台商品sku unique
|
||||
$productUnique = $skuValueServices->value(['suk' => $suk, 'product_id' => $product_id, 'type' => 0], 'unique');
|
||||
/** @var StoreProductServices $services */
|
||||
$services = app()->make(StoreProductServices::class);
|
||||
//减去普通商品库存
|
||||
$res = $services->incProductStock($num, $product_id, (string)$productUnique);
|
||||
} else {
|
||||
$res = false;
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 下单|加入购物车验证秒杀商品库存
|
||||
* @param int $uid
|
||||
* @param int $newcomerId
|
||||
* @param int $cartNum
|
||||
* @param string $unique
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function checkNewcomerStock(int $uid, int $newcomerId, int $cartNum = 1, string $unique = '')
|
||||
{
|
||||
if (!$this->checkUserNewcomer($uid)) {
|
||||
throw new ValidateException('您已无法享受新人专享价');
|
||||
}
|
||||
/** @var StoreProductAttrValueServices $attrValueServices */
|
||||
$attrValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
if ($unique == '') {
|
||||
$unique = $attrValueServices->value(['product_id' => $newcomerId, 'type' => 7], 'unique');
|
||||
}
|
||||
//检查商品活动状态
|
||||
$newcomerInfo = $this->getInfo($newcomerId);
|
||||
if (!$newcomerInfo) {
|
||||
throw new ValidateException('该活动已下架');
|
||||
}
|
||||
$attrInfo = $attrValueServices->getOne(['product_id' => $newcomerId, 'unique' => $unique, 'type' => 7]);
|
||||
if (!$attrInfo || $attrInfo['product_id'] != $newcomerId) {
|
||||
throw new ValidateException('请选择有效的商品属性');
|
||||
}
|
||||
$suk = $attrInfo['suk'];
|
||||
$productAttrInfo = $attrValueServices->getOne(['suk' => $suk, 'product_id' => $newcomerInfo['product_id'], 'type' => 0]);
|
||||
if (!$productAttrInfo) {
|
||||
throw new ValidateException('请选择有效的商品属性');
|
||||
}
|
||||
//库存要验证愿商品库存
|
||||
if ($cartNum > $productAttrInfo['stock']) {
|
||||
throw new ValidateException('该商品库存不足' . $cartNum);
|
||||
}
|
||||
return [$attrInfo, $unique, $newcomerInfo];
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证用户是否可以享受首单优惠
|
||||
* @param int $uid
|
||||
* @param $userInfo
|
||||
* @return array
|
||||
*/
|
||||
public function checkUserFirstDiscount(int $uid, $userInfo = [])
|
||||
{
|
||||
if (!$uid) {
|
||||
return [];
|
||||
}
|
||||
//开启新人礼
|
||||
if (!sys_config('newcomer_status')) {
|
||||
return [];
|
||||
}
|
||||
//开启首单优惠
|
||||
if (!sys_config('first_order_status')) {
|
||||
return [];
|
||||
}
|
||||
if (!$userInfo) {
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$userInfo = $userServices->getUserInfo($uid);
|
||||
if (!$userInfo) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
if (isset($userInfo['is_first_order']) && $userInfo['is_first_order'] != 0) {
|
||||
return [];
|
||||
}
|
||||
$timeStatus = sys_config('newcomer_limit_status', 1);
|
||||
if ($timeStatus) {//设置限时,且超过时间不再享受
|
||||
$time = sys_config('newcomer_limit_time');
|
||||
if ($time) {
|
||||
$time = (int)bcsub((string)time(), (string)bcmul((string)$time, '86400'));
|
||||
if ($time > $userInfo['add_time']) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
/** @var StoreOrderServices $storeOrderServices */
|
||||
$storeOrderServices = app()->make(StoreOrderServices::class);
|
||||
$count = $storeOrderServices->getCount([['type', 'not in', [7]], ['uid', '=', $uid], ['paid', '=', 1]]);
|
||||
if ($count) {//有过订单
|
||||
return [];
|
||||
}
|
||||
$discount = sys_config('first_order_discount', 100);
|
||||
$discount_limit = sys_config('first_order_discount_limit', 0);
|
||||
return [$discount, $discount_limit];
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证用户是否可以购买新人专享
|
||||
* @param int $uid
|
||||
* @param $userInfo
|
||||
* @return bool
|
||||
*/
|
||||
public function checkUserNewcomer(int $uid, $userInfo = [])
|
||||
{
|
||||
if (!$uid) {
|
||||
return false;
|
||||
}
|
||||
//开启新人礼
|
||||
if (!sys_config('newcomer_status')) {
|
||||
return false;
|
||||
}
|
||||
//开启新人专享
|
||||
if (!sys_config('register_price_status')) {
|
||||
return false;
|
||||
}
|
||||
if (!$userInfo) {
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$userInfo = $userServices->getUserCacheInfo($uid);
|
||||
if (!$userInfo) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (isset($userInfo['is_newcomer']) && $userInfo['is_newcomer'] != 0) {
|
||||
return false;
|
||||
}
|
||||
$timeStatus = sys_config('newcomer_limit_status', 1);
|
||||
if ($timeStatus) {//设置限时,且超过时间不再享受
|
||||
$time = sys_config('newcomer_limit_time');
|
||||
if ($time) {
|
||||
$time = (int)bcsub((string)time(), (string)bcmul((string)$time, '86400'));
|
||||
if ($time > $userInfo['add_time']) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
/** @var StoreOrderServices $orderServices */
|
||||
$orderServices = app()->make(StoreOrderServices::class);
|
||||
$count = $orderServices->count(['uid' => $uid, 'type' => 7, 'paid' => 1]);
|
||||
if ($count) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户会员卡激活状态
|
||||
* @param int $uid
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function setUserLevel(int $uid)
|
||||
{
|
||||
if (!$uid) {
|
||||
return false;
|
||||
}
|
||||
//开启会员卡 且不需要激活 直接设置为已激活状态
|
||||
if (sys_config('member_func_status') && !sys_config('level_activate_status')) {
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
return $userServices->update($uid, ['level_status' => 1]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户注册设置:首单优惠、新人专享是否可用 -1:不可用 0:未使用 1:已使用
|
||||
* @param int $uid
|
||||
* @return false|mixed
|
||||
*/
|
||||
public function setUserNewcomer(int $uid)
|
||||
{
|
||||
if (!$uid) {
|
||||
return false;
|
||||
}
|
||||
//是否开启新人礼
|
||||
$newcomer_status = sys_config('newcomer_status');
|
||||
$update = [];
|
||||
if ($newcomer_status) {
|
||||
//开启首单优惠
|
||||
$first_order = sys_config('first_order_status');
|
||||
$update['is_first_order'] = $first_order ? 0 : -1;
|
||||
//开启新人专享
|
||||
$is_newcomer = sys_config('register_price_status');
|
||||
$update['is_newcomer'] = $is_newcomer ? 0 : -1;
|
||||
} else {//不可用,数据记录已使用
|
||||
$update = ['is_first_order' => -1, 'is_newcomer' => -1];
|
||||
}
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
return $userServices->update($uid, $update);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下单修改用户首单优惠
|
||||
* @param int $uid
|
||||
* @param $orderInfo
|
||||
* @return bool
|
||||
*/
|
||||
public function updateUserNewcomer(int $uid, $orderInfo)
|
||||
{
|
||||
if (!$uid || !$orderInfo) {
|
||||
return false;
|
||||
}
|
||||
$update = [];
|
||||
//享受首单优惠
|
||||
if (isset($orderInfo['first_order_price']) && $orderInfo['first_order_price'] > 0) {
|
||||
$update['is_first_order'] = 1;
|
||||
}
|
||||
//新人专享
|
||||
if (isset($orderInfo['type']) && $orderInfo['type'] == 7) {
|
||||
$update['is_newcomer'] = 1;
|
||||
}
|
||||
if ($update) {
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$userServices->update($uid, $update);
|
||||
$userServices->cacheTag()->clear();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取新人专享商品
|
||||
* @param int $uid
|
||||
* @param array $where
|
||||
* @param int $limit
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getDiyNewcomerList(int $uid = 0, array $where = [], int $limit = 0)
|
||||
{
|
||||
$newcomer_products = $newcomer_integral = $newcomer_coupon = [];
|
||||
if ($uid) {//验证权限
|
||||
//验证用户是否享受过新人礼
|
||||
if (!$this->checkUserNewcomer($uid)) {
|
||||
return compact('newcomer_products', 'newcomer_integral', 'newcomer_coupon');
|
||||
}
|
||||
} else {//验证是否开启 无登录:如果开启新人礼默认要展示
|
||||
//开启新人礼
|
||||
if (!sys_config('newcomer_status')) {
|
||||
return compact('newcomer_products', 'newcomer_integral', 'newcomer_coupon');
|
||||
}
|
||||
}
|
||||
$data = SystemConfigService::more([
|
||||
'register_integral_status',
|
||||
'register_give_integral',
|
||||
'register_coupon_status',
|
||||
'register_give_coupon'
|
||||
]);
|
||||
$ids = $data['register_give_coupon'] ?? [];
|
||||
$newcomer_coupon = [];
|
||||
if ($data['register_coupon_status'] && $ids) {
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
if ($uid) {//查询之前赠送他的
|
||||
/** @var StoreCouponUserServices $couponServices */
|
||||
$couponServices = app()->make(StoreCouponUserServices::class);
|
||||
$coupon = $couponServices->getList(['cid' => $ids, 'uid' => $uid], '*', ['issue'], $page, $limit);
|
||||
if ($coupon) $coupon = $couponServices->tidyCouponList($coupon);
|
||||
} else {
|
||||
/** @var StoreCouponIssueServices $couponServices */
|
||||
$couponServices = app()->make(StoreCouponIssueServices::class);
|
||||
$coupon = $couponServices->getList(['id' => $ids], $page, $limit);
|
||||
}
|
||||
$newcomer_coupon = $coupon;
|
||||
}
|
||||
$newcomer_integral = $data['register_integral_status'] ? $data['register_give_integral'] : 0;
|
||||
//开启新人专享
|
||||
if (sys_config('register_price_status')) {
|
||||
$newcomer_products = $this->getCustomerProduct($where, 'id,type,product_id,relation_id,product_type,price', ['product' => function ($query) {
|
||||
$query->field('id,image,store_name,stock,sales,ot_price');
|
||||
}]);
|
||||
}
|
||||
return compact('newcomer_products', 'newcomer_integral', 'newcomer_coupon');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\activity\promotions;
|
||||
|
||||
|
||||
use app\dao\activity\promotions\StorePromotionsAuxiliaryDao;
|
||||
use app\services\product\sku\StoreProductAttrValueServices;
|
||||
use app\services\BaseServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* 优惠活动辅助表
|
||||
* Class StorePromotionsAuxiliaryServices
|
||||
* @package app\services\activity\promotions
|
||||
* @mixin StorePromotionsAuxiliaryDao
|
||||
*/
|
||||
class StorePromotionsAuxiliaryServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var StorePromotionsAuxiliaryDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StorePromotionsAuxiliaryDao $dao;
|
||||
|
||||
/**
|
||||
* 优惠活动关联保存
|
||||
* @param int $promotionsId
|
||||
* @param int $type
|
||||
* @param array $promotionsAuxiliaryData
|
||||
* @param array $couponData
|
||||
* @param array $giveProductData
|
||||
* @return bool
|
||||
*/
|
||||
public function savePromotionsRelation(int $promotionsId, int $type, array $promotionsAuxiliaryData, array $couponData = [], array $giveProductData = [], bool $isAttr = true)
|
||||
{
|
||||
$this->dao->delete(['promotions_id' => $promotionsId]);
|
||||
if ($promotionsAuxiliaryData) $this->savePromotionsProducts($promotionsId, $type, $promotionsAuxiliaryData, $isAttr);
|
||||
if ($couponData) $this->savePromotionsGiveCoupon($promotionsId, $couponData);
|
||||
if ($giveProductData) $this->savePromotionsGiveProducts($promotionsId, $giveProductData);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置活动关联商品
|
||||
* @param int $promotionsId
|
||||
* @param int $type
|
||||
* @param array $productIds
|
||||
* @return bool
|
||||
*/
|
||||
public function savePromotionsProducts(int $promotionsId, int $type, array $promotionsAuxiliaryData, bool $isAttr = true)
|
||||
{
|
||||
if ($promotionsAuxiliaryData) {
|
||||
$data = [];
|
||||
$unitData = ['type' => 1, 'promotions_id' => $promotionsId, 'product_partake_type' => $type];
|
||||
switch ($type) {
|
||||
case 1://所有商品
|
||||
$data[] = $unitData;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
if ($isAttr) {
|
||||
$productIds = array_column($promotionsAuxiliaryData, 'product_id');
|
||||
$promotionsAuxiliaryData = array_combine($productIds, $promotionsAuxiliaryData);
|
||||
/** @var StoreProductAttrValueServices $skuValueServices */
|
||||
$skuValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
foreach ($productIds as $productId) {
|
||||
$unique = $promotionsAuxiliaryData[$productId]['unique'] ?? [];
|
||||
$skuCount = $skuValueServices->count(['product_id' => $productId, 'type' => 0]);
|
||||
$unitData['product_id'] = $productId;
|
||||
$unitData['is_all'] = count($unique) >= $skuCount ? 1 : 0;
|
||||
$unitData['unique'] = implode(',', $unique);
|
||||
$data[] = $unitData;
|
||||
}
|
||||
} else {
|
||||
$productIds = $promotionsAuxiliaryData['product_id'] ?? [];
|
||||
foreach ($productIds as $productId) {
|
||||
$unitData['product_id'] = $productId;
|
||||
$data[] = $unitData;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4://品牌
|
||||
$brandIds = $promotionsAuxiliaryData['brand_id'] ?? [];
|
||||
if ($brandIds) {
|
||||
foreach ($brandIds as $id) {
|
||||
$unitData['brand_id'] = $id;
|
||||
$data[] = $unitData;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 5://标签
|
||||
$storeLabelIds = $promotionsAuxiliaryData['store_label_id'] ?? [];
|
||||
if ($storeLabelIds) {
|
||||
foreach ($storeLabelIds as $id) {
|
||||
$unitData['store_label_id'] = $id;
|
||||
$data[] = $unitData;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ($data) $this->dao->saveAll($data);
|
||||
$this->setPromotionsAuxiliaryCache($promotionsId, $data);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置活动关联赠送优惠券
|
||||
* @param int $promotionsId
|
||||
* @param array $couponData
|
||||
* @return bool
|
||||
*/
|
||||
public function savePromotionsGiveCoupon(int $promotionsId, array $couponData)
|
||||
{
|
||||
if ($couponData) {
|
||||
$data = [];
|
||||
$couponIds = array_column($couponData, 'give_coupon_id');
|
||||
$couponData = array_combine($couponIds, $couponData);
|
||||
foreach ($couponIds as $couponId) {
|
||||
$data[] = [
|
||||
'type' => 2,
|
||||
'promotions_id' => $promotionsId,
|
||||
'coupon_id' => $couponId,
|
||||
'limit_num' => $couponData[$couponId]['give_coupon_num'] ?? 0,
|
||||
'surplus_num' => $couponData[$couponId]['give_coupon_num'] ?? 0
|
||||
];
|
||||
}
|
||||
$this->dao->saveAll($data);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置活动关联赠送商品
|
||||
* @param int $promotionsId
|
||||
* @param array $giveProductData
|
||||
* @return bool
|
||||
*/
|
||||
public function savePromotionsGiveProducts(int $promotionsId, array $giveProductData)
|
||||
{
|
||||
if ($giveProductData) {
|
||||
$data = [];
|
||||
foreach ($giveProductData as $product) {
|
||||
$data[] = [
|
||||
'type' => 3,
|
||||
'promotions_id' => $promotionsId,
|
||||
'product_id' => $product['give_product_id'],
|
||||
'limit_num' => $product['give_product_num'] ?? 0,
|
||||
'surplus_num' => $product['give_product_num'] ?? 0,
|
||||
'unique' => $product['unique'] ?? ''
|
||||
];
|
||||
}
|
||||
$this->dao->saveAll($data);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 优惠活动关联赠品限量处理
|
||||
* @param array $promotions_id
|
||||
* @param int $type
|
||||
* @param int $id
|
||||
* @param bool $is_dec
|
||||
* @param string $unique
|
||||
* @param int $num
|
||||
* @return bool
|
||||
*/
|
||||
public function updateLimit(array $promotions_id, int $type, int $id, bool $is_dec = true, string $unique = '', int $num = 1)
|
||||
{
|
||||
if (!$promotions_id) return true;
|
||||
$where = ['promotions_id' => $promotions_id, 'type' => $type];
|
||||
if ($type == 2) {
|
||||
$where['coupon_id'] = $id;
|
||||
} else {
|
||||
$where['product_id'] = $id;
|
||||
$where['unique'] = $unique;
|
||||
}
|
||||
$info = $this->dao->get($where);
|
||||
if ($info) {
|
||||
if ($is_dec) {
|
||||
if ($info['surplus_num'] < $num) {
|
||||
$surplus_num = 0;
|
||||
} else {
|
||||
$surplus_num = bcsub((string)$info['surplus_num'], (string)$num, 0);
|
||||
}
|
||||
} else {
|
||||
$surplus_num = bcadd((string)$info['surplus_num'], (string)$num, 0);
|
||||
}
|
||||
|
||||
$this->dao->update($info['id'], ['surplus_num' => $surplus_num]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置优惠活动关联缓存
|
||||
* @param int $promotions_id
|
||||
* @param array $data
|
||||
* @param int $product_partake_type
|
||||
* @return array
|
||||
*/
|
||||
public function setPromotionsAuxiliaryCache(int $promotions_id, array $data, int $product_partake_type = 1)
|
||||
{
|
||||
$key = 'cache_promotions_auxiliary_' . $promotions_id;
|
||||
$cacheData = [];
|
||||
if ($data) {
|
||||
switch ($product_partake_type) {
|
||||
case 1://所有商品
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
$cacheData = array_unique(array_column($data, 'product_id'));
|
||||
break;
|
||||
case 4://品牌
|
||||
$cacheData = array_unique(array_column($data, 'brand_id'));
|
||||
break;
|
||||
case 5://标签
|
||||
$cacheData = array_unique(array_column($data, 'store_label_id'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->dao->cacheHander()->delete($key);
|
||||
$this->dao->cacheTag()->set($key, $cacheData);
|
||||
return $cacheData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新缓存
|
||||
* @param int $promotions_id
|
||||
* @param string $key
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function updatePromotionsAuxiliaryCache(int $promotions_id)
|
||||
{
|
||||
$data = $this->dao->getList(['promotions_id' => $promotions_id, 'type' => 1]);
|
||||
$cacheData = [];
|
||||
if ($data) {
|
||||
$product_partake_type = $data[0]['product_partake_type'] ?? 0;
|
||||
$cacheData = $this->setPromotionsAuxiliaryCache($promotions_id, $data, $product_partake_type);
|
||||
}
|
||||
return $cacheData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商品关联缓存
|
||||
* @param int $product_id
|
||||
* @param array $type
|
||||
* @param bool $isCache
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getPromotionsAuxiliaryCache(int $promotions_id, bool $isCache = false)
|
||||
{
|
||||
$key = 'cache_promotions_auxiliary_' . $promotions_id;
|
||||
$data = $this->dao->cacheHander()->get($key);
|
||||
if (!$data || $isCache) {
|
||||
$data = $this->updatePromotionsAuxiliaryCache($promotions_id);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
2138
app/services/activity/promotions/StorePromotionsServices.php
Normal file
2138
app/services/activity/promotions/StorePromotionsServices.php
Normal file
File diff suppressed because it is too large
Load Diff
886
app/services/activity/seckill/StoreSeckillServices.php
Normal file
886
app/services/activity/seckill/StoreSeckillServices.php
Normal file
@@ -0,0 +1,886 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\seckill;
|
||||
|
||||
|
||||
use app\services\activity\StoreActivityServices;
|
||||
use app\services\BaseServices;
|
||||
use app\dao\activity\seckill\StoreSeckillDao;
|
||||
use app\services\diy\DiyServices;
|
||||
use app\services\order\StoreOrderServices;
|
||||
use app\services\other\QrcodeServices;
|
||||
use app\services\product\ensure\StoreProductEnsureServices;
|
||||
use app\services\product\label\StoreProductLabelServices;
|
||||
use app\services\product\product\StoreDescriptionServices;
|
||||
use app\services\user\UserRelationServices;
|
||||
use app\services\product\product\StoreProductReplyServices;
|
||||
use app\services\product\product\StoreProductServices;
|
||||
use app\services\product\sku\StoreProductAttrServices;
|
||||
use app\services\product\sku\StoreProductAttrValueServices;
|
||||
use app\jobs\product\ProductLogJob;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use crmeb\services\CacheService;
|
||||
use crmeb\services\GroupDataService;
|
||||
use crmeb\services\SystemConfigService;
|
||||
use crmeb\traits\OptionTrait;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
/**
|
||||
* Class StoreSeckillServices
|
||||
* @package app\services\activity\seckill
|
||||
* @method getSeckillIdsArray(array $ids, array $field)
|
||||
* @mixin StoreSeckillDao
|
||||
*/
|
||||
class StoreSeckillServices extends BaseServices
|
||||
{
|
||||
use OptionTrait;
|
||||
|
||||
const OPOXMWTJ = 'k8kkOJ';
|
||||
|
||||
/**
|
||||
* 商品活动类型
|
||||
*/
|
||||
const TYPE = 1;
|
||||
|
||||
/**
|
||||
* @var StoreSeckillDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreSeckillDao $dao;
|
||||
|
||||
/**
|
||||
* @param array $productIds
|
||||
* @return array
|
||||
* @author 等风来
|
||||
* @email 136327134@qq.com
|
||||
* @date 2022/11/14
|
||||
*/
|
||||
public function getSeckillIdsArrayCache(array $productIds)
|
||||
{
|
||||
$list = $this->dao->cacheList();
|
||||
if (!$list) {
|
||||
return $this->dao->getSeckillIdsArray($productIds, ['id', 'time_id', 'product_id']);
|
||||
} else {
|
||||
$seckill = [];
|
||||
$time = time();
|
||||
foreach ($list as $item) {
|
||||
if ($item['is_del'] == 0 && $item['status'] == 1 && $item['start_time'] <= $time && $item['stop_time'] >= ($time - 86400) && in_array($item['product_id'], $productIds)) {
|
||||
$seckill[] = [
|
||||
'id' => $item['id'],
|
||||
'time_id' => $item['time_id'],
|
||||
'product_id' => $item['product_id'],
|
||||
];
|
||||
}
|
||||
}
|
||||
return $seckill;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取秒杀活动数量
|
||||
* @param array $where 查询条件
|
||||
* @return int
|
||||
*/
|
||||
public function getCount(array $where)
|
||||
{
|
||||
return $this->dao->count($where);
|
||||
}
|
||||
|
||||
/**
|
||||
* 秒杀是否存在
|
||||
* @param int $id
|
||||
* @param string $field
|
||||
* @return array|int|\think\Model
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getSeckillCount(int $id = 0, string $field = 'time_id')
|
||||
{
|
||||
$where = [];
|
||||
$where[] = ['is_del', '=', 0];
|
||||
$where[] = ['status', '=', 1];
|
||||
$config = [];
|
||||
$currentHour = date('Hi');
|
||||
/** @var StoreSeckillTimeServices $storeSeckillTimeServices */
|
||||
$storeSeckillTimeServices = app()->make(StoreSeckillTimeServices::class);
|
||||
if ($id) {
|
||||
$time = time();
|
||||
$where[] = ['id', '=', $id];
|
||||
$where[] = ['start_time', '<=', $time];
|
||||
$where[] = ['stop_time', '>=', $time - 86400];
|
||||
$seckill_one = $this->dao->getOne($where, $field);
|
||||
if (!$seckill_one) {
|
||||
throw new ValidateException('活动已结束');
|
||||
}
|
||||
$time_id = $seckill_one['time_id'] ?? [];
|
||||
if ($time_id) {
|
||||
$time_id = is_string($time_id) ? explode(',', $time_id) : $time_id;
|
||||
$timeList = $storeSeckillTimeServices->getList(['id' => $time_id, 'status' => 1]);
|
||||
foreach ($timeList as $value) {
|
||||
$value['start_time'] = $start = str_replace(':', '', $value['start_time']);
|
||||
$value['end_time'] = $end = str_replace(':', '', $value['end_time']);
|
||||
if ($currentHour >= $start && $currentHour < $end) {
|
||||
$config = $value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$config) {
|
||||
throw new ValidateException('活动已结束');
|
||||
}
|
||||
//获取秒杀商品状态
|
||||
if ($config['start_time'] <= $currentHour && $config['end_time'] > $currentHour) {
|
||||
return $seckill_one;
|
||||
} else if ($config['start_time'] > $currentHour) {
|
||||
throw new ValidateException('活动未开始');
|
||||
} else {
|
||||
throw new ValidateException('活动已结束');
|
||||
}
|
||||
} else {
|
||||
$timeList = $storeSeckillTimeServices->getList(['status' => 1]);
|
||||
foreach ($timeList as $value) {
|
||||
$start = str_replace(':', '', $value['start_time']);
|
||||
$end = str_replace(':', '', $value['end_time']);
|
||||
if ($currentHour >= $start && $currentHour < $end) {
|
||||
$config = $value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$config) return 0;
|
||||
|
||||
//获取秒杀商品状态
|
||||
$start = substr_replace($config['start_time'], ':', 2, 0);
|
||||
$end = substr_replace($config['end_time'], ':', 2, 0);
|
||||
|
||||
$startTime = strtotime(date('Y-m-d') . ' ' . $start);
|
||||
$stopTime = strtotime(date('Y-m-d') . ' ' . $end);
|
||||
|
||||
$where[] = ['start_time', '<', $startTime];
|
||||
$where[] = ['stop_time', '>', $stopTime];
|
||||
return $this->dao->getCount($where);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 保存数据
|
||||
* @param int $id
|
||||
* @param array $data
|
||||
*/
|
||||
public function saveData(int $id, array $data)
|
||||
{
|
||||
/** @var StoreProductServices $storeProductServices */
|
||||
$storeProductServices = app()->make(StoreProductServices::class);
|
||||
$productInfo = $storeProductServices->getOne(['is_del' => 0, 'is_verify' => 1, 'id' => $data['product_id']]);
|
||||
if (!$productInfo) {
|
||||
throw new AdminException('原商品已移入回收站');
|
||||
}
|
||||
if ($productInfo['is_vip_product']) {
|
||||
throw new AdminException("【{$productInfo["store_name"]}】是svip专享");
|
||||
}
|
||||
if ($productInfo['is_presale_product']) {
|
||||
throw new AdminException("【{$productInfo["store_name"]}】是预售商品");
|
||||
}
|
||||
$data['product_type'] = $productInfo['product_type'];
|
||||
$data['type'] = $productInfo['type'] ?? 0;
|
||||
$data['relation_id'] = $productInfo['relation_id'] ?? 0;
|
||||
$custom_form = $productInfo['custom_form'] ?? [];
|
||||
$data['custom_form'] = is_array($custom_form) ? json_encode($custom_form) : $custom_form;
|
||||
$data['system_form_id'] = $productInfo['system_form_id'] ?? 0;
|
||||
$store_label_id = $productInfo['store_label_id'] ?? [];
|
||||
$data['store_label_id'] = is_array($store_label_id) ? implode(',', $store_label_id) : $store_label_id;
|
||||
$ensure_id = $productInfo['ensure_id'] ?? [];
|
||||
$data['ensure_id'] = is_array($ensure_id) ? implode(',', $ensure_id) : $ensure_id;
|
||||
$specs = $productInfo['specs'] ?? [];
|
||||
$data['specs'] = is_array($specs) ? json_encode($specs) : $specs;
|
||||
if (in_array($data['product_type'], [1, 2, 3])) {
|
||||
$data['freight'] = 2;
|
||||
$data['temp_id'] = 0;
|
||||
$data['postage'] = 0;
|
||||
} else {
|
||||
if ($data['freight'] == 1) {
|
||||
$data['temp_id'] = 0;
|
||||
$data['postage'] = 0;
|
||||
} elseif ($data['freight'] == 2) {
|
||||
$data['temp_id'] = 0;
|
||||
} elseif ($data['freight'] == 3) {
|
||||
$data['postage'] = 0;
|
||||
}
|
||||
if ($data['freight'] == 2 && !$data['postage']) {
|
||||
throw new AdminException('请设置运费金额');
|
||||
}
|
||||
if ($data['freight'] == 3 && !$data['temp_id']) {
|
||||
throw new AdminException('请选择运费模版');
|
||||
}
|
||||
}
|
||||
$description = $data['description'];
|
||||
$detail = $data['attrs'];
|
||||
$items = $data['items'];
|
||||
$data['start_time'] = strtotime($data['section_time'][0]);
|
||||
$data['stop_time'] = strtotime($data['section_time'][1]);
|
||||
$data['image'] = $data['images'][0] ?? '';
|
||||
$data['images'] = json_encode($data['images']);
|
||||
$data['price'] = min(array_column($detail, 'price'));
|
||||
$data['ot_price'] = min(array_column($detail, 'ot_price'));
|
||||
$data['quota'] = $data['quota_show'] = array_sum(array_column($detail, 'quota'));
|
||||
if ($data['quota'] > $productInfo['stock']) {
|
||||
throw new AdminException('限量不能超过商品库存');
|
||||
}
|
||||
$data['stock'] = array_sum(array_column($detail, 'stock'));
|
||||
unset($data['section_time'], $data['description'], $data['attrs'], $data['items']);
|
||||
/** @var StoreDescriptionServices $storeDescriptionServices */
|
||||
$storeDescriptionServices = app()->make(StoreDescriptionServices::class);
|
||||
/** @var StoreProductAttrServices $storeProductAttrServices */
|
||||
$storeProductAttrServices = app()->make(StoreProductAttrServices::class);
|
||||
$id = $this->transaction(function () use ($id, $data, $description, $detail, $items, $storeDescriptionServices, $storeProductAttrServices) {
|
||||
if ($id) {
|
||||
$res = $this->dao->update($id, $data);
|
||||
if (!$res) throw new AdminException('修改失败');
|
||||
} else {
|
||||
$data['add_time'] = time();
|
||||
$res = $this->dao->save($data);
|
||||
if (!$res) throw new AdminException('添加失败');
|
||||
$id = (int)$res->id;
|
||||
}
|
||||
$storeDescriptionServices->saveDescription((int)$id, $description, 1);
|
||||
$storeProductAttrServices->setItem('store_product_id', $data['product_id']);
|
||||
$skuList = $storeProductAttrServices->validateProductAttr($items, $detail, (int)$id, 1);
|
||||
$storeProductAttrServices->reset();
|
||||
$valueGroup = $storeProductAttrServices->saveProductAttr($skuList, (int)$id, 1);
|
||||
|
||||
$res = true;
|
||||
foreach ($valueGroup as $item) {
|
||||
if ($item['quota_show']) $res = $res && CacheService::setStock($item['unique'], (int)$item['quota_show']);
|
||||
}
|
||||
if (!$res) {
|
||||
throw new AdminException('占用库存失败');
|
||||
}
|
||||
|
||||
return $id;
|
||||
});
|
||||
$this->dao->cacheTag()->clear();
|
||||
//保存
|
||||
$seckill = $this->dao->get($id, ['*'], ['descriptions']);
|
||||
$this->dao->cacheUpdate($seckill->toArray());
|
||||
CacheService::redisHandler('product_attr')->clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $timeId
|
||||
* @param int $id
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* @author 等风来
|
||||
* @email 136327134@qq.com
|
||||
* @date 2022/11/4
|
||||
*/
|
||||
public function createSeckillListCache(int $timeId, int $id = 0)
|
||||
{
|
||||
//创建数据缓存
|
||||
$list = $this->dao->getListByTime($timeId);
|
||||
$timeId = (string)$timeId;
|
||||
if ($id) {
|
||||
$this->dao->cacheUpdateList($list, $timeId);
|
||||
} else {
|
||||
$this->dao->cacheCreate($list, $timeId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function systemPage(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getList($where, $page, $limit);
|
||||
$count = $this->dao->count($where);
|
||||
$activityIds = array_column($list, 'activity_id');
|
||||
$activityInfos = app()->make(StoreActivityServices::class)->getColumn(['id' => $activityIds], 'id,name', 'id');
|
||||
foreach ($list as &$item) {
|
||||
$item['store_name'] = $item['title'];
|
||||
if ($item['status']) {
|
||||
if ($item['start_time'] > time())
|
||||
$item['start_name'] = '未开始';
|
||||
else if (bcadd($item['stop_time'], '86400') < time())
|
||||
$item['start_name'] = '已结束';
|
||||
else if (bcadd($item['stop_time'], '86400') > time() && $item['start_time'] < time()) {
|
||||
$item['start_name'] = '进行中';
|
||||
}
|
||||
} else $item['start_name'] = '已结束';
|
||||
$end_time = $item['stop_time'] ? (date('Y-m-d', (int)$item['stop_time']) . ' 23:59:59') : '';
|
||||
$item['_stop_time'] = $end_time;
|
||||
$item['stop_status'] = $item['stop_time'] + 86400 < time() ? 1 : 0;
|
||||
$item['activity_name'] = $activityInfos[$item['activity_id']]['name'] ?? '';
|
||||
}
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取秒杀详情
|
||||
* @param int $id
|
||||
* @return array|\think\Model|null
|
||||
*/
|
||||
public function getInfo(int $id)
|
||||
{
|
||||
$info = $this->dao->get($id);
|
||||
if ($info) {
|
||||
if ($info['start_time'])
|
||||
$start_time = date('Y-m-d', (int)$info['start_time']);
|
||||
|
||||
if ($info['stop_time'])
|
||||
$stop_time = date('Y-m-d', (int)$info['stop_time']);
|
||||
if (isset($start_time) && isset($stop_time))
|
||||
$info['section_time'] = [$start_time, $stop_time];
|
||||
else
|
||||
$info['section_time'] = [];
|
||||
unset($info['start_time'], $info['stop_time']);
|
||||
$info['give_integral'] = intval($info['give_integral']);
|
||||
$info['price'] = floatval($info['price']);
|
||||
$info['ot_price'] = floatval($info['ot_price']);
|
||||
$info['postage'] = floatval($info['postage']);
|
||||
$info['cost'] = floatval($info['cost']);
|
||||
$info['weight'] = floatval($info['weight']);
|
||||
$info['volume'] = floatval($info['volume']);
|
||||
if (!$info['delivery_type']) {
|
||||
$info['delivery_type'] = [1];
|
||||
}
|
||||
if ($info['postage']) {
|
||||
$info['freight'] = 2;
|
||||
} elseif ($info['temp_id']) {
|
||||
$info['freight'] = 3;
|
||||
} else {
|
||||
$info['freight'] = 1;
|
||||
}
|
||||
/** @var StoreDescriptionServices $storeDescriptionServices */
|
||||
$storeDescriptionServices = app()->make(StoreDescriptionServices::class);
|
||||
$info['description'] = $storeDescriptionServices->getDescription(['product_id' => $id, 'type' => 1]);
|
||||
/** @var StoreProductAttrValueServices $storeProductAttrValueServices */
|
||||
$storeProductAttrValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
$info['attrs'] = $storeProductAttrValueServices->attrList($id, $info['product_id'], 1);
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param int $time
|
||||
* @return array|mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* @author 等风来
|
||||
* @email 136327134@qq.com
|
||||
* @date 2022/11/4
|
||||
*/
|
||||
public function getListByTimeCache(int $time)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$res = $this->dao->cacheList();
|
||||
|
||||
$list = [];
|
||||
$stime = time();
|
||||
$etime = $stime - 86400;
|
||||
foreach ($res as $value) {
|
||||
if (isset($value['is_del']) && $value['is_del'] == 0 && isset($value['start_time']) && $value['start_time'] <= $stime && isset($value['stop_time']) && $value['stop_time'] >= $etime && isset($value['status']) && isset($value['time_id']) && $value['status'] && $value['time_id'] == $time) {
|
||||
$list[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$newResList = array_slice($list, ($page - 1) * $limit, $limit);
|
||||
|
||||
if (!$newResList) {
|
||||
$newResList = $this->getListByTime($time);
|
||||
} else {
|
||||
foreach ($newResList as &$item) {
|
||||
if ($item['quota'] > 0) {
|
||||
$percent = (int)(($item['quota_show'] - $item['quota']) / $item['quota_show'] * 100);
|
||||
$item['percent'] = $percent;
|
||||
$item['stock'] = $item['quota'];
|
||||
} else {
|
||||
$item['percent'] = 100;
|
||||
$item['stock'] = 0;
|
||||
}
|
||||
$item['price'] = floatval($item['price']);
|
||||
$item['ot_price'] = floatval($item['ot_price']);
|
||||
}
|
||||
}
|
||||
|
||||
return $newResList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某个时间段的秒杀列表
|
||||
* @param int $time
|
||||
* @param int $limit
|
||||
* @return array
|
||||
* @throws \ReflectionException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getListByTime(int $time)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
/** @var StoreActivityServices $storeActivityServices */
|
||||
$storeActivityServices = app()->make(StoreActivityServices::class);
|
||||
$activityList = $storeActivityServices->getList(['time_id' => $time, 'type' => 1, 'status' => 1, 'is_del' => 0, 'activityTime' => true], 'id,image');
|
||||
$seckillInfo = [];
|
||||
if ($activityList) {
|
||||
$activityIds = array_column($activityList, 'id');
|
||||
$field = 'id,product_id,activity_id,title,image,price,ot_price,quota,quota_show,freight,stock,store_label_id';
|
||||
$seckillInfo = $this->dao->getListByTime($activityIds, [], $field, $page, $limit);
|
||||
if (count($seckillInfo)) {
|
||||
$activityList = array_combine($activityIds, $activityList);
|
||||
/** @var StoreProductLabelServices $storeProductLabelServices */
|
||||
$storeProductLabelServices = app()->make(StoreProductLabelServices::class);
|
||||
foreach ($seckillInfo as $key => &$item) {
|
||||
if ($item['quota'] > 0) {
|
||||
$percent = (float)sprintf("%.1f", (($item['quota_show'] - $item['quota']) / $item['quota_show'] * 100));
|
||||
$item['percent'] = $percent;
|
||||
$item['stock'] = $item['quota'];
|
||||
} else {
|
||||
$item['percent'] = 100;
|
||||
$item['stock'] = 0;
|
||||
}
|
||||
$item['price'] = floatval($item['price']);
|
||||
$item['ot_price'] = floatval($item['ot_price']);
|
||||
$item['discount_num'] = $item['ot_price'] ? (float)bcmul(bcdiv((string)$item['price'], (string)$item['ot_price'], 4), '10', 1) : 10;
|
||||
$item['activity_image'] = $activityList[$item['activity_id']]['image'] ?? '';
|
||||
$item['store_label'] = [];
|
||||
if ($item['store_label_id']) {
|
||||
$item['store_label'] = $storeProductLabelServices->getLabelCache($item['store_label_id'], ['id', 'label_name', 'style_type', 'color', 'bg_color', 'border_color', 'icon']);
|
||||
}
|
||||
/** @var StoreProductServices $storeProductServices */
|
||||
$storeProductServices = app()->make(StoreProductServices::class);
|
||||
$item['brand_name'] = $storeProductServices->productIdByBrandName((int)$item['product_id']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $seckillInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取秒杀详情
|
||||
* @param int $id
|
||||
* @return mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function seckillDetail(int $uid, int $id)
|
||||
{
|
||||
//读取秒杀商品缓存信息
|
||||
$storeInfo = $this->dao->cacheRemember($id, function () use ($id) {
|
||||
$storeInfo = $this->dao->getOne(['id' => $id], '*,title as store_name', ['descriptions']);
|
||||
if (!$storeInfo) {
|
||||
throw new ValidateException('商品不存在');
|
||||
} else {
|
||||
$storeInfo = $storeInfo->toArray();
|
||||
}
|
||||
return $storeInfo;
|
||||
});
|
||||
$storeInfo['activity'] = [];
|
||||
if ($storeInfo['activity_id']) {
|
||||
$activityServices = app()->make(StoreActivityServices::class);
|
||||
$storeInfo['activity'] = $activityServices->getInfo((int)$storeInfo['activity_id'], ['id', 'start_day', 'end_day', 'time_id']);
|
||||
}
|
||||
/** @var DiyServices $diyServices */
|
||||
$diyServices = app()->make(DiyServices::class);
|
||||
$infoDiy = $diyServices->getProductDetailDiy();
|
||||
//diy控制参数
|
||||
if (!isset($infoDiy['showService']) || in_array(3, $infoDiy['showService'])) {
|
||||
$storeInfo['specs'] = [];
|
||||
}
|
||||
$configData = SystemConfigService::more(['site_url', 'routine_contact_type', 'site_name', 'share_qrcode', 'store_self_mention', 'store_func_status', 'product_poster_title']);
|
||||
$siteUrl = $configData['site_url'] ?? '';
|
||||
$storeInfo['image'] = set_file_url($storeInfo['image'], $siteUrl);
|
||||
$storeInfo['image_base'] = set_file_url($storeInfo['image'], $siteUrl);
|
||||
|
||||
//品牌名称
|
||||
/** @var StoreProductServices $storeProductServices */
|
||||
$storeProductServices = app()->make(StoreProductServices::class);
|
||||
|
||||
$productInfo = $storeProductServices->getCacheProductInfo((int)$storeInfo['product_id']);
|
||||
|
||||
$storeInfo['brand_name'] = $storeProductServices->productIdByBrandName((int)$storeInfo['product_id'], $productInfo);
|
||||
$delivery_type = $storeInfo['delivery_type'] ?? $productInfo['delivery_type'];
|
||||
$storeInfo['delivery_type'] = is_string($delivery_type) ? explode(',', $delivery_type) : $delivery_type;
|
||||
|
||||
/**
|
||||
* 判断配送方式
|
||||
*/
|
||||
$storeInfo['delivery_type'] = $storeProductServices->getDeliveryType($storeInfo['type'], $storeInfo['relation_id'], $storeInfo['delivery_type']);
|
||||
$storeInfo['total'] = $productInfo['sales'] + $productInfo['ficti'];
|
||||
$storeInfo['store_label'] = $storeInfo['ensure'] = [];
|
||||
if ($storeInfo['store_label_id']) {
|
||||
/** @var StoreProductLabelServices $storeProductLabelServices */
|
||||
$storeProductLabelServices = app()->make(StoreProductLabelServices::class);
|
||||
$storeInfo['store_label'] = $storeProductLabelServices->getLabelCache($storeInfo['store_label_id'], ['id', 'label_name', 'style_type', 'color', 'bg_color', 'border_color', 'icon']);
|
||||
}
|
||||
if ($storeInfo['ensure_id'] && isset($infoDiy['showService']) && in_array(2, $infoDiy['showService'])) {
|
||||
/** @var StoreProductEnsureServices $storeProductEnsureServices */
|
||||
$storeProductEnsureServices = app()->make(StoreProductEnsureServices::class);
|
||||
$storeInfo['ensure'] = $storeProductEnsureServices->getEnsurCache($storeInfo['ensure_id'], ['id', 'name', 'image', 'desc']);
|
||||
}
|
||||
$time = $this->getItem('time', '');
|
||||
$status = $this->getItem('status', '');
|
||||
$time_id = (int)$this->getItem('time_id', '');
|
||||
|
||||
/** @var QrcodeServices $qrcodeService */
|
||||
$qrcodeService = app()->make(QrcodeServices::class);
|
||||
if (($configData['share_qrcode'] ?? 0) && request()->isWechat()) {
|
||||
$storeInfo['code_base'] = $qrcodeService->getTemporaryQrcode('seckill-' . $id . '-' . $uid . '-' . $time . '-' . $status, $uid)->url;
|
||||
} else {
|
||||
$storeInfo['code_base'] = $qrcodeService->getWechatQrcodePath($id . '_product_seckill_detail_wap.jpg', '/pages/activity/goods_seckill_details/index?id=' . $id . '&spid=' . $uid . '&time=' . $time . '&status=' . $status);
|
||||
}
|
||||
|
||||
/** @var StoreOrderServices $storeOrderServices */
|
||||
$storeOrderServices = app()->make(StoreOrderServices::class);
|
||||
$data['buy_num'] = $storeOrderServices->getBuyCount($uid, 1, $id);
|
||||
|
||||
/** @var UserRelationServices $userRelationServices */
|
||||
$userRelationServices = app()->make(UserRelationServices::class);
|
||||
$storeInfo['userCollect'] = $userRelationServices->isProductRelationCache(['uid' => $uid, 'relation_id' => $storeInfo['product_id'], 'type' => 'collect', 'category' => UserRelationServices::CATEGORY_PRODUCT]);
|
||||
$storeInfo['userLike'] = 0;
|
||||
|
||||
$storeInfo['uid'] = $uid;
|
||||
if ($storeInfo['quota'] > 0) {
|
||||
$percent = (float)sprintf("%.1f", ($storeInfo['quota_show'] - $storeInfo['quota']) / $storeInfo['quota_show'] * 100);
|
||||
$storeInfo['percent'] = $percent;
|
||||
$storeInfo['stock'] = $storeInfo['quota'];
|
||||
} else {
|
||||
$storeInfo['percent'] = 100;
|
||||
$storeInfo['stock'] = 0;
|
||||
}
|
||||
|
||||
$storeInfo['last_time'] = 0;
|
||||
$time_id = $time_id ?: ($storeInfo['activity']['time_id'] ?? []);
|
||||
$storeInfo['status'] = (int)$storeInfo['status'];
|
||||
if ($time_id && $storeInfo['status'] == 1) {
|
||||
$time_id = is_string($time_id) ? explode(',', $time_id) : $time_id;
|
||||
/** @var StoreSeckillTimeServices $storeSeckillTimeServices */
|
||||
$storeSeckillTimeServices = app()->make(StoreSeckillTimeServices::class);
|
||||
$timeList = $storeSeckillTimeServices->getList(['id' => $time_id, 'status' => 1]);
|
||||
$config = [];
|
||||
$today = date('Y-m-d');
|
||||
$currentHour = date('Hi');
|
||||
if (count($timeList) <= 1) {
|
||||
$config = $timeList[0] ?? [];
|
||||
} else {
|
||||
foreach ($timeList as $value) {
|
||||
$start = str_replace(':', '', $value['start_time']);
|
||||
$end = str_replace(':', '', $value['end_time']);
|
||||
if ($currentHour >= $start && $currentHour < $end) {
|
||||
$config = $value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//获取秒杀商品状态
|
||||
if ($storeInfo['status'] == 1) {
|
||||
if ($config) {//正在进行中的
|
||||
$start = str_replace(':', '', $config['start_time']);
|
||||
$end = str_replace(':', '', $config['end_time']);
|
||||
if ($start <= $currentHour && $end > $currentHour) {
|
||||
$storeInfo['status'] = 1;
|
||||
$storeInfo['last_time'] = strtotime($today . ' ' . $config['end_time']);
|
||||
} else if ($start > $currentHour) {
|
||||
$storeInfo['status'] = 2;
|
||||
} else {
|
||||
$storeInfo['status'] = 0;
|
||||
}
|
||||
} else {
|
||||
$storeInfo['status'] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//商品详情
|
||||
$storeInfo['small_image'] = get_thumb_water($storeInfo['image']);
|
||||
$data['storeInfo'] = $storeInfo;
|
||||
$storeInfo['product_id'] = (int)$storeInfo['product_id'];
|
||||
$data['reply'] = [];
|
||||
$data['replyChance'] = $data['replyCount'] = 0;
|
||||
if (isset($infoDiy['showReply']) && $infoDiy['showReply']) {
|
||||
/** @var StoreProductReplyServices $storeProductReplyService */
|
||||
$storeProductReplyService = app()->make(StoreProductReplyServices::class);
|
||||
$reply = $storeProductReplyService->getRecProductReplyCache($storeInfo['product_id'], (int)($infoDiy['replyNum'] ?? 1));
|
||||
$data['reply'] = $reply ? get_thumb_water($reply, 'small', ['pics']) : [];
|
||||
[$replyCount, $goodReply, $replyChance] = $storeProductReplyService->getProductReplyData((int)$storeInfo['product_id']);
|
||||
$data['replyChance'] = $replyChance;
|
||||
$data['replyCount'] = $replyCount;
|
||||
}
|
||||
|
||||
/** @var StoreProductAttrServices $storeProductAttrServices */
|
||||
$storeProductAttrServices = app()->make(StoreProductAttrServices::class);
|
||||
[$productAttr, $productValue] = $storeProductAttrServices->getProductAttrDetailCache($id, $uid, 0, 1, $storeInfo['product_id'], $productInfo);
|
||||
$data['productAttr'] = $productAttr;
|
||||
$data['productValue'] = $productValue;
|
||||
$data['routine_contact_type'] = $configData['routine_contact_type'] ?? 0;
|
||||
$data['store_func_status'] = (int)($configData['store_func_status'] ?? 1);//门店是否开启
|
||||
$data['store_self_mention'] = $data['store_func_status'] ? (int)($configData['store_self_mention'] ?? 0) : 0;//门店自提是否开启
|
||||
$data['site_name'] = $configData['site_name'] ?? '';
|
||||
$data['share_qrcode'] = $configData['share_qrcode'] ?? 0;
|
||||
$data['product_poster_title'] = $configData['product_poster_title'] ?? '';
|
||||
//浏览记录
|
||||
ProductLogJob::dispatch(['visit', ['uid' => $uid, 'id' => $id, 'product_id' => $storeInfo['product_id']], 'seckill']);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改秒杀库存
|
||||
* @param int $num
|
||||
* @param int $seckillId
|
||||
* @param string $unique
|
||||
* @param int $store_id
|
||||
* @return bool
|
||||
*/
|
||||
public function decSeckillStock(int $num, int $seckillId, string $unique = '', int $store_id = 0)
|
||||
{
|
||||
return $this->transaction(function () use ($num, $seckillId, $unique) {
|
||||
$product_id = $this->dao->value(['id' => $seckillId], 'product_id');
|
||||
$res = false;
|
||||
if ($product_id) {
|
||||
if ($unique) {
|
||||
/** @var StoreProductAttrValueServices $skuValueServices */
|
||||
$skuValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
//减去秒杀商品的sku库存增加销量
|
||||
$res = false !== $skuValueServices->decProductAttrStock($seckillId, $unique, $num, 1);
|
||||
|
||||
//减去当前普通商品sku的库存增加销量
|
||||
//秒杀商品sku
|
||||
$suk = $skuValueServices->value(['unique' => $unique, 'product_id' => $seckillId, 'type' => 1], 'suk');
|
||||
//平台商品sku unique
|
||||
$productUnique = $skuValueServices->value(['suk' => $suk, 'product_id' => $product_id, 'type' => 0], 'unique');
|
||||
/** @var StoreProductServices $services */
|
||||
$services = app()->make(StoreProductServices::class);
|
||||
//减去普通商品库存
|
||||
$res = $res && $services->decProductStock($num, $product_id, (string)$productUnique);
|
||||
}
|
||||
//减去秒杀库存
|
||||
$res = $res && false !== $this->dao->decStockIncSales(['id' => $seckillId, 'type' => 1], $num);
|
||||
}
|
||||
//更新单个缓存
|
||||
$info = $this->dao->getOne(['id' => $seckillId], '*', ['descriptions']);
|
||||
if ($info) {
|
||||
$info = $info->toArray();
|
||||
$this->dao->cacheUpdate($info);
|
||||
}
|
||||
return $res;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 加库存减销量
|
||||
* @param int $num
|
||||
* @param int $seckillId
|
||||
* @param string $unique
|
||||
* @param int $store_id
|
||||
* @return bool
|
||||
*/
|
||||
public function incSeckillStock(int $num, int $seckillId, string $unique = '', int $store_id = 0)
|
||||
{
|
||||
return $this->transaction(function () use ($num, $seckillId, $unique) {
|
||||
$product_id = $this->dao->value(['id' => $seckillId], 'product_id');
|
||||
$res = false;
|
||||
if ($product_id) {
|
||||
if ($unique) {
|
||||
/** @var StoreProductAttrValueServices $skuValueServices */
|
||||
$skuValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
//减去秒杀商品的sku库存增加销量
|
||||
$res = false !== $skuValueServices->incProductAttrStock($seckillId, $unique, $num, 1);
|
||||
|
||||
//减去当前普通商品sku的库存增加销量
|
||||
//秒杀商品sku
|
||||
$suk = $skuValueServices->value(['unique' => $unique, 'product_id' => $seckillId, 'type' => 1], 'suk');
|
||||
//平台商品sku unique
|
||||
$productUnique = $skuValueServices->value(['suk' => $suk, 'product_id' => $product_id, 'type' => 0], 'unique');
|
||||
/** @var StoreProductServices $services */
|
||||
$services = app()->make(StoreProductServices::class);
|
||||
//减去普通商品库存
|
||||
$res = $res && $services->incProductStock($num, $product_id, (string)$productUnique);
|
||||
}
|
||||
//减去秒杀库存
|
||||
$res = $res && false !== $this->dao->incStockDecSales(['id' => $seckillId, 'type' => 1], $num);
|
||||
}
|
||||
//更新单个缓存
|
||||
$info = $this->dao->getOne(['id' => $seckillId], '*', ['descriptions']);
|
||||
if ($info) {
|
||||
$info = $info->toArray();
|
||||
$this->dao->cacheUpdate($info);
|
||||
}
|
||||
return $res;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 下单|加入购物车验证秒杀商品库存
|
||||
* @param int $uid
|
||||
* @param int $seckillId
|
||||
* @param int $cartNum
|
||||
* @param string $unique
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function checkSeckillStock(int $uid, int $seckillId, int $cartNum = 1, string $unique = '')
|
||||
{
|
||||
/** @var StoreProductAttrValueServices $attrValueServices */
|
||||
$attrValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
if ($unique == '') {
|
||||
$unique = $attrValueServices->value(['product_id' => $seckillId, 'type' => 1], 'unique');
|
||||
}
|
||||
//检查商品活动状态
|
||||
$storeSeckillinfo = $this->getSeckillCount($seckillId, '*,title as store_name');
|
||||
if (!$storeSeckillinfo) {
|
||||
throw new ValidateException('该活动已下架');
|
||||
}
|
||||
if ($storeSeckillinfo['once_num'] < $cartNum) {
|
||||
throw new ValidateException('每个订单限购' . $storeSeckillinfo['once_num'] . '件');
|
||||
}
|
||||
/** @var StoreOrderServices $orderServices */
|
||||
$orderServices = app()->make(StoreOrderServices::class);
|
||||
$userBuyCount = $orderServices->getBuyCount($uid, 1, $seckillId);
|
||||
if ($storeSeckillinfo['num'] < ($userBuyCount + $cartNum)) {
|
||||
throw new ValidateException('每人总共限购' . $storeSeckillinfo['num'] . '件');
|
||||
}
|
||||
if ($storeSeckillinfo['num'] < $cartNum) {
|
||||
throw new ValidateException('每人限购' . $storeSeckillinfo['num'] . '件');
|
||||
}
|
||||
$attrInfo = $attrValueServices->getOne(['product_id' => $seckillId, 'unique' => $unique, 'type' => 1]);
|
||||
if (!$attrInfo || $attrInfo['product_id'] != $seckillId) {
|
||||
throw new ValidateException('请选择有效的商品属性');
|
||||
}
|
||||
if ($cartNum > $attrInfo['quota']) {
|
||||
throw new ValidateException('该商品库存不足' . $cartNum);
|
||||
}
|
||||
return [$attrInfo, $unique, $storeSeckillinfo];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前的秒杀时间time
|
||||
* @return int|string
|
||||
*/
|
||||
public function getSeckillTime()
|
||||
{
|
||||
$seckillTime = GroupDataService::getData('routine_seckill_time') ?? [];
|
||||
$currentHour = (int)date('H');
|
||||
$time = 0;
|
||||
foreach ($seckillTime as $item) {
|
||||
$activityEndHour = (int)bcadd((string)$item['time'], (string)$item['continued'], 0);
|
||||
if ($currentHour >= $item['time'] && $currentHour < $activityEndHour) {
|
||||
$time = $item['id'];
|
||||
}
|
||||
}
|
||||
return $time;
|
||||
}
|
||||
|
||||
/**
|
||||
* 秒杀统计
|
||||
* @return array
|
||||
*/
|
||||
public function seckillStatistics($id)
|
||||
{
|
||||
/** @var StoreOrderServices $orderServices */
|
||||
$orderServices = app()->make(StoreOrderServices::class);
|
||||
$pay_count = $orderServices->getDistinctCount(['type' => 1, 'activity_id' => $id, 'paid' => 1, 'pid' => [0, -1]], 'uid');
|
||||
$order_count = $orderServices->getDistinctCount(['type' => 1, 'activity_id' => $id, 'pid' => [0, -1]], 'uid');
|
||||
$all_price = $orderServices->sum(['type' => 1, 'activity_id' => $id, 'paid' => 1, 'refund_type' => [0, 3], 'pid' => [0, -1]], 'pay_price');
|
||||
$seckillInfo = $this->dao->get($id);
|
||||
$pay_rate = $seckillInfo['quota'] . '/' . $seckillInfo['quota_show'];
|
||||
return compact('pay_count', 'order_count', 'all_price', 'pay_rate');
|
||||
}
|
||||
|
||||
/**
|
||||
* 秒杀参与人统计
|
||||
* @param $id
|
||||
* @param string $keyword
|
||||
* @return array
|
||||
*/
|
||||
public function seckillPeople($id, $keyword = '')
|
||||
{
|
||||
/** @var StoreOrderServices $orderServices */
|
||||
$orderServices = app()->make(StoreOrderServices::class);
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $orderServices->seckillPeople($id, $keyword, $page, $limit);
|
||||
$count = $orderServices->getDistinctCount([['paid', '=', 1], ['type', '=', 1], ['activity_id', '=', $id], ['pid', 'in', [0, -1]], ['real_name|uid|user_phone', 'like', '%' . $keyword . '%']], 'uid', false);
|
||||
foreach ($list as &$item) {
|
||||
$item['add_time'] = date('Y-m-d H:i:s', $item['add_time']);
|
||||
}
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 秒杀订单统计
|
||||
* @param $id
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function seckillOrder(int $id, array $where = [])
|
||||
{
|
||||
/** @var StoreOrderServices $orderServices */
|
||||
$orderServices = app()->make(StoreOrderServices::class);
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $orderServices->activityStatisticsOrder($id, 1, $where, $page, $limit);
|
||||
$where['type'] = 1;
|
||||
$where['activity_id'] = $id;
|
||||
$count = $orderServices->count($where);
|
||||
foreach ($list as &$item) {
|
||||
if ($item['is_del'] || $item['is_system_del']) {
|
||||
$item['status'] = '已删除';
|
||||
} else if ($item['paid'] == 0 && $item['status'] == 0) {
|
||||
$item['status'] = '待付款';
|
||||
} else if ($item['paid'] == 1 && $item['status'] == 4 && in_array($item['shipping_type'], [1, 3]) && $item['refund_status'] == 0) {
|
||||
$item['status'] = '部分发货';
|
||||
} else if ($item['paid'] == 1 && $item['refund_status'] == 2) {
|
||||
$item['status'] = '已退款';
|
||||
} else if ($item['paid'] == 1 && $item['status'] == 5 && $item['refund_status'] == 0) {
|
||||
$item['status'] = $item['shipping_type'] == 2 ? '部分核销' : '部分收货';
|
||||
$item['_status'] = 12;//已支付 部分核销
|
||||
} else if ($item['paid'] == 1 && $item['refund_status'] == 1) {
|
||||
$item['status'] = '申请退款';
|
||||
} else if ($item['paid'] == 1 && $item['refund_status'] == 4) {
|
||||
$item['status'] = '退款中';
|
||||
} else if ($item['paid'] == 1 && $item['status'] == 0 && in_array($item['shipping_type'], [1, 3]) && $item['refund_status'] == 0) {
|
||||
$item['status'] = '未发货';
|
||||
$item['_status'] = 2;//已支付 未发货
|
||||
} else if ($item['paid'] == 1 && in_array($item['status'], [0, 1]) && $item['shipping_type'] == 2 && $item['refund_status'] == 0) {
|
||||
$item['status'] = '未核销';
|
||||
} else if ($item['paid'] == 1 && in_array($item['status'], [1, 5]) && in_array($item['shipping_type'], [1, 3]) && $item['refund_status'] == 0) {
|
||||
$item['status'] = '待收货';
|
||||
} else if ($item['paid'] == 1 && $item['status'] == 2 && $item['refund_status'] == 0) {
|
||||
$item['status'] = '待评价';
|
||||
} else if ($item['paid'] == 1 && $item['status'] == 3 && $item['refund_status'] == 0) {
|
||||
$item['status'] = '已完成';
|
||||
} else if ($item['paid'] == 1 && $item['refund_status'] == 3) {
|
||||
$item['status'] = '部分退款';
|
||||
} else {
|
||||
$item['status'] = '未知';
|
||||
}
|
||||
$item['add_time'] = date('Y-m-d H:i:s', $item['add_time']);
|
||||
$item['pay_time'] = $item['pay_time'] ? date('Y-m-d H:i:s', $item['pay_time']) : '';
|
||||
}
|
||||
return compact('list', 'count');
|
||||
}
|
||||
}
|
||||
182
app/services/activity/seckill/StoreSeckillTimeServices.php
Normal file
182
app/services/activity/seckill/StoreSeckillTimeServices.php
Normal file
@@ -0,0 +1,182 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\seckill;
|
||||
|
||||
|
||||
use app\dao\activity\seckill\StoreSeckillTimeDao;
|
||||
use app\services\BaseServices;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use crmeb\services\FormBuilder as Form;
|
||||
use FormBuilder\Factory\Iview;
|
||||
use think\annotation\Inject;
|
||||
use think\facade\Route as Url;
|
||||
|
||||
/**
|
||||
* 秒杀时间
|
||||
* Class StoreSeckillTimeServices
|
||||
* @package app\services\activity\seckill
|
||||
* @mixin StoreSeckillTimeDao
|
||||
*/
|
||||
class StoreSeckillTimeServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var StoreSeckillTimeDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreSeckillTimeDao $dao;
|
||||
|
||||
/**
|
||||
* 获取当前的秒杀时间time
|
||||
* @return int
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getSeckillTime()
|
||||
{
|
||||
$seckillTime = $this->time_list();
|
||||
$currentHour = date('Hi');
|
||||
$time = 0;
|
||||
foreach ($seckillTime as $value) {
|
||||
$start = str_replace(':', '', $value['start_time']);
|
||||
$end = str_replace(':', '', $value['end_time']);
|
||||
if ($currentHour >= $start && $currentHour < $end) {
|
||||
$time = $value['id'];
|
||||
}
|
||||
}
|
||||
return (int)$time;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function systemPage(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getList($where, '*', $page, $limit);
|
||||
$count = $this->dao->count($where);
|
||||
foreach ($list as &$item) {
|
||||
$item['start_time'] = substr_replace($item['start_time'], ':', 2, 0);
|
||||
$item['end_time'] = substr_replace($item['end_time'], ':', 2, 0);
|
||||
}
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 可用秒杀时间段
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function time_list()
|
||||
{
|
||||
$list = $this->dao->getList(['status' => 1], 'id,title,start_time,end_time,pic');
|
||||
foreach ($list as &$item) {
|
||||
$item['start_time'] = substr_replace($item['start_time'], ':', 2, 0);
|
||||
$item['end_time'] = substr_replace($item['end_time'], ':', 2, 0);
|
||||
$item['slide'] = $item['pic'];
|
||||
};
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证时间是否重复
|
||||
* @param array $where
|
||||
* @param int $id
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DbException
|
||||
*/
|
||||
public function checkTime(array $where, int $id)
|
||||
{
|
||||
if (!$this->dao->valStartTime($where['start_time'], $id) && !$this->dao->valEndTime($where['end_time'], $id) && !$this->dao->valAllTime($where, $id)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取秒杀时间
|
||||
* @param int $id
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getInfo(int $id)
|
||||
{
|
||||
$info = $this->dao->get($id);
|
||||
if (!$info) {
|
||||
throw new AdminException('数据不存在');
|
||||
}
|
||||
$info = $info->toArray();
|
||||
$info['time'] = [
|
||||
substr_replace($info['start_time'], ':', 2, 0) . ':00',
|
||||
substr_replace($info['end_time'], ':', 2, 0) . ':00'
|
||||
];
|
||||
return $info;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 添加、编辑表单
|
||||
* @param int $id
|
||||
* @return mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function createForm(int $id)
|
||||
{
|
||||
$info = [];
|
||||
if ($id) {
|
||||
$info = $this->getInfo($id);
|
||||
}
|
||||
$f[] = Form::input('title', '标题:', $info['title'] ?? '')->required();
|
||||
$f[] = Form::timeRange('time', '时间选择:', $info['time'][0] ?? '', $info['time'][1] ?? '')->prop('picker-options', ['format' => 'HH'])->appendValidate(Iview::validateArr()->required()->message('请选择时间'))->format('HH:mm');
|
||||
// $f[] = Form::frameImage('pic', '图片', Url::buildUrl('admin/widget.images/index', array('fodder' => 'pic')), $info['pic'] ?? '')->icon('ios-add')->width('960px')->height('505px')->modal(['footer-hide' => true])->appendValidate(Iview::validateStr()->required()->message('请选择图片'));
|
||||
$f[] = Form::radio('status', '状态:', $info['status'] ?? 1)->options([['label' => '显示', 'value' => 1], ['label' => '隐藏', 'value' => 0]]);
|
||||
$f[] = Form::input('describe', '描述:',$info['describe'] ?? '')->required();
|
||||
return create_form($id ? '编辑' : '添加秒杀时间', $f, $this->url('/marketing/seckill/time/' . $id), 'POST');
|
||||
}
|
||||
|
||||
/**
|
||||
* 组合4位秒杀时间
|
||||
* @param $time
|
||||
* @return array|string|string[]
|
||||
*/
|
||||
public function changeTime($time)
|
||||
{
|
||||
$str_time = '';
|
||||
switch (strlen($time)) {
|
||||
case 1:
|
||||
$str_time = '0' . $time . '00';
|
||||
break;
|
||||
case 2:
|
||||
$str_time = $time . '00';
|
||||
break;
|
||||
case 3:
|
||||
$str_time = '0' . $time;
|
||||
break;
|
||||
case 4:
|
||||
$str_time = $time;
|
||||
break;
|
||||
}
|
||||
return substr_replace($str_time, ':', 2, 0);
|
||||
}
|
||||
|
||||
}
|
||||
256
app/services/activity/video/VideoCommentServices.php
Normal file
256
app/services/activity/video/VideoCommentServices.php
Normal file
@@ -0,0 +1,256 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\video;
|
||||
|
||||
use app\dao\activity\video\VideoCommentDao;
|
||||
use app\services\BaseServices;
|
||||
use app\services\user\UserRelationServices;
|
||||
use app\services\user\UserServices;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use crmeb\services\FormBuilder as Form;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
use think\facade\Route as Url;
|
||||
|
||||
|
||||
/**
|
||||
* Class VideoCommentServices
|
||||
* @package app\services\activity\video
|
||||
* @mixin VideoCommentDao
|
||||
*/
|
||||
class VideoCommentServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var VideoCommentDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected VideoCommentDao $dao;
|
||||
|
||||
/**
|
||||
* 视频评价列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function sysPage(array $where)
|
||||
{
|
||||
$where['pid'] = 0;
|
||||
$where['is_del'] = 0;
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$with = ['video', 'replyContent'];
|
||||
$list = $this->dao->getList($where, '*', $with, $page, $limit);
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 回复评论
|
||||
* @param int $id
|
||||
* @param string $content
|
||||
*/
|
||||
public function setReply(int $id, string $content)
|
||||
{
|
||||
if ($content == '') throw new AdminException('请输入回复内容');
|
||||
$comment = $this->dao->get($id);
|
||||
if (!$comment) {
|
||||
throw new AdminException('回复的评论不存在');
|
||||
}
|
||||
$save = [];
|
||||
$save['type'] = $comment['type'];
|
||||
$save['relation_id'] = $comment['relation_id'];
|
||||
$save['pid'] = $comment['pid'] ? $comment['pid'] : $id;
|
||||
$save['video_id'] = $comment['video_id'];
|
||||
$save['content'] = $content;
|
||||
$save['nickname'] = sys_config('site_name');
|
||||
$save['avatar'] = sys_config('wap_login_logo');
|
||||
$where = ['video_id' => $comment['video_id'], 'uid' => 0, 'pid' => $id, 'is_del' => 0];
|
||||
if ($this->dao->count($where)) {
|
||||
$res = $this->dao->update($where, ['content' => $content, 'update_time' => time()]);
|
||||
} else {
|
||||
$save['add_time'] = time();
|
||||
$res = $this->dao->save($save);
|
||||
/** @var VideoServices $videoServices */
|
||||
$videoServices = app()->make(VideoServices::class);
|
||||
$videoServices->bcInc($comment['video_id'], 'comment_num', '1');
|
||||
}
|
||||
if (!$res) throw new AdminException('回复失败,请稍后再试');
|
||||
$this->dao->update($id, ['is_reply' => 1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取评论回复列表
|
||||
* @param int $id
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getCommentReplyList(int $id, array $where)
|
||||
{
|
||||
$comment = $this->dao->get($id);
|
||||
if (!$comment) {
|
||||
throw new AdminException('回复的评论不存在');
|
||||
}
|
||||
$where['pid'] = $id;
|
||||
$where['is_del'] = 0;
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getList($where, '*', ['video', 'user' => function ($query) {
|
||||
$query->field('uid,avatar,nickname,is_money_level');
|
||||
}, 'children' => function ($query) {
|
||||
$query->with([
|
||||
'user' => function ($query) {
|
||||
$query->field('uid,avatar,nickname,is_money_level');
|
||||
}
|
||||
]);
|
||||
}], $page, $limit);
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建虚拟评论表单
|
||||
* @param int $video_id
|
||||
* @param $store_id
|
||||
* @return mixed
|
||||
*/
|
||||
public function createForm(int $video_id, $store_id = 0)
|
||||
{
|
||||
if ($video_id == 0) {
|
||||
$field[] = Form::frameImage('video', '视频', Url::buildUrl($store_id ? 'store/video.shortVideo/index' : 'admin/video.shortVideo/index', array('fodder' => 'video')))->icon('ios-add')->width('960px')->height('560px')->modal(['footer-hide' => true])->Props(['srcKey' => 'image']);
|
||||
} else {
|
||||
$field[] = Form::hidden('video_id', $video_id);
|
||||
}
|
||||
$field[] = Form::frameImage('avatar', '用户头像', Url::buildUrl($store_id ? 'store/widget.images/index' : 'admin/widget.images/index', array('fodder' => 'avatar')))->icon('ios-add')->width('960px')->height('505px')->modal(['footer-hide' => true]);
|
||||
$field[] = Form::input('nickname', '用户名称')->col(24);
|
||||
$field[] = Form::input('content', '评价文字')->type('textarea');
|
||||
$field[] = Form::dateTime('add_time', '评论时间', '')->placeholder('请选择评论时间(不选择默认当前添加时间)');
|
||||
return create_form('添加虚拟评论', $field, Url::buildUrl('/marketing/video/comment/save_fictitious'), 'POST');
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存评价、回复
|
||||
* @param int $uid
|
||||
* @param int $video_id
|
||||
* @param $id
|
||||
* @param array $data
|
||||
* @return \crmeb\basic\BaseModel|\think\Model
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function saveComment(int $uid, int $video_id, $id, array $data)
|
||||
{
|
||||
/** @var VideoServices $videoServices */
|
||||
$videoServices = app()->make(VideoServices::class);
|
||||
$video = $videoServices->get($video_id);
|
||||
if (!$video) {
|
||||
throw new AdminException('评论的视频不存在');
|
||||
}
|
||||
$pid = $id;
|
||||
if ($id) {//回复评价
|
||||
$comment = $this->dao->get($id);
|
||||
if (!$comment) {
|
||||
throw new ValidateException('评论不存在或已删除');
|
||||
}
|
||||
if ($comment['pid']) $pid = $comment['pid'];
|
||||
}
|
||||
if ($uid && $uid != -1) {
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$userInfo = $userServices->getUserInfo($uid);
|
||||
if (!$userInfo) {
|
||||
throw new ValidateException('用户不存在');
|
||||
}
|
||||
$data['nickname'] = $userInfo['nickname'] ?? '';
|
||||
$data['avatar'] = $userInfo['avatar'] ?? '';
|
||||
}
|
||||
//ip转城市信息
|
||||
if (isset($data['ip']) && $data['ip']) {
|
||||
$data['city'] = $this->convertIp($data['ip']);
|
||||
}
|
||||
$data['uid'] = $uid;
|
||||
$data['video_id'] = $video_id;
|
||||
$data['pid'] = $pid;
|
||||
$data['type'] = $video['type'];
|
||||
$data['relation_id'] = $video['relation_id'];
|
||||
$time = time();
|
||||
if (isset($data['add_time']) && $data['add_time']) {
|
||||
if ($data['add_time'] > $time) {
|
||||
throw new AdminException('评论时间应小于当前时间');
|
||||
}
|
||||
$data['add_time'] = strtotime($data['add_time']);
|
||||
} else {
|
||||
$data['add_time'] = $time;
|
||||
}
|
||||
$res = $this->dao->save($data);
|
||||
/** @var VideoServices $videoServices */
|
||||
$videoServices = app()->make(VideoServices::class);
|
||||
$videoServices->bcInc($video_id, 'comment_num', 1);
|
||||
if (!$res) throw new AdminException('保存评论失败');
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取短视频评价列表
|
||||
* @param int $uid
|
||||
* @param int $id
|
||||
* @param int $pid
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getVideoCommentList(int $uid, int $id, int $pid = 0)
|
||||
{
|
||||
$where = ['video_id' => $id, 'is_del' => 0];
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
if ($limit > 20) $limit = 20;
|
||||
|
||||
if ($pid) {
|
||||
$comment = $this->dao->get($pid);
|
||||
if (!$comment) {
|
||||
throw new ValidateException('评论不存在或已删除');
|
||||
}
|
||||
$where['video_id'] = $comment['video_id'];
|
||||
}
|
||||
$where['pid'] = $pid;
|
||||
$list = $this->dao->getList($where, 'id,pid,video_id,uid,nickname,avatar,content,like_num,city,add_time', ['children' => function ($query) {
|
||||
$query->field("id,pid")->with(['userVip']);
|
||||
}, 'userVip'], $page, $limit);
|
||||
if ($list) {
|
||||
$userLike = [];
|
||||
if ($uid) {
|
||||
$ids = array_column($list, 'id');
|
||||
/** @var UserRelationServices $userRelationServices */
|
||||
$userRelationServices = app()->make(UserRelationServices::class);
|
||||
$userLike = $userRelationServices->getColumn([['uid', '=', $uid], ['relation_id', 'in', $ids], ['category', '=', 'video_comment'], ['type', '=', 'like']], 'id,relation_id', 'relation_id');
|
||||
}
|
||||
foreach ($list as &$item) {
|
||||
$item['add_time'] = $item['add_time'] ? date('Y-m-d H:i:s', $item['add_time']) : '';
|
||||
$item['is_like'] = isset($userLike[$item['id']]);
|
||||
$item['reply'] = [];
|
||||
$item['reply_count'] = isset($item['children']) ? (int)count($item['children']) : 0;
|
||||
$item['city'] = $this->addressHandle($item['city'])['city'] ?? '';
|
||||
unset($item['children']);
|
||||
}
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
346
app/services/activity/video/VideoServices.php
Normal file
346
app/services/activity/video/VideoServices.php
Normal file
@@ -0,0 +1,346 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\video;
|
||||
|
||||
use app\dao\activity\video\VideoDao;
|
||||
use app\jobs\activity\VideoJob;
|
||||
use app\services\activity\live\LiveRoomServices;
|
||||
use app\services\BaseServices;
|
||||
use app\services\product\product\StoreProductServices;
|
||||
use app\services\product\category\StoreProductCategoryServices;
|
||||
use app\services\user\UserRelationServices;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
|
||||
/**
|
||||
* Class VideoServices
|
||||
* @package app\services\activity\video
|
||||
* @mixin VideoDao
|
||||
*/
|
||||
class VideoServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* 移动端视频需要默认值
|
||||
* @var array
|
||||
*/
|
||||
protected array $videoDefault = [
|
||||
'isMore' => false,
|
||||
'state' => "pause",
|
||||
'playIng' => false,
|
||||
'isShowimage' => false,
|
||||
'isShowProgressBarTime' => false,
|
||||
'isplay' => true
|
||||
];
|
||||
|
||||
/**
|
||||
* @var VideoDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected VideoDao $dao;
|
||||
|
||||
/**
|
||||
* 获取短视频信息(获取不到抛出异常)
|
||||
* @param int $id
|
||||
* @param string $field
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getVideoInfo(int $id, string $field = '*')
|
||||
{
|
||||
$videoInfo = $this->dao->getOne(['id' => $id], $field);
|
||||
if (!$videoInfo) {
|
||||
throw new ValidateException('获取短视频信息失败');
|
||||
}
|
||||
return $videoInfo->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取视频详情
|
||||
* @param int $id
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getInfo(int $id)
|
||||
{
|
||||
$info = $this->dao->get($id);
|
||||
if (!$info) {
|
||||
throw new ValidateException('视频不存在');
|
||||
}
|
||||
$info = $info->toArray();
|
||||
$productInfo = [];
|
||||
$info['type_name'] = '平台';
|
||||
if ($info['product_id']) {
|
||||
$info['product_id'] = is_string($info['product_id']) ? explode(',', $info['product_id']) : $info['product_id'];
|
||||
/** @var StoreProductServices $productServices */
|
||||
$productServices = app()->make(StoreProductServices::class);
|
||||
$product_where = ['is_del' => 0, 'is_show' => 1, 'is_verify' => 1];
|
||||
$productInfo = $productServices->getSearchList($product_where + ['ids' => $info['product_id']], 0, 0, ['id', 'type', 'product_type', 'price', 'image', 'store_name', 'cate_id', 'sales', 'stock'], '', []);
|
||||
if ($productInfo) {
|
||||
$cateIds = implode(',', array_column($productInfo, 'cate_id'));
|
||||
/** @var StoreProductCategoryServices $categoryService */
|
||||
$categoryService = app()->make(StoreProductCategoryServices::class);
|
||||
$cateList = $categoryService->getCateParentAndChildName($cateIds);
|
||||
foreach ($productInfo as $key => &$item) {
|
||||
$item['cate_name'] = '';
|
||||
if (isset($item['cate_id']) && $item['cate_id']) {
|
||||
$cate_ids = explode(',', $item['cate_id']);
|
||||
$cate_name = $categoryService->getCateName($cate_ids, $cateList);
|
||||
if ($cate_name) {
|
||||
$item['cate_name'] = is_array($cate_name) ? implode(',', $cate_name) : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$info['productInfo'] = $productInfo;
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* 后台获取视频列表
|
||||
* @param $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function sysPage($where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getList($where, '*', $page, $limit);
|
||||
$count = 0;
|
||||
if ($list) {
|
||||
$site_name = sys_config('site_name');
|
||||
$site_image = sys_config('wap_login_logo');
|
||||
/** @var StoreProductServices $productServices */
|
||||
$productServices = app()->make(StoreProductServices::class);
|
||||
$product_where = ['is_del' => 0, 'is_show' => 1, 'is_verify' => 1];
|
||||
foreach ($list as &$item) {
|
||||
$item['product_id'] = is_string($item['product_id']) ? explode(',', $item['product_id']) : $item['product_id'];
|
||||
$item['product_info'] = [];
|
||||
$item['product_num'] = 0;
|
||||
if ($item['product_id']) {
|
||||
$item['product_info'] = $productServices->getSearchList($product_where + ['ids' => $item['product_id']], 0, 0, ['id', 'store_name', 'image', 'price'], '', []);
|
||||
$item['product_num'] = count($item['product_info']);
|
||||
}
|
||||
|
||||
$item['type_name'] = $site_name;
|
||||
$item['type_image'] = $site_image;
|
||||
$item['add_time'] = $item['add_time'] ? date('Y-m-d H:i:s', $item['add_time']) : '';
|
||||
}
|
||||
$count = $this->dao->count($where);
|
||||
}
|
||||
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取短视频列表
|
||||
* @param int $uid
|
||||
* @param string $field
|
||||
* @param int $order_type
|
||||
* @param int $id
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getVideoList(int $uid, string $field = '*', int $order_type = 1, int $id = 0)
|
||||
{
|
||||
//短视频未启用
|
||||
if (!sys_config('video_func_status', 1)) {
|
||||
return [];
|
||||
}
|
||||
$where = ['is_show' => 1, 'is_del' => 0, 'is_verify' => 1];
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
//限制一次最多请求条数
|
||||
if ($limit > 10) $limit = 10;
|
||||
if ($id) {//指定视频进入
|
||||
$ids = array_merge([$id], $this->dao->getColumn($where, 'id'));
|
||||
$where['order_by_id'] = array_slice($ids, 0, $limit);
|
||||
$order = '';
|
||||
} elseif ($order_type == 1) {//最新
|
||||
$order = 'id desc,sort desc';
|
||||
} else if ($order_type == 2) {//推荐
|
||||
$where['is_recommend'] = 1;
|
||||
$order = 'is_recommend desc,sort desc,id desc';
|
||||
} else {
|
||||
$order = 'sort desc,id desc';
|
||||
}
|
||||
$list = $this->dao->getList($where, $field, $page, $limit, $order);
|
||||
if ($list) {
|
||||
/** @var LiveRoomServices $liveServices */
|
||||
$liveServices = app()->make(LiveRoomServices::class);
|
||||
$liveCount = $liveServices->count(['is_show' => 1, 'is_del' => 0, 'status' => 1, 'live_status' => [101, 105, 106]]);
|
||||
$is_live = (bool)$liveCount;
|
||||
$site_name = sys_config('site_name');
|
||||
$site_image = sys_config('wap_login_logo');
|
||||
$userLike = $userCollect = [];
|
||||
$ids = array_column($list, 'id');
|
||||
if ($uid) {
|
||||
/** @var UserRelationServices $userRelationServices */
|
||||
$userRelationServices = app()->make(UserRelationServices::class);
|
||||
$userLike = $userRelationServices->getColumn([['uid', '=', $uid], ['relation_id', 'in', $ids], ['category', '=', 'video'], ['type', '=', 'like']], 'id,relation_id', 'relation_id');
|
||||
$userCollect = $userRelationServices->getColumn([['uid', '=', $uid], ['relation_id', 'in', $ids], ['category', '=', 'video'], ['type', '=', 'collect']], 'id,relation_id', 'relation_id');
|
||||
}
|
||||
/** @var StoreProductServices $storeProductServices */
|
||||
$storeProductServices = app()->make(StoreProductServices::class);
|
||||
$productWhere = ['is_show' => 1, 'is_del' => 0, 'is_verify' => 1];
|
||||
foreach ($list as &$item) {
|
||||
$item['product_id'] = is_string($item['product_id']) ? explode(',', $item['product_id']) : $item['product_id'];
|
||||
$item['product_num'] = count($item['product_id']);
|
||||
//过滤下架、审核中等商品
|
||||
$item['product_num'] = $item['product_num'] ? $storeProductServices->getCount($productWhere + ['ids' => $item['product_id']]) : 0;
|
||||
$item['type_name'] = $site_name;
|
||||
$item['type_image'] = $site_image;
|
||||
$item['date'] = $item['add_time'] ? date('m月d日', $item['add_time']) : '';
|
||||
$item['add_time'] = $item['add_time'] ? date('Y-m-d H:i:s', $item['add_time']) : '';
|
||||
$item['is_like'] = isset($userLike[$item['id']]);
|
||||
$item['is_collect'] = isset($userCollect[$item['id']]);
|
||||
//app需要
|
||||
$item['id'] = (string)$item['id'];
|
||||
$item = array_merge($item, $this->videoDefault);
|
||||
$item['is_live'] = $is_live;
|
||||
}
|
||||
//增加浏览量
|
||||
VideoJob::dispatchDo('setVideoPlayNum', [$ids, $uid]);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取推荐短信视频
|
||||
* @param int $id
|
||||
* @param int $limit
|
||||
* @return array|mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getRecommend(int $id, int $limit = 1)
|
||||
{
|
||||
$where = ['is_show' => 1, 'is_del' => 0, 'is_recommend' => 1, 'notId' => $id];
|
||||
$list = $this->dao->getList($where, 'id,desc', 0, $limit, 'rand');
|
||||
$res = [];
|
||||
if ($limit == 1) {
|
||||
if ($list) {
|
||||
$res = $list[0] ?? [];
|
||||
}
|
||||
} else {
|
||||
$res = $list;
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* diy获取短视频
|
||||
* @param int $uid
|
||||
* @param string $field
|
||||
* @param int $order_type
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getDiyVideoList(int $uid, string $field = '*', int $order_type = 0)
|
||||
{
|
||||
//短视频未启用
|
||||
if (!sys_config('video_func_status', 1)) {
|
||||
return [];
|
||||
}
|
||||
$where = ['is_show' => 1, 'is_del' => 0, 'is_verify' => 1];
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
//限制一次最多请求条数
|
||||
if ($limit > 10) $limit = 10;
|
||||
if ($order_type == 1) {//最新
|
||||
$order = 'id desc,sort desc';
|
||||
} else if ($order_type == 2) {//推荐
|
||||
$where['is_recommend'] = 1;
|
||||
$order = 'is_recommend desc,sort desc,id desc';
|
||||
} else {
|
||||
$order = 'sort desc,id desc';
|
||||
}
|
||||
$list = $this->dao->getList($where, $field, $page, $limit, $order);
|
||||
if ($list) {
|
||||
$site_name = sys_config('site_name');
|
||||
$site_image = sys_config('wap_login_logo');
|
||||
/** @var StoreProductServices $productServices */
|
||||
$productServices = app()->make(StoreProductServices::class);
|
||||
$product_where = ['is_del' => 0, 'is_show' => 1, 'is_verify' => 1];
|
||||
foreach ($list as &$item) {
|
||||
$item['product_id'] = is_string($item['product_id']) ? explode(',', $item['product_id']) : $item['product_id'];
|
||||
$item['product_info'] = [];
|
||||
$item['product_num'] = 0;
|
||||
if ($item['product_id']) {
|
||||
$item['product_info'] = $productServices->getSearchList($product_where + ['ids' => $item['product_id']], 0, 0, ['id', 'store_name', 'image', 'price'], '', []);
|
||||
$item['product_num'] = count($item['product_info']);
|
||||
}
|
||||
$item['type_name'] = $site_name;
|
||||
$item['type_image'] = $site_image;
|
||||
$item['add_time'] = $item['add_time'] ? date('Y-m-d H:i:s', $item['add_time']) : '';
|
||||
}
|
||||
$ids = array_column($list, 'id');
|
||||
//增加浏览量
|
||||
VideoJob::dispatchDo('setVideoPlayNum', [$ids, $uid]);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户点赞、收藏、分享、浏览播放视频
|
||||
* @param int $uid
|
||||
* @param int $id
|
||||
* @param string $type
|
||||
* @param int $num
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function userRelationVideo(int $uid, int $id, string $type = 'like', int $num = 1)
|
||||
{
|
||||
$info = $this->getVideoInfo((int)$id);
|
||||
$data = ['uid' => $uid, 'relation_id' => $id, 'category' => UserRelationServices::CATEGORY_VIDEO, 'type' => $type];
|
||||
$typeArr = UserRelationServices::TYPE_NAME;
|
||||
if (!isset($typeArr[$type])) {
|
||||
throw new ValidateException('类型错误');
|
||||
}
|
||||
/** @var UserRelationServices $userRelationServices */
|
||||
$userRelationServices = app()->make(UserRelationServices::class);
|
||||
//播放 每一次都是增加数量
|
||||
if ($type != 'play') {
|
||||
$relation = $userRelationServices->get($data);
|
||||
} else {
|
||||
$relation = [];
|
||||
}
|
||||
$field = $type . '_num';
|
||||
$balance = $info[$field] ?? 0;
|
||||
if ($relation) {//取消
|
||||
$userRelationServices->delete($relation['id']);
|
||||
$new = (int)bcsub((string)$balance, (string)$num);
|
||||
} else {//增加
|
||||
$data['add_time'] = time();
|
||||
$userRelationServices->save($data);
|
||||
$new = (int)bcadd((string)$balance, (string)$num);
|
||||
}
|
||||
$new = max($new, 0);
|
||||
$this->dao->update($id, [$field => $new]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user