This commit is contained in:
2025-07-02 10:57:38 +08:00
8 changed files with 265 additions and 5 deletions

View File

@@ -0,0 +1,217 @@
<?php
declare (strict_types = 1);
namespace app\admin\controller;
use app\admin\model\v1\LanguageModel;
use app\admin\model\v1\ProductCategoryModel;
use app\admin\model\v1\ProductModel;
use app\admin\model\v1\ProductTcoCategoryModel;
use think\facade\Db;
class Operate_Of_ReceiveSync
{
const Add = 'add';
const Update = 'update';
const Enable = 'enable';
const Disable = 'disable';
}
/**
* 接收产品相关同步数据
*/
class ReceiveProductSync
{
// 接收产品目录分类同步数据
public function category()
{
$data = request()->post();
if (empty($data)) return error('请确认同步数据');
$validate = validate([
'name|分类名称' => 'require',
'erp_code|分类ERP编码' => 'require',
]);
if (!$validate->check($data)) {
return error((string)$validate->getError());
}
// 获取对应语言ID
$lang_id = LanguageModel::where('code', $data['lang'])->value('id');
if (empty($lang_id)) {
return error('语言不存在');
}
Db::startTrans();
try {
$tco_category_data = [
'language_id' => $lang_id,
'name' => $data['name'],
'tco_id' => $data['tco_id'],
'tco_pid' => $data['tco_pid'],
'tco_path' => $data['tco_path'],
'erp_id' => $data['erp_id'],
'erp_pid' => $data['erp_pid'],
'erp_code' => $data['erp_code'],
'erp_path' => $data['erp_path'],
'disabled' => Operate_Of_ReceiveSync::Disable == $data['operate'] ? 1 : 0,
'sync_time' => strtotime($data['created_at'])
];
$tco_category = ProductTcoCategoryModel::language($lang_id)->erpCode($tco_category_data['erp_code'])->find();
if (empty($tco_category)) {
$tco_category = ProductTcoCategoryModel::create($tco_category_data);
if ($tco_category->isEmpty()) {
throw new \Exception('产品目录分类创建失败');
}
$category_data = [
'language_id' => $lang_id,
'unique_id' => uniqid('PRO_CATE_'),
'pid' => 0,
'path' => '',
'name' => $tco_category_data['name'],
'icon' => '',
'desc' => '',
'related_tco_category' => $tco_category['id'],
'sort' => 0,
'level' => 1,
'is_show' => 1,
];
$tco_parent = ProductTcoCategoryModel::language($lang_id)->tcoId($tco_category['tco_pid'])->find();
if (!empty($tco_parent)) {
$parent = ProductCategoryModel::language($lang_id)->tcoId($tco_parent['id'])->find();
if ($parent->isEmpty()) {
throw new \Exception('产品分类父级不存在');
}
$category_data['pid'] = $parent['id'];
$category_data['path'] = $parent['path'] . $parent['pid'];
$category_data['level'] = $parent['level'] + 1;
}
$category = ProductCategoryModel::create($category_data);
if ($category->isEmpty()) {
throw new \Exception('产品分类创建失败');
}
}
else if ($tco_category['sync_time'] < $tco_category_data['sync_time']) {
$success = $tco_category->save($tco_category_data);
if (!$success) {
throw new \Exception('产品目录分类更新失败');
}
$category = ProductCategoryModel::language($lang_id)->tcoId($tco_category['id'])->find();
$tco_parent = ProductTcoCategoryModel::language($lang_id)->tcoId($tco_category['tco_pid'])->find();
if (!empty($tco_parent)) {
$parent = ProductCategoryModel::language($lang_id)->tcoId($tco_parent['id'])->find();
if ($parent->isEmpty()) {
throw new \Exception('产品分类父级不存在');
}
$category['pid'] = $parent['id'];
$category['path'] = $parent['path'] . $parent['pid'];
$category['level'] = $parent['level'] + 1;
}
if (!$category->save($category)) {
throw new \Exception('产品分类更新失败');
}
}
Db::commit();
} catch (\Throwable $th) {
Db::rollback();
return error(sprintf('%s %s:%d', $th->getMessage(), $th->getFile(), $th->getLine()));
}
return success('同步成功');
}
// 接收产品同步数据
public function product()
{
$data = request()->post();
if (empty($data)) {
return error('请确认同步数据');
}
$validate = validate([
'spu' => 'require',
'name' => 'require',
'category_erp_code' => 'require',
'lang' => 'require',
'created_at' => 'require',
]);
if (!$validate->check($data)) {
return error((string)$validate->getError());
}
// 获取对应语言ID
$lang_id = LanguageModel::where('code', $data['lang'])->value('id');
if (empty($lang_id)) {
return error('语言不存在');
}
// 如果 spu_before_modification 存在则根据 spu_before_modification 更新型号
$product = null;
if (!empty($data['spu_before_modification'])) {
$product = ProductModel::language($lang_id)->spu($data['spu_before_modification'])->find();
}
if (
(empty($data['spu_before_modification']) && !empty($data['spu']))
// 避免 spu_before_modification 更新型号时,人为删除了旧型号导致的新增,从而出现重复型号问题,而进行再次验证
|| (!empty($data['spu_before_modification']) && empty($product))
) {
$product = ProductModel::language($lang_id)->spu($data['spu'])->find();
}
try {
$product_tco_category = ProductTcoCategoryModel::language($lang_id)->erpCade($data['category_erp_code'])->find();
if (empty($product_tco_category)) {
throw new \Exception('官网未找到产品目录同步分类');
}
$product_category = ProductCategoryModel::language($lang_id)->tcoId($product_tco_category['id'])->find();
if (empty($product_category)) {
throw new \Exception('官网未找到产品目录同步分类关联的分类');
}
if (empty($product)) {
$product = ProductModel::create([
'language_id' => $lang_id,
'category_id' => $product_category['id'],
'spu' => $data['spu'],
'name' => $data['name'],
'short_name' => '',
'cover_image' => '',
'desc' => '',
'video_img' => '',
'video_url' => '',
'is_sale' => 0,
'is_new' => 0,
'is_hot' => 0,
'is_show' => Operate_Of_ReceiveSync::Disable == $data['operate'] ? 0 : 1,
'sort' => 0,
'detail' => '',
'status' => 1,
'seo_title' => '',
'seo_keywords' => '',
'seo_desc' => '',
'updated_at' => $data['created_at'],
]);
if ($product->isEmpty()) {
throw new \Exception('产品创建失败');
}
}
else if (strtotime($product['updated_at']) < strtotime($data['created_at'])) {
$product->spu = $data['spu'];
$product->name = $data['name'];
$product->category_id = $product_category['id'];
$product->is_show = Operate_Of_ReceiveSync::Disable == $data['operate'] ? 0 : 1;
if (!$product->save()) {
throw new \Exception('产品更新失败');
}
}
} catch (\Throwable $th) {
return error(sprintf('%s %s:%d', $th->getMessage(), $th->getFile(), $th->getLine()));
}
return success('同步成功');
}
}

