diff --git a/app/command/DataMigration.php b/app/command/DataMigration.php
index 1b48d496..648ff1d3 100644
--- a/app/command/DataMigration.php
+++ b/app/command/DataMigration.php
@@ -45,7 +45,13 @@ class DataMigration extends Command
// $this->migrateProductAttr();
// 迁移产品
- $this->migrateProduct();
+ // $this->migrateProduct();
+
+ // 迁移产品关联产品数据
+ // $this->migrateProductRelated();
+
+ // 迁移产品购买链接
+ // $this->migrateProductPurchaseLinks();
// 迁移文章
// $this->migrateArticle([
@@ -168,18 +174,25 @@ class DataMigration extends Command
->select()
->toArray();
+ $tree = array_to_tree($category, 0, 'pid', 1);
// 处理数据
- $this->handlerProductCategory(array_to_tree($category, 0, 'pid', 1), $tco_category_map);
+ $this->handlerProductCategory($tree, $tco_category_map);
}
- private function handlerProductCategory($category, $map) {
+ private function handlerProductCategory($category, $map, $path = []) {
foreach ($category as $val) {
$key = sprintf("%s_%s", $val['id'], $val['country_code']);
+ if ($val['pid'] == 0) {
+ $path = [];
+ } else {
+ if (!in_array($val['pid'], $path)) $path[] = $val['pid'];
+ }
$item = [
'id' => $val['id'],
'language_id' => $val['country_code'] == 'ZH' ? 1 : 2,
'unique_id' => uniqid('PRO_CATE_'),
'pid' => $val['pid'],
'name' => $val['name'],
+ 'path' => implode(',', $path),
'icon' => $val['icon'],
'desc' => $val['description'],
'related_tco_category' => isset($map[$key]) ? implode(',', $map[$key]) : '',
@@ -189,7 +202,7 @@ class DataMigration extends Command
];
Db::name('product_category')->insert($item);
if (isset($val['children'])) {
- $this->handlerProductCategory($val['children'], $map);
+ $this->handlerProductCategory($val['children'], $map, $path);
}
}
}
@@ -245,15 +258,27 @@ class DataMigration extends Command
$old_db = Db::connect('old');
+ $success_map = [];
+ $success_arr = include_once(runtime_path() . 'product_success.php');
+ foreach ($success_arr as $so) {
+ $success_map['p_' . $so['cod_product_id']] = $so;
+ }
+
$products = $old_db->name('product')
- ->where('id', '=', 128)
->where('country_code', 'in', ['ZH', 'US'])
+ ->where('id', '>', 0)
->order(['id' => 'asc'])
->cursor();
+ $total = 0;
$uploadMgr = new UploadMannager();
foreach ($products as $v)
{
+ $start = microtime(true);
+ if (isset($success_map['p_' . $v['id']])) {
+ continue;
+ }
+
Db::startTrans();
try {
// 处理封面图片
@@ -262,7 +287,9 @@ class DataMigration extends Command
if ($image_ret['code'] == 0) {
$image = $image_ret['data']['path'];
} else {
- $image = $image_ret['msg'];
+ if ($image_ret['code'] != 400) {
+ $image = $image_ret['msg'];
+ }
}
// 处理视频
@@ -271,7 +298,9 @@ class DataMigration extends Command
if ($video_ret['code'] == 0) {
$video = $video_ret['data']['path'];
} else {
- $video = $video_ret['msg'];
+ if ($video_ret['code'] != 400) {
+ $video = $video_ret['msg'];
+ }
}
// 处理详情中图片
@@ -287,11 +316,11 @@ class DataMigration extends Command
return '';
}
return '
';
- }, $v['ld_md_content']);
+ }, $v['ld_md_content']??'');
$item = [
'language_id' => $v['country_code'] == 'ZH' ? 1 : 2,
- 'category_id' => '',
+ 'category_id' => $v['cid'],
'spu' => $v['brand_id'],
'name' => $v['name'],
'short_name' => $v['shortname'],
@@ -302,31 +331,33 @@ class DataMigration extends Command
'is_sale' => $v['is_onsale'],
'is_new' => $v['isnew'],
'is_hot' => $v['ishot'],
- 'is_show' => $v['is_show'],
- 'sort' => $v['sort'],
+ 'is_show' => $v['is_show'] == 0 ? 1 : 0,
+ 'sort' => $v['sort'] == 9999 ? 0 : $v['sort'],
'detail' => $content,
'status' => $v['stat'] == -1 ? -1 : 1,
'seo_title' => $v['seo_title'],
'seo_keywords' => $v['seo_keyword'],
'seo_desc' => $v['seo_description'],
'created_at' => date('Y-m-d H:i:s', $v['createtime']),
- 'updated_at' => date('Y-m-d H:i:s', $v['updatetime']),
+ 'updated_at' => $v['updatetime'] == 0 ? date('Y-m-d H:i:s', $v['createtime']) : date('Y-m-d H:i:s', $v['updatetime']),
'deleted_at' => $v['stat'] == -1 ? date('Y-m-d H:i:s') : null,
];
// 保存产品数据
$id = Db::name('product')->insertGetId($item);
// 保存产品参数数据
- $prarms = [];
- $views = unserialize($v['product_view']);
- foreach ($views as $p) {
- $prarms[] = [
- 'product_id' => $id,
- 'name' => $p['desc_title'],
- 'value' => $p['desc_desc']
- ];
+ if (!empty($v['product_view'])) {
+ $prarms = [];
+ $views = unserialize($v['product_view']);
+ foreach ($views as $p) {
+ $prarms[] = [
+ 'product_id' => $id,
+ 'name' => $p['desc_title'],
+ 'value' => $p['desc_desc']
+ ];
+ }
+ Db::name('product_params')->insertAll($prarms);
}
- Db::name('product_params')->insertAll($prarms);
// 保存sku数据
$skus = [];
@@ -350,6 +381,7 @@ class DataMigration extends Command
if (!isset($images[$pkey])) {
$images[$pkey] = [];
$images[$pkey]['sku'] = $im['sku'];
+ $images[$pkey]['attrs'] = [];
}
// 处理图册
@@ -365,6 +397,10 @@ class DataMigration extends Command
$photo_album[$pkey] = [];
}
$photo_album[$pkey][] = $photos_ret['data']['path'];
+ } else {
+ if ($photos_ret['code'] != 400) {
+ $photo_album[$pkey][] = json_encode($photos_ret);
+ }
}
}
}
@@ -372,17 +408,19 @@ class DataMigration extends Command
// 处理属性
$attrs = json_decode($im['image_color'], true);
if (!empty($attrs)) {
- foreach ($attrs as $k => $at) {
- if ($k != 'sort') {
- $attr_value = $at;
- if (in_array($k, ['颜色', 'Color'])) {
- if ($k == 'Color') $k = '颜色';
- $attr_value = '/static/common/images/colors/' . $at . '.png';
+ foreach ($attrs as $attr) {
+ foreach ($attr as $k => $at) {
+ if ($k != 'sort') {
+ $attr_value = $at;
+ if (in_array($k, ['颜色', 'Color'])) {
+ if ($k == 'Color') $k = '颜色';
+ $attr_value = '/static/common/images/colors/' . $at . '.png';
+ }
+ $images[$pkey]['attrs'][] = [
+ 'attr_id' => $attrs_map[$v['country_code']][$k],
+ 'attr_value' => $attr_value,
+ ];
}
- $images[$pkey]['attrs'] = [
- 'attr_id' => $attrs_map[$v['country_code']][$k],
- 'attr_value' => $attr_value,
- ];
}
}
} else {
@@ -402,20 +440,21 @@ class DataMigration extends Command
'attr_value' => $attr_value,
];
if (
- empty($images[$pkey]['attrs']) ||
- (!empty($images[$pkey]['attrs']) && empty(array_intersect($images[$pkey]['attrs'], $attr_arr)))
+ empty($images[$pkey]['attrs']) || !array_some($images[$pkey]['attrs'], function($k, $v) use($attr_arr) {
+ return $v == $attr_arr;
+ })
) {
-
$images[$pkey]['attrs'][] = $attr_arr;
- file_put_contents(runtime_path() . 'attrs.txt', json_encode($attr_arr));
}
}
}
- foreach ($images as $key => $image) {
- $images[$key]['photo_album'] = $photo_album[$key];
+ if (!empty($photo_album)) {
+ foreach ($images as $key => $image) {
+ if (isset($photo_album[$key])) {
+ $images[$key]['photo_album'] = $photo_album[$key];
+ }
+ }
}
- file_put_contents(runtime_path() . 'images.txt', json_encode($images, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
- file_put_contents(runtime_path() . 'photo_album.txt', json_encode($photo_album, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
$two_images = $old_db->name('product_two_img')
->where('product_id', '=', $v['id'])
@@ -428,56 +467,74 @@ class DataMigration extends Command
if (!empty($ti['image_color'])) {
$tpkey = md5($ti['image_color']);
}
- if (!empty($ti['image_url'])) {
+ if (!empty($ti['image_url']) && $ti['image_url'] != '[]') {
$main_image_ret = $uploadMgr->upload($uploadMgr->download($ti['image_url']), 'image', 'product');
if ($main_image_ret['code'] == 0) {
$ti['image_url'] = $main_image_ret['data']['path'];
}
}
- $skus[] = ['main_image' => $ti['image_url'], 'image_color' => $ti['image_color'], 'pkey' => $tpkey];
+ if (\think\helper\Str::endsWith($ti['image_color'], ['.png', '.jpg', 'jpeg', '.gif'])) {
+ $arrt_ret = $uploadMgr->upload($uploadMgr->download($ti['image_color']), 'image', 'product');
+ if ($arrt_ret['code'] == 0) {
+ $ti['image_color'] = $arrt_ret['data']['path'];
+ }
+ }
+ $skus[] = [
+ 'main_image' => $ti['image_url'],
+ 'attrs' => [[
+ 'attr_id' => $attrs_map[$v['country_code']]['颜色'],
+ 'attr_value' => $ti['image_color'],
+ ]],
+ 'pkey' => $tpkey
+ ];
}
+
if (!empty($skus)) {
- $temp = [];
+ $temp = [];
+ $temp_images = [];
foreach ($skus as $idx => $sku) {
+ $skus[$idx]['product_id'] = $id;
if (isset($images[$sku['pkey']])) {
- $skus[$idx]['product_id'] = $id;
- $skus[$idx]['sku'] = $images[$sku['pkey']]['sku'];
- $skus[$idx]['photo_album'] = $images[$sku['pkey']]['photo_album'];
- $skus[$idx]['attrs'] = $images[$sku['pkey']]['attrs'];
+ $skus[$idx]['sku'] = $images[$sku['pkey']]['sku']??null;
+ $skus[$idx]['photo_album'] = $images[$sku['pkey']]['photo_album']??null;
+ if (!empty($images[$sku['pkey']]['attrs'])) {
+ $skus[$idx]['attrs'] = $images[$sku['pkey']]['attrs'];
+ }
} else {
- if (!empty($images[$idx])) {
- $temp = $images[$idx];
+ if (empty($temp_images)) {
+ $temp_images = array_values($images);
+ }
+ if (!empty($temp_images[$idx])) {
+ $temp = $temp_images[$idx];
}
if (!empty($temp)) {
- $skus[$idx]['product_id'] = $id;
- $skus[$idx]['sku'] = $temp['sku'];
- $skus[$idx]['photo_album'] = $temp['photo_album'];
- $skus[$idx]['attrs'] = $temp['attrs'];
+ $skus[$idx]['sku'] = $temp['sku']??null;
+ $skus[$idx]['photo_album'] = $temp['photo_album']??null;
+ if (!empty($temp['attrs'])) {
+ $skus[$idx]['attrs'] = $temp['attrs'];
+ }
}
}
unset($skus[$idx]['pkey']);
- unset($skus[$idx]['image_color']);
}
} else {
foreach ($images as $image) {
$skus[] = [
'product_id' => $id,
- 'sku' => $image['sku'],
+ 'sku' => $image['sku']??null,
'main_image' => '',
- 'photo_album' => $image['photo_album'],
+ 'photo_album' => $image['photo_album']??null,
'skus' => $image['attrs']
];
}
}
- file_put_contents(runtime_path() . 'skus.txt', json_encode($skus, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
- // throw new \Exception("exit;");
foreach ($skus as $sku) {
$sku_id = Db::name('product_sku')->insertGetId([
'product_id' => $sku['product_id'],
- 'sku' => $sku['sku'],
- 'main_image' => $sku['main_image'],
- 'photo_album' => json_encode($sku['photo_album']),
+ 'sku' => $sku['sku']??'',
+ 'main_image' => $sku['main_image']??'',
+ 'photo_album' => !empty($sku['photo_album']) ? json_encode($sku['photo_album']) : null,
]);
if (!empty($sku['attrs'])) {
foreach ($sku['attrs'] as $attr) {
@@ -491,13 +548,21 @@ class DataMigration extends Command
}
}
}
+
Db::commit();
- $this->println(sprintf('迁移产品ID:%s => %s', $v['id'], $id));
+ $total += 1;
+ file_put_contents(
+ runtime_path() . 'product_success.txt',
+ sprintf('["ow_product_id" => %d, "cod_product_id" => %d]'.PHP_EOL, $id, $v['id']),
+ FILE_APPEND
+ );
+ $this->println(sprintf('迁移产品ID:%s => %s 【耗时:%s】', $v['id'], 0, round(microtime(true) - $start, 2) . 's'));
} catch (\Throwable $th) {
Db::rollback();
file_put_contents(
runtime_path() . 'product_throwable.txt',
- sprintf('【%s】 产品【%s】,迁移失败,错误【%s:%d】' . PHP_EOL, date('Y-h-d H:i:s'), $v['id'], $th->getMessage(), $th->getLine())
+ sprintf('【%s】 产品【%s】,迁移失败,错误【%s:%d】' . PHP_EOL, date('Y-h-d H:i:s'), $v['id'], $th->getMessage(), $th->getLine()),
+ FILE_APPEND
);
file_put_contents(
runtime_path() . 'product_throwable_details.txt',
@@ -505,6 +570,74 @@ class DataMigration extends Command
);
}
}
+
+ $this->println(sprintf('迁移产品完成,共迁移 %s 条数据', $total));
+ }
+
+ // 迁移产品关联产品数据
+ private function migrateProductRelated()
+ {
+ $sources = include_once(runtime_path() . 'product_success.php');
+ $maps = [];
+ foreach ($sources as $so) {
+ $maps[$so['cod_product_id']] = $so;
+ }
+
+ $old_db = Db::connect('old');
+ $related = $old_db->name('product_related')
+ ->where('country_code', 'in', ['ZH', 'US'])
+ ->where('stat', '=', 0)
+ ->cursor();
+
+ $data = [];
+ foreach ($related as $rl) {
+ if (empty($maps[$rl['product_id']]) || empty($maps[$rl['related_product_id']])) {
+ continue;
+ }
+ $data[] = [
+ 'product_id' => $maps[$rl['product_id']]['ow_product_id'],
+ 'related_product_id' => $maps[$rl['related_product_id']]['ow_product_id'],
+ 'desc' => empty($rl['related_desc']) ? null : $rl['related_desc'],
+ 'sort' => $rl['related_sort'] == 9999 ? 0 : $rl['related_sort']
+ ];
+ }
+ Db::name('product_related')->insertAll($data);
+ }
+
+ // 迁移产品购买链接
+ private function migrateProductPurchaseLinks()
+ {
+ $platform_maps = [
+ 1 => 2,
+ 2 => 1,
+ 3 => 3,
+ 4 => 4
+ ];
+
+ $sources = include_once(runtime_path() . 'product_success.php');
+ $maps = [];
+ foreach ($sources as $so) {
+ $maps[$so['cod_product_id']] = $so;
+ }
+
+ $old_db = Db::connect('old');
+ $links = $old_db->name('product_purchase_links')
+ ->where('country_code', 'in', ['ZH', 'US'])
+ ->where('link', '<>', '')
+ ->cursor();
+
+ foreach ($links as $link) {
+ if (empty($maps[$link['product_id']])) {
+ continue;
+ }
+ $item = [
+ 'language_id' => $link['country_code'] == 'ZH' ? 1 : 2,
+ 'product_id' => $maps[$link['product_id']]['ow_product_id'],
+ 'platform_id' => $platform_maps[$link['platform_id']],
+ 'link' => $link['link']
+ ];
+ Db::name('product_purchase_link')->insert($item);
+ }
}
// 迁移文章
@@ -758,11 +891,13 @@ class UploadMannager
private $password = 'Aa-1221';
private $token = '';
private $retrys = [];
+ private $maps = [];
public function __construct()
{
// 登录获取token
$this->token = $this->getAuthorization();
+ $this->maps = include_once(runtime_path() . 'fiber_product_image_mapping.php');
}
// 下载图片
@@ -805,21 +940,14 @@ class UploadMannager
$file_path = self::DOWNLOAD_TEMP_PATH . $file_name;
if (file_exists($file_path)) {
+ if (!is_valid_image($file_path)) {
+ return '';
+ }
return $file_path;
}
- // 使用file_get_contents下载
- // $opts = [
- // 'http' => [
- // 'method' => 'GET',
- // 'header' => 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
- // ]
- // ];
- // $context = stream_context_create($opts);
- // $file = file_get_contents($url, false, $context);
-
// 使用curl下载
- $file = $this->file_get_withcurl($url);
+ $file = file_get_withcurl($url);
$dir = dirname($file_path);
if (!is_dir($dir)) {
mkdir($dir, 0777, true);
@@ -828,34 +956,17 @@ class UploadMannager
return $file_path;
}
- // 使用curl下载图片
- private function file_get_withcurl($url)
- {
- $ch = curl_init($url);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); // 连接超时 10 秒
- curl_setopt($ch, CURLOPT_TIMEOUT, 30); // 传输超时 30 秒
- curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // 跟随重定向
- curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0'); // 模拟浏览器 UA
-
- $data = curl_exec($ch);
- if ($data === false) {
- error_log(sprintf('cURL Error: %s; URL: %s', curl_error($ch), $url));
- return false;
- }
- curl_close($ch);
-
- return $data;
- }
-
// 上传图片
public function upload($file_path, $field_name, $module = 'unknown') {
if (empty($file_path)) {
- return ['code' => 0, 'msg' => 'file_path为空', 'data' => ['path' => '']];
+ return ['code' => 400, 'msg' => 'file_path为空', 'data' => ['path' => '']];
}
if (\think\helper\Str::startsWith($file_path, 'http')) {
return ['code' => 0, 'msg' => 'file_path为http', 'data' => ['path' => $file_path]];
}
+ if (isset($this->maps[$file_path])) {
+ return ['code' => 0, 'msg' => '成功', 'data' => ['path' => $this->maps[$file_path]]];
+ }
switch($field_name){
case 'image':
@@ -939,3 +1050,48 @@ class UploadMannager
return $result['data']['token'];
}
}
+
+// 使用curl下载图片
+function file_get_withcurl($url)
+{
+ $ch = curl_init($url);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); // 连接超时 10 秒
+ curl_setopt($ch, CURLOPT_TIMEOUT, 60); // 传输超时 30 秒
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // 跟随重定向
+ curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0'); // 模拟浏览器 UA
+
+ $data = curl_exec($ch);
+ if ($data === false) {
+ file_put_contents(runtime_path() . 'file_get_withcurl.txt', sprintf('cURL Error: %s; URL: %s' . PHP_EOL, curl_error($ch), $url), FILE_APPEND);
+ return false;
+ }
+ curl_close($ch);
+
+ return $data;
+}
+
+// 检查图片是否有效
+function is_valid_image($filepath)
+{
+ try {
+ $image_size = getimagesize($filepath);
+ if ($image_size === false) {
+ return false;
+ }
+ [$width, $height] = $image_size;
+ return $width > 0 && $height > 0;
+ } catch (\Throwable $e) {
+ return false;
+ }
+}
+
+// 根据自定义函数检查数组
+function array_some($array, callable $ca): bool
+{
+ foreach ($array as $k => $v) {
+ if ($ca($k, $v)) return true;
+ }
+
+ return false;
+}
diff --git a/app/index/controller/Attachment.php b/app/index/controller/Attachment.php
index af288e40..5fe82545 100644
--- a/app/index/controller/Attachment.php
+++ b/app/index/controller/Attachment.php
@@ -111,7 +111,7 @@ class Attachment extends Common
])
->withSearch(['name'], ['name' => $param['keyword']??null])
->language($this->lang_id)
- ->category($param['id']??null)
+ ->category($param['id']??$video_categorys[0]['id']??null)
->order(['sort' => 'asc', 'id' => 'desc'])
->paginate([
'list_rows' => $param['size'],
diff --git a/app/index/controller/Common.php b/app/index/controller/Common.php
index 9040bb91..04eba78e 100644
--- a/app/index/controller/Common.php
+++ b/app/index/controller/Common.php
@@ -121,6 +121,7 @@ abstract class Common extends BaseController
$products = ProductModel::field([
'id',
'name',
+ 'short_name',
'cover_image',
])
->language($language)
diff --git a/app/index/controller/Index.php b/app/index/controller/Index.php
index ab7610d2..efb15f72 100644
--- a/app/index/controller/Index.php
+++ b/app/index/controller/Index.php
@@ -26,7 +26,14 @@ class Index extends Common
View::assign('featured_topics', $banner['featured_topics']);
View::assign('video', array_shift($banner['video']));
View::assign('scenes', $banner['scenes']);
- View::assign('brand_story', $banner['brand_story']);
+ View::assign('brand_story', array_map(function($item) {
+ $item['year'] = '';
+ $arr = explode('-', $item['title']);
+ if (count($arr) > 1) {
+ $item['year'] = $arr[0];
+ }
+ return $item;
+ }, $banner['brand_story']??null));
View::assign('data_statistics', $banner['data_statistics']);
// 获取明星产品/热点产品
@@ -45,7 +52,7 @@ class Index extends Common
private function getBannerData()
{
$banners = SysBannerModel::with(['items' => function($query) {
- $query->where('type', '=', 'image')->where('status', '=', 1)->order(['sort' => 'asc', 'id' => 'desc']);
+ $query->where('type', 'IN', ['image', 'video'])->where('status', '=', 1)->order(['sort' => 'asc', 'id' => 'desc']);
}])
->uniqueLabel([
'BANNER_67f61cd70e8e1',
@@ -64,7 +71,7 @@ class Index extends Common
foreach ($banners as $v) {
$banner_map[$v->unique_label] = $v;
}
-
+
// 处理焦点轮播图和产品分类
$data['focus_images'] = []; // 焦点轮播图
$data['product_categorys'] = []; // 产品分类信息
diff --git a/app/index/controller/Product.php b/app/index/controller/Product.php
index 080502bd..52a8205d 100644
--- a/app/index/controller/Product.php
+++ b/app/index/controller/Product.php
@@ -22,12 +22,100 @@ use think\helper\Arr;
*/
class Product extends Common
{
- // 产品分类
+ // 产品分类 - 查看顶层分类
public function category()
{
// 参数
$param = request()->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 &$it) {
+ if (isset($pros_map[$it['id']])) {
+ $it['products'] = $pros_map[$it['id']];
+ }
+ unset($it['children']);
+ }
+ unset($it);
+ }
+ }
+ }
+ View::assign('list', $list);
+
+ return View::fetch('category');
+ }
+ // 产品分类 - 查看子类
+ public function subcategory()
+ {
+ // 参数
+ $param = request()->param(['id']);
+
$focus_image = [];
// 获取产品分类页焦点横幅
$banner = SysBannerModel::with(['items' => function($query) {
@@ -60,6 +148,7 @@ class Product extends Common
->child($param['id'], true)
->order(['sort' => 'asc', 'id' => 'desc'])
->select();
+
if (!$categorys_data->isEmpty()) {
if ($categorys_data->count() > 1) {
// 当分类数不只一个时,当前分类下有子分类,移除当前分类,只输出子分类
@@ -70,8 +159,8 @@ class Product extends Common
$categorys_data = $categorys_data->toArray();
$products = ProductModel::field([
- 'id',
- 'category_id',
+ 'id',
+ 'category_id',
'spu',
'name',
'short_name',
@@ -151,7 +240,40 @@ class Product extends Common
}
View::assign('categorys_data', $categorys_data);
- return View::fetch('category');
+ return View::fetch('subcategory');
+ }
+
+ /**
+ * 产品搜索
+ */
+ public function search()
+ {
+ $keywords = request()->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'])
+ ->select()
+ ->each(function ($item) use($keywords) {
+ $item['spu'] = str_replace($keywords, ''.$keywords.'', $item['spu']);
+ $item['name'] = str_replace($keywords, ''.$keywords.'', $item['name']);
+ $item['short_name'] = str_replace($keywords, ''.$keywords.'', $item['short_name']);
+ return $item;
+ });
+ View::assign('products', $products);
+
+ return View::fetch('search');
}
/**
@@ -334,7 +456,7 @@ class Product extends Common
$newpros = [];
// 获取新品上市产品
- $products = ProductModel::field(['id', 'category_id', 'name', 'spu', 'cover_image'])
+ $products = ProductModel::field(['id', 'category_id', 'name', 'spu', 'cover_image', 'is_new'])
->language($this->lang_id)
->enabled(true)
->onSale(true)
@@ -343,24 +465,45 @@ class Product extends Common
->order(['sort' => 'asc', 'id' => 'desc'])
->select();
if (!$products->isEmpty()) {
- // 按分类分组产品
- $products_map = [];
- foreach ($products as $product) {
- $products_map[$product['category_id']][] = $product;
- }
// 获取产品分类信息
- $categorys = ProductCategoryModel::field(['id', 'name'])
- ->byPks(array_keys($products_map))
+ $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' => 'desc'])
+ ->order(['sort' => 'asc', 'id' => 'asc'])
->select();
if (!$categorys->isEmpty()) {
+ // 根据产品分类path信息分组
+ $map = [];
foreach ($categorys as $category) {
- $newpros[] = [
- 'category' => $category,
- 'products' => $products_map[$category['id']] ?? [],
- ];
+ $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(',', $k))) {
+ $newpros[] = [
+ 'category' => $val,
+ 'products' => $pro,
+ ];
+ break;
+ }
+ }
}
}
}
diff --git a/app/index/lang/en-us.php b/app/index/lang/en-us.php
index 62b86746..e0452af2 100644
--- a/app/index/lang/en-us.php
+++ b/app/index/lang/en-us.php
@@ -2,7 +2,8 @@
return [
'header_navigation' => [
- 'product_categorys' => 'Products'
+ 'product_categorys' => 'Products',
+ 'store' => 'Store'
],
'header_search' => [
'history' => 'Search History',
@@ -163,6 +164,9 @@ return [
'send_success' => 'Add Success!',
'send_fail' => 'Add Fail!',
],
+ 'product_newpro' => [
+ 'view_all' => 'View all'
+ ],
'product_detail' => [
'detail_section_title' => 'Product Description',
'related_products' => 'Related Products',
diff --git a/app/index/lang/zh-cn.php b/app/index/lang/zh-cn.php
index f12d0f37..a0f867e1 100644
--- a/app/index/lang/zh-cn.php
+++ b/app/index/lang/zh-cn.php
@@ -2,7 +2,8 @@
return [
'header_navigation' => [
- 'product_categorys' => '产品列表'
+ 'product_categorys' => '产品列表',
+ 'store' => '店铺'
],
'header_search' => [
'hot_product' => '热销产品',
@@ -163,6 +164,9 @@ return [
'send_success' => '信息已成功提交',
'send_fail' => '信息提交失败',
],
+ 'product_newpro' => [
+ 'view_all' => '查看全部'
+ ],
'product_detail' => [
'detail_section_title' => '产品详情',
'related_products' => '相关产品',
diff --git a/app/index/model/ProductModel.php b/app/index/model/ProductModel.php
index e5d18164..5b8a74f3 100644
--- a/app/index/model/ProductModel.php
+++ b/app/index/model/ProductModel.php
@@ -4,6 +4,7 @@ declare (strict_types = 1);
namespace app\index\model;
use app\common\model\ProductBaseModel;
+use think\facade\Db;
use think\model\concern\SoftDelete;
/**
@@ -74,4 +75,10 @@ class ProductModel extends ProductBaseModel
{
$query->where('is_new', '=', (int)$stat);
}
+
+ // 关键词搜索
+ public function searchKeywordsAttr($query, string $keywords)
+ {
+ $query->whereRaw('BINARY spu LIKE "%' . $keywords . '%" OR BINARY name LIKE "%' . $keywords . '%" OR BINARY short_name LIKE "%' . $keywords . '%"');
+ }
}
diff --git a/app/index/view/attachment/video.html b/app/index/view/attachment/video.html
index 8f6a0239..02302065 100644
--- a/app/index/view/attachment/video.html
+++ b/app/index/view/attachment/video.html
@@ -36,8 +36,8 @@
{notempty name="video_categorys"}
@@ -243,12 +243,14 @@
+
+
-
-
-
-
-
-
-
-
-
- {$product.name|default=''}
-{$product.desc|default=''}
-{$related.name}
{$related.spu}
diff --git a/app/index/view/product/newpro.html b/app/index/view/product/newpro.html index 6c75dc8a..a425c586 100644 --- a/app/index/view/product/newpro.html +++ b/app/index/view/product/newpro.html @@ -16,26 +16,22 @@
-
-
-
-
-
-
-
-
-
@@ -11,6 +12,7 @@
Need to contact us? Just send us an e-mail at odmmarket@orico.com.cn
Store
+ {notempty name="basic_config['navigation_store_url']['value']"}
+
+
{:lang('header_navigation.store')}
+
+ {/notempty}
@@ -109,7 +112,7 @@
{/volist}
diff --git a/app/index/view/public/nas_header.html b/app/index/view/public/nas_header.html
index f0b4f0b9..e52d3056 100644
--- a/app/index/view/public/nas_header.html
+++ b/app/index/view/public/nas_header.html
@@ -1,6 +1,8 @@
+
+
+
{notempty name="header_navigation"}