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', 'created_at' => 'desc', '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', 'created_at' => 'desc', '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', 'created_at' => 'desc', '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) { $replace = fn($txt) => '' . $txt . ''; $item['spu'] = highlight_keywords($item['spu'], $keywords, $replace); $item['name'] = highlight_keywords($item['name'], $keywords, $replace); $item['short_name'] = highlight_keywords($item['short_name'], $keywords, $replace); 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', 'platform_sort' => 'sort']) ->toArray(); // 根据购买链接平台排序 $sort_by_arr = array_column($product_purchase_links, 'platform_sort'); array_multisort($sort_by_arr, SORT_ASC, $product_purchase_links); // 获取相关产品信息 $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'); } }