View File

@@ -29,6 +29,12 @@ class ProductCategoryModel extends ProductCategoryBaseModel
$query->where('language_id', '=', $value); $query->where('language_id', '=', $value);
} }
// 所属产品目录分类id查询
public function scopeTcoId($query, $value)
{
$query->where('related_tco_category', '=', $value);
}
/** /**
* 根据是否显示查询 * 根据是否显示查询
* @param $query * @param $query

View File

@@ -80,6 +80,12 @@ class ProductModel extends ProductBaseModel
$query->where('category_id', '=', $value); $query->where('category_id', '=', $value);
} }
// 规格型号查询
public function scopeSpu($query, $spu)
{
$query->where('spu', '=', $spu);
}
// 启用状态查询 // 启用状态查询
public function scopeEnabled($query) public function scopeEnabled($query)
{ {

View File

@@ -23,6 +23,18 @@ class ProductTcoCategoryModel extends ProductTcoCategoryBaseModel
$query->where('language_id', '=', $value); $query->where('language_id', '=', $value);
} }
// 根据 tco_id 查询
public function scopeTcoId($query, $value)
{
$query->where('tco_id', '=', $value);
}
// 根据ERP Code查询
public function scopeErpCode($query, $value)
{
$query->where('erp_code', '=', $value);
}
// 按分类名称搜索 // 按分类名称搜索
public function searchNameAttr($query, $value, $data) public function searchNameAttr($query, $value, $data)
{ {

View File

@@ -222,3 +222,22 @@ if (!function_exists('get_platform')) {
return $platform; return $platform;
} }
} }
if (!function_exists('highlight_keywords')) {
/**
* 高亮关键词
* @param string $item
* @param string $keywords
* @param array $class
* @return string
*/
function highlight_keywords(string $text, string $keywords, array $class=[]): string
{
return preg_replace_callback('/' . preg_quote($keywords, '/') . '+/i', function($match) use($text, $class) {
if (empty($match)) {
return $text;
}
return '<strong class="' . implode(' ', $class) . '">' . $match[0] . '</strong>';
}, $text);
}
}

View File

@@ -299,9 +299,9 @@ class Product extends Common
'query' => request()->param() 'query' => request()->param()
]) ])
->each(function ($item) use($keywords) { ->each(function ($item) use($keywords) {
$item['spu'] = str_replace($keywords, '<strong class="redpoint">'.$keywords.'</strong>', $item['spu']); $item['spu'] = highlight_keywords($item['spu'], $keywords, ['redpoint']);
$item['name'] = str_replace($keywords, '<strong class="redpoint">'.$keywords.'</strong>', $item['name']); $item['name'] = highlight_keywords($item['name'], $keywords, ['redpoint']);
$item['short_name'] = str_replace($keywords, '<strong class="redpoint">'.$keywords.'</strong>', $item['short_name']); $item['short_name'] = highlight_keywords($item['short_name'], $keywords, ['redpoint']);
return $item; return $item;
}); });
View::assign('products', $products); View::assign('products', $products);

View File

@@ -79,6 +79,6 @@ class ProductModel extends ProductBaseModel
// 关键词搜索 // 关键词搜索
public function searchKeywordsAttr($query, string $keywords) public function searchKeywordsAttr($query, string $keywords)
{ {
$query->whereRaw('BINARY spu LIKE "%' . $keywords . '%" OR BINARY name LIKE "%' . $keywords . '%" OR BINARY short_name LIKE "%' . $keywords . '%"'); $query->whereRaw('spu LIKE "%' . $keywords . '%" OR name LIKE "%' . $keywords . '%" OR short_name LIKE "%' . $keywords . '%"');
} }
} }

View File

@@ -136,7 +136,7 @@
$('#dropdown').hide(); $('#dropdown').hide();
} }
}); });
$('.nhlplxwmit:not(:first)').hover(function () { $('.nhlplxwmit').hover(function () {
// 当鼠标移入时,显示.lxewmimg 并隐藏.lximg // 当鼠标移入时,显示.lxewmimg 并隐藏.lximg
var lxe = $(this).find('.lxewmimg'); var lxe = $(this).find('.lxewmimg');
var lxi = $(this).find('.lximg'); var lxi = $(this).find('.lximg');