From c151191430ea853f11cee62f6d7fbfc8e91eeb5e Mon Sep 17 00:00:00 2001 From: lwh <2679599887@qq.com> Date: Thu, 29 Jun 2023 10:32:28 +0800 Subject: [PATCH] =?UTF-8?q?fixex=20=E4=BF=AE=E6=94=B9=E4=BA=A7=E5=93=81?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E5=92=8C=E6=96=B0=E9=97=BB=E5=AF=BC=E5=85=A5?= =?UTF-8?q?=E5=AF=BC=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/admin/controller/News/News.php | 219 +++++++------ app/admin/controller/Products/ProductType.php | 98 +++--- app/common/model/News/News.php | 291 ++++++++++-------- app/common/model/Products/ProductType.php | 40 ++- public/excel/news/新闻导入模板.xlsx | Bin 0 -> 13054 bytes 5 files changed, 350 insertions(+), 298 deletions(-) create mode 100644 public/excel/news/新闻导入模板.xlsx diff --git a/app/admin/controller/News/News.php b/app/admin/controller/News/News.php index f6a3384..e39ab37 100644 --- a/app/admin/controller/News/News.php +++ b/app/admin/controller/News/News.php @@ -25,25 +25,26 @@ class News extends BaseController $params = $request->param(); $con = []; - $con = Tool::getOptionalQuery(['news_type','='],['news_title','LIKE'],); + $con = Tool::getOptionalQuery(['news_type', '='], ['news_title', 'LIKE'],); $query = ModelNews::where($con) ->field([ -'news_id', -'news_guid', -'news_type', -'news_title', -'news_intro', -'news_source', -'news_link', -'news_issue_date', -'news_views_num', -'news_sort', -'news_content' -]) + 'news_id', + 'news_guid', + 'news_type', + 'news_cover', + 'news_title', + 'news_intro', + 'news_source', + 'news_link', + 'news_issue_date', + 'news_views_num', + 'news_sort', + 'news_content' + ]) ->order('news_sort', 'asc'); - return $isExport ? $query->select()->toArray() : msg("获取新闻列表成功!",$query); + return $isExport ? $query->select()->toArray() : msg("获取新闻列表成功!", $query); } /** @@ -54,29 +55,31 @@ class News extends BaseController Db::startTrans(); Tool::adminLockTableWrite('news'); try { - $params = $request->param(); - $this->validate($params, [ -'news_type|新闻类型'=>'require', -'news_title|新闻标题'=>'require', -'news_sort|新闻排序'=>'require' -]); - $model = ModelNews::create($params,[ -'news_type', -'news_title', -'news_intro', -'news_source', -'news_link', -'news_issue_date', -'news_views_num', -'news_sort', -'news_content', -'news_guid', -'news_create_user_guid', -'news_update_user_guid' -]); - Db::commit(); - Tool::unlockTable(); - return msg('添加成功!'); + $params = $request->param(); + $this->validate($params, [ + 'news_type|新闻类型' => 'require', + 'news_title|新闻标题' => 'require', + 'news_cover|新闻封面' => 'require', + 'news_sort|新闻排序' => 'require' + ]); + $model = ModelNews::create($params, [ + 'news_type', + 'news_title', + 'news_cover', + 'news_intro', + 'news_source', + 'news_link', + 'news_issue_date', + 'news_views_num', + 'news_sort', + 'news_content', + 'news_guid', + 'news_create_user_guid', + 'news_update_user_guid' + ]); + Db::commit(); + Tool::unlockTable(); + return msg('添加成功!'); } catch (\Throwable $th) { Db::rollback(); Tool::unlockTable(); @@ -92,29 +95,31 @@ class News extends BaseController Db::startTrans(); Tool::adminLockTableWrite('news'); try { - $params = $request->param(); - $this->validate($params, [ -'news_type|新闻类型'=>'require', -'news_title|新闻标题'=>'require', -'news_sort|新闻排序'=>'require' -]); - $model = ModelNews::where('news_guid',$params['news_guid'])->find(); - if (!$model) throwErrorMsg("该新闻不存在", 1); - $model->allowField([ -'news_type', -'news_title', -'news_intro', -'news_source', -'news_link', -'news_issue_date', -'news_views_num', -'news_sort', -'news_content', -'news_update_user_guid' -])->save($params); - Db::commit(); - Tool::unlockTable(); - return msg('编辑成功!'); + $params = $request->param(); + $this->validate($params, [ + 'news_type|新闻类型' => 'require', + 'news_title|新闻标题' => 'require', + 'news_cover|新闻封面' => 'require', + 'news_sort|新闻排序' => 'require' + ]); + $model = ModelNews::where('news_guid', $params['news_guid'])->find(); + if (!$model) throwErrorMsg("该新闻不存在", 1); + $model->allowField([ + 'news_type', + 'news_title', + 'news_cover', + 'news_intro', + 'news_source', + 'news_link', + 'news_issue_date', + 'news_views_num', + 'news_sort', + 'news_content', + 'news_update_user_guid' + ])->save($params); + Db::commit(); + Tool::unlockTable(); + return msg('编辑成功!'); } catch (\Throwable $th) { Db::rollback(); Tool::unlockTable(); @@ -130,17 +135,17 @@ class News extends BaseController Db::startTrans(); Tool::adminLockTableWrite('news'); try { - $params = $request->param(); - $this->validate($params, [ - 'news_guid' => 'require', - ]); - $news = ModelNews::where([ - 'news_guid' => explode(',', $params['news_guid']) - ])->select(); - $news->delete(); - Db::commit(); - Tool::unlockTable(); - return msg('删除成功!'); + $params = $request->param(); + $this->validate($params, [ + 'news_guid' => 'require', + ]); + $news = ModelNews::where([ + 'news_guid' => explode(',', $params['news_guid']) + ])->select(); + $news->delete(); + Db::commit(); + Tool::unlockTable(); + return msg('删除成功!'); } catch (\Throwable $th) { Db::rollback(); Tool::unlockTable(); @@ -149,39 +154,49 @@ class News extends BaseController } /** -* 导出Excel -*/ - public function exportExcel(Request $request):void - { - ModelNews::exportExcel(self::getNewsList($request, true)); - } + * 导出Excel + */ + public function exportExcel(Request $request): void + { + ModelNews::exportExcel(self::getNewsList($request, true)); + } /** -* 下载导入模板 -*/ - public function downloadTemplate(Request $request):void - { - $params = $request->param(); - $data = [ - array_values(ModelNews::EXCELFIELD), - ['默认值1','默认值2','默认值3','默认值4','默认值5','默认值6','默认值7','默认值8','默认值9',] - ]; - $excel = (new Excel())->exporTsheet($data); - $excel->save('新闻导入模板.xlsx'); - } + * 下载导入模板 + */ + public function downloadTemplate(Request $request): void + { + $params = $request->param(); + $data = [ + array_values(ModelNews::EXCELFIELD), + [ + '公司新闻', + '想学嵌入式Linux?领免费的瑞萨RZ/G2L开发板!', + 'https://www.myir-tech.com/attached/image/20230609/1-1.jpg', + '学习嵌入式系统开发是一个渐进的过程,一般我们从51单片机开始,逐步迁移到STM32微控制器,然后学习使用FreeRTOS操作系统,最终进入嵌入式Linux领域。以下是一个典型的学习路线:51单片机:作为嵌入式系统的入门级平台,学习51单片机可以帮助我们了解基本的嵌入式开发概念和编程技巧。可以学习使用C语言编写简单的驱动程序、控制IO口和外设等。 ', + '米尔科技', + '', + '2023.6.9', + '0', + '1', + '

需要报名RZ/G2L免费开发板请扫码

', + ] + ]; + $excel = (new Excel())->exporTsheet($data); + $excel->save('新闻导入模板.xlsx'); + } /** -* 导入excel -*/ - public function importExcel(Request $request):array - { - $file = new UploadFile('uploads', 'fileExt:xlsx'); - $file->putFile('news'); - $msg = ModelNews::importExcel($file); - return [ - 'code' => 0, - 'msg' => $msg - ]; - } - + * 导入excel + */ + public function importExcel(Request $request): array + { + $file = new UploadFile('uploads', 'fileExt:xlsx'); + $file->putFile('news'); + $msg = ModelNews::importExcel($file); + return [ + 'code' => 0, + 'msg' => $msg + ]; + } } diff --git a/app/admin/controller/Products/ProductType.php b/app/admin/controller/Products/ProductType.php index a2dc94c..947bfb1 100644 --- a/app/admin/controller/Products/ProductType.php +++ b/app/admin/controller/Products/ProductType.php @@ -27,7 +27,7 @@ class ProductType extends BaseController * @author xjh * @since 1.0.0 */ - public function getProductTypeTree(Request $request): array + public function getProductTypeTree(Request $request, $isExport = false): array { $con = Tool::getOptionalQuery( ['b.product_delete_time', 'NULL'], @@ -64,9 +64,50 @@ class ProductType extends BaseController ]; }); - return msg("获取产品类目列表成功!", $product_type_tree); + return $isExport ? $product_type : msg("获取产品类目列表成功!", $product_type_tree); } + /** + * 添加产品类目接口 + * + * @param Request request + * @date 2023-03-25 + * @example + * @author xjh + * @since 1.0.0 + */ + public function addProductType(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'product_type_name|产品类型名称' => 'require', + 'product_type_order|产品类目排序' => 'require' + ]); + + ModelProductType::isDuplicateName($params['product_type_name'], $params['product_type_parent_guid']); + + $product_type_parent_where = []; + if (!empty($params['product_type_parent_guid'])) { + $params['product_type_ancestors_guid'] = ModelProductType::buildAncestorsGuid($params['product_type_parent_guid']); + $product_type_parent_where['product_type_parent_guid'] = $params['product_type_parent_guid']; + } + + ModelProductType::create($params, [ + 'product_type_guid', + 'product_type_create_user_guid', + 'product_type_update_user_guid', + 'product_type_parent_guid', + 'product_type_ancestors_guid', + 'product_type_name', + 'product_type_title', + 'product_type_link', + 'product_type_icon', + 'product_type_order' + ]); + return msg('添加成功!'); + } + + /** * 编辑产品类目接口 * @@ -88,6 +129,9 @@ class ProductType extends BaseController $model = ModelProductType::where('product_type_guid', $params['product_type_guid'])->find(); if (!$model) throwErrorMsg("该产品类目不存在", 1); + if ($model->product_type_parent_guid == $model->product_type_guid) { + throwErrorMsg("上级菜单不能选择与当前菜单一样的", 1); + } ModelProductType::isDuplicateName($params['product_type_name'], $params['product_type_guid']); @@ -107,46 +151,6 @@ class ProductType extends BaseController } - /** - * 添加产品类目接口 - * - * @param Request request - * @date 2023-03-25 - * @example - * @author xjh - * @since 1.0.0 - */ - public function addProductType(Request $request): array - { - $params = $request->param(); - $this->validate($params, [ - 'product_type_name|产品类型名称' => 'require', - 'product_type_order|产品类目排序' => 'require' - ]); - - ModelProductType::isDuplicateName($params['product_type_name']); - - $product_type_parent_where = []; - if (!empty($params['product_type_parent_guid'])) { - $params['product_type_ancestors_guid'] = ModelProductType::buildAncestorsGuid($params['product_type_parent_guid']); - $product_type_parent_where['product_type_parent_guid'] = $params['product_type_parent_guid']; - } - - ModelProductType::create($params, [ - 'product_type_guid', - 'product_type_create_user_guid', - 'product_type_update_user_guid', - 'product_type_parent_guid', - 'product_type_ancestors_guid', - 'product_type_name', - 'product_type_title', - 'product_type_link', - 'product_type_icon', - 'product_type_order' - ]); - return msg('添加成功!'); - } - /** * 删除产品类目接口 * @@ -186,15 +190,7 @@ class ProductType extends BaseController */ public function exportExcel(Request $request) { - $params = $request->param(); - $select = ModelProductType::field([ - 'product_type_title', - 'product_type_icon', - 'product_type_cover' - ]) - ->order('product_type_update_time', 'desc') - ->select(); - return ModelProductType::exportExcel($select); + ModelProductType::exportExcel(self::getProductTypeTree($request, true)); } /** diff --git a/app/common/model/News/News.php b/app/common/model/News/News.php index 4cf0182..d0355cf 100644 --- a/app/common/model/News/News.php +++ b/app/common/model/News/News.php @@ -9,6 +9,7 @@ use app\common\arw\adjfut\src\Excel; use app\Request; use app\common\exception\Tool; use think\facade\Db; +use app\common\model\Dictionary\Dictionary as ModelDictionary; class News extends BaseModel { @@ -21,25 +22,26 @@ class News extends BaseModel protected $disuse = []; // 设置字段信息 protected $schema = [ - 'news_id' => 'int' , - 'news_guid' => 'string' , - 'news_type' => 'int' , - 'news_title' => 'string' , - 'news_intro' => 'string' , - 'news_source' => 'string' , - 'news_link' => 'string' , - 'news_issue_date' => '' , - 'news_views_num' => 'int' , - 'news_sort' => 'int' , - 'news_content' => '' , - 'news_create_time' => 'datetime' , - 'news_create_user_guid' => 'string' , - 'news_update_time' => 'datetime' , - 'news_update_user_guid' => 'string' , - 'news_delete_time' => 'datetime' , - 'news_delete_user_guid' => 'string' , + 'news_id' => 'int', + 'news_guid' => 'string', + 'news_type' => 'int', + 'news_title' => 'string', + 'news_cover' => 'string', + 'news_intro' => 'string', + 'news_source' => 'string', + 'news_link' => 'string', + 'news_issue_date' => '', + 'news_views_num' => 'int', + 'news_sort' => 'int', + 'news_content' => '', + 'news_create_time' => 'datetime', + 'news_create_user_guid' => 'string', + 'news_update_time' => 'datetime', + 'news_update_user_guid' => 'string', + 'news_delete_time' => 'datetime', + 'news_delete_user_guid' => 'string', - ]; + ]; // 设置json类型字段 protected $json = ['']; // 开启自动写入时间戳字段 @@ -52,18 +54,19 @@ class News extends BaseModel //排序字段 public $order_field = 'news_sort'; - // excel导入/下载模板表头 - public const EXCELFIELD = [ -'news_type' => '新闻类型', -'news_title' => '新闻标题', -'news_intro' => '新闻简介', -'news_source' => '文章来源', -'news_link' => '跳转链接', -'news_issue_date' => '发布日期', -'news_views_num' => '浏览次数', -'news_sort' => '新闻排序', -'news_content' => '新闻内容', -]; + // excel导入/下载模板表头 + public const EXCELFIELD = [ + 'news_type' => '新闻类型', + 'news_title' => '新闻标题', + 'news_cover' => '新闻封面', + 'news_intro' => '新闻简介', + 'news_source' => '文章来源', + 'news_link' => '跳转链接', + 'news_issue_date' => '发布日期', + 'news_views_num' => '浏览次数', + 'news_sort' => '新闻排序', + 'news_content' => '新闻内容', + ]; /** * 新增前 @@ -92,114 +95,138 @@ class News extends BaseModel $model->completeDeleteField(); } - - /** - * 导出Excel - * - * @param array $select 导出的数据 - */ - public static function exportExcel(array $select): void - { - $data = [[ -'新闻类型', -'新闻标题', -'新闻简介', -'文章来源', -'跳转链接', -'发布日期', -'浏览次数', -'新闻排序', -'新闻内容' -]]; - foreach ($select as $key => $val) { - $data[] = [ -$val['news_type'], -$val['news_title'], -$val['news_intro'], -$val['news_source'], -$val['news_link'], -$val['news_issue_date'], -$val['news_views_num'], -$val['news_sort'], -$val['news_content'], -]; - } - $excel = (new Excel())->exporTsheet($data); - $excel->save('新闻.xlsx'); + + /** + * 导出Excel + * + * @param array $select 导出的数据 + */ + public static function exportExcel(array $select): void + { + $data = [[ + '新闻类型', + '新闻标题', + '新闻封面', + '新闻简介', + '文章来源', + '跳转链接', + '发布日期', + '浏览次数', + '新闻排序', + // '新闻内容' + ]]; + foreach ($select as $key => $val) { + + // 获取新闻类型名称 + $news_type = ModelDictionary::getDictionaryData('news_type'); + $val['news_type'] = ModelDictionary::getDataDictionaryName($news_type, $val['news_type']); + + $data[] = [ + $val['news_type'], + $val['news_title'], + Excel::ExportImgFiled($val['news_cover']), + $val['news_intro'], + $val['news_source'], + $val['news_link'], + $val['news_issue_date'], + $val['news_views_num'], + $val['news_sort'], + // $val['news_content'], + ]; } + $excel = (new Excel())->exporTsheet($data); + $excel->save('新闻.xlsx'); + } - - /** - * 导入excel - * - * @param \app\common\arw\adjfut\src\UploadFile $file excel - */ - public static function importExcel(\app\common\arw\adjfut\src\UploadFile $file): string - { - $msg = []; - Db::startTrans(); - try { - $excel = new Excel($file); - $data = $excel->parseExcel( - Tool::getExcelRule(self::EXCELFIELD), - ['titleLine' => [1]]); - if (!$data) throwErrorMsg('excel无数据', 1); - $msg = []; - foreach ($data as $line => $value) { - try { - $model = self::importExcelInit($value); - $msg[] = "{$line} 新增成功!
"; - } catch (\Throwable $th) { - $msg[] = "{$line} {$th->getMessage()}
"; - } - } - Db::commit(); - return implode(', ', $msg); - } catch (\Throwable $th) { - Db::rollback(); - throw $th; - } - } + /** + * 导入excel + * + * @param \app\common\arw\adjfut\src\UploadFile $file excel + */ + public static function importExcel(\app\common\arw\adjfut\src\UploadFile $file): string + { + $msg = []; - - /** - * 导入excel初始化 - * - * @param array $value excel每行数据 - */ - public static function importExcelInit(array $value):void - { - $news_type = $value['news_type'];$news_title = $value['news_title'];$news_intro = $value['news_intro'];$news_source = $value['news_source'];$news_link = $value['news_link'];$news_issue_date = $value['news_issue_date'];$news_views_num = $value['news_views_num'];$news_sort = $value['news_sort'];$news_content = $value['news_content']; - - self::create( - ['news_type' => $news_type, -'news_title' => $news_title, -'news_intro' => $news_intro, -'news_source' => $news_source, -'news_link' => $news_link, -'news_issue_date' => $news_issue_date, -'news_views_num' => $news_views_num, -'news_sort' => $news_sort, -'news_content' => $news_content, -], - [ -'news_type', -'news_title', -'news_intro', -'news_source', -'news_link', -'news_issue_date', -'news_views_num', -'news_sort', -'news_content', -'news_guid', -'news_create_user_guid', -'news_update_user_guid' -] + Db::startTrans(); + try { + $excel = new Excel($file); + $data = $excel->parseExcel( + Tool::getExcelRule(self::EXCELFIELD), + ['titleLine' => [1]] ); + if (!$data) throwErrorMsg('excel无数据', 1); + $msg = []; + foreach ($data as $line => $value) { + try { + $model = self::importExcelInit($value); + $msg[] = "{$line} 新闻:【{$value['news_title']}】 新增成功!
"; + } catch (\Throwable $th) { + $msg[] = "{$line} {$th->getMessage()}
"; + } + } + Db::commit(); + return implode(', ', $msg); + } catch (\Throwable $th) { + Db::rollback(); + throw $th; } - + } + /** + * 导入excel初始化 + * + * @param array $value excel每行数据 + */ + public static function importExcelInit(array $value): void + { + $news_type = $value['news_type']; + $news_title = $value['news_title']; + $news_cover = $value['news_cover']; + $news_intro = $value['news_intro']; + $news_source = $value['news_source']; + $news_link = $value['news_link']; + $news_issue_date = $value['news_issue_date']; + $news_views_num = $value['news_views_num']; + $news_sort = $value['news_sort']; + $news_content = $value['news_content']; + + + // 根据新闻类型名称获取新闻类型的字段值 + $news_type_dic = ModelDictionary::getDictionaryData('news_type'); + $news_type_value = ModelDictionary::getDataDictionaryValue($news_type_dic, $news_type); + if (!$news_type_value) throwErrorMsg("新闻类型:【{$news_type}】 不存在,请重新确认!"); + + + self::create( + [ + 'news_type' => $news_type_value, + 'news_title' => $news_title, + 'news_cover' => $news_cover, + 'news_intro' => $news_intro, + 'news_source' => $news_source, + 'news_link' => $news_link, + 'news_issue_date' => $news_issue_date, + 'news_views_num' => $news_views_num, + 'news_sort' => $news_sort, + 'news_content' => $news_content, + ], + [ + 'news_type', + 'news_title', + 'news_cover', + 'news_intro', + 'news_source', + 'news_link', + 'news_issue_date', + 'news_views_num', + 'news_sort', + 'news_content', + 'news_guid', + 'news_create_user_guid', + 'news_update_user_guid' + ] + ); + } } diff --git a/app/common/model/Products/ProductType.php b/app/common/model/Products/ProductType.php index 191cb92..e6e738b 100644 --- a/app/common/model/Products/ProductType.php +++ b/app/common/model/Products/ProductType.php @@ -96,17 +96,18 @@ class ProductType extends BaseModel * @param string $product_type_name 产品类目名称 * @param string $product_type_guid 产品类目guid */ - public static function isDuplicateName(string $product_type_name, string $product_type_guid = null): void + public static function isDuplicateName(string $product_type_name, string $product_type_parent_guid = null): void { - $con = [ - ['product_type_name', '=', $product_type_name] - ]; - if ($product_type_guid) { - $con[] = ['product_type_guid', '<>', $product_type_guid]; + if ($product_type_parent_guid) { + $parent_children = self::where('product_type_parent_guid', $product_type_parent_guid)->select(); + if ($parent_children) { + foreach ($parent_children as $key => $value) { + if ($product_type_name == $value['product_type_name']) { + throwErrorMsg('产品类目不可重名!'); + } + } + } } - if (self::where($con)->find()) { - throwErrorMsg('产品类目不可重名!'); - }; } /** @@ -115,15 +116,28 @@ class ProductType extends BaseModel public static function exportExcel($select) { $data = [[ + '上级类目', + '产品类目名称', '产品类目标题', - '产品类目图标', - '产品类目封面' + '产品类目链接', + '排序', + '图标', ]]; + foreach ($select as $key => $val) { + // $product_type_name = ""; + // if($val['product_type_parent_guid'] != 0){ + // $product_type_parent = self::where('product_type_guid', $val['product_type_parent_guid'])->find(); + // $product_type_name = $product_type_parent['product_type_name']; + // } $data[] = [ + // $product_type_parent->product_type_name, + $val['product_type_parent_name'], + $val['product_type_name'], $val['product_type_title'], - $val['product_type_icon'], - Excel::ExportImgFiled($val['product_type_cover']), + $val['product_type_link'], + $val['product_type_order'], + Excel::ExportImgFiled($val['product_type_icon']), ]; } $excel = (new Excel())->exporTsheet($data); diff --git a/public/excel/news/新闻导入模板.xlsx b/public/excel/news/新闻导入模板.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..6d1dce20be5e0d11d8d5c3bb24addf49249c9f75 GIT binary patch literal 13054 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 literal 0 HcmV?d00001