writeTableNew.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. <template>
  2. <div :class="['writeTable']" v-if="data">
  3. <div class="writeTop">
  4. <template v-if="editCardflag">
  5. <div class="left">
  6. <UploadDrag
  7. :fileList="data.left.fileList"
  8. @changeFillId="changeFillId"
  9. v-if="data.left.fileList.length === 0"
  10. :disabled="is_preview"
  11. ></UploadDrag>
  12. <div class="item-image" v-else>
  13. <el-image
  14. style="width: 536px; height: 536px"
  15. :src="data.left.fileList[0].fileUrl"
  16. :preview-src-list="[data.left.fileList[0].fileUrl]"
  17. fit="contain"
  18. />
  19. <span v-if="!is_preview" class="item-image-del" @click="handleDeleteImg"
  20. ><i class="el-icon-delete"></i
  21. ></span>
  22. </div>
  23. <el-input class="item-con" v-model="data.left.con" placeholder="输入" @blur="handleBlurCon"></el-input>
  24. <a class="del-btn" @click="handleDelItem"><i class="el-icon-delete"></i></a>
  25. </div>
  26. <div class="right">
  27. <label>释义</label>
  28. <el-input type="textarea" :rows="6" v-model="data.right.definition" placeholder="请输入"></el-input>
  29. <label>搭配</label>
  30. <el-input type="textarea" :rows="6" v-model="data.right.collocation" placeholder="请输入"></el-input>
  31. <label>例句</label>
  32. <el-input type="textarea" :rows="6" v-model="data.right.exampleSent" placeholder="请输入"></el-input>
  33. </div>
  34. </template>
  35. <template v-else>
  36. <div class="left" :class="[data.left.fileList.length === 0 ? 'left-big' : '']">
  37. <div class="item-image" v-if="data.left.fileList.length > 0">
  38. <el-image
  39. style="width: 536px; height: 536px"
  40. :src="data.left.fileList[0].fileUrl"
  41. :preview-src-list="[data.left.fileList[0].fileUrl]"
  42. fit="contain"
  43. />
  44. </div>
  45. <h2 :class="['con-preview', data.left.fileList.length === 0 ? 'con-preview-big' : '']">
  46. {{ data.left.con }}
  47. </h2>
  48. </div>
  49. <div class="right right-preview">
  50. <div class="hz-box">
  51. <div class="hz-item" v-for="(itemh, indexh) in data.right.hz_info" :key="indexh">
  52. <p>{{ data.right.pinyin[indexh] ? data.right.pinyin[indexh] : '' }}</p>
  53. <Strockplay
  54. className="adult-strockplay"
  55. :Book_text="itemh.con"
  56. :playStorkes="true"
  57. :strokePlayColor="'#D65353'"
  58. :strokeColor="'#000000'"
  59. :palyWidth="'18px'"
  60. :BoxbgType="'0'"
  61. :curItem="itemh.hzDetail.hz_json"
  62. :targetDiv="'writeTops-item-' + pageNumber + '-' + indexh + '-' + itemh.con"
  63. :class="[indexh !== 0 ? 'writeTop-item-noLeft' : '']"
  64. class="writeTop-item"
  65. />
  66. </div>
  67. </div>
  68. <AudioPlay :file-id="data.right.audio_file" v-if="data.right.audio_file" />
  69. <div class="definition-box">
  70. <div v-if="data.right.definition">
  71. <label>释义:</label>
  72. <p>{{ data.right.definition }}</p>
  73. </div>
  74. <div v-if="data.right.collocation">
  75. <label>搭配:</label>
  76. <p>{{ data.right.collocation }}</p>
  77. </div>
  78. <div v-if="data.right.exampleSent">
  79. <label>例句:</label>
  80. <p>{{ data.right.exampleSent }}</p>
  81. </div>
  82. </div>
  83. </div>
  84. </template>
  85. </div>
  86. </div>
  87. </template>
  88. <script>
  89. //这里可以导入其它文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
  90. import StrockplayredlineTable from '../../components/corpus/StrockplayredlineTable.vue';
  91. import Strockplay from '../../components/corpus/Strockplay.vue';
  92. import Strockred from '../../components/corpus/Strockred.vue';
  93. import FreewriteLettle from '../../components/corpus/FreewriteLettle.vue';
  94. import UploadDrag from './UploadDrag.vue';
  95. import AudioPlay from './AudioPlay.vue';
  96. const HanziWriter = require('hanzi-writer');
  97. import { getLogin, getHZChineseInfo } from '@/api/api';
  98. export default {
  99. //import引入的组件需要注入到对象中才能使用
  100. components: {
  101. StrockplayredlineTable,
  102. Strockplay,
  103. Strockred,
  104. FreewriteLettle,
  105. UploadDrag,
  106. AudioPlay,
  107. },
  108. props: ['dataConfig', 'data', 'pageNumber', 'totalNumber', 'editCardflag', 'none', 'is_preview', 'infoObj'],
  109. data() {
  110. //这里存放数据
  111. return {
  112. ifFreeShow: false,
  113. activeIndex: null,
  114. activeColIndex: null,
  115. fileList: [],
  116. info: {
  117. definition: '',
  118. collocation: '',
  119. exampleSent: '',
  120. },
  121. writer: null,
  122. audio_file: '',
  123. loading: false,
  124. };
  125. },
  126. //计算属性 类似于data概念
  127. computed: {},
  128. //监控data中数据变化
  129. watch: {
  130. pageNumber: {
  131. handler: function (val, oldVal) {
  132. if (val != oldVal) {
  133. this.initHanziwrite();
  134. }
  135. },
  136. deep: true,
  137. },
  138. },
  139. //方法集合
  140. methods: {
  141. changePraShow() {
  142. this.ifFreeShow = false;
  143. },
  144. closeifFreeShow(data, rowIndex, colIndex) {
  145. this.ifFreeShow = false;
  146. this.$forceUpdate();
  147. },
  148. freeWrite(item, row, col) {
  149. this.ifFreeShow = true;
  150. this.activeIndex = row;
  151. this.activeColIndex = col;
  152. // this.currentHz = this.curQue.option[indexs].rightOption[rightindex].con;
  153. if (item) {
  154. this.currenHzData = item;
  155. } else {
  156. this.currenHzData = {};
  157. }
  158. },
  159. ExerciseChangeCurQue(answer, rowIndex, colIndex) {
  160. if (answer) {
  161. this.data.list[rowIndex][colIndex].strokes_image_url = answer.strokes_image_url;
  162. this.data.list[rowIndex][colIndex].history = answer.history;
  163. this.$forceUpdate();
  164. }
  165. },
  166. changeFillId(file, fileList) {
  167. let obj = {
  168. name: file.name,
  169. fileId: file.file_id,
  170. fileUrl: file.file_url_open,
  171. };
  172. this.data.left.fileList.push(obj);
  173. },
  174. handleDeleteImg() {
  175. this.data.left.fileList = [];
  176. },
  177. initHanziwrite() {
  178. if (this.data.left.con.trim()) {
  179. this.loading = true;
  180. let MethodName = 'tool-TextToVoiceFile';
  181. let datas = {
  182. text: this.data.left.con.trim(),
  183. };
  184. getLogin(MethodName, datas)
  185. .then((res) => {
  186. this.loading = false;
  187. if (res.status === 1) {
  188. this.data.right.audio_file = res.file_id;
  189. }
  190. })
  191. .catch(() => {
  192. this.loading = false;
  193. });
  194. }
  195. },
  196. handleDelItem() {
  197. this.$emit('handleDelItem', this.pageNumber - 1);
  198. },
  199. // 获取数据
  200. handleBlurCon() {
  201. this.loading = true;
  202. let con = this.data.left.con.trim();
  203. let MethodName = 'hz_resource_manager-GetMultHZStrokesContent';
  204. let data = {
  205. hz_str: con,
  206. };
  207. getLogin(MethodName, data)
  208. .then((res) => {
  209. this.loading = false;
  210. for (let key in res) {
  211. if (key != 'status' && key != ',' && res[key]) {
  212. res[key] = JSON.parse(res[key]);
  213. }
  214. }
  215. let hzDetailList = res;
  216. let hz_list = [];
  217. con.split('').forEach((items) => {
  218. let res = JSON.parse(JSON.stringify(hzDetailList[items]));
  219. let obj = {
  220. con: items,
  221. hzDetail: {
  222. hz_json: res,
  223. },
  224. };
  225. hz_list.push(obj);
  226. });
  227. this.data.right.hz_info = hz_list;
  228. this.data.right.pinyin = cnchar.spell(con, 'array', 'low', 'tone');
  229. let MethodName = 'tool-TextToVoiceFile';
  230. let datas = {
  231. text: con,
  232. };
  233. getLogin(MethodName, datas).then((res) => {
  234. if (res.status === 1) {
  235. this.data.right.audio_file = res.file_id;
  236. }
  237. });
  238. console.log(this.data);
  239. })
  240. .catch(() => {
  241. this.loading = false;
  242. });
  243. },
  244. },
  245. //生命周期 - 创建完成(可以访问当前this实例)
  246. created() {
  247. this.initHanziwrite();
  248. },
  249. //生命周期 - 挂载完成(可以访问DOM元素)
  250. mounted() {
  251. // let _this = this;
  252. // _this.$nextTick(() => {
  253. // if (_this.data.hz_info && _this.data.hz_info.length === 1) {
  254. // _this.initHanziwrite();
  255. // }
  256. // });
  257. },
  258. //生命周期-创建之前
  259. beforeCreated() {},
  260. //生命周期-挂载之前
  261. beforeMount() {},
  262. //生命周期-更新之前
  263. beforUpdate() {},
  264. //生命周期-更新之后
  265. updated() {},
  266. //生命周期-销毁之前
  267. beforeDestory() {},
  268. //生命周期-销毁完成
  269. destoryed() {},
  270. //如果页面有keep-alive缓存功能,这个函数会触发
  271. activated() {},
  272. };
  273. </script>
  274. <style lang="scss" scoped>
  275. .writeTable {
  276. width: 1208px;
  277. margin: 0 auto 8px auto;
  278. // height: 842px;
  279. box-sizing: border-box;
  280. .writeTop {
  281. height: 800px;
  282. display: flex;
  283. column-gap: 8px;
  284. .left,
  285. .right {
  286. width: 600px;
  287. height: 100%;
  288. padding: 32px;
  289. border-radius: 24px;
  290. background: #fff;
  291. box-sizing: border-box;
  292. position: relative;
  293. }
  294. .left-big {
  295. display: flex;
  296. align-items: center;
  297. justify-content: center;
  298. }
  299. .del-btn {
  300. cursor: pointer;
  301. border-radius: 8px;
  302. background: #f56767;
  303. padding: 8px;
  304. position: absolute;
  305. right: 24px;
  306. bottom: 24px;
  307. color: #fff;
  308. }
  309. .right {
  310. display: flex;
  311. align-items: center;
  312. flex-flow: wrap;
  313. padding: 120px 86px;
  314. row-gap: 8px;
  315. label {
  316. width: 100%;
  317. color: #4e5969;
  318. font-size: 14px;
  319. font-weight: 400;
  320. line-height: 22px;
  321. height: 22px;
  322. }
  323. :deep .el-textarea {
  324. height: 140px;
  325. }
  326. }
  327. .right-preview {
  328. padding: 72px;
  329. display: block;
  330. .hz-box {
  331. justify-content: center;
  332. width: 100%;
  333. .hz-item {
  334. text-align: center;
  335. :deep .strockplayInner {
  336. width: 98px;
  337. height: 98px;
  338. }
  339. p {
  340. color: #de4444;
  341. font-feature-settings: 'cv01' on;
  342. font-family: League;
  343. font-size: 20px;
  344. line-height: 120%;
  345. margin-bottom: 8px;
  346. }
  347. }
  348. }
  349. :deep .audio-wrapper {
  350. margin: 24px auto;
  351. border-radius: 40px;
  352. background: #f3f3f3;
  353. padding: 16px;
  354. width: 56px;
  355. height: 56px;
  356. box-sizing: border-box;
  357. cursor: pointer;
  358. .voice-play {
  359. width: 24px;
  360. height: 24pxs;
  361. }
  362. }
  363. .definition-box {
  364. white-space: pre;
  365. > div {
  366. display: flex;
  367. margin-bottom: 16px;
  368. label,
  369. p {
  370. width: 40px;
  371. color: #000;
  372. font-size: 24px;
  373. font-weight: 400;
  374. line-height: 150%;
  375. }
  376. label {
  377. width: 68px;
  378. }
  379. }
  380. }
  381. }
  382. .item-image {
  383. position: relative;
  384. background: #f2f3f5;
  385. border-radius: 8px;
  386. overflow: hidden;
  387. .item-image-del {
  388. position: absolute;
  389. top: 8px;
  390. right: 8px;
  391. width: 16px;
  392. height: 16px;
  393. display: block;
  394. cursor: pointer;
  395. background-color: #ffffff;
  396. color: #ee3232;
  397. padding: 8px;
  398. border-radius: 50%;
  399. box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25);
  400. }
  401. }
  402. .item-con {
  403. margin-top: 74px;
  404. :deep .el-input__inner {
  405. color: rgba(0, 0, 0, 1);
  406. text-align: center;
  407. font-size: 80px;
  408. font-weight: 400;
  409. line-height: 100%;
  410. height: 80px;
  411. font-family: 'FZJCGFKTK';
  412. border: none;
  413. }
  414. }
  415. .con-preview {
  416. margin-top: 74px;
  417. color: #000;
  418. text-align: center;
  419. font-family: 'FZJCGFKTK';
  420. font-size: 80px;
  421. font-weight: 400;
  422. line-height: 100%;
  423. &-big {
  424. font-size: 144px;
  425. }
  426. }
  427. .writeTop-row {
  428. display: flex;
  429. justify-content: center;
  430. }
  431. }
  432. .writeTop-nopadding {
  433. padding-top: 0;
  434. height: 842px;
  435. }
  436. .item-info {
  437. display: flex;
  438. width: 100%;
  439. padding: 0 46px 8px 46px;
  440. column-gap: 16px;
  441. box-sizing: border-box;
  442. &-left {
  443. .writeTop-item {
  444. width: 98px;
  445. height: 98px;
  446. :deep .strock-play-box {
  447. width: 18px !important;
  448. height: 18px !important;
  449. }
  450. :deep .playStorkes-btn {
  451. width: 18px !important;
  452. height: 18px !important;
  453. }
  454. &-small {
  455. width: 62px;
  456. height: 62px;
  457. :deep .strock-play-box {
  458. width: 11px !important;
  459. height: 11px !important;
  460. }
  461. :deep .playStorkes-btn {
  462. width: 11px !important;
  463. height: 11px !important;
  464. }
  465. }
  466. }
  467. &-long {
  468. width: 100%;
  469. }
  470. }
  471. &-right {
  472. flex: 1;
  473. }
  474. :deep .el-textarea__inner {
  475. resize: none;
  476. background-color: #f3f3f3;
  477. border: none;
  478. outline: none;
  479. }
  480. .voice-box {
  481. width: 100%;
  482. height: 32px;
  483. display: flex;
  484. align-items: center;
  485. justify-content: center;
  486. column-gap: 4px;
  487. img {
  488. width: 24px;
  489. height: 24px;
  490. }
  491. span {
  492. font-family: League;
  493. font-size: 16px;
  494. font-weight: 400;
  495. color: #de4444;
  496. }
  497. }
  498. .item-info-row {
  499. display: flex;
  500. column-gap: 11px;
  501. margin-bottom: 6px;
  502. :deep .el-input__inner {
  503. background-color: #f3f3f3;
  504. border: none;
  505. outline: none;
  506. height: 32px;
  507. }
  508. }
  509. .item-info-half,
  510. .item-info-all {
  511. width: 50%;
  512. display: flex;
  513. font-size: 14px;
  514. line-height: 22px;
  515. height: 22px;
  516. }
  517. .item-info-all {
  518. width: 100%;
  519. }
  520. }
  521. .hz-box {
  522. display: flex;
  523. width: max-content;
  524. }
  525. .writeTop-item {
  526. border: 1px solid #de4444;
  527. }
  528. .writeTop-item-noLeft {
  529. border-left: none;
  530. }
  531. .writeBottom {
  532. display: flex;
  533. width: 100%;
  534. justify-content: space-between;
  535. padding: 0 38px;
  536. box-sizing: border-box;
  537. position: relative;
  538. span {
  539. font-weight: 500;
  540. font-size: 10px;
  541. line-height: 14px;
  542. color: #000000;
  543. opacity: 0.2;
  544. }
  545. b {
  546. font-weight: 400;
  547. font-size: 14px;
  548. line-height: 14px;
  549. color: #000000;
  550. width: 60px;
  551. text-align: center;
  552. position: absolute;
  553. left: 50%;
  554. margin-left: -30px;
  555. top: 0px;
  556. }
  557. a {
  558. font-weight: 500;
  559. font-size: 12px;
  560. line-height: 14px;
  561. color: #000000;
  562. opacity: 0.2;
  563. }
  564. }
  565. .tian-div {
  566. width: 100%;
  567. height: 100%;
  568. position: relative;
  569. .tian {
  570. width: 100%;
  571. height: 100%;
  572. }
  573. img {
  574. width: 100%;
  575. height: 100%;
  576. position: absolute;
  577. left: 0;
  578. top: 0;
  579. }
  580. }
  581. .practiceBox {
  582. position: fixed;
  583. left: 0;
  584. top: 0;
  585. z-index: 100100;
  586. width: 100%;
  587. height: 100vh;
  588. background: rgba(0, 0, 0, 0.19);
  589. box-sizing: border-box;
  590. overflow: hidden;
  591. overflow-y: auto;
  592. &.practiceBoxStrock {
  593. display: flex;
  594. justify-content: center;
  595. align-items: center;
  596. padding-top: 0px;
  597. }
  598. }
  599. .punctuation-box {
  600. position: relative;
  601. width: 100%;
  602. height: 100%;
  603. .character-target-div {
  604. position: absolute;
  605. width: 100%;
  606. height: 100%;
  607. top: 0;
  608. left: 0;
  609. .svg-icon {
  610. width: 100%;
  611. height: 100%;
  612. }
  613. }
  614. h3 {
  615. position: absolute;
  616. width: 100%;
  617. height: 100%;
  618. top: 0;
  619. left: 0;
  620. font-family: FZJCGFKTK;
  621. text-align: center;
  622. font-weight: normal;
  623. }
  624. }
  625. }
  626. </style>