作者 赵彬吉

product

... ... @@ -113,7 +113,7 @@ class Handler extends ExceptionHandler
$code = $exception->getCode();
} elseif ($exception instanceof ValidationException) {
$code = Code::USER_PARAMS_ERROE();
$message = Arr::first(Arr::first($exception->errors()));
$message = $code->description = Arr::first(Arr::first($exception->errors()));
} elseif ($exception instanceof NotFoundHttpException || $exception instanceof MethodNotAllowedHttpException) {
return response('404 Not Found', 404);
} else {
... ...
... ... @@ -125,4 +125,64 @@ class Arr extends \Illuminate\Support\Arr
return $signle ? $rows[0] : $rows;
}
/**
* 数组转字符串
* @param $arr
* @return string
* @author zbj
* @date 2023/4/17
*/
public static function a2s($arr): string
{
return json_encode($arr, JSON_UNESCAPED_UNICODE);
}
/**
* 字符串转数组
* @param $str
* @return array|mixed
* @author zbj
* @date 2023/4/17
*/
public static function s2a($str)
{
if (is_array($str)) {
return $str;
}
return is_object($str) ? (array)$str : json_decode($str, true);
}
/**
* 数组转set形式字符串
* @param $arr
* @param string $format
* @return string
* @author zbj
* @date 2023/4/17
*/
public static function arrToSet($arr, string $format = 'intval'): string
{
$arr = array_unique(array_filter(Arr::splitFilterToArray($arr, $format, ',')));
return $arr ? implode(',', $arr) : '';
}
/**
* set形式字符串转数组
* @param $str
* @param string $format
* @return array
* @author zbj
* @date 2023/4/17
*/
public static function setToArr($str, string $format = 'intval')
{
if (is_string($str)) {
return Arr::splitFilterToArray($str, $format, ',');
}
return $str ?: [];
}
}
... ...
... ... @@ -2,6 +2,8 @@
namespace App\Http\Controllers\Bside\Product;
use App\Enums\Common\Code;
use App\Exceptions\BsideGlobalException;
use App\Helper\Arr;
use App\Http\Controllers\Bside\BaseController;
use App\Http\Logic\Bside\Product\ProductLogic;
... ... @@ -13,7 +15,7 @@ use Illuminate\Http\Request;
* Class ProductController
* @package App\Http\Controllers\Bside
* @author zbj
* @date 2023/4/12
* @date 2023/4/17
*/
class ProductController extends BaseController
{
... ... @@ -24,9 +26,12 @@ class ProductController extends BaseController
if(!empty($this->param['search'])){
$map[] = ['title', 'like', "%{$this->param['search']}%"];
}
if(!empty($this->param['created_at'])){
$map[] = ['created_at', 'between', $this->param['created_at']];
}
$sort = ['id' => 'desc'];
$data = $logic->getList($map, $sort, ['id', 'pid', 'title', 'image', 'keywords', 'describe', 'status','created_at'],0);
return $this->success(Arr::listToTree($data));
$data = $logic->getList($map, $sort, ['id', 'title', 'thumb', 'category_id', 'keywords', 'status', 'created_at', 'updated_at']);
return $this->success($data);
}
public function info(Request $request, ProductLogic $logic){
... ... @@ -36,11 +41,47 @@ class ProductController extends BaseController
'id.required' => 'ID不能为空'
]);
$data = $logic->getInfo($this->param['id']);
return $this->success(Arr::twoKeepKeys($data, ['id', 'pid', 'title', 'image', 'keywords', 'describe', 'status']));
return $this->success(Arr::twoKeepKeys($data, ['id', 'title', 'gallery', 'attrs', 'category_id', 'keywords', 'intro', 'content',
'describe', 'seo_mate', 'related_product_id', 'status']));
}
public function save(ProductRequest $request, ProductLogic $logic)
{
//验证图片集格式
foreach ($this->param['gallery'] as $v){
if(empty($v['url'])){
throw new BsideGlobalException(Code::SYSTEM_ERROR, '图片链接不能为空');
}
}
//验证产品参数
foreach ($this->param['attrs'] as $v){
if(empty($v['key'])){
throw new BsideGlobalException(Code::SYSTEM_ERROR, '产品属性名不能为空');
}
if(empty($v['value'])){
throw new BsideGlobalException(Code::SYSTEM_ERROR, '产品属性值不能为空');
}
}
//验证seo_mate参数
if(empty($this->param['seo_mate']['title'])){
throw new BsideGlobalException(Code::SYSTEM_ERROR, 'SEO标题不能为空');
}
if(empty($this->param['seo_mate']['description'])){
throw new BsideGlobalException(Code::SYSTEM_ERROR, 'SEO描述不能为空');
}
if(empty($this->param['seo_mate']['keyword'])){
throw new BsideGlobalException(Code::SYSTEM_ERROR, 'SEO关键词不能为空');
}
//关联产品 最多16个
$this->param['related_product_id'] = array_filter(Arr::splitFilterToArray($this->param['related_product_id']), 'intval');
if(count($this->param['related_product_id']) > 16){
throw new BsideGlobalException(Code::SYSTEM_ERROR, '关联产品不能超过16个');
}
//封面取第一个图片
$this->param['thumb'] = $this->param['gallery'][0] ?? '';
$data = $logic->save($this->param);
return $this->success($data);
}
... ... @@ -57,5 +98,4 @@ class ProductController extends BaseController
return $this->success($data);
}
//todo Ai生成 关键词和描述
}
... ...
... ... @@ -62,17 +62,4 @@ class AttrLogic extends BaseLogic
}
return $this->success();
}
public function delete($ids){
$ids= array_filter(Arr::splitFilterToArray($ids), 'intval');
foreach ($ids as $id){
$info = $this->getCacheInfo($id);
if(!$info){
continue;
}
//todo 是否有关联商品
}
return parent::delete($ids);
}
}
... ...
... ... @@ -20,18 +20,4 @@ class DescribeLogic extends BaseLogic
$this->model = new Describe();
}
public function delete($ids){
$ids= array_filter(Arr::splitFilterToArray($ids), 'intval');
foreach ($ids as $id){
$info = $this->getCacheInfo($id);
if(!$info){
continue;
}
//todo 是否有关联商品
}
return parent::delete($ids);
}
}
... ...
... ... @@ -28,7 +28,7 @@ class KeywordLogic extends BaseLogic
try {
$res = parent::save($param);
//路由映射
RouteMap::setRoute($param['title'], RouteMap::SOURCE_PRODUCT_KEYWORD, $res['id'], $param['project_id'], true);
RouteMap::setRoute($param['title'], RouteMap::SOURCE_PRODUCT_KEYWORD, $res['id'], $param['project_id']);
DB::commit();
}catch (\Exception $e){
DB::rollBack();
... ...
... ... @@ -2,9 +2,10 @@
namespace App\Http\Logic\Bside\Product;
use App\Helper\Arr;
use App\Http\Logic\Bside\BaseLogic;
use App\Models\Product\Product;
use App\Models\RouteMap;
use Illuminate\Support\Facades\DB;
/**
* Class ProductLogic
... ... @@ -22,32 +23,18 @@ class ProductLogic extends BaseLogic
}
public function save($param){
if(!empty($param['pid'])){
if(!empty($param['id']) && $param['pid'] == $param['id']){
$this->fail('上级分类不能是本分类');
}
$p_cate = Product::find($param['pid']);
if(!$p_cate){
$this->fail('上级分类不存在');
}
}
return parent::save($param);
}
public function delete($ids){
$ids= array_filter(Arr::splitFilterToArray($ids), 'intval');
foreach ($ids as $id){
$info = $this->getCacheInfo($id);
if(!$info){
continue;
}
//是否有子分类
if(Product::where('pid', $id)->count()){
$this->fail("分类{$info['title']}存在子分类,不能删除");
}
//todo 是否有对应商品
}
return parent::delete($ids);
DB::beginTransaction();
try {
$data = $param;
unset($data['route']);
$res = parent::save($data);
//路由映射
RouteMap::setRoute($param['route'], RouteMap::SOURCE_PRODUCT, $res['id'], $param['project_id']);
DB::commit();
}catch (\Exception $e){
DB::rollBack();
$this->fail('保存失败');
}
return $this->success();
}
}
... ...
... ... @@ -2,7 +2,9 @@
namespace App\Http\Requests\Bside\product;
use App\Models\Product\Product;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
/**
* Class ProductRequest
... ... @@ -30,23 +32,44 @@ class ProductRequest extends FormRequest
public function rules()
{
return [
'title'=>'required|max:20',
'image'=>'required',
'keywords'=>'required|max:50',
'describe'=>'required|max:200',
'title'=>'required|max:200',
'route'=>'required|max:100',
'gallery'=>'required|array',
'attrs'=>'required|array',
'category_id'=>'required',
'keywords'=>'required',
'intro'=>'required|max:500',
'content'=>'required',
'describe'=>'required|array',
'seo_mate'=>'required|array',
'related_product_id'=>'required',
'status'=>['required', Rule::in(array_keys(Product::statusMap()))],
];
}
public function messages()
{
return [
'title.required' => '请输入分类名称',
'title.max' => '分类名称不能超过20个字符',
'image.required' => '请上传分类图片',
'keywords.required' => '请输入分类关键词',
'keywords.max' => '分类关键词不能超过50个字符',
'describe.required' => '请输入分类描述',
'describe.max' => '分类描述不能超过200个字符',
'title.required' => '请输入产品标题',
'title.max' => '产品标题不能超过20个字符',
'route.required' => '请输入产品链接',
'route.max' => '产品链接不能超过100个字符',
'gallery.required' => '请上传产品图片',
'gallery.array' => '产品图片格式异常',
'attrs.required' => '请添加产品参数',
'attrs.array' => '产品参数格式异常',
'category_id.required' => '请选择分类',
'keywords.required' => '请添加关键词标签',
'intro.required' => '请输入短描述',
'intro.max' => '短描述不能超过20个字符',
'content.required' => '请输入产品描述',
'describe.required' => '请添加描述切换栏',
'describe.array' => '描述切换栏格式异常',
'seo_mate.required' => '请输入SEO',
'seo_mate.array' => 'SEO格式异常',
'related_product_id.required' => '请选择相关产品',
'status.required' => '请选择产品状态',
'status.in' => '产品状态值异常',
];
}
... ...
... ... @@ -2,6 +2,7 @@
namespace App\Models\Product;
use App\Helper\Arr;
use App\Models\Base;
use Illuminate\Database\Eloquent\SoftDeletes;
... ... @@ -12,4 +13,81 @@ class Product extends Base
//设置关联表名
protected $table = 'gl_product';
const STATUS_DRAFT = 0;
const STATUS_ON = 1;
const STATUS_OFF = 2;
public static function statusMap(){
return [
self::STATUS_DRAFT => '草稿',
self::STATUS_ON => '已上架',
self::STATUS_OFF => '未上架',
];
}
public function setThumbAttribute($value){
$this->attributes['thumb'] = Arr::a2s($value);
}
public function getThumbAttribute($value){
return Arr::s2a($value);
}
public function setGalleryAttribute($value){
$this->attributes['gallery'] = Arr::a2s($value);
}
public function getGalleryAttribute($value){
return Arr::s2a($value);
}
public function setAttrsAttribute($value){
$this->attributes['attrs'] = Arr::a2s($value);
}
public function getAttrsAttribute($value){
return Arr::s2a($value);
}
public function setDescribeAttribute($value){
$this->attributes['describe'] = Arr::a2s($value);
}
public function getDescribeAttribute($value){
return Arr::s2a($value);
}
public function setSeoMateAttribute($value){
$this->attributes['seo_mate'] = Arr::a2s($value);
}
public function getSeoMateAttribute($value){
return Arr::s2a($value);
}
public function setCategoryIdAttribute($value){
$this->attributes['category_id'] = Arr::arrToSet($value);
}
public function getCategoryIdAttribute($value){
return Arr::setToArr($value);
}
public function setKeywordsAttribute($value){
$this->attributes['keywords'] = Arr::arrToSet($value, 'trim');
}
public function getKeywordsAttribute($value){
return Arr::setToArr($value, 'trim');
}
public function setRelatedProductIdAttribute($value){
$this->attributes['related_product_id'] = Arr::arrToSet($value);
}
public function getRelatedProductIdAttribute($value){
return Arr::setToArr($value);
}
}
... ...
... ... @@ -74,18 +74,13 @@ class RouteMap extends Model
* @param $source
* @param $source_id
* @param int $project_id
* @param bool $auto
* @return bool
* @throws \Exception
* @author zbj
* @date 2023/4/17
*/
public static function setRoute($title, $source, $source_id, $project_id = 0, $auto=false){
$route = $title;
if($auto){
public static function setRoute($title, $source, $source_id, $project_id = 0){
$route = self::generateRoute($title, $source, $source_id, $project_id);
}
if(!$route){
throw new \Exception('路由不能为空');
}
... ...
... ... @@ -2,6 +2,7 @@
namespace App\Utils;
use App\Enums\Common\Common;
use App\Helper\Arr;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Route;
... ... @@ -17,7 +18,12 @@ class LogUtils
public static function error($title, $params = [], $response = [])
{
$route=Route::current();
$side=$route->action['prefix']??Common::A;
if(!empty($route->action['prefix'])){
$prefix = Arr::splitFilterToArray($route->action['prefix'], 'trim', '/');
$side = $prefix[0];
}else{
$side = Common::A;
}
$params = is_array($params) ? json_encode($params, JSON_UNESCAPED_UNICODE) : $params;
$response = is_array($response) || is_object($response) ? json_encode($response, JSON_UNESCAPED_UNICODE) : $response;
Log::channel($side.'side')->error("$title::请求参数:$params--------响应:$response");
... ... @@ -33,7 +39,12 @@ class LogUtils
public static function info($title, $params = [], $response = [])
{
$route=Route::current();
$side=$route->action['prefix']??Common::A;
if(!empty($route->action['prefix'])){
$prefix = Arr::splitFilterToArray($route->action['prefix'], 'trim', '/');
$side = $prefix[0];
}else{
$side = Common::A;
}
$params = is_array($params) ? json_encode($params, JSON_UNESCAPED_UNICODE) : $params;
$response = is_array($response) || is_object($response) ? json_encode($response, JSON_UNESCAPED_UNICODE) : $response;
Log::channel($side.'side')->info("$title::请求参数:$params--------响应:$response");
... ...