TemplateRender.php 35 KB

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