detail.tsx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. import {
  2. defineComponent,
  3. nextTick,
  4. onMounted,
  5. reactive,
  6. ref,
  7. watch
  8. } from 'vue';
  9. import styles from './index.module.less';
  10. import {
  11. NButton,
  12. // NBreadcrumb,
  13. // NBreadcrumbItem,
  14. // NScrollbar,
  15. NSlider,
  16. NSpace,
  17. NSpin
  18. } from 'naive-ui';
  19. import iconT from '/src/views/content-information/images/icon-t.png';
  20. import iconAddT from '/src/views/content-information/images/icon-add-t.png';
  21. import iconPlusT from '/src/views/content-information/images/icon-plus-t.png';
  22. import {
  23. api_lessonCoursewareDetail_listKnowledge,
  24. api_lessonCoursewareKnowledgeDetail
  25. } from '/src/views/content-information/api';
  26. import TheEmpty from '/src/components/TheEmpty';
  27. // import { PageEnum } from '/src/enums/pageEnum';
  28. import { useSpeak } from '/src/views/content-information/useSpeak';
  29. export default defineComponent({
  30. name: 'cotnent-knowledge',
  31. props: {
  32. id: {
  33. type: String,
  34. default: ''
  35. },
  36. type: {
  37. type: String,
  38. default: ''
  39. },
  40. activeStatus: {
  41. type: Boolean,
  42. default: false
  43. }
  44. },
  45. emits: ['close', 'confirm'],
  46. setup(props, { expose }) {
  47. const content = ref(false);
  48. const musicContentRef = ref();
  49. const speakMusicContent =
  50. 'musicContent' + new Date().getTime() + Math.floor(Math.random() * 100);
  51. const selectionCouser =
  52. 'selectionCouser' +
  53. new Date().getTime() +
  54. Math.floor(Math.random() * 100);
  55. const speak = useSpeak(speakMusicContent, selectionCouser);
  56. const state = reactive({
  57. fontSize: 18,
  58. tableList: [] as any,
  59. selectKey: null,
  60. details: {} as any,
  61. domString: '',
  62. display: 'block'
  63. });
  64. const getDetail = async () => {
  65. content.value = true;
  66. try {
  67. const { data } = await api_lessonCoursewareKnowledgeDetail({
  68. id: props.id
  69. });
  70. state.details = data;
  71. content.value = false;
  72. nextTick(async () => {
  73. // 使用 DOMParser 解析 HTML 字符串
  74. // 获取 HTML 字符串
  75. // const htmlString = tempDiv.innerHTML;
  76. // console.log(htmlString);
  77. const parser = new DOMParser();
  78. const doc = parser.parseFromString(state.details.desc, 'text/html');
  79. const childNodes = doc.body.childNodes;
  80. childNodes?.forEach((node: any) => {
  81. node?.classList.add('only-child-select');
  82. });
  83. // 提取并分割 HTML 文档中的内容
  84. console.log(
  85. speakMusicContent,
  86. document.querySelector('#' + speakMusicContent),
  87. processNode(doc.body)
  88. );
  89. // state.details.desc = '';
  90. // state.display = 'none';
  91. const node: any = speak.processNode(doc.body);
  92. document.querySelector('#' + speakMusicContent)?.appendChild(node);
  93. });
  94. } catch {
  95. //
  96. }
  97. content.value = false;
  98. };
  99. const onStopAll = (type: 'play' | 'pause' | 'pre' | 'next' | 'favitor') => {
  100. speak.onCloseSpeak();
  101. };
  102. onMounted(() => {
  103. getDetail();
  104. });
  105. watch(
  106. () => props.activeStatus,
  107. () => {
  108. if (!props.activeStatus) {
  109. onStopAll('pause');
  110. }
  111. }
  112. );
  113. expose({
  114. handleChangeAudio: onStopAll
  115. });
  116. return () => (
  117. <div
  118. class={[
  119. styles.containerDetail,
  120. props.type === 'preview' && styles.detailPreview
  121. ]}>
  122. {/* <div class={styles.detail2}> */}
  123. <div class={styles.contentWrap}>
  124. <div class={styles.musicStaff}>
  125. <div class={styles.musicTitleRight}>
  126. {speak.isSpeak.value ? (
  127. <span class={styles.textClose} onClick={speak.onCloseSpeak}>
  128. <i class={styles.icon}></i>关闭朗读
  129. </span>
  130. ) : (
  131. <span class={styles.textRead} onClick={speak.onAllSpeak}>
  132. <i class={styles.icon}></i>全文朗读
  133. </span>
  134. )}
  135. </div>
  136. <NSpin
  137. show={content.value}
  138. ref={musicContentRef}
  139. class={
  140. !content.value && !state.details?.desc ? styles.empty : ''
  141. }>
  142. {state.details?.desc ? (
  143. <div
  144. class={styles.musicContent}
  145. id={speakMusicContent}
  146. style={{ fontSize: state.fontSize + 'px' }}>
  147. {/* 选中的内容 */}
  148. <div
  149. id={selectionCouser}
  150. class={[
  151. styles.selectionCouser,
  152. !speak.showDom.value && styles.hide
  153. ]}>
  154. <span class={styles.textStart} onClick={speak.onTextStart}>
  155. 开始朗读<i class={styles.icon}></i>
  156. </span>
  157. <span
  158. class={styles.textReadOnly}
  159. onClick={speak.onTextReadOnly}>
  160. 只读这段<i class={styles.icon}></i>
  161. </span>
  162. </div>
  163. </div>
  164. ) : (
  165. ''
  166. )}
  167. {!content.value && !state.details?.desc && <TheEmpty />}
  168. </NSpin>
  169. </div>
  170. <div class={styles.changeSizeSection}>
  171. <img src={iconT} class={styles.iconT} />
  172. <img
  173. src={iconAddT}
  174. class={styles.iconAddT}
  175. onClick={() => {
  176. if (state.fontSize >= 32) return;
  177. state.fontSize += 1;
  178. }}
  179. />
  180. <NSlider
  181. v-model:value={state.fontSize}
  182. vertical
  183. min={12}
  184. placement="left"
  185. max={32}
  186. />
  187. <img
  188. src={iconPlusT}
  189. class={styles.iconPlusT}
  190. onClick={() => {
  191. if (state.fontSize <= 12) return;
  192. state.fontSize -= 1;
  193. }}
  194. />
  195. </div>
  196. </div>
  197. {/* </div> */}
  198. </div>
  199. );
  200. }
  201. });