Archives.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. <?php
  2. namespace app\index\controller\cms;
  3. use addons\cms\library\FulltextSearch;
  4. use addons\cms\library\Service;
  5. use addons\cms\model\Channel;
  6. use addons\cms\model\Modelx;
  7. use addons\cms\model\Tag;
  8. use app\common\controller\Frontend;
  9. use app\common\model\User;
  10. use fast\Tree;
  11. use think\Db;
  12. use think\Exception;
  13. use think\Validate;
  14. /**
  15. * 会员文档
  16. */
  17. class Archives extends Frontend
  18. {
  19. protected $layout = 'default';
  20. protected $noNeedLogin = [];
  21. protected $noNeedRight = ['*'];
  22. /**
  23. * 发表文章
  24. */
  25. public function post()
  26. {
  27. $config = get_addon_config('cms');
  28. $id = $this->request->get('id');
  29. $archives = $id ? \app\admin\model\cms\Archives::get($id) : null;
  30. if ($archives) {
  31. $channel = Channel::get($archives['channel_id']);
  32. if (!$channel) {
  33. $this->error(__('未找到指定栏目'));
  34. }
  35. $model = \addons\cms\model\Modelx::get($channel['model_id']);
  36. if (!$model) {
  37. $this->error(__('未找到指定模型'));
  38. }
  39. if ($archives['user_id'] != $this->auth->id) {
  40. $this->error("无法进行越权操作!");
  41. }
  42. } else {
  43. $model = null;
  44. $model_id = $this->request->request('model_id');
  45. // 如果有model_id则调用指定模型
  46. if ($model_id) {
  47. $model = Modelx::get($model_id);
  48. }
  49. }
  50. // 如果来源于提交
  51. if ($this->request->isPost()) {
  52. $this->token();
  53. if ($this->auth->score < $config['limitscore']['postarchives']) {
  54. $this->error("积分必须大于{$config['limitscore']['postarchives']}才可以发布文章");
  55. }
  56. $row = $this->request->post('row/a', '', 'trim,xss_clean');
  57. $rule = [
  58. 'title|标题' => 'require|length:3,100',
  59. 'channel_id|栏目' => 'require|integer',
  60. ];
  61. $msg = [
  62. 'title.require' => '标题不能为空',
  63. 'title.length' => '标题长度限制在3~100个字符',
  64. 'channel_id' => '栏目不能为空',
  65. 'content.require' => '内容不能为空',
  66. ];
  67. $validate = new Validate($rule, $msg);
  68. $result = $validate->check($row);
  69. if (!$result) {
  70. $this->error($validate->getError());
  71. }
  72. $channelIds = isset($row['channel_ids']) ? (is_array($row['channel_ids']) ? $row['channel_ids'] : explode(',', $row['channel_ids'])) : [];
  73. $channelIds = array_merge([$row['channel_id']], $channelIds);
  74. $channelIds = array_filter($channelIds);
  75. $count = Channel::where('id', 'in', $channelIds)->where('iscontribute', 0)->count();
  76. if ($count > 0) {
  77. $this->error("栏目不允许投稿");
  78. }
  79. //审核状态
  80. $status = 'normal';
  81. if ($config['isarchivesaudit'] == 1) {
  82. $status = 'hidden';
  83. } elseif ($config['isarchivesaudit'] == 0) {
  84. $status = 'normal';
  85. } else {
  86. $textArr = array_map(function ($item) {
  87. return is_array($item) ? json_encode($item, JSON_UNESCAPED_UNICODE) : $item;
  88. }, $row);
  89. if (!Service::isContentLegal(implode(' ', $textArr))) {
  90. $status = 'hidden';
  91. }
  92. }
  93. $row['user_id'] = $this->auth->id;
  94. $row['status'] = $status;
  95. $row['publishtime'] = time();
  96. Db::startTrans();
  97. try {
  98. if ($archives) {
  99. $archives->allowField(true)->save($row);
  100. } else {
  101. (new \app\admin\model\cms\Archives)->allowField(true)->save($row);
  102. }
  103. //增加积分
  104. $status == 'normal' && User::score($config['score']['postarchives'], $this->auth->id, '发布文章');
  105. Db::commit();
  106. } catch (Exception $e) {
  107. Db::rollback();
  108. $this->error("发生错误:" . $e->getMessage());
  109. }
  110. if ($status === 'hidden') {
  111. //发送通知
  112. $status === 'hidden' && Service::notice('CMS收到一篇新的文章审核', $config['auditnotice'], $config['noticetemplateid']);
  113. $this->success("发布成功!请等待审核!");
  114. } else {
  115. $this->success("发布成功!");
  116. }
  117. }
  118. $channel = new Channel();
  119. // 合并主副表
  120. if ($archives) {
  121. $addon = db($model['table'])->where('id', $archives['id'])->find();
  122. if ($addon) {
  123. $archives->setData($addon);
  124. }
  125. }
  126. // 读取可发布的栏目列表
  127. $disabledIds = [];
  128. $channelList = collection(
  129. $channel->where('status', 'normal')
  130. ->where("iscontribute", 1)
  131. ->order("weigh desc,id desc")
  132. ->cache(true)
  133. ->select()
  134. )->toArray();
  135. $channelParents = [];
  136. foreach ($channelList as $index => $item) {
  137. if ($item['parent_id']) {
  138. $channelParents[] = $item['parent_id'];
  139. }
  140. }
  141. foreach ($channelList as $k => $v) {
  142. if ($v['type'] == 'link' || ($model && $model['id'] != $v['model_id'])) {
  143. $disabledIds[] = $v['id'];
  144. }
  145. //if ($v['type'] == 'channel' && !in_array($v['id'], $channelParents)) {
  146. // unset($channelList[$k]);
  147. //}
  148. }
  149. $tree = Tree::instance()->init($channelList, 'parent_id');
  150. $channelOptions = $tree->getTree(0, "<option model='@model_id' value=@id @selected @disabled>@spacer@name</option>", $archives ? $archives['channel_id'] : '', $disabledIds);
  151. $this->view->assign('channelOptions', $channelOptions);
  152. $this->view->assign([
  153. 'archives' => $archives,
  154. 'channelOptions' => $channelOptions,
  155. 'categoryList' => ''
  156. ]);
  157. $this->assignconfig('archives_id', $archives ? $archives['id'] : 0);
  158. //读取副栏目
  159. $disabledIds = [];
  160. $all = collection(Channel::order("weigh desc,id desc")->select())->toArray();
  161. foreach ($all as $k => $v) {
  162. if ($v['type'] == 'link' || ($archives && $v['model_id'] != $archives->model_id)) {
  163. $disabledIds[] = $v['id'];
  164. }
  165. }
  166. $tree = Tree::instance()->init($all, 'parent_id');
  167. $secondChannelOptions = $tree->getTree(0, "<option model='@model_id' value=@id @selected @disabled>@spacer@name</option>", explode(',', $archives ? $archives['channel_ids'] : ''), $disabledIds);
  168. $this->view->assign('secondChannelOptions', $secondChannelOptions);
  169. $modelName = $model ? $model['name'] : '文章';
  170. $this->view->assign('title', $archives ? "修改{$modelName}" : "发布{$modelName}");
  171. $this->view->assign('model', $model);
  172. return $this->view->fetch();
  173. }
  174. /**
  175. * 我的发布
  176. */
  177. public function my()
  178. {
  179. $archives = new \addons\cms\model\Archives;
  180. $model = null;
  181. $model_id = (int)$this->request->request('model_id');
  182. $channel_id = (int)$this->request->request('channel_id');
  183. $q = $this->request->request('q');
  184. $config = ['query' => []];
  185. // 指定模型
  186. if ($model_id) {
  187. $model = Modelx::get($model_id);
  188. if ($model) {
  189. $archives->where('model_id', $model_id);
  190. $config['query']['model_id'] = $model_id;
  191. }
  192. }
  193. // 搜索关键字
  194. if ($q) {
  195. $archives->where('title|keywords|description', 'like', '%' . $q . '%');
  196. $config['query']['q'] = $q;
  197. }
  198. // 栏目
  199. if ($channel_id) {
  200. $archives->where('channel_id', $channel_id);
  201. $config['query']['channel_id'] = $channel_id;
  202. }
  203. $user_id = $this->auth->id;
  204. $archivesList = $archives->where('user_id', $user_id)
  205. ->order('id', 'desc')
  206. ->paginate(10, null, $config);
  207. $channelList = Channel::where('id', 'in', function ($query) use ($user_id) {
  208. $query->name('cms_archives')->where('user_id', $user_id)->field('channel_id');
  209. })->where('status', 'normal')->select();
  210. $this->view->assign('archivesList', $archivesList);
  211. $this->view->assign('channelList', $channelList);
  212. $this->view->assign('title', '我发布的' . ($model ? $model['name'] : '文档'));
  213. $this->view->assign('model', $model);
  214. return $this->view->fetch();
  215. }
  216. /**
  217. * 删除文档
  218. */
  219. public function delete()
  220. {
  221. $id = (int)$this->request->request('id/d');
  222. if (!$id) {
  223. $this->error("参数不正确");
  224. }
  225. $archives = \addons\cms\model\Archives::where('id', $id)->where('user_id', $this->auth->id)->find();
  226. if (!$archives) {
  227. $this->error("未找到指定的文档");
  228. }
  229. Db::startTrans();
  230. try {
  231. $archives->delete();
  232. if ($archives->channel->items > 0) {
  233. $archives->channel->setDec("items");
  234. }
  235. Db::commit();
  236. } catch (Exception $e) {
  237. Db::rollback();
  238. $this->error("删除文档失败");
  239. }
  240. $this->success("删除文档成功");
  241. }
  242. /**
  243. * 获取栏目列表
  244. * @internal
  245. */
  246. public function get_channel_fields()
  247. {
  248. $this->view->engine->layout(false);
  249. $channel_id = $this->request->post('channel_id');
  250. $archives_id = $this->request->post('archives_id');
  251. $channel = Channel::get($channel_id, 'model');
  252. if ($channel && $channel['type'] != 'link') {
  253. $model_id = $channel['model_id'];
  254. $values = [];
  255. if ($archives_id) {
  256. $values = db($channel['model']['table'])->where('id', $archives_id)->find();
  257. //优先从栏目获取模型ID,再从文档获取
  258. $archives = \app\admin\model\cms\Archives::get($archives_id);
  259. $model_id = $archives ? $archives['model_id'] : $model_id;
  260. }
  261. $fields = Service::getCustomFields('model', $model_id, $values, ['iscontribute' => 1]);
  262. $this->view->assign('fields', $fields);
  263. $this->view->assign('values', $values);
  264. $setting = $channel->getRelation('model')->setting ?? [];
  265. $this->success('', null, ['contributefields' => $setting && isset($setting['contributefields']) ? $setting['contributefields'] : [], 'html' => $this->view->fetch('cms/common/fields')]);
  266. } else {
  267. $this->error(__('请选择栏目'));
  268. }
  269. $this->error(__('参数不能为空', 'ids'));
  270. }
  271. /**
  272. * 标签自动完成
  273. * @internal
  274. */
  275. public function tags_autocomplete()
  276. {
  277. $q = $this->request->request('q');
  278. $list = \addons\cms\model\Tag::where('name', 'like', '%' . $q . '%')->limit(10)->column('name');
  279. echo json_encode($list);
  280. return;
  281. }
  282. /**
  283. * 搜索建议
  284. * @internal
  285. */
  286. public function suggestion()
  287. {
  288. $q = trim($this->request->request("q"));
  289. $id = trim($this->request->request("id/d"));
  290. $list = [];
  291. $result = \addons\cms\model\Archives::where("title|keywords|description", "like", "%{$q}%")->where('id', '<>', $id)->limit(10)->order("id", "desc")->select();
  292. foreach ($result as $index => $item) {
  293. $list[] = ['id' => $item['id'], 'url' => $item['fullurl'], 'image' => cdnurl($item['image']), 'title' => $item['title'], 'create_date' => datetime($item['createtime'])];
  294. }
  295. return json($list);
  296. }
  297. }