videoOperation.vue 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. <!-- 新增编辑视频 -->
  2. <template>
  3. <div class="app-container">
  4. <div style="display: flex">
  5. <el-button type="primary" @click="formSubmit">保存</el-button>
  6. <el-button type="primary" @click="addSource">管理素材</el-button>
  7. <el-button type="info" @click="videoView">视频预览</el-button>
  8. <el-button @click="returnList">返回</el-button>
  9. </div>
  10. <!-- 节点模块编辑 -->
  11. <div class="border_box">
  12. <InteractiveVideoEditor
  13. ref="editorRef"
  14. :graphData="graphData"
  15. :videoSources="videoSources"
  16. :imageSources="imageSources"
  17. />
  18. </div>
  19. <!-- 视频预览 -->
  20. <el-dialog
  21. title="视频预览"
  22. v-model="videoViewOpen"
  23. width="1200"
  24. destroy-on-close
  25. >
  26. <XGVideoViewer
  27. :question="videoDetail.data.question"
  28. :options="videoDetail.data.optionsList"
  29. :videoUrl="videoDetail.data.uri"
  30. :autoplay="true"
  31. :autoplayMuted="false"
  32. :poster="videoDetail.data.image"
  33. @onClickOption="onClickOption"
  34. />
  35. </el-dialog>
  36. <!-- 添加素材 -->
  37. <AddSouce
  38. :open="materialOpen"
  39. :baseInfo="interactionVideoInfo"
  40. @close="formFieldsClose"
  41. />
  42. </div>
  43. </template>
  44. <script setup name="VideoOperation">
  45. import {
  46. interactionVideoUpdate,
  47. getInteractionVideoDetail,
  48. getMaterialInfoDetail,
  49. } from "@/api/interactVideo/videoManage";
  50. // 编辑器
  51. import {
  52. transformGraphdata,
  53. transfromReturnGraphdata,
  54. } from "@/hooks/transformGraphdata";
  55. import InteractiveVideoEditor from "@/components/InteractiveVideoEditor";
  56. import XGVideoViewer from "@/components/XGVideoViewer";
  57. import AddSouce from "./addSouce.vue";
  58. import { watchEffect } from "vue";
  59. const { proxy } = getCurrentInstance();
  60. const route = useRoute();
  61. // 互动视频基本信息
  62. const { interactionId } = route.query;
  63. const interactionVideoInfo = ref({});
  64. // 资源数据
  65. const videoSources = ref([]);
  66. const imageSources = ref([]);
  67. // 组件实例
  68. const editorRef = ref(null);
  69. // 默认流程图数据
  70. const graphData = ref({
  71. id: "0",
  72. type: "root-node",
  73. preNodeId: null,
  74. children: [],
  75. data: {
  76. name: "默认节点",
  77. image: "",
  78. url: "",
  79. imageId: "",
  80. videoId: "",
  81. question: "",
  82. optionsList: [],
  83. },
  84. });
  85. // 获取视频基本节点信息、素材信息
  86. function getInitData() {
  87. // 获取互动视频基本信息以及节点
  88. getInteractionVideoDetail(interactionId).then((res) => {
  89. if (res.code == 200) {
  90. interactionVideoInfo.value = res.data.interactionVideoInfo;
  91. graphData.value = transfromReturnGraphdata(res.data.rootNode);
  92. videoSource.value = treeToArray(graphData.value);
  93. console.log("graphData", graphData.value);
  94. }
  95. });
  96. // 获取相关素材信息
  97. getMaterialInfoDetail(interactionId).then((res) => {
  98. // 素材类型 0 视频 1 图片
  99. videoSources.value = res.data.materialLibraryVOList
  100. .filter((i) => i.materialType == 0)
  101. .map((i) => {
  102. return {
  103. id: i.materialId,
  104. name: i.materialName,
  105. url: i.accessory?.url,
  106. };
  107. });
  108. imageSources.value = res.data.materialLibraryVOList
  109. .filter((i) => i.materialType == 1)
  110. .map((i) => {
  111. return {
  112. id: i.materialId,
  113. name: i.materialName,
  114. url: i.accessory?.url,
  115. };
  116. });
  117. });
  118. }
  119. /**
  120. * 视频ID变化,则获取相关素材以及节点数据
  121. */
  122. watchEffect(() => {
  123. getInitData();
  124. }, [interactionId]);
  125. // 关闭当前页签
  126. function returnList() {
  127. proxy.$tab.closePage();
  128. }
  129. function formSubmit() {
  130. // 剧情节点信息
  131. const rootNode = transformGraphdata(graphData.value);
  132. interactionVideoUpdate({
  133. interactionVideoInfo: interactionVideoInfo.value,
  134. rootNode,
  135. }).then((res) => {
  136. if (res.code == 200) {
  137. proxy.$modal.msgSuccess(res.msg);
  138. }
  139. });
  140. }
  141. // 视频预览
  142. const videoViewOpen = ref(false);
  143. const videoDetail = ref({});
  144. const videoSource = ref([]);
  145. function videoView() {
  146. videoDetail.value = graphData.value;
  147. console.log(videoDetail.value);
  148. if (!videoDetail.value.data.uri) {
  149. proxy.$modal.msgError("暂无可播放视频,可添加视频素材后预览");
  150. return;
  151. }
  152. videoViewOpen.value = true;
  153. }
  154. // 点击选中选项
  155. const onClickOption = (option) => {
  156. // 过滤出当前选中项的nodeId和视频资源的id相同的项
  157. let videoData = videoSource.value.filter((i) => i.id == option.nodeId)[0];
  158. // 如果筛选出的数据 节点类型时跳转节点的,需要特殊处理一下:筛选出视频资源中id和跳转jumpNodeId相同的数据
  159. if (videoData.nodeType === "jump-node") {
  160. videoData = videoSource.value.filter(
  161. (i) => i.id == videoData.data.jumpNodeId
  162. )[0];
  163. }
  164. videoDetail.value = videoData;
  165. };
  166. // 将树形数据转化为数组
  167. const treeToArray = (tree, arr = []) => {
  168. arr.push(tree);
  169. if (tree.children) {
  170. for (let child of tree.children) {
  171. treeToArray(child, arr);
  172. }
  173. }
  174. return arr;
  175. };
  176. const materialOpen = ref(false);
  177. function addSource() {
  178. materialOpen.value = true;
  179. }
  180. function formFieldsClose() {
  181. materialOpen.value = false;
  182. getInitData();
  183. }
  184. </script>
  185. <style>
  186. .border_box {
  187. border: 1px solid #ccc;
  188. margin-top: 10px;
  189. }
  190. </style>