SentenceInput.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. <!-- -->
  2. <template>
  3. <div class="Big-Book-prev-Textdes" v-if="curQue">
  4. <h2 v-if="curQue.title">{{ curQue.title }}</h2>
  5. <ul>
  6. <li v-for="(items, indexs) in curQue.option" :key="indexs">
  7. <b class="xuhao" v-if="items.number">{{ items.number }}</b>
  8. <p
  9. :class="[oldsrc == items.mp3_list[0].id ? palyClass : '']"
  10. @click="handlePlayVoice(items.mp3_list[0].id)"
  11. v-if="items.mp3_list && items.mp3_list.length > 0"
  12. ></p>
  13. <!-- 句子内容 -->
  14. <div class="item-content">
  15. <!-- 如果不是填空题 不替换 -->
  16. <template v-if="dataType.indexOf('sentence_input_chs') == -1">
  17. <template v-if="items.detail.wordsList.length == 0">
  18. <p :class="['content-con']" v-if="items.detail.sentence">
  19. {{ items.detail.sentence }}
  20. </p>
  21. </template>
  22. <template v-else>
  23. <div class="con-box">
  24. <div
  25. :class="['con-item', indexCon === 0 ? 'con-item-0' : '']"
  26. v-for="(itemCon, indexCon) in items.detail.resArr"
  27. :key="indexCon"
  28. v-show="itemCon.isShow"
  29. >
  30. <template
  31. v-if="
  32. items.detail.wordsList[indexCon + 1] &&
  33. items.detail.wordsList[indexCon + 1].chs &&
  34. chsFhList.indexOf(
  35. items.detail.wordsList[indexCon + 1].chs
  36. ) > -1
  37. "
  38. >
  39. <div class="synthesis-box">
  40. <div>
  41. <span
  42. class="pinyin"
  43. :class="[
  44. noFont.indexOf(itemCon.pinyin) > -1 ? 'noFont' : '',
  45. ]"
  46. >{{ itemCon.pinyin }}</span
  47. >
  48. <span class="hanzi content-con">{{ itemCon.chs }}</span>
  49. </div>
  50. <div style="text-align: left">
  51. <span
  52. class="pinyin"
  53. :class="[
  54. noFont.indexOf(
  55. items.detail.wordsList[indexCon + 1].pinyin
  56. ) > -1
  57. ? 'noFont'
  58. : '',
  59. ]"
  60. >{{
  61. items.detail.wordsList[indexCon + 1].pinyin
  62. }}</span
  63. >
  64. <span class="hanzi content-con">{{
  65. items.detail.wordsList[indexCon + 1].chs
  66. }}</span>
  67. </div>
  68. </div>
  69. </template>
  70. <template v-else>
  71. <span
  72. class="pinyin"
  73. :class="[
  74. noFont.indexOf(itemCon.pinyin) > -1 ? 'noFont' : '',
  75. ]"
  76. >{{ itemCon.pinyin }}</span
  77. >
  78. <span class="hanzi content-con">{{ itemCon.chs }}</span>
  79. </template>
  80. </div>
  81. </div>
  82. </template>
  83. <b class="content-en" v-if="items.en">{{ items.en }}</b>
  84. </template>
  85. <template v-else>
  86. <div class="chs_pinyin">
  87. <div
  88. v-for="(conent, conIndex) in items.detail.wordsList"
  89. :key="conIndex + 'con'"
  90. >
  91. <template v-if="items.detail.pyPosition == 'top'">
  92. <!-- <div
  93. v-if="conent.pinyin == '__'"
  94. contenteditable="true"
  95. class="input pinyin"
  96. v-html="answerList[indexs].pinyin"
  97. @change="changeAnswerList($event, indexs, 'pinyin')"
  98. ></div> -->
  99. <!--
  100. v-model="answerList[indexs].pinyin"
  101. -->
  102. <p class="pinyin" v-if="conent.pinyin.indexOf('__')==-1">
  103. {{ conent.pinyin }}
  104. </p>
  105. </template>
  106. <template v-if="conent.chs.indexOf('__')>-1">
  107. <EditDiv class="input chs" v-model='curQue.Bookanswer[indexs].answerList[items.detail.resArr[conIndex].inputNumber].chs' :TaskModel="TaskModel"></EditDiv>
  108. <!-- <el-input
  109. class="input chs"
  110. type="textarea"
  111. autosize
  112. placeholder="输入"
  113. v-model="curQue.Bookanswer[indexs].answerList[items.detail.resArr[conIndex].inputNumber].chs"
  114. :readonly="TaskModel=='ANSWER'"
  115. maxlength="200">
  116. </el-input> -->
  117. </template>
  118. <template v-else>
  119. <p class="chs">
  120. {{ conent.chs }}
  121. </p>
  122. </template>
  123. <template
  124. v-if="items.detail.pyPosition == 'bottom' && conent.pinyin"
  125. >
  126. <!-- <div
  127. v-if="conent.pinyin == '__'"
  128. contenteditable="true"
  129. class="input pinyin"
  130. v-html="answerList[indexs].pinyin"
  131. @change="changeAnswerList($event, indexs, 'pinyin')"
  132. ></div> -->
  133. <p class="pinyin" v-if="conent.pinyin.indexOf('__')==-1">
  134. {{ conent.pinyin }}
  135. </p>
  136. </template>
  137. </div>
  138. </div>
  139. </template>
  140. </div>
  141. <template v-if="dataType.indexOf('sentence_answer_chs') > -1">
  142. <input
  143. @input="handleInput"
  144. :class="['item-input']"
  145. v-model="curQue.Bookanswer[indexs].answer"
  146. placeholder="输入"
  147. />
  148. </template>
  149. <template v-if="dataType.indexOf('sentence_judge_chs') > -1">
  150. <div class="judge-box" :class="[TaskModel == 'ANSWER'?'notAllow':'']">
  151. <a
  152. :class="[
  153. 'right-btn',
  154. curQue.Bookanswer[indexs].answer == 'right' ? 'active' : '',
  155. ]"
  156. @click="handleSelectJudge('right', indexs)"
  157. ></a>
  158. <a
  159. :class="[
  160. 'error-btn',
  161. curQue.Bookanswer[indexs].answer == 'error' ? 'active' : '',
  162. ]"
  163. @click="handleSelectJudge('error', indexs)"
  164. ></a>
  165. </div>
  166. </template>
  167. <template v-if="dataType.indexOf('sentence_record_chs') > -1">
  168. <template v-if="dataType.indexOf('sentence_input_chs') != -1">
  169. <Soundrecord
  170. @handleWav="handleWav"
  171. :answerRecordList="curQue.Bookanswer[indexs].recordList"
  172. :tmIndex="indexs"
  173. :TaskModel="TaskModel"
  174. type="normal"
  175. v-if="items.IsRecord"
  176. />
  177. </template>
  178. <template v-else>
  179. <Soundrecord
  180. @handleWav="handleWav"
  181. :answerRecordList="curQue.Bookanswer[indexs].recordList"
  182. :tmIndex="indexs"
  183. :TaskModel="TaskModel"
  184. type="mini"
  185. class="luyin-box"
  186. v-if="items.IsRecord"
  187. />
  188. </template>
  189. </template>
  190. </li>
  191. </ul>
  192. </div>
  193. </template>
  194. <script>
  195. import Soundrecord from "../preview/Soundrecord.vue"; // 录音模板
  196. import EditDiv from "../preview/EditDiv.vue"
  197. export default {
  198. components: { Soundrecord, EditDiv },
  199. props: ["curQue","TaskModel"],
  200. data() {
  201. return {
  202. audio: new Audio(),
  203. oldsrc: "", // 存储播放音频的src 用来比对是否点击的是同一个音频
  204. palyClass: "",
  205. dataType: [], // 题型
  206. chsFhList: [",", "。", "“", ":", "》", "《", "?", "!", ";"],
  207. noFont: ["~", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")"], // 对应不要拼音字体
  208. answerList: [],
  209. };
  210. },
  211. computed: {},
  212. watch: {},
  213. //方法集合
  214. methods: {
  215. // input 输入时
  216. handleInput(e) {
  217. e.target.value = e.target.value ? e.target.value.trim() : "";
  218. },
  219. handlePlayVoice(url) {
  220. let _this = this;
  221. if (!url) {
  222. return;
  223. }
  224. if (!this.audio.paused && this.oldsrc == url) {
  225. this.audio.pause();
  226. } else if (this.audio.paused && this.oldsrc == url) {
  227. this.audio.play();
  228. } else {
  229. _this.audio.pause();
  230. _this.audio.load();
  231. _this.audio.src = url;
  232. _this.oldsrc = url;
  233. _this.audio.loop = false;
  234. _this.audio.play();
  235. }
  236. },
  237. // 处理数据
  238. handleData() {
  239. let _this = this;
  240. this.dataType = [];
  241. this.curQue.fn_list.forEach((item) => {
  242. if (item.isFn) {
  243. _this.dataType.push(item.type);
  244. }
  245. });
  246. if (!this.curQue.Bookanswer) {
  247. let answerList = []
  248. let curCorrect = [];
  249. this.curQue.option.forEach((item) => {
  250. if (this.dataType.indexOf("sentence_input_chs") != -1) {
  251. answerList = []
  252. item.answer.forEach((it) => {
  253. answerList.push({
  254. chs: "",
  255. pinyin: "",
  256. });
  257. });
  258. }
  259. curCorrect.push({
  260. answer: "",
  261. recordList: [],
  262. answerList: answerList
  263. });
  264. });
  265. this.$set(this.curQue, "Bookanswer", curCorrect);
  266. }
  267. let curQue = JSON.parse(JSON.stringify(this.curQue));
  268. curQue.option.forEach((dItem, dIndex) => {
  269. let paraArr = [];
  270. let inputNumber = 0
  271. dItem.detail.wordsList.forEach((sItem, sIndex) => {
  272. this.mergeWordSymbol(dItem.detail.wordsList, sItem, sIndex);
  273. let obj = {
  274. pinyin: sItem.pinyin,
  275. chs: sItem.chs,
  276. isShow: sItem.isShow,
  277. inputNumber: sItem.chs.indexOf('__')>-1?inputNumber:''
  278. };
  279. paraArr.push(obj);
  280. if(sItem.chs.indexOf('__')>-1){
  281. inputNumber++
  282. }
  283. });
  284. this.$set(_this.curQue.option[dIndex].detail, "resArr", paraArr);
  285. });
  286. },
  287. //词和标点合一起
  288. mergeWordSymbol(sItem, wItem, curIndex) {
  289. let leg = sItem.length;
  290. if (curIndex < leg - 1) {
  291. if (this.chsFhList.indexOf(wItem.chs) > -1) {
  292. wItem.isShow = false;
  293. } else {
  294. wItem.isShow = true;
  295. }
  296. }
  297. },
  298. // 判断题选择
  299. handleSelectJudge(obj, index) {
  300. if(!this.TaskModel||this.TaskModel!='ANSWER'){
  301. this.curQue.Bookanswer[index].answer = obj
  302. }
  303. },
  304. handleWav(list, tmIndex) {
  305. tmIndex = tmIndex ? tmIndex : 0;
  306. this.$set(this.curQue.Bookanswer[tmIndex], "recordList", list);
  307. },
  308. handleDatas(str, type) {
  309. str = str.trim();
  310. str = str.replace(/_{2,}/g, "^ ");
  311. str =
  312. type == "hanzi" ? str.replace(/\s+/g, "") : str.replace(/\s+/g, " ");
  313. let resArr = type == "hanzi" ? str.split("") : str.split(/\s+/);
  314. return resArr;
  315. },
  316. changeAnswerList(e, index, type, indexs) {
  317. if (type == "pinyin") {
  318. this.curQue.Bookanswer[index].answerList[indexs].pinyin += e.target.innerHTML;
  319. } else {
  320. this.curQue.Bookanswer[index].answerList[indexs].chs += e.target.innerHTML;
  321. }
  322. },
  323. handleFalse(){
  324. return false;
  325. }
  326. },
  327. //生命周期 - 创建完成(可以访问当前this实例)
  328. created() {
  329. this.handleData();
  330. },
  331. //生命周期 - 挂载完成(可以访问DOM元素)
  332. mounted() {
  333. let _this = this;
  334. _this.audio.addEventListener("play", function () {
  335. _this.palyClass = "active";
  336. });
  337. _this.audio.addEventListener("pause", function () {
  338. _this.palyClass = "";
  339. });
  340. _this.audio.addEventListener("ended", function () {
  341. _this.palyClass = "";
  342. });
  343. },
  344. beforeCreate() {}, //生命周期 - 创建之前
  345. beforeMount() {}, //生命周期 - 挂载之前
  346. beforeUpdate() {}, //生命周期 - 更新之前
  347. updated() {}, //生命周期 - 更新之后
  348. beforeDestroy() {}, //生命周期 - 销毁之前
  349. destroyed() {}, //生命周期 - 销毁完成
  350. activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
  351. };
  352. </script>
  353. <style lang='scss' scoped>
  354. //@import url(); 引入公共css类
  355. .Big-Book-prev-Textdes {
  356. width: 100%;
  357. h2 {
  358. font-weight: normal;
  359. font-size: 16px;
  360. line-height: 150%;
  361. color: #000000;
  362. margin: 0 2px 8px 2px;
  363. }
  364. ul {
  365. display: flex;
  366. flex-flow: wrap;
  367. justify-content: start;
  368. list-style: none;
  369. li {
  370. width: 100%;
  371. background: #ffffff;
  372. border: 1px solid rgba(0, 0, 0, 0.1);
  373. box-sizing: border-box;
  374. border-radius: 8px;
  375. display: flex;
  376. align-items: center;
  377. padding: 8px 12px;
  378. margin-bottom: 8px;
  379. > b {
  380. width: 24px;
  381. line-height: 24px;
  382. font-size: 16px;
  383. text-align: center;
  384. margin-right: 8px;
  385. font-weight: 400;
  386. color: #ffffff;
  387. // margin-top: 4px;
  388. font-family: "FZJCGFKTK";
  389. border-radius: 50%;
  390. }
  391. > p {
  392. width: 24px;
  393. height: 24px;
  394. cursor: pointer;
  395. background: url("../../../assets/newImage/common/icon-voice.png") left
  396. center no-repeat;
  397. background-size: 24px;
  398. margin: 0px 8px 0 0;
  399. &.active {
  400. background: url("../../../assets/newImage/common/icon-voice-play-zise.png")
  401. left center no-repeat;
  402. background-size: 24px;
  403. }
  404. }
  405. .item-content {
  406. flex: 1;
  407. .chs_pinyin {
  408. display: flex;
  409. margin-left: 8px;
  410. .input {
  411. margin-left: 16px;
  412. margin-right: 8px;
  413. min-width: 50px;
  414. border-bottom: 1px solid black;
  415. }
  416. .pinyin {
  417. font-family: "GB-PINYINOK-B";
  418. font-size: 14px;
  419. line-height: 130%;
  420. color: rgba(0, 0, 0, 0.6);
  421. margin-top: 8px;
  422. }
  423. .chs {
  424. font-family: "FZJCGFKTK";
  425. font-style: normal;
  426. font-weight: normal;
  427. font-size: 20px;
  428. line-height: 150%;
  429. color: #000000;
  430. }
  431. p {
  432. margin: 0;
  433. }
  434. }
  435. .content-con {
  436. font-size: 20px;
  437. line-height: 150%;
  438. color: #000000;
  439. font-family: "FZJCGFKTK";
  440. margin: 0;
  441. &.content-con-small {
  442. font-size: 16px;
  443. }
  444. }
  445. .content-en {
  446. font-weight: normal;
  447. font-size: 16px;
  448. line-height: 150%;
  449. color: #000000;
  450. font-family: "robot";
  451. }
  452. .con-box {
  453. display: flex;
  454. flex-flow: wrap;
  455. .con-item {
  456. text-align: center;
  457. padding: 0 3px;
  458. &.con-item-0 {
  459. text-align: left;
  460. padding-left: 0;
  461. }
  462. }
  463. span {
  464. display: block;
  465. }
  466. .pinyin {
  467. font-family: "GB-PINYINOK-B";
  468. font-size: 14px;
  469. line-height: 130%;
  470. color: #000000;
  471. height: 18px;
  472. &.noFont {
  473. font-family: initial;
  474. }
  475. }
  476. .synthesis-box {
  477. display: flex;
  478. }
  479. }
  480. }
  481. input {
  482. width: 68px;
  483. border: 1px solid rgba(0, 0, 0, 0.15);
  484. box-sizing: border-box;
  485. border-radius: 4px;
  486. outline: none;
  487. height: 32px;
  488. padding: 4px 8px;
  489. color: #000000;
  490. text-align: center;
  491. font-size: 16px;
  492. line-height: 150%;
  493. }
  494. .judge-box {
  495. display: flex;
  496. justify-content: center;
  497. &.notAllow{
  498. a,a.error-btn{
  499. cursor: not-allowed;
  500. }
  501. }
  502. a {
  503. width: 32px;
  504. height: 32px;
  505. background: #fff url("../../../assets/newImage/common/right-btn.png")
  506. center no-repeat;
  507. background-size: 24px;
  508. border-radius: 8px;
  509. border: 1px solid rgba(0, 0, 0, 0.1);
  510. &:hover,
  511. &.active {
  512. background-color: #e5fff0;
  513. border-color: #00c850;
  514. }
  515. }
  516. a.error-btn {
  517. background: #fff url("../../../assets/newImage/common/error-btn.png")
  518. center no-repeat;
  519. background-size: 24px;
  520. margin-left: 4px;
  521. &:hover,
  522. &.active {
  523. background-color: #ffe5e5;
  524. border-color: #de4444;
  525. }
  526. }
  527. }
  528. .luyin-box {
  529. border: 1px solid rgba(0, 0, 0, 0.1);
  530. border-radius: 8px;
  531. width: 64px;
  532. }
  533. }
  534. }
  535. }
  536. .NPC-Big-Book-preview-green {
  537. .Big-Book-prev-Textdes {
  538. b.xuhao {
  539. background: #24b99e;
  540. }
  541. }
  542. }
  543. .NPC-Big-Book-preview-brown {
  544. .Big-Book-prev-Textdes {
  545. b.xuhao {
  546. background: #bd8865;
  547. }
  548. }
  549. }
  550. </style>