552 lines
21 KiB
PHP
552 lines
21 KiB
PHP
<?php
|
|
declare (strict_types = 1);
|
|
|
|
namespace app\index\controller;
|
|
|
|
use app\index\model\ProductAttrModel;
|
|
use app\index\model\ProductCategoryModel;
|
|
use app\index\model\ProductInquiryModel;
|
|
use app\index\model\ProductModel;
|
|
use app\index\model\ProductParamsModel;
|
|
use app\index\model\ProductPurchaseLinkModel;
|
|
use app\index\model\ProductRelatedModel;
|
|
use app\index\model\ProductSkuAttrModel;
|
|
use app\index\model\ProductSkuModel;
|
|
use app\index\model\SysBannerModel;
|
|
use app\index\model\SysBannerProdCateMappingModel;
|
|
use app\index\validate\ProductInquiryValidate;
|
|
use think\facade\View;
|
|
use think\helper\Arr;
|
|
|
|
/**
|
|
* 产品控制器
|
|
*/
|
|
class Product extends Common
|
|
{
|
|
// 获取分类页的banner图焦点横幅
|
|
private function getCategoryBanner($category_id)
|
|
{
|
|
$focus_image = [];
|
|
// 获取产品分类页焦点横幅
|
|
$banner = SysBannerModel::with(['items' => function($query) use($category_id) {
|
|
$query->withoutField([
|
|
'status',
|
|
'created_at',
|
|
'updated_at',
|
|
'deleted_at'
|
|
])
|
|
->whereExists(function($q) use($category_id) {
|
|
$r = $q->getModel()->getTable();
|
|
$m = new SysBannerProdCateMappingModel;
|
|
$q->model($m)->name($m->getName())
|
|
->where("banner_item_id = $r.id")
|
|
->where('product_category_id' , '=', $category_id);
|
|
})
|
|
->where('status', '=', 1)
|
|
->order(['sort' => 'asc', 'id' => 'desc']);
|
|
}])
|
|
->atPlatform(request()->from)
|
|
->uniqueLabel(['BANNER_6808abd813d78'])
|
|
->language($this->lang_id)
|
|
->enabled(true)
|
|
->select();
|
|
if (!$banner->isEmpty()) {
|
|
$banner_map = [];
|
|
foreach ($banner as $v) {
|
|
$banner_map[$v->unique_label] = $v;
|
|
}
|
|
$focus_image = data_get($banner_map, 'BANNER_6808abd813d78')?->items->toArray();
|
|
}
|
|
return $focus_image;
|
|
}
|
|
// 产品分类 - 查看顶层分类
|
|
public function category()
|
|
{
|
|
// 参数
|
|
$param = request()->param(['id']);
|
|
|
|
// 获取产品分类页焦点横幅
|
|
View::assign('focus_image', $this->getCategoryBanner($param['id']));
|
|
|
|
// 获取分类及产品信息
|
|
$categorys_data = ProductCategoryModel::field(['id', 'pid', 'name', 'path', 'level'])
|
|
->language($this->lang_id)
|
|
->displayed(true)
|
|
->children($param['id'])
|
|
->order(['pid' => 'asc', 'sort' => 'asc', 'id' => 'desc'])
|
|
->select()
|
|
->toArray();
|
|
|
|
$list = [];
|
|
if (!empty($categorys_data)) {
|
|
// 分组分类
|
|
$list = array_filter($categorys_data, fn($it) => $it['level'] == 2);
|
|
foreach ($list as &$it) {
|
|
$it['children'] = array_column(array_filter($categorys_data, fn($v) => in_array($it['id'], explode(',', $v['path']))), 'id');
|
|
}
|
|
unset($it);
|
|
|
|
// 获取分类下的产品信息
|
|
if (!empty($list)) {
|
|
$product_model = new ProductModel;
|
|
$sql = $product_model->field([
|
|
'id',
|
|
'category_id',
|
|
'spu',
|
|
'name',
|
|
'cover_image',
|
|
'is_new',
|
|
'(' . $list[0]['id'] . ')' => 'group_mark'
|
|
])
|
|
->byCategory(data_get($list[0], 'children'))
|
|
->language($this->lang_id)
|
|
->enabled(true)
|
|
->onSale(true)
|
|
->onShelves(true)
|
|
->append(['p' => $list[0]['id']])
|
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
|
->limit(5)
|
|
->buildSql();
|
|
$query = \think\facade\Db::table("($sql) as a");
|
|
foreach ($list as $it) {
|
|
$query = $query->union(function($query) use($product_model, $it) {
|
|
$query->model($product_model)
|
|
->name($product_model->getName())
|
|
->field([
|
|
'id',
|
|
'category_id',
|
|
'spu',
|
|
'name',
|
|
'cover_image',
|
|
'is_new',
|
|
'(' . $it['id'] . ')' => 'group_mark'
|
|
])
|
|
->byCategory($it['children'])
|
|
->language($this->lang_id)
|
|
->enabled(true)
|
|
->onSale(true)
|
|
->onShelves(true)
|
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
|
->limit(5);
|
|
});
|
|
}
|
|
$pros = $query->select();
|
|
if (!empty($pros)) {
|
|
$pros_map = [];
|
|
foreach ($pros as $pro) {
|
|
$pros_map[$pro['group_mark']][] = $pro;
|
|
}
|
|
foreach ($list as $k => &$it) {
|
|
unset($it['children']);
|
|
if (!isset($pros_map[$it['id']])) {
|
|
unset($list[$k]);
|
|
continue;
|
|
}
|
|
$it['products'] = $pros_map[$it['id']];
|
|
}
|
|
unset($it);
|
|
}
|
|
}
|
|
}
|
|
View::assign('list', $list);
|
|
|
|
return View::fetch('category');
|
|
}
|
|
// 产品分类 - 查看子类
|
|
public function subcategory()
|
|
{
|
|
// 参数
|
|
$param = request()->param(['id']);
|
|
|
|
// 获取产品分类页焦点横幅
|
|
View::assign('focus_image', $this->getCategoryBanner($param['id']));
|
|
|
|
// 获取分类及产品信息
|
|
$categorys_data = ProductCategoryModel::field(['id', 'name', 'level'])
|
|
->language($this->lang_id)
|
|
->displayed(true)
|
|
->child($param['id'], true)
|
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
|
->select();
|
|
|
|
if (!$categorys_data->isEmpty()) {
|
|
if ($categorys_data->count() > 1) {
|
|
// 当分类数不只一个时,当前分类下有子分类,移除当前分类,只输出子分类
|
|
$categorys_data = $categorys_data->filter(function($item) use($param) {
|
|
return $item->id != $param['id'];
|
|
});
|
|
}
|
|
$categorys_data = $categorys_data->toArray();
|
|
|
|
$products = ProductModel::field([
|
|
'id',
|
|
'category_id',
|
|
'spu',
|
|
'name',
|
|
'short_name',
|
|
'cover_image',
|
|
'desc'
|
|
])
|
|
->byCategory(array_column($categorys_data, 'id'))
|
|
->language($this->lang_id)
|
|
->enabled(true)
|
|
->onSale(true)
|
|
->onShelves(true)
|
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
|
->select();
|
|
if (!$products->isEmpty()) {
|
|
// 获取sku信息
|
|
$skus_map = [];
|
|
$color_map = [];
|
|
$skus = ProductSkuModel::withoutField(['sort', 'created_at', 'updated_at'])
|
|
->byProductId(Arr::pluck($products, 'id'))
|
|
->order(['sort' => 'asc', 'id' => 'asc'])
|
|
->select();
|
|
if (!$skus->isEmpty()) {
|
|
// 获取产品sku属性信息
|
|
$sku_attrs_map = [];
|
|
$sku_attrs = ProductSkuAttrModel::bySkuId(array_unique(Arr::pluck($skus, 'id')))->select()->toArray();
|
|
if (!empty($sku_attrs)) {
|
|
// 获取属性名称
|
|
$attrs = ProductAttrModel::bypks(array_unique(Arr::pluck($sku_attrs, 'attr_id')))->column(['attr_name'], 'id');
|
|
// 获取属性名称
|
|
foreach ($sku_attrs as $v) {
|
|
$sku_attrs_map[$v['sku_id']][] = [
|
|
'sku_id' => $v['sku_id'],
|
|
'attr_id' => $v['attr_id'],
|
|
'attr_name' => $attrs[$v['attr_id']]?? '',
|
|
'attr_value' => $v['attr_value']
|
|
];
|
|
}
|
|
}
|
|
// sku匹配属性
|
|
foreach ($skus as $v) {
|
|
// 找到相应产品的sku图片信息
|
|
$skus_map[$v['product_id']][] = [
|
|
'id' => $v['id'],
|
|
'sku' => $v['sku'],
|
|
'main_image' => $v['main_image'],
|
|
];
|
|
// 找到相应产品的sku产色属性信息
|
|
$attr = $sku_attrs_map[$v['id']]?? [];
|
|
if (!empty($attr)) {
|
|
foreach ($attr as $at) {
|
|
if (in_array($at['attr_name'], ['颜色', 'Color'])) {
|
|
$color_map[$v['product_id']][] = $at;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 按分类分组产品
|
|
$products_map = [];
|
|
foreach ($products as $v) {
|
|
$products_map[$v['category_id']][] = [
|
|
'id' => $v['id'],
|
|
'spu' => $v['spu'],
|
|
'name' => $v['name'],
|
|
'short_name' => $v['short_name'],
|
|
'cover_image' => $v['cover_image'],
|
|
'desc' => $v['desc'],
|
|
'sku' => $skus_map[$v['id']]?? [],
|
|
'colors' => $color_map[$v['id']]?? []
|
|
];
|
|
}
|
|
foreach ($categorys_data as $k => $v) {
|
|
if (!isset($products_map[$v['id']])) {
|
|
unset($categorys_data[$k]);
|
|
continue;
|
|
}
|
|
$categorys_data[$k]['products'] = $products_map[$v['id']];
|
|
}
|
|
}
|
|
}
|
|
View::assign('categorys_data', $categorys_data);
|
|
|
|
return View::fetch('subcategory');
|
|
}
|
|
|
|
/**
|
|
* 产品搜索
|
|
*/
|
|
public function search()
|
|
{
|
|
$param = request()->param([
|
|
'keywords',
|
|
'page/d' => 1,
|
|
'size/d' => 10
|
|
]);
|
|
$keywords = $param['keywords'] ?? '';
|
|
|
|
// 关键词搜索
|
|
$products = ProductModel::field([
|
|
'id',
|
|
'name',
|
|
'short_name',
|
|
'cover_image',
|
|
'spu'
|
|
])
|
|
->where(fn ($query) => $query->withSearch(['keywords'], ['keywords' => $keywords]))
|
|
->language($this->lang_id)
|
|
->enabled(true)
|
|
->onSale(true)
|
|
->onShelves(true)
|
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
|
->paginate([
|
|
'list_rows' => $param['size'],
|
|
'page' => $param['page'],
|
|
'query' => request()->param()
|
|
])
|
|
->each(function ($item) use($keywords) {
|
|
$item['spu'] = highlight_keywords($item['spu'], $keywords, ['redpoint']);
|
|
$item['name'] = highlight_keywords($item['name'], $keywords, ['redpoint']);
|
|
$item['short_name'] = highlight_keywords($item['short_name'], $keywords, ['redpoint']);
|
|
return $item;
|
|
});
|
|
View::assign('products', $products);
|
|
View::assign('page', $products->render());
|
|
|
|
return View::fetch('search');
|
|
}
|
|
|
|
/**
|
|
* 产品详情页
|
|
*/
|
|
public function detail()
|
|
{
|
|
$param = request()->param(['id']);
|
|
|
|
// 获取产品信息
|
|
$product = ProductModel::withoutField([
|
|
'language_id',
|
|
'status',
|
|
'created_at',
|
|
'updated_at',
|
|
'deleted_at'
|
|
])
|
|
->bypk($param['id'])
|
|
->find();
|
|
View::assign('product', $product);
|
|
|
|
$product_categorys = [];
|
|
$product_params = [];
|
|
$product_skus = [];
|
|
$product_sku_attrs = [];
|
|
$product_purchase_links = [];
|
|
$product_related = [];
|
|
if (!empty($product)) {
|
|
// 获取产品分类信息
|
|
$product_categorys = ProductCategoryModel::field(['id', 'pid', 'name'])
|
|
->bypk($product['category_id'])
|
|
->union(function($query) use($product) {
|
|
$query->name('product_category')
|
|
->field(['id', 'pid', 'name'])
|
|
->where('id', 'IN', function($sub_query) use($product) {
|
|
$sub_query->name('product_category')
|
|
->where('id', '=', $product['category_id'])
|
|
->field('path');
|
|
});
|
|
})
|
|
->order(['id' => 'asc'])
|
|
->select()
|
|
->toArray();
|
|
|
|
// 获取产品参数信息
|
|
$product_params = ProductParamsModel::field(['id', 'name', 'value'])
|
|
->byProductId($product['id'])
|
|
->order(['id' => 'asc'])
|
|
->select()
|
|
->toArray();
|
|
|
|
// 获取产品sku信息
|
|
$skus = ProductSkuModel::withoutField(['created_at', 'updated_at'])
|
|
->byProductId($product['id'])
|
|
->order(['sort' => 'asc', 'id' => 'asc'])
|
|
->select();
|
|
if (!empty($skus)) {
|
|
$product_skus = $skus->toArray();
|
|
|
|
// 获取产品sku属性信息
|
|
$sku_attrs = ProductSkuAttrModel::bySkuId(array_unique(Arr::pluck($skus, 'id')))->select()->toArray();
|
|
if (!empty($sku_attrs)) {
|
|
// 获取属性名称
|
|
$attrs = ProductAttrModel::bypks(array_unique(Arr::pluck($sku_attrs, 'attr_id')))->column(['attr_name'], 'id');
|
|
foreach ($sku_attrs as $v) {
|
|
if (empty($v['attr_value'])) continue;
|
|
|
|
$v['attr_name'] = $attrs[$v['attr_id']]?? '';
|
|
// 按属性分组
|
|
$product_sku_attrs[$v['attr_id']]['attr_id'] = $v['attr_id'];
|
|
$product_sku_attrs[$v['attr_id']]['attr_name'] = $v['attr_name'];
|
|
$product_sku_attrs[$v['attr_id']]['attr_values'][] = [
|
|
'sku_id' => $v['sku_id'],
|
|
'attr_value' => $v['attr_value'],
|
|
];
|
|
}
|
|
$product_sku_attrs = array_values($product_sku_attrs);
|
|
}
|
|
}
|
|
|
|
// 获取产品购买链接信息
|
|
$product_purchase_links = ProductPurchaseLinkModel::with(['platform'])
|
|
->field(['platform_id', 'link'])
|
|
->byProductId($product['id'])
|
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
|
->select()
|
|
->hidden(['platform'])
|
|
->bindAttr('platform', ['platform_name' => 'platform'])
|
|
->toArray();
|
|
|
|
// 获取相关产品信息
|
|
$related = ProductRelatedModel::with(['product' => function($query) {
|
|
$query->field(['id', 'name', 'spu', 'cover_image']);
|
|
}])
|
|
->byProductId($product['id'])
|
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
|
->select();
|
|
if (!$related->isEmpty()) {
|
|
$product_related = Arr::pluck($related, 'product');
|
|
}
|
|
}
|
|
View::assign('product_categorys', $product_categorys); // 产品分类
|
|
View::assign('product_params', $product_params); // 产品参数
|
|
View::assign('product_skus', $product_skus); // 产品sku
|
|
View::assign('product_sku_attrs', $product_sku_attrs); // 产品sku属性
|
|
View::assign('product_purchase_links', $product_purchase_links); // 产品购买链接
|
|
View::assign('product_related', $product_related); // 相关产品
|
|
|
|
// 获取询盘可选国家
|
|
$config = $this->basic_config['optional_country_for_product_inquiry'];
|
|
View::assign('country_list', explode(',', preg_replace('/\r?\n/', ',', $config['value']?? '')));
|
|
|
|
return View::fetch('detail');
|
|
}
|
|
|
|
/**
|
|
* 产品询盘
|
|
*/
|
|
public function inquiry()
|
|
{
|
|
$post = request()->post([
|
|
'first_name',
|
|
'last_name',
|
|
'email',
|
|
'phone',
|
|
'country_name',
|
|
'corp_name',
|
|
'industry',
|
|
'message'
|
|
]);
|
|
|
|
// 输出校验
|
|
$validate = new ProductInquiryValidate;
|
|
if (!$validate->check($post)) {
|
|
return error($validate->getError());
|
|
}
|
|
|
|
// 保存询盘信息
|
|
$ret = ProductInquiryModel::create([
|
|
'language_id' => $this->lang_id,
|
|
'first_name' => $post['first_name'],
|
|
'last_name' => $post['last_name'],
|
|
'email' => $post['email'],
|
|
'phone' => $post['phone'],
|
|
'country_name' => $post['country_name'],
|
|
'corp_name' => $post['corp_name'],
|
|
'industry' => $post['industry'],
|
|
'referer_url' => request()->header('referer'),
|
|
'message' => $post['message'],
|
|
]);
|
|
if ($ret->isEmpty()) {
|
|
return error(lang('提交失败'));
|
|
}
|
|
return success(lang('提交成功'));
|
|
}
|
|
|
|
/**
|
|
* 新品上市
|
|
*/
|
|
public function newpro()
|
|
{
|
|
$focus_image = [];
|
|
// 获取焦点图
|
|
$banner = SysBannerModel::with(['items' => function($query) {
|
|
$query->withoutField([
|
|
'status',
|
|
'created_at',
|
|
'updated_at',
|
|
'deleted_at'
|
|
])
|
|
->where('status', '=', 1)
|
|
->order(['sort' => 'asc', 'id' => 'desc']);
|
|
}])
|
|
->atPlatform(request()->from)
|
|
->uniqueLabel(['BANNER_680dd7ceaa529'])
|
|
->language($this->lang_id)
|
|
->enabled(true)
|
|
->select();
|
|
if (!$banner->isEmpty()) {
|
|
$focus_image = $banner->first()?->items ?? [];
|
|
}
|
|
View::assign('focus_image', $focus_image);
|
|
|
|
$newpros = [];
|
|
// 获取新品上市产品
|
|
$products = ProductModel::field(['id', 'category_id', 'name', 'spu', 'cover_image', 'is_new'])
|
|
->language($this->lang_id)
|
|
->enabled(true)
|
|
->onSale(true)
|
|
->onShelves(true)
|
|
->isNew(true)
|
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
|
->select();
|
|
if (!$products->isEmpty()) {
|
|
// 获取产品分类信息
|
|
$categorys = ProductCategoryModel::field(['id', 'name', 'path', 'level'])
|
|
->where(function($query) use($products) {
|
|
$query->where('id', 'IN', Arr::pluck($products, 'category_id'))->whereOr('level', '=', 2);
|
|
})
|
|
->language($this->lang_id)
|
|
->displayed(true)
|
|
->order(['sort' => 'asc', 'id' => 'asc'])
|
|
->select();
|
|
if (!$categorys->isEmpty()) {
|
|
// 根据产品分类path信息分组
|
|
$map = [];
|
|
foreach ($categorys as $category) {
|
|
$map[$category['id']] = $category;
|
|
}
|
|
$pro_map = [];
|
|
foreach ($products as $pro) {
|
|
if (!isset($map[$pro['category_id']])) {
|
|
continue;
|
|
}
|
|
$m = $map[$pro['category_id']];
|
|
$pro_map[$m['path']][] = $pro;
|
|
}
|
|
|
|
// 获取二级分类下的产品信息
|
|
foreach ($categorys as $val) {
|
|
if ($val['level'] != 2) {
|
|
continue;
|
|
}
|
|
|
|
foreach ($pro_map as $k => $pro) {
|
|
if (in_array($val['id'], explode(',', strval($k)))) {
|
|
$newpros[] = [
|
|
'category' => $val,
|
|
'products' => $pro,
|
|
];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
View::assign('newpros', $newpros);
|
|
|
|
return View::fetch('newpro');
|
|
}
|
|
}
|