瀏覽代碼

feat: 功能优化:1-添加素材改为管理素材,能查看并修改与互动视频已关联的素材;2-互动视频视频管理列表添加预览功能;3-素材管理添加预览图片功能

mnisting 2 月之前
父節點
當前提交
8e4c8e5ede

+ 16 - 2
src/api/interactVideo/sourceMaterialManage.js

@@ -1,13 +1,20 @@
 import request from "@/utils/request";
 
-// 查询素材库列表
+// 查询素材库未关联列表  /interactionVideo/noRelation/list
 export function getLibraryList(params) {
   return request({
-    url: "/business/library/list",
+    url: "/interactionVideo/noRelation/list",
     method: "get",
     params,
   });
 }
+// 查询素材库已关联列表
+export function getReleateList(interactionId) {
+  return request({
+    url: `/interactionVideo/detail/materialInfo/${interactionId}`,
+    method: "get",
+  });
+}
 // 素材详情
 export function getLibraryDetail(materialId) {
   return request({
@@ -38,3 +45,10 @@ export function libraryDelete(materialIds) {
     method: "delete",
   });
 }
+// 删除素材关联  /interactionVideo/deleteRelation/{interactionId}/{materialId}
+export function releateDelete(interactionId, materialId) {
+  return request({
+    url: `/interactionVideo/deleteRelation/${interactionId}/${materialId}`,
+    method: "delete",
+  });
+}

+ 20 - 6
src/components/InteractiveVideoEditor/VideoLineGraph/hooks/useGraphPlugins.js

@@ -54,13 +54,23 @@ const createMenuListByNode = {
       </ul>`;
   },
 };
+// 根节点data的默认数据
+const rootNodeDefaultData = {
+  name: "",
+  image: "",
+  uri: "",
+  imageId: "",
+  videoId: "",
+  question: "",
+};
 
 // 剧情节点data的默认值
 const plotNodeDefaultData = {
   name: "",
   image: "",
-  url: "",
-  materialId: "",
+  uri: "",
+  imageId: "",
+  videoId: "",
   question: "",
 };
 
@@ -70,6 +80,12 @@ const jumpNodeDefaultData = {
   jumpNodeId: "",
 };
 
+const defaultDataMap = {
+  "root-node": rootNodeDefaultData,
+  "plot-node": plotNodeDefaultData,
+  "jump-node": jumpNodeDefaultData,
+};
+
 // 不同点击类型的功能处理
 const menuClickFuncMap = {
   // 创建剧情模块
@@ -120,10 +136,8 @@ const menuClickFuncMap = {
   },
   // 清空模块数据
   clean: (node, graph) => {
-    const defaultData =
-      node.getModel().type === "plot-node"
-        ? plotNodeDefaultData
-        : jumpNodeDefaultData;
+    const model = node.getModel();
+    const defaultData = defaultDataMap[model.type];
     graph.updateItem(node, {
       data: defaultData,
     });

+ 3 - 0
src/hooks/transformGraphdata.js

@@ -86,6 +86,9 @@ function transformReturnNodeDataByList(nodeList, nodeMap) {
     node.id = String(node.id);
     node.type = node.nodeType;
     node.data.name = node.data.nodeName;
+    node.data.uri =
+      import.meta.env.VITE_APP_BASE_API + (node.data.uri || node.data.url);
+    node.data.image = import.meta.env.VITE_APP_BASE_API + node.data.image;
     setNextNodeId(node, nodeMap);
     transformReturnNodeDataByList(node.children, nodeMap);
   }

+ 34 - 23
src/hooks/useIframeEvent.js

@@ -1,47 +1,58 @@
-import { onMounted, onBeforeUnmount } from 'vue'
-import { postMessageOk, postMessageFail } from '@/utils/iframePip.js'
+import { onMounted, onBeforeUnmount } from "vue";
+import { postMessageOk, postMessageFail } from "@/utils/iframePip.js";
 
 // 检查数据字段的有效性
 const checkData = (list, propList) => {
-  if (!Array.isArray(list)) return false
+  if (!Array.isArray(list)) return false;
   for (let i = 0; i < list.length; i++) {
-    const item = list[i]
+    const item = list[i];
     for (let j = 0; j < propList.length; j++) {
-      const key = propList[j]
-      if (item[key] === undefined) return false
+      const key = propList[j];
+      if (item[key] === undefined) return false;
     }
   }
-  return true
-}
+  return true;
+};
 
 // 监听iframe通讯
 const useIframeEvent = (detailInfoRef) => {
   const handleMessage = (e) => {
-    if (e.data.source === 'InteractiveVideo') {
-      console.log('接收到外部调用者的数据', e)
+    if (e.data.source === "InteractiveVideo") {
+      console.log("接收到外部调用者的数据", e);
       // 外部传入流程图数据,此时需要更新流程图数据
-      if (e.data.toolType === 'InteractiveVideoUser' && e.data.msgType === 'video_change_data') {
+      if (
+        e.data.toolType === "InteractiveVideoUser" &&
+        e.data.msgType === "video_change_data"
+      ) {
         if (
           !e.data.content ||
           // 检查数据字段是否符合要求
-          checkData(e.data.content, ['id', 'image', 'name', 'materialId', 'uri', 'optionsList'])
+          checkData(e.data.content, [
+            "id",
+            "image",
+            "name",
+            "imageId",
+            "videoId",
+            "uri",
+            "optionsList",
+          ])
         ) {
-          postMessageFail('video_change_data', '数据格式不正确')
-          return
+          postMessageFail("video_change_data", "数据格式不正确");
+          return;
         }
-        detailInfoRef.value = e.data.content
-        postMessageOk('video_change_data')
+        detailInfoRef.value = e.data.content;
+        postMessageOk("video_change_data");
       }
     }
-  }
+  };
 
   onMounted(() => {
-    window.addEventListener('message', handleMessage)
-  })
+    window.addEventListener("message", handleMessage);
+  });
 
   onBeforeUnmount(() => {
-    window.removeEventListener('message', handleMessage)
-  })
-}
+    window.removeEventListener("message", handleMessage);
+  });
+};
 
-export default useIframeEvent
+export default useIframeEvent;

+ 30 - 1
src/views/interactVideo/sourceMaterialManage/index.vue

@@ -88,6 +88,13 @@
             v-if="row.materialType == 0"
             >视频预览</el-button
           >
+          <el-button
+            type="primary"
+            link
+            @click="handleViewPic(row)"
+            v-if="row.materialType == 1"
+            >图片预览</el-button
+          >
         </template>
       </el-table-column>
     </el-table>
@@ -168,6 +175,16 @@
         :autoplayMuted="false"
       />
     </el-dialog>
+
+    <!-- 图片预览 -->
+    <el-dialog
+      title="图片预览"
+      v-model="picViewOpen"
+      width="1200"
+      destroy-on-close
+    >
+      <img style="width: 100%" :src="imgUrl" alt="" />
+    </el-dialog>
   </div>
 </template>
 
@@ -194,6 +211,8 @@ const dialogTitle = ref("新增素材");
 const materialOpen = ref(false);
 const videoViewOpen = ref(false);
 const videoUrl = ref("");
+const picViewOpen = ref(false);
+const imgUrl = ref("");
 const data = reactive({
   form: {
     materialName: undefined,
@@ -354,7 +373,17 @@ function handlepreview(row) {
     proxy.$modal.msgError("视频文件错误,请重新上传视频");
     return;
   }
-  videoUrl.value = row.url;
+  videoUrl.value = import.meta.env.VITE_APP_BASE_API + row.url;
   videoViewOpen.value = true;
 }
+
+function handleViewPic(row) {
+  console.log(row);
+  if (!row.url) {
+    proxy.$modal.msgError("图片文件错误,请重新上传图片");
+    return;
+  }
+  imgUrl.value = import.meta.env.VITE_APP_BASE_API + row.url;
+  picViewOpen.value = true;
+}
 </script>

+ 130 - 25
src/views/interactVideo/videoManage/addSouce.vue

@@ -3,25 +3,32 @@
     <el-dialog
       title="添加素材"
       v-model="materialOpen"
-      width="1200"
+      width="1280"
+      :close-on-click-modal="false"
       append-to-body
       destroy-on-close
+      :before-close="dialogCancel"
     >
       <el-form :model="form" ref="dataForm" label-width="110px" inline>
         <el-row :gutter="10">
-          <el-col :span="6">
-            <el-form-item label="素材" prop="selectMaterial">
+          <el-col :span="14">
+            <el-form-item label="选择素材" prop="selectMaterial">
               <el-radio-group v-model="form.selectMaterial">
                 <el-radio :label="1">选择已有素材</el-radio>
                 <el-radio :label="2" @click="uploadSource">上传素材</el-radio>
               </el-radio-group>
             </el-form-item>
           </el-col>
-          <el-col :span="24" v-show="form.selectMaterial == 1">
-            <el-form-item label="">
+          <el-col :span="10">
+            <el-form-item label="已选素材" prop="selectMaterial">
+            </el-form-item>
+          </el-col>
+          <el-col :span="10">
+            <el-form-item label="" v-show="form.selectMaterial == 1">
               <!-- 列表 -->
               <el-table
                 border
+                ref="tableRef"
                 row-key="materialId"
                 v-loading="loading"
                 :data="libraryList"
@@ -33,12 +40,12 @@
                   align="center"
                   :reserve-selection="true"
                 />
-                <el-table-column
-                  type="index"
-                  label="序号"
-                  width="100"
-                  align="center"
-                />
+                <!-- <el-table-column
+                    type="index"
+                    label="序号"
+                    width="100"
+                    align="center"
+                  /> -->
                 <el-table-column
                   prop="materialName"
                   label="素材名称"
@@ -55,13 +62,15 @@
                   </template>
                 </el-table-column>
                 <!-- 0=未发布,1=发布 -->
-                <el-table-column prop="status" label="状态" align="center">
-                  <template #default="{ row }">
-                    {{ libraryStatus[row.status] }}
-                  </template>
-                </el-table-column>
+                <!-- <el-table-column prop="status" label="状态" align="center">
+                    <template #default="{ row }">
+                      {{ libraryStatus[row.status] }}
+                    </template>
+                  </el-table-column> -->
               </el-table>
               <pagination
+                layout="total,sizes, prev, pager, next"
+                pager-count="5"
                 v-show="total > 0"
                 :total="total"
                 v-model:page="queryParams.pageNum"
@@ -70,16 +79,68 @@
               />
             </el-form-item>
           </el-col>
+          <el-col
+            :span="4"
+            style="display: flex; justify-content: center; align-items: center"
+          >
+            <el-button
+              v-show="form.selectMaterial == 1"
+              type="primary"
+              :loading="confirmLoading"
+              @click="dialogSubmit"
+              >确定选择 =></el-button
+            >
+          </el-col>
+          <el-col :span="10">
+            <el-form-item label="" style="width: 100%">
+              <!-- 列表 -->
+              <el-table
+                border
+                row-key="materialId"
+                v-loading="loading"
+                :data="releateList"
+              >
+                <el-table-column
+                  prop="materialName"
+                  label="素材名称"
+                  align="center"
+                />
+                <!-- 素材类型,0-视频、1-图片 -->
+                <el-table-column
+                  prop="materialType"
+                  label="素材类型"
+                  align="center"
+                >
+                  <template #default="{ row }">
+                    {{ libraryType[row.materialType] }}
+                  </template>
+                </el-table-column>
+                <el-table-column label="操作" align="center">
+                  <template #default="{ row }">
+                    <el-button
+                      link
+                      type="primary"
+                      size="small"
+                      @click="handleDelete(row)"
+                    >
+                      删除
+                    </el-button>
+                  </template>
+                </el-table-column>
+              </el-table>
+            </el-form-item>
+          </el-col>
         </el-row>
       </el-form>
+
       <template #footer>
         <div class="dialog-footer">
-          <el-button
+          <!-- <el-button
             type="primary"
             :loading="confirmLoading"
             @click="dialogSubmit"
             >确 定</el-button
-          >
+          > -->
           <el-button :loading="confirmLoading" @click="dialogCancel"
             >取 消</el-button
           >
@@ -148,7 +209,9 @@
 <script setup name="FormFields">
 import {
   getLibraryList,
+  getReleateList,
   libraryAdd,
+  releateDelete,
 } from "@/api/interactVideo/sourceMaterialManage";
 import { updateMaterialInfo } from "@/api/interactVideo/videoManage";
 const { proxy } = getCurrentInstance();
@@ -172,6 +235,8 @@ const materialOpen = ref(false);
 const confirmLoading = ref(false);
 const loading = ref(false);
 const libraryList = ref([]);
+const releateList = ref([]);
+const releateIds = ref([]);
 const total = ref(0);
 const materialConfirmLoading = ref(false);
 const addSourceOpen = ref(false);
@@ -230,6 +295,8 @@ watchEffect(() => {
   }
 });
 
+const tableRef = ref();
+
 // 互动视频新增并关联素材
 function dialogSubmit() {
   proxy.$refs["dataForm"].validate((valid) => {
@@ -239,9 +306,10 @@ function dialogSubmit() {
         proxy.$modal.msgError("请选择素材");
         return;
       }
+      const materialIds = [...ids.value, ...releateIds.value];
       confirmLoading.value = true;
       const params = {
-        materialIds: ids.value,
+        materialIds,
         ...props.baseInfo,
       };
       updateMaterialInfo(params)
@@ -249,7 +317,10 @@ function dialogSubmit() {
           // 新增成功后拿到id跳转互动视频节点编辑
           if (res.code == 200) {
             proxy.$modal.msgSuccess("添加成功");
-            dialogCancel();
+            // dialogCancel();
+            getList();
+            // 清除勾选
+            tableRef.value.clearSelection();
           }
         })
         .finally(() => {
@@ -267,11 +338,28 @@ function dialogCancel() {
 /** 查询素材列表 */
 function getList() {
   loading.value = true;
-  getLibraryList(queryParams.value).then((response) => {
-    libraryList.value = response.rows;
-    total.value = response.total;
-    loading.value = false;
-  });
+  console.log(props.baseInfo);
+  const interactionId = props.baseInfo.interactionId;
+  queryParams.value = {
+    ...queryParams.value,
+    interactionId,
+  };
+  // 未关联的素材
+  getLibraryList(queryParams.value)
+    .then((res) => {
+      libraryList.value = res.rows;
+      total.value = res.total;
+    })
+    .finally(() => (loading.value = false));
+  // 已关联的素材
+  getReleateList(interactionId)
+    .then((res) => {
+      console.log(res);
+      const arr = res.data.materialLibraryVOList || [];
+      releateList.value = arr;
+      releateIds.value = arr.map((item) => item.materialId);
+    })
+    .finally(() => (loading.value = false));
 }
 // 选中素材id
 function handleSelectionChange(selection) {
@@ -329,4 +417,21 @@ function uploadChange(file) {
 function uploadRemove() {
   materialForm.value.fileList = [];
 }
+
+// 删除
+function handleDelete(row) {
+  console.log(row);
+  const interactionId = props.baseInfo.interactionId;
+  const materialId = row.materialId;
+  proxy.$modal
+    .confirm("是否确认删除当前素材?")
+    .then(function () {
+      return releateDelete(interactionId, materialId);
+    })
+    .then(() => {
+      getList();
+      proxy.$modal.msgSuccess("删除成功");
+    })
+    .catch(() => {});
+}
 </script>

+ 67 - 0
src/views/interactVideo/videoManage/index.vue

@@ -69,6 +69,9 @@
           <el-button type="danger" link @click="handleDelete(row)"
             >删除</el-button
           >
+          <el-button type="primary" link @click="handleView(row)"
+            >预览</el-button
+          >
         </template>
       </el-table-column>
     </el-table>
@@ -81,6 +84,23 @@
     />
     <!-- 新增编辑 -->
     <FormFields :open="materialOpen" @close="formFieldsClose" />
+    <!-- 视频预览 -->
+    <el-dialog
+      title="视频预览"
+      v-model="videoViewOpen"
+      width="1200"
+      destroy-on-close
+    >
+      <XGVideoViewer
+        :question="videoDetail.data.question"
+        :options="videoDetail.data.optionsList"
+        :videoUrl="videoDetail.data.uri"
+        :autoplay="true"
+        :autoplayMuted="false"
+        :poster="videoDetail.data.image"
+        @onClickOption="onClickOption"
+      />
+    </el-dialog>
   </div>
 </template>
 
@@ -88,8 +108,12 @@
 import {
   getInteractionVideoList,
   interactionVideoDel,
+  getInteractionVideoDetail,
 } from "@/api/interactVideo/videoManage";
+import { transfromReturnGraphdata } from "@/hooks/transformGraphdata";
 import FormFields from "./formFields.vue";
+import XGVideoViewer from "@/components/XGVideoViewer";
+
 const { proxy } = getCurrentInstance();
 const router = useRouter();
 const loading = ref(false);
@@ -151,6 +175,49 @@ function handleDelete(row) {
     .catch(() => {});
 }
 
+// 视频预览
+const videoViewOpen = ref(false);
+const videoDetail = ref({});
+const graphData = ref({
+  id: "0",
+  type: "root-node",
+  preNodeId: null,
+  children: [],
+  data: {
+    name: "默认节点",
+    image: "",
+    url: "",
+    imageId: "",
+    videoId: "",
+    question: "",
+    optionsList: [],
+  },
+});
+
+/** 预览按钮操作 */
+function handleView(row) {
+  console.log(row);
+  // 获取互动视频基本信息以及节点
+  getInteractionVideoDetail(row.interactionId).then((res) => {
+    if (res.code == 200) {
+      graphData.value = transfromReturnGraphdata(res.data.rootNode);
+      videoDetail.value = graphData.value;
+      if (!videoDetail.value.data.uri) {
+        proxy.$modal.msgError("暂无可播放视频,可添加视频素材后预览");
+        return;
+      }
+      videoViewOpen.value = true;
+    }
+  });
+}
+
+// 点击选中选项
+const onClickOption = (option) => {
+  videoDetail.value = graphData.value.children.filter(
+    (i) => i.id == option.nodeId
+  )[0];
+};
+
 function handleAdd() {
   // router.push("/interactVideo/videoOperation");
   materialOpen.value = true;

+ 7 - 4
src/views/interactVideo/videoManage/videoOperation.vue

@@ -3,7 +3,7 @@
   <div class="app-container">
     <div style="display: flex">
       <el-button type="primary" @click="formSubmit">保存</el-button>
-      <el-button type="primary" @click="addSource">添加素材</el-button>
+      <el-button type="primary" @click="addSource">管理素材</el-button>
       <el-button type="info" @click="videoView">视频预览</el-button>
       <el-button @click="returnList">返回</el-button>
     </div>
@@ -26,7 +26,7 @@
       <XGVideoViewer
         :question="videoDetail.data.question"
         :options="videoDetail.data.optionsList"
-        :videoUrl="videoDetail.data.url"
+        :videoUrl="videoDetail.data.uri"
         :autoplay="true"
         :autoplayMuted="false"
         :poster="videoDetail.data.image"
@@ -79,7 +79,8 @@ const graphData = ref({
     name: "默认节点",
     image: "",
     url: "",
-    materialId: "1",
+    imageId: "",
+    videoId: "",
     question: "",
     optionsList: [],
   },
@@ -91,6 +92,7 @@ function getInitData() {
     if (res.code == 200) {
       interactionVideoInfo.value = res.data.interactionVideoInfo;
       graphData.value = transfromReturnGraphdata(res.data.rootNode);
+      console.log("graphData", graphData.value);
     }
   });
   // 获取相关素材信息
@@ -147,7 +149,8 @@ const videoDetail = ref({});
 
 function videoView() {
   videoDetail.value = graphData.value;
-  if (!videoDetail.value.data.url || !videoDetail.value.data.uri) {
+  console.log(videoDetail.value);
+  if (!videoDetail.value.data.uri) {
     proxy.$modal.msgError("暂无可播放视频,可添加视频素材后预览");
     return;
   }