TemplateRender.php 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042
  1. <?php
  2. namespace App\Http\Api;
  3. use Illuminate\Support\Facades\Cache;
  4. use Illuminate\Support\Facades\Log;
  5. use Illuminate\Support\Str;
  6. use Illuminate\Support\Facades\Http;
  7. use App\Models\DhammaTerm;
  8. use App\Models\PaliText;
  9. use App\Models\Channel;
  10. use App\Models\PageNumber;
  11. use App\Models\Discussion;
  12. use App\Http\Controllers\CorpusController;
  13. use App\Tools\RedisClusters;
  14. use App\Http\Api\ChannelApi;
  15. use App\Http\Api\MdRender;
  16. use App\Http\Api\PaliTextApi;
  17. class TemplateRender{
  18. protected $param = [];
  19. protected $mode = "read";
  20. protected $channel_id = [];
  21. protected $debug = [];
  22. protected $format = 'react';
  23. protected $studioId = null;
  24. protected $lang = 'en';
  25. protected $langFamily = 'en';
  26. /**
  27. * Create a new command instance.
  28. * string $mode 'read' | 'edit'
  29. * string $format 'react' | 'text' | 'tex' | 'unity'
  30. * @return void
  31. */
  32. public function __construct($param, $channelInfo, $mode,$format='react',$studioId,$debug=[],$lang='zh-Hans')
  33. {
  34. $this->param = $param;
  35. foreach ($channelInfo as $value) {
  36. $this->channel_id[] = $value->uid;
  37. }
  38. $this->channelInfo = $channelInfo;
  39. $this->mode = $mode;
  40. $this->format = $format;
  41. $this->studioId = $studioId;
  42. $this->debug = $debug;
  43. if(count($this->channel_id)>0){
  44. $channelId = $this->channel_id[0];
  45. if(Str::isUuid($channelId)){
  46. $lang = Channel::where('uid',$channelId)->value('lang');
  47. }
  48. }
  49. if(!empty($lang)){
  50. $this->lang = $lang;
  51. $this->langFamily = explode('-',$lang)[0];
  52. }
  53. }
  54. /**
  55. * TODO 设置默认语言。在渲染某些内容的时候需要语言信息
  56. */
  57. public function setLang($lang){
  58. $this->lang = $lang;
  59. $this->langFamily = explode('-',$lang)[0];
  60. }
  61. private function info($message,$debug){
  62. if(in_array($debug,$this->debug)){
  63. Log::info($message);
  64. }
  65. }
  66. private function error($message,$debug){
  67. if(in_array($debug,$this->debug)){
  68. Log::error($message);
  69. }
  70. }
  71. public function render($tpl_name){
  72. switch ($tpl_name) {
  73. case 'term':
  74. # 术语
  75. $result = $this->render_term();
  76. break;
  77. case 'note':
  78. $result = $this->render_note();
  79. break;
  80. case 'sent':
  81. $result = $this->render_sent();
  82. break;
  83. case 'quote':
  84. $result = $this->render_quote();
  85. break;
  86. case 'ql':
  87. $result = $this->render_quote_link();
  88. break;
  89. case 'exercise':
  90. $result = $this->render_exercise();
  91. break;
  92. case 'article':
  93. $result = $this->render_article();
  94. break;
  95. case 'nissaya':
  96. $result = $this->render_nissaya();
  97. break;
  98. case 'mermaid':
  99. $result = $this->render_mermaid();
  100. break;
  101. case 'qa':
  102. $result = $this->render_qa();
  103. break;
  104. case 'v':
  105. $result = $this->render_video();
  106. break;
  107. case 'g':
  108. $result = $this->render_grammar_lookup();
  109. break;
  110. default:
  111. # code...
  112. $result = [
  113. 'props'=>base64_encode(\json_encode([])),
  114. 'html'=>'',
  115. 'tag'=>'span',
  116. 'tpl'=>'unknown',
  117. ];
  118. break;
  119. }
  120. return $result;
  121. }
  122. public function getTermProps($word,$tag=null,$channel=null){
  123. if($channel && !empty($channel)){
  124. $channelId = $channel;
  125. }else{
  126. if(count($this->channel_id)>0){
  127. $channelId = $this->channel_id[0];
  128. }else{
  129. $channelId = null;
  130. }
  131. }
  132. if(count($this->channelInfo)===0){
  133. if(!empty($channel)){
  134. $channelInfo = Channel::where('uid',$channel)->first();
  135. if(!$channelInfo){
  136. unset($channelInfo);
  137. }
  138. }
  139. if(!isset($channelInfo)){
  140. Log::error('channel is null');
  141. $output = [
  142. "word" => $word,
  143. 'innerHtml' => '',
  144. ];
  145. return $output;
  146. }
  147. }else{
  148. $channelInfo = $this->channelInfo[0];
  149. }
  150. if(Str::isUuid($channelId)){
  151. $lang = Channel::where('uid',$channelId)->value('lang');
  152. if(!empty($lang)){
  153. $langFamily = explode('-',$lang)[0];
  154. }else{
  155. $langFamily = 'zh';
  156. }
  157. $this->info("term:{$word} 先查属于这个channel 的",'term');
  158. $this->info('channel id'.$channelId,'term');
  159. $table = DhammaTerm::where("word",$word)
  160. ->where('channal',$channelId);
  161. if($tag && !empty($tag)){
  162. $table = $table->where('tag',$tag);
  163. }
  164. $tplParam = $table->orderBy('updated_at','desc')
  165. ->first();
  166. $studioId = $channelInfo->owner_uid;
  167. }else{
  168. $tplParam = false;
  169. $lang = '';
  170. $langFamily = '';
  171. $studioId = $this->studioId;
  172. }
  173. if(!$tplParam){
  174. if(Str::isUuid($studioId)){
  175. /**
  176. * 没有,再查这个studio的
  177. * 按照语言过滤
  178. * 完全匹配的优先
  179. * 语族匹配也行
  180. */
  181. $this->info("没有-再查这个studio的",'term');
  182. $table = DhammaTerm::where("word",$word);
  183. if(!empty($tag)){
  184. $table = $table->where('tag',$tag);
  185. }
  186. $termsInStudio = $table->where('owner',$channelInfo->owner_uid)
  187. ->orderBy('updated_at','desc')
  188. ->get();
  189. if(count($termsInStudio)>0){
  190. $list = array();
  191. foreach ($termsInStudio as $key=>$term) {
  192. if(empty($term->channal)){
  193. if($term->language===$lang){
  194. $list[$term->guid]=2;
  195. }else if(strpos($term->language,$langFamily) !== false){
  196. $list[$term->guid]=1;
  197. }
  198. }
  199. }
  200. if(count($list)>0){
  201. arsort($list);
  202. foreach ($list as $key => $one) {
  203. foreach ($termsInStudio as $term) {
  204. if($term->guid===$key){
  205. $tplParam = $term;
  206. break;
  207. }
  208. }
  209. break;
  210. }
  211. }
  212. }
  213. }
  214. }
  215. if(!$tplParam){
  216. $this->info("没有,再查社区",'term');
  217. $community_channel = ChannelApi::getSysChannel("_community_term_zh-hans_");
  218. $table = DhammaTerm::where("word",$word);
  219. if(!empty($tag)){
  220. $table = $table->where('tag',$tag);
  221. }
  222. $tplParam = $table->where('channal',$community_channel)
  223. ->first();
  224. if($tplParam){
  225. $isCommunity = true;
  226. }else{
  227. $this->info("查社区没有",'term');
  228. }
  229. }
  230. $output = [
  231. "word" => $word,
  232. "parentChannelId" => $channelId,
  233. "parentStudioId" => $channelInfo->owner_uid,
  234. ];
  235. $innerString = $output["word"];
  236. if($tplParam){
  237. $output["id"] = $tplParam->guid;
  238. $output["meaning"] = $tplParam->meaning;
  239. $output["channel"] = $tplParam->channal;
  240. if(isset($isCommunity)){
  241. $output["isCommunity"] = true;
  242. }
  243. $innerString = "{$output["meaning"]}({$output["word"]})";
  244. if(!empty($tplParam->other_meaning)){
  245. $output["meaning2"] = $tplParam->other_meaning;
  246. }
  247. }
  248. $output['innerHtml'] = $innerString;
  249. return $output;
  250. }
  251. private function render_term(){
  252. $word = $this->get_param($this->param,"word",1);
  253. $props = $this->getTermProps($word,'');
  254. //$key = "/term/{$channelId}/{$word}";
  255. $output = $props['word'];
  256. switch ($this->format) {
  257. case 'react':
  258. $output=[
  259. 'props'=>base64_encode(\json_encode($props)),
  260. 'html'=>$props['innerHtml'],
  261. 'tag'=>'span',
  262. 'tpl'=>'term',
  263. ];
  264. break;
  265. case 'unity':
  266. $output=[
  267. 'props'=>base64_encode(\json_encode($props)),
  268. 'tpl'=>'term',
  269. ];
  270. break;
  271. case 'html':
  272. if(isset($props["meaning"])){
  273. $key = 'term-'.$props["word"];
  274. $termHead = "<a href='#'>".$props['meaning']."</a>";
  275. if(isset($GLOBALS[$key])){
  276. $output = $termHead;
  277. }else{
  278. $GLOBALS[$key] = 1;
  279. $output = $termHead.'(<em>'.$props["word"].'</em>)';
  280. }
  281. }else{
  282. $output = $props["word"];
  283. }
  284. break;
  285. case 'text':
  286. if(isset($props["meaning"])){
  287. $key = 'term-'.$props["word"];
  288. if(isset($GLOBALS[$key])){
  289. $output = $props["meaning"];
  290. }else{
  291. $GLOBALS[$key] = 1;
  292. $output = $props["meaning"].'('.$props["word"].')';
  293. }
  294. }else{
  295. $output = $props["word"];
  296. }
  297. break;
  298. case 'tex':
  299. if(isset($props["meaning"])){
  300. $key = 'term-'.$props["word"];
  301. if(isset($GLOBALS[$key])){
  302. $output = $props["meaning"];
  303. }else{
  304. $GLOBALS[$key] = 1;
  305. $output = $props["meaning"].'('.$props["word"].')';
  306. }
  307. }else{
  308. $output = $props["word"];
  309. }
  310. break;
  311. case 'simple':
  312. if(isset($props["meaning"])){
  313. $output = $props["meaning"];
  314. }else{
  315. $output = $props["word"];
  316. }
  317. break;
  318. default:
  319. if(isset($props["meaning"])){
  320. $output = $props["meaning"];
  321. }else{
  322. $output = $props["word"];
  323. }
  324. break;
  325. }
  326. return $output;
  327. }
  328. private function render_note(){
  329. $note = $this->get_param($this->param,"text",1);
  330. $trigger = $this->get_param($this->param,"trigger",2);
  331. $props = ["note" => $note ];
  332. $innerString = "";
  333. if(!empty($trigger)){
  334. $props["trigger"] = $trigger;
  335. $innerString = $props["trigger"];
  336. }
  337. if($this->format==='unity'){
  338. $props["note"] = MdRender::render($props["note"],
  339. $this->channel_id,
  340. null,
  341. 'read',
  342. 'translation',
  343. 'markdown',
  344. 'unity'
  345. );
  346. }
  347. $output = $note;
  348. switch ($this->format) {
  349. case 'react':
  350. $output=[
  351. 'props'=>base64_encode(\json_encode($props)),
  352. 'html'=>$innerString,
  353. 'tag'=>'span',
  354. 'tpl'=>'note',
  355. ];
  356. break;
  357. case 'unity':
  358. $output=[
  359. 'props'=>base64_encode(\json_encode($props)),
  360. 'tpl'=>'note',
  361. ];
  362. break;
  363. case 'html':
  364. if(isset($GLOBALS['note_sn'])){
  365. $GLOBALS['note_sn']++;
  366. }else{
  367. $GLOBALS['note_sn'] = 1;
  368. $GLOBALS['note'] = array();
  369. }
  370. $GLOBALS['note'][] = [
  371. 'sn' => 1,
  372. 'trigger' => $trigger,
  373. 'content' => MdRender::render($props["note"],
  374. $this->channel_id,
  375. null,
  376. 'read',
  377. 'translation',
  378. 'markdown',
  379. 'html'
  380. ),
  381. ];
  382. $link="<a href='#footnote-".$GLOBALS['note_sn']."' name='note-".$GLOBALS['note_sn']."'>";
  383. if(empty($trigger)){
  384. $output = $link. "<sup>[" . $GLOBALS['note_sn'] . "]</sup></a>";
  385. }else{
  386. $output = $link . $trigger . "</a>";
  387. }
  388. break;
  389. case 'text':
  390. $output = $trigger;
  391. break;
  392. case 'tex':
  393. $output = $trigger;
  394. break;
  395. case 'simple':
  396. $output = '';
  397. break;
  398. default:
  399. $output = '';
  400. break;
  401. }
  402. return $output;
  403. }
  404. private function render_nissaya(){
  405. $pali = $this->get_param($this->param,"pali",1);
  406. $meaning = $this->get_param($this->param,"meaning",2);
  407. $innerString = "";
  408. $props = [
  409. "pali" => $pali,
  410. "meaning" => $meaning,
  411. "lang" => $this->lang,
  412. ];
  413. switch ($this->format) {
  414. case 'react':
  415. $output = [
  416. 'props'=>base64_encode(\json_encode($props)),
  417. 'html'=>$innerString,
  418. 'tag'=>'span',
  419. 'tpl'=>'nissaya',
  420. ];
  421. break;
  422. case 'unity':
  423. $output = [
  424. 'props'=>base64_encode(\json_encode($props)),
  425. 'tpl'=>'nissaya',
  426. ];
  427. break;
  428. case 'text':
  429. $output = $pali.'၊'.$meaning;
  430. break;
  431. case 'tex':
  432. $output = $pali.'၊'.$meaning;
  433. break;
  434. case 'simple':
  435. $output = $pali.'၊'.$meaning;
  436. break;
  437. default:
  438. $output = $pali.'၊'.$meaning;
  439. break;
  440. }
  441. return $output;
  442. }
  443. private function render_exercise(){
  444. $id = $this->get_param($this->param,"id",1);
  445. $title = $this->get_param($this->param,"title",1);
  446. $props = [
  447. "id" => $id,
  448. "title" => $title,
  449. "channel" => $this->channel_id[0],
  450. ];
  451. switch ($this->format) {
  452. case 'react':
  453. $output = [
  454. 'props'=>base64_encode(\json_encode($props)),
  455. 'html'=>"",
  456. 'tag'=>'span',
  457. 'tpl'=>'exercise',
  458. ];
  459. break;
  460. case 'unity':
  461. $output = [
  462. 'props'=>base64_encode(\json_encode($props)),
  463. 'tpl'=>'exercise',
  464. ];
  465. break;
  466. case 'text':
  467. $output = $title;
  468. break;
  469. case 'tex':
  470. $output = $title;
  471. break;
  472. case 'simple':
  473. $output = $title;
  474. break;
  475. default:
  476. $output = '';
  477. break;
  478. }
  479. return $output;
  480. }
  481. private function render_article(){
  482. $type = $this->get_param($this->param,"type",1);
  483. $id = $this->get_param($this->param,"id",2);
  484. $title = $this->get_param($this->param,"title",3);
  485. $channel = $this->get_param($this->param,"channel",4,$this->channel_id[0]);
  486. $style = $this->get_param($this->param,"style",5);
  487. $book = $this->get_param($this->param,"book",6);
  488. $paragraphs = $this->get_param($this->param,"paragraphs",7);
  489. $props = [
  490. "type" => $type,
  491. "id" => $id,
  492. "channel" => $channel,
  493. 'style' => $style,
  494. ];
  495. if(!empty($title)){
  496. $props['title'] = $title;
  497. }
  498. if(!empty($book)){
  499. $props['book'] = $book;
  500. }
  501. if(!empty($paragraphs)){
  502. $props['paragraphs'] = $paragraphs;
  503. }
  504. switch ($this->format) {
  505. case 'react':
  506. $output = [
  507. 'props'=>base64_encode(\json_encode($props)),
  508. 'html'=>"",
  509. 'text'=>$title,
  510. 'tag'=>'span',
  511. 'tpl'=>'article',
  512. ];
  513. break;
  514. case 'unity':
  515. $output = [
  516. 'props'=>base64_encode(\json_encode($props)),
  517. 'tpl'=>'article',
  518. ];
  519. break;
  520. case 'text':
  521. $output = $title;
  522. break;
  523. case 'tex':
  524. $output = $title;
  525. break;
  526. case 'simple':
  527. $output = $title;
  528. break;
  529. default:
  530. $output = '';
  531. break;
  532. }
  533. return $output;
  534. }
  535. private function render_quote(){
  536. $paraId = $this->get_param($this->param,"para",1);
  537. $channelId = $this->channel_id[0];
  538. $props = RedisClusters::remember("/quote/{$channelId}/{$paraId}",
  539. config('mint.cache.expire'),
  540. function() use($paraId,$channelId){
  541. $para = \explode('-',$paraId);
  542. $output = [
  543. "paraId" => $paraId,
  544. "channel" => $channelId,
  545. "innerString" => $paraId,
  546. ];
  547. if(count($para)<2){
  548. return $output;
  549. }
  550. $PaliText = PaliText::where("book",$para[0])
  551. ->where("paragraph",$para[1])
  552. ->select(['toc','path'])
  553. ->first();
  554. if($PaliText){
  555. $output["pali"] = $PaliText->toc;
  556. $output["paliPath"] = \json_decode($PaliText->path);
  557. $output["innerString"]= $PaliText->toc;
  558. }
  559. return $output;
  560. });
  561. switch ($this->format) {
  562. case 'react':
  563. $output = [
  564. 'props'=>base64_encode(\json_encode($props)),
  565. 'html'=>$props["innerString"],
  566. 'tag'=>'span',
  567. 'tpl'=>'quote',
  568. ];
  569. break;
  570. case 'unity':
  571. $output = [
  572. 'props'=>base64_encode(\json_encode($props)),
  573. 'tpl'=>'quote',
  574. ];
  575. break;
  576. case 'text':
  577. $output = $props["innerString"];
  578. break;
  579. case 'tex':
  580. $output = $props["innerString"];
  581. break;
  582. case 'simple':
  583. $output = $props["innerString"];
  584. break;
  585. default:
  586. $output = $props["innerString"];
  587. break;
  588. }
  589. return $output;
  590. }
  591. private function render_quote_link(){
  592. $type = $this->get_param($this->param,"type",1);
  593. $title = $this->get_param($this->param,"title",6,'');
  594. $bookName = $this->get_param($this->param,"bookname",2,'');
  595. $volume = $this->get_param($this->param,"volume",3);
  596. $page = $this->get_param($this->param,"page",4,'');
  597. $style = $this->get_param($this->param,"style",5,'modal');
  598. $book = $this->get_param($this->param,"book",7,false);
  599. $para = $this->get_param($this->param,"para",8,false);
  600. $props = [
  601. 'type' => $type,
  602. 'style' => $style,
  603. 'found' => true,
  604. ];
  605. if(!empty($bookName) && $volume !== '' && !empty($page)){
  606. $props['bookName'] = $bookName;
  607. $props['volume'] = (int)$volume;
  608. $props['page'] = $page;
  609. $props['found'] = true;
  610. }else if($book && $para){
  611. /**
  612. * 没有指定书名,根据book para 查询
  613. */
  614. if($type==='c'){
  615. //按照章节名称显示
  616. $path = PaliTextApi::getChapterPath($book,$para);
  617. if($path){
  618. $path = json_decode($path,true);
  619. }
  620. if($path && is_array($path) && count($path)>2){
  621. $props['bookName'] = strtolower($path[0]['title']) ;
  622. $props['chapter'] = strtolower(end($path)['title']);
  623. $props['found'] = true;
  624. }else{
  625. $props['found'] = false;
  626. }
  627. }else{
  628. $pageInfo = $this->pageInfoByPara($type,$book,$para);
  629. if($pageInfo['found']){
  630. $props['bookName'] = $pageInfo['bookName'];
  631. $props['volume'] = $pageInfo['volume'];
  632. $props['page'] = $pageInfo['page'];
  633. $props['found'] = true;
  634. }else{
  635. $props['found'] = false;
  636. }
  637. }
  638. }else if($title){
  639. //没有书号用title查询
  640. $tmpTitle = explode('။',$title);
  641. if(count($tmpTitle)>1){
  642. $tmpBookTitle = $tmpTitle[0];
  643. $tmpBookPage = $tmpTitle[1];
  644. $tmpBookPage = (int)str_replace(
  645. ['၁','၂','၃','၄','၅','၆','၇','၈','၉','၀'],
  646. ['1','2','3','4','5','6','7','8','9','0'],
  647. $tmpBookPage);
  648. $found_key = array_search($tmpBookTitle, array_column(BookTitle::my(), 'title2'));
  649. if($found_key !== false){
  650. $props['bookName'] = BookTitle::my()[$found_key]['bookname'];
  651. $props['volume'] = BookTitle::my()[$found_key]['volume'];
  652. $props['page'] = $tmpBookPage;
  653. if(!empty($props['bookName'])){
  654. $found_title = array_search($props['bookName'], array_column(BookTitle::my(), 'bookname'));
  655. if($found_title === false){
  656. $props['found'] = false;
  657. }
  658. }
  659. }else{
  660. //没找到,返回术语和页码
  661. $props['found'] = false;
  662. $props['bookName'] = $tmpBookTitle;
  663. $props['page'] = $tmpBookPage;
  664. $props['volume'] = 0;
  665. }
  666. }
  667. }else{
  668. $props['found'] = false;
  669. }
  670. if($book && $para){
  671. $props['book'] = $book;
  672. $props['para'] = $para;
  673. }
  674. if($title){
  675. $props['title'] = $title;
  676. }
  677. $text = '';
  678. if(isset($props['bookName'])){
  679. $searchField = '';
  680. switch ($type) {
  681. case 'm':
  682. $searchField = 'm_title';
  683. break;
  684. case 'p':
  685. $searchField = 'p_title';
  686. break;
  687. }
  688. $found_title = array_search($props['bookName'], array_column(BookTitle::get(), $searchField));
  689. if($found_title === false){
  690. $props['found'] = false;
  691. }
  692. $term = $this->getTermProps($props['bookName'],':quote:');
  693. $props['term'] = $term;
  694. if(isset($term['id'])){
  695. $props['bookNameLocal'] = $term['meaning'];
  696. $text .= $term['meaning'];
  697. }else{
  698. $text .= $bookName;
  699. }
  700. }
  701. if(isset($props['volume']) && isset($props['page'])){
  702. $text .= " {$volume}.{$page}";
  703. }
  704. switch ($this->format) {
  705. case 'react':
  706. $output = [
  707. 'props'=>base64_encode(\json_encode($props)),
  708. 'html'=>'',
  709. 'tag'=>'span',
  710. 'tpl'=>'quote-link',
  711. ];
  712. break;
  713. case 'unity':
  714. $output = [
  715. 'props'=>base64_encode(\json_encode($props)),
  716. 'tpl'=>'quote-link',
  717. ];
  718. break;
  719. default:
  720. $output = $text;
  721. break;
  722. }
  723. return $output;
  724. }
  725. private function pageInfoByPara($type,$book,$para){
  726. $output = array();
  727. $pageInfo = PageNumber::where('type',strtoupper($type))
  728. ->where('book',$book)
  729. ->where('paragraph','<=',$para)
  730. ->orderBy('paragraph','desc')
  731. ->first();
  732. if($pageInfo){
  733. foreach (BookTitle::get() as $value) {
  734. if($value['id']===$pageInfo->pcd_book_id){
  735. switch (strtoupper($type)) {
  736. case 'M':
  737. $key = 'm_title';
  738. break;
  739. case 'P':
  740. $key = 'p_title';
  741. break;
  742. case 'V':
  743. $key = 'v_title';
  744. break;
  745. default:
  746. $key = 'term';
  747. break;
  748. }
  749. $output['bookName'] = $value[$key];
  750. break;
  751. }
  752. }
  753. $output['volume'] = $pageInfo->volume;
  754. $output['page'] = $pageInfo->page;
  755. $output['found'] = true;
  756. }else{
  757. $output['found'] = false;
  758. }
  759. return $output;
  760. }
  761. private function render_sent(){
  762. $sid = $this->get_param($this->param,"sid",1);
  763. $channel = $this->get_param($this->param,"channel",2);
  764. if(!empty($channel)){
  765. $channels = explode(',',$channel);
  766. }else{
  767. $channels = $this->channel_id;
  768. }
  769. $sentInfo = explode('@',trim($sid));
  770. $sentId = $sentInfo[0];
  771. if(isset($sentInfo[1])){
  772. $channels = [$sentInfo[1]];
  773. }
  774. $Sent = new CorpusController();
  775. $props = $Sent->getSentTpl($sentId,$channels,
  776. $this->mode,true,
  777. $this->format);
  778. if($props === false){
  779. $props['error']="句子模版渲染错误。句子参数个数不符。应该是四个。";
  780. }
  781. if($this->mode==='read'){
  782. $tpl = "sentread";
  783. }else{
  784. $tpl = "sentedit";
  785. }
  786. switch ($this->format) {
  787. case 'react':
  788. $output = [
  789. 'props'=>base64_encode(\json_encode($props)),
  790. 'html'=>"",
  791. 'tag'=>'span',
  792. 'tpl'=>$tpl,
  793. ];
  794. break;
  795. case 'unity':
  796. $output = [
  797. 'props'=>base64_encode(\json_encode($props)),
  798. 'tpl'=>$tpl,
  799. ];
  800. break;
  801. case 'text':
  802. $output = '';
  803. if(isset($props['translation']) && is_array($props['translation'])){
  804. foreach ($props['translation'] as $key => $value) {
  805. $output .= $value['html'];
  806. }
  807. }
  808. break;
  809. case 'html':
  810. $output = '';
  811. if(isset($props['translation']) && is_array($props['translation'])){
  812. foreach ($props['translation'] as $key => $value) {
  813. $output .= '<span class="sentence">'.$value['html'].'</span>';
  814. }
  815. }
  816. break;
  817. case 'tex':
  818. $output = '';
  819. if(isset($props['translation']) && is_array($props['translation'])){
  820. foreach ($props['translation'] as $key => $value) {
  821. $output .= $value['html'];
  822. }
  823. }
  824. break;
  825. case 'simple':
  826. $output = '';
  827. if(isset($props['translation']) &&
  828. is_array($props['translation']) &&
  829. count($props['translation']) > 0
  830. ){
  831. $sentences = $props['translation'];
  832. foreach ($sentences as $key => $value) {
  833. $output .= $value['html'];
  834. }
  835. }
  836. if(empty($output)){
  837. if(isset($props['origin']) &&
  838. is_array($props['origin']) &&
  839. count($props['origin']) > 0
  840. ){
  841. $sentences = $props['origin'];
  842. foreach ($sentences as $key => $value) {
  843. $output .= $value['html'];
  844. }
  845. }
  846. }
  847. break;
  848. default:
  849. $output = '';
  850. break;
  851. }
  852. return $output;
  853. }
  854. private function render_mermaid(){
  855. $text = json_decode(base64_decode($this->get_param($this->param,"text",1)));
  856. $props = ["text" => implode("\n",$text)];
  857. switch ($this->format) {
  858. case 'react':
  859. $output = [
  860. 'props'=>base64_encode(\json_encode($props)),
  861. 'html'=>"mermaid",
  862. 'tag'=>'div',
  863. 'tpl'=>'mermaid',
  864. ];
  865. break;
  866. case 'unity':
  867. $output = [
  868. 'props'=>base64_encode(\json_encode($props)),
  869. 'tpl'=>'mermaid',
  870. ];
  871. break;
  872. case 'text':
  873. $output = 'mermaid';
  874. break;
  875. case 'tex':
  876. $output = 'mermaid';
  877. break;
  878. case 'simple':
  879. $output = 'mermaid';
  880. break;
  881. default:
  882. $output = 'mermaid';
  883. break;
  884. }
  885. return $output;
  886. }
  887. private function render_qa(){
  888. $id = $this->get_param($this->param,"id",1);
  889. $style = $this->get_param($this->param,"style",2);
  890. $props = [
  891. "type" => 'qa',
  892. "id" => $id,
  893. 'title' => '',
  894. 'style' => $style,
  895. ];
  896. $qa = Discussion::where('id',$id)->first();
  897. if($qa){
  898. $props['title'] = $qa->title;
  899. $props['resId'] = $qa->res_id;
  900. $props['resType'] = $qa->res_type;
  901. }
  902. switch ($this->format) {
  903. case 'react':
  904. $output = [
  905. 'props'=>base64_encode(\json_encode($props)),
  906. 'html'=>"",
  907. 'text'=>$props['title'],
  908. 'tag'=>'div',
  909. 'tpl'=>'qa',
  910. ];
  911. break;
  912. case 'unity':
  913. $output = [
  914. 'props'=>base64_encode(\json_encode($props)),
  915. 'tpl'=>'qa',
  916. ];
  917. break;
  918. default:
  919. $output = $props['title'];
  920. break;
  921. }
  922. return $output;
  923. }
  924. private function render_grammar_lookup(){
  925. $word = $this->get_param($this->param,"word",1);
  926. $props = ['word' => $word];
  927. $localTermChannel = ChannelApi::getSysChannel(
  928. "_System_Grammar_Term_".strtolower($this->lang)."_",
  929. "_System_Grammar_Term_en_"
  930. );
  931. $term = $this->getTermProps($word,null,$localTermChannel);
  932. $props['term'] = $term;
  933. switch ($this->format) {
  934. case 'react':
  935. $output = [
  936. 'props'=>base64_encode(\json_encode($props)),
  937. 'html'=>"",
  938. 'text'=>$props['word'],
  939. 'tag'=>'span',
  940. 'tpl'=>'grammar',
  941. ];
  942. break;
  943. case 'unity':
  944. $output = [
  945. 'props'=>base64_encode(\json_encode($props)),
  946. 'tpl'=>'grammar',
  947. ];
  948. break;
  949. default:
  950. $output = $props['word'];
  951. break;
  952. }
  953. return $output;
  954. }
  955. private function render_video(){
  956. $url = $this->get_param($this->param,"url",1);
  957. $style = $this->get_param($this->param,"style",2,'modal');
  958. $title = $this->get_param($this->param,"title",3);
  959. $props = [
  960. "url" => $url,
  961. 'title' => $title,
  962. 'style' => $style,
  963. ];
  964. switch ($this->format) {
  965. case 'react':
  966. $output = [
  967. 'props'=>base64_encode(\json_encode($props)),
  968. 'html'=>"",
  969. 'text'=>$props['title'],
  970. 'tag'=>'span',
  971. 'tpl'=>'video',
  972. ];
  973. break;
  974. case 'unity':
  975. $output = [
  976. 'props'=>base64_encode(\json_encode($props)),
  977. 'tpl'=>'video',
  978. ];
  979. break;
  980. default:
  981. $output = $props['title'];
  982. break;
  983. }
  984. return $output;
  985. }
  986. private function get_param(array $param,string $name,int $id,string $default=''){
  987. if(isset($param[$name])){
  988. return trim($param[$name]);
  989. }else if(isset($param["{$id}"])){
  990. return trim($param["{$id}"]);
  991. }else{
  992. return $default;
  993. }
  994. }
  995. }