Neword.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. <!-- -->
  2. <template>
  3. <div class="Big-Book-Single" v-if="curQue">
  4. <div class="Big-Book-Single-content" style="margin-top: 20px">
  5. <div class="adult-book-input-item">
  6. <span class="adult-book-lable">标题:</span>           
  7. <el-input
  8. style="width: 300px"
  9. placeholder="请输入标题"
  10. v-model="curQue.title"
  11. @blur="onBlur(curQue, 'title')"
  12. class="adult-book-input"
  13. :autosize="{ minRows: 2 }"
  14. maxlength="500"
  15. show-word-limit
  16. ></el-input>
  17. </div>
  18. <div class="adult-book-input-item">
  19. <span class="adult-book-lable">标题颜色:</span>  
  20. <div class="adult-book-main">
  21. <el-radio-group v-model="curQue.titleBg">
  22. <el-radio label="white">白色</el-radio>
  23. <el-radio label="themeColor">书的主题色</el-radio> </el-radio-group
  24. >  
  25. </div>
  26. </div>
  27. <div class="adult-book-input-item">
  28. <span class="adult-book-lable">详细信息:</span>  
  29. <div class="adult-book-main">
  30. <el-radio-group v-model="curQue.isInfor">
  31. <el-radio :label="true">有</el-radio>
  32. <el-radio :label="false">没有</el-radio> </el-radio-group
  33. >  
  34. </div>
  35.       
  36. </div>
  37. <div class="adult-book-input-item">
  38. <span class="adult-book-lable">预览展开:</span>  
  39. <div class="adult-book-main">
  40. <el-radio-group v-model="curQue.isWordShow">
  41. <el-radio :label="true">是</el-radio>
  42. <el-radio :label="false">否</el-radio> </el-radio-group
  43. >  
  44. </div>
  45.       
  46. </div>
  47. <div class="adult-book-input-item">
  48. <span class="adult-book-lable">题目音频:</span>
  49. <Upload
  50. :changeFillId="changeMp3"
  51. :datafileList="curQue.mp3_list"
  52. :filleNumber="mp3Number"
  53. :uploadType="'mp3'"
  54. :handleMp3Base64="handleChange"
  55. />
  56. </div>
  57. <div class="adult-book-input-item">
  58. <span class="adult-book-lable">题目lrc:</span>
  59. <Upload
  60. :changeFillId="changeLrc"
  61. :datafileList="curQue.lrc_list"
  62. :filleNumber="mp3Number"
  63. :uploadType="'lrc'"
  64. />
  65. </div>
  66. <div class="lrc-box">
  67. <div
  68. v-if="this.curQue.wordTime && this.curQue.wordTime.length > 0"
  69. class="lrc-box"
  70. >
  71. <span>已有字幕时间节点</span>
  72. <el-button type="text" @click="againWordTime">重新生成</el-button>
  73. </div>
  74. <template v-else>
  75. <el-button v-if="!isWordTime" size="medium" @click="createWordTime"
  76. >自动生成字幕节点</el-button
  77. >
  78. <p v-else>字幕节点生成中...请等待</p>
  79. </template>
  80. </div>
  81. <div class="adult-book-input-item">
  82. <span class="adult-book-lable"></span>
  83. <el-button
  84. type="primary"
  85. size="small"
  86. class="distribution"
  87. @click="parseLrcFile"
  88. >
  89. 分配时间
  90. </el-button>
  91. </div>
  92. <div
  93. class="Big-Book-main"
  94. v-for="(item, index) in curQue.option"
  95. :key="'newWord' + index"
  96. style="border-bottom: 1px #ccc solid; margin-bottom: 20px"
  97. >
  98. <div
  99. class="Big-Book-main-inner"
  100. v-for="(sItem, sIndex) in item"
  101. :key="'newWord_' + sIndex"
  102. >
  103. <NewordPhraseModule
  104. :curQue="curQue"
  105. :curQueItem="sItem"
  106. :index="index"
  107. :sIndex="sIndex"
  108. :type="curQue.type"
  109. :deleteGroup="deleteGroup"
  110. />
  111. </div>
  112. <div class="addoption addoption2" @click="saddoption(item)">
  113. 添加字词
  114. </div>
  115. <el-button size="mini" type="danger" @click="delsItem(index)">
  116. 删除本组
  117. </el-button>
  118. </div>
  119. <div class="addoption" @click="addoption">添加一组</div>
  120. </div>
  121. </div>
  122. </template>
  123. <script>
  124. import Inputmodule from "../common/Inputmodule.vue";
  125. import NewordPhraseModule from "../common/NewordPhraseModule.vue";
  126. import { getWordTime, getContentFile, prepareTranscribe } from "@/api/ajax";
  127. import Upload from "../common/Upload";
  128. export default {
  129. name: "Single",
  130. props: ["curQue", "changeCurQue"],
  131. components: {
  132. Inputmodule,
  133. NewordPhraseModule,
  134. Upload,
  135. },
  136. data() {
  137. return {
  138. mp3Number: 1,
  139. isWordTime: false,
  140. data_structure: {
  141. type: "NewWord_chs",
  142. name: "生词",
  143. title: "",
  144. isInfor: true,
  145. isWordShow: true,
  146. titleBg: "themeColor", //标题背景颜色
  147. mp3_list: [],
  148. lrc_list: [],
  149. taskId: [],
  150. wordTime: null,
  151. option: [
  152. [
  153. {
  154. new_word: "",
  155. cixing: "", //词性
  156. definition_list: [""], //需要增加词性
  157. pinyin: "",
  158. img_list: [],
  159. mp3_list: [],
  160. pinyin_site: "first", //拼音位置
  161. motif_color: false, //主题色
  162. },
  163. ],
  164. ],
  165. },
  166. };
  167. },
  168. computed: {},
  169. watch: {},
  170. //方法集合
  171. methods: {
  172. onBlur(item, field) {
  173. item[field] = item[field] ? item[field].trim() : "";
  174. },
  175. addoption() {
  176. let res_data = JSON.parse(JSON.stringify(this.data_structure));
  177. let obj = res_data.option[0];
  178. obj.index = this.curQue.option.push(obj);
  179. },
  180. deleteGroup(index, sIndex) {
  181. this.$confirm("确定要删除吗?", "提示", {
  182. confirmButtonText: "确定",
  183. cancelButtonText: "取消",
  184. type: "warning",
  185. }).then(() => {
  186. if (this.curQue.option[index].length == 1) {
  187. this.$message.warning("至少剩余1个,不能全部删除");
  188. return;
  189. }
  190. this.curQue.option[index].splice(sIndex, 1);
  191. });
  192. },
  193. saddoption(item) {
  194. let con = {
  195. new_word: "",
  196. cixing: "", //词性
  197. definition_list: [""], //需要增加词性
  198. pinyin: "",
  199. img_list: [],
  200. mp3_list: [],
  201. };
  202. item.push(con);
  203. },
  204. delsItem(index) {
  205. this.$confirm("确定要删除吗?", "提示", {
  206. confirmButtonText: "确定",
  207. cancelButtonText: "取消",
  208. type: "warning",
  209. }).then(() => {
  210. this.curQue.option.splice(index, 1);
  211. });
  212. },
  213. changeMp3(fileList) {
  214. const articleImgList = JSON.parse(JSON.stringify(fileList));
  215. const articleImgRes = [];
  216. articleImgList.forEach((item) => {
  217. if (item.response) {
  218. const obj = {
  219. name: item.name,
  220. url: item.response.file_info_list[0].file_url,
  221. id: "[FID##" + item.response.file_info_list[0].file_id + "##FID]",
  222. media_duration: item.response.file_info_list[0].media_duration, //音频时长
  223. };
  224. articleImgRes.push(obj);
  225. }
  226. });
  227. this.curQue.mp3_list = JSON.parse(JSON.stringify(articleImgRes));
  228. },
  229. parseLrcFile() {
  230. let lrcList = this.curQue.lrc_list;
  231. if (lrcList.length === 0) {
  232. if (this.curQue.wordTime.length > 0) {
  233. this.handleNewwordList();
  234. } else {
  235. this.$message.warning("请先上传lrc文件或自动生成字幕节点");
  236. }
  237. } else {
  238. getContentFile("tool-ParseLRCFile", {
  239. content_type: "FILE",
  240. file_id: this.curQue.lrc_list[0].file_id,
  241. }).then(({ lrc_list }) => {
  242. let lrc_list_res = [];
  243. lrc_list.forEach((item) => {
  244. let obj = {
  245. bg: item.begin_time,
  246. ed: item.end_time,
  247. };
  248. lrc_list_res.push(obj);
  249. });
  250. this.handleNewwordList();
  251. this.curQue.wordTime = lrc_list_res;
  252. });
  253. }
  254. },
  255. handleNewwordList() {
  256. let index = 0;
  257. // let option = JSO
  258. this.curQue.option.map((item) => {
  259. item.map((sItem) => {
  260. this.$set(sItem, "index", index);
  261. index++;
  262. return sItem;
  263. });
  264. return item;
  265. });
  266. console.log(this.curQue.option);
  267. },
  268. getBase64(file) {
  269. return new Promise(function (resolve, reject) {
  270. let reader = new FileReader();
  271. let imgResult = "";
  272. reader.readAsDataURL(file);
  273. reader.onload = function () {
  274. imgResult = reader.result;
  275. };
  276. reader.onerror = function (error) {
  277. reject(error);
  278. };
  279. reader.onloadend = function () {
  280. resolve(imgResult);
  281. };
  282. });
  283. },
  284. createWordTime() {
  285. if (this.curQue.taskId) {
  286. let verseList = [];
  287. this.curQue.option.forEach((item, index) => {
  288. item.forEach((sItem, sIndex) => {
  289. verseList.push(sItem.new_word);
  290. });
  291. });
  292. if (verseList.length > 0) {
  293. this.isWordTime = true;
  294. let data = {
  295. taskId: this.curQue.taskId,
  296. verseList: JSON.stringify(verseList),
  297. matchType: "chinese",
  298. language: "ch",
  299. };
  300. getWordTime(data).then((res) => {
  301. this.curQue.wordTime = res.data.result;
  302. this.isWordTime = false;
  303. });
  304. }
  305. } else {
  306. this.$message.warning("请先上传音频");
  307. }
  308. },
  309. againWordTime() {
  310. this.isWordTime = false;
  311. this.$set(this.curQue, "wordTime", []);
  312. },
  313. // 上传音频文件
  314. handleChange(file, fileList) {
  315. let _this = this;
  316. _this.getBase64(file.raw).then((res) => {
  317. let base_res = res.split("base64,");
  318. let data = {
  319. fileName: file.raw.name,
  320. speechBase64: base_res[1],
  321. language: "ch",
  322. };
  323. prepareTranscribe(data).then((reses) => {
  324. _this.$set(_this.curQue, "taskId", reses.data.taskId);
  325. });
  326. });
  327. },
  328. changeLrc(fileList) {
  329. let lrc_list = [];
  330. fileList.forEach(({ response, name }) => {
  331. if (response) {
  332. let fileLists = response.file_info_list[0];
  333. lrc_list.push({
  334. name,
  335. duration: fileLists.media_duration,
  336. url: fileLists.file_url,
  337. id: "[FID##" + fileLists.file_id + "##FID]",
  338. file_id: fileLists.file_id,
  339. });
  340. }
  341. });
  342. this.curQue.lrc_list = lrc_list;
  343. },
  344. },
  345. //生命周期 - 创建完成(可以访问当前this实例)
  346. created() {},
  347. //生命周期 - 挂载完成(可以访问DOM元素)
  348. mounted() {
  349. if (!this.curQue) {
  350. let res_data = JSON.parse(JSON.stringify(this.data_structure));
  351. this.changeCurQue(res_data);
  352. } else {
  353. if (!this.curQue.hasOwnProperty("isInfor")) {
  354. this.$set(this.curQue, "isInfor", true);
  355. }
  356. if (!this.curQue.hasOwnProperty("isWordShow")) {
  357. this.$set(this.curQue, "isWordShow", true);
  358. }
  359. if (!this.curQue.hasOwnProperty("titleBg")) {
  360. this.$set(this.curQue, "titleBg", "themeColor");
  361. }
  362. if (!this.curQue.hasOwnProperty("mp3_list")) {
  363. this.$set(this.curQue, "mp3_list", []);
  364. }
  365. if (!this.curQue.hasOwnProperty("lrc_list")) {
  366. this.$set(this.curQue, "lrc_list", []);
  367. }
  368. if (!this.curQue.hasOwnProperty("taskId")) {
  369. this.$set(this.curQue, "taskId", "");
  370. }
  371. if (!this.curQue.hasOwnProperty("wordTime")) {
  372. this.$set(this.curQue, "wordTime", null);
  373. }
  374. // let data = JSON.parse(JSON.stringify(this.curQue));
  375. this.curQue.option.forEach((item) => {
  376. if (!item[0].pinyin_site) {
  377. item[0].pinyin_site = "first"; //拼音位置
  378. }
  379. if (!item[0].motif_color) {
  380. item[0].motif_color = false; //主题色
  381. }
  382. });
  383. // this.curQue = JSON.parse(JSON.stringify(data));
  384. }
  385. },
  386. beforeCreate() {}, //生命周期 - 创建之前
  387. beforeMount() {}, //生命周期 - 挂载之前
  388. beforeUpdate() {}, //生命周期 - 更新之前
  389. updated() {}, //生命周期 - 更新之后
  390. beforeDestroy() {}, //生命周期 - 销毁之前
  391. destroyed() {}, //生命周期 - 销毁完成
  392. activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
  393. };
  394. </script>
  395. <style lang='scss' scope>
  396. //@import url(); 引入公共css类
  397. .Big-Book-Single {
  398. &-content {
  399. &.m {
  400. display: flex;
  401. justify-content: flex-start;
  402. align-items: flex-start;
  403. }
  404. .Big-Book-title {
  405. font-size: 16px;
  406. line-height: 40px;
  407. color: #000;
  408. margin-right: 15px;
  409. }
  410. .Big-Book-main {
  411. background: rgba(230, 229, 229, 0.3);
  412. border: 1px #999 solid;
  413. border-radius: 8px;
  414. padding: 20px;
  415. > div {
  416. margin-bottom: 10px;
  417. &.Big-Book-pinyin {
  418. display: flex;
  419. justify-content: flex-start;
  420. align-items: center;
  421. }
  422. }
  423. .Big-Book-main-inner {
  424. }
  425. }
  426. }
  427. .addoption {
  428. width: 565px;
  429. height: 40px;
  430. left: 40px;
  431. top: 304px;
  432. background: #f3f3f3;
  433. border: 1px dashed rgba(0, 0, 0, 0.15);
  434. box-sizing: border-box;
  435. border-radius: 4px;
  436. text-align: center;
  437. line-height: 40px;
  438. cursor: pointer;
  439. &.addoption2 {
  440. width: 200px;
  441. }
  442. }
  443. .Big-Book-con {
  444. padding-bottom: 6px;
  445. border-bottom: 1px dashed rgba(0, 0, 0, 0.15);
  446. }
  447. }
  448. </style>
  449. <style lang="scss">
  450. </style>