<?php
namespace app\service;
use think\facade\Db;
use app\service\SystemService;
use app\service\SystemBaseService;
use app\service\ResourcesService;
use app\service\AttachmentService;
use app\service\UserService;
use app\service\BrandService;
use app\service\RegionService;
use app\service\WarehouseGoodsService;
use app\service\GoodsCategoryService;
use app\service\GoodsSpecService;
use app\service\GoodsParamsService;
use app\service\GoodsCommentsService;
* 商品服务层
* @author Devil
* @blog http://gong.gg/
* @version 0.0.1
* @datetime 2016-12-01T21:51:08+0800
*/
class GoodsService
{
public static $goods_spec_to_string_separator = '{|}';
* 商品规格默认名称
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2023-02-09
* @desc description
*/
public static function GoodsSpecDefaultName()
{
return MyLang('common_service.goods.base_goods_spec_default_name');
}
* 获取首页楼层数据
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-08-29
* @desc description
* @param [array] $params [输入参数]
*/
public static function HomeFloorList($params = [])
{
$is_spec = (!isset($params['is_spec']) || $params['is_spec'] == 1) ? 1 : 0;
$is_cart = (!isset($params['is_cart']) || $params['is_cart'] == 1) ? 1 : 0;
$key = SystemService::CacheKey('shopxo.cache_goods_floor_list_key');
$data = MyCache($key);
if($data === null || MyEnv('app_debug') || MyC('common_data_is_use_cache') != 1)
{
$data = GoodsCategoryService::GoodsCategoryList(['where'=>[
['pid', '=', 0],
['is_home_recommended', '=', 1],
['is_enable', '=', 1],
]]);
if(!empty($data))
{
$floor_left_top_category = MyC('home_index_floor_left_top_category');
if(!empty($floor_left_top_category))
{
$floor_left_top_category = json_decode($floor_left_top_category, true);
}
$floor_keywords = MyC('home_index_floor_top_right_keywords');
if(!empty($floor_keywords))
{
$floor_keywords = json_decode($floor_keywords, true);
}
$floor_data_type = MyC('home_index_floor_data_type', 0, true);
switch($floor_data_type)
{
case 0 :
$goods_count = MyC('home_index_floor_goods_max_count', 8, true);
$floor_order_by_type_list = MyConst('common_goods_order_by_type_list');
$floor_order_by_rule_list = MyConst('common_data_order_by_rule_list');
$floor_order_by_type = MyC('home_index_floor_goods_order_by_type', 0, true);
$floor_order_by_rule = MyC('home_index_floor_goods_order_by_rule', 0, true);
$order_by_field = array_key_exists($floor_order_by_type, $floor_order_by_type_list) ? $floor_order_by_type_list[$floor_order_by_type]['value'] : $floor_order_by_type_list[0]['value'];
$order_by_rule = array_key_exists($floor_order_by_rule, $floor_order_by_rule_list) ? $floor_order_by_rule_list[$floor_order_by_rule]['value'] : $floor_order_by_rule_list[0]['value'];
$order_by = implode(' '.$order_by_rule.', ', explode(',', $order_by_field)).' '.$order_by_rule;
break;
case 1 :
$manual_mode = MyC('home_index_floor_manual_mode_goods');
if(!empty($manual_mode))
{
$floor_manual_mode_goods = json_decode($manual_mode, true);
}
break;
}
$hook_name = 'plugins_service_home_floor_data_begin';
MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'params' => $params,
'data' => &$data,
]);
foreach($data as &$v)
{
switch($floor_data_type)
{
case 0 :
if(isset($goods_count) && isset($order_by))
{
$category_ids = GoodsCategoryService::GoodsCategoryItemsIds([$v['id']], 1);
$goods_params = [
'where' => [
['gci.category_id', 'in', $category_ids],
['g.is_shelves', '=', 1],
['g.is_delete_time', '=', 0],
],
'order_by' => $order_by,
'field' => 'g.id',
'n' => $goods_count,
'is_data_handle' => 0,
'is_spec' => $is_spec,
'is_cart' => $is_cart,
];
$res = self::CategoryGoodsList($goods_params);
$v['goods_ids'] = empty($res) ? [] : array_column($res, 'id');
}
break;
case 1 :
if(!empty($floor_manual_mode_goods) && is_array($floor_manual_mode_goods) && array_key_exists($v['id'], $floor_manual_mode_goods))
{
$v['goods_ids'] = $floor_manual_mode_goods[$v['id']];
}
break;
}
$v['goods'] = [];
if(!empty($floor_left_top_category) && !empty($floor_left_top_category[$v['id']]))
{
$v['items'] = GoodsCategoryService::GoodsCategoryList(['where'=>[['id', 'in', explode(',', $floor_left_top_category[$v['id']])]], 'm'=>0, 'n'=>0, 'is_spec'=>0, 'is_cart'=>0]);
} else {
$v['items'] = [];
}
$v['config_keywords'] = (empty($floor_keywords) || empty($floor_keywords[$v['id']])) ? [] : explode(',', $floor_keywords[$v['id']]);
}
} else {
$data = [];
}
MyCache($key, $data, 180);
}
if(!empty($data) && is_array($data))
{
$goods_ids = [];
foreach($data as $cg)
{
if(!empty($cg['goods_ids']) && is_array($cg['goods_ids']))
{
$goods_ids = array_merge($goods_ids, $cg['goods_ids']);
}
}
$goods_list = [];
if(!empty($goods_ids))
{
$res = self::GoodsList([
'where' => [
['id', 'in', array_unique($goods_ids)],
['is_shelves', '=', 1],
],
'm' => 0,
'n' => 0,
'field' => '*',
'is_spec' => $is_spec,
'is_cart' => $is_cart,
]);
$goods_list = empty($res['data']) ? [] : array_column($res['data'], null, 'id');
}
if(!empty($goods_list))
{
foreach($data as &$cv)
{
if(!empty($cv['goods_ids']) && is_array($cv['goods_ids']))
{
$temp = [];
foreach($cv['goods_ids'] as $gid)
{
if(array_key_exists($gid, $goods_list))
{
$temp[] = $goods_list[$gid];
}
}
$cv['goods'] = $temp;
}
}
}
}
return $data;
}
* 商品数据
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-09-07
* @desc description
* @param array $where [条件]
*/
public static function GoodsData($goods_id, $field = '*')
{
$data = Db::name('Goods')->field($field)->find($goods_id);
$hook_name = 'plugins_service_goods_data';
MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'goods_id' => $goods_id,
'data' => &$data,
]);
return $data;
}
* 获取分类与商品关联总数
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-09-07
* @desc description
* @param array $where [条件]
*/
public static function CategoryGoodsTotal($where = [])
{
$hook_name = 'plugins_service_category_goods_total_begin';
MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'where' => &$where,
]);
return (int) Db::name('Goods')->alias('g')->join('goods_category_join gci', 'g.id=gci.goods_id')->where($where)->count('DISTINCT g.id');
}
* 获取分类与商品关联列表
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-08-29
* @desc description
* @param array $params [输入参数: where, field, is_photo]
*/
public static function CategoryGoodsList($params = [])
{
$where = empty($params['where']) ? [] : $params['where'];
$field = empty($params['field']) ? 'g.*' : $params['field'];
$order_by = empty($params['order_by']) ? 'g.sort_level desc, g.id desc' : trim($params['order_by']);
$m = isset($params['m']) ? intval($params['m']) : 0;
$n = isset($params['n']) ? intval($params['n']) : 10;
$hook_name = 'plugins_service_category_goods_list_begin';
MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'params' => &$params,
'where' => &$where,
'field' => &$field,
'order_by' => &$order_by,
'm' => &$m,
'n' => &$n,
]);
$where_g = [];
$where_gci = [];
foreach($where as $v)
{
if(is_array($v) && count($v) == 3)
{
if(substr($v[0], 0, 4) == 'gci.')
{
$where_gci[] = $v;
} else {
$where_g[] = $v;
}
}
}
if(empty($where_gci) && stripos($field, 'gci.') === false && stripos($order_by, 'gci.') === false)
{
$data = Db::name('Goods')->alias('g')->where($where_g)->field($field)->order($order_by)->limit($m, $n)->select()->toArray();
} else if((stripos($order_by, 'gci.') !== false && stripos($order_by, 'g.') !== false) || (stripos($field, 'gci.') !== false && stripos($field, 'g.') !== false))
{
$data = Db::name('Goods')->alias('g')->join('goods_category_join gci', 'g.id=gci.goods_id')->field($field)->where($where)->group('g.id')->order($order_by)->limit($m, $n)->select()->toArray();
} else {
$data = Db::name('Goods')->alias('g')->where($where_g)->where('g.id', 'IN', function($query) use($where_gci) {
$query->name('GoodsCategoryJoin')->alias('gci')->where($where_gci)->field('gci.goods_id');
})->order($order_by)->limit($m, $n)->select()->toArray();
}
if(!isset($params['is_data_handle']) || $params['is_data_handle'] == 1)
{
$data = self::GoodsDataHandle($data, $params);
}
return $data;
}
* 商品数据处理
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @datetime 2018-12-08T23:16:42+0800
* @param [array] $data [商品列表]
* @param [array] $params [输入参数]
*/
public static function GoodsDataHandle($data, $params = [])
{
if(!empty($data))
{
$hook_name = 'plugins_service_goods_list_handle_begin';
MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'params' => &$params,
'data' => &$data,
]);
$is_photo = !isset($params['is_photo']) || (isset($params['is_photo']) && $params['is_photo'] == 1);
$is_spec = isset($params['is_spec']) && $params['is_spec'] == 1;
$is_content_app = isset($params['is_content_app']) && $params['is_content_app'] == 1;
$is_category = isset($params['is_category']) && $params['is_category'] == 1;
$is_params = isset($params['is_params']) && $params['is_params'] == 1;
$is_cart = isset($params['is_cart']) && $params['is_cart'] == 1;
$is_favor = isset($params['is_favor']) && $params['is_favor'] == 1;
$is_score = isset($params['is_score']) && $params['is_score'] == 1;
$data_key_field = empty($params['data_key_field']) ? 'id' : $params['data_key_field'];
$goods_ids = array_filter(array_column($data, $data_key_field));
$currency_symbol = ResourcesService::CurrencyDataSymbol();
$common_goods_sales_price_status = MyC('common_goods_sales_price_status', 0, true);
$common_goods_original_price_status = MyC('common_goods_original_price_status', 0, true);
$common_goods_sales_price_unit_status = MyC('common_goods_sales_price_unit_status', 0, true);
$common_goods_original_price_unit_status = MyC('common_goods_original_price_unit_status', 0, true);
$common_goods_sales_number_status = MyC('common_goods_sales_number_status', 0, true);
$common_goods_inventory_status = MyC('common_goods_inventory_status', 0, true);
$keys = ArrayKeys($data);
if(in_array('brand_id', $keys))
{
$brand_list = BrandService::BrandName(array_column($data, 'brand_id'));
}
if(in_array('produce_region', $keys))
{
$produce_region_list = RegionService::RegionName(array_column($data, 'produce_region'));
}
$photo = $is_photo ? self::GoodsPhotoData($goods_ids) : [];
$category_group = $is_category ? self::GoodsListCategoryGroupList($goods_ids, $params) : [];
$spec_group = $is_spec ? self::GoodsSpecificationsData($goods_ids, $params) : [];
$params_group = $is_params ? self::GoodsParametersData($goods_ids, $params) : [];
$app_group = $is_content_app ? self::GoodsAppData($goods_ids, $params) : [];
$user_cart = $is_cart ? self::UserCartGoodsCountData($goods_ids, $params) : [];
$user_favor = $is_favor ? self::UserFavorGoodsCountData($goods_ids, $params) : [];
$goods_score = $is_score ? self::GoodsScoreData($goods_ids, $params) : [];
$base_fields = MyConst('common_goods_base_data_fields');
$base_fields_show = MyC('common_goods_detail_base_fields_show', [], true);
foreach($data as $k=>&$v)
{
$v['data_index'] = $k+1;
$data_id = isset($v[$data_key_field]) ? $v[$data_key_field] : 0;
$inventory_unit = empty($v['inventory_unit']) ? '' : ' / '.$v['inventory_unit'];
$v['show_field_original_price_text'] = MyLang('goods_original_price_title');
$v['show_original_price_symbol'] = $currency_symbol;
$v['show_original_price_unit'] = $common_goods_original_price_unit_status == 1 ? $inventory_unit : '';
$v['show_field_original_price_status'] = $common_goods_original_price_status;
$v['show_field_price_text'] = MyLang('goods_sales_price_title');
$v['show_price_symbol'] = $currency_symbol;
$v['show_price_unit'] = $common_goods_sales_price_unit_status == 1 ? $inventory_unit : '';
$v['show_field_price_status'] = $common_goods_sales_price_status;
$v['show_sales_number_status'] = $common_goods_sales_number_status;
$v['show_inventory_status'] = $common_goods_inventory_status;
$v['plugins_view_panel_data'] = [];
$v['plugins_view_icon_data'] = [];
$v['price_container'] = [
'price' => isset($v['price']) ? $v['price'] : 0.00,
'min_price' => isset($v['min_price']) ? $v['min_price'] : 0.00,
'max_price' => isset($v['max_price']) ? $v['max_price'] : 0.00,
'original_price' => isset($v['original_price']) ? $v['original_price'] : 0.00,
'min_original_price' => isset($v['min_original_price']) ? $v['min_original_price'] : 0.00,
'max_original_price' => isset($v['max_original_price']) ? $v['max_original_price'] : 0.00,
];
$hook_name = 'plugins_service_goods_handle_begin';
$ret = EventReturnHandle(MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'params' => &$params,
'goods' => &$v,
'goods_id' => $data_id,
]));
if(isset($ret['code']) && $ret['code'] != 0)
{
return $ret;
}
if(!empty($data_id))
{
$v['goods_url'] = self::GoodsUrlCreate($data_id);
}
if($is_photo && !empty($data_id))
{
$v['photo'] = (empty($photo) || empty($photo[$data_id])) ? [] : $photo[$data_id];
}
if(isset($v['images']))
{
if(empty($v['images']))
{
$v['images'] = ResourcesService::AttachmentPathHandle(self::GoodsImagesCoverHandle($data_id, isset($v['photo']) ? $v['photo'] : []));
}
$v['images'] = ResourcesService::AttachmentPathViewHandle($v['images']);
}
if(isset($v['video']))
{
$v['video'] = ResourcesService::AttachmentPathViewHandle($v['video']);
}
if(isset($v['share_images']))
{
$v['share_images'] = ResourcesService::AttachmentPathViewHandle($v['share_images']);
}
if(isset($v['content_web']))
{
$v['content_web'] = ResourcesService::ContentStaticReplace($v['content_web'], 'get');
if(APPLICATION == 'app')
{
$v['content_web'] = ResourcesService::ApMiniRichTextContentHandle($v['content_web']);
}
}
if(isset($v['fictitious_goods_value']))
{
if(RequestModule() != 'admin')
{
unset($v['fictitious_goods_value']);
} else {
$v['fictitious_goods_value'] = ResourcesService::ContentStaticReplace($v['fictitious_goods_value'], 'get');
}
}
if(isset($v['use_guide']))
{
$v['use_guide'] = ResourcesService::ContentStaticReplace($v['use_guide'], 'get');
}
if(isset($v['produce_region']))
{
$v['produce_region_name'] = (!empty($produce_region_list) && is_array($produce_region_list) && array_key_exists($v['produce_region'], $produce_region_list)) ? $produce_region_list[$v['produce_region']] : '';
}
if(isset($v['brand_id']))
{
$v['brand_name'] = (!empty($brand_list) && is_array($brand_list) && array_key_exists($v['brand_id'], $brand_list)) ? $brand_list[$v['brand_id']] : '';
$v['brand_goods_url'] = (APPLICATION == 'app') ? '/pages/goods-search/goods-search?brand='.$v['brand_id'] : MyUrl('index/search/index', ['brand'=>$v['brand_id']]);
}
if(isset($v['approval_number_expire']))
{
$v['approval_number_expire'] = empty($v['approval_number_expire']) ? '' : date('Y-m-d', $v['approval_number_expire']);
}
if(isset($v['batch_number_expire']))
{
$v['batch_number_expire'] = empty($v['batch_number_expire']) ? '' : date('Y-m-d', $v['batch_number_expire']);
}
if(isset($v['add_time']))
{
$v['add_time'] = date('Y-m-d H:i:s', $v['add_time']);
}
if(isset($v['upd_time']))
{
$v['upd_time'] = empty($v['upd_time']) ? '' : date('Y-m-d H:i:s', $v['upd_time']);
}
if($is_category && !empty($data_id))
{
if(array_key_exists($data_id, $category_group))
{
$temp = $category_group[$data_id];
$v['category_ids'] = $temp['category_ids'];
$v['category_text'] = empty($temp['category_names']) ? '' : implode(',', $temp['category_names']);
} else {
$v['category_ids'] = [];
$v['category_text'] = '';
}
}
if(isset($v['spec_base']))
{
$v['spec_base'] = empty($v['spec_base']) ? '' : json_decode($v['spec_base'], true);
}
if($is_spec && !empty($data_id))
{
$v['specifications'] = (!empty($spec_group) && array_key_exists($data_id, $spec_group)) ? $spec_group[$data_id] : [];
}
if($is_params && !empty($data_id))
{
$v['parameters'] = (!empty($params_group) && array_key_exists($data_id, $params_group)) ? $params_group[$data_id] : [];
}
if($is_content_app && !empty($data_id))
{
$v['content_app'] = (!empty($app_group) && array_key_exists($data_id, $app_group)) ? $app_group[$data_id] : [];
}
if($is_cart && !empty($data_id))
{
$v['user_cart_count'] = (!empty($user_cart) && array_key_exists($data_id, $user_cart)) ? $user_cart[$data_id] : 0;
}
if($is_favor)
{
$v['user_is_favor'] = (!empty($user_favor) && in_array($data_id, $user_favor)) ? 1 : 0;
}
if($is_score)
{
$v['goods_score'] = (!empty($goods_score) && array_key_exists($data_id, $goods_score)) ? $goods_score[$data_id] : ['avg'=>0, 'score'=>0, 'count'=>0];
}
if(!empty($base_fields) && is_array($base_fields) && !empty($base_fields_show) && is_array($base_fields_show))
{
$base_data = [];
foreach($base_fields as $bfk=>$bfv)
{
if(in_array($bfk, $base_fields_show) && array_key_exists($bfk, $v) && $v[$bfk] != 0 && $v[$bfk] != '')
{
$base_data[] = [
'field' => $bfk,
'name' => $bfv,
'value' => $v[$bfk],
];
}
}
$v['base_data'] = empty($base_data) ? '' : $base_data;
}
$hook_name = 'plugins_service_goods_handle_end';
$ret = EventReturnHandle(MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'params' => &$params,
'goods' => &$v,
'goods_id' => isset($data_id) ? $data_id : 0,
]));
if(isset($ret['code']) && $ret['code'] != 0)
{
return $ret;
}
}
$hook_name = 'plugins_service_goods_list_handle_end';
MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'params' => &$params,
'data' => &$data,
]);
if(!empty($data) && is_array($data))
{
foreach($data as &$gv)
{
$data_id = isset($gv[$data_key_field]) ? $gv[$data_key_field] : 0;
if(!isset($gv['is_error']) || $gv['is_error'] == 0)
{
$gv['is_error'] = 0;
$gv['error_msg'] = '';
}
if($gv['is_error'] == 0 && array_key_exists('is_delete_time', $gv) && $gv['is_delete_time'] != 0)
{
$gv['is_error'] = 1;
$gv['error_msg'] = MyLang('goods_already_nullify_title');
}
if($gv['is_error'] == 0 && array_key_exists('is_shelves', $gv) && $gv['is_shelves'] != 1)
{
$gv['is_error'] = 1;
$gv['error_msg'] = MyLang('goods_already_shelves_title');
}
if($gv['is_error'] == 0 && array_key_exists('inventory', $gv) && $gv['inventory'] <= 0)
{
$gv['is_error'] = 1;
$gv['error_msg'] = MyLang('goods_no_inventory_title');
}
if($gv['is_error'] == 0 && array_key_exists('site_type', $gv) && !empty($data_id))
{
$ret = self::IsGoodsSiteTypeConsistent($data_id, $gv['site_type']);
if($ret['code'] != 0)
{
$gv['is_error'] = 1;
$gv['error_msg'] = $ret['msg'];
}
}
}
}
}
return DataReturn('success', 0, $data);
}
* 商品列表获取产品分类分组信息
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2022-10-13
* @desc description
* @param [array] $goods_ids [商品id]
* @param [array] $params [输入参数]
*/
public static function GoodsListCategoryGroupList($goods_ids, $params = [])
{
$result = [];
$category_join = Db::name('GoodsCategoryJoin')->where(['goods_id'=>$goods_ids])->field('goods_id,category_id')->select()->toArray();
if(!empty($category_join))
{
$category_name = Db::name('GoodsCategory')->where(['id'=>array_unique(array_column($category_join, 'category_id'))])->column('name', 'id');
if(!empty($category_name))
{
foreach($category_join as $v)
{
if(array_key_exists($v['category_id'], $category_name))
{
if(!array_key_exists($v['goods_id'], $result))
{
$result[$v['goods_id']] = [
'category_ids' => [],
'category_names' => [],
];
}
$result[$v['goods_id']]['category_ids'][] = $v['category_id'];
$result[$v['goods_id']]['category_names'][] = $category_name[$v['category_id']];
}
}
}
}
return $result;
}
* 获取商品封面图片
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-08-19
* @desc description
* @param [int] $goods_id [商品id]
* @param [array] $photo [商品相册]
*/
public static function GoodsImagesCoverHandle($goods_id = 0, $photo = [])
{
if(!empty($photo))
{
$photo = self::GoodsPhotoData($goods_id);
if(!empty($photo[0]) && !empty($photo[0]['images']))
{
$images = $photo[0]['images'];
}
}
if(empty($images) && !empty($goods_id))
{
$images = Db::name('GoodsPhoto')->where(['goods_id'=>$goods_id, 'is_show'=>1])->order('sort asc')->value('images');
}
return isset($images) ? $images : '';
}
* 商品相册
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-08-19
* @desc description
* @param [int|array] $goods_ids [商品id]
*/
public static function GoodsPhotoData($goods_ids)
{
$data = Db::name('GoodsPhoto')->where(['goods_id'=>$goods_ids, 'is_show'=>1])->order('sort asc')->select()->toArray();
if(is_array($goods_ids))
{
$group = [];
if(!empty($data))
{
foreach($data as $v)
{
if(!array_key_exists($v['goods_id'], $group))
{
$group[$v['goods_id']] = [];
}
$v['images'] = ResourcesService::AttachmentPathViewHandle($v['images']);
$group[$v['goods_id']][] = $v;
}
}
return $group;
}
return $data;
}
* 商品评分
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2023-03-20
* @desc description
* @param [array] $goods_ids [商品id]
* @param [array] $params [输入参数]
*/
public static function GoodsScoreData($goods_ids, $params = [])
{
$data = Db::name('GoodsComments')->where(['goods_id'=>$goods_ids])->group('goods_id')->column('goods_id, AVG(rating) AS avg, COUNT(goods_id) AS count', 'goods_id');
if(!empty($data))
{
foreach($data as &$v)
{
unset($v['goods_id']);
$v['avg'] = PriceNumberFormat($v['avg'], 1);
$v['score'] = ($v['avg'] <= 0) ? 100 : intval(($v['avg']/5)*100);
}
}
return $data;
}
* 获取用户收藏商品数据
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2023-03-20
* @desc description
* @param [array] $goods_ids [商品id]
* @param [array] $params [输入参数]
*/
public static function UserFavorGoodsCountData($goods_ids, $params = [])
{
$result = [];
$user = UserService::LoginUserInfo();
if(!empty($user))
{
$where = [
['goods_id', 'in', $goods_ids],
['user_id', '=', $user['id']],
];
$result = Db::name('GoodsFavor')->where($where)->column('goods_id');
}
return $result;
}
* 获取用户购物车商品总数
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2023-03-20
* @desc description
* @param [array] $goods_ids [商品id]
* @param [array] $params [输入参数]
*/
public static function UserCartGoodsCountData($goods_ids, $params = [])
{
$result = [];
$user = UserService::LoginUserInfo();
if(!empty($user))
{
$where = [
['goods_id', 'in', $goods_ids],
['user_id', '=', $user['id']],
];
$result = Db::name('Cart')->where($where)->field('SUM(stock) AS count, goods_id')->group('goods_id')->select()->toArray();
if(!empty($result))
{
$result = array_column($result, 'count', 'goods_id');
}
}
return $result;
}
* 获取商品手机详情
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-07-10
* @desc description
* @param [array] $goods_ids [商品id]
* @param [array] $params [输入参数]
* @return [array] [app内容]
*/
public static function GoodsAppData($goods_ids, $params = [])
{
$data = [];
$list = Db::name('GoodsContentApp')->where(['goods_id'=>$goods_ids])->field('id,goods_id,images,content')->order('sort asc')->select()->toArray();
if(!empty($list))
{
foreach($list as $v)
{
$v['images'] = ResourcesService::AttachmentPathViewHandle($v['images']);
$v['content_old'] = $v['content'];
$v['content'] = empty($v['content']) ? null : explode("\n", $v['content']);
if(!array_key_exists($v['goods_id'], $data))
{
$data[$v['goods_id']] = [];
}
$data[$v['goods_id']][] = $v;
}
}
$hook_name = 'plugins_service_goods_content_app_data';
MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'data' => &$data,
'goods_ids' => $goods_ids,
]);
return $data;
}
* 获取商品规格
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-07-16
* @desc description
* @param [array] $goods_ids [商品id]
* @param [array] $params [输入参数]
*/
public static function GoodsSpecificationsData($goods_ids, $params = [])
{
static $goods_spec_group_static_data = [];
$temp_goods_ids = [];
foreach($goods_ids as $gid)
{
if(empty($goods_spec_group_static_data) || !array_key_exists($gid, $goods_spec_group_static_data))
{
$temp_goods_ids[] = $gid;
}
}
if(!empty($temp_goods_ids))
{
$temp_group = [];
$data = Db::name('GoodsSpecType')->where(['goods_id'=>$temp_goods_ids])->order('id asc')->select()->toArray();
if(!empty($data))
{
foreach($data as $v)
{
if(!array_key_exists($v['goods_id'], $temp_group))
{
$temp_group[$v['goods_id']] = ['choose'=>[]];
}
$temp_group[$v['goods_id']]['choose'][] = $v;
}
foreach($temp_group as $gid=>&$gv)
{
if(!empty($gv['choose']))
{
foreach($gv['choose'] as &$gvs)
{
$gvs_value = json_decode($gvs['value'], true);
foreach($gvs_value as &$gvss)
{
$gvss['images'] = ResourcesService::AttachmentPathViewHandle($gvss['images']);
}
$gvs['value'] = $gvs_value;
$gvs['add_time'] = date('Y-m-d H:i:s', $gvs['add_time']);
}
if(count($gv['choose']) == 1)
{
foreach($gv['choose'][0]['value'] as &$temp_spec)
{
$temp_spec_params = array_merge($params, [
'id' => $gid,
'spec' => [
['type' => $gv['choose'][0]['name'], 'value' => $temp_spec['name']]
],
]);
$temp = self::GoodsSpecDetail($temp_spec_params);
if($temp['code'] == 0)
{
$temp_spec['is_only_level_one'] = 1;
$temp_spec['inventory'] = $temp['data']['spec_base']['inventory'];
}
}
}
}
$goods_spec_group_static_data[$gid] = $gv;
}
}
foreach($temp_goods_ids as $gid)
{
if(!array_key_exists($gid, $goods_spec_group_static_data))
{
$goods_spec_group_static_data[$gid] = [];
}
}
}
$data = [];
if(!empty($goods_spec_group_static_data))
{
foreach($goods_ids as $gid)
{
if(!empty($goods_spec_group_static_data[$gid]))
{
$data[$gid] = $goods_spec_group_static_data[$gid];
}
}
}
$hook_name = 'plugins_service_goods_spec_data';
MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'data' => &$data,
'goods_ids' => $goods_ids,
]);
return $data;
}
* 获取商品参数
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-08-31
* @desc description
* @param [array] $goods_ids [商品id]
* @param [array] $params [输入参数]
*/
public static function GoodsParametersData($goods_ids, $params = [])
{
$data = [];
$list = Db::name('GoodsParams')->where(['goods_id'=>$goods_ids])->order('id asc')->select()->toArray();
if(!empty($list))
{
foreach($list as $v)
{
if(!array_key_exists($v['goods_id'], $data))
{
$data[$v['goods_id']] = ['base'=>[], 'detail'=>[]];
}
if(in_array($v['scope'], [0,2]))
{
$data[$v['goods_id']]['base'][] = $v;
}
if(in_array($v['scope'], [0,1]))
{
$data[$v['goods_id']]['detail'][] = $v;
}
}
}
$hook_name = 'plugins_service_goods_parameters_data';
MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'data' => &$data,
'goods_ids' => $goods_ids,
]);
return $data;
}
* 商品规格简洁的数据处理
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-07-15
* @desc description
* @param [array] $data [规格数据]
*/
public static function GoodsSpecificationsConcise($data)
{
$result = [];
if(!empty($data))
{
foreach($data as $v)
{
$result[] = array_column($v['value'], 'name');
}
}
return $result;
}
* 获取商品当前实际存在的规格
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-07-16
* @desc description
* @param [int] $goods_id [商品id]
*/
public static function GoodsSpecificationsActual($goods_id)
{
$where = ['goods_id'=>$goods_id];
$title = Db::name('GoodsSpecType')->where($where)->column('name');
$value = Db::name('GoodsSpecValue')->where($where)->field('goods_spec_base_id,value')->select()->toArray();
$group = [];
if(!empty($value))
{
foreach($value as $v)
{
if(!isset($group[$v['goods_spec_base_id']]))
{
$group[$v['goods_spec_base_id']] = [];
$group[$v['goods_spec_base_id']]['base_id'] = $v['goods_spec_base_id'];
}
$group[$v['goods_spec_base_id']]['value'][] = $v['value'];
}
foreach($group as &$gv)
{
$gv['value'] = implode(self::$goods_spec_to_string_separator, $gv['value']);
}
sort($group);
}
return [
'title' => $title,
'value' => $group,
];
}
* 规格值组合
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-07-16
* @desc description
* @param [string] $spec_str [规格字符串,英文逗号分割]
* @param [array] $spec_title [规格类型名称]
*/
public static function GoodsSpecMuster($spec_str, $spec_title)
{
$result = [];
$arr = explode(self::$goods_spec_to_string_separator, $spec_str);
if(count($arr) == count($spec_title))
{
foreach($arr as $k=>$v)
{
$result[] = [
'type' => $spec_title[$k],
'value' => $v,
];
}
}
return $result;
}
* 商品访问统计加1
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-10-15
* @desc description
* @param [array] $params [输入参数]
*/
public static function GoodsAccessCountInc($params = [])
{
if(!empty($params['goods_id']))
{
return Db::name('Goods')->where(['id'=>intval($params['goods_id'])])->inc('access_count')->update();
}
return false;
}
* 获取商品总数
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-09-07
* @desc description
* @param [array] $where [条件]
*/
public static function GoodsTotal($where = [])
{
$hook_name = 'plugins_service_goods_total_begin';
MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'where' => &$where,
]);
return (int) Db::name('Goods')->where($where)->count();
}
* 获取商品列表
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-08-29
* @desc description
* @param array $params [输入参数: where, field, is_photo]
*/
public static function GoodsList($params = [])
{
$where = empty($params['where']) ? [] : $params['where'];
$field = empty($params['field']) ? '*' : $params['field'];
$order_by = empty($params['order_by']) ? 'id desc' : trim($params['order_by']);
$m = isset($params['m']) ? intval($params['m']) : 0;
$n = isset($params['n']) ? intval($params['n']) : 10;
$hook_name = 'plugins_service_goods_list_begin';
MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'params' => &$params,
'where' => &$where,
'field' => &$field,
'order_by' => &$order_by,
'm' => &$m,
'n' => &$n,
]);
$data = Db::name('Goods')->field($field)->where($where)->order($order_by)->limit($m, $n)->select()->toArray();
return self::GoodsDataHandle($data, $params);
}
* 商品保存
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @datetime 2018-12-10T01:02:11+0800
* @param [array] $params [输入参数]
*/
public static function GoodsSave($params = [])
{
$category_ids = empty($params['category_id']) ? [] : (is_array($params['category_id']) ? $params['category_id'] : explode(',', $params['category_id']));
$required_fields = empty($category_ids) ? [] : self::GoodsBaseFieldsRequiredConfigData($category_ids);
$is_simple_desc = !empty($required_fields) && isset($required_fields['simple_desc']) && $required_fields['simple_desc'] == 1;
$is_spec_desc = !empty($required_fields) && isset($required_fields['spec_desc']) && $required_fields['spec_desc'] == 1;
$is_approval_number = !empty($required_fields) && isset($required_fields['approval_number']) && $required_fields['approval_number'] == 1;
$is_approval_number_expire = !empty($required_fields) && isset($required_fields['approval_number_expire']) && $required_fields['approval_number_expire'] == 1;
$is_batch_number = !empty($required_fields) && isset($required_fields['batch_number']) && $required_fields['batch_number'] == 1;
$is_batch_number_expire = !empty($required_fields) && isset($required_fields['batch_number_expire']) && $required_fields['batch_number_expire'] == 1;
$is_coding = !empty($required_fields) && isset($required_fields['coding']) && $required_fields['coding'] == 1;
$is_model = !empty($required_fields) && isset($required_fields['model']) && $required_fields['model'] == 1;
$is_brand_id = !empty($required_fields) && isset($required_fields['brand_id']) && $required_fields['brand_id'] == 1;
$is_produce_company = !empty($required_fields) && isset($required_fields['produce_company']) && $required_fields['produce_company'] == 1;
$is_produce_region = !empty($required_fields) && isset($required_fields['produce_region']) && $required_fields['produce_region'] == 1;
$p = [
[
'checked_type' => 'length',
'key_name' => 'title',
'checked_data' => '2,160',
'error_msg' => MyLang('common_service.goods.form_item_title_message'),
],
[
'checked_type' => 'length',
'key_name' => 'simple_desc',
'checked_data' => $is_simple_desc ? '1,230' : '230',
'is_checked' => $is_simple_desc ? null : 1,
'error_msg' => MyLang('common_service.goods.form_item_simple_desc_message'),
],
[
'checked_type' => 'length',
'key_name' => 'spec_desc',
'checked_data' => $is_spec_desc ? '1,230' : '230',
'is_checked' => $is_spec_desc ? null : 1,
'error_msg' => MyLang('common_service.goods.form_item_spec_desc_message'),
],
[
'checked_type' => 'length',
'key_name' => 'approval_number',
'checked_data' => $is_approval_number ? '1,180' : '180',
'is_checked' => $is_approval_number ? null : 1,
'error_msg' => MyLang('common_service.goods.form_item_approval_number_message'),
],
[
'checked_type' => 'empty',
'key_name' => 'approval_number_expire',
'is_checked' => $is_approval_number_expire ? null : 1,
'error_msg' => MyLang('common_service.goods.form_item_approval_number_expire_message'),
],
[
'checked_type' => 'length',
'key_name' => 'batch_number',
'checked_data' => $is_batch_number ? '1,180' : '180',
'is_checked' => $is_batch_number ? null : 1,
'error_msg' => MyLang('common_service.goods.form_item_batch_number_message'),
],
[
'checked_type' => 'empty',
'key_name' => 'batch_number_expire',
'is_checked' => $is_batch_number_expire ? null : 1,
'error_msg' => MyLang('common_service.goods.form_item_batch_number_expire_message'),
],
[
'checked_type' => 'length',
'key_name' => 'coding',
'checked_data' => $is_coding ? '1,180' : '180',
'is_checked' => $is_coding ? null : 1,
'error_msg' => MyLang('common_service.goods.form_item_coding_message'),
],
[
'checked_type' => 'length',
'key_name' => 'model',
'checked_data' => $is_model ? '1,180' : '180',
'is_checked' => $is_model ? null : 1,
'error_msg' => MyLang('common_service.goods.form_item_model_message'),
],
[
'checked_type' => 'empty',
'key_name' => 'brand_id',
'is_checked' => $is_brand_id ? null : 1,
'error_msg' => MyLang('common_service.goods.form_item_brand_id_message'),
],
[
'checked_type' => 'length',
'key_name' => 'produce_company',
'checked_data' => $is_produce_company ? '1,180' : '180',
'is_checked' => $is_produce_company ? null : 1,
'error_msg' => MyLang('common_service.goods.form_item_produce_company_message'),
],
[
'checked_type' => 'empty',
'key_name' => 'produce_region',
'is_checked' => $is_produce_region ? null : 1,
'error_msg' => MyLang('common_service.goods.form_item_produce_region_message'),
],
[
'checked_type' => 'empty',
'key_name' => 'category_id',
'error_msg' => MyLang('common_service.goods.form_item_category_id_message'),
],
[
'checked_type' => 'length',
'key_name' => 'inventory_unit',
'checked_data' => '1,6',
'error_msg' => MyLang('common_service.goods.form_item_inventory_unit_message'),
],
[
'checked_type' => 'in',
'key_name' => 'site_type',
'checked_data' => array_column(MyConst('common_site_type_list'), 'value'),
'is_checked' => 1,
'error_msg' => MyLang('common_service.goods.save_site_type_error_tips'),
],
[
'checked_type' => 'length',
'key_name' => 'seo_title',
'checked_data' => '100',
'is_checked' => 1,
'error_msg' => MyLang('form_seo_title_message'),
],
[
'checked_type' => 'length',
'key_name' => 'seo_keywords',
'checked_data' => '130',
'is_checked' => 1,
'error_msg' => MyLang('form_seo_keywords_message'),
],
[
'checked_type' => 'length',
'key_name' => 'seo_desc',
'checked_data' => '230',
'is_checked' => 1,
'error_msg' => MyLang('form_seo_desc_message'),
],
];
$ret = ParamsChecked($params, $p);
if($ret !== true)
{
return DataReturn($ret, -1);
}
$specifications_base = self::GetFormGoodsSpecificationsBaseParams($params);
if($specifications_base['code'] != 0)
{
return $specifications_base;
}
$specifications = self::GetFormGoodsSpecificationsParams($params);
if($specifications['code'] != 0)
{
return $specifications;
}
$parameter = GoodsParamsService::GoodsParamsTemplateSaveHandle($params);
$parameter_template_check = GoodsParamsService::GoodsParamsTemplateSaveCheck(['category_ids'=>$category_ids, 'parameter_value'=>$parameter['data']]);
if($parameter_template_check['code'] != 0)
{
return $parameter_template_check;
}
$photo = self::GetFormGoodsPhotoParams($params);
if($photo['code'] != 0)
{
return $photo;
}
$content_app = self::GetFormGoodsContentAppParams($params);
if($content_app['code'] != 0)
{
return $content_app;
}
$attachment = ResourcesService::AttachmentParams($params, ['images', 'video', 'share_images']);
if($attachment['code'] != 0)
{
return $attachment;
}
$content_web = empty($params['content_web']) ? '' : str_replace("\n", '', ResourcesService::ContentStaticReplace(htmlspecialchars_decode($params['content_web']), 'add'));
$fictitious_goods_value = empty($params['fictitious_goods_value']) ? '' : str_replace("\n", '', ResourcesService::ContentStaticReplace(htmlspecialchars_decode($params['fictitious_goods_value']), 'add'));
$use_guide = empty($params['use_guide']) ? '' : str_replace("\n", '', ResourcesService::ContentStaticReplace(htmlspecialchars_decode($params['use_guide']), 'add'));
$images = empty($attachment['data']['images']) ? (isset($photo['data'][0]) ? $photo['data'][0] : '') : $attachment['data']['images'];
$data = [
'title' => $params['title'],
'title_color' => empty($params['title_color']) ? '' : $params['title_color'],
'simple_desc' => empty($params['simple_desc']) ? '' : $params['simple_desc'],
'spec_desc' => empty($params['spec_desc']) ? '' : $params['spec_desc'],
'approval_number' => empty($params['approval_number']) ? '' : $params['approval_number'],
'approval_number_expire' => empty($params['approval_number_expire']) ? 0 : strtotime($params['approval_number_expire']),
'batch_number' => empty($params['batch_number']) ? '' : $params['batch_number'],
'batch_number_expire' => empty($params['batch_number_expire']) ? 0 : strtotime($params['batch_number_expire']),
'coding' => empty($params['coding']) ? '' : $params['coding'],
'model' => empty($params['model']) ? '' : $params['model'],
'produce_company' => empty($params['produce_company']) ? '' : $params['produce_company'],
'produce_region' => isset($params['produce_region']) ? intval($params['produce_region']) : 0,
'inventory_unit' => $params['inventory_unit'],
'is_deduction_inventory' => isset($params['is_deduction_inventory']) ? intval($params['is_deduction_inventory']) : 0,
'is_shelves' => isset($params['is_shelves']) ? intval($params['is_shelves']) : 0,
'content_web' => $content_web,
'photo_count' => count($photo['data']),
'images' => $images,
'brand_id' => isset($params['brand_id']) ? intval($params['brand_id']) : 0,
'video' => $attachment['data']['video'],
'seo_title' => empty($params['seo_title']) ? '' : $params['seo_title'],
'seo_keywords' => empty($params['seo_keywords']) ? '' : $params['seo_keywords'],
'seo_desc' => empty($params['seo_desc']) ? '' : $params['seo_desc'],
'is_exist_many_spec' => empty($specifications['data']['title']) ? 0 : 1,
'spec_base' => empty($specifications_base['data']) ? '' : json_encode($specifications_base['data'], JSON_UNESCAPED_UNICODE),
'fictitious_goods_value' => $fictitious_goods_value,
'use_guide' => $use_guide,
'site_type' => (isset($params['site_type']) && $params['site_type'] != '') ? $params['site_type'] : -1,
'sort_level' => empty($params['sort_level']) ? 0 : intval($params['sort_level']),
'share_images' => $attachment['data']['share_images'],
];
if(array_key_exists('give_integral', $params))
{
$data['give_integral'] = intval($params['give_integral']);
}
$hook_name = 'plugins_service_goods_save_handle';
$ret = EventReturnHandle(MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'params' => &$params,
'data' => &$data,
'spec' => &$specifications['data'],
'parameter' => &$parameter['data'],
'photo' => &$photo['data'],
'content_app' => &$content_app['data'],
'goods_id' => isset($params['id']) ? intval($params['id']) : 0,
]));
if(isset($ret['code']) && $ret['code'] != 0)
{
return $ret;
}
Db::startTrans();
try {
$hook_name = 'plugins_service_goods_save_thing_begin';
$ret = MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'params' => $params,
'data' => &$data,
'goods_id' => isset($params['id']) ? intval($params['id']) : 0,
]);
if(isset($ret['code']) && $ret['code'] != 0)
{
throw new \Exception($ret['msg']);
}
if(empty($params['id']))
{
$data['add_time'] = time();
$goods_id = Db::name('Goods')->insertGetId($data);
if($goods_id <= 0)
{
throw new \Exception(MyLang('insert_fail'));
}
} else {
$data['upd_time'] = time();
if(Db::name('Goods')->where(['id'=>intval($params['id'])])->update($data))
{
$goods_id = $params['id'];
} else {
throw new \Exception(MyLang('update_fail'));
}
}
$ret = self::GoodsCategoryInsert($category_ids, $goods_id);
if($ret['code'] != 0)
{
throw new \Exception($ret['msg']);
}
$ret = self::GoodsSpecificationsInsert($specifications['data'], $goods_id);
if($ret['code'] != 0)
{
throw new \Exception($ret['msg']);
}
$ret = self::GoodsSaveBaseUpdate($goods_id);
if($ret['code'] != 0)
{
throw new \Exception($ret['msg']);
}
$ret = self::GoodsPhotoInsert($photo['data'], $goods_id);
if($ret['code'] != 0)
{
throw new \Exception($ret['msg']);
}
$ret = self::GoodsContentAppInsert($content_app['data'], $goods_id);
if($ret['code'] != 0)
{
throw new \Exception($ret['msg']);
}
$ret = self::GoodsParamsInsert($parameter['data'], $goods_id);
if($ret['code'] != 0)
{
throw new \Exception($ret['msg']);
}
$ret = WarehouseGoodsService::GoodsSpecChangeInventorySync($goods_id);
if($ret['code'] != 0)
{
throw new \Exception($ret['msg']);
}
$hook_name = 'plugins_service_goods_save_thing_end';
$ret = MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'params' => $params,
'data' => $data,
'goods_id' => $goods_id,
]);
if(isset($ret['code']) && $ret['code'] != 0)
{
throw new \Exception($ret['msg']);
}
Db::commit();
} catch(\Exception $e) {
Db::rollback();
return DataReturn($e->getMessage(), -1);
}
$hook_name = 'plugins_service_goods_save_end';
MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'params' => $params,
'data' => $data,
'goods_id' => $goods_id,
]);
return DataReturn(MyLang('operate_success'), 0);
}
* 商品参数添加
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-08-31
* @desc description
* @param [array] $data [商品参数数据]
* @param [int] $goods_id [商品id]
*/
public static function GoodsParamsInsert($data, $goods_id)
{
Db::name('GoodsParams')->where(['goods_id'=>$goods_id])->delete();
if(!empty($data))
{
foreach($data as &$v)
{
$v['goods_id'] = $goods_id;
$v['add_time'] = time();
}
if(Db::name('GoodsParams')->insertAll($data) < count($data))
{
return DataReturn(MyLang('common_service.goods.save_params_add_fail_tips'), -1);
}
}
return DataReturn(MyLang('operate_success'), 0);
}
* 商品保存基础信息更新
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @datetime 2018-12-16T01:56:42+0800
* @param [int] $goods_id [商品id]
* @param [array] $params [输入参数]
*/
public static function GoodsSaveBaseUpdate($goods_id, $params = [])
{
$base = Db::name('GoodsSpecBase')->where(['goods_id'=>$goods_id])->select()->toArray();
if(empty($base))
{
return DataReturn(MyLang('common_service.goods.save_goods_base_empty_tips'), -1);
}
$data = [
'min_price' => min(array_column($base, 'price')),
'max_price' => max(array_column($base, 'price')),
'min_original_price' => min(array_column($base, 'original_price')),
'max_original_price' => max(array_column($base, 'original_price')),
'inventory' => array_sum(array_column($base, 'inventory')),
];
$data['buy_min_number'] = min(array_column($base, 'buy_min_number'));
if($data['buy_min_number'] <= 0)
{
$data['buy_min_number'] = 1;
}
$buy_max_number = max(array_column($base, 'buy_max_number'));
$data['buy_max_number'] = ($buy_max_number > 0 && min(array_column($base, 'buy_max_number')) > 0) ? $buy_max_number : 0;
$data['price'] = (!empty($data['max_price']) && $data['min_price'] != $data['max_price']) ? $data['min_price'].'-'.$data['max_price'] : $data['min_price'];
$data['original_price'] = (!empty($data['max_original_price']) && $data['min_original_price'] != $data['max_original_price']) ? $data['min_original_price'].'-'.$data['max_original_price'] : $data['min_original_price'];
$data['upd_time'] = time();
if(Db::name('Goods')->where(['id'=>$goods_id])->update($data) === false)
{
return DataReturn(MyLang('common_service.goods.save_goods_base_update_fail_tips'), -1);
}
$hook_name = 'plugins_service_goods_base_update';
$ret = EventReturnHandle(MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'goods_id' => $goods_id,
'params' => $params,
]));
if(isset($ret['code']) && $ret['code'] != 0)
{
return $ret;
}
return DataReturn(MyLang('operate_success'), 0);
}
* 获取规格值参数
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-07-09
* @desc description
* @param [array] $params [输入参数]
* @param [array] $base_count [教程参数个数,默认9]
*/
public static function GetFormGoodsSpecificationsParams($params = [], $base_count = 9)
{
$data = [];
$title = [];
$images = [];
foreach($params as $k=>$v)
{
if(substr($k, 0, 15) == 'specifications_')
{
$keys = explode('_', $k);
if(count($keys) > 1)
{
if($keys[1] != 'name')
{
foreach($v as $ks=>$vs)
{
if($keys[1] == 'extends')
{
$data[$ks][] = empty($vs) ? null : htmlspecialchars_decode($vs);
} else {
$data[$ks][] = trim($vs);
}
}
}
}
}
}
if(!empty($data[0]))
{
$count = count($data[0])-$base_count;
if($count > 0)
{
$column_value = [];
foreach($data as $data_value)
{
foreach($data_value as $temp_key=>$temp_value)
{
if($temp_key < $count)
{
$column_value[$temp_key][] = $temp_value;
}
}
}
if(!empty($column_value) && count($column_value) > 1)
{
$temp_column = [];
foreach($column_value as $column_key=>$column_val)
{
foreach($column_value as $column_keys=>$column_vals)
{
if($column_key != $column_keys)
{
$temp = array_intersect($column_val, $column_vals);
$temp_column = array_merge($temp_column, $temp);
}
}
}
if(!empty($temp_column))
{
return DataReturn(MyLang('common_service.goods.save_spec_column_repeat_tips').'['.implode(',', array_unique($temp_column)).']', -1);
}
}
if(!empty($column_value[0]))
{
$temp_row_data = [];
$temp_row_count = count($column_value);
foreach($column_value[0] as $row_key=>$row_value)
{
for($i=0; $i<$temp_row_count; $i++)
{
if(isset($column_value[$i][$row_key]))
{
if(isset($temp_row_data[$row_key]))
{
$temp_row_data[$row_key] .= $column_value[$i][$row_key];
} else {
$temp_row_data[$row_key] = $column_value[$i][$row_key];
}
}
}
}
if(!empty($temp_row_data))
{
$unique_all = array_unique($temp_row_data);
$repeat_rows_all = array_diff_assoc($temp_row_data, $unique_all);
if(!empty($repeat_rows_all))
{
return DataReturn(MyLang('common_service.goods.save_spec_value_repeat_tips').'['.implode(',', array_unique($repeat_rows_all)).']', -1);
}
}
}
$names_value = [];
$names = array_slice($data[0], 0, $count);
foreach($names as $v)
{
foreach($params as $ks=>$vs)
{
if(substr($ks, 0, 21) == 'specifications_value_')
{
if(in_array($v, $vs))
{
$key = substr($ks, 21);
if(!empty($params['specifications_name_'.$key]))
{
$spec_name = trim($params['specifications_name_'.$key]);
$title[$spec_name] = [
'name' => $spec_name,
'value' => array_unique($vs),
];
$names_value[] = $params['specifications_name_'.$key];
}
}
}
}
}
$unique_all = array_unique($names_value);
$repeat_names_all = array_diff_assoc($names_value, $unique_all);
if(!empty($repeat_names_all))
{
return DataReturn(MyLang('common_service.goods.save_spec_name_column_repeat_tips').'['.implode(',', array_unique($repeat_names_all)).']', -1);
}
} else {
if(!isset($data[0][0]) || $data[0][0] < 0)
{
return DataReturn(MyLang('common_service.goods.save_spec_base_price_error_tips'), -1);
}
}
} else {
return DataReturn(MyLang('common_service.goods.save_spec_empty_tips'), -1);
}
if(!empty($params['spec_images_name']) && !empty($params['spec_images']))
{
foreach($params['spec_images_name'] as $k=>$v)
{
if(!empty($params['spec_images'][$k]))
{
$images[$v] = $params['spec_images'][$k];
}
}
}
return DataReturn('success', 0, ['data'=>$data, 'title'=>$title, 'images'=>$images]);
}
* 获取规格基础参数
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2019-09-23
* @desc description
* @param [array] $params [输入参数]
*/
public static function GetFormGoodsSpecificationsBaseParams($params = [])
{
$result = [];
foreach($params as $k=>$v)
{
if(substr($k, 0, 16) == 'spec_base_title_')
{
$key = substr($k, 16);
$result[] = [
'title' => $v,
'value' => isset($params['spec_base_value_'.$key]) ? $params['spec_base_value_'.$key] : [],
];
}
}
return DataReturn('success', 0, $result);
}
* 获取商品相册
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-07-10
* @desc description
* @param [array] $params [输入参数]
* @return [array] [一维数组但图片地址]
*/
public static function GetFormGoodsPhotoParams($params = [])
{
if(empty($params['photo']))
{
return DataReturn(MyLang('common_service.goods.save_photo_empty_tips'), -1);
}
$result = ResourcesService::AttachmentPathHandle($params['photo']);
return DataReturn('success', 0, $result);
}
* 获取app内容
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-07-09
* @desc description
* @param [array] $params [输入参数]
*/
public static function GetFormGoodsContentAppParams($params = [])
{
$result = [];
$name = 'content_app_';
foreach($params AS $k=>$v)
{
if(substr($k, 0, 12) == $name)
{
$key = explode('_', str_replace($name, '', $k));
if(count($key) == 2)
{
$result[$key[1]][$key[0]] = $v;
if($key[0] == 'images')
{
$result[$key[1]][$key[0]] = ResourcesService::AttachmentPathHandle($v);
}
}
}
}
return DataReturn('success', 0, $result);
}
* 商品分类添加
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-07-10
* @desc description
* @param [array] $data [数据]
* @param [int] $goods_id [商品id]
* @return [array] [boolean | msg]
*/
public static function GoodsCategoryInsert($data, $goods_id)
{
Db::name('GoodsCategoryJoin')->where(['goods_id'=>$goods_id])->delete();
if(!empty($data))
{
foreach($data as $category_id)
{
$temp_category = [
'goods_id' => $goods_id,
'category_id' => $category_id,
'add_time' => time(),
];
if(Db::name('GoodsCategoryJoin')->insertGetId($temp_category) <= 0)
{
return DataReturn(MyLang('common_service.goods.save_category_add_fail_tips'), -1);
}
}
}
return DataReturn(MyLang('insert_success'), 0);
}
* 商品手机详情添加
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-07-10
* @desc description
* @param [array] $data [数据]
* @param [int] $goods_id [商品id]
* @return [array] [boolean | msg]
*/
public static function GoodsContentAppInsert($data, $goods_id)
{
Db::name('GoodsContentApp')->where(['goods_id'=>$goods_id])->delete();
if(!empty($data))
{
foreach(array_values($data) as $k=>$v)
{
$temp_content = [
'goods_id' => $goods_id,
'images' => empty($v['images']) ? '' : $v['images'],
'content' => $v['text'],
'sort' => $k,
'add_time' => time(),
];
if(Db::name('GoodsContentApp')->insertGetId($temp_content) <= 0)
{
return DataReturn(MyLang('common_service.goods.save_app_content_add_fail_tips'), -1);
}
}
}
return DataReturn(MyLang('insert_success'), 0);
}
* 商品相册添加
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-07-10
* @desc description
* @param [array] $data [数据]
* @param [int] $goods_id [商品id]
* @return [array] [boolean | msg]
*/
public static function GoodsPhotoInsert($data, $goods_id)
{
Db::name('GoodsPhoto')->where(['goods_id'=>$goods_id])->delete();
if(!empty($data))
{
foreach($data as $k=>$v)
{
$temp_photo = [
'goods_id' => $goods_id,
'images' => $v,
'is_show' => 1,
'sort' => $k,
'add_time' => time(),
];
if(Db::name('GoodsPhoto')->insertGetId($temp_photo) <= 0)
{
return DataReturn(MyLang('common_service.goods.save_photo_add_fail_tips'), -1);
}
}
}
return DataReturn(MyLang('insert_success'), 0);
}
* 商品规格添加
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-07-10
* @desc description
* @param [array] $data [数据]
* @param [int] $goods_id [商品id]
* @return [array] [boolean | msg]
*/
public static function GoodsSpecificationsInsert($data, $goods_id)
{
Db::name('GoodsSpecType')->where(['goods_id'=>$goods_id])->delete();
Db::name('GoodsSpecValue')->where(['goods_id'=>$goods_id])->delete();
Db::name('GoodsSpecBase')->where(['goods_id'=>$goods_id])->delete();
if(!empty($data['title']))
{
foreach($data['title'] as &$v)
{
$spec = [];
foreach($v['value'] as $vs)
{
$spec[] = [
'name' => $vs,
'images' => isset($data['images'][$vs]) ? ResourcesService::AttachmentPathHandle($data['images'][$vs]) : '',
];
}
$v['goods_id'] = $goods_id;
$v['value'] = json_encode($spec, JSON_UNESCAPED_UNICODE);
$v['add_time'] = time();
}
if(Db::name('GoodsSpecType')->insertAll($data['title']) < count($data['title']))
{
return DataReturn(MyLang('common_service.goods.save_spec_type_add_fail_tips'), -1);
}
}
if(!empty($data['data']))
{
$count = count($data['data'][0]);
$temp_key = self::GoodsSpecBaseFields();
$key_count = count($temp_key);
if($count == $key_count)
{
$temp_data = [
'goods_id' => $goods_id,
'add_time' => time(),
];
for($i=0; $i<$count; $i++)
{
$temp_data[$temp_key[$i]] = $data['data'][0][$i];
}
$temp_data['inventory'] = WarehouseGoodsService::WarehouseGoodsSpecInventory($goods_id);
if(Db::name('GoodsSpecBase')->insertGetId($temp_data) <= 0)
{
return DataReturn(MyLang('common_service.goods.save_spec_base_add_fail_tips'), -1);
}
} else {
$base_start = $count-$key_count;
foreach($data['data'] as $v)
{
$temp_value = [];
$temp_data = [
'goods_id' => $goods_id,
'add_time' => time(),
];
for($i=0; $i<$count; $i++)
{
if($i < $base_start)
{
$temp_value[] = [
'goods_id' => $goods_id,
'value' => $v[$i],
'md5_key' => empty($v[$i]) ? '' : md5($v[$i]),
'add_time' => time()
];
} else {
$temp_data[$temp_key[$i-$base_start]] = $v[$i];
}
}
$temp_data['inventory'] = WarehouseGoodsService::WarehouseGoodsSpecInventory($goods_id, implode('', array_column($temp_value, 'value')));
$base_id = Db::name('GoodsSpecBase')->insertGetId($temp_data);
if(empty($base_id))
{
return DataReturn(MyLang('common_service.goods.save_spec_base_add_fail_tips'), -1);
}
foreach($temp_value as &$value)
{
$value['goods_spec_base_id'] = $base_id;
}
if(Db::name('GoodsSpecValue')->insertAll($temp_value) < count($temp_value))
{
return DataReturn(MyLang('common_service.goods.save_spec_value_add_fail_tips'), -1);
}
}
}
}
return DataReturn(MyLang('insert_success'), 0);
}
* 商品规格基础数据字段
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2025-09-16
* @desc description
* @param [array] $params [输入参数]
*/
public static function GoodsSpecBaseFields($params = [])
{
return [
'price',
'original_price',
'buy_min_number',
'buy_max_number',
'weight',
'volume',
'coding',
'barcode',
'inventory_unit',
'extends',
];
}
* 商品删除
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @datetime 2018-12-07T00:24:14+0800
* @param [array] $params [输入参数]
*/
public static function GoodsDelete($params = [])
{
if(empty($params['ids']))
{
return DataReturn(MyLang('data_id_error_tips'), -1);
}
if(!is_array($params['ids']))
{
$params['ids'] = explode(',', $params['ids']);
}
Db::startTrans();
try {
self::GoodsDeleteHandle($params['ids'], $params);
$hook_name = 'plugins_service_goods_delete';
MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'params' => $params,
'goods_ids' => $params['ids'],
]);
Db::commit();
return DataReturn(MyLang('delete_success'), 0);
} catch(\Exception $e) {
Db::rollback();
return DataReturn($e->getMessage(), -1);
}
}
* 商品删除操作
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2021-01-27
* @desc description
* @param [array] $goods_ids [商品id]
* @param [array] $params [输入参数]
*/
public static function GoodsDeleteHandle($goods_ids, $params = [])
{
$del_attachment_data = [];
$is_del_images = isset($params['is_del_images']) && $params['is_del_images'] == 1;
if($is_del_images)
{
$goods_images = Db::name('Goods')->where([['id', 'in', $goods_ids], ['images', '<>', '']])->column('images');
if(!empty($goods_images))
{
$del_attachment_data = array_unique(array_merge($del_attachment_data, $goods_images));
}
$goods_video = Db::name('Goods')->where([['id', 'in', $goods_ids], ['video', '<>', '']])->column('video');
if(!empty($goods_video))
{
$del_attachment_data = array_unique(array_merge($del_attachment_data, $goods_video));
}
$goods_share_images = Db::name('Goods')->where([['id', 'in', $goods_ids], ['share_images', '<>', '']])->column('share_images');
if(!empty($goods_share_images))
{
$del_attachment_data = array_unique(array_merge($del_attachment_data, $goods_share_images));
}
$goods_spec_type = Db::name('GoodsSpecType')->where(['goods_id'=>$goods_ids])->column('value');
if(!empty($goods_spec_type))
{
foreach($goods_spec_type as $v)
{
$v = json_decode($v, true);
if(!empty($v) && is_array($v))
{
$temp = array_unique(array_filter(array_column($v, 'images')));
if(!empty($temp))
{
$del_attachment_data = array_unique(array_merge($del_attachment_data, $temp));
}
}
}
}
$goods_photo = Db::name('GoodsPhoto')->where(['goods_id'=>$goods_ids])->column('images');
if(!empty($goods_photo))
{
$del_attachment_data = array_unique(array_merge($del_attachment_data, $goods_photo));
}
$goods_content = Db::name('Goods')->where([['id', 'in', $goods_ids], ['content_web', '<>', '']])->column('content_web');
if(!empty($goods_content))
{
foreach($goods_content as $v)
{
$temp = ResourcesService::RichTextMatchContentAttachment($v, 'goods', 'images');
if(!empty($temp))
{
$del_attachment_data = array_unique(array_merge($del_attachment_data, $temp));
}
$temp = ResourcesService::RichTextMatchContentAttachment($v, 'goods', 'video');
if(!empty($temp))
{
$del_attachment_data = array_unique(array_merge($del_attachment_data, $temp));
}
$temp = ResourcesService::RichTextMatchContentAttachment($v, 'goods', 'file');
if(!empty($temp))
{
$del_attachment_data = array_unique(array_merge($del_attachment_data, $temp));
}
}
}
$goods_fictitious = Db::name('Goods')->where([['id', 'in', $goods_ids], ['fictitious_goods_value', '<>', '']])->column('fictitious_goods_value');
if(!empty($goods_fictitious))
{
foreach($goods_fictitious as $v)
{
$temp = ResourcesService::RichTextMatchContentAttachment($v, 'goods', 'images');
if(!empty($temp))
{
$del_attachment_data = array_unique(array_merge($del_attachment_data, $temp));
}
$temp = ResourcesService::RichTextMatchContentAttachment($v, 'goods', 'video');
if(!empty($temp))
{
$del_attachment_data = array_unique(array_merge($del_attachment_data, $temp));
}
$temp = ResourcesService::RichTextMatchContentAttachment($v, 'goods', 'file');
if(!empty($temp))
{
$del_attachment_data = array_unique(array_merge($del_attachment_data, $temp));
}
}
}
$goods_use_guide = Db::name('Goods')->where([['id', 'in', $goods_ids], ['use_guide', '<>', '']])->column('use_guide');
if(!empty($goods_use_guide))
{
foreach($goods_use_guide as $v)
{
$temp = ResourcesService::RichTextMatchContentAttachment($v, 'goods', 'images');
if(!empty($temp))
{
$del_attachment_data = array_unique(array_merge($del_attachment_data, $temp));
}
$temp = ResourcesService::RichTextMatchContentAttachment($v, 'goods', 'video');
if(!empty($temp))
{
$del_attachment_data = array_unique(array_merge($del_attachment_data, $temp));
}
$temp = ResourcesService::RichTextMatchContentAttachment($v, 'goods', 'file');
if(!empty($temp))
{
$del_attachment_data = array_unique(array_merge($del_attachment_data, $temp));
}
}
}
$goods_app = Db::name('GoodsContentApp')->where([['goods_id', 'in', $goods_ids], ['images', '<>', '']])->column('images');
if(!empty($goods_app))
{
$del_attachment_data = array_unique(array_merge($del_attachment_data, $goods_app));
}
}
if(Db::name('Goods')->where(['id'=>$goods_ids])->delete() === false)
{
throw new \Exception(MyLang('common_service.goods.delete_goods_fail_tips'));
}
if(Db::name('GoodsSpecType')->where(['goods_id'=>$goods_ids])->delete() === false)
{
throw new \Exception(MyLang('common_service.goods.delete_spec_type_fail_tips'));
}
if(Db::name('GoodsSpecValue')->where(['goods_id'=>$goods_ids])->delete() === false)
{
throw new \Exception(MyLang('common_service.goods.delete_spec_value_fail_tips'));
}
if(Db::name('GoodsSpecBase')->where(['goods_id'=>$goods_ids])->delete() === false)
{
throw new \Exception(MyLang('common_service.goods.delete_spec_base_fail_tips'));
}
if(Db::name('GoodsCategoryJoin')->where(['goods_id'=>$goods_ids])->delete() === false)
{
throw new \Exception(MyLang('common_service.goods.delete_goods_category_fail_tips'));
}
if(Db::name('GoodsPhoto')->where(['goods_id'=>$goods_ids])->delete() === false)
{
throw new \Exception(MyLang('common_service.goods.delete_goods_photo_fail_tips'));
}
if(Db::name('GoodsContentApp')->where(['goods_id'=>$goods_ids])->delete() === false)
{
throw new \Exception(MyLang('common_service.goods.delete_app_content_fail_tips'));
}
if(Db::name('GoodsParams')->where(['goods_id'=>$goods_ids])->delete() === false)
{
throw new \Exception(MyLang('common_service.goods.delete_params_fail_tips'));
}
if(Db::name('WarehouseGoods')->where(['goods_id'=>$goods_ids])->delete() === false)
{
throw new \Exception(MyLang('common_service.goods.delete_warehouse_goods_fail_tips'));
}
if(Db::name('WarehouseGoodsSpec')->where(['goods_id'=>$goods_ids])->delete() === false)
{
throw new \Exception(MyLang('common_service.goods.delete_warehouse_goods_spec_fail_tips'));
}
if($is_del_images && !empty($del_attachment_data))
{
AttachmentService::AttachmentUrlDelete($del_attachment_data);
}
}
* 商品状态更新
* @author Devil
* @blog http://gong.gg/
* @version 0.0.1
* @datetime 2016-12-06T21:31:53+0800
* @param [array] $params [输入参数]
*/
public static function GoodsStatusUpdate($params = [])
{
$p = [
[
'checked_type' => 'empty',
'key_name' => 'id',
'error_msg' => MyLang('data_id_error_tips'),
],
[
'checked_type' => 'empty',
'key_name' => 'field',
'error_msg' => MyLang('operate_field_error_tips'),
],
[
'checked_type' => 'in',
'key_name' => 'state',
'checked_data' => [0,1],
'error_msg' => MyLang('form_status_range_message'),
],
];
$ret = ParamsChecked($params, $p);
if($ret !== true)
{
return DataReturn($ret, -1);
}
Db::startTrans();
try {
$goods_id = intval($params['id']);
$field = $params['field'];
$status = intval($params['state']);
if(!Db::name('Goods')->where(['id'=>$goods_id])->update([$field=>$status, 'upd_time'=>time()]))
{
throw new \Exception(MyLang('operate_fail'));
}
$hook_name = 'plugins_service_goods_field_status_update';
MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'params' => $params,
'goods_id' => $goods_id,
'field' => $field,
'status' => $status,
]);
Db::commit();
return DataReturn(MyLang('operate_success'), 0);
} catch(\Exception $e) {
Db::rollback();
return DataReturn($e->getMessage(), -1);
}
}
* 获取商品编辑规格
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-12-14
* @desc description
* @param [int] $goods_id [商品id]
*/
public static function GoodsEditSpecifications($goods_id)
{
$where = ['goods_id'=>$goods_id];
$type = Db::name('GoodsSpecType')->where($where)->order('id asc')->field('id,name,value')->select()->toArray();
$value = [];
if(!empty($type))
{
foreach($type as &$temp_type)
{
$temp_type_value = json_decode($temp_type['value'], true);
foreach($temp_type_value as &$vs)
{
$vs['images'] = ResourcesService::AttachmentPathViewHandle($vs['images']);
}
$temp_type['value'] = $temp_type_value;
}
$temp_value = Db::name('GoodsSpecValue')->where($where)->field('goods_spec_base_id,value')->order('id asc')->select()->toArray();
if(!empty($temp_value))
{
foreach($temp_value as $value_v)
{
$key = '';
foreach($type as $type_v)
{
foreach($type_v['value'] as $type_vs)
{
if(trim($type_vs['name']) == trim($value_v['value']))
{
$key = $type_v['id'];
break;
}
}
}
if(!empty($key))
{
$value[$value_v['goods_spec_base_id']][] = [
'data_type' => 'spec',
'data' => [
'key' => $key,
'value' => trim($value_v['value']),
],
];
}
}
}
if(!empty($value))
{
foreach($value as $k=>&$v)
{
$base = Db::name('GoodsSpecBase')->find($k);
$base['weight'] = PriceBeautify($base['weight']);
$base['volume'] = PriceBeautify($base['volume']);
$v[] = [
'data_type' => 'base',
'data' => $base,
];
}
}
} else {
$base = Db::name('GoodsSpecBase')->where($where)->find();
if(!empty($base))
{
$base['weight'] = PriceBeautify($base['weight']);
$base['volume'] = PriceBeautify($base['volume']);
$value[] = [
[
'data_type' => 'base',
'data' => $base,
]
];
}
}
return [
'type' => $type,
'value' => array_values($value),
];
}
* 获取商品编辑参数
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-08-31
* @desc description
* @param [int] $goods_id [商品id]
* @param [array] $data [指定参数数据]
*/
public static function GoodsEditParameters($goods_id = 0, $data = [])
{
$data = empty($data) ? Db::name('GoodsParams')->where(['goods_id'=>$goods_id])->order('id asc')->select()->toArray() : $data;
if(!empty($data))
{
foreach($data as &$v)
{
$v['key'] = (isset($v['scope']) && isset($v['name']) && isset($v['data_type'])) ? md5($v['scope'].$v['name'].$v['data_type']) : '';
if(isset($v['value']) && isset($v['data_type']) && in_array($v['data_type'], [2]))
{
$v['value'] = explode(',', $v['value']);
}
}
$data = array_column($data, null, 'key');
}
return $data;
}
* 商品规格信息
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-12-14
* @desc description
* @param [array] $params [输入参数]
*/
public static function GoodsSpecDetail($params = [])
{
$p = [
[
'checked_type' => 'empty',
'key_name' => 'id',
'error_msg' => MyLang('goods_id_error_tips'),
],
[
'checked_type' => 'empty',
'key_name' => 'spec',
'is_checked' => 1,
'error_msg' => MyLang('common_service.goods.base_spec_not_choice_tips'),
],
];
$ret = ParamsChecked($params, $p);
if($ret !== true)
{
return DataReturn($ret, -1);
}
$goods_id = intval($params['id']);
$where = [
'goods_id' => $goods_id,
];
$spec = [];
if(!empty($params['spec']))
{
if(!is_array($params['spec']))
{
$params['spec'] = json_decode(htmlspecialchars_decode($params['spec']), true);
}
$spec = array_column($params['spec'], 'value');
}
static $goods_service_goods_spec_base_static_data = [];
$key = $goods_id.(empty($spec) ? '' : md5(json_encode($spec, JSON_UNESCAPED_UNICODE)));
if(array_key_exists($key, $goods_service_goods_spec_base_static_data))
{
$base = Db::name('GoodsSpecBase')->find($goods_service_goods_spec_base_static_data[$key]);
} else {
$info = Db::name('Goods')->where(['id'=>$goods_id])->field('id,title,is_exist_many_spec')->find();
if(empty($info))
{
return DataReturn('【'.$goods_id.'】'.MyLang('no_goods'), -1);
}
$base = [];
if(empty($spec))
{
if($info['is_exist_many_spec'] == 1)
{
return DataReturn('【'.$info['title'].'】'.MyLang('common_service.goods.base_spec_not_choice_tips'), -1);
}
$base = Db::name('GoodsSpecBase')->where($where)->find();
} else {
if($info['is_exist_many_spec'] == 0)
{
return DataReturn('【'.$info['title'].'】'.MyLang('common_service.goods.base_spec_empty_tips'), -1);
}
$where['value'] = $spec;
$ids = Db::name('GoodsSpecValue')->where($where)->column('goods_spec_base_id');
if(!empty($ids))
{
$temp_data = Db::name('GoodsSpecValue')->where(['goods_spec_base_id'=>$ids])->field('goods_spec_base_id,value')->order('id asc')->select()->toArray();
if(!empty($temp_data))
{
$data = [];
foreach($temp_data as $v)
{
$data[$v['goods_spec_base_id']][] = $v;
}
$base_id = 0;
$spec_str = implode('', array_column($params['spec'], 'value'));
foreach($data as $value_v)
{
$temp_str = implode('', array_column($value_v, 'value'));
if($temp_str == $spec_str)
{
$base_id = $value_v[0]['goods_spec_base_id'];
break;
}
}
if(!empty($base_id))
{
$base = Db::name('GoodsSpecBase')->find($base_id);
}
}
}
}
if(!empty($base))
{
$goods_service_goods_spec_base_static_data[$key] = $base['id'];
}
}
if(!empty($base))
{
$base['weight'] = PriceBeautify($base['weight']);
$data = [
'spec_base' => $base,
'extends_element' => [],
];
$hook_name = 'plugins_service_goods_spec_base';
$ret = EventReturnHandle(MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'params' => $params,
'spec' => $spec,
'data' => &$data,
'goods_id' => $goods_id
]));
if(isset($ret['code']) && $ret['code'] != 0)
{
return $ret;
}
return DataReturn(MyLang('operate_success'), 0, $data);
}
return DataReturn(MyLang('common_service.goods.base_spec_empty_tips'), -100);
}
* 商品规格类型
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-12-14
* @desc description
* @param [array] $params [输入参数]
*/
public static function GoodsSpecType($params = [])
{
$p = [
[
'checked_type' => 'empty',
'key_name' => 'id',
'error_msg' => MyLang('goods_id_error_tips'),
],
[
'checked_type' => 'empty',
'key_name' => 'spec',
'error_msg' => MyLang('common_service.goods.base_spec_not_choice_tips'),
],
];
$ret = ParamsChecked($params, $p);
if($ret !== true)
{
return DataReturn($ret, -1);
}
$goods_id = intval($params['id']);
$where = [
'goods_id' => intval($params['id']),
];
if(!is_array($params['spec']))
{
$params['spec'] = json_decode(htmlspecialchars_decode($params['spec']), true);
}
$where['value'] = array_column($params['spec'], 'value');
$ids = Db::name('GoodsSpecValue')->where($where)->column('goods_spec_base_id');
if(!empty($ids))
{
$temp_data = Db::name('GoodsSpecValue')->where(['goods_spec_base_id'=>$ids])->field('goods_spec_base_id,value')->order('id asc')->select()->toArray();
if(!empty($temp_data))
{
$group = [];
foreach($temp_data as $v)
{
$group[$v['goods_spec_base_id']][] = $v;
}
$index = count($params['spec'])-1;
$spec_str = implode('', array_column($params['spec'], 'value'));
$spec_type = [];
foreach($group as $v)
{
$temp_str = implode('', array_column($v, 'value'));
if(isset($v[$index+1]) && stripos($temp_str, $spec_str) !== false)
{
$inventory = Db::name('GoodsSpecBase')->where(['id'=>$v[$index+1]['goods_spec_base_id']])->value('inventory');
if($inventory > 0)
{
$spec_type[$v[$index+1]['value']] = $v[$index+1]['value'];
}
}
}
$data = [
'spec_type' => array_values($spec_type),
'extends_element' => [],
];
$hook_name = 'plugins_service_goods_spec_type';
$ret = EventReturnHandle(MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'params' => $params,
'data' => &$data,
'goods_id' => $goods_id
]));
if(isset($ret['code']) && $ret['code'] != 0)
{
return $ret;
}
return DataReturn(MyLang('operate_success'), 0, $data);
}
}
return DataReturn(MyLang('common_service.goods.base_spec_type_empty_tips'), -100);
}
* 商品购买数量获取商品信息
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2021-10-05
* @desc description
* @param [array] $params [输入参数]
*/
public static function GoodsStock($params = [])
{
if(!empty($params['goods_data']))
{
if(!is_array($params['goods_data']))
{
$params['goods_data'] = json_decode(htmlspecialchars_decode($params['goods_data']), true);
}
if(empty($params['goods_data']))
{
return DataReturn(MyLang('params_error_tips'), -1);
}
$result = [];
foreach($params['goods_data'] as $v)
{
$p = [
[
'checked_type' => 'empty',
'key_name' => 'id',
'error_msg' => MyLang('goods_id_error_tips'),
],
[
'checked_type' => 'isset',
'key_name' => 'stock',
'error_msg' => MyLang('common_service.goods.base_buy_stock_error_tips'),
],
];
$ret = ParamsChecked($v, $p);
if($ret !== true)
{
return DataReturn($ret, -1);
}
$result[] = self::GoodsSpecDetail($v);
}
return DataReturn(MyLang('operate_success'), 0, $result);
} else {
$p = [
[
'checked_type' => 'empty',
'key_name' => 'id',
'error_msg' => MyLang('goods_id_error_tips'),
],
[
'checked_type' => 'isset',
'key_name' => 'stock',
'error_msg' => MyLang('common_service.goods.base_buy_stock_error_tips'),
],
];
$ret = ParamsChecked($params, $p);
if($ret !== true)
{
return DataReturn($ret, -1);
}
return self::GoodsSpecDetail($params);
}
}
* 商品规格扩展数据
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @datetime 2019-07-21T16:08:34+0800
* @param [array] $params [输入参数]
*/
public static function GoodsSpecificationsExtends($params = [])
{
$data = [];
$hook_name = 'plugins_service_goods_spec_extends_handle';
MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'params' => $params,
'data' => &$data,
]);
return DataReturn(MyLang('get_success'), 0, $data);
}
* 商品类型校验
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-07-03
* @desc description
* @param [int] $goods_id [商品 id]
* @param [int] $site_type [商品类型]
*/
public static function IsGoodsSiteTypeConsistent($goods_id, $site_type = null)
{
if($site_type === null)
{
$site_type = Db::name('Goods')->where(['id'=>$goods_id])->value('site_type');
}
if($site_type == 4)
{
return DataReturn(MyLang('goods_only_show_title'), -1, $site_type);
}
if(IsGoodsSiteTypeConsistent($site_type) == 1)
{
return DataReturn('success', 0, $site_type);
}
$site_type_arr = MyConst('common_site_type_list');
$msg = array_key_exists($site_type, $site_type_arr) ? MyLang('only_title').$site_type_arr[$site_type]['name'] : MyLang('goods_only_buy_title');
return DataReturn($msg, -1, $site_type);
}
* 商品销售默认类型
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-07-03
* @desc description
* @param [int] $goods_id [商品 id]
* @param [int] $site_type [商品类型]
*/
public static function GoodsSalesModelType($goods_id, $site_type = null)
{
if($site_type === null)
{
$site_type = Db::name('Goods')->where(['id'=>$goods_id])->value('site_type');
}
return DataReturn('success', 0, GoodsSalesModelType($site_type));
}
* 商品底部左侧小导航
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2021-02-19
* @desc description
* @param [array] $goods [商品信息]
*/
public static function GoodsBuyLeftNavList($goods)
{
$user_is_favor = isset($goods['user_is_favor']) && $goods['user_is_favor'] == 1;
$data = [
[
'name' => MyLang('home_title'),
'icon' => (APPLICATION == 'web') ? 'iconfont icon-index' : StaticAttachmentUrl('home-icon.png'),
'type' => 'home',
'url' => SystemService::DomainUrl(),
'active' => 0,
'class' => '',
'document' => '',
],
[
'name' => $user_is_favor ? MyLang('already_favor_title') : MyLang('favor_title'),
'icon' => (APPLICATION == 'web') ? ('iconfont '.($user_is_favor ? 'icon-heart' : 'icon-heart-o')) : StaticAttachmentUrl('favor'.($user_is_favor ? '-active' : '').'-icon.png'),
'type' => 'favor',
'active' => $user_is_favor ? 1 : 0,
'class' => '',
'document' => '',
]
];
if(APPLICATION == 'app' && MyC('common_app_is_online_service') == 1)
{
$custom = MyC('common_app_customer_service_custom', []);
if(empty($custom) || empty($custom[APPLICATION_CLIENT_TYPE]))
{
$status = in_array(APPLICATION_CLIENT_TYPE, ['h5', 'ios', 'android']);
if($status)
{
$tel = MyC('common_app_customer_service_tel');
$status = !empty($tel);
} else {
$status = true;
}
} else {
$status = true;
}
if($status)
{
$data[] = [
'name' => MyLang('chat_title'),
'icon' => StaticAttachmentUrl('chat-icon.png'),
'type' => 'chat',
];
}
}
$hook_name = 'plugins_service_goods_buy_left_nav_handle';
MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'goods' => $goods,
'data' => &$data,
]);
return $data;
}
* 商品购买按钮列表
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2021-02-19
* @desc description
* @param [array] $goods [商品信息]
*/
public static function GoodsBuyButtonList($goods)
{
$error = '';
if(isset($goods['is_shelves']) && $goods['is_shelves'] != 1)
{
$error = MyLang('goods_already_shelves_title');
}
$data = [];
if(empty($error))
{
if(isset($goods['id']) && isset($goods['site_type']))
{
$model_type = self::GoodsSalesModelType($goods['id'], $goods['site_type']);
if($model_type['data'] == 4)
{
$name = MyC('common_is_exhibition_mode_btn_text');
$data[] = [
'color' => 'main',
'type' => 'show',
'name' => empty($name) ? MyLang('goods_show_title') : $name,
'value' => MyC('common_customer_store_chat_tel'),
'icon' => 'am-icon-phone',
];
$error = MyLang('goods_only_show_title');
} else {
if(isset($goods['inventory']) && $goods['inventory'] <= 0)
{
$error = MyLang('goods_no_inventory_title');
}
if(empty($error))
{
$class_name = (APPLICATION == 'web') ? 'buy-event login-event' : '';
$name = (MyC('common_order_is_booking', 0, true) == 1) ? MyLang('goods_booking_title') : MyLang('goods_buy_title');
$buy = [
'color' => 'main',
'type' => 'buy',
'title' => $name,
'name' => $name,
'class' => $class_name,
'icon' => '',
];
$cart = [];
$ret = self::IsGoodsSiteTypeConsistent($goods['id'], $goods['site_type']);
if($ret['code'] == 0)
{
$name = MyLang('goods_cart_title');
$cart = [
'color' => 'second',
'type' => 'cart',
'title' => $name,
'name' => $name,
'class' => $class_name,
'icon' => 'am-icon-opencart',
];
} else {
$error = $ret['msg'];
}
$close_buy_button = MyC('common_goods_close_buy_button');
if(!empty($close_buy_button) && is_array($close_buy_button))
{
if(in_array('cart', $close_buy_button))
{
$cart = [];
}
if(in_array('buy', $close_buy_button))
{
$buy = [];
}
}
if(!empty($buy))
{
$data[] = $buy;
}
if(!empty($cart))
{
$data[] = $cart;
}
if(APPLICATION == 'app')
{
$data = array_reverse($data);
}
}
}
}
}
$hook_name = 'plugins_service_goods_buy_nav_button_handle';
MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'goods' => $goods,
'data' => &$data,
'error' => &$error,
]);
if(empty($data) && empty($error))
{
$error = MyLang('goods_stop_sale_title');
}
$count = 0;
$types = [];
if(!empty($data) && is_array($data))
{
$count = count($data);
$types = array_column($data, 'type');
}
return [
'data' => $data,
'count' => $count,
'error' => $error,
'is_buy' => in_array('buy', $types) ? 1 : 0,
'is_cart' => in_array('cart', $types) ? 1 : 0,
'is_show' => in_array('show', $types) ? 1 : 0,
];
}
* 商品购买指向链接数据
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2026-03-09
* @desc description
* @param [array] $goods [商品信息]
*/
public static function GoodsBuyToLinkData($goods)
{
$data = [
'buy' => MyUrl('index/buy/index'),
'cart' => MyUrl('index/cart/save'),
];
$hook_name = 'plugins_service_goods_buy_to_link_data';
MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'goods' => $goods,
'data' => &$data,
]);
return $data;
}
* 商品详情中间tabs导航列表
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2021-02-19
* @desc description
* @param [array] $goods [商品信息]
*/
public static function GoodsDetailMiddleTabsNavList($goods)
{
$key = SystemService::CacheKey('shopxo.cache_goods_detail_middle_tabs_key').APPLICATION;
$data = MyCache($key);
if($data === null || MyEnv('app_debug') || MyC('common_data_is_use_cache') != 1)
{
$is_comments = MyC('common_is_goods_detail_show_comments', 1);
if(APPLICATION == 'app')
{
$data = [
[
'type' => 'main',
'name' => MyLang('goods_main_title'),
'ent' => '.page',
],
];
if($is_comments == 1)
{
$data[] = [
'type' => 'comments',
'name' => MyLang('comment_title'),
'ent' => '.goods-comment',
];
}
$data[] = [
'type' => 'detail',
'name' => MyLang('detail_title'),
'ent' => '.goods-detail',
];
} else {
$comments_count = isset($goods['comments_count']) ? $goods['comments_count'] : GoodsCommentsService::GoodsCommentsTotal(['goods_id'=>$goods['id'], 'is_show'=>1]);
$data = [
[
'type' => 'detail',
'name' => MyLang('detail_title'),
'active' => 1,
],
];
if($is_comments == 1)
{
$data[] = [
'type' => 'comments',
'name' => MyLang('comment_title').'('.$comments_count.')',
];
}
if(MyC('common_is_goods_detail_show_guess_you_like', 0) == 1)
{
$data[] = [
'type' => 'guess_you_like',
'name' => MyLang('goods_guess_you_like_title'),
];
}
}
$hook_name = 'plugins_service_goods_detail_middle_tabs_nav_handle';
MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'goods' => $goods,
'data' => &$data,
]);
$data = [
'nav' => $data,
'type' => array_column($data, 'type'),
];
MyCache($key, $data, 180);
}
return $data;
}
* 商品二维码生成
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2024-09-05
* @desc description
* @param [array] $goods [商品数据]
* @param [array] $user [用户数据]
*/
public static function GoodsQrcode($goods = [], $user = [])
{
if(empty($goods))
{
return DataReturn(MyLang('no_data'), -1);
}
$url_params = ['id'=>$goods['id']];
if(!empty($user))
{
$url_params['referrer'] = $user['id'];
}
$web_url = MyUrl('index/goods/index', $url_params);
$h5_url = MyC('common_app_h5_url');
$qrcode = [];
$platform = MyConst('common_platform_type');
if(!empty($platform) && is_array($platform))
{
$time_dir = date('Y/m/d', is_numeric($goods['add_time']) ? $goods['add_time'] : strtotime($goods['add_time'])).(empty($user) ? '' : '/'.$user['id']);
$filename = $goods['id'].'.png';
$page = 'pages/goods-detail/goods-detail';
$query = 'id='.$goods['id'];
if(!empty($user))
{
$query .= '&referrer='.$user['id'];
}
if(!empty($h5_url))
{
$h5_url .= $page.'?'.$query;
}
foreach($platform as $v)
{
$path = 'download'.DS.'goods_qrcode'.DS.APPLICATION_CLIENT_TYPE.DS.$v['value'].DS.$time_dir.DS;
$dir_params = [
'path' => DS.$path,
'filename' => $filename,
'dir' => ROOT.'public'.DS.$path.$filename,
];
$status = false;
if(!file_exists($dir_params['dir']))
{
switch($v['value'])
{
case 'pc' :
$ret = (new \base\Qrcode())->Create(array_merge($dir_params, ['content'=>$web_url]));
if($ret['code'] == 0)
{
$status = true;
}
break;
case 'h5' :
if(!empty($h5_url))
{
$ret = (new \base\Qrcode())->Create(array_merge($dir_params, ['content'=>$h5_url]));
if($ret['code'] == 0)
{
$status = true;
}
}
break;
case 'weixin' :
$appid = AppMiniUserService::AppMiniConfig('common_app_mini_weixin_appid');
$appsecret = AppMiniUserService::AppMiniConfig('common_app_mini_weixin_appsecret');
if(!empty($appid) && !empty($appsecret))
{
$request_params = [
'page' => $page,
'scene' => $query,
'width' => 300,
];
$ret = (new \base\Wechat($appid, $appsecret))->MiniQrCodeCreate($request_params);
if($ret['code'] == 0)
{
if(\base\FileUtil::CreateDir(ROOT.'public'.DS.$path))
{
if(@file_put_contents($dir_params['dir'], $ret['data']) !== false)
{
$status = true;
}
}
}
}
break;
case 'alipay' :
$appid = AppMiniUserService::AppMiniConfig('common_app_mini_alipay_appid');
if(!empty($appid))
{
$request_params = [
'appid' => $appid,
'page' => $page,
'scene' => $query,
'width' => 300,
];
$ret = (new \base\Alipay())->MiniQrCodeCreate($request_params);
if($ret['code'] == 0)
{
if(\base\FileUtil::CreateDir(ROOT.'public'.DS.$path))
{
if(@file_put_contents($dir_params['dir'], RequestGet($ret['data'])) !== false)
{
$status = true;
}
}
}
}
break;
case 'toutiao' :
$config = [
'appid' => AppMiniUserService::AppMiniConfig('common_app_mini_toutiao_appid'),
'secret' => AppMiniUserService::AppMiniConfig('common_app_mini_toutiao_appsecret'),
];
if(!empty($config['appid']) && !empty($config['secret']))
{
$request_params = [
'page' => $page,
'scene' => $query,
'width' => 300,
];
$ret = (new \base\Toutiao($config))->MiniQrCodeCreate($request_params);
if($ret['code'] == 0)
{
if(\base\FileUtil::CreateDir(ROOT.'public'.DS.$path))
{
if(@file_put_contents($dir_params['dir'], $ret['data']) !== false)
{
$status = true;
}
}
}
}
break;
case 'baidu' :
$config = [
'appid' => AppMiniUserService::AppMiniConfig('common_app_mini_baidu_appid'),
'key' => AppMiniUserService::AppMiniConfig('common_app_mini_baidu_appkey'),
'secret' => AppMiniUserService::AppMiniConfig('common_app_mini_baidu_appsecret'),
];
if(!empty($config['appid']) && !empty($config['key']) && !empty($config['secret']))
{
$request_params = [
'page' => $page,
'scene' => $query,
'width' => 300,
];
$ret = (new \base\Baidu($config))->MiniQrCodeCreate($request_params);
if($ret['code'] == 0)
{
if(\base\FileUtil::CreateDir(ROOT.'public'.DS.$path))
{
if(@file_put_contents($dir_params['dir'], $ret['data']) !== false)
{
$status = true;
}
}
}
}
break;
case 'kuaishou' :
$appid = AppMiniUserService::AppMiniConfig('common_app_mini_kuaishou_appid');
if(!empty($appid))
{
$url = 'kwai://miniapp?appId='.$appid.'&KSMP_source=011012&KSMP_internal_source=011012&path='.urlencode($page.'?'.$query);
$ret = (new \base\Qrcode())->Create(array_merge($dir_params, ['content'=>$url]));
if($ret['code'] == 0)
{
$status = true;
}
}
break;
}
} else {
$status = true;
}
if($status)
{
if(($v['value'] == 'h5' && !empty($h5_url)) || $v['value'] != 'h5')
{
$qrcode[] = [
'name' => $v['name'],
'type' => $v['value'],
'url' => ($v['value'] == 'h5') ? $h5_url : (($v['value'] == 'pc') ? $web_url : ''),
'qrcode' => ResourcesService::AttachmentPathViewHandle($dir_params['path'].$dir_params['filename']),
];
}
}
}
}
return DataReturn('success', 0, [
'qrcode' => $qrcode,
'h5_url' => $h5_url,
'web_url' => $web_url,
]);
}
* 商品url生成
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2022-02-12
* @desc description
* @param [int] $goods_id [商品id]
*/
public static function GoodsUrlCreate($goods_id)
{
return (APPLICATION_CLIENT_TYPE == 'pc') ? MyUrl('index/goods/index', ['id'=>$goods_id]) : '/pages/goods-detail/goods-detail?id='.$goods_id;
}
* 获取商品列表
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-09-07
* @desc description
* @param [array] $params [输入参数]
*/
public static function GoodsSearchList($params = [])
{
$page = max(1, isset($params['page']) ? intval($params['page']) : 1);
$page_size = empty($params['page_size']) ? 20 : min(intval($params['page_size']), 100);
$page_start = intval(($page-1)*$page_size);
$result = [
'page' => $page,
'page_start' => $page_start,
'page_size' => $page_size,
'page_total' => 0,
'total' => 0,
'data' => [],
];
$where_base = empty($params['where_base']) ? [] : $params['where_base'];
$where_keywords = empty($params['where_keywords']) ? [] : $params['where_keywords'];
$order_by = empty($params['order_by']) ? 'access_count desc, sales_count desc, id desc' : $params['order_by'];
$field = empty($params['field']) ? '*' : $params['field'];
$hook_name = 'plugins_service_goods_search_list_begin';
MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'params' => $params,
'where_base' => &$where_base,
'where_keywords' => &$where_keywords,
'field' => &$field,
'order_by' => &$order_by,
'page' => &$result['page'],
]);
$result['total'] = (int) Db::name('Goods')->where($where_base)->where(function($query) use($where_keywords) {
$query->whereOr($where_keywords);
})->count();
if($result['total'] > 0)
{
$goods = self::GoodsDataHandle(Db::name('Goods')->field($field)->where($where_base)->where(function($query) use($where_keywords) {
$query->whereOr($where_keywords);
})->order($order_by)->limit($result['page_start'], $result['page_size'])->select()->toArray(), $params);
$result['data'] = $goods['data'];
$result['page_total'] = ceil($result['total']/$result['page_size']);
}
return DataReturn(MyLang('handle_success'), 0, $result);
}
* 商品基础模板
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2022-08-26
* @desc description
* @param [array] $params [输入参数]
*/
public static function GoodsBaseTemplate($params = [])
{
$p = [
[
'checked_type' => 'empty',
'key_name' => 'category_ids',
'error_msg' => MyLang('form_goods_category_message'),
],
];
$ret = ParamsChecked($params, $p);
if($ret !== true)
{
return DataReturn($ret, -1);
}
if(!is_array($params['category_ids']))
{
$params['category_ids'] = explode(',', $params['category_ids']);
}
$spec = GoodsSpecService::GoodsCategorySpecTemplateList($params);
$parameter = GoodsParamsService::GoodsCategoryParamsTemplateList($params);
$required_fields = self::GoodsBaseFieldsRequiredConfigData($params['category_ids']);
return DataReturn(MyLang('operate_success'), 0, [
'spec' => $spec['data'],
'params' => $parameter['data'],
'required_fields' => empty($required_fields) ? null : $required_fields,
]);
}
* 商品基础字段必填配置数据
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2025-11-06
* @desc description
* @param [array] $category_ids [商品分类id]
*/
public static function GoodsBaseFieldsRequiredConfigData($category_ids)
{
if(!is_array($category_ids))
{
$category_ids = explode(',', $category_ids);
}
$required_fields = [];
$goods_base_fields_required = MyC('common_goods_base_fields_required_data');
if(!empty($goods_base_fields_required) && is_array($goods_base_fields_required))
{
foreach($goods_base_fields_required as $k=>$v)
{
$ids = GoodsCategoryService::GoodsCategoryItemsIds($v);
$temp = array_diff($ids, $category_ids);
$required_fields[$k] = (count($temp) < count($ids)) ? 1 : 0;
}
}
return $required_fields;
}
* 商品详情页面猜你喜欢的相关商品
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2023-12-29
* @desc description
* @param [int] $goods_id [商品id]
* @param [array] $params [输入参数]
*/
public static function GoodsDetailGuessYouLikeData($goods_id, $params = [])
{
$goods_list = [];
if(!empty($goods_id) && MyC('common_is_goods_detail_show_guess_you_like', 0) == 1)
{
$category_ids = Db::name('GoodsCategoryJoin')->where(['goods_id'=>$goods_id])->column('category_id');
if(!empty($category_ids))
{
$category_ids = GoodsCategoryService::GoodsCategoryParentIds(GoodsCategoryService::GoodsCategoryItemsIds($category_ids));
$data_params = [
'where' => [
['g.is_shelves', '=', 1],
['g.is_delete_time', '=', 0],
['gci.category_id', 'in', $category_ids],
['g.id', 'not in', $goods_id],
],
'order_by' => 'g.sales_count desc',
'n' => 16,
'is_spec' => (!isset($params['is_spec']) || $params['is_spec'] == 1) ? 1 : 0,
'is_cart' => (!isset($params['is_cart']) || $params['is_cart'] == 1) ? 1 : 0,
];
$ret = self::CategoryGoodsList($data_params);
$goods_list = empty($ret['data']) ? [] : $ret['data'];
}
}
return $goods_list;
}
* 商品详情页面看了又看的相关商品
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2023-12-29
* @desc description
* @param [int] $goods_id [商品id]
* @param [array] $params [输入参数]
*/
public static function GoodsDetailSeeingYouData($goods_id, $params = [])
{
$goods_list = [];
if(!empty($goods_id) && MyC('common_is_goods_detail_show_seeing_you', 0) == 1)
{
$data_params = [
'where' => [
['is_shelves', '=', 1],
['is_delete_time', '=', 0],
['id', 'not in', $goods_id],
],
'order_by' => 'access_count desc',
'n' => 10,
'is_spec' => (!isset($params['is_spec']) || $params['is_spec'] == 1) ? 1 : 0,
'is_cart' => (!isset($params['is_cart']) || $params['is_cart'] == 1) ? 1 : 0,
];
$ret = self::GoodsList($data_params);
if(!empty($ret['data']))
{
$goods_list = $ret['data'];
}
}
return $goods_list;
}
* 指定读取商品列表
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-09-29
* @desc description
* @param [array] $params [输入参数]
*/
public static function AppointGoodsList($params = [])
{
$result = [];
if(!empty($params['goods_ids']))
{
if(!is_array($params['goods_ids']))
{
$params['goods_ids'] = explode(',', $params['goods_ids']);
}
$params['where'] = [
['is_delete_time', '=', 0],
['is_shelves', '=', 1],
['id', 'in', array_unique($params['goods_ids'])]
];
$params['is_spec'] = isset($params['is_spec']) ? $params['is_spec'] : 0;
$params['is_cart'] = isset($params['is_cart']) ? $params['is_cart'] : 0;
$params['is_favor'] = isset($params['is_favor']) ? $params['is_favor'] : 0;
$params['m'] = 0;
$params['n'] = 0;
$params['field'] = '*';
$params['is_appoint_goods_list'] = 1;
$ret = self::GoodsList($params);
if(!empty($ret['data']))
{
$temp = array_column($ret['data'], null, 'id');
foreach($params['goods_ids'] as $id)
{
if(!empty($id) && array_key_exists($id, $temp))
{
$result[] = $temp[$id];
}
}
}
}
return $result;
}
* 自动读取商品列表
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-09-29
* @desc description
* @param [array] $params [输入参数]
*/
public static function AutoGoodsList($params = [])
{
$params['where'] = [
['g.is_delete_time', '=', 0],
['g.is_shelves', '=', 1],
];
if(!empty($params['goods_keywords']))
{
$params['where'][] = ['g.title|g.simple_desc', 'like', '%'.$params['goods_keywords'].'%'];
}
if(!empty($params['goods_category_ids']))
{
if(!is_array($params['goods_category_ids']))
{
$params['goods_category_ids'] = explode(',', $params['goods_category_ids']);
}
$params['where'][] = ['gci.category_id', 'in', GoodsCategoryService::GoodsCategoryItemsIds($params['goods_category_ids'], 1)];
}
if(!empty($params['goods_brand_ids']))
{
if(!is_array($params['goods_brand_ids']))
{
$params['goods_brand_ids'] = explode(',', $params['goods_brand_ids']);
}
$params['where'][] = ['g.brand_id', 'in', $params['goods_brand_ids']];
}
$order_by_type_list = MyConst('common_goods_order_by_type_list');
$order_by_rule_list = MyConst('common_data_order_by_rule_list');
$order_by_type = !isset($params['goods_order_by_type']) || !array_key_exists($params['goods_order_by_type'], $order_by_type_list) ? $order_by_type_list[0]['value'] : $order_by_type_list[$params['goods_order_by_type']]['value'];
$order_by_rule = !isset($params['goods_order_by_rule']) || !array_key_exists($params['goods_order_by_rule'], $order_by_rule_list) ? $order_by_rule_list[0]['value'] : $order_by_rule_list[$params['goods_order_by_rule']]['value'];
$params['order_by'] = $order_by_type.' '.$order_by_rule;
$params['m'] = 0;
$params['n'] = empty($params['goods_number']) ? 10 : intval($params['goods_number']);
$params['field'] = 'g.*';
$params['is_spec'] = isset($params['is_spec']) ? $params['is_spec'] : 0;
$params['is_cart'] = isset($params['is_cart']) ? $params['is_cart'] : 0;
$params['is_favor'] = isset($params['is_favor']) ? $params['is_favor'] : 0;
$params['is_auto_goods_list'] = 1;
$ret = self::CategoryGoodsList($params);
return empty($ret['data']) ? [] : $ret['data'];
}
* 商品基础禁止操作数据
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2025-07-02
* @desc description
* @param [int] $goods_id [商品id]
* @param [array] $goods [商品数据]
* @param [array] $params [输入参数]
*/
public static function GoodsBaseForbidOperateData($goods_id = 0, $goods = [], $params = [])
{
$data = [
];
$hook_name = 'plugins_service_goods_base_forbid_operate_data';
MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'goods_id' => $goods_id,
'goods' => $goods,
'params' => $params,
'data' => &$data,
]);
return $data;
}
* 商品参数操作数据
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2025-07-02
* @desc description
* @param [int] $goods_id [商品id]
* @param [array] $goods [商品数据]
* @param [array] $params [输入参数]
*/
public static function GoodsParamsOperateData($goods_id = 0, $goods = [], $params = [])
{
$data = [
'is_created' => 1,
'is_add' => 1,
'is_edit' => 1,
'is_copy' => 1,
'is_remove' => 1,
'msg' => '',
];
$hook_name = 'plugins_service_goods_params_operate_data';
MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'goods_id' => $goods_id,
'goods' => $goods,
'params' => $params,
'data' => &$data,
]);
return $data;
}
* 商品规格操作数据
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2025-07-02
* @desc description
* @param [int] $goods_id [商品id]
* @param [array] $goods [商品数据]
* @param [array] $params [输入参数]
*/
public static function GoodsSpecOperateData($goods_id = 0, $goods = [], $params = [])
{
$data = [
'is_created' => 1,
'is_add' => 1,
'is_edit' => 1,
'is_copy' => 1,
'is_remove' => 1,
'msg' => '',
];
$hook_name = 'plugins_service_goods_spec_operate_data';
MyEventTrigger($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'goods_id' => $goods_id,
'goods' => $goods,
'params' => $params,
'data' => &$data,
]);
return $data;
}
* 商品数据编辑状态
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2025-09-16
* @desc description
* @param [int] $goods_id [商品id]
* @param [int] $data [商品编辑的数据]
*/
public static function GoodsDataEditStatusCheck($goods_id, $data)
{
$result = [
'is_base' => 0,
'is_photo' => 0,
'is_content_app' => 0,
'is_parameter' => 0,
'is_spec' => 0,
];
if(!empty($goods_id))
{
if(empty($data['data']))
{
$data['data'] = [];
}
$goods = Db::name('Goods')->where(['id'=>$goods_id])->find();
$temp_data = [];
foreach($data['data'] as $k=>$v)
{
if(array_key_exists($k, $goods))
{
$temp_data[$k] = $goods[$k];
}
}
$diff1 = array_diff($data['data'], $temp_data);
$diff2 = array_diff($temp_data, $data['data']);
$result['is_base'] = (count($diff1) == 0 && count($diff2) == 0) ? 0 : 1;
$temp_photo = empty($data['photo']) ? [] : $data['photo'];
$photo = Db::name('GoodsPhoto')->where(['goods_id'=>$goods_id])->order('id asc')->column('images');
$diff1 = array_diff($temp_photo, $photo);
$diff2 = array_diff($photo, $temp_photo);
$result['is_photo'] = (count($diff1) == 0 && count($diff2) == 0) ? 0 : 1;
$temp_content_app = empty($data['content_app']) ? [] : array_map(function($item)
{
return implode(';', array_filter($item));
}, array_values($data['content_app']));
$content_app = Db::name('GoodsContentApp')->where(['goods_id'=>$goods_id])->order('sort asc, id asc')->field('images,content as text')->select()->toArray();
if(!empty($content_app))
{
$content_app = array_map(function($item)
{
return implode(';', array_filter($item));
}, array_values($content_app));
}
$diff1 = array_diff($temp_content_app, $content_app);
$diff2 = array_diff($content_app, $temp_content_app);
$result['is_content_app'] = (count($diff1) == 0 && count($diff2) == 0) ? 0 : 1;
$temp_parameter = empty($data['parameter']) ? [] : array_map(function($item)
{
unset($item['md5_key']);
return implode(';', $item);
}, array_values($data['parameter']));
$parameter = Db::name('GoodsParams')->where(['goods_id'=>$goods_id])->order('id asc')->field('scope,data_type,name,value')->select()->toArray();
if(!empty($parameter))
{
$parameter = array_map(function($item)
{
return implode(';', $item);
}, array_values($parameter));
}
$diff1 = array_diff($temp_parameter, $parameter);
$diff2 = array_diff($parameter, $temp_parameter);
$result['is_parameter'] = (count($diff1) == 0 && count($diff2) == 0) ? 0 : 1;
$temp_spec_title = [];
if(!empty($data['spec']['title']))
{
foreach($data['spec']['title'] as $k=>$v)
{
$spec = [];
foreach($v['value'] as $vs)
{
$spec[] = [
'name' => $vs,
'images' => isset($data['spec']['images'][$vs]) ? ResourcesService::AttachmentPathHandle($data['spec']['images'][$vs]) : '',
];
}
$v['value'] = json_encode($spec, JSON_UNESCAPED_UNICODE);
$temp_spec_title[] = $v;
}
if(!empty($temp_spec_title))
{
$temp_spec_title = array_map(function($item)
{
return implode(';', $item);
}, $temp_spec_title);
}
}
$spec_title = Db::name('GoodsSpecType')->where(['goods_id'=>$goods_id])->order('id asc')->field('name,value')->select()->toArray();
if(!empty($spec_title))
{
$spec_title = array_map(function($item)
{
return implode(';', $item);
}, $spec_title);
}
$diff1 = array_diff($temp_spec_title, $spec_title);
$diff2 = array_diff($spec_title, $temp_spec_title);
$is_spec_title = (count($diff1) == 0 && count($diff2) == 0) ? 0 : 1;
$temp_spec_value = [];
$temp_spec_base = [];
if(!empty($data['spec']) && !empty($data['spec']['data']))
{
$spec_field_defult_value = ['price'=>'0.00', 'original_price'=>'0.00', 'weight'=>'0.00', 'volume'=>'0.00', 'buy_min_number'=>0, 'buy_max_number'=>0];
$count = count($data['spec']['data'][0]);
$temp_key = self::GoodsSpecBaseFields();
$key_count = count($temp_key);
if($count == $key_count)
{
$temp_spec_base_item = [];
for($i=0; $i<$count; $i++)
{
if(in_array($temp_key[$i], ['price', 'original_price', 'weight', 'volume']))
{
$temp_spec_base_item[$temp_key[$i]] = PriceNumberFormat($data['spec']['data'][0][$i]);
} else if(in_array($temp_key[$i], ['buy_min_number', 'buy_max_number']))
{
$temp_spec_base_item[$temp_key[$i]] = intval($data['spec']['data'][0][$i]);
} else {
$temp_spec_base_item[$temp_key[$i]] = $data['spec']['data'][0][$i];
}
}
$temp_spec_base[] = $temp_spec_base_item;
} else {
$base_start = $count-$key_count;
foreach($data['spec']['data'] as $v)
{
$temp_spec_base_item = [];
for($i=0; $i<$count; $i++)
{
if($i < $base_start)
{
$temp_spec_value[] = $v[$i];
} else {
if(in_array($temp_key[$i-$base_start], ['price', 'original_price', 'weight', 'volume']))
{
$temp_spec_base_item[$temp_key[$i-$base_start]] = PriceNumberFormat($v[$i]);
} else if(in_array($temp_key[$i-$base_start], ['buy_min_number', 'buy_max_number']))
{
$temp_spec_base_item[$temp_key[$i-$base_start]] = intval($v[$i]);
} else {
$temp_spec_base_item[$temp_key[$i-$base_start]] = $v[$i];
}
}
}
$temp_spec_base[] = $temp_spec_base_item;
}
}
if(!empty($temp_spec_base))
{
$temp_spec_base = array_map(function($item)
{
return implode(';', $item);
}, array_values($temp_spec_base));
}
}
$spec_base = Db::name('GoodsSpecBase')->where(['goods_id'=>$goods_id])->field($temp_key)->order('id asc')->select()->toArray();
if(!empty($spec_base))
{
$spec_base = array_map(function($item)
{
return implode(';', $item);
}, array_values($spec_base));
}
$spec_value = Db::name('GoodsSpecValue')->where(['goods_id'=>$goods_id])->order('id asc')->column('value');
$diff1 = array_diff($temp_spec_base, $spec_base);
$diff2 = array_diff($spec_base, $temp_spec_base);
$is_spec_base = (count($diff1) == 0 && count($diff2) == 0) ? 0 : 1;
$diff1 = array_diff($temp_spec_value, $spec_value);
$diff2 = array_diff($spec_value, $temp_spec_value);
$is_spec_value = (count($diff1) == 0 && count($diff2) == 0) ? 0 : 1;
$result['is_spec'] = ($is_spec_title+$is_spec_base+$is_spec_value > 0) ? 1 : 0;
}
return $result;
}
}
?>