Art.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. <?php
  2. namespace app\api\controller;
  3. use think\Db;
  4. use think\Request;
  5. class Art extends Base
  6. {
  7. use PublicApi;
  8. public function __construct()
  9. {
  10. parent::__construct();
  11. $this->check_config();
  12. }
  13. public function index()
  14. {
  15. }
  16. /**
  17. * 获取列表
  18. *
  19. * @param Request $request
  20. * @return \think\response\Json
  21. */
  22. public function get_list(Request $request)
  23. {
  24. // 参数校验
  25. $param = $request->param();
  26. $validate = validate($request->controller());
  27. if (!$validate->scene($request->action())->check($param)) {
  28. return json([
  29. 'code' => 1001,
  30. 'msg' => '参数错误: ' . $validate->getError(),
  31. ]);
  32. }
  33. // 查询条件组装
  34. $where = [];
  35. $offset = isset($param['offset']) ? (int)$param['offset'] : 0;
  36. $limit = isset($param['limit']) ? (int)$param['limit'] : 20;
  37. if (isset($param['type_id']) && (int)$param['type_id'] > 0) {
  38. $where['type_id|type_id_1'] = ['eq', (int)$param['type_id']];
  39. }
  40. if (isset($param['time_end']) && isset($param['time_start'])) {
  41. $where['art_time'] = ['between', [(int)$param['time_start'], (int)$param['time_end']]];
  42. }elseif (isset($param['time_end'])) {
  43. $where['art_time'] = ['<=', (int)$param['time_end']];
  44. }elseif (isset($param['time_start'])) {
  45. $where['art_time'] = ['>=', (int)$param['time_start']];
  46. }
  47. if (isset($param['letter'])) {
  48. $where['art_letter'] = $param['letter'];
  49. }
  50. if (isset($param['status'])) {
  51. $where['art_status'] = (int)$param['status'];
  52. }
  53. if (isset($param['name']) && strlen($param['name']) > 0) {
  54. $where['art_name'] = ['like', '%' . $this->format_sql_string($param['name']) . '%'];
  55. }
  56. if (isset($param['sub']) && strlen($param['sub']) > 0) {
  57. $where['art_sub'] = ['like', '%' . $this->format_sql_string($param['sub']) . '%'];
  58. }
  59. if (isset($param['blurb']) && strlen($param['blurb']) > 0) {
  60. $where['art_blurb'] = ['like', '%' . $this->format_sql_string($param['blurb']) . '%'];
  61. }
  62. if (isset($param['title']) && strlen($param['title']) > 0) {
  63. $where['art_title'] = ['like', '%' . $this->format_sql_string($param['title']) . '%'];
  64. }
  65. if (isset($param['content']) && strlen($param['content']) > 0) {
  66. $where['art_content'] = ['like', '%' . $this->format_sql_string($param['content']) . '%'];
  67. }
  68. if (isset($param['class']) && strlen($param['class']) > 0) {
  69. $where['art_class'] = ['like', '%' . $this->format_sql_string($param['class']) . '%'];
  70. }
  71. if (isset($param['tag']) && strlen($param['tag']) > 0) {
  72. $where['art_tag'] = ['like', '%' . $this->format_sql_string($param['tag']) . '%'];
  73. }
  74. if (isset($param['level']) && strlen($param['level']) > 0) {
  75. $where['art_level'] = ['in', $this->format_sql_string($param['level'])];
  76. }
  77. // 数据获取
  78. $total = model('Art')->getCountByCond($where);
  79. $list = [];
  80. if ($total > 0) {
  81. // 排序
  82. $order = "art_time DESC";
  83. $field = 'art_id,art_name,art_sub,art_en,art_pic,art_blurb,art_time,art_time_add,art_hits,art_points,art_points_detail,art_remarks,art_author,type_id';
  84. if (strlen($param['orderby']) > 0) {
  85. $order = 'art_' . $param['orderby'] . " DESC";
  86. }
  87. $list = model('Art')->getListByCond($offset, $limit, $where, $order, $field, []);
  88. $type_list = model('Type')->getCache('type_list');
  89. foreach ($list as &$v) {
  90. if (!empty($v['type_id']) && isset($type_list[$v['type_id']])) {
  91. $v['type'] = $type_list[$v['type_id']];
  92. $pid = isset($v['type']['type_pid']) ? (int) $v['type']['type_pid'] : 0;
  93. $v['type_1'] = ($pid > 0 && isset($type_list[$pid])) ? $type_list[$pid] : ['type_id' => 0, 'type_en' => ''];
  94. }
  95. $v['art_link'] = mac_url_art_detail($v);
  96. if (!empty($v['art_pic'])) {
  97. $v['art_pic'] = mac_url_img($v['art_pic']);
  98. }
  99. if (isset($v['art_time']) && is_numeric($v['art_time'])) {
  100. $v['art_time'] = date('Y-m-d H:i:s', (int)$v['art_time']);
  101. }
  102. $v['art_read_points'] = mac_content_read_points_amount('art', $v);
  103. }
  104. unset($v);
  105. mac_append_type_is_vip_exclusive_for_rows($list);
  106. }
  107. // 返回
  108. return json([
  109. 'code' => 1,
  110. 'msg' => '获取成功',
  111. 'info' => [
  112. 'offset' => $offset,
  113. 'limit' => $limit,
  114. 'total' => $total,
  115. 'rows' => $list,
  116. ],
  117. ]);
  118. }
  119. /**
  120. * 视频文章详情
  121. *
  122. * @param Request $request
  123. * @return \think\response\Json
  124. * @throws \think\db\exception\DataNotFoundException
  125. * @throws \think\db\exception\ModelNotFoundException
  126. * @throws \think\exception\DbException
  127. */
  128. public function get_detail(Request $request)
  129. {
  130. $param = $request->param();
  131. $validate = validate($request->controller());
  132. if (!$validate->scene($request->action())->check($param)) {
  133. return json([
  134. 'code' => 1001,
  135. 'msg' => '参数错误: ' . $validate->getError(),
  136. ]);
  137. }
  138. $aid = (int)$param['art_id'];
  139. $data = model('Art')->infoData(['art_id' => ['eq', $aid]], '*', 0);
  140. if ($data['code'] != 1 || empty($data['info'])) {
  141. return json(['code' => 1001, 'msg' => $data['msg'] ?? '数据不存在']);
  142. }
  143. $info = $data['info'];
  144. $info['art_pic'] = mac_url_img($info['art_pic'] ?? '');
  145. $info['art_pic_thumb'] = mac_url_img($info['art_pic_thumb'] ?? '');
  146. $info['art_pic_slide'] = mac_url_img($info['art_pic_slide'] ?? '');
  147. $info['art_link'] = mac_url_art_detail($info);
  148. if (!empty($info['art_page_list']) && is_array($info['art_page_list'])) {
  149. $slim = [];
  150. foreach ($info['art_page_list'] as $page => $row) {
  151. if (!is_array($row)) {
  152. continue;
  153. }
  154. $p = isset($row['page']) ? (int)$row['page'] : (int)$page;
  155. $slim[$p] = [
  156. 'page' => $p,
  157. 'title' => $row['title'] ?? '',
  158. 'note' => $row['note'] ?? '',
  159. ];
  160. }
  161. $info['art_page_list'] = $slim;
  162. $info['art_page_total'] = count($slim);
  163. } else {
  164. $info['art_page_list'] = [];
  165. $info['art_page_total'] = 0;
  166. }
  167. unset($info['art_content']);
  168. $tid = (int)($info['type_id'] ?? 0);
  169. $info['art_prev'] = null;
  170. $info['art_next'] = null;
  171. if ($tid > 0 && $aid > 0) {
  172. $prev = Db::table('mac_art')->where(['art_status' => 1, 'type_id' => $tid])->where('art_id', '<', $aid)
  173. ->order('art_id', 'desc')->field('art_id,art_name,art_en')->find();
  174. $next = Db::table('mac_art')->where(['art_status' => 1, 'type_id' => $tid])->where('art_id', '>', $aid)
  175. ->order('art_id', 'asc')->field('art_id,art_name,art_en')->find();
  176. if (!empty($prev)) {
  177. $prev['art_link'] = mac_url_art_detail($prev);
  178. $info['art_prev'] = $prev;
  179. }
  180. if (!empty($next)) {
  181. $next['art_link'] = mac_url_art_detail($next);
  182. $info['art_next'] = $next;
  183. }
  184. }
  185. $uid = (int) ($GLOBALS['user']['user_id'] ?? 0);
  186. $aid = (int) ($info['art_id'] ?? 0);
  187. $fav = mac_user_fav_state($uid, 2, $aid);
  188. $info['is_fav'] = $fav['is_fav'];
  189. $info['fav_ulog_id'] = $fav['fav_ulog_id'];
  190. $info['user_has_up'] = mac_user_has_digg(2, $aid);
  191. return json([
  192. 'code' => 1,
  193. 'msg' => '获取成功',
  194. 'info' => $info,
  195. ]);
  196. }
  197. /**
  198. * 单页正文(供 uni-app / SPA 原生渲染小说阅读页)
  199. * GET api.php/art/get_read_page 参数:art_id,page 可选默认 1
  200. */
  201. public function get_read_page(Request $request)
  202. {
  203. $param = $request->param();
  204. $validate = validate($request->controller());
  205. if (!$validate->scene('get_read_page')->check($param)) {
  206. return json([
  207. 'code' => 1001,
  208. 'msg' => '参数错误: ' . $validate->getError(),
  209. ]);
  210. }
  211. $artId = (int) $param['art_id'];
  212. $page = isset($param['page']) ? (int) $param['page'] : 1;
  213. if ($page < 1) {
  214. $page = 1;
  215. }
  216. $data = model('Art')->infoData(['art_id' => ['eq', $artId]], '*', 0);
  217. if ($data['code'] != 1 || empty($data['info'])) {
  218. return json(['code' => 1002, 'msg' => $data['msg'] ?? '数据不存在']);
  219. }
  220. $info = $data['info'];
  221. if ((int) ($info['art_status'] ?? 0) != 1) {
  222. return json(['code' => 1002, 'msg' => '数据不存在']);
  223. }
  224. $popParam = ['id' => $artId, 'page' => $page];
  225. $popedom = $this->check_user_popedom($info['type_id'], 3, $popParam, 'art_read', $info);
  226. $pageList = $info['art_page_list'] ?? [];
  227. $pageTotal = count($pageList);
  228. if ($pageTotal < 1) {
  229. return json(['code' => 1002, 'msg' => '暂无正文']);
  230. }
  231. if ($page > $pageTotal) {
  232. $page = $pageTotal;
  233. }
  234. $cur = $pageList[$page] ?? $pageList[(string) $page] ?? null;
  235. if (empty($cur) || !is_array($cur)) {
  236. return json(['code' => 1002, 'msg' => '该页不存在']);
  237. }
  238. $html = '';
  239. if ($popedom['code'] == 1 && !empty($cur['content'])) {
  240. $html = mac_url_content_img($cur['content']);
  241. }
  242. $canRead = ($popedom['code'] == 1) ? 1 : 0;
  243. $out = [
  244. 'can_read' => $canRead,
  245. 'deny_code' => (int) ($popedom['code'] ?? 0),
  246. 'deny_msg' => $canRead ? '' : (string) ($popedom['msg'] ?? ''),
  247. 'points_hint' => isset($popedom['points']) ? (int) $popedom['points'] : 0,
  248. 'art_id' => $artId,
  249. 'art_name' => (string) ($info['art_name'] ?? ''),
  250. 'page' => $page,
  251. 'page_total' => $pageTotal,
  252. 'title' => (string) ($cur['title'] ?? ''),
  253. 'note' => (string) ($cur['note'] ?? ''),
  254. 'content_html' => $html,
  255. 'has_prev' => $page > 1,
  256. 'has_next' => $page < $pageTotal,
  257. ];
  258. return json(['code' => 1, 'msg' => 'ok', 'info' => $out]);
  259. }
  260. /**
  261. * 获取热门文章/小说
  262. * 对应首页热门小说区块
  263. *
  264. * @param Request $request
  265. * @return \think\response\Json
  266. *
  267. * 参数说明:
  268. * num - 可选,数量,默认6
  269. * type_id - 可选,分类ID
  270. * start - 可选,偏移量,默认0
  271. * by - 可选,排序字段,默认 time,可选: hits,hits_day,hits_week,hits_month,time
  272. */
  273. /**
  274. * 文章顶/踩
  275. */
  276. public function digg(Request $request)
  277. {
  278. $param = $request->param();
  279. $id = intval($param['id'] ?? 0);
  280. if ($id < 1) return json(['code' => 1001, 'msg' => '参数错误']);
  281. $where = ['art_id' => $id];
  282. $model = model('Art');
  283. $type = trim($param['type'] ?? '');
  284. if ($type) {
  285. $cookie = 'art-digg-' . $id;
  286. if (!empty(cookie($cookie))) return json(['code' => 1002, 'msg' => lang('index/haved')]);
  287. if ($type == 'up') { $model->where($where)->setInc('art_up'); cookie($cookie, 't', 30); }
  288. elseif ($type == 'down') { $model->where($where)->setInc('art_down'); cookie($cookie, 't', 30); }
  289. }
  290. $res = $model->infoData($where, 'art_up,art_down');
  291. if ($res['code'] > 1) return json($res);
  292. return json(['code' => 1, 'msg' => 'ok', 'data' => ['up' => $res['info']['art_up'] ?? 0, 'down' => $res['info']['art_down'] ?? 0]]);
  293. }
  294. /**
  295. * 更新/获取文章点击数
  296. */
  297. public function update_hits(Request $request)
  298. {
  299. $param = $request->param();
  300. $id = intval($param['id'] ?? 0);
  301. if ($id < 1) return json(['code' => 1001, 'msg' => '参数错误']);
  302. $where = ['art_id' => $id];
  303. $field = 'art_hits,art_hits_day,art_hits_week,art_hits_month,art_time_hits';
  304. $res = model('Art')->infoData($where, $field);
  305. if ($res['code'] > 1) return json($res);
  306. $info = $res['info'];
  307. if (($param['type'] ?? '') == 'update') {
  308. $update = ['art_hits'=>$info['art_hits'],'art_hits_day'=>$info['art_hits_day'],'art_hits_week'=>$info['art_hits_week'],'art_hits_month'=>$info['art_hits_month']];
  309. $new = getdate(); $old = getdate($info['art_time_hits']);
  310. $update['art_hits_month'] = ($new['year']==$old['year'] && $new['mon']==$old['mon']) ? $update['art_hits_month']+1 : 1;
  311. $ws = mktime(0,0,0,$new["mon"],$new["mday"],$new["year"]) - ($new["wday"]*86400);
  312. $we = mktime(23,59,59,$new["mon"],$new["mday"],$new["year"]) + ((6-$new["wday"])*86400);
  313. $update['art_hits_week'] = ($info['art_time_hits']>=$ws && $info['art_time_hits']<=$we) ? $update['art_hits_week']+1 : 1;
  314. $update['art_hits_day'] = ($new['year']==$old['year'] && $new['mon']==$old['mon'] && $new['mday']==$old['mday']) ? $update['art_hits_day']+1 : 1;
  315. $update['art_hits']++; $update['art_time_hits'] = time();
  316. model('Art')->where($where)->update($update);
  317. return json(['code'=>1,'msg'=>'ok','data'=>['hits'=>$update['art_hits'],'hits_day'=>$update['art_hits_day'],'hits_week'=>$update['art_hits_week'],'hits_month'=>$update['art_hits_month']]]);
  318. }
  319. return json(['code'=>1,'msg'=>'ok','data'=>['hits'=>$info['art_hits'],'hits_day'=>$info['art_hits_day'],'hits_week'=>$info['art_hits_week'],'hits_month'=>$info['art_hits_month']]]);
  320. }
  321. /**
  322. * 文章评分
  323. */
  324. public function update_score(Request $request)
  325. {
  326. $param = $request->param();
  327. $id = intval($param['id'] ?? 0);
  328. if ($id < 1) return json(['code' => 1001, 'msg' => '参数错误']);
  329. $where = ['art_id' => $id];
  330. $res = model('Art')->infoData($where, 'art_score,art_score_num,art_score_all');
  331. if ($res['code'] > 1) return json($res);
  332. $info = $res['info'];
  333. $score = intval($param['score'] ?? 0);
  334. if ($score > 0) {
  335. $cookie = 'art-score-' . $id;
  336. if (!empty(cookie($cookie))) return json(['code' => 1002, 'msg' => lang('index/haved')]);
  337. $num = intval($info['art_score_num']) + 1;
  338. $all = intval($info['art_score_all']) + $score;
  339. $avg = number_format($all / $num, 1, '.', '');
  340. model('Art')->where($where)->update(['art_score_num'=>$num,'art_score_all'=>$all,'art_score'=>$avg]);
  341. cookie($cookie, 't', 30);
  342. return json(['code'=>1,'msg'=>lang('score_ok'),'data'=>['score'=>$avg,'score_num'=>$num,'score_all'=>$all]]);
  343. }
  344. return json(['code'=>1,'msg'=>'ok','data'=>['score'=>$info['art_score']??0,'score_num'=>$info['art_score_num']??0,'score_all'=>$info['art_score_all']??0]]);
  345. }
  346. public function get_hot(Request $request)
  347. {
  348. $param = $request->param();
  349. $num = isset($param['num']) ? (int)$param['num'] : 6;
  350. $start = isset($param['start']) ? (int)$param['start'] : 0;
  351. $typeId = isset($param['type_id']) ? (int)$param['type_id'] : 0;
  352. $by = isset($param['by']) ? trim($param['by']) : 'time';
  353. $allowBy = ['hits', 'hits_day', 'hits_week', 'hits_month', 'time'];
  354. if (!in_array($by, $allowBy)) {
  355. $by = 'time';
  356. }
  357. $where = [];
  358. $where['art_status'] = ['eq', 1];
  359. if ($typeId > 0) {
  360. $where['type_id|type_id_1'] = ['eq', $typeId];
  361. }
  362. $list = Db::table('mac_art')
  363. ->field('art_id,art_name,art_sub,art_pic,art_author,art_blurb,art_time,art_hits,art_hits_month,art_points,art_remarks,type_id')
  364. ->where($where)
  365. ->order('art_' . $by . ' desc')
  366. ->limit($start, $num)
  367. ->select();
  368. foreach ($list as &$v) {
  369. $v['art_pic'] = mac_url_img($v['art_pic']);
  370. $v['art_time_text'] = date('m-d', $v['art_time']);
  371. $v['art_link'] = mac_url_art_detail($v);
  372. }
  373. unset($v);
  374. return json([
  375. 'code' => 1,
  376. 'msg' => '获取成功',
  377. 'info' => [
  378. 'total' => count($list),
  379. 'rows' => $list,
  380. ],
  381. ]);
  382. }
  383. /**
  384. * 获取最新文章/资讯
  385. * 对应首页最新小说 + 最新影视资讯区块
  386. *
  387. * @param Request $request
  388. * @return \think\response\Json
  389. *
  390. * 参数说明:
  391. * num - 可选,数量,默认24
  392. * type_id - 可选,分类ID
  393. */
  394. public function get_latest(Request $request)
  395. {
  396. $param = $request->param();
  397. $num = isset($param['num']) ? (int)$param['num'] : 24;
  398. $typeId = isset($param['type_id']) ? (int)$param['type_id'] : 0;
  399. $start = isset($param['start']) ? max(0, (int)$param['start']) : 0;
  400. $where = [];
  401. $where['art_status'] = ['eq', 1];
  402. if ($typeId > 0) {
  403. $where['type_id|type_id_1'] = ['eq', $typeId];
  404. }
  405. $list = Db::table('mac_art')
  406. ->field('art_id,art_name,art_sub,art_pic,art_author,art_blurb,art_remarks,art_points,art_hits,art_time,type_id')
  407. ->where($where)
  408. ->order('art_time desc')
  409. ->limit($start, $num)
  410. ->select();
  411. foreach ($list as &$v) {
  412. $v['art_pic'] = mac_url_img($v['art_pic']);
  413. $v['art_time_text'] = date('m-d', $v['art_time']);
  414. $v['art_link'] = mac_url_art_detail($v);
  415. }
  416. unset($v);
  417. mac_append_type_is_vip_exclusive_for_rows($list);
  418. return json([
  419. 'code' => 1,
  420. 'msg' => '获取成功',
  421. 'info' => [
  422. 'total' => count($list),
  423. 'rows' => $list,
  424. ],
  425. ]);
  426. }
  427. }