DocsController.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. <?php
  2. namespace App\Http\Controllers\Api;
  3. use App\Http\Controllers\Controller;
  4. use App\Module\Base;
  5. use App\Module\Docs;
  6. use App\Module\Users;
  7. use App\Tasks\PushTask;
  8. use Cache;
  9. use DB;
  10. use Hhxsv5\LaravelS\Swoole\Task\Task;
  11. use Request;
  12. /**
  13. * @apiDefine docs
  14. *
  15. * 知识库
  16. */
  17. class DocsController extends Controller
  18. {
  19. public function __invoke($method, $action = '')
  20. {
  21. $app = $method ? $method : 'main';
  22. if ($action) {
  23. $app .= "__" . $action;
  24. }
  25. return (method_exists($this, $app)) ? $this->$app() : Base::ajaxError("404 not found (" . str_replace("__", "/", $app) . ").");
  26. }
  27. /**
  28. * 知识库列表
  29. *
  30. * @apiParam {Number} [page] 当前页,默认:1
  31. * @apiParam {Number} [pagesize] 每页显示数量,默认:20,最大:100
  32. */
  33. public function book__lists()
  34. {
  35. $user = Users::authE();
  36. if (Base::isError($user)) {
  37. return $user;
  38. } else {
  39. $user = $user['data'];
  40. }
  41. //
  42. $lists = DB::table('docs_book')
  43. ->where('username', $user['username'])
  44. ->orWhere(function ($query) use ($user) {
  45. $query->where('role_edit', 'private')->where('username', $user['username']);
  46. })
  47. ->orWhere(function ($query) use ($user) {
  48. $query->where('role_edit', 'member')->whereIn('id', function ($query2) use ($user) {
  49. $query2->select('bookid')
  50. ->from('docs_users')
  51. ->where('username', $user['username'])
  52. ->whereRaw(env('DB_PREFIX') . 'docs_book.id = bookid');
  53. });
  54. })
  55. ->orderByDesc('id')
  56. ->paginate(Min(Max(Base::nullShow(Request::input('pagesize'), 10), 1), 100));
  57. $lists = Base::getPageList($lists);
  58. if ($lists['total'] == 0) {
  59. return Base::retError('暂无知识库', $lists);
  60. }
  61. return Base::retSuccess('success', $lists);
  62. }
  63. /**
  64. * 添加/修改知识库
  65. *
  66. * @apiParam {Number} id 知识库数据ID
  67. * @apiParam {String} title 知识库名称
  68. */
  69. public function book__add()
  70. {
  71. $user = Users::authE();
  72. if (Base::isError($user)) {
  73. return $user;
  74. } else {
  75. $user = $user['data'];
  76. }
  77. //
  78. $id = intval(Request::input('id'));
  79. $title = trim(Request::input('title'));
  80. if ($id > 0) {
  81. $role = Docs::checkRole($id, 'edit');
  82. if (Base::isError($role)) {
  83. return $role;
  84. }
  85. }
  86. if (mb_strlen($title) < 2 || mb_strlen($title) > 100) {
  87. return Base::retError('标题限制2-100个字!');
  88. }
  89. if ($id > 0) {
  90. // 修改
  91. $row = Base::DBC2A(DB::table('docs_book')->where('id', $id)->first());
  92. if (empty($row)) {
  93. return Base::retError('知识库不存在或已被删除!');
  94. }
  95. $data = [
  96. 'title' => $title,
  97. ];
  98. DB::table('docs_book')->where('id', $id)->update($data);
  99. return Base::retSuccess('修改成功!', $data);
  100. } else {
  101. // 添加
  102. $data = [
  103. 'username' => $user['username'],
  104. 'title' => $title,
  105. 'indate' => Base::time(),
  106. ];
  107. $id = DB::table('docs_book')->insertGetId($data);
  108. if (empty($id)) {
  109. return Base::retError('系统繁忙,请稍后再试!');
  110. }
  111. $data['id'] = $id;
  112. return Base::retSuccess('添加成功!', $data);
  113. }
  114. }
  115. /**
  116. * 设置知识库
  117. *
  118. * @apiParam {Number} id 知识库数据ID
  119. * @apiParam {String} role_edit
  120. * @apiParam {String} role_view
  121. */
  122. public function book__setting()
  123. {
  124. $user = Users::authE();
  125. if (Base::isError($user)) {
  126. return $user;
  127. } else {
  128. $user = $user['data'];
  129. }
  130. //
  131. $id = intval(Request::input('id'));
  132. $role = Docs::checkRole($id, 'edit');
  133. if (Base::isError($role)) {
  134. return $role;
  135. }
  136. $row = Base::DBC2A(DB::table('docs_book')->where('id', $id)->first());
  137. if (empty($row)) {
  138. return Base::retError('知识库不存在或已被删除!');
  139. }
  140. $setting = Base::string2array($row['setting']);
  141. $type = trim(Request::input('type'));
  142. if ($type == 'save') {
  143. foreach (Request::input() AS $key => $value) {
  144. if (in_array($key, ['role_edit', 'role_view'])) {
  145. $setting[$key] = $value;
  146. }
  147. }
  148. DB::table('docs_book')->where('id', $id)->update([
  149. 'role_edit' => $setting['role_edit'],
  150. 'role_view' => $setting['role_view'],
  151. 'setting' => Base::array2string($setting),
  152. ]);
  153. }
  154. return Base::retSuccess($type == 'save' ? '修改成功!' : 'success', $setting ?: json_decode('{}'));
  155. }
  156. /**
  157. * 删除知识库
  158. *
  159. * @apiParam {Number} id 知识库数据ID
  160. */
  161. public function book__delete()
  162. {
  163. $user = Users::authE();
  164. if (Base::isError($user)) {
  165. return $user;
  166. } else {
  167. $user = $user['data'];
  168. }
  169. //
  170. $id = intval(Request::input('id'));
  171. $row = Base::DBC2A(DB::table('docs_book')->where('id', $id)->first());
  172. if (empty($row)) {
  173. return Base::retError('知识库不存在或已被删除!');
  174. }
  175. if ($row['username'] != $user['username']) {
  176. return Base::retError('此操作仅限知识库负责人!');
  177. }
  178. DB::table('docs_book')->where('id', $id)->delete();
  179. DB::table('docs_section')->where('bookid', $id)->delete();
  180. DB::table('docs_content')->where('bookid', $id)->delete();
  181. return Base::retSuccess('删除成功!');
  182. }
  183. /**
  184. * 成员-列表
  185. *
  186. * @apiParam {Number} id 知识库数据ID
  187. * @apiParam {Number} [page] 当前页,默认:1
  188. * @apiParam {Number} [pagesize] 每页显示数量,默认:20,最大:100
  189. */
  190. public function users__lists()
  191. {
  192. $user = Users::authE();
  193. if (Base::isError($user)) {
  194. return $user;
  195. } else {
  196. $user = $user['data'];
  197. }
  198. //
  199. $id = intval(Request::input('id'));
  200. $role = Docs::checkRole($id, 'edit');
  201. if (Base::isError($role)) {
  202. return $role;
  203. }
  204. $row = Base::DBC2A(DB::table('docs_book')->where('id', $id)->first());
  205. if (empty($row)) {
  206. return Base::retError('知识库不存在或已被删除!');
  207. }
  208. //
  209. $lists = DB::table('docs_book')
  210. ->join('docs_users', 'docs_book.id', '=', 'docs_users.bookid')
  211. ->select(['docs_book.title', 'docs_users.*'])
  212. ->where([
  213. ['docs_book.id', $id],
  214. ])
  215. ->orderByDesc('docs_users.id')->paginate(Min(Max(Base::nullShow(Request::input('pagesize'), 10), 1), 100));
  216. $lists = Base::getPageList($lists);
  217. if ($lists['total'] == 0) {
  218. return Base::retError('未找到任何相关的成员');
  219. }
  220. foreach ($lists['lists'] AS $key => $item) {
  221. $userInfo = Users::username2basic($item['username']);
  222. $lists['lists'][$key]['userimg'] = $userInfo['userimg'];
  223. $lists['lists'][$key]['nickname'] = $userInfo['nickname'];
  224. $lists['lists'][$key]['profession'] = $userInfo['profession'];
  225. }
  226. return Base::retSuccess('success', $lists);
  227. }
  228. /**
  229. * 成员-添加、删除
  230. *
  231. * @apiParam {String} act
  232. * - delete: 删除成员
  233. * - else: 添加成员
  234. * @apiParam {Number} id 知识库数据ID
  235. * @apiParam {Array|String} username 用户名(或用户名组)
  236. */
  237. public function users__join()
  238. {
  239. $user = Users::authE();
  240. if (Base::isError($user)) {
  241. return $user;
  242. } else {
  243. $user = $user['data'];
  244. }
  245. //
  246. $id = intval(Request::input('id'));
  247. $role = Docs::checkRole($id, 'edit');
  248. if (Base::isError($role)) {
  249. return $role;
  250. }
  251. $row = Base::DBC2A(DB::table('docs_book')->where('id', $id)->first());
  252. if (empty($row)) {
  253. return Base::retError('知识库不存在或已被删除!');
  254. }
  255. //
  256. $usernames = Request::input('username');
  257. if (empty($usernames)) {
  258. return Base::retError('参数错误!');
  259. }
  260. if (!is_array($usernames)) {
  261. if (Base::strExists($usernames, ',')) {
  262. $usernames = explode(',', $usernames);
  263. } else {
  264. $usernames = [$usernames];
  265. }
  266. }
  267. //
  268. foreach ($usernames AS $username) {
  269. $inRow = Base::DBC2A(DB::table('docs_users')->where(['bookid' => $id, 'username' => $username])->first());
  270. switch (Request::input('act')) {
  271. case 'delete': {
  272. if ($inRow) {
  273. DB::table('docs_users')->where([
  274. 'bookid' => $id,
  275. 'username' => $username
  276. ])->delete();
  277. }
  278. break;
  279. }
  280. default: {
  281. if (!$inRow && $username != $user['username']) {
  282. DB::table('docs_users')->insert([
  283. 'bookid' => $id,
  284. 'username' => $username,
  285. 'indate' => Base::time()
  286. ]);
  287. }
  288. break;
  289. }
  290. }
  291. }
  292. return Base::retSuccess('操作完成!');
  293. }
  294. /**
  295. * 章节列表
  296. *
  297. * @apiParam {String} act 请求方式,用于判断权限
  298. * - edit: 管理页请求
  299. * - view: 阅读页请求
  300. * @apiParam {Number} bookid 知识库数据ID
  301. */
  302. public function section__lists()
  303. {
  304. $bookid = intval(Request::input('bookid'));
  305. $role = Docs::checkRole($bookid, Request::input('act'));
  306. if (Base::isError($role)) {
  307. return $role;
  308. }
  309. $lists = Base::DBC2A(DB::table('docs_section')
  310. ->where('bookid', $bookid)
  311. ->orderByDesc('inorder')
  312. ->orderByDesc('id')
  313. ->take(500)
  314. ->get());
  315. if (empty($lists)) {
  316. return Base::retError('暂无章节');
  317. }
  318. foreach ($lists AS $key => $item) {
  319. $lists[$key]['icon'] = Base::fillUrl('images/files/' . $item['type'] . '.png');
  320. }
  321. $bookDetail = Base::DBC2A(DB::table('docs_book')->select(['title'])->where('id', $bookid)->first());
  322. return Base::retSuccess('success', [
  323. 'book' => $bookDetail ?: json_decode('{}'),
  324. 'tree' => Base::list2Tree($lists, 'id', 'parentid')
  325. ]);
  326. }
  327. /**
  328. * 添加/修改章节
  329. *
  330. * @apiParam {Number} bookid 知识库数据ID
  331. * @apiParam {String} title 章节名称
  332. * @apiParam {String} type 章节类型
  333. */
  334. public function section__add()
  335. {
  336. $user = Users::authE();
  337. if (Base::isError($user)) {
  338. return $user;
  339. } else {
  340. $user = $user['data'];
  341. }
  342. //
  343. $bookid = intval(Request::input('bookid'));
  344. $role = Docs::checkRole($bookid, 'edit');
  345. if (Base::isError($role)) {
  346. return $role;
  347. }
  348. $bookRow = Base::DBC2A(DB::table('docs_book')->where('id', $bookid)->first());
  349. if (empty($bookRow)) {
  350. return Base::retError('知识库不存在或已被删除!');
  351. }
  352. $count = DB::table('docs_section')->where('bookid', $bookid)->count();
  353. if ($count >= 500) {
  354. return Base::retError(['知识库章节已经超过最大限制(%)!', 500]);
  355. }
  356. //
  357. $id = intval(Request::input('id'));
  358. $title = trim(Request::input('title'));
  359. $type = trim(Request::input('type'));
  360. if (mb_strlen($title) < 2 || mb_strlen($title) > 100) {
  361. return Base::retError('标题限制2-100个字!');
  362. }
  363. if ($id > 0) {
  364. // 修改
  365. $row = Base::DBC2A(DB::table('docs_section')->where('id', $id)->first());
  366. if (empty($row)) {
  367. return Base::retError('知识库不存在或已被删除!');
  368. }
  369. $data = [
  370. 'title' => $title,
  371. ];
  372. DB::table('docs_section')->where('id', $id)->update($data);
  373. return Base::retSuccess('修改成功!', $data);
  374. } else {
  375. // 添加
  376. if (!in_array($type, ['document', 'mind', 'sheet', 'flow', 'folder'])) {
  377. return Base::retError('参数错误!');
  378. }
  379. $parentid = 0;
  380. if ($id < 0) {
  381. $count = Base::DBC2A(DB::table('docs_section')->where('id', abs($id))->where('bookid', $bookid)->count());
  382. if ($count > 0) {
  383. $parentid = abs($id);
  384. }
  385. }
  386. $data = [
  387. 'bookid' => $bookid,
  388. 'parentid' => $parentid,
  389. 'username' => $user['username'],
  390. 'title' => $title,
  391. 'type' => $type,
  392. 'inorder' => intval(DB::table('docs_section')->select(['inorder'])->where('bookid', $bookid)->orderByDesc('inorder')->value('inorder')) + 1,
  393. 'indate' => Base::time(),
  394. ];
  395. $id = DB::table('docs_section')->insertGetId($data);
  396. if (empty($id)) {
  397. return Base::retError('系统繁忙,请稍后再试!');
  398. }
  399. $data['id'] = $id;
  400. return Base::retSuccess('添加成功!', $data);
  401. }
  402. }
  403. /**
  404. * 排序章节
  405. *
  406. * @apiParam {Number} bookid 知识库数据ID
  407. * @apiParam {String} oldsort 旧排序数据
  408. * @apiParam {String} newsort 新排序数据
  409. */
  410. public function section__sort()
  411. {
  412. $user = Users::authE();
  413. if (Base::isError($user)) {
  414. return $user;
  415. } else {
  416. $user = $user['data'];
  417. }
  418. //
  419. $bookid = intval(Request::input('bookid'));
  420. $role = Docs::checkRole($bookid, 'edit');
  421. if (Base::isError($role)) {
  422. return $role;
  423. }
  424. $bookRow = Base::DBC2A(DB::table('docs_book')->where('id', $bookid)->first());
  425. if (empty($bookRow)) {
  426. return Base::retError('知识库不存在或已被删除!');
  427. }
  428. //
  429. $newSort = explode(";", Request::input('newsort'));
  430. if (count($newSort) == 0) {
  431. return Base::retError('参数错误!');
  432. }
  433. //
  434. $count = count($newSort);
  435. foreach ($newSort AS $sort => $item) {
  436. list($newId, $newParentid) = explode(':', $item);
  437. DB::table('docs_section')->where([
  438. 'id' => $newId,
  439. 'bookid' => $bookid
  440. ])->update([
  441. 'inorder' => $count - intval($sort),
  442. 'parentid' => $newParentid
  443. ]);
  444. }
  445. return Base::retSuccess('保存成功!');
  446. }
  447. /**
  448. * 删除章节
  449. *
  450. * @apiParam {Number} id 章节数据ID
  451. */
  452. public function section__delete()
  453. {
  454. $user = Users::authE();
  455. if (Base::isError($user)) {
  456. return $user;
  457. } else {
  458. $user = $user['data'];
  459. }
  460. //
  461. $id = intval(Request::input('id'));
  462. $row = Base::DBC2A(DB::table('docs_section')->where('id', $id)->first());
  463. if (empty($row)) {
  464. return Base::retError('文档不存在或已被删除!');
  465. }
  466. $role = Docs::checkRole($row['bookid'], 'edit');
  467. if (Base::isError($role)) {
  468. return $role;
  469. }
  470. DB::table('docs_section')->where('parentid', $id)->update([ 'parentid' => $row['parentid'] ]);
  471. DB::table('docs_section')->where('id', $id)->delete();
  472. DB::table('docs_content')->where('sid', $id)->delete();
  473. return Base::retSuccess('删除成功!');
  474. }
  475. /**
  476. * 获取章节内容
  477. *
  478. * @apiParam {String} act 请求方式,用于判断权限
  479. * - edit: 管理页请求
  480. * - view: 阅读页请求
  481. * @apiParam {Number|String} id 章节数据ID(或:章节数据ID-历史数据ID)
  482. */
  483. public function section__content()
  484. {
  485. $id = Request::input('id');
  486. $hid = 0;
  487. if (Base::strExists($id, '-')) {
  488. list($id, $hid) = explode("-", $id);
  489. }
  490. $id = intval($id);
  491. $hid = intval($hid);
  492. $row = Base::DBC2A(DB::table('docs_section')->where('id', $id)->first());
  493. if (empty($row)) {
  494. return Base::retError('文档不存在或已被删除!');
  495. }
  496. $role = Docs::checkRole($row['bookid'], Request::input('act'));
  497. if (Base::isError($role)) {
  498. return $role;
  499. }
  500. $whereArray = [];
  501. if ($hid > 0) {
  502. $whereArray[] = ['id', '=', $hid];
  503. }
  504. $whereArray[] = ['sid', '=', $id];
  505. $cRow = Base::DBC2A(DB::table('docs_content')->select(['id AS hid', 'content'])->where($whereArray)->orderByDesc('id')->first());
  506. if (empty($cRow)) {
  507. $cRow = [ 'hid' => 0, 'content' => '' ];
  508. }
  509. return Base::retSuccess('success', array_merge($row, $cRow));
  510. }
  511. /**
  512. * 获取章节历史内容
  513. *
  514. * @apiParam {Number} id 章节数据ID
  515. */
  516. public function section__history()
  517. {
  518. $user = Users::authE();
  519. if (Base::isError($user)) {
  520. return $user;
  521. } else {
  522. $user = $user['data'];
  523. }
  524. //
  525. $id = intval(Request::input('id'));
  526. $row = Base::DBC2A(DB::table('docs_section')->where('id', $id)->first());
  527. if (empty($row)) {
  528. return Base::retError('文档不存在或已被删除!');
  529. }
  530. $role = Docs::checkRole($row['bookid'], 'view');
  531. if (Base::isError($role)) {
  532. return $role;
  533. }
  534. //
  535. $lists = Base::DBC2A(DB::table('docs_content')
  536. ->where('sid', $id)
  537. ->orderByDesc('id')
  538. ->take(50)
  539. ->get());
  540. if (count($lists) <= 1) {
  541. return Base::retError('暂无历史数据');
  542. }
  543. return Base::retSuccess('success', $lists);
  544. }
  545. /**
  546. * 保存章节内容
  547. *
  548. * @apiParam {Number} id 章节数据ID
  549. * @apiParam {Object} [D] Request Payload 提交
  550. * - content: 内容
  551. */
  552. public function section__save()
  553. {
  554. $user = Users::authE();
  555. if (Base::isError($user)) {
  556. return $user;
  557. } else {
  558. $user = $user['data'];
  559. }
  560. //
  561. $id = intval(Request::input('id'));
  562. $row = Base::DBC2A(DB::table('docs_section')->where('id', $id)->first());
  563. if (empty($row)) {
  564. return Base::retError('文档不存在或已被删除!');
  565. }
  566. $role = Docs::checkRole($row['bookid'], 'edit');
  567. if (Base::isError($role)) {
  568. return $role;
  569. }
  570. if ($row['lockdate'] + 60 > Base::time() && $row['lockname'] != $user['username']) {
  571. return Base::retError(['已被会员【%】锁定!', Users::nickname($row['lockname'])]);
  572. }
  573. $D = Base::getContentsParse('D');
  574. if ($row['type'] == 'document') {
  575. $data = Base::json2array($D['content']);
  576. $isRep = false;
  577. preg_match_all("/<img\s*src=\"data:image\/(png|jpg|jpeg);base64,(.*?)\"/s", $data['content'], $matchs);
  578. foreach ($matchs[2] as $key => $text) {
  579. $p = "uploads/docs/document/" . $id . "/";
  580. Base::makeDir(public_path($p));
  581. $p.= md5($text) . "." . $matchs[1][$key];
  582. $r = file_put_contents(public_path($p), base64_decode($text));
  583. if ($r) {
  584. $data['content'] = str_replace($matchs[0][$key], '<img src="' . Base::fillUrl($p) . '"', $data['content']);
  585. $isRep = true;
  586. }
  587. }
  588. if ($isRep == true) {
  589. $D['content'] = Base::array2json($data);
  590. }
  591. }
  592. DB::table('docs_content')->insert([
  593. 'bookid' => $row['bookid'],
  594. 'sid' => $id,
  595. 'content' => $D['content'],
  596. 'username' => $user['username'],
  597. 'indate' => Base::time()
  598. ]);
  599. Docs::notice($id, [ 'type' => 'update' ]);
  600. //
  601. return Base::retSuccess('保存成功!');
  602. }
  603. /**
  604. * 保存章节内容
  605. *
  606. * @apiParam {String} act
  607. * - lock: 锁定
  608. * - unlock: 解锁
  609. * @apiParam {Number} id 章节数据ID
  610. */
  611. public function section__lock()
  612. {
  613. $user = Users::authE();
  614. if (Base::isError($user)) {
  615. return $user;
  616. } else {
  617. $user = $user['data'];
  618. }
  619. //
  620. $id = intval(Request::input('id'));
  621. $act = trim(Request::input('act'));
  622. $row = Base::DBC2A(DB::table('docs_section')->where('id', $id)->first());
  623. if (empty($row)) {
  624. return Base::retError('文档不存在或已被删除!');
  625. }
  626. $role = Docs::checkRole($row['bookid'], 'edit');
  627. if (Base::isError($role)) {
  628. return $role;
  629. }
  630. if ($row['lockdate'] + 60 > Base::time() && $row['lockname'] != $user['username']) {
  631. return Base::retError(['已被会员【%】锁定!', Users::nickname($row['lockname'])]);
  632. }
  633. if ($act == 'lock') {
  634. $upArray = [
  635. 'lockname' => $user['username'],
  636. 'lockdate' => Base::time(),
  637. ];
  638. } else {
  639. $upArray = [
  640. 'lockname' => '',
  641. 'lockdate' => 0,
  642. ];
  643. }
  644. DB::table('docs_section')->where('id', $id)->update($upArray);
  645. $upArray['type'] = $act;
  646. Docs::notice($id, $upArray);
  647. //
  648. return Base::retSuccess($act == 'lock' ? '锁定成功' : '已解除锁定', $upArray);
  649. }
  650. }