CorpusController.php 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. <?php
  2. namespace App\Http\Controllers;
  3. use App\Models\Sentence;
  4. use App\Models\Channel;
  5. use App\Models\PaliText;
  6. use App\Models\WbwTemplate;
  7. use App\Models\WbwBlock;
  8. use App\Models\Wbw;
  9. use App\Models\Discussion;
  10. use App\Models\PaliSentence;
  11. use App\Models\SentSimIndex;
  12. use Illuminate\Support\Str;
  13. use Illuminate\Http\Request;
  14. use Illuminate\Support\Facades\Cache;
  15. use App\Http\Api\MdRender;
  16. use App\Http\Api\SuggestionApi;
  17. use App\Http\Api\ChannelApi;
  18. use App\Http\Api\UserApi;
  19. use App\Http\Api\StudioApi;
  20. use Illuminate\Support\Facades\Log;
  21. use Illuminate\Support\Arr;
  22. use App\Http\Resources\TocResource;
  23. class CorpusController extends Controller
  24. {
  25. protected $result = [
  26. "uid"=> '',
  27. "title"=> '',
  28. "path"=>[],
  29. "sub_title"=> '',
  30. "summary"=> '',
  31. "content"=> '',
  32. "content_type"=> "html",
  33. "toc" => [],
  34. "status"=>30,
  35. "lang"=> "",
  36. "created_at"=> "",
  37. "updated_at"=> "",
  38. ];
  39. protected $wbwChannels = [];
  40. //句子需要查询的列
  41. protected $selectCol = [
  42. 'uid',
  43. 'book_id',
  44. 'paragraph',
  45. 'word_start',
  46. "word_end",
  47. 'channel_uid',
  48. 'content',
  49. 'editor_uid',
  50. 'acceptor_uid',
  51. 'pr_edit_at',
  52. 'updated_at'
  53. ];
  54. public function __construct()
  55. {
  56. }
  57. /**
  58. * Display a listing of the resource.
  59. *
  60. * @return \Illuminate\Http\Response
  61. */
  62. public function index(Request $request)
  63. {
  64. //
  65. switch ($request->get('view')) {
  66. case 'para':
  67. return $this->showPara($request);
  68. break;
  69. default:
  70. # code...
  71. break;
  72. }
  73. }
  74. /**
  75. * Store a newly created resource in storage.
  76. *
  77. * @param \Illuminate\Http\Request $request
  78. * @return \Illuminate\Http\Response
  79. */
  80. public function store(Request $request)
  81. {
  82. //
  83. }
  84. /**
  85. * Display the specified resource.
  86. *
  87. * @param \App\Models\Sentence $sentence
  88. * @return \Illuminate\Http\Response
  89. */
  90. public function show(Sentence $sentence)
  91. {
  92. //
  93. }
  94. public function getSentTpl($id,$channels,$mode='edit',$onlyProps=false){
  95. $sent = [];
  96. $sentId = \explode('-',$id);
  97. if(count($sentId) !== 4){
  98. return false;
  99. }
  100. if($mode==='read'){
  101. $channelId = ChannelApi::getSysChannel('_System_Pali_VRI_');
  102. }else{
  103. $channelId = ChannelApi::getSysChannel('_System_Wbw_VRI_');
  104. }
  105. if($channelId !== false){
  106. array_push($channels,$channelId);
  107. }
  108. $record = Sentence::select($this->selectCol)
  109. ->where('book_id',$sentId[0])
  110. ->where('paragraph',$sentId[1])
  111. ->where('word_start',(int)$sentId[2])
  112. ->where('word_end',(int)$sentId[3])
  113. ->whereIn('channel_uid',$channels)
  114. ->get();
  115. $channelIndex = $this->getChannelIndex($channels);
  116. //获取wbw channel
  117. //目前默认的 wbw channel 是第一个translation channel
  118. foreach ($channels as $channel) {
  119. # code...
  120. if($channelIndex[$channel]->type==='translation'){
  121. $this->wbwChannels[] = $channel;
  122. break;
  123. }
  124. }
  125. return $this->makeContent($record,$mode,$channelIndex,[],$onlyProps);
  126. }
  127. /**
  128. * Display the specified resource.
  129. *
  130. * @param string $id
  131. * @return \Illuminate\Http\Response
  132. */
  133. public function showSent($id)
  134. {
  135. //
  136. $param = \explode('_',$id);
  137. if(count($param)>1){
  138. $channels = array_slice($param,1);
  139. }else{
  140. $channels = [];
  141. }
  142. $this->result['content'] = getSentTpl($param[0],$channels);
  143. return $this->ok($this->result);
  144. }
  145. public function showSentences($type,$id,$mode='read'){
  146. $param = \explode('_',$id);
  147. $sentId = \explode('-',$param[0]);
  148. $channels = [];
  149. #获取channel类型
  150. $sentChannel = Sentence::select('channel_uid')
  151. ->where('book_id',$sentId[0])
  152. ->where('paragraph',$sentId[1])
  153. ->where('word_start',$sentId[2])
  154. ->where('word_end',$sentId[3])
  155. ->get();
  156. foreach ($sentChannel as $key => $value) {
  157. # code...
  158. $channels[] = $value->channel_uid;
  159. }
  160. $channelInfo = Channel::whereIn("uid",$channels)->select(['uid','type','name'])->get();
  161. $indexChannel = [];
  162. $channels = [];
  163. foreach ($channelInfo as $key => $value) {
  164. # code...
  165. if($value->type === $type){
  166. $indexChannel[$value->uid] = $value;
  167. $channels[] = $value->uid;
  168. }
  169. }
  170. //获取句子数据
  171. $record = Sentence::select($this->selectCol)
  172. ->where('book_id',$sentId[0])
  173. ->where('paragraph',$sentId[1])
  174. ->where('word_start',$sentId[2])
  175. ->where('word_end',$sentId[3])
  176. ->whereIn('channel_uid',$channels)
  177. ->orderBy('paragraph')
  178. ->orderBy('word_start')
  179. ->get();
  180. if(count($record) ===0){
  181. return $this->error("no data");
  182. }
  183. $this->result['content'] = $this->makeContent($record,$mode,$indexChannel);
  184. return $this->ok($this->result);
  185. }
  186. /**
  187. * Store a newly created resource in storage.
  188. * @param \Illuminate\Http\Request $request
  189. * @param string $id
  190. * @param string $mode
  191. * @return \Illuminate\Http\Response
  192. */
  193. public function showPara(Request $request)
  194. {
  195. //
  196. $channels = [];
  197. if($request->get('mode') === 'edit'){
  198. //翻译模式加载json格式原文
  199. $channels[] = ChannelApi::getSysChannel('_System_Wbw_VRI_');
  200. }else{
  201. //阅读模式加载html格式原文
  202. $channels[] = ChannelApi::getSysChannel('_System_Pali_VRI_');
  203. }
  204. if($request->has('channel')){
  205. $channels = array_merge($channels,explode(",",$request->get('channel')) );
  206. }
  207. $para = explode(",",$request->get('par'));
  208. //段落所在章节
  209. $parent = PaliText::where('book',$request->get('book'))
  210. ->where('paragraph',$para[0])->first();
  211. $chapter = PaliText::where('book',$request->get('book'))
  212. ->where('paragraph',$parent->parent)->first();
  213. if($chapter){
  214. if(empty($chapter->toc)){
  215. $this->result['title'] = "unknown";
  216. }else{
  217. $this->result['title'] = $chapter->toc;
  218. $this->result['sub_title'] = $chapter->toc;
  219. $this->result['path'] = json_decode($chapter->path);
  220. }
  221. }
  222. $paraFrom = $para[0];
  223. $paraTo = end($para);
  224. $indexedHeading = [];
  225. #获取channel索引表
  226. $tranChannels = [];
  227. $channelInfo = Channel::whereIn("uid",$channels)->select(['uid','type','name'])->get();
  228. foreach ($channelInfo as $key => $value) {
  229. # code...
  230. if($value->type==="translation" ){
  231. $tranChannels[] = $value->uid;
  232. }
  233. }
  234. $indexChannel = [];
  235. $indexChannel = $this->getChannelIndex($channels);
  236. //获取wbw channel
  237. //目前默认的 wbw channel 是第一个translation channel
  238. foreach ($channels as $key => $value) {
  239. # code...
  240. if($indexChannel[$value]->type==='translation'){
  241. $this->wbwChannels[] = $value;
  242. break;
  243. }
  244. }
  245. //章节译文标题
  246. $title = Sentence::select($this->selectCol)
  247. ->where('book_id',$parent->book)
  248. ->where('paragraph',$parent->paragraph)
  249. ->whereIn('channel_uid',$tranChannels)
  250. ->first();
  251. if($title){
  252. $this->result['title'] = MdRender::render($title->content,$title->channel_uid);
  253. }
  254. /**
  255. * 获取句子数据
  256. */
  257. $record = Sentence::select($this->selectCol)
  258. ->where('book_id',$request->get('book'))
  259. ->whereIn('paragraph',$para)
  260. ->whereIn('channel_uid',$channels)
  261. ->orderBy('paragraph')
  262. ->orderBy('word_start')
  263. ->get();
  264. if(count($record) ===0){
  265. $this->result['content'] = "<span>No Data</span>";
  266. }else{
  267. $this->result['content'] = $this->makeContent($record,$request->get('mode','read'),$indexChannel,$indexedHeading);
  268. }
  269. return $this->ok($this->result);
  270. }
  271. /**
  272. * Store a newly created resource in storage.
  273. * @param \Illuminate\Http\Request $request
  274. * @param string $id
  275. * @return \Illuminate\Http\Response
  276. */
  277. public function showChapter(Request $request, string $id)
  278. {
  279. //
  280. $sentId = \explode('-',$id);
  281. $channels = [];
  282. if($request->has('channels')){
  283. $channels = explode('_',$request->get('channels'));
  284. }
  285. $mode = $request->get('mode','read');
  286. if($mode === 'read'){
  287. //阅读模式加载html格式原文
  288. $channelId = ChannelApi::getSysChannel('_System_Pali_VRI_');
  289. }else{
  290. //翻译模式加载json格式原文
  291. $channelId = ChannelApi::getSysChannel('_System_Wbw_VRI_');
  292. }
  293. if($channelId !== false){
  294. $channels[] = $channelId;
  295. }
  296. $chapter = PaliText::where('book',$sentId[0])->where('paragraph',$sentId[1])->first();
  297. if(!$chapter){
  298. return $this->error("no data");
  299. }
  300. if(empty($chapter->toc)){
  301. $this->result['title'] = "unknown";
  302. }else{
  303. $this->result['title'] = $chapter->toc;
  304. $this->result['sub_title'] = $chapter->toc;
  305. $this->result['path'] = json_decode($chapter->path);
  306. }
  307. $paraFrom = $sentId[1];
  308. $paraTo = $sentId[1]+$chapter->chapter_len-1;
  309. //获取标题
  310. $heading = PaliText::select(["book","paragraph","level"])
  311. ->where('book',$sentId[0])
  312. ->whereBetween('paragraph',[$paraFrom,$paraTo])
  313. ->where('level','<',8)
  314. ->get();
  315. //将标题段落转成索引数组 以便输出标题层级
  316. $indexedHeading = [];
  317. foreach ($heading as $key => $value) {
  318. # code...
  319. $indexedHeading["{$value->book}-{$value->paragraph}"] = $value->level;
  320. }
  321. #获取channel索引表
  322. $tranChannels = [];
  323. $channelInfo = Channel::whereIn("uid",$channels)->select(['uid','type','name'])->get();
  324. foreach ($channelInfo as $key => $value) {
  325. # code...
  326. if($value->type==="translation" ){
  327. $tranChannels[] = $value->uid;
  328. }
  329. }
  330. $indexChannel = [];
  331. $indexChannel = $this->getChannelIndex($channels);
  332. //获取wbw channel
  333. //目前默认的 wbw channel 是第一个translation channel
  334. foreach ($channels as $key => $value) {
  335. # code...
  336. if($indexChannel[$value]->type==='translation'){
  337. $this->wbwChannels[] = $value;
  338. break;
  339. }
  340. }
  341. $title = Sentence::select($this->selectCol)
  342. ->where('book_id',$sentId[0])
  343. ->where('paragraph',$sentId[1])
  344. ->whereIn('channel_uid',$tranChannels)
  345. ->first();
  346. if($title){
  347. $this->result['title'] = MdRender::render($title->content,$title->channel_uid);
  348. }
  349. /**
  350. * 获取句子数据
  351. * 算法:
  352. * 1. 如果标题和下一级第一个标题之间有段落。只输出这些段落和子目录
  353. * 2. 如果标题和下一级第一个标题之间没有间隔 且 chapter 长度大于10000个字符 且有子目录,只输出子目录
  354. * 3. 如果二者都不是,lazy load
  355. */
  356. //1. 计算 标题和下一级第一个标题之间 是否有间隔
  357. $nextChapter = PaliText::where('book',$sentId[0])
  358. ->where('paragraph',">",$sentId[1])
  359. ->where('level','<',8)
  360. ->orderBy('paragraph')
  361. ->value('paragraph');
  362. $between = $nextChapter - $sentId[1];
  363. //输出子目录
  364. $chapterLen = $chapter->chapter_len;
  365. $toc = PaliText::where('book',$sentId[0])
  366. ->whereBetween('paragraph',[$paraFrom+1,$paraFrom+$chapterLen-1])
  367. ->where('level','<',8)
  368. ->orderBy('paragraph')
  369. ->select(['book','paragraph','level','toc'])
  370. ->get();
  371. if($between > 1){
  372. //有间隔
  373. $paraTo = $nextChapter - 1;
  374. }else{
  375. if($chapter->chapter_strlen>5000){
  376. if(count($toc)>0){
  377. //有子目录只输出标题和目录
  378. $paraTo = $paraFrom;
  379. }else{
  380. //没有子目录 全部输出
  381. }
  382. }else{
  383. //章节小。全部输出 不输出章节
  384. $toc = [];
  385. }
  386. }
  387. $record = Sentence::select($this->selectCol)
  388. ->where('book_id',$sentId[0])
  389. ->whereBetween('paragraph',[$paraFrom,$paraTo])
  390. ->whereIn('channel_uid',$channels)
  391. ->orderBy('paragraph')
  392. ->orderBy('word_start')
  393. ->get();
  394. if(count($record) ===0){
  395. return $this->error("no data");
  396. }
  397. $this->result['content'] = $this->makeContent($record,$mode,$indexChannel,$indexedHeading);
  398. $this->result['toc'] = TocResource::collection($toc);
  399. Log::info("show chapter");
  400. return $this->ok($this->result);
  401. }
  402. private function getChannelIndex($channels,$type=null){
  403. #获取channel索引表
  404. $channelInfo = Channel::whereIn("uid",$channels)->select(['uid','type','name','owner_uid'])->get();
  405. $indexChannel = [];
  406. foreach ($channelInfo as $key => $value) {
  407. # code...
  408. if($type !== null && $value->type !== $type){
  409. continue;
  410. }
  411. $indexChannel[$value->uid] = $value;
  412. }
  413. foreach ($indexChannel as $uid => $value) {
  414. # 查询studio
  415. $indexChannel[$uid]['studio'] = StudioApi::getById($value->owner_uid);
  416. }
  417. return $indexChannel;
  418. }
  419. /**
  420. * 根据句子库数据生成文章内容
  421. * $record 句子数据
  422. * $mode read | edit | wbw
  423. * $indexChannel channel索引
  424. * $indexedHeading 标题索引 用于给段落加标题标签 <h1> ect.
  425. */
  426. private function makeContent($record,$mode,$indexChannel,$indexedHeading=[],$onlyProps=false){
  427. $content = [];
  428. $lastSent = "0-0";
  429. $sentCount = 0;
  430. $sent = [];
  431. $sent["origin"] = [];
  432. $sent["translation"] = [];
  433. //获取句子编号列表
  434. $sentList = [];
  435. foreach ($record as $key => $value) {
  436. $currSentId = "{$value->book_id}-{$value->paragraph}-{$value->word_start}-{$value->word_end}";
  437. $sentList[$currSentId]=[$value->book_id ,$value->paragraph,$value->word_start,$value->word_end];
  438. $value['sid'] = "{$currSentId}_{$value->channel_uid}";
  439. }
  440. //遍历列表查找每个句子的所有channel的数据,并填充
  441. foreach ($sentList as $currSentId => $arrSentId) {
  442. # code...
  443. $sent = $this->newSent($arrSentId[0],$arrSentId[1],$arrSentId[2],$arrSentId[3]);
  444. foreach ($indexChannel as $channelId => $info) {
  445. # code...
  446. $sid = "{$currSentId}_{$channelId}";
  447. $newSent = [
  448. "content"=>"",
  449. "html"=> "",
  450. "book"=> $arrSentId[0],
  451. "para"=> $arrSentId[1],
  452. "wordStart"=> $arrSentId[2],
  453. "wordEnd"=> $arrSentId[3],
  454. "channel"=> [
  455. "name"=>$info->name,
  456. "type"=>$info->type,
  457. "id"=> $info->uid,
  458. ],
  459. "studio" => $info['studio'],
  460. "updateAt"=> "",
  461. "suggestionCount" => SuggestionApi::getCountBySent($arrSentId[0],$arrSentId[1],$arrSentId[2],$arrSentId[3],$channelId),
  462. ];
  463. $row = Arr::first($record,function($value,$key) use($sid){
  464. return $value['sid']===$sid;
  465. });
  466. if($row){
  467. $newSent['id'] = $row->uid;
  468. $newSent['content'] = $row->content;
  469. $newSent['html'] = "";
  470. $newSent["editor"]=UserApi::getById($row->editor_uid);
  471. $newSent['updateAt'] = $row->updated_at;
  472. if($mode !== "read"){
  473. if(isset($row->acceptor_uid) && !empty($row->acceptor_uid)){
  474. $newSent["acceptor"]=UserApi::getById($row->acceptor_uid);
  475. $newSent["prEditAt"]=$row->pr_edit_at;
  476. }
  477. }
  478. switch ($info->type) {
  479. case 'wbw':
  480. case 'original':
  481. //
  482. // 在编辑模式下。
  483. // 如果是原文,查看是否有逐词解析数据,
  484. // 有的话优先显示。
  485. // 阅读模式直接显示html原文
  486. // 传过来的数据一定有一个原文channel
  487. //
  488. if($mode !== "read"){
  489. $newSent['channel']['type'] = "wbw";
  490. if(isset($this->wbwChannels[0])){
  491. $newSent['channel']['name'] = $indexChannel[$this->wbwChannels[0]]->name;
  492. $newSent['channel']['id'] = $this->wbwChannels[0];
  493. //存在一个translation channel
  494. //尝试查找逐词解析数据。找到,替换现有数据
  495. $wbwData = $this->getWbw($arrSentId[0],$arrSentId[1],$arrSentId[2],$arrSentId[3],$this->wbwChannels[0]);
  496. if($wbwData){
  497. $newSent['content'] = $wbwData;
  498. $newSent['html'] = "";
  499. }
  500. }
  501. }else{
  502. $newSent['content'] = "";
  503. $newSent['html'] = $row->content;
  504. }
  505. break;
  506. case 'nissaya':
  507. $newSent['html'] = Cache::remember("/sent/{$channelId}/{$currSentId}",10,
  508. function() use($row,$mode){
  509. return MdRender::render($row->content,$row->channel_uid,null,$mode,"nissaya");
  510. });
  511. break;
  512. default:
  513. //译文需要markdown渲染
  514. $newSent['html'] = Cache::remember("/sent/{$channelId}/{$currSentId}",10,
  515. function() use($row){
  516. return MdRender::render($row->content,$row->channel_uid);
  517. });
  518. break;
  519. }
  520. }
  521. switch ($info->type) {
  522. case 'wbw':
  523. case 'original':
  524. array_push($sent["origin"],$newSent);
  525. break;
  526. default:
  527. array_push($sent["translation"],$newSent);
  528. break;
  529. }
  530. }
  531. if($onlyProps){
  532. return $sent;
  533. }
  534. $content = $this->pushSent($content,$sent,0,$mode);
  535. }
  536. $output = \implode("",$content);
  537. return "<div>{$output}</div>";
  538. }
  539. public function getWbw($book,$para,$start,$end,$channel){
  540. /**
  541. * 非阅读模式下。原文使用逐词解析数据。
  542. * 优先加载第一个translation channel 如果没有。加载默认逐词解析。
  543. */
  544. //获取逐词解析数据
  545. $wbwBlock = WbwBlock::where('channel_uid',$channel)
  546. ->where('book_id',$book)
  547. ->where('paragraph',$para)
  548. ->select('uid')
  549. ->first();
  550. if(!$wbwBlock){
  551. return false;
  552. }
  553. //找到逐词解析数据
  554. $wbwData = Wbw::where('block_uid',$wbwBlock->uid)
  555. ->whereBetween('wid',[$start,$end])
  556. ->select(['book_id','paragraph','wid','data','uid'])
  557. ->orderBy('wid')
  558. ->get();
  559. $wbwContent = [];
  560. foreach ($wbwData as $wbwrow) {
  561. $wbw = str_replace("&nbsp;",' ',$wbwrow->data);
  562. $wbw = str_replace("<br>",' ',$wbw);
  563. $xmlString = "<root>" . $wbw . "</root>";
  564. try{
  565. $xmlWord = simplexml_load_string($xmlString);
  566. }catch(Exception $e){
  567. continue;
  568. }
  569. $wordsList = $xmlWord->xpath('//word');
  570. foreach ($wordsList as $word) {
  571. $case = \str_replace(['#','.'],['$',''],$word->case->__toString());
  572. $case = \str_replace('$$','$',$case);
  573. $case = trim($case);
  574. $case = trim($case,"$");
  575. $wbwId = explode('-',$word->id->__toString());
  576. $wbwData = [
  577. 'uid'=>$wbwrow->uid,
  578. 'book'=>$wbwrow->book_id,
  579. 'para'=>$wbwrow->paragraph,
  580. 'sn'=> array_slice($wbwId,2),
  581. 'word'=>['value'=>$word->pali->__toString(),'status'=>0],
  582. 'real'=> ['value'=>$word->real->__toString(),'status'=>0],
  583. 'meaning'=> ['value'=>$word->mean->__toString() ,'status'=>0],
  584. 'type'=> ['value'=>$word->type->__toString(),'status'=>0],
  585. 'grammar'=> ['value'=>$word->gramma->__toString(),'status'=>0],
  586. 'case'=> ['value'=>$word->case->__toString(),'status'=>0],
  587. 'parent'=> ['value'=>$word->parent->__toString(),'status'=>0],
  588. 'style'=> ['value'=>$word->style->__toString(),'status'=>0],
  589. 'factors'=> ['value'=>$word->org->__toString(),'status'=>0],
  590. 'factorMeaning'=> ['value'=>$word->om->__toString(),'status'=>0],
  591. 'confidence'=> $word->cf->__toString(),
  592. 'hasComment'=>Discussion::where('res_id',$wbwrow->uid)->exists(),
  593. ];
  594. if(isset($word->parent2)){
  595. $wbwData['parent2']['value'] = $word->parent2->__toString();
  596. if(isset($word->parent2['status'])){
  597. $wbwData['parent2']['status'] = (int)$word->parent2['status'];
  598. }else{
  599. $wbwData['parent2']['status'] = 0;
  600. }
  601. }
  602. if(isset($word->pg)){
  603. $wbwData['grammar2']['value'] = $word->pg->__toString();
  604. if(isset($word->pg['status'])){
  605. $wbwData['grammar2']['status'] = (int)$word->pg['status'];
  606. }else{
  607. $wbwData['grammar2']['status'] = 0;
  608. }
  609. }
  610. if(isset($word->rela)){
  611. $wbwData['relation']['value'] = $word->rela->__toString();
  612. if(isset($word->rela['status'])){
  613. $wbwData['relation']['status'] = (int)$word->rela['status'];
  614. }else{
  615. $wbwData['relation']['status'] = 7;
  616. }
  617. }
  618. if(isset($word->bmt)){
  619. $wbwData['bookMarkText']['value'] = $word->bmt->__toString();
  620. if(isset($word->bmt['status'])){
  621. $wbwData['bookMarkText']['status'] = (int)$word->bmt['status'];
  622. }else{
  623. $wbwData['bookMarkText']['status'] = 7;
  624. }
  625. }
  626. if(isset($word->bmc)){
  627. $wbwData['bookMarkColor']['value'] = $word->bmc->__toString();
  628. if(isset($word->bmc['status'])){
  629. $wbwData['bookMarkColor']['status'] = (int)$word->bmc['status'];
  630. }else{
  631. $wbwData['bookMarkColor']['status'] = 7;
  632. }
  633. }
  634. if(isset($word->note)){
  635. $wbwData['note']['value'] = $word->note->__toString();
  636. if(isset($word->note['status'])){
  637. $wbwData['note']['status'] = (int)$word->note['status'];
  638. }else{
  639. $wbwData['note']['status'] = 7;
  640. }
  641. }
  642. if(isset($word->cf)){
  643. $wbwData['confidence'] = (float)$word->cf->__toString();
  644. }
  645. if(isset($word->pali['status'])){
  646. $wbwData['word']['status'] = (int)$word->pali['status'];
  647. }
  648. if(isset($word->real['status'])){
  649. $wbwData['real']['status'] = (int)$word->real['status'];
  650. }
  651. if(isset($word->mean['status'])){
  652. $wbwData['meaning']['status'] = (int)$word->mean['status'];
  653. }
  654. if(isset($word->type['status'])){
  655. $wbwData['type']['status'] = (int)$word->type['status'];
  656. }
  657. if(isset($word->gramma['status'])){
  658. $wbwData['grammar']['status'] = (int)$word->gramma['status'];
  659. }
  660. if(isset($word->case['status'])){
  661. $wbwData['case']['status'] = (int)$word->case['status'];
  662. }
  663. if(isset($word->parent['status'])){
  664. $wbwData['parent']['status'] = (int)$word->parent['status'];
  665. }
  666. if(isset($word->org['status'])){
  667. $wbwData['factors']['status'] = (int)$word->org['status'];
  668. }
  669. if(isset($word->om['status'])){
  670. $wbwData['factorMeaning']['status'] = (int)$word->om['status'];
  671. }
  672. $wbwContent[] = $wbwData;
  673. }
  674. }
  675. if(count($wbwContent)===0){
  676. return false;
  677. }
  678. return \json_encode($wbwContent,JSON_UNESCAPED_UNICODE);
  679. }
  680. /**
  681. * 将句子放进结果列表
  682. */
  683. private function pushSent($result,$sent,$level=0,$mode='read'){
  684. $sentProps = base64_encode(\json_encode($sent)) ;
  685. if($mode === 'read'){
  686. $sentWidget = "<MdTpl tpl='sentread' props='{$sentProps}' />";
  687. }else{
  688. $sentWidget = "<MdTpl tpl='sentedit' props='{$sentProps}' />";
  689. }
  690. //增加标题的html标记
  691. if($level>0){
  692. $sentWidget = "<h{$level}>".$sentWidget."</h{$level}>";
  693. }
  694. array_push($result,$sentWidget);
  695. return $result;
  696. }
  697. private function newSent($book,$para,$word_start,$word_end){
  698. $sent = [
  699. "id"=>"{$book}-{$para}-{$word_start}-{$word_end}",
  700. "book"=>$book,
  701. "para"=>$para,
  702. "wordStart"=>$word_start,
  703. "wordEnd"=>$word_end,
  704. "origin"=>[],
  705. "translation"=>[],
  706. ];
  707. #生成channel 数量列表
  708. $sentId = "{$book}-{$para}-{$word_start}-{$word_end}";
  709. $channelCount = CorpusController::sentResCount($book,$para,$word_start,$word_end);
  710. $path = json_decode(PaliText::where('book',$book)->where('paragraph',$para)->value("path"),true);
  711. $sent["path"] = [];
  712. foreach ($path as $key => $value) {
  713. # code...
  714. $value['paliTitle'] = $value['title'];
  715. $sent["path"][] = $value;
  716. }
  717. $sent["tranNum"] = $channelCount['tranNum'];
  718. $sent["nissayaNum"] = $channelCount['nissayaNum'];
  719. $sent["commNum"] = $channelCount['commNum'];
  720. $sent["originNum"] = $channelCount['originNum'];
  721. $sent["simNum"] = $channelCount['simNum'];
  722. return $sent;
  723. }
  724. /**
  725. * 获取某个句子的相关资源的句子数量
  726. */
  727. public static function sentResCount($book,$para,$start,$end){
  728. $sentId = "{$book}-{$para}-{$start}-{$end}";
  729. $channelCount = Cache::remember("/sentence/{$sentId}/channels/count",
  730. 60,
  731. function() use($book,$para,$start,$end){
  732. $channels = Sentence::where('book_id',$book)
  733. ->where('paragraph',$para)
  734. ->where('word_start',$start)
  735. ->where('word_end',$end)
  736. ->select('channel_uid')
  737. ->groupBy('channel_uid')
  738. ->get();
  739. $channelList = [];
  740. foreach ($channels as $key => $value) {
  741. # code...
  742. if(Str::isUuid($value->channel_uid)){
  743. $channelList[] = $value->channel_uid;
  744. }
  745. }
  746. $simId = PaliSentence::where('book',$book)
  747. ->where('paragraph',$para)
  748. ->where('word_begin',$start)
  749. ->where('word_end',$end)
  750. ->value('id');
  751. if($simId){
  752. $output["simNum"]=SentSimIndex::where('sent_id',$simId)->value('count');
  753. }else{
  754. $output["simNum"]=0;
  755. }
  756. $channelInfo = Channel::whereIn("uid",$channelList)->select('type')->get();
  757. $output["tranNum"]=0;
  758. $output["nissayaNum"]=0;
  759. $output["commNum"]=0;
  760. $output["originNum"]=0;
  761. foreach ($channelInfo as $key => $value) {
  762. # code...
  763. switch($value->type){
  764. case "translation":
  765. $output["tranNum"]++;
  766. break;
  767. case "nissaya":
  768. $output["nissayaNum"]++;
  769. break;
  770. case "commentary":
  771. $output["commNum"]++;
  772. break;
  773. case "original":
  774. $output["originNum"]++;
  775. break;
  776. }
  777. }
  778. return $output;
  779. });
  780. return $channelCount;
  781. }
  782. private function markdownRender($input){
  783. }
  784. /**
  785. * Update the specified resource in storage.
  786. *
  787. * @param \Illuminate\Http\Request $request
  788. * @param \App\Models\Sentence $sentence
  789. * @return \Illuminate\Http\Response
  790. */
  791. public function update(Request $request, Sentence $sentence)
  792. {
  793. //
  794. }
  795. /**
  796. * Remove the specified resource from storage.
  797. *
  798. * @param \App\Models\Sentence $sentence
  799. * @return \Illuminate\Http\Response
  800. */
  801. public function destroy(Sentence $sentence)
  802. {
  803. //
  804. }
  805. }