ArticleService.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
  4. // +----------------------------------------------------------------------
  5. // | 版权所有 2017~2021 LARAVEL研发中心
  6. // +----------------------------------------------------------------------
  7. // | 官方网站: http://www.laravel.cn
  8. // +----------------------------------------------------------------------
  9. // | Author: laravel开发员 <laravel.qq.com>
  10. // +----------------------------------------------------------------------
  11. namespace App\Services\Api;
  12. use App\Models\ArticleCateModel;
  13. use App\Models\ArticleModel;
  14. use App\Models\ExamAccessLogModel;
  15. use App\Services\BaseService;
  16. use App\Services\ConfigService;
  17. use App\Services\RedisService;
  18. use PhpOffice\PhpWord\IOFactory;
  19. /**
  20. * 文章-服务类
  21. * @author laravel开发员
  22. * @since 2020/11/11
  23. * @package App\Services\Api
  24. */
  25. class ArticleService extends BaseService
  26. {
  27. // 静态对象
  28. protected static $instance = null;
  29. /**
  30. * 构造函数
  31. * @author laravel开发员
  32. * @since 2020/11/11
  33. */
  34. public function __construct()
  35. {
  36. $this->model = new ArticleModel();
  37. }
  38. /**
  39. * 静态入口
  40. */
  41. public static function make()
  42. {
  43. if (!self::$instance) {
  44. self::$instance = new static();
  45. }
  46. return self::$instance;
  47. }
  48. /**
  49. * 信息
  50. * @param int $num
  51. * @return array|mixed
  52. */
  53. public function getInfoByType($type)
  54. {
  55. $cacheKey = "caches:article:info_{$type}";
  56. $datas = RedisService::get($cacheKey);
  57. if($datas){
  58. return $datas;
  59. }
  60. $datas = $this->model->where(['type'=>$type,'status'=>1,'mark'=>1])
  61. ->select(['id','title','type','content','status'])
  62. ->orderBy('create_time','desc')
  63. ->first();
  64. $datas = $datas? $datas->toArray() : [];
  65. if($datas){
  66. $datas['content'] = preg_replace("/\n+/",'<br/>',$datas['content']);
  67. $datas['content'] = get_format_content($datas['content']);
  68. RedisService::set($cacheKey, $datas, 86400);
  69. }
  70. return $datas;
  71. }
  72. /**
  73. * @param $params
  74. * @param int $pageSize
  75. * @return array
  76. */
  77. public function getDataList($params, $pageSize = 15)
  78. {
  79. $page = isset($params['page'])? $params['page'] : 1;
  80. $cacheKey = "caches:articles:list_{$page}_{$pageSize}:".md5(json_encode($params));
  81. $datas = RedisService::get($cacheKey);
  82. if($datas){
  83. return $datas;
  84. }
  85. $query = $this->getQuery($params);
  86. $list = $query->select(['a.id','a.type','a.title','a.cover','a.view_num','a.show_type','a.create_time','a.description','a.status'])
  87. ->orderBy('a.create_time','desc')
  88. ->paginate($pageSize > 0 ? $pageSize : 9999999);
  89. $list = $list? $list->toArray() :[];
  90. if($list){
  91. foreach($list['data'] as &$item){
  92. $item['create_time'] = $item['create_time']? datetime($item['create_time'],'Y-m-d') : '';
  93. $item['cover'] = $item['cover']? get_image_url($item['cover']) : '';
  94. }
  95. }
  96. $rows = isset($list['data'])? $list['data'] : [];
  97. $datas = [
  98. 'pageSize'=> $pageSize,
  99. 'total'=> isset($list['total'])? $list['total'] : 0,
  100. 'list'=> $rows
  101. ];
  102. if($rows){
  103. RedisService::set($cacheKey, $datas, rand(3600, 7200));
  104. }
  105. return $datas;
  106. }
  107. /**
  108. * 查询
  109. * @param $params
  110. * @return mixed
  111. */
  112. public function getQuery($params)
  113. {
  114. $where = ['a.mark' => 1];
  115. $status = isset($params['status'])? $params['status'] : 0;
  116. $type = isset($params['type'])? $params['type'] : 0;
  117. $answerType = isset($params['answer_type'])? $params['answer_type'] : 0;
  118. $cateId = isset($params['cate_id'])? $params['cate_id'] : 0;
  119. if($status>0){
  120. $where['a.status'] = $status;
  121. }
  122. if($type>0){
  123. $where['a.type'] = $type;
  124. }
  125. if($answerType>0){
  126. $where['a.answer_type'] = $answerType;
  127. }
  128. if($cateId>=0){
  129. $where['a.cate_id'] = $cateId;
  130. }
  131. return $this->model->from('article as a')
  132. ->where($where)
  133. ->where(function ($query) use($params){
  134. $keyword = isset($params['keyword'])? $params['keyword'] : '';
  135. if($keyword){
  136. $query->where('a.title','like',"%{$keyword}%");
  137. }
  138. });
  139. }
  140. /**
  141. * 热门问答(都在问列表)
  142. * @param $userId
  143. * @param $answerType 问答类型:1-职高,3-专升本
  144. * @param false $refresh
  145. * @return array|mixed
  146. */
  147. public function getHotList($userId,$answerType=1,$refresh=false)
  148. {
  149. $cacheKey = "caches:articles:hotList_{$userId}_{$answerType}";
  150. $datas = RedisService::get($cacheKey);
  151. if($datas && !$refresh){
  152. return $datas;
  153. }
  154. $model = $this->model->where(['type'=>9,'answer_type'=>$answerType,'status'=>1,'mark'=>1]);
  155. $model1 = clone $model;
  156. if($model1->where('view_num','>', 0)->count('id')>5){
  157. $model = $model1;
  158. }
  159. $num = ConfigService::make()->getConfigByCode('custom_hot_num', 3);
  160. $num = $num>=2 && $num<= 20? $num : 3;
  161. $datas = $model->select(['id','cover','type','answer_type','title','description','status'])
  162. ->orderByRaw('RAND()')
  163. ->take($num)
  164. ->get();
  165. $datas = $datas? $datas->toArray() : [];
  166. if($datas){
  167. RedisService::set($cacheKey, $datas, rand(300, 600));
  168. }
  169. return $datas;
  170. }
  171. /**
  172. * 推荐问答
  173. * @param $answerType
  174. * @param false $refresh
  175. * @return array|mixed
  176. */
  177. public function getRecommendList($answerType=1,$refresh=false)
  178. {
  179. $cacheKey = "caches:articles:recList_{$answerType}";
  180. $datas = RedisService::get($cacheKey);
  181. if($datas && !$refresh){
  182. return $datas;
  183. }
  184. $num = ConfigService::make()->getConfigByCode('custom_rec_num', 3);
  185. $num = $num>=2 && $num<= 20? $num : 3;
  186. $datas = $this->model->where(['type'=>9,'answer_type'=>$answerType,'status'=>1,'mark'=>1])
  187. ->select(['id','cover','title','answer_type','type','description','status'])
  188. ->orderBy('view_num','desc')
  189. ->take($num)
  190. ->get();
  191. $datas = $datas? $datas->toArray() : [];
  192. if($datas){
  193. RedisService::set($cacheKey, $datas, rand(300, 600));
  194. }
  195. return $datas;
  196. }
  197. /**
  198. * 获取文章详情
  199. * @param $id
  200. * @return array|mixed
  201. */
  202. public function getInfo($id)
  203. {
  204. $cacheKey = "caches:articles:info_{$id}";
  205. $info = RedisService::get($cacheKey);
  206. if($info){
  207. return $info;
  208. }
  209. $info = $this->model->where(['id'=> $id,'status'=>1,'mark'=>1])
  210. ->select(['id','title','type','answer_type','cover','show_type','file_url','view_num','author','description','create_time','type','content'])
  211. ->first();
  212. $info = $info? $info->toArray() : [];
  213. if($info){
  214. $info['create_time'] = $info['create_time']? datetime($info['create_time'],'Y-m-d') : '';
  215. $info['cover'] = get_image_url($info['cover']);
  216. $info['file_url'] = get_image_url($info['file_url']);
  217. if($info['show_type']==2){
  218. if($content = $this->convertDocxToHtml($info['file_url'])){
  219. $info['file_content'] = $content;
  220. }else{
  221. $info['file_content'] = $this->error;
  222. }
  223. }
  224. $info['content'] = get_format_content($info['content']);
  225. $this->model->where(['id'=> $id])->increment('view_num',1);
  226. $info['view_num'] += intval($info['view_num']);
  227. RedisService::set($cacheKey, $info, rand(5,10));
  228. }
  229. return $info;
  230. }
  231. /**
  232. * @param $inputFile
  233. * @return false|string
  234. * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
  235. */
  236. public function convertDocxToHtml($inputFile)
  237. {
  238. $filePath = get_image_path($inputFile);
  239. $outputFile = str_replace('.docx', '.html', $filePath);
  240. $outputFile = str_replace('.doc', '.html', $outputFile);
  241. $filePath = ATTACHMENT_PATH.get_image_path($filePath);
  242. // 检查文件是否存在
  243. if (!file_exists($filePath)) {
  244. $this->error = '解析文档不存在,请确认已成功上传';
  245. return false;
  246. }
  247. if (file_exists(ATTACHMENT_PATH.$outputFile)) {
  248. return file_get_contents(ATTACHMENT_PATH.$outputFile);
  249. }
  250. try {
  251. // 加载文档
  252. $phpWord = IOFactory::load($filePath);
  253. //保存为HTML
  254. $htmlWriter = IOFactory::createWriter($phpWord, 'HTML');
  255. $htmlWriter->save(ATTACHMENT_PATH.$outputFile);
  256. if (file_exists(ATTACHMENT_PATH.$outputFile)) {
  257. return file_get_contents(ATTACHMENT_PATH.$outputFile);
  258. } else {
  259. $this->error = '解析文档失败';
  260. return false;
  261. }
  262. }catch (\Exception $exception){
  263. $this->error = '解析文档失败:'.$exception->getMessage();
  264. return false;
  265. }
  266. }
  267. /**
  268. * 查找或查看
  269. * @param $params
  270. * @return array|false|mixed
  271. */
  272. public function search($params)
  273. {
  274. $cacheKey = "caches:articles:search_".md5(json_encode($params));
  275. $data = RedisService::get($cacheKey);
  276. if($data){
  277. return $data;
  278. }
  279. $id = isset($params['id'])? $params['id'] : 0;
  280. $answerType = isset($params['answer_type']) && $params['answer_type']? $params['answer_type'] : 1;
  281. $keyword = isset($params['keyword'])? $params['keyword'] : '';
  282. if(empty($keyword) && $id<=0){
  283. $this->error = '请选择或输入问题';
  284. return false;
  285. }
  286. $where = ['id'=>0,'type'=>9,'answer_type'=>$answerType,'status'=>1,'mark'=>1];
  287. if($id){
  288. $where['id'] = $id;
  289. }else{
  290. unset($where['id']);
  291. }
  292. $data = $this->model->where($where)
  293. ->where(function($query) use($keyword){
  294. if($keyword){
  295. $query->where('title', 'like',"%{$keyword}%")->orWhere('content', 'like',"%{$keyword}%");
  296. }
  297. })
  298. ->select(['id','title','type','answer_type','description','content','status'])
  299. ->orderByRaw('RAND()')
  300. ->orderBy('sort','desc')
  301. ->first();
  302. $data = $data? $data->toArray() :[];
  303. if($data){
  304. RedisService::set($cacheKey, $data, rand(3,5));
  305. }
  306. return $data;
  307. }
  308. /**
  309. * 获取分类文章推荐
  310. * @param int $cateId 推荐分类ID
  311. * @param int $type 类别:3-普通文章,4-客服回复
  312. * @return array|mixed
  313. */
  314. public function getCustomRecommend($cateId=0, $type=4)
  315. {
  316. $cacheKey = "caches:articles:list_{$cateId}";
  317. $datas = RedisService::get($cacheKey);
  318. if($datas){
  319. return $datas;
  320. }
  321. $limitNum = ConfigService::make()->getConfigByCode('custom_recommend_num', 6);
  322. $limitNum = $limitNum? $limitNum : 6;
  323. $datas = ArticleCateModel::where(function($query) use($cateId){
  324. if($cateId){
  325. $query->where('cate_id', $cateId);
  326. }
  327. })->where(['type'=>$type,'status'=>1,'mark'=>1])
  328. ->select(['id','cate_id','title','description','sort','type','status'])
  329. ->limit($limitNum)
  330. ->orderBy('sort','desc')
  331. ->orderBy('create_time','desc')
  332. ->get();
  333. $datas = $datas? $datas->toArray() : [];
  334. if($datas){
  335. RedisService::set($cacheKey, $datas, rand(300,600));
  336. }
  337. return $datas;
  338. }
  339. /**
  340. * 获取文章推荐分类
  341. * @param int $type 1-普通文章分类
  342. * @return array|mixed
  343. */
  344. public function getIndexList($type=1)
  345. {
  346. $cacheKey = "caches:articles:list_{$type}";
  347. $datas = RedisService::get($cacheKey);
  348. if($datas){
  349. return $datas;
  350. }
  351. $limitNum = ConfigService::make()->getConfigByCode('index_article_num', 6);
  352. $limitNum = $limitNum? $limitNum : 6;
  353. $datas = $this->model::where(['type'=> $type,'status'=>1,'mark'=>1])
  354. ->orderBy('sort','desc')
  355. ->orderBy('id','desc')
  356. ->limit($limitNum)
  357. ->get();
  358. $datas = $datas? $datas->toArray() : [];
  359. if($datas){
  360. RedisService::set($cacheKey, $datas, rand(300,600));
  361. }
  362. return $datas;
  363. }
  364. /**
  365. * 获取文章推荐分类
  366. * @param int $type 2-对口资料分类,3-专升本资料分类
  367. * @return array|mixed
  368. */
  369. public function getCateList($type=2, $sc=0)
  370. {
  371. $cacheKey = "caches:articles:cateList_{$type}";
  372. $datas = RedisService::get($cacheKey);
  373. // 复习资料访问统计
  374. if (empty($sc)) {
  375. ExamAccessLogModel::saveLog(date('Y-m-d'), $type, 5);
  376. }
  377. if($datas){
  378. return $datas;
  379. }
  380. $datas = ArticleCateModel::where(['type'=> $type,'status'=>1,'mark'=>1])
  381. ->select(['id','icon','name','pid','description','type','sort','status'])
  382. ->orderBy('sort','desc')
  383. ->orderBy('id','asc')
  384. ->get();
  385. $datas = $datas? $datas->toArray() : [];
  386. //var_dump($datas);
  387. $list = [];
  388. if($datas){
  389. foreach ($datas as $item){
  390. $pid = isset($item['pid'])? $item['pid'] : 0;
  391. $id = isset($item['id'])? $item['id'] : 0;
  392. if($pid>0){
  393. $list[$pid] = isset($list[$pid])? $list[$pid] : [];
  394. $list[$pid]['children'][] = $item;
  395. }else {
  396. $item['children'] = isset($list[$id]['children'])? $list[$id]['children'] : [];
  397. $list[$id] = $item;
  398. }
  399. }
  400. RedisService::set($cacheKey, $list, rand(300,600));
  401. }
  402. return $list;
  403. }
  404. }