chore: 添加静态资源文件和版本配置文件
添加大量图片、字体、音频等静态资源文件,包括用户界面图片、模板文件和安装界面素材 添加系统版本配置文件(.version)和常量定义文件(.constant) 更新供应商依赖文件,包括Symfony VarDumper组件和相关许可证文件 添加验证码配置文件(captcha.php)和.gitignore规则
This commit is contained in:
776
app/services/product/product/CopyTaobaoServices.php
Normal file
776
app/services/product/product/CopyTaobaoServices.php
Normal file
@@ -0,0 +1,776 @@
|
||||
<?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\product\product;
|
||||
|
||||
use app\services\BaseServices;
|
||||
use app\services\product\shipping\ShippingTemplatesServices;
|
||||
use app\services\product\sku\StoreProductAttrServices;
|
||||
use app\services\product\category\StoreProductCategoryServices;
|
||||
use app\services\serve\ServeServices;
|
||||
use app\services\system\attachment\SystemAttachmentCategoryServices;
|
||||
use app\services\system\attachment\SystemAttachmentServices;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use crmeb\services\CopyProductService;
|
||||
use crmeb\services\UploadService;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class CopyTaobaoServices
|
||||
* @package app\services\product\product
|
||||
*/
|
||||
class CopyTaobaoServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $errorInfo = true;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $AttachmentCategoryName = '远程下载';
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected array $host = ['taobao', 'tmall', 'jd', 'pinduoduo', 'suning', 'yangkeduo', '1688'];
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
* @param $id
|
||||
* @param $shopid
|
||||
* @param $url
|
||||
* @return array
|
||||
*/
|
||||
public function copyProduct($type, $id, $shopid, $url)
|
||||
{
|
||||
switch ((int)sys_config('system_product_copy_type')) {
|
||||
case 1://平台
|
||||
/** @var ServeServices $services */
|
||||
$services = app()->make(ServeServices::class);
|
||||
$resultData = $services->copy()->goods($url);
|
||||
if (isset($resultData['description_image']) && is_string($resultData['description_image'])) {
|
||||
$resultData['description_image'] = json_decode($resultData['description_image'], true);
|
||||
}
|
||||
if (isset($resultData['slider_image']) && is_string($resultData['slider_image'])) {
|
||||
$resultData['slider_image'] = json_decode($resultData['slider_image'], true);
|
||||
}
|
||||
$result['status'] = 200;
|
||||
$result['data'] = $resultData;
|
||||
break;
|
||||
case 2://99API
|
||||
$apikey = sys_config('copy_product_apikey');
|
||||
if (!$apikey) throw new AdminException('请先配置接口密钥');
|
||||
if ((!$type || !$id) && $url) {
|
||||
$url_arr = parse_url($url);
|
||||
if (isset($url_arr['host'])) {
|
||||
foreach ($this->host as $name) {
|
||||
if (strpos($url_arr['host'], $name) !== false) {
|
||||
$type = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
$type = ($type == 'pinduoduo' || $type == 'yangkeduo') ? 'pdd' : $type;
|
||||
switch ($type) {
|
||||
case 'taobao':
|
||||
case 'tmall':
|
||||
$params = [];
|
||||
if (isset($url_arr['query']) && $url_arr['query']) {
|
||||
$queryParts = explode('&', $url_arr['query']);
|
||||
foreach ($queryParts as $param) {
|
||||
$item = explode('=', $param);
|
||||
if (isset($item[0]) && $item[1]) $params[$item[0]] = $item[1];
|
||||
}
|
||||
}
|
||||
$id = $params['id'] ?? '';
|
||||
break;
|
||||
case 'jd':
|
||||
$params = [];
|
||||
if (isset($url_arr['path']) && $url_arr['path']) {
|
||||
$path = str_replace('.html', '', $url_arr['path']);
|
||||
$params = explode('/', $path);
|
||||
}
|
||||
$id = $params[1] ?? '';
|
||||
break;
|
||||
case 'pdd':
|
||||
$params = [];
|
||||
if (isset($url_arr['query']) && $url_arr['query']) {
|
||||
$queryParts = explode('&', $url_arr['query']);
|
||||
foreach ($queryParts as $param) {
|
||||
$item = explode('=', $param);
|
||||
if (isset($item[0]) && $item[1]) $params[$item[0]] = $item[1];
|
||||
}
|
||||
}
|
||||
$id = $params['goods_id'] ?? $params['goodsId'] ?? '';
|
||||
break;
|
||||
case 'suning':
|
||||
$params = [];
|
||||
if (isset($url_arr['path']) && $url_arr['path']) {
|
||||
$path = str_replace('.html', '', $url_arr['path']);
|
||||
$params = explode('/', $path);
|
||||
}
|
||||
$id = $params[2] ?? '';
|
||||
$shopid = $params[1] ?? '';
|
||||
break;
|
||||
case '1688':
|
||||
$params = [];
|
||||
if (isset($url_arr['query']) && $url_arr['query']) {
|
||||
$path = str_replace('.html', '', $url_arr['path']);
|
||||
$params = explode('/', $path);
|
||||
}
|
||||
$id = $params[2] ?? '';
|
||||
$shopid = $params[1] ?? '';
|
||||
break;
|
||||
}
|
||||
}
|
||||
$result = CopyProductService::getInfo($type, ['itemid' => $id, 'shopid' => $shopid], $apikey);
|
||||
break;
|
||||
}
|
||||
if (isset($result['status']) && $result['status']) {
|
||||
/** @var ShippingTemplatesServices $shippingTemplates */
|
||||
$shippingTemplates = app()->make(ShippingTemplatesServices::class);
|
||||
/** @var StoreProductCategoryServices $storeCategoryService */
|
||||
$storeCategoryService = app()->make(StoreProductCategoryServices::class);
|
||||
$data = [];
|
||||
$productInfo = $result['data'];
|
||||
|
||||
//参数
|
||||
$sku_props = $this->parameter($productInfo['sku_props'] ?? [], $url);
|
||||
$productInfo['specs'] = $sku_props;
|
||||
|
||||
//查询附件分类
|
||||
/** @var SystemAttachmentCategoryServices $systemAttachmentCategoryService */
|
||||
$systemAttachmentCategoryService = app()->make(SystemAttachmentCategoryServices::class);
|
||||
$AttachmentCategory = $systemAttachmentCategoryService->getOne(['name' => $this->AttachmentCategoryName]);
|
||||
//不存在则创建
|
||||
if (!$AttachmentCategory) $AttachmentCategory = $systemAttachmentCategoryService->save(['pid' => '0', 'name' => $this->AttachmentCategoryName, 'enname' => '']);
|
||||
//生成附件目录
|
||||
try {
|
||||
if (make_path('attach', 3, true) === '')
|
||||
throw new AdminException('无法创建文件夹,请检查您的上传目录权限:' . app()->getRootPath() . 'public' . DS . 'uploads' . DS . 'attach' . DS);
|
||||
} catch (\Exception $e) {
|
||||
throw new AdminException($e->getMessage() . '或无法创建文件夹,请检查您的上传目录权限:' . app()->getRootPath() . 'public' . DS . 'uploads' . DS . 'attach' . DS);
|
||||
}
|
||||
$images = [
|
||||
['w' => 305, 'h' => 305, 'line' => $productInfo['image'], 'valuename' => 'image']
|
||||
];
|
||||
//执行下载
|
||||
$res = $this->uploadImage($images, false, 0, $AttachmentCategory['id']);
|
||||
if (!is_array($res)) throw new AdminException($this->errorInfo ? $this->errorInfo : '保存图片失败');
|
||||
if (isset($res['image'])) $productInfo['image'] = $res['image'];
|
||||
$productInfo['image'] = str_replace('\\', '/', $productInfo['image']);
|
||||
if (count($productInfo['slider_image'])) {
|
||||
$productInfo['slider_image'] = array_map(function ($item) {
|
||||
$item = str_replace('\\', '/', $item);
|
||||
return $item;
|
||||
}, $productInfo['slider_image']);
|
||||
}
|
||||
$productInfo['slider_image'] = array_slice($productInfo['slider_image'], 0, 10);
|
||||
$data['tempList'] = $shippingTemplates->getTemp();
|
||||
$menus = [];
|
||||
foreach ($storeCategoryService->getTierList(1) as $menu) {
|
||||
$menus[] = ['value' => $menu['id'], 'label' => $menu['html'] . $menu['cate_name'], 'disabled' => $menu['pid'] == 0 ? 0 : 1];//,'disabled'=>$menu['pid']== 0];
|
||||
}
|
||||
$data['cateList'] = $menus;
|
||||
|
||||
$productInfo['attrs'] = $result['data']['info']['value'];
|
||||
foreach ($productInfo['attrs'] as $attrs_k => $attrs_v) {
|
||||
$productInfo['attrs'][$attrs_k]['attr_arr'] = array_values($attrs_v['detail']);
|
||||
$productInfo['attrs'][$attrs_k]['is_show'] = 1;
|
||||
$productInfo['attrs'][$attrs_k]['is_default_select'] = 0;
|
||||
}
|
||||
|
||||
$productInfo['type'] = 0;
|
||||
$productInfo['product_clear'] = ['is_general_product'];
|
||||
$productInfo['relation_id'] = 0;
|
||||
$productInfo['activity'] = ['默认', '秒杀', '砍价', '拼团'];
|
||||
$productInfo['bar_code'] = '';
|
||||
$productInfo['product_type'] = 0;
|
||||
$productInfo['browse'] = 0;
|
||||
$productInfo['cate_id'] = [];
|
||||
$productInfo['code_path'] = '';
|
||||
$productInfo['command_word'] = '';
|
||||
$productInfo['coupons'] = [];
|
||||
$productInfo['is_bargain'] = '';
|
||||
$productInfo['is_benefit'] = 0;
|
||||
$productInfo['is_best'] = 0;
|
||||
$productInfo['is_del'] = 0;
|
||||
$productInfo['is_good'] = 0;
|
||||
$productInfo['is_hot'] = 0;
|
||||
$productInfo['is_new'] = 0;
|
||||
$productInfo['is_postage'] = 0;
|
||||
$productInfo['is_seckill'] = 0;
|
||||
$productInfo['is_show'] = 0;
|
||||
$productInfo['is_sub'] = [];
|
||||
$productInfo['is_vip'] = 0;
|
||||
$productInfo['label_id'] = [];
|
||||
$productInfo['mer_id'] = 0;
|
||||
$productInfo['mer_use'] = 0;
|
||||
$productInfo['recommend_image'] = '';
|
||||
$productInfo['sales'] = '';
|
||||
$productInfo['sort'] = 0;
|
||||
$productInfo['spec_type'] = 1;
|
||||
$productInfo['spu'] = '';
|
||||
$productInfo['id'] = 0;
|
||||
$productInfo['recommend'] = [];
|
||||
$productInfo['recommend_list'] = [];
|
||||
$productInfo['delivery_type'] = ['1'];
|
||||
$productInfo['soure_link'] = $url;
|
||||
$productInfo['code'] = '';
|
||||
$productInfo['freight'] = 1;
|
||||
$productInfo['postage'] = 0;
|
||||
$productInfo['temp_id'] = 0;
|
||||
$productInfo['is_support_refund'] = 1;
|
||||
$productInfo['is_presale_product'] = 0;
|
||||
$productInfo['presale_time'] = [];
|
||||
$productInfo['presale_day'] = 0;
|
||||
$productInfo['is_vip_product'] = 0;
|
||||
$productInfo['auto_on_time'] = 0;
|
||||
$productInfo['auto_off_time'] = 0;
|
||||
$productInfo['custom_form'] = [];
|
||||
$productInfo['system_form_id'] = 0;
|
||||
$productInfo['store_label_id'] = [];
|
||||
$productInfo['brand_id'] = [];
|
||||
$productInfo['ensure_id'] = [];
|
||||
$productInfo['specs_id'] = [];
|
||||
$productInfo['is_limit'] = 0;
|
||||
$productInfo['limit_type'] = 1;
|
||||
$productInfo['limit_num'] = 0;
|
||||
|
||||
//兼容新版本
|
||||
foreach ($productInfo['items'] as &$items) {
|
||||
$details = [];
|
||||
foreach ($items['detail'] as $detail) {
|
||||
$details[] = [
|
||||
'value' => $detail,
|
||||
'pic' => '',
|
||||
];
|
||||
}
|
||||
$items['detail'] = $details;
|
||||
$items['add_pic'] = 0;
|
||||
}
|
||||
|
||||
$data['productInfo'] = $productInfo;
|
||||
return $data;
|
||||
} else {
|
||||
throw new AdminException($result['msg']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析第三方平台商品参数
|
||||
* @param array $data 原始参数数据
|
||||
* @param string $url 商品链接
|
||||
* @return array
|
||||
*/
|
||||
public function parameter($data, $url)
|
||||
{
|
||||
if (!$data || !$url) {
|
||||
return [];
|
||||
}
|
||||
$url_arr = parse_url($url);
|
||||
if (isset($url_arr['host'])) {
|
||||
foreach ($this->host as $name) {
|
||||
if (strpos($url_arr['host'], $name) !== false) {
|
||||
$type = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
$props = [];
|
||||
$type = ($type == 'pinduoduo' || $type == 'yangkeduo') ? 'pdd' : $type;
|
||||
switch ($type) {
|
||||
case 'taobao':
|
||||
case 'tmall':
|
||||
foreach ($data as $item) {
|
||||
foreach ($item as $val) {
|
||||
foreach ($val as $k => $v) {
|
||||
foreach ($v as $name => $value) {
|
||||
if ($value) {
|
||||
$props[] = [
|
||||
'name' => $name,
|
||||
'value' => $value
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'jd':
|
||||
foreach ($data as $item) {
|
||||
$props[] = [
|
||||
'name' => $item,
|
||||
'value' => ''
|
||||
];
|
||||
}
|
||||
break;
|
||||
case '1688':
|
||||
foreach ($data as $item) {
|
||||
$_props = explode(':', $item);
|
||||
if (count($_props) == 2) {
|
||||
$props[] = [
|
||||
'name' => $_props[0],
|
||||
'value' => $_props[1]
|
||||
];
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
return $props;
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载商品详情图片
|
||||
* @param int $id
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function uploadDescriptionImage(int $id)
|
||||
{
|
||||
//查询附件分类
|
||||
/** @var SystemAttachmentCategoryServices $systemAttachmentCategoryService */
|
||||
$systemAttachmentCategoryService = app()->make(SystemAttachmentCategoryServices::class);
|
||||
/** @var StoreDescriptionServices $storeDescriptionServices */
|
||||
$storeDescriptionServices = app()->make(StoreDescriptionServices::class);
|
||||
/** @var StoreProductServices $StoreProductServices */
|
||||
$StoreProductServices = app()->make(StoreProductServices::class);
|
||||
$AttachmentCategory = $systemAttachmentCategoryService->getOne(['name' => $this->AttachmentCategoryName]);
|
||||
//不存在则创建
|
||||
if (!$AttachmentCategory) $AttachmentCategory = $systemAttachmentCategoryService->save(['pid' => '0', 'name' => $this->AttachmentCategoryName, 'enname' => '']);
|
||||
//生成附件目录
|
||||
try {
|
||||
if (make_path('attach', 3, true) === '')
|
||||
throw new AdminException('无法创建文件夹,请检查您的上传目录权限:' . app()->getRootPath() . 'public' . DS . 'uploads' . DS . 'attach' . DS);
|
||||
} catch (\Exception $e) {
|
||||
throw new AdminException($e->getMessage() . '或无法创建文件夹,请检查您的上传目录权限:' . app()->getRootPath() . 'public' . DS . 'uploads' . DS . 'attach' . DS);
|
||||
}
|
||||
$description = $storeDescriptionServices->getDescription(['product_id ' => $id, 'type' => 0]);
|
||||
if (!$description) throw new AdminException('商品参数错误!');
|
||||
//替换并下载详情里面的图片默认下载全部图片
|
||||
$description = preg_replace('#<style>.*?</style>#is', '', $description);
|
||||
$description = $this->uploadImage([], $description, 1, $AttachmentCategory['id']);
|
||||
$storeDescriptionServices->saveDescription((int)$id, $description);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载商品轮播图片
|
||||
* @param int $id
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function uploadSliderImage(int $id)
|
||||
{
|
||||
//查询附件分类
|
||||
/** @var SystemAttachmentCategoryServices $systemAttachmentCategoryService */
|
||||
$systemAttachmentCategoryService = app()->make(SystemAttachmentCategoryServices::class);
|
||||
/** @var StoreProductServices $StoreProductServices */
|
||||
$StoreProductServices = app()->make(StoreProductServices::class);
|
||||
$AttachmentCategory = $systemAttachmentCategoryService->getOne(['name' => $this->AttachmentCategoryName]);
|
||||
//不存在则创建
|
||||
if (!$AttachmentCategory) $AttachmentCategory = $systemAttachmentCategoryService->save(['pid' => '0', 'name' => $this->AttachmentCategoryName, 'enname' => '']);
|
||||
//生成附件目录
|
||||
try {
|
||||
if (make_path('attach', 3, true) === '')
|
||||
throw new AdminException('无法创建文件夹,请检查您的上传目录权限:' . app()->getRootPath() . 'public' . DS . 'uploads' . DS . 'attach' . DS);
|
||||
} catch (\Exception $e) {
|
||||
throw new AdminException($e->getMessage() . '或无法创建文件夹,请检查您的上传目录权限:' . app()->getRootPath() . 'public' . DS . 'uploads' . DS . 'attach' . DS);
|
||||
}
|
||||
$slider_image = $StoreProductServices->value(['id' => $id], 'slider_image');
|
||||
$slider_image = $slider_image ? json_decode($slider_image, true) : [];
|
||||
$images = [];
|
||||
//放入轮播图
|
||||
foreach ($slider_image as $item) {
|
||||
$value = ['w' => 640, 'h' => 640, 'line' => $item, 'valuename' => 'slider_image', 'isTwoArray' => true];
|
||||
$images[] = $value;
|
||||
}
|
||||
$res = $this->uploadImage($images, false, 0, $AttachmentCategory['id']);
|
||||
if (!is_array($res)) throw new AdminException($this->errorInfo ? $this->errorInfo : '保存图片失败');
|
||||
if (isset($res['slider_image'])) $slider_images = $res['slider_image'];
|
||||
if (count($slider_images)) {
|
||||
$slider_images = array_map(function ($item) {
|
||||
$item = str_replace('\\', '/', $item);
|
||||
return $item;
|
||||
}, $slider_images);
|
||||
}
|
||||
$slider_images = $slider_images ? json_encode($slider_images) : '';
|
||||
$StoreProductServices->update($id, ['slider_image' => $slider_images]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存数据
|
||||
* @param array $data
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function save(array $data)
|
||||
{
|
||||
$detail = $data['attrs'];
|
||||
$attrs = $data['items'];
|
||||
$data['spec_type'] = $data['attrs'] ? 1 : 0;
|
||||
if (count($detail)) {
|
||||
$data['price'] = min(array_column($detail, 'price'));
|
||||
$data['ot_price'] = min(array_column($detail, 'ot_price'));
|
||||
$data['cost'] = min(array_column($detail, 'cost'));
|
||||
$data['stock'] = array_sum(array_column($detail, 'stock'));
|
||||
}
|
||||
unset($data['attrs'], $data['items'], $data['info']);
|
||||
if (!$data['cate_id']) throw new AdminException('请选择分类!');
|
||||
if (!$data['store_name']) throw new AdminException('请填写商品名称');
|
||||
if (!$data['unit_name']) throw new AdminException('请填写商品单位');
|
||||
if (!$data['temp_id']) throw new AdminException('请选择运费模板');
|
||||
//关联补充信息
|
||||
$relationData = [];
|
||||
$relationData['cate_id'] = $data['cate_id'] ?? [];
|
||||
$relationData['brand_id'] = $data['brand_id'] ?? [];
|
||||
$relationData['store_label_id'] = $data['store_label_id'] ?? [];
|
||||
$relationData['label_id'] = $data['label_id'] ?? [];
|
||||
$relationData['ensure_id'] = $data['ensure_id'] ?? [];
|
||||
$relationData['specs_id'] = $data['specs_id'] ?? [];
|
||||
$relationData['coupon_ids'] = $data['coupon_ids'] ?? [];
|
||||
//查询附件分类
|
||||
/** @var SystemAttachmentCategoryServices $systemAttachmentCategoryService */
|
||||
$systemAttachmentCategoryService = app()->make(SystemAttachmentCategoryServices::class);
|
||||
$AttachmentCategory = $systemAttachmentCategoryService->getOne(['name' => $this->AttachmentCategoryName]);
|
||||
//不存在则创建
|
||||
if (!$AttachmentCategory) $AttachmentCategory = $systemAttachmentCategoryService->save(['pid' => '0', 'name' => $this->AttachmentCategoryName, 'enname' => '']);
|
||||
//生成附件目录
|
||||
try {
|
||||
if (make_path('attach', 3, true) === '')
|
||||
throw new AdminException('无法创建文件夹,请检查您的上传目录权限:' . app()->getRootPath() . 'public' . DS . 'uploads' . DS . 'attach' . DS);
|
||||
} catch (\Exception $e) {
|
||||
throw new AdminException($e->getMessage() . '或无法创建文件夹,请检查您的上传目录权限:' . app()->getRootPath() . 'public' . DS . 'uploads' . DS . 'attach' . DS);
|
||||
}
|
||||
ini_set("max_execution_time", '600');
|
||||
/** @var StoreProductServices $storeProductServices */
|
||||
$storeProductServices = app()->make(StoreProductServices::class);
|
||||
/** @var StoreProductAttrServices $storeProductAttrServices */
|
||||
$storeProductAttrServices = app()->make(StoreProductAttrServices::class);
|
||||
//开始图片下载处理
|
||||
$this->transaction(function () use ($attrs, $detail, $data, $AttachmentCategory, $storeProductServices, $storeProductAttrServices, $relationData) {
|
||||
//放入主图
|
||||
$images = [
|
||||
['w' => 305, 'h' => 305, 'line' => $data['image'], 'valuename' => 'image']
|
||||
];
|
||||
//放入轮播图
|
||||
foreach ($data['slider_image'] as $item) {
|
||||
$value = ['w' => 640, 'h' => 640, 'line' => $item, 'valuename' => 'slider_image', 'isTwoArray' => true];
|
||||
$images[] = $value;
|
||||
}
|
||||
//执行下载
|
||||
$res = $this->uploadImage($images, false, 0, $AttachmentCategory['id']);
|
||||
if (!is_array($res)) throw new AdminException($this->errorInfo ? $this->errorInfo : '保存图片失败');
|
||||
if (isset($res['image'])) $data['image'] = $res['image'];
|
||||
if (isset($res['slider_image'])) $data['slider_image'] = $res['slider_image'];
|
||||
$data['image'] = str_replace('\\', '/', $data['image']);
|
||||
if (count($data['slider_image'])) {
|
||||
$data['slider_image'] = array_map(function ($item) {
|
||||
$item = str_replace('\\', '/', $item);
|
||||
return $item;
|
||||
}, $data['slider_image']);
|
||||
}
|
||||
$data['slider_image'] = count($data['slider_image']) ? json_encode($data['slider_image']) : '';
|
||||
//替换并下载详情里面的图片默认下载全部图片
|
||||
$data['description'] = preg_replace('#<style>.*?</style>#is', '', $data['description']);
|
||||
$data['description'] = $this->uploadImage($data['description_images'], $data['description'], 1, $AttachmentCategory['id']);
|
||||
unset($data['description_images']);
|
||||
$description = $data['description'];
|
||||
unset($data['description']);
|
||||
$data['add_time'] = time();
|
||||
$data['cate_id'] = implode(',', $data['cate_id']);
|
||||
$productInfo = $storeProductServices->getOne(['soure_link' => $data['soure_link']]);
|
||||
if ($productInfo) {
|
||||
$is_new = 0;
|
||||
$id = $productInfo['id'];
|
||||
$productInfo->slider_image = $data['slider_image'];
|
||||
$productInfo->image = $data['image'];
|
||||
$productInfo->store_name = $data['store_name'];
|
||||
$res = $storeProductServices->update($productInfo->id, $data);
|
||||
$skuList = [];
|
||||
} else {
|
||||
$is_new = 1;
|
||||
$data['code_path'] = '';
|
||||
$data['spu'] = $this->createSpu();
|
||||
if ($data['spec_type'] == 0) {
|
||||
$attrs = [
|
||||
[
|
||||
'value' => '规格',
|
||||
'detailValue' => '',
|
||||
'attrHidden' => '',
|
||||
'detail' => ['默认']
|
||||
]
|
||||
];
|
||||
$detail[0]['value1'] = '规格';
|
||||
$detail[0]['detail'] = ['规格' => '默认'];
|
||||
}
|
||||
$res = $storeProductServices->save($data);
|
||||
$id = $res['id'] ?? 0;
|
||||
$skuList = $storeProductAttrServices->validateProductAttr($attrs, $detail, (int)$res['id']);
|
||||
$attrRes = $storeProductAttrServices->saveProductAttr($skuList, (int)$res['id'], 0);
|
||||
}
|
||||
if (!$res) throw new AdminException('保存失败');
|
||||
event('product.create', [$id, $data, $skuList, $is_new, [], $description, 1, $relationData]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传图片处理
|
||||
* @param array $images
|
||||
* @param string $html
|
||||
* @param int $uploadType
|
||||
* @param int $AttachmentCategoryId
|
||||
* @return array|bool|string|string[]|null
|
||||
*/
|
||||
public function uploadImage(array $images = [], $html = '', $uploadType = 0, $AttachmentCategoryId = 0)
|
||||
{
|
||||
/** @var SystemAttachmentServices $systemAttachmentService */
|
||||
$systemAttachmentService = app()->make(SystemAttachmentServices::class);
|
||||
$uploadImage = [];
|
||||
$siteUrl = sys_config('site_url');
|
||||
switch ($uploadType) {
|
||||
case 0:
|
||||
foreach ($images as $item) {
|
||||
//下载图片文件
|
||||
if ($item['w'] && $item['h'])
|
||||
$uploadValue = $this->downloadImage($item['line'], '', 0, 30, $item['w'], $item['h']);
|
||||
else
|
||||
$uploadValue = $this->downloadImage($item['line']);
|
||||
//下载成功更新数据库
|
||||
if (is_array($uploadValue)) {
|
||||
// 拼接图片地址
|
||||
if ($uploadValue['image_type'] == 1) $imagePath = $siteUrl . $uploadValue['path'];
|
||||
else $imagePath = $uploadValue['path'];
|
||||
//写入数据库
|
||||
if (!$uploadValue['is_exists'] && $AttachmentCategoryId) {
|
||||
$systemAttachmentService->save([
|
||||
'name' => $uploadValue['name'],
|
||||
'real_name' => $uploadValue['name'],
|
||||
'att_dir' => $imagePath,
|
||||
'satt_dir' => $imagePath,
|
||||
'att_size' => $uploadValue['size'],
|
||||
'att_type' => $uploadValue['mime'],
|
||||
'image_type' => $uploadValue['image_type'],
|
||||
'module_type' => 1,
|
||||
'time' => time(),
|
||||
'pid' => $AttachmentCategoryId
|
||||
]);
|
||||
}
|
||||
//组装数组
|
||||
if (isset($item['isTwoArray']) && $item['isTwoArray'])
|
||||
$uploadImage[$item['valuename']][] = $imagePath;
|
||||
else
|
||||
$uploadImage[$item['valuename']] = $imagePath;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
preg_match_all('#<img.*?src="([^"]*)"[^>]*>#i', $html, $match);
|
||||
if (isset($match[1])) {
|
||||
foreach ($match[1] as $item) {
|
||||
if (is_int(strpos($item, 'http')))
|
||||
$arcurl = $item;
|
||||
else
|
||||
$arcurl = 'http://' . ltrim($item, '\//');
|
||||
$uploadValue = $this->downloadImage($arcurl);
|
||||
//下载成功更新数据库
|
||||
if (is_array($uploadValue)) {
|
||||
// 拼接图片地址
|
||||
if ($uploadValue['image_type'] == 1) $imagePath = $siteUrl . $uploadValue['path'];
|
||||
else $imagePath = $uploadValue['path'];
|
||||
//写入数据库
|
||||
if (!$uploadValue['is_exists'] && $AttachmentCategoryId) {
|
||||
$systemAttachmentService->save([
|
||||
'name' => $uploadValue['name'],
|
||||
'real_name' => $uploadValue['name'],
|
||||
'att_dir' => $imagePath,
|
||||
'satt_dir' => $imagePath,
|
||||
'att_size' => $uploadValue['size'],
|
||||
'att_type' => $uploadValue['mime'],
|
||||
'image_type' => $uploadValue['image_type'],
|
||||
'module_type' => 1,
|
||||
'time' => time(),
|
||||
'pid' => $AttachmentCategoryId
|
||||
]);
|
||||
}
|
||||
//替换图片
|
||||
$html = str_replace($item, $imagePath, $html);
|
||||
} else {
|
||||
//替换掉没有下载下来的图片
|
||||
$html = preg_replace('#<img.*?src="' . $item . '"*>#i', '', $html);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $html;
|
||||
break;
|
||||
default:
|
||||
throw new AdminException('上传方式错误');
|
||||
break;
|
||||
}
|
||||
return $uploadImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param string $name
|
||||
* @param int $type
|
||||
* @param int $timeout
|
||||
* @param int $w
|
||||
* @param int $h
|
||||
* @return string
|
||||
*/
|
||||
public function downloadImage($url = '', $name = '', $type = 0, $timeout = 30, $w = 0, $h = 0)
|
||||
{
|
||||
if (!strlen(trim($url))) return '';
|
||||
if (!strlen(trim($name))) {
|
||||
// 获取要下载的文件名称
|
||||
$downloadImageInfo = $this->getImageExtname($url);
|
||||
$name = $downloadImageInfo['file_name'];
|
||||
$ext = $downloadImageInfo['ext_name'];
|
||||
if (!strlen(trim($name))) return '';
|
||||
} else {
|
||||
$ext = $this->getImageExtname($name)['ext_name'];
|
||||
}
|
||||
if (!in_array($ext, ['png', 'jpg', 'jpeg', 'gif'])) {
|
||||
throw new ValidateException('格式错误,文件后缀不允许');
|
||||
}
|
||||
|
||||
// 获取远程文件所采用的方法
|
||||
if ($type) {
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, false);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 跳过证书检查
|
||||
if (stripos($url, "https://") !== FALSE) curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); // 从证书中检查SSL加密算法是否存在
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, array('user-agent:' . $_SERVER['HTTP_USER_AGENT']));
|
||||
if (ini_get('open_basedir') == '' && ini_get('safe_mode') == 'Off') curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);// 是否采集301、302之后的页面
|
||||
$content = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
} else {
|
||||
try {
|
||||
ob_start();
|
||||
if (substr($url, 0, 2) == '//') {
|
||||
$url = "https:" . $url;
|
||||
}
|
||||
readfile($url);
|
||||
$content = ob_get_contents();
|
||||
ob_end_clean();
|
||||
} catch (\Exception $e) {
|
||||
throw new AdminException($e->getMessage());
|
||||
}
|
||||
}
|
||||
$size = strlen(trim($content));
|
||||
if (!$content || $size <= 2) throw new AdminException('图片流获取失败');
|
||||
$date_dir = date('Y') . '/' . date('m') . '/' . date('d');
|
||||
$upload_type = sys_config('upload_type', 1);
|
||||
$upload = UploadService::init($upload_type);
|
||||
if ($upload->to('attach/' . $date_dir)->validate()->stream($content, $name) === false) {
|
||||
throw new AdminException($upload->getError());
|
||||
}
|
||||
$imageInfo = $upload->getUploadInfo();
|
||||
$date['path'] = $imageInfo['dir'];
|
||||
$date['name'] = $imageInfo['name'];
|
||||
$date['size'] = $imageInfo['size'];
|
||||
$date['mime'] = $imageInfo['type'];
|
||||
$date['image_type'] = $upload_type;
|
||||
$date['is_exists'] = false;
|
||||
return $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取即将要下载的图片扩展名
|
||||
* @param string $url
|
||||
* @param string $ex
|
||||
* @return array|string[]
|
||||
*/
|
||||
public function getImageExtname($url = '', $ex = 'jpg')
|
||||
{
|
||||
$_empty = ['file_name' => '', 'ext_name' => $ex];
|
||||
if (!$url) return $_empty;
|
||||
if (strpos($url, '?')) {
|
||||
$_tarr = explode('?', $url);
|
||||
$url = trim($_tarr[0]);
|
||||
}
|
||||
$arr = explode('.', $url);
|
||||
if (!is_array($arr) || count($arr) <= 1) return $_empty;
|
||||
$ext_name = trim($arr[count($arr) - 1]);
|
||||
$ext_name = !$ext_name ? $ex : $ext_name;
|
||||
return ['file_name' => md5($url) . '.' . $ext_name, 'ext_name' => $ext_name];
|
||||
}
|
||||
|
||||
/**
|
||||
* SPU
|
||||
* @return string
|
||||
*/
|
||||
public function createSpu()
|
||||
{
|
||||
mt_srand();
|
||||
return substr(implode('', array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8) . str_pad((string)mt_rand(1, 99999), 5, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程图片并上传
|
||||
* @param $image
|
||||
* @return false|mixed|string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function downloadCopyImage($image)
|
||||
{
|
||||
//查询附件分类
|
||||
/** @var SystemAttachmentCategoryServices $systemAttachmentCategoryService */
|
||||
$attachmentCategoryService = app()->make(SystemAttachmentCategoryServices::class);
|
||||
$AttachmentCategory = $attachmentCategoryService->getOne(['name' => '远程下载']);
|
||||
//不存在则创建
|
||||
if (!$AttachmentCategory) {
|
||||
$AttachmentCategory = $systemAttachmentCategoryService->save(['pid' => '0', 'name' => '远程下载', 'enname' => '']);
|
||||
}
|
||||
|
||||
//生成附件目录
|
||||
if (make_path('attach', 3, true) === '') {
|
||||
throw new AdminException('无法创建文件夹,请检查您的上传目录权限:' . app()->getRootPath() . 'public' . DS . 'uploads' . DS . 'attach' . DS);
|
||||
}
|
||||
|
||||
//上传图片
|
||||
/** @var SystemAttachmentServices $systemAttachmentService */
|
||||
$systemAttachmentService = app()->make(SystemAttachmentServices::class);
|
||||
$siteUrl = sys_config('site_url');
|
||||
$uploadValue = $this->downloadImage($image);
|
||||
if (is_array($uploadValue)) {
|
||||
//TODO 拼接图片地址
|
||||
if ($uploadValue['image_type'] == 1) {
|
||||
$imagePath = $siteUrl . $uploadValue['path'];
|
||||
} else {
|
||||
$imagePath = $uploadValue['path'];
|
||||
}
|
||||
//写入数据库
|
||||
if (!$uploadValue['is_exists'] && $AttachmentCategory['id']) {
|
||||
$systemAttachmentService->save([
|
||||
'name' => $uploadValue['name'],
|
||||
'real_name' => $uploadValue['name'],
|
||||
'att_dir' => $imagePath,
|
||||
'satt_dir' => $imagePath,
|
||||
'att_size' => $uploadValue['size'],
|
||||
'att_type' => $uploadValue['mime'],
|
||||
'image_type' => $uploadValue['image_type'],
|
||||
'module_type' => 1,
|
||||
'time' => time(),
|
||||
'pid' => $AttachmentCategory['id']
|
||||
]);
|
||||
}
|
||||
return $imagePath;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
66
app/services/product/product/StoreDescriptionServices.php
Normal file
66
app/services/product/product/StoreDescriptionServices.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?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\product\product;
|
||||
|
||||
|
||||
use app\dao\product\product\StoreDescriptionDao;
|
||||
use app\services\BaseServices;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* Class StoreDescriptionService
|
||||
* @package app\services\product\product
|
||||
* @mixin StoreDescriptionDao
|
||||
*/
|
||||
class StoreDescriptionServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var StoreDescriptionDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreDescriptionDao $dao;
|
||||
|
||||
/**
|
||||
* 获取商品详情
|
||||
* @param array $where
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription(array $where)
|
||||
{
|
||||
$info = $this->dao->getDescription($where);
|
||||
if ($info) return htmlspecialchars_decode($info->description);
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存商品详情
|
||||
* @param int $id
|
||||
* @param string $description
|
||||
* @param int $type
|
||||
* @return bool
|
||||
*/
|
||||
public function saveDescription(int $id, string $description, int $type = 0)
|
||||
{
|
||||
$description = htmlspecialchars($description);
|
||||
$data = ['product_id' => $id, 'type' => $type];
|
||||
$info = $this->dao->count($data);
|
||||
if ($info) {
|
||||
$res = $this->dao->update($data, ['description' => $description]);
|
||||
} else {
|
||||
$data['description'] = $description;
|
||||
$res = $this->dao->save($data);
|
||||
}
|
||||
if (!$res) throw new AdminException('商品详情保存失败!');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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\product\product;
|
||||
|
||||
|
||||
use app\jobs\product\ProductBatchJob;
|
||||
use app\jobs\product\ProductCouponJob;
|
||||
use app\jobs\product\ProductRelationJob;
|
||||
use app\services\BaseServices;
|
||||
use app\dao\product\product\StoreProductDao;
|
||||
use app\services\product\category\StoreProductCategoryServices;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
/**
|
||||
* 商品批量操作
|
||||
* Class StoreProductBatchProcessServices
|
||||
* @package app\services\product\product
|
||||
* @mixin StoreProductDao
|
||||
*/
|
||||
class StoreProductBatchProcessServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* 批量处理参数
|
||||
* @var array[]
|
||||
*/
|
||||
protected array $data = [
|
||||
'cate_id' => [],//分类ids
|
||||
'store_label_id' => [],//商品标签
|
||||
'brand_id' => [],//商品品牌
|
||||
'delivery_type' => [],//物流方式1:快递,2:门店自提,3:门店配送
|
||||
'freight' => 1,//运费设置1:包邮,2:固定运费,3:运费模版
|
||||
'postage' => 0,//邮费金额
|
||||
'temp_id' => 0,//运费模版
|
||||
'give_integral' => 0,//赠送积分
|
||||
'coupon_ids' => [],//赠送优惠券ids
|
||||
'label_id' => [],//关联用户标签ids
|
||||
'recommend' => [],//活动推荐:is_hot、is_benefit、is_new、is_best、is_good
|
||||
// 'custom_form' => [],//自定义留言
|
||||
'system_form_id' => 0,//系统表单
|
||||
];
|
||||
|
||||
/**
|
||||
* @var StoreProductDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreProductDao $dao;
|
||||
|
||||
/**
|
||||
* 根据搜索条件查询ids
|
||||
* @param $where
|
||||
* @return array
|
||||
*/
|
||||
public function getIdsByWhere($where)
|
||||
{
|
||||
$ids = [];
|
||||
$cateIds = [];
|
||||
if (isset($where['cate_id']) && $where['cate_id']) {
|
||||
/** @var StoreProductCategoryServices $storeCategory */
|
||||
$storeCategory = app()->make(StoreProductCategoryServices::class);
|
||||
$cateIds = $storeCategory->getColumn(['pid', 'in', $where['cate_id']], 'id');
|
||||
}
|
||||
if ($cateIds) {
|
||||
$cateIds[] = $where['cate_id'];
|
||||
$where['cate_id'] = $cateIds;
|
||||
}
|
||||
/** @var StoreProductServices $productService */
|
||||
$productService = app()->make(StoreProductServices::class);
|
||||
$dataInfo = $productService->getProductListByWhere($where, 'id');
|
||||
if ($dataInfo) {
|
||||
$ids = array_unique(array_column($dataInfo, 'id'));
|
||||
}
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品批量操作
|
||||
* @param int $type
|
||||
* @param array $ids
|
||||
* @param array $input_data
|
||||
* @param bool $is_all
|
||||
* @param array $where
|
||||
* @return bool
|
||||
*/
|
||||
public function batchProcess(int $type, array $ids, array $input_data, bool $is_all = false, array $where = [])
|
||||
{
|
||||
//全选
|
||||
if ($is_all == 1) {
|
||||
$ids = $this->getIdsByWhere($where);
|
||||
}
|
||||
$data = [];
|
||||
$isBatch = true;
|
||||
switch ($type) {
|
||||
case 1://分类
|
||||
$isBatch = false;
|
||||
$cate_id = $input_data['cate_id'] ?? 0;
|
||||
if (!$cate_id) throw new ValidateException('请选择分类');
|
||||
|
||||
$data['cate_id'] = $cate_id;
|
||||
break;
|
||||
case 2://商品标签 不选默认清空标签
|
||||
$store_label_id = $input_data['store_label_id'] ?? [];
|
||||
$data['store_label_id'] = $store_label_id;
|
||||
break;
|
||||
case 3://物流设置
|
||||
$data['delivery_type'] = $input_data['delivery_type'] ?? [];
|
||||
if (!$data['delivery_type']) throw new AdminException('请选择商品配送方式');
|
||||
break;
|
||||
case 4://购买即送积分、优惠券
|
||||
$isBatch = false;
|
||||
$data['give_integral'] = $input_data['give_integral'] ?? 0;
|
||||
$data['coupon_ids'] = $input_data['coupon_ids'] ?? [];
|
||||
if (!$data['give_integral'] && !$data['coupon_ids']) {
|
||||
throw new AdminException('请输入赠送积分或选择赠送优惠券');
|
||||
}
|
||||
break;
|
||||
case 5://关联用户标签 不选默认清空标签
|
||||
$label_id = $input_data['label_id'] ?? [];
|
||||
$data['label_id'] = $label_id;
|
||||
break;
|
||||
case 6://活动推荐
|
||||
$recommend = $input_data['recommend'] ?? [];
|
||||
$data['is_hot'] = $data['is_benefit'] = $data['is_new'] = $data['is_good'] = $data['is_best'] = 0;
|
||||
if ($recommend) {
|
||||
$arr = ['is_hot', 'is_benefit', 'is_new', 'is_good', 'is_best'];
|
||||
foreach ($recommend as $item) {
|
||||
if (in_array($item, $arr)) {
|
||||
$data[$item] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 7://自定义留言 可以为空 清空之前的设置
|
||||
$data['system_form_id'] = $input_data['system_form_id'] ?? 0;
|
||||
break;
|
||||
case 8://运费设置
|
||||
$data['freight'] = $input_data['freight'] ?? 0;
|
||||
$data['postage'] = $input_data['postage'] ?? 0;
|
||||
$data['temp_id'] = $input_data['temp_id'] ?? 0;
|
||||
if ($data['freight'] == 2 && !$data['postage']) {
|
||||
throw new AdminException('请设置运费金额');
|
||||
}
|
||||
if ($data['freight'] == 3 && !$data['temp_id']) {
|
||||
throw new AdminException('请选择运费模版');
|
||||
}
|
||||
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;
|
||||
}
|
||||
break;
|
||||
case 9://商品品牌 不选默认清空标签
|
||||
$data['brand_com'] = $input_data['brand_id'] ? implode(',', $input_data['brand_id']) : '';
|
||||
$data['brand_id'] = $input_data['brand_id'] ? end($input_data['brand_id']) : 0;
|
||||
break;
|
||||
case 10://商品佣金设置
|
||||
$data['brokerage'] = $input_data['brokerage'] ?? 0;
|
||||
$data['brokerage_two'] = $input_data['brokerage_two'] ?? 0;
|
||||
break;
|
||||
default:
|
||||
throw new AdminException('暂不支持该类型批操作');
|
||||
}
|
||||
//加入批量队列
|
||||
ProductBatchJob::dispatchDo('productBatch', [$type, $ids, $data, $isBatch]);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行批量修改eb_store_product
|
||||
* @param array $ids
|
||||
* @param array $data
|
||||
* @return bool
|
||||
*/
|
||||
public function runBatch(array $ids, array $data, int $type = 2)
|
||||
{
|
||||
if (!$ids || !$data) {
|
||||
return false;
|
||||
}
|
||||
if (isset($data['delivery_type']) && $data['delivery_type']) {
|
||||
$data['delivery_type'] = is_array($data['delivery_type']) ? implode(',', $data['delivery_type']) : $data['delivery_type'];
|
||||
}
|
||||
switch ($type) {
|
||||
case 2://商品标签
|
||||
$this->dao->batchUpdate($ids, ['store_label_id' => implode(',', $data['store_label_id'])], 'id');
|
||||
foreach ($ids as $id) {
|
||||
ProductRelationJob::dispatch([$id, $data['store_label_id'], 3]);
|
||||
}
|
||||
break;
|
||||
case 5://用户标签
|
||||
$this->dao->batchUpdate($ids, ['label_id' => implode(',', $data['label_id'])], 'id');
|
||||
foreach ($ids as $id) {
|
||||
ProductRelationJob::dispatch([$id, $data['label_id'], 4]);
|
||||
}
|
||||
break;
|
||||
case 6://活动推荐 用商品标签关联
|
||||
$this->dao->batchUpdate($ids, $data, 'id');
|
||||
$arr = ['is_hot' => 1, 'is_benefit' => 2, 'is_best' => 3, 'is_new' => 4, 'is_good' => 5];
|
||||
$label_ids = [];
|
||||
foreach ($data as $key => $value) {
|
||||
$label_id = $arr[$key] ?? 0;
|
||||
if (!$label_id || !$value) continue;
|
||||
$label_ids[] = $label_id;
|
||||
}
|
||||
foreach ($ids as $id) {
|
||||
ProductRelationJob::dispatch([$id, $label_ids, 3]);
|
||||
}
|
||||
break;
|
||||
case 9:// 商品品牌
|
||||
$this->dao->batchUpdate($ids, ['brand_id' => $data['brand_id'], 'brand_com' => $data['brand_com']], 'id');
|
||||
foreach ($ids as $id) {
|
||||
ProductRelationJob::dispatch([$id, $data['brand_id'], 2]);
|
||||
}
|
||||
break;
|
||||
case 10://商品佣金
|
||||
foreach ($ids as $id) {
|
||||
ProductBrokerageJob::dispatch([$id, $data['brokerage'], $data['brokerage_two']]);
|
||||
}
|
||||
break;
|
||||
default://
|
||||
$this->dao->batchUpdate($ids, $data, 'id');
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存商品分类
|
||||
* @param int $id
|
||||
* @param array $data
|
||||
* @return bool
|
||||
*/
|
||||
public function setPrdouctCate(int $id, array $data)
|
||||
{
|
||||
if (!$id || !$data) {
|
||||
return true;
|
||||
}
|
||||
$cate_id = $data['cate_id'] ?? 0;
|
||||
if ($cate_id) {
|
||||
$this->dao->update($id, ['cate_id' => implode(',', $cate_id)]);
|
||||
//商品分类关联
|
||||
ProductRelationJob::dispatch([$id, $cate_id, 1]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存商品赠送积分、优惠券
|
||||
* @param int $id
|
||||
* @param array $data
|
||||
* @return bool
|
||||
*/
|
||||
public function setGiveIntegralCoupon(int $id, array $data)
|
||||
{
|
||||
if (!$id || !$data) {
|
||||
return true;
|
||||
}
|
||||
$give_integral = $data['give_integral'] ?? 0;
|
||||
if ($give_integral) {
|
||||
$this->dao->update($id, ['give_integral' => $give_integral]);
|
||||
}
|
||||
$coupon_ids = $data['coupon_ids'] ?? [];
|
||||
if ($coupon_ids) {
|
||||
//商品关联优惠券
|
||||
ProductCouponJob::dispatchDo('setProductCoupon', [$id, $coupon_ids]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
70
app/services/product/product/StoreProductCateServices.php
Normal file
70
app/services/product/product/StoreProductCateServices.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?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\product\product;
|
||||
|
||||
|
||||
use app\dao\product\product\StoreProductCateDao;
|
||||
use app\services\BaseServices;
|
||||
use app\services\product\category\StoreProductCategoryServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* Class StoreProductCateService
|
||||
* @package app\services\product\product
|
||||
* @mixin StoreProductCateDao
|
||||
*/
|
||||
class StoreProductCateServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var StoreProductCateDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreProductCateDao $dao;
|
||||
|
||||
/**
|
||||
* 保存商品分类关联
|
||||
* @param int $id
|
||||
* @param array $cate_id
|
||||
* @param int $is_show
|
||||
* @return bool
|
||||
*/
|
||||
public function saveCate(int $id, array $cate_id, int $is_show = 0)
|
||||
{
|
||||
$cateData = [];
|
||||
if ($cate_id) {
|
||||
$time = time();
|
||||
/** @var StoreProductCategoryServices $storeCategoryServices */
|
||||
$storeCategoryServices = app()->make(StoreProductCategoryServices::class);
|
||||
$cateGory = $storeCategoryServices->getColumn([['id', 'IN', $cate_id]], 'id,pid', 'id');
|
||||
foreach ($cate_id as $cid) {
|
||||
if ($cid && isset($cateGory[$cid]['pid'])) {
|
||||
$cateData[] = ['product_id' => $id, 'cate_id' => $cid, 'cate_pid' => $cateGory[$cid]['pid'], 'status' => $is_show, 'add_time' => $time];
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->change($id, $cateData);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品添加修改商品分类关联
|
||||
* @param $id
|
||||
* @param $cateData
|
||||
*/
|
||||
public function change($id, $cateData)
|
||||
{
|
||||
$this->dao->delete(['product_id' => $id]);
|
||||
if ($cateData) $this->dao->saveAll($cateData);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
141
app/services/product/product/StoreProductCouponServices.php
Normal file
141
app/services/product/product/StoreProductCouponServices.php
Normal file
@@ -0,0 +1,141 @@
|
||||
<?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\product\product;
|
||||
|
||||
use app\services\BaseServices;
|
||||
use app\dao\product\product\StoreProductCouponDao;
|
||||
use app\services\activity\coupon\StoreCouponIssueServices;
|
||||
use app\services\order\StoreOrderCartInfoServices;
|
||||
use app\services\order\StoreOrderServices;
|
||||
use app\services\user\UserServices;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use crmeb\services\CacheService;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class StoreProductCouponServices
|
||||
* @package app\services\coupon
|
||||
* @mixin StoreProductCouponDao
|
||||
*/
|
||||
class StoreProductCouponServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var StoreProductCouponDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreProductCouponDao $dao;
|
||||
|
||||
/**
|
||||
* 商品关联优惠券
|
||||
* @param int $id
|
||||
* @param array $coupon_ids
|
||||
* @return bool
|
||||
*/
|
||||
public function setCoupon(int $id, array $coupon_ids)
|
||||
{
|
||||
$this->dao->delete(['product_id' => $id]);
|
||||
if ($coupon_ids) {
|
||||
$data = $data_all = [];
|
||||
$data['product_id'] = $id;
|
||||
$data['add_time'] = time();
|
||||
foreach ($coupon_ids as $cid) {
|
||||
if (!empty($cid) && (int)$cid) {
|
||||
$data['issue_coupon_id'] = $cid;
|
||||
$data_all[] = $data;
|
||||
}
|
||||
}
|
||||
$res = true;
|
||||
if ($data_all) {
|
||||
$res = $this->dao->saveAll($data_all);
|
||||
}
|
||||
if (!$res) throw new AdminException('关联优惠券失败!');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下单赠送优惠券
|
||||
* @param int $uid
|
||||
* @param string $orderId
|
||||
* @param $order
|
||||
* @return array|mixed
|
||||
*/
|
||||
public function getOrderProductCoupon(int $uid, string $orderId, $order = [])
|
||||
{
|
||||
if (!$uid || !$orderId) {
|
||||
return [];
|
||||
}
|
||||
if (!$order) {
|
||||
/** @var StoreOrderServices $storeOrder */
|
||||
$storeOrder = app()->make(StoreOrderServices::class);
|
||||
$order = $storeOrder->getOne(['order_id' => $orderId]);
|
||||
}
|
||||
if (!$order || $order['uid'] != $uid) {
|
||||
throw new ValidateException('订单不存在');
|
||||
}
|
||||
$key = 'order_product_coupon_' . $uid . '_' . $order['id'];
|
||||
return CacheService::redisHandler()->get($key, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下单赠送优惠劵
|
||||
* @param int $uid
|
||||
* @param int $orderId
|
||||
* @return bool
|
||||
*/
|
||||
public function giveOrderProductCoupon(int $uid, int $orderId)
|
||||
{
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$user = $userServices->getUserInfo($uid);
|
||||
if (!$user) {
|
||||
throw new ValidateException('用户不存在');
|
||||
}
|
||||
/** @var StoreOrderServices $storeOrder */
|
||||
$storeOrder = app()->make(StoreOrderServices::class);
|
||||
$order = $storeOrder->getOne(['id' => $orderId]);
|
||||
if (!$order || $order['uid'] != $uid) {
|
||||
throw new ValidateException('订单不存在');
|
||||
}
|
||||
/** @var StoreOrderCartInfoServices $storeOrderCartInfo */
|
||||
$storeOrderCartInfo = app()->make(StoreOrderCartInfoServices::class);
|
||||
$productIds = $storeOrderCartInfo->getColumn(['oid' => $order['id']], 'product_id');
|
||||
$list = [];
|
||||
if ($productIds) {
|
||||
$couponList = $this->dao->getProductCoupon($productIds);
|
||||
if ($couponList) {
|
||||
/** @var StoreCouponIssueServices $storeCoupon */
|
||||
$storeCoupon = app()->make(StoreCouponIssueServices::class);
|
||||
$list = $storeCoupon->orderPayGiveCoupon($uid, array_column((array)$couponList, 'issue_coupon_id'));
|
||||
if ($list) {
|
||||
$ids = array_column($list, 'cid');
|
||||
$coupons = $storeCoupon->getColumn(['id' => $ids], 'id,type,coupon_type,product_id,category_id,brand_id', 'id');
|
||||
foreach ($list as &$item) {
|
||||
$item['applicable_type'] = $coupons[$item['cid']]['type'] ?? 1;
|
||||
$item['coupon_type'] = $coupons[$item['cid']]['coupon_type'] ?? 1;
|
||||
$item['product_id'] = $coupons[$item['cid']]['product_id'] ?? 1;
|
||||
$item['category_id'] = $coupons[$item['cid']]['category_id'] ?? 1;
|
||||
$item['brand_id'] = $coupons[$item['cid']]['brand_id'] ?? 1;
|
||||
$item['add_time'] = date('Y-m-d', $item['add_time']);
|
||||
$item['end_time'] = date('Y-m-d', $item['end_time']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$key = 'order_product_coupon_' . $uid . '_' . $orderId;
|
||||
CacheService::redisHandler()->set($key, $list, 7200);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
183
app/services/product/product/StoreProductLogServices.php
Normal file
183
app/services/product/product/StoreProductLogServices.php
Normal file
@@ -0,0 +1,183 @@
|
||||
<?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\product\product;
|
||||
|
||||
|
||||
use app\dao\product\product\StoreProductLogDao;
|
||||
use app\services\order\StoreOrderCartInfoServices;
|
||||
use app\services\BaseServices;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
/**
|
||||
* 商品访问记录日志
|
||||
* Class StoreProductLogServices
|
||||
* @package app\services\product\product
|
||||
* @mixin StoreProductLogDao
|
||||
*/
|
||||
class StoreProductLogServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var StoreProductLogDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreProductLogDao $dao;
|
||||
|
||||
/**
|
||||
* 创建各种访问日志
|
||||
* @param string $type
|
||||
* @param array $data
|
||||
* @return bool
|
||||
*/
|
||||
public function createLog(string $type, array $data)
|
||||
{
|
||||
if (!in_array($type, ['order', 'pay', 'refund']) && (!isset($data['product_id']) || !$data['product_id'])) {
|
||||
throw new ValidateException('缺少商品ID');
|
||||
}
|
||||
$log_data = $log_data_all = [];
|
||||
$log_data['type'] = $type;
|
||||
$log_data['uid'] = $data['uid'] ?? 0;
|
||||
$log_data['add_time'] = time();
|
||||
switch ($type) {
|
||||
case 'visit'://访问
|
||||
case 'cart'://加入购物车
|
||||
case 'collect'://收藏
|
||||
$key = $type . '_num';
|
||||
$log_data[$key] = isset($data[$key]) && $data[$key] ? $data[$key] : 1;
|
||||
$log_data['product_id'] = 0;
|
||||
if (isset($data['product_id']) && $data['product_id']) {
|
||||
if (is_array($data['product_id'])) {
|
||||
foreach ($data['product_id'] as $key => $product_id) {
|
||||
$log_data['product_id'] = $product_id;
|
||||
$log_data_all[] = $log_data;
|
||||
}
|
||||
} else {
|
||||
$log_data['product_id'] = $data['product_id'];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'order'://下单
|
||||
if (!isset($data['order_id']) || !$data['order_id']) {
|
||||
throw new ValidateException('缺少订单ID');
|
||||
}
|
||||
/** @var StoreOrderCartInfoServices $cartInfoServices */
|
||||
$cartInfoServices = app()->make(StoreOrderCartInfoServices::class);
|
||||
$cartInfo = $cartInfoServices->getOrderCartInfo((int)$data['order_id']);
|
||||
foreach ($cartInfo as $value) {
|
||||
$product = $value['cart_info'];
|
||||
$log_data['product_id'] = $product['product_id'] ?? 0;
|
||||
$log_data['order_num'] = $product['cart_num'] ?? 1;
|
||||
$log_data_all[] = $log_data;
|
||||
}
|
||||
break;
|
||||
case 'pay'://支付
|
||||
if (!isset($data['order_id']) || !$data['order_id']) {
|
||||
throw new ValidateException('缺少订单ID');
|
||||
}
|
||||
/** @var StoreOrderCartInfoServices $cartInfoServices */
|
||||
$cartInfoServices = app()->make(StoreOrderCartInfoServices::class);
|
||||
$cartInfo = $cartInfoServices->getOrderCartInfo((int)$data['order_id']);
|
||||
foreach ($cartInfo as $value) {
|
||||
$product = $value['cart_info'];
|
||||
$log_data['product_id'] = $product['product_id'] ?? 0;
|
||||
$log_data['pay_num'] = $product['cart_num'] ?? 0;
|
||||
$log_data['cost_price'] = $product['costPrice'] ?? 0;
|
||||
$log_data['pay_price'] = $product['truePrice'] ?? 0;
|
||||
$log_data['pay_uid'] = $data['uid'] ?? 0;
|
||||
$log_data_all[] = $log_data;
|
||||
}
|
||||
break;
|
||||
case 'refund'://退款
|
||||
if (!isset($data['order_id']) || !$data['order_id']) {
|
||||
throw new ValidateException('缺少订单ID');
|
||||
}
|
||||
/** @var StoreOrderCartInfoServices $cartInfoServices */
|
||||
$cartInfoServices = app()->make(StoreOrderCartInfoServices::class);
|
||||
$cartInfo = $cartInfoServices->getOrderCartInfo((int)$data['order_id']);
|
||||
foreach ($cartInfo as $value) {
|
||||
$product = $value['cart_info'];
|
||||
$log_data['product_id'] = $product['product_id'] ?? 0;
|
||||
$log_data['order_num'] = $product['cart_num'] ?? 1;
|
||||
$log_data_all[] = $log_data;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ValidateException('暂不支持该类型记录');
|
||||
break;
|
||||
}
|
||||
if ($log_data_all) {
|
||||
$res = $this->dao->saveAll($log_data_all);
|
||||
} else {
|
||||
$res = $this->dao->save($log_data);
|
||||
}
|
||||
if (!$res) {
|
||||
throw new ValidateException('添加商品记录失败');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找购买商品排行
|
||||
* @param $where
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRanking(array $where)
|
||||
{
|
||||
$list = $this->dao->getRanking($where);
|
||||
foreach ($list as $key => &$item) {
|
||||
if (!$item['store_name'] || !$item['image']) {
|
||||
unset($list[$key]);
|
||||
}
|
||||
if ($item['profit'] == null) $item['profit'] = 0;
|
||||
if ($item['changes'] == null) $item['changes'] = 0;
|
||||
if ($item['repeats'] == null) {
|
||||
$item['repeats'] = 0;
|
||||
} else {
|
||||
$item['repeats'] = bcdiv($this->dao->getRepeats($where, $item['product_id']), $item['repeats'], 2);
|
||||
}
|
||||
}
|
||||
return array_merge($list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 浏览商品列表
|
||||
* @param array $where
|
||||
* @param string $group
|
||||
* @param string $field
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getList(array $where, string $group = '', string $field = '*')
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getList($where, $field, $page, $limit, $group);
|
||||
if ($group) {
|
||||
$count = $this->dao->getDistinctCount($where, $group, true);
|
||||
} else {
|
||||
$count = $this->dao->count($where);
|
||||
}
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商品日志关联的商品列表
|
||||
* @param array $where 查询条件
|
||||
* @return array
|
||||
*/
|
||||
public function getProduct(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
return $this->dao->getProduct($where, $page, $limit);
|
||||
}
|
||||
}
|
||||
103
app/services/product/product/StoreProductRankServices.php
Normal file
103
app/services/product/product/StoreProductRankServices.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?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\product\product;
|
||||
|
||||
use app\dao\product\product\StoreProductDao;
|
||||
use app\services\BaseServices;
|
||||
use app\services\user\UserServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
|
||||
/**
|
||||
* Class StoreProductRankServices
|
||||
* @package app\services\product\product
|
||||
* @mixin StoreProductDao
|
||||
*/
|
||||
class StoreProductRankServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* 排名最大名次
|
||||
* @var int
|
||||
*/
|
||||
protected int $rankMax = 20;
|
||||
|
||||
/**
|
||||
* @var StoreProductDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreProductDao $dao;
|
||||
|
||||
|
||||
/**
|
||||
* 获取商品在排行榜中排名
|
||||
* @param int $uid
|
||||
* @param int $productId
|
||||
* @param int $type
|
||||
* @return int
|
||||
*/
|
||||
public function getProductRank(int $uid, int $productId, int $type = 1)
|
||||
{
|
||||
$where['is_vip_product'] = 0;
|
||||
$where['is_verify'] = 1;
|
||||
$where['pid'] = 0;
|
||||
$where['is_show'] = 1;
|
||||
$where['is_del'] = 0;
|
||||
if ($uid) {
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$is_vip = $userServices->value(['uid' => $uid], 'is_money_level');
|
||||
$where['is_vip_product'] = $is_vip ? -1 : 0;
|
||||
}
|
||||
$field = ['id', 'IFNULL(sales,0) + IFNULL(ficti,0) as sales', 'star'];
|
||||
$order = match($type) {
|
||||
1 => 'sales desc, sort desc, id desc',//销量
|
||||
2 => 'star desc, sort desc, id desc',//评分
|
||||
3 => 'collect desc, sort desc, id desc',//收藏
|
||||
default => 'sales desc, sort desc, id desc',
|
||||
};
|
||||
$list = $this->dao->getRecommendProduct($where, $field, $this->rankMax, 0, 0, [], $order);
|
||||
$rank = 0;
|
||||
if ($list) {
|
||||
$key = array_search($productId, array_column($list, 'id'));
|
||||
if ($key !== false) {
|
||||
$rank = (int)$key + 1;
|
||||
}
|
||||
}
|
||||
return $rank;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商品排行数据
|
||||
* @param int $uid
|
||||
* @param int $type
|
||||
* @param array $where
|
||||
* @param int $limit
|
||||
* @return array|null
|
||||
* @throws \ReflectionException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* @throws \throwable
|
||||
*/
|
||||
public function getProductRankList(int $uid, int $type = 1, array $where = [], int $limit = 0)
|
||||
{
|
||||
/** @var StoreProductServices $productServices */
|
||||
$productServices = app()->make(StoreProductServices::class);
|
||||
$order = match($type) {
|
||||
1 => 'sales desc, sort desc, id desc',//销量
|
||||
2 => 'star desc, sort desc, id desc',//评分
|
||||
3 => 'collect desc, sort desc, id desc',//收藏
|
||||
default => 'sales desc, sort desc, id desc',
|
||||
};
|
||||
return $productServices->getRecommendProduct($uid, $where, $limit, 'mid', $order);
|
||||
}
|
||||
|
||||
}
|
||||
193
app/services/product/product/StoreProductRelationServices.php
Normal file
193
app/services/product/product/StoreProductRelationServices.php
Normal file
@@ -0,0 +1,193 @@
|
||||
<?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\product\product;
|
||||
|
||||
|
||||
use app\dao\product\product\StoreProductRelationDao;
|
||||
use app\services\BaseServices;
|
||||
use app\services\product\category\StoreProductCategoryServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* 商品关联关系
|
||||
* Class StoreProductRelationServices
|
||||
* @package app\services\product\product
|
||||
* @mixin StoreProductRelationDao
|
||||
*/
|
||||
class StoreProductRelationServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* 1:分类2:品牌3:商品标签4:用户标签5:保障服务6:商品参数
|
||||
* @var string[]
|
||||
*/
|
||||
protected array $type = [
|
||||
1 => '商品分类',
|
||||
2 => '商品品牌',
|
||||
3 => '商品标签',
|
||||
4 => '用户标签',
|
||||
5 => '保障服务',
|
||||
6 => '商品参数'
|
||||
];
|
||||
|
||||
/**
|
||||
* 缓存key
|
||||
* @var string[]
|
||||
*/
|
||||
protected array $typeKey = [
|
||||
1 => 'cate',
|
||||
2 => 'brand',
|
||||
3 => 'product_label',
|
||||
4 => 'user_label',
|
||||
5 => 'ensure',
|
||||
6 => 'specs'
|
||||
];
|
||||
|
||||
/**
|
||||
* @var StoreProductRelationDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreProductRelationDao $dao;
|
||||
|
||||
/**
|
||||
* 保存商品关联关系
|
||||
* @param int $id
|
||||
* @param array $relation_id
|
||||
* @param int $type
|
||||
* @param int $is_show
|
||||
* @return bool
|
||||
*/
|
||||
public function saveRelation(int $id, array $relation_id, int $type = 1, int $is_show = 1)
|
||||
{
|
||||
$cateData = [];
|
||||
if ($relation_id) {
|
||||
$time = time();
|
||||
if ($type == 1) {//分类
|
||||
/** @var StoreProductCategoryServices $storeCategoryServices */
|
||||
$storeCategoryServices = app()->make(StoreProductCategoryServices::class);
|
||||
$cateGory = $storeCategoryServices->getColumn([['id', 'IN', $relation_id]], 'id,pid', 'id');
|
||||
foreach ($relation_id as $cid) {
|
||||
if ($cid && isset($cateGory[$cid]['pid'])) {
|
||||
$cateData[] = ['type' => $type, 'product_id' => $id, 'relation_id' => $cid, 'relation_pid' => $cateGory[$cid]['pid'], 'status' => $is_show, 'add_time' => $time];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach ($relation_id as $cid) {
|
||||
$cateData[] = ['type' => $type, 'product_id' => $id, 'relation_id' => $cid, 'status' => 1, 'add_time' => $time];
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->change($id, $cateData, $type);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品添加商品关联
|
||||
* @param int $id
|
||||
* @param array $cateData
|
||||
* @param int $type
|
||||
* @return bool
|
||||
*/
|
||||
public function change(int $id, array $cateData, int $type = 1)
|
||||
{
|
||||
$this->dao->delete(['product_id' => $id, 'type' => $type]);
|
||||
if ($cateData) $this->dao->saveAll($cateData);
|
||||
$this->setProductRelationCache($id, $cateData, $type);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量设置关联状态
|
||||
* @param array $ids
|
||||
* @param int $is_show
|
||||
* @param int $type
|
||||
* @return bool
|
||||
*/
|
||||
public function setShow(array $ids, int $is_show = 1, int $type = 1)
|
||||
{
|
||||
$this->dao->setShow($ids, $is_show, $type);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置商品关联缓存
|
||||
* @param int $product_id
|
||||
* @param array $data
|
||||
* @param int $type
|
||||
* @return array
|
||||
*/
|
||||
public function setProductRelationCache(int $product_id, array $data, int $type = 1)
|
||||
{
|
||||
$key = 'cache_product_relation_' . ($this->typeKey[$type] ?? '') . '_' . $product_id;
|
||||
if ($type == 1) {
|
||||
$cacheData = $data;
|
||||
} else {
|
||||
$cacheData = array_column($data, 'relation_id');
|
||||
}
|
||||
$this->dao->cacheHander()->delete($key);
|
||||
$this->dao->cacheTag()->set($key, $cacheData);
|
||||
return $cacheData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新缓存
|
||||
* @param int $product_id
|
||||
* @param int $type
|
||||
* @param string $key
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function updateProductRelationCache(int $product_id, int $type = 1)
|
||||
{
|
||||
$data = $this->dao->getList(['product_id' => $product_id, 'type' => $type]);
|
||||
$cacheData = [];
|
||||
if ($data) {
|
||||
$cacheData = $this->setProductRelationCache($product_id, $data, $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 getProductRelationCache(int $product_id, array $type = [], bool $isCache = false)
|
||||
{
|
||||
if (!$type) {
|
||||
$typeArr = [1, 2, 3, 4, 5, 6];
|
||||
} else {
|
||||
$typeArr = $type;
|
||||
}
|
||||
$data = [];
|
||||
$typeKey = $this->typeKey;
|
||||
$key = 'cache_product_relation_';
|
||||
foreach ($typeArr as $value) {
|
||||
$key .= ($typeKey[$value] ?? '') . '_' . $product_id;
|
||||
$relation = $this->dao->cacheHander()->get($key);
|
||||
if (!$relation || $isCache) {
|
||||
$relation = $this->updateProductRelationCache($product_id, (int)$value, $key);
|
||||
}
|
||||
$data[$value] = $relation;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
<?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\product\product;
|
||||
|
||||
|
||||
use app\dao\product\product\StoreProductReplyCommentDao;
|
||||
use app\services\BaseServices;
|
||||
use app\services\user\UserRelationServices;
|
||||
use app\services\user\UserServices;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
/**
|
||||
* Class StoreProductReplyCommentServices
|
||||
* @package app\services\product\product
|
||||
* @mixin StoreProductReplyCommentDao
|
||||
*/
|
||||
class StoreProductReplyCommentServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var StoreProductReplyCommentDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreProductReplyCommentDao $dao;
|
||||
|
||||
/**
|
||||
* 获取评论回复列表
|
||||
* @param int $replyId
|
||||
* @param string $time
|
||||
* @param int $uid
|
||||
* @param bool $notUid
|
||||
* @return array
|
||||
*/
|
||||
public function getReplCommenList(int $replyId, string $time = '', int $uid = 0, bool $notUid = true)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$where = ['reply_id' => $replyId, 'pid' => 0, 'notUid' => 0, 'create_time' => $time];
|
||||
if (false === $notUid) {
|
||||
unset($where['notUid']);
|
||||
}
|
||||
$list = $this->dao->getDataList($where, ['*'], $page, $limit, ['praise' => 'desc', 'create_time' => 'desc'], [
|
||||
'user' => function ($query) {
|
||||
$query->field('uid,avatar,nickname,is_money_level');
|
||||
},
|
||||
'children' => function ($query) use ($uid) {
|
||||
$query->with([
|
||||
'user' => function ($query) {
|
||||
$query->field('uid,avatar,nickname,is_money_level');
|
||||
},
|
||||
'productRelation' => function ($query) use ($uid) {
|
||||
$query->where('uid', $uid)->where('type', UserRelationServices::TYPE_LIKE)
|
||||
->where('category', UserRelationServices::CATEGORY_COMMENT)
|
||||
->field(['uid', 'relation_id']);
|
||||
}
|
||||
]);
|
||||
},
|
||||
'productRelation' => function ($query) use ($uid) {
|
||||
$query->where('uid', $uid)->where('type', UserRelationServices::TYPE_LIKE)
|
||||
->where('category', UserRelationServices::CATEGORY_COMMENT)
|
||||
->field(['uid', 'relation_id']);
|
||||
}
|
||||
]);
|
||||
$count = $this->dao->count($where);
|
||||
$siteLogoSquare = sys_config('site_logo_square');
|
||||
$siteName = sys_config('site_name');
|
||||
|
||||
//用户是否是付费会员和等级会员
|
||||
$uids = array_column($list, 'uid');
|
||||
$uids = array_filter(array_unique($uids));
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$vipArray = $userServices->checkIsVip($uids);
|
||||
|
||||
foreach ($list as &$item) {
|
||||
if (!isset($item['user']) && $item['uid'] === 0) {
|
||||
$item['user'] = ['nickname' => $siteName, 'avatar' => $siteLogoSquare];
|
||||
}
|
||||
if (isset($item['children']) && !isset($item['children']['user']) && $item['children']['uid'] === 0) {
|
||||
$item['children']['user'] = ['nickname' => $siteName, 'avatar' => $siteLogoSquare];
|
||||
}
|
||||
if (isset($item['user']['nickname'])) {
|
||||
$item['user']['nickname'] = anonymity($item['user']['nickname']);
|
||||
}
|
||||
$item['user']['level_name'] = $vipArray[$item['uid']]['level_name'] ?? '';
|
||||
$item['user']['vip_status'] = $vipArray[$item['uid']]['vip_status'] ?? '';
|
||||
if ($uid) {
|
||||
$item['is_praise'] = !empty($item['productRelation']);
|
||||
if (isset($item['children'])) {
|
||||
$item['children']['is_praise'] = !empty($item['children']['productRelation']);
|
||||
}
|
||||
} else {
|
||||
$item['is_praise'] = false;
|
||||
if (isset($item['children'])) {
|
||||
$item['children']['is_praise'] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存回复
|
||||
* @param int $uid
|
||||
* @param int $replyId
|
||||
* @param string $content
|
||||
* @return \crmeb\basic\BaseModel|\think\Model
|
||||
*/
|
||||
public function saveComment(int $uid, int $replyId, string $content)
|
||||
{
|
||||
return $this->dao->save(['uid' => $uid, 'reply_id' => $replyId, 'content' => $content, 'create_time' => time()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 点赞回复
|
||||
* @param int $id
|
||||
* @param int $uid
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function commentPraise(int $id, int $uid)
|
||||
{
|
||||
$commentInfo = $this->dao->get($id, ['id', 'praise']);
|
||||
if (!$commentInfo) {
|
||||
throw new ValidateException('回复不存在');
|
||||
}
|
||||
$commentInfo->praise++;
|
||||
/** @var UserRelationServices $service */
|
||||
$service = app()->make(UserRelationServices::class);
|
||||
$res = $service->getUserCount($uid, $id, UserRelationServices::TYPE_LIKE, UserRelationServices::CATEGORY_COMMENT);
|
||||
if ($res) {
|
||||
return true;
|
||||
}
|
||||
$this->transaction(function () use ($id, $uid, $service, $commentInfo) {
|
||||
$res = $service->save([
|
||||
'uid' => $uid,
|
||||
'relation_id' => $id,
|
||||
'type' => UserRelationServices::TYPE_LIKE,
|
||||
'category' => UserRelationServices::CATEGORY_COMMENT,
|
||||
'add_time' => time()
|
||||
]);
|
||||
$res = $res && $commentInfo->save();
|
||||
if (!$res) {
|
||||
throw new ValidateException('点赞失败');
|
||||
}
|
||||
});
|
||||
event('product.reply.update', [$uid]);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消回复点赞
|
||||
* @param int $id
|
||||
* @param int $uid
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function unCommentPraise(int $id, int $uid)
|
||||
{
|
||||
$commentInfo = $this->dao->get($id, ['id', 'praise']);
|
||||
if (!$commentInfo) {
|
||||
throw new ValidateException('回复不存在');
|
||||
}
|
||||
$commentInfo->praise--;
|
||||
/** @var UserRelationServices $service */
|
||||
$service = app()->make(UserRelationServices::class);
|
||||
$this->transaction(function () use ($id, $uid, $service, $commentInfo) {
|
||||
$res = $service->delete([
|
||||
'uid' => $uid,
|
||||
'relation_id' => $id,
|
||||
'type' => UserRelationServices::TYPE_LIKE,
|
||||
'category' => UserRelationServices::CATEGORY_COMMENT
|
||||
]);
|
||||
$res = $res && $commentInfo->save();
|
||||
if (!$res) {
|
||||
throw new ValidateException('点赞失败');
|
||||
}
|
||||
});
|
||||
event('product.reply.update', [$uid]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
677
app/services/product/product/StoreProductReplyServices.php
Normal file
677
app/services/product/product/StoreProductReplyServices.php
Normal file
@@ -0,0 +1,677 @@
|
||||
<?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\product\product;
|
||||
|
||||
|
||||
use app\dao\product\product\StoreProductReplyDao;
|
||||
use app\services\BaseServices;
|
||||
use app\services\product\sku\StoreProductAttrValueServices;
|
||||
use app\services\supplier\SystemSupplierServices;
|
||||
use app\services\user\level\SystemUserLevelServices;
|
||||
use app\services\user\UserBillServices;
|
||||
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\db\exception\DataNotFoundException;
|
||||
use think\db\exception\DbException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
use think\exception\ValidateException;
|
||||
use think\facade\Route as Url;
|
||||
|
||||
/**
|
||||
* Class StoreProductReplyService
|
||||
* @package app\services\product\product
|
||||
* @mixin StoreProductReplyDao
|
||||
*/
|
||||
class StoreProductReplyServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var StoreProductReplyDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreProductReplyDao $dao;
|
||||
|
||||
/**
|
||||
* 获取评论列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function sysPage(array $where)
|
||||
{
|
||||
/** @var StoreProductReplyStoreProductServices $storeProductReplyStoreProductServices */
|
||||
$storeProductReplyStoreProductServices = app()->make(StoreProductReplyStoreProductServices::class);
|
||||
$data = $storeProductReplyStoreProductServices->getProductReplyList($where, [
|
||||
'replyComment' => function ($query) use ($where) {
|
||||
if ($where['type'] ?? 0) {
|
||||
$query->where('uid', 0)->where('pid', 0)->where('type', $where['type'] ?? 0)->where('relation_id', $where['relation_id'] ?? 0);
|
||||
} else {
|
||||
$query->where('uid', 0)->where('pid', 0);
|
||||
}
|
||||
}
|
||||
]);
|
||||
foreach ($data['list'] as &$item) {
|
||||
$item['time'] = time_tran(strtotime($item['add_time']));
|
||||
$item['create_time'] = $item['add_time'];
|
||||
$item['score'] = $item['product_score'] + $item['service_score'] + $item['delivery_score'];
|
||||
$item['score'] = bcdiv($item['score'], '3', 0);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建虚拟评论表单
|
||||
* @param int $product_id
|
||||
* @return array
|
||||
* @throws \FormBuilder\Exception\FormBuilderException
|
||||
*/
|
||||
public function createForm(int $product_id)
|
||||
{
|
||||
if ($product_id == 0) {
|
||||
$field[] = Form::frameImage('image', '商品', Url::buildUrl('admin/store.StoreProduct/index', array('fodder' => 'image')))->icon('ios-add')->width('960px')->height('560px')->modal(['footer-hide' => true])->Props(['srcKey' => 'image']);
|
||||
} else {
|
||||
$field[] = Form::hidden('product_id', $product_id);
|
||||
}
|
||||
$field[] = Form::frameImage('avatar', '用户头像', Url::buildUrl('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('comment', '评价文字')->type('textarea');
|
||||
$field[] = Form::rate('product_score', '商品分数', 0)->allowHalf(false);
|
||||
$field[] = Form::rate('service_score', '服务分数', 0)->allowHalf(false);
|
||||
$field[] = Form::frameImages('pics', '评价图片', Url::buildUrl('admin/widget.images/index', array('fodder' => 'pics', 'type' => 'many', 'maxLength' => 8)))->maxLength(8)->icon('ios-add')->width('960px')->height('505px')->modal(['footer-hide' => true])->modal(['footer-hide' => true])->props(['closeBtn' => false, 'okBtn' => false]);
|
||||
$field[] = Form::dateTime('add_time', '评论时间', '')->placeholder('请选择评论时间(不选择默认当前添加时间)');
|
||||
return create_form('添加虚拟评论', $field, Url::buildUrl('/product/reply/save_fictitious_reply'), 'POST');
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加自评
|
||||
* @param array $data
|
||||
* @param int $type
|
||||
* @param int $relation_id
|
||||
* @return bool
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function saveReply(array $data, int $type = 0, int $relation_id = 0)
|
||||
{
|
||||
$time = time();
|
||||
$data['uid'] = 0;
|
||||
$data['oid'] = 0;
|
||||
$data['type'] = $type;
|
||||
$data['relation_id'] = $relation_id;
|
||||
$data['unique'] = uniqid();
|
||||
$data['reply_type'] = 'product';
|
||||
$data['add_time'] = empty($data['add_time']) ? $time : strtotime($data['add_time']);
|
||||
$data['pics'] = json_encode($data['pics']);
|
||||
if (isset($data['sku_unique']) && $data['sku_unique']) {
|
||||
/** @var StoreProductAttrValueServices $productAttrValueServices */
|
||||
$productAttrValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
$attrDetail = $productAttrValueServices->getone(['product_id' => $data['product_id'], 'unique' => $data['sku_unique']]);
|
||||
$data['sku'] = $attrDetail ? $attrDetail['suk'] : '';
|
||||
}
|
||||
unset($data['image']);
|
||||
if ($data['add_time'] > $time) {
|
||||
throw new AdminException('评论时间应小于当前时间');
|
||||
}
|
||||
$res = $this->dao->save($data);
|
||||
if (!$res) throw new AdminException('添加虚拟评论失败');
|
||||
$this->dao->cacheTag()->clear();
|
||||
|
||||
if (isset($data['product_id'])) {
|
||||
//商品评价
|
||||
event('product.reply', [$data['product_id']]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 回复评论
|
||||
* @param int $replyId
|
||||
* @param string $content
|
||||
* @param int $type
|
||||
* @param int $relation_id
|
||||
* @return void
|
||||
*/
|
||||
public function setReply(int $replyId, string $content, int $type = 0, int $relation_id = 0)
|
||||
{
|
||||
if ($content == '') throw new AdminException('请输入回复内容');
|
||||
$reply = $this->dao->get($replyId);
|
||||
if (!$reply) {
|
||||
throw new AdminException('评论不存在或已删除');
|
||||
}
|
||||
$save['content'] = $content;
|
||||
$save['create_time'] = time();
|
||||
$save['type'] = $type;
|
||||
$save['relation_id'] = $relation_id;
|
||||
$save['reply_id'] = $replyId;
|
||||
/** @var StoreProductReplyCommentServices $service */
|
||||
$service = app()->make(StoreProductReplyCommentServices::class);
|
||||
$where = ['reply_id' => $replyId, 'uid' => 0, 'type' => $type, 'relation_id' => $relation_id, 'pid' => 0];
|
||||
if ($service->count($where)) {
|
||||
$res = $service->update($where, ['content' => $content, 'update_time' => time()]);
|
||||
} else {
|
||||
$res = $service->save($save);
|
||||
}
|
||||
if (!$res) throw new AdminException('回复失败,请稍后再试');
|
||||
if ($type == $reply['type']) {//回复端 与商品端一致 修改回复状态
|
||||
$this->dao->update($replyId, ['is_reply' => 1]);
|
||||
}
|
||||
$this->dao->cacheTag()->clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param int $id
|
||||
*/
|
||||
public function del(int $id)
|
||||
{
|
||||
$res = $this->dao->update($id, ['is_del' => 1]);
|
||||
if (!$res) throw new AdminException('删除失败');
|
||||
$this->dao->cacheTag()->clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $productId
|
||||
* @param int $limit
|
||||
* @return mixed
|
||||
* @throws \Throwable
|
||||
* @author 等风来
|
||||
* @email 136327134@qq.com
|
||||
* @date 2022/11/3
|
||||
*/
|
||||
public function getRecProductReplyCache(int $productId, int $limit = 1)
|
||||
{
|
||||
return $this->dao->cacheTag()->remember('id:' . $productId . ':limit:' . $limit, function () use ($productId, $limit) {
|
||||
return $this->getRecProductReply($productId, $limit);
|
||||
}, 3600);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最近的几条评论
|
||||
* @param int $productId
|
||||
* @param int $limit
|
||||
* @return array
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function getRecProductReply(int $productId, int $limit = 1)
|
||||
{
|
||||
$page = $limit ? 1 : 0;
|
||||
$list = $this->dao->getProductReply($productId, '*', $page, $limit);
|
||||
if ($list) {
|
||||
//用户是否是付费会员和等级会员
|
||||
$uids = array_column($list, 'uid');
|
||||
$uids = array_filter(array_unique($uids));
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$vipArray = $userServices->checkIsVip($uids);
|
||||
|
||||
foreach ($list as &$item) {
|
||||
$item['suk'] = $item['sku'];
|
||||
$item['nickname'] = anonymity($item['nickname']);
|
||||
$item['merchant_reply_time'] = date('Y-m-d H:i', $item['merchant_reply_time']);
|
||||
$item['add_time'] = time_tran($item['add_time']);
|
||||
$item['star'] = bcadd((string)bcadd((string)$item['product_score'], (string)$item['service_score'], 2), (string)$item['delivery_score'], 2);
|
||||
$item['star'] = bcdiv($item['star'], '3', 0);
|
||||
$item['comment'] = $item['comment'] ?: '此用户没有填写评价';
|
||||
$item['pics'] = $item['pics'] ? (is_string($item['pics']) ? json_decode($item['pics'], true) : $item['pics']) : [];
|
||||
$item['level_name'] = $vipArray[$item['uid']]['level_name'] ?? '';
|
||||
$item['vip_status'] = $vipArray[$item['uid']]['vip_status'] ?? '';
|
||||
}
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取好评率
|
||||
* @param int $id
|
||||
* @return int|string
|
||||
*/
|
||||
public function getProductReplyChance(int $id)
|
||||
{
|
||||
$replyCount = $this->dao->replyCount($id);
|
||||
if ($replyCount) {
|
||||
$goodReply = $this->dao->replyCount($id, 1);
|
||||
if ($goodReply) {
|
||||
$replyCount = bcdiv((string)$goodReply, (string)$replyCount, 2);
|
||||
$replyCount = bcmul((string)$replyCount, '100', 0);
|
||||
} else {
|
||||
$replyCount = 0;
|
||||
}
|
||||
} else {
|
||||
$replyCount = 100;
|
||||
}
|
||||
return $replyCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取评论数据 评论总数 好评总数 好评率
|
||||
* @param int $id
|
||||
* @return array
|
||||
*/
|
||||
public function getProductReplyData(int $id)
|
||||
{
|
||||
return $this->dao->cacheTag()->remember('ReplyData_' . $id, function () use ($id) {
|
||||
$goodReply = $replyChance = 0;
|
||||
$replyCount = $this->dao->replyCount($id);
|
||||
if ($replyCount) {
|
||||
$goodReply = $this->dao->replyCount($id, 3);
|
||||
if ($goodReply) {
|
||||
$replyChance = bcmul((string)bcdiv((string)$goodReply, (string)$replyCount, 2), '100', 0);
|
||||
} else {
|
||||
$replyChance = 0;
|
||||
}
|
||||
} else {
|
||||
$replyChance = 100;
|
||||
}
|
||||
return [$replyCount, $goodReply, $replyChance];
|
||||
}, 3600);
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品评论数量
|
||||
* @param int $type
|
||||
* @param int $relation_id
|
||||
* @return int
|
||||
*/
|
||||
public function replyCount(int $type = 0, int $relation_id = 0)
|
||||
{
|
||||
return $this->dao->count(['is_reply' => 0, 'is_del' => 0, 'type' => $type, 'relation_id' => $relation_id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商品评论数量
|
||||
* @param int $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function productReplyCount(int $id)
|
||||
{
|
||||
|
||||
$data['sum_count'] = $this->dao->replyCount($id);
|
||||
$data['good_count'] = $this->dao->replyCount($id, 3);
|
||||
$data['in_count'] = $this->dao->replyCount($id, 2);
|
||||
$data['poor_count'] = $this->dao->replyCount($id, 1);
|
||||
if ($data['sum_count'] != 0) {
|
||||
$data['reply_chance'] = bcdiv($data['good_count'], $data['sum_count'], 2);
|
||||
$data['reply_star'] = bcdiv(($this->dao->sum(['product_id' => $id, 'is_del' => 0], 'product_score') + $this->dao->sum(['product_id' => $id, 'is_del' => 0], 'service_score')), $data['sum_count'] * 2, 0);
|
||||
} else {
|
||||
$data['reply_chance'] = 100;
|
||||
$data['reply_star'] = 5;
|
||||
}
|
||||
// $data['reply_star'] = bcmul($data['reply_chance'], 5, 0);
|
||||
$data['reply_chance'] = $data['sum_count'] == 0 ? 100 : bcmul($data['reply_chance'], 100, 0);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商品评论列表
|
||||
* @param int $id
|
||||
* @param int $type
|
||||
* @return array
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function getProductReplyList(int $id, int $type)
|
||||
{
|
||||
if (!$id) {
|
||||
return [];
|
||||
}
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->replyList($id, $type, $page, $limit);
|
||||
foreach ($list as &$item) {
|
||||
$item['suk'] = $item['sku'];
|
||||
$item['nickname'] = anonymity($item['nickname']);
|
||||
$item['merchant_reply_time'] = date('Y-m-d H:i', $item['merchant_reply_time']);
|
||||
$item['add_time'] = date('Y-m-d H:i', $item['add_time']);
|
||||
$item['star'] = bcadd((string)bcadd((string)$item['product_score'], (string)$item['service_score'], 2), (string)$item['delivery_score'], 2);
|
||||
$item['star'] = bcdiv($item['star'], '3', 0);
|
||||
$item['comment'] = $item['comment'] ?: '此用户没有填写评价';
|
||||
$item['pics'] = is_string($item['pics']) ? json_decode($item['pics'], true) : $item['pics'];
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 评价点赞
|
||||
* @param int $id
|
||||
* @param int $uid
|
||||
* @return bool
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function replyPraise(int $id, int $uid)
|
||||
{
|
||||
$relyInfo = $this->dao->get($id, ['id', 'praise']);
|
||||
if (!$relyInfo) {
|
||||
throw new ValidateException('点赞的评价不存在');
|
||||
}
|
||||
/** @var UserRelationServices $service */
|
||||
$service = app()->make(UserRelationServices::class);
|
||||
if ($service->getUserCount($uid, $id, UserRelationServices::TYPE_COLLECT, UserRelationServices::CATEGORY_REPLY)) {
|
||||
return true;
|
||||
}
|
||||
$relyInfo->praise++;
|
||||
$this->transaction(function () use ($uid, $relyInfo, $service, $id) {
|
||||
$res = $service->save([
|
||||
'uid' => $uid,
|
||||
'relation_id' => $id,
|
||||
'type' => UserRelationServices::TYPE_LIKE,
|
||||
'category' => UserRelationServices::CATEGORY_REPLY,
|
||||
'add_time' => time()
|
||||
]);
|
||||
$res = $res && $relyInfo->save();
|
||||
if (!$res) {
|
||||
throw new ValidateException('点赞失败');
|
||||
}
|
||||
});
|
||||
event('product.reply.update', [$uid]);
|
||||
$this->dao->cacheTag()->clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消点赞
|
||||
* @param int $id
|
||||
* @param int $uid
|
||||
* @return bool
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function unReplyPraise(int $id, int $uid)
|
||||
{
|
||||
$relyInfo = $this->dao->get($id, ['id', 'praise']);
|
||||
if (!$relyInfo) {
|
||||
throw new ValidateException('点赞的评价不存在');
|
||||
}
|
||||
/** @var UserRelationServices $service */
|
||||
$service = app()->make(UserRelationServices::class);
|
||||
$relyInfo->praise--;
|
||||
$this->transaction(function () use ($uid, $relyInfo, $service, $id) {
|
||||
$res = $service->delete([
|
||||
'uid' => $uid,
|
||||
'relation_id' => $id,
|
||||
'type' => UserRelationServices::TYPE_LIKE,
|
||||
'category' => UserRelationServices::CATEGORY_REPLY
|
||||
]);
|
||||
$res = $res && $relyInfo->save();
|
||||
if (!$res) {
|
||||
throw new ValidateException('取消点赞失败');
|
||||
}
|
||||
});
|
||||
event('product.reply.update', [$uid]);
|
||||
$this->dao->cacheTag()->clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取评论详情
|
||||
* @param int $id
|
||||
* @param int $uid
|
||||
* @return mixed
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function getReplyInfo(int $id, int $uid)
|
||||
{
|
||||
$replyInfo = $this->dao->get($id, ['*']);
|
||||
if (!$replyInfo) {
|
||||
throw new ValidateException('查看的评论不存在');
|
||||
}
|
||||
/** @var StoreProductServices $productServices */
|
||||
$productServices = app()->make(StoreProductServices::class);
|
||||
$productInfo = $productServices->get($replyInfo->product_id, ['id', 'store_name', 'image', 'is_presale_product']);
|
||||
/** @var UserServices $userService */
|
||||
$userService = app()->make(UserServices::class);
|
||||
$uids = $replyInfo->uid ? [$replyInfo->uid] : [];
|
||||
$vipArray = $userService->checkIsVip($uids);
|
||||
|
||||
$userInfo = $userService->get($replyInfo->uid, ['nickname', 'uid', 'avatar', 'is_money_level']);
|
||||
$userInfo = $userInfo ? $userInfo->toArray() : [];
|
||||
|
||||
$userInfo['level_name'] = $vipArray[$replyInfo->uid]['level_name'] ?? '';
|
||||
$userInfo['vip_status'] = $vipArray[$replyInfo->uid]['vip_status'] ?? '';
|
||||
$userInfo['nickname'] = anonymity($userInfo['nickname'] ?? '');
|
||||
$replyInfo->nickname = anonymity($replyInfo['nickname'] ?? '');
|
||||
$data['reply'] = $replyInfo->toArray();
|
||||
$data['reply']['add_time'] = $data['reply']['add_time'] ? date('Y-m-d H:i:s', $data['reply']['add_time']) : '';
|
||||
$data['reply']['suk'] = $replyInfo['sku'] ?? '';
|
||||
/** @var StoreProductReplyCommentServices $commentService */
|
||||
$commentService = app()->make(StoreProductReplyCommentServices::class);
|
||||
$data['reply']['comment_sum'] = $commentService->count(['reply_id' => $id, 'pid' => 0]);
|
||||
$data['product'] = $productInfo ? $productInfo->toArray() : [];
|
||||
$data['user'] = $userInfo;
|
||||
$data['star'] = bcdiv(bcadd($data['reply']['product_score'], $data['reply']['service_score'], 2), 2, 0);
|
||||
/** @var UserRelationServices $make */
|
||||
$make = app()->make(UserRelationServices::class);
|
||||
$data['is_praise'] = !!$make->getUserCount($uid, $id, UserRelationServices::TYPE_LIKE, UserRelationServices::CATEGORY_REPLY);
|
||||
//记录浏览量
|
||||
$replyInfo->views_num++;
|
||||
$replyInfo->save();
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新版本获取商品评价
|
||||
* @param int $id
|
||||
* @param int $type
|
||||
* @return array
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function getNewProductReplyList(int $id, int $type, int $uid)
|
||||
{
|
||||
if (!$id) {
|
||||
return [];
|
||||
}
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->replyList($id, $type, $page, $limit, ['userInfo',
|
||||
'replyComment' => function ($query) {
|
||||
$query->with([
|
||||
'user' => function ($query) {
|
||||
$query->field('uid,avatar,nickname');
|
||||
}
|
||||
])->where('pid', 0)->field(['uid', 'reply_id', 'content'])
|
||||
->order('praise desc,create_time desc');
|
||||
},
|
||||
'productRelation' => function ($query) use ($uid) {
|
||||
$query->where('uid', $uid)->where('type', UserRelationServices::TYPE_LIKE)->where('category', UserRelationServices::CATEGORY_REPLY)->field(['uid', 'relation_id']);
|
||||
}
|
||||
]);
|
||||
if ($list) {
|
||||
$siteLogoSquare = sys_config('site_logo_square');
|
||||
$siteName = sys_config('site_name');
|
||||
$supplierIds = $storeIds = [];
|
||||
foreach ($list as $value) {
|
||||
switch ($value['type']) {
|
||||
case 0:
|
||||
break;
|
||||
case 2://供应商
|
||||
$supplierIds[] = $value['relation_id'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
$supplierIds = array_unique($supplierIds);
|
||||
$supplierList = [];
|
||||
if ($supplierIds) {
|
||||
/** @var SystemSupplierServices $supplierServices */
|
||||
$supplierServices = app()->make(SystemSupplierServices::class);
|
||||
$supplierList = $supplierServices->getColumn([['id', 'in', $supplierIds], ['is_del', '=', 0]], 'id,supplier_name,avatar', 'id');
|
||||
}
|
||||
$replyId = array_column($list, 'id');
|
||||
/** @var StoreProductReplyCommentServices $make */
|
||||
$make = app()->make(StoreProductReplyCommentServices::class);
|
||||
$replySum = $make->getReplyCommentCountList($replyId);
|
||||
|
||||
//是否付费会员和等级会员
|
||||
$uids = array_column($list, 'uid');
|
||||
$uids = array_filter(array_unique($uids));
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$vipArray = $userServices->checkIsVip($uids);
|
||||
|
||||
foreach ($list as &$item) {
|
||||
$item['suk'] = $item['sku'];
|
||||
$item['nickname'] = anonymity($item['nickname']);
|
||||
$item['merchant_reply_time'] = date('Y-m-d H:i', $item['merchant_reply_time']);
|
||||
$item['add_time'] = date('Y-m-d H:i', $item['add_time']);
|
||||
$item['star'] = bcadd((string)bcadd((string)$item['product_score'], (string)$item['service_score'], 2), (string)$item['delivery_score'], 2);
|
||||
$item['star'] = bcdiv($item['star'], '3', 0);
|
||||
$item['comment'] = $item['comment'] ?: '此用户没有填写评价';
|
||||
$item['pics'] = $item['pics'] ? (is_string($item['pics']) ? json_decode($item['pics'], true) : $item['pics']) : [];
|
||||
if (isset($item['replyComment']['user']['nickname'])) {
|
||||
$item['replyComment']['user']['nickname'] = anonymity($item['replyComment']['user']['nickname']);
|
||||
} else if (isset($item['replyComment']) && !$item['replyComment']['user'] && $item['replyComment']['uid'] === 0) {
|
||||
$user = [];
|
||||
switch ($item['replyComment']['type'] ?? 0) {
|
||||
case 0:
|
||||
$user = ['nickname' => $siteName, 'avatar' => $siteLogoSquare];
|
||||
break;
|
||||
case 2://供应商
|
||||
$user = ['nickname' => $supplierList[$item['relation_id']]['supplier_name'] ?? '', 'avatar' => $supplierList[$item['relation_id']]['avatar'] ?? ''];
|
||||
break;
|
||||
default:
|
||||
$user = ['nickname' => $siteName, 'avatar' => $siteLogoSquare];
|
||||
break;
|
||||
}
|
||||
$item['replyComment']['user'] = $user;
|
||||
}
|
||||
|
||||
if ($uid) {
|
||||
$item['is_praise'] = !empty($item['productRelation']);
|
||||
} else {
|
||||
$item['is_praise'] = false;
|
||||
}
|
||||
if (isset($item['replyComment'])) {
|
||||
foreach ($replySum as $value) {
|
||||
if ($item['id'] === $value['reply_id']) {
|
||||
$item['replyComment']['sum'] = $value['sum'];
|
||||
}
|
||||
}
|
||||
}
|
||||
$item['level_name'] = $vipArray[$item['uid']]['level_name'] ?? '';
|
||||
$item['vip_status'] = $vipArray[$item['uid']]['vip_status'] ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算商品评分
|
||||
* @param int $id
|
||||
* @return bool
|
||||
*/
|
||||
public function computedProductStar(int $id)
|
||||
{
|
||||
/** @var StoreProductServices $productServices */
|
||||
$productServices = app()->make(StoreProductServices::class);
|
||||
$productInfo = $productServices->get($id, ['id', 'star']);
|
||||
if ($productInfo) {
|
||||
$starList = $this->dao->getColumn(['product_id' => $id, 'is_del' => 0], 'product_score,product_id');
|
||||
if ($starList) {
|
||||
$star = bcdiv((string)array_sum(array_column($starList, 'product_score')), (string)count($starList), 1);
|
||||
$productServices->update(['id' => $id], ['star' => $star]);
|
||||
$productServices->cacheTag()->clear();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 评论赠送积分和经验值
|
||||
* @param $oid
|
||||
* @param $uid
|
||||
* @return bool
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
* @author wuhaotian
|
||||
* @email 442384644@qq.com
|
||||
* @date 2025/4/22
|
||||
*/
|
||||
public function replySendPointExp($oid, $uid)
|
||||
{
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$userInfo = $userServices->getUserInfo($uid);
|
||||
if (!$userInfo) {
|
||||
return true;
|
||||
}
|
||||
/** @var UserBillServices $userBillServices */
|
||||
$userBillServices = app()->make(UserBillServices::class);
|
||||
if (sys_config('reply_point_switch') == 1) {
|
||||
$replayPointDay = sys_config('reply_point_day');
|
||||
$replayPointOnce = sys_config('reply_point_once');
|
||||
$replyDayGetPoint = $userBillServices->getBillSum([
|
||||
'uid' => $uid,
|
||||
'type' => 'reply_add_integral',
|
||||
'time' => [strtotime(date('Y-m-d')), time()]
|
||||
]);
|
||||
if ($replayPointDay == 0 || $replyDayGetPoint < $replayPointDay) {
|
||||
$balance = bcadd((string)$userInfo['integral'], (string)$replayPointOnce);
|
||||
$userBillServices->income('reply_add_integral', $uid, (int)$replayPointOnce, (int)$balance, $oid);
|
||||
$userServices->update($uid, ['integral' => $balance]);
|
||||
}
|
||||
}
|
||||
if (sys_config('reply_exp_switch') == 1) {
|
||||
$replayExpDay = sys_config('reply_exp_day');
|
||||
$replayExpOnce = sys_config('reply_exp_once');
|
||||
$replyDayGetExp = $userBillServices->getBillSum([
|
||||
'uid' => $uid,
|
||||
'type' => 'reply_add_exp',
|
||||
'time' => [strtotime(date('Y-m-d')), time()]
|
||||
]);
|
||||
if ($replayExpDay == 0 || $replyDayGetExp < $replayExpDay) {
|
||||
$balance = bcadd((string)$userInfo['exp'], (string)$replayExpOnce);
|
||||
$userBillServices->income('reply_add_exp', $uid, (int)$replayExpOnce, (int)$balance, $oid);
|
||||
$userServices->update($uid, ['exp' => $balance]);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量AI生成并保存商品评价
|
||||
* @param array $data 评价数据列表
|
||||
* @return bool
|
||||
*/
|
||||
public function saveAllAiReply($data)
|
||||
{
|
||||
try {
|
||||
foreach ($data as $item) {
|
||||
$saveData = [
|
||||
'nickname' => $item['nickname'],
|
||||
'avatar' => $item['avatar'],
|
||||
'comment' => $item['comment'],
|
||||
'pics' => [],
|
||||
'reply_score' => $item['reply_score'],
|
||||
'product_score' => $item['product_score'],
|
||||
'service_score' => $item['service_score'],
|
||||
'delivery_score' => $item['delivery_score'],
|
||||
'product_id' => $item['product_id'],
|
||||
'sku_unique' => $item['unique'],
|
||||
'add_time' => $item['add_time'],
|
||||
];
|
||||
$this->saveReply($saveData);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?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\product\product;
|
||||
|
||||
use app\services\BaseServices;
|
||||
use app\dao\product\product\StoreProductReplyStoreProductDao;
|
||||
use think\annotation\Inject;
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\DbException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class StoreProductReplyStoreProductServices
|
||||
* @package app\services\product\product
|
||||
* @mixin StoreProductReplyStoreProductDao
|
||||
*/
|
||||
class StoreProductReplyStoreProductServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var StoreProductReplyStoreProductDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreProductReplyStoreProductDao $dao;
|
||||
|
||||
/**
|
||||
* 获取评论列表
|
||||
* @param array $where
|
||||
* @param array $with
|
||||
* @return array
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function getProductReplyList(array $where, array $with = [])
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getProductReplyList($where, $page, $limit, $with);
|
||||
$count = $this->dao->replyCount($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
}
|
||||
3586
app/services/product/product/StoreProductServices.php
Normal file
3586
app/services/product/product/StoreProductServices.php
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,82 @@
|
||||
<?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\product\product;
|
||||
|
||||
|
||||
use app\dao\product\product\StoreProductStockRecordDao;
|
||||
use app\services\BaseServices;
|
||||
use app\services\product\sku\StoreProductAttrValueServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* 商品库存记录
|
||||
* Class StoreProductStockRecordServices
|
||||
* @package app\services\product\product
|
||||
* @mixin StoreProductStockRecordDao
|
||||
*/
|
||||
class StoreProductStockRecordServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var StoreProductStockRecordDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreProductStockRecordDao $dao;
|
||||
|
||||
/**
|
||||
* 保存入库、出库记录
|
||||
* @param int $id
|
||||
* @param array $attrs
|
||||
* @param int $type
|
||||
* @param int $store_id
|
||||
* @return bool
|
||||
*/
|
||||
public function saveRecord(int $id, array $attrs, int $type = 0, int $store_id = 0)
|
||||
{
|
||||
if (!$attrs) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
/** @var StoreProductAttrValueServices $storeProductAttrValueServices */
|
||||
$storeProductAttrValueServices = app()->make(StoreProductAttrValueServices::class);
|
||||
//原来规格数据
|
||||
$attrValues = $storeProductAttrValueServices->getProductAttrValue(['product_id' => $id, 'type' => $type]);
|
||||
if ($attrValues) $attrValues = array_combine(array_column($attrValues, 'unique'), $attrValues);
|
||||
$time = time();
|
||||
$dataAll = $data = [];
|
||||
foreach ($attrs as $attr) {
|
||||
$data = [
|
||||
'store_id' => $store_id,
|
||||
'product_id' => $id,
|
||||
'unique' => $attr['unique'],
|
||||
'cost_price' => $attrValues[$attr['unique']]['cost'] ?? 0,
|
||||
'add_time' => $time,
|
||||
];
|
||||
if (!isset($attrValues[$attr['unique']]) || $attr['stock'] > $attrValues[$attr['unique']]['stock']) {
|
||||
$data['pm'] = 1;
|
||||
$data['number'] = !isset($attrValues[$attr['unique']]) ? $attr['stock'] : bcsub((string)$attr['stock'], (string)$attrValues[$attr['unique']]['stock'], 2);
|
||||
} else {
|
||||
$data['pm'] = 0;
|
||||
$data['number'] = !isset($attrValues[$attr['unique']]) ? $attr['stock'] : bcsub((string)$attrValues[$attr['unique']]['stock'], (string)$attr['stock'], 2);
|
||||
}
|
||||
if ($data['number']) $dataAll[] = $data;
|
||||
}
|
||||
if ($dataAll) {
|
||||
$this->dao->saveAll($dataAll);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
114
app/services/product/product/StoreProductUnitServices.php
Normal file
114
app/services/product/product/StoreProductUnitServices.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?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\product\product;
|
||||
|
||||
|
||||
use app\dao\product\product\StoreProductUnitDao;
|
||||
use app\services\BaseServices;
|
||||
use crmeb\services\FormBuilder;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
|
||||
/**
|
||||
* 商品单位
|
||||
* Class StoreProductUnitServices
|
||||
* @package app\services\product\product
|
||||
* @mixin StoreProductUnitDao
|
||||
*/
|
||||
class StoreProductUnitServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var StoreProductUnitDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreProductUnitDao $dao;
|
||||
|
||||
/**
|
||||
* 获取所有商品单位列表
|
||||
* @param int $type
|
||||
* @param int $relation_id
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getAllUnitList(int $type = 0, int $relation_id = 0)
|
||||
{
|
||||
$where = [];
|
||||
// $where['type'] = $type;
|
||||
// $where['relation_id'] = $relation_id;
|
||||
$where['status'] = 1;
|
||||
$where['is_del'] = 0;
|
||||
return $this->dao->getList($where, 'id,name');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商品单位
|
||||
* @param array $where
|
||||
* @param string $field
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getUnitList(array $where, string $field = '*')
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getList($where, $field, $page, $limit);
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 创建表单
|
||||
* @param array $cataData
|
||||
* @return array
|
||||
*/
|
||||
public function unitCateForm(array $cataData = [])
|
||||
{
|
||||
$f[] = FormBuilder::input('name', '单位名称:', $cataData['name'] ?? '')->maxlength(15)->required();
|
||||
$f[] = FormBuilder::number('sort', '排序:', (int)($cataData['sort'] ?? 0))->min(0);
|
||||
return $f;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建表单
|
||||
* @return array
|
||||
* @throws \FormBuilder\Exception\FormBuilderException
|
||||
*/
|
||||
public function createForm()
|
||||
{
|
||||
return create_form('添加商品单位', $this->unitCateForm(), $this->url('/product/unit'), '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 updateForm(int $id)
|
||||
{
|
||||
$unit = $this->dao->get($id);
|
||||
if (!$unit) {
|
||||
throw new ValidateException('分类标签没有查到');
|
||||
}
|
||||
return create_form('编辑商品单位', $this->unitCateForm($unit->toArray()), $this->url('/product/unit/' . $id), 'PUT');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
31
app/services/product/product/StoreProductVisitServices.php
Normal file
31
app/services/product/product/StoreProductVisitServices.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?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\product\product;
|
||||
|
||||
|
||||
use app\dao\product\product\StoreProductVisitDao;
|
||||
use app\services\BaseServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* Class StoreProductVisitServices
|
||||
* @package app\services\product\product
|
||||
* @mixin StoreProductVisitDao
|
||||
*/
|
||||
class StoreProductVisitServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var StoreProductVisitDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreProductVisitDao $dao;
|
||||
}
|
||||
161
app/services/product/product/StoreProductWordsServices.php
Normal file
161
app/services/product/product/StoreProductWordsServices.php
Normal file
@@ -0,0 +1,161 @@
|
||||
<?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\product\product;
|
||||
|
||||
|
||||
use app\dao\product\product\StoreProductWordsDao;
|
||||
use app\services\BaseServices;
|
||||
use crmeb\exceptions\AdminException;
|
||||
use think\annotation\Inject;
|
||||
|
||||
|
||||
/**
|
||||
* 热词
|
||||
* Class StoreProductWordsServices
|
||||
* @package app\services\product\product
|
||||
* @mixin StoreProductWordsDao
|
||||
*/
|
||||
class StoreProductWordsServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var StoreProductWordsDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreProductWordsDao $dao;
|
||||
|
||||
/**
|
||||
* 获取所有商品单位列表
|
||||
* @param int $type
|
||||
* @param int $relation_id
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getAllWordsList(int $type = 0, int $relation_id = 0)
|
||||
{
|
||||
$where = [];
|
||||
// $where['type'] = $type;
|
||||
// $where['relation_id'] = $relation_id;
|
||||
$where['is_show'] = 1;
|
||||
$where['is_del'] = 0;
|
||||
return $this->dao->getList($where, 'id,name');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商品单位
|
||||
* @param array $where
|
||||
* @param string $field
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getWordsList(array $where, string $field = '*')
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getList($where, $field, $page, $limit);
|
||||
if ($list) {
|
||||
foreach ($list as &$item) {
|
||||
$item['add_time'] = date('Y-m-d H:i:s', time());
|
||||
}
|
||||
}
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存数据
|
||||
* @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 saveData(int $id, array $data)
|
||||
{
|
||||
$words = $this->dao->getOne(['name' => $data['name'], 'is_del' => 0, 'type' => 0]);
|
||||
if ($id) {
|
||||
if ($words && $words['id'] != $id) {
|
||||
throw new AdminException('热词名称已经存在');
|
||||
}
|
||||
if ($this->dao->update($id, $data)) {
|
||||
$data['id'] = $id;
|
||||
$this->cacheUpdate($data);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if ($words) {
|
||||
throw new AdminException('热词已经存在,请勿重复添加');
|
||||
}
|
||||
$data['add_time'] = time();
|
||||
if ($res = $this->dao->save($data)) {
|
||||
$id = $res->id;
|
||||
$data['id'] = $id;
|
||||
$this->cacheUpdate($data);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置状态
|
||||
* @param $id
|
||||
* @param $is_show
|
||||
*/
|
||||
public function setShow(int $id, int $is_show)
|
||||
{
|
||||
$res = $this->dao->update($id, ['is_show' => $is_show]);
|
||||
if (!$res) {
|
||||
throw new AdminException('设置失败');
|
||||
}
|
||||
|
||||
//设置缓存
|
||||
if (!$is_show) {
|
||||
$this->cacheDelById($id);
|
||||
return;
|
||||
}
|
||||
$branInfo = $this->dao->cacheInfoById($id);
|
||||
if ($branInfo) {
|
||||
$branInfo['is_show'] = 1;
|
||||
} else {
|
||||
$branInfo = $this->dao->get($id);
|
||||
if (!$branInfo) {
|
||||
return;
|
||||
}
|
||||
$branInfo = $branInfo->toArray();
|
||||
}
|
||||
$this->dao->cacheUpdate($branInfo);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除数据
|
||||
* @param int $id
|
||||
*/
|
||||
public function del(int $id)
|
||||
{
|
||||
$res = $this->dao->delete($id);
|
||||
if (!$res) throw new AdminException('删除失败');
|
||||
|
||||
//更新缓存
|
||||
$this->cacheDelById($id);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
82
app/services/product/product/StoreVisitServices.php
Normal file
82
app/services/product/product/StoreVisitServices.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?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\product\product;
|
||||
|
||||
|
||||
use app\dao\product\product\StoreVisitDao;
|
||||
use app\services\BaseServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* Class StoreVisitService
|
||||
* @package app\services\product\product
|
||||
* @mixin StoreVisitDao
|
||||
*/
|
||||
class StoreVisitServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var StoreVisitDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected StoreVisitDao $dao;
|
||||
|
||||
/**
|
||||
* 设置浏览信息
|
||||
* @param $uid
|
||||
* @param array $productIds
|
||||
* @param string $product_type
|
||||
* @param int $cate
|
||||
* @param string $type
|
||||
* @param string $content
|
||||
* @param int $min
|
||||
* @return bool
|
||||
*/
|
||||
public function setView($uid, $productIds = [], $product_type = 'product', $cate = 0, $type = '', $content = '', $min = 20)
|
||||
{
|
||||
if (!$productIds) {
|
||||
return true;
|
||||
}
|
||||
if (!is_array($productIds)) {
|
||||
$productIds = [$productIds];
|
||||
}
|
||||
$views = $this->dao->getColumn(['uid' => $uid, 'product_id' => $productIds, 'product_type' => $product_type], 'count,add_time,id', 'product_id');
|
||||
$cate = explode(',', $cate)[0];
|
||||
$dataAll = [];
|
||||
$time = time();
|
||||
foreach ($productIds as $key => $product_id) {
|
||||
if (isset($views[$product_id]) && $type != 'search') {
|
||||
$view = $views[$product_id] ?? [];
|
||||
if ($view && ($view['add_time'] + $min) < $time) {
|
||||
$this->dao->update($view['id'], ['count' => $view['count'] + 1, 'add_time' => time()]);
|
||||
}
|
||||
} else {
|
||||
$data = [
|
||||
'add_time' => $time,
|
||||
'count' => 1,
|
||||
'product_id' => $product_id,
|
||||
'product_type' => $product_type,
|
||||
'cate_id' => $cate,
|
||||
'type' => $type,
|
||||
'uid' => $uid,
|
||||
'content' => $content
|
||||
];
|
||||
$dataAll[] = $data;
|
||||
}
|
||||
}
|
||||
if ($dataAll) {
|
||||
if (!$this->dao->saveAll($dataAll)) {
|
||||
throw new ValidateException('添加失败');
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user