Explorar o código

h5游戏组件

natasha hai 1 semana
pai
achega
4d81fd5460

+ 7 - 0
src/api/app.js

@@ -82,3 +82,10 @@ export function GetStaticResources(MethodName, data) {
 export function GetBookWebSIContent(MethodName, data) {
   return http.post(`/GCLSBookWebSI/ServiceInterface?MethodName=${MethodName}`, data);
 }
+
+/**
+ * 解压 H5 游戏包并创建启动文件
+ */
+export function H5StartupFile(data) {
+  return http.post(`/FileServer/SI?MethodName=file_store_manager-UnzipH5GamePackCreateStartupFile`, data);
+}

+ 13 - 0
src/icons/svg/games.svg

@@ -0,0 +1,13 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1750410306045"
+  class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2380"
+  xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200">
+  <path
+    d="M917.4 507c-27.8-98.4-66-189.8-79.3-214.7-16.8-31.4-39.9-55.5-68.7-71.5-29.8-16.6-66.7-25.1-109.6-25.1H364c-42.9 0-79.8 8.4-109.6 25.1-28.7 16-51.8 40.1-68.7 71.5-13.4 24.9-51.5 116.3-79.3 214.7-37.1 131.4-42.1 224.8-14.7 277.7 15.2 29.3 40.4 47 73.1 51.1 13.5 1.7 26 2.5 37.7 2.5 87.6 0 127.7-44.2 163.5-83.8 21.2-23.4 41.3-45.6 70.9-57.9h166.3c29.4 12.3 46.5 33.8 66.1 58.5 18 22.7 36.7 46.1 65.9 62.6 32.8 18.5 73.3 24.5 123.9 18.1 32.7-4.1 57.9-21.8 73.1-51.1 27.3-52.9 22.3-146.3-14.8-277.7z m-29.7 254.8c-7.7 14.8-18.4 22.4-34.9 24.4-11.4 1.4-21.8 2.1-31.3 2.1-61.9 0-85-29-113.1-64.4-22-27.6-46.9-59-91.7-75.8-2.8-1.1-5.8-1.6-8.8-1.6H432.1c-3 0-6 0.5-8.8 1.6-43.2 16.2-70.4 46.3-94.4 72.8-38.7 42.7-69.2 76.4-158 65.3-16.5-2.1-27.2-9.6-34.9-24.4-20.7-40.1-14.2-125.7 18.4-241.1 27.3-96.7 64.4-184.4 75.3-204.7 25.6-47.9 68.3-70.1 134.2-70.1h295.8c65.9 0 108.6 22.3 134.2 70.1 10.9 20.3 48 108 75.3 204.7 32.7 115.4 39.2 201 18.5 241.1z"
+    fill="currentColor" p-id="2381"></path>
+  <path
+    d="M450 444.9h-70.3v-70.5c0-11-9-20-20-20s-20 9-20 20v70.5H270c-11 0-20 9-20 20s9 20 20 20h69.7v69.5c0 11 9 20 20 20s20-9 20-20v-69.5H450c11 0 20-9 20-20s-9-20-20-20z"
+    fill="currentColor" p-id="2382"></path>
+  <path d="M640.5 427m-41.9 0a41.9 41.9 0 1 0 83.8 0 41.9 41.9 0 1 0-83.8 0Z" fill="currentColor" p-id="2383"></path>
+  <path d="M739.1 525.6m-41.9 0a41.9 41.9 0 1 0 83.8 0 41.9 41.9 0 1 0-83.8 0Z" fill="currentColor" p-id="2384"></path>
+</svg>

+ 3 - 0
src/views/book/courseware/create/components/base/common/UploadFile.vue

@@ -244,6 +244,9 @@ export default {
           'rar',
         ];
         typeTip = '文件不支持';
+      } else if (this.type === 'h5_games') {
+        fileType = ['zip'];
+        typeTip = 'H5游戏文件只能是 zip 格式!';
       }
       const isNeedType = fileType.includes(suffix);
       if (!isNeedType) {

+ 49 - 0
src/views/book/courseware/create/components/base/h5_games/H5Games.vue

@@ -0,0 +1,49 @@
+<template>
+  <ModuleBase :type="data.type">
+    <template #content>
+      <UploadFile
+        key="upload_games"
+        :courseware-id="courseware_id"
+        :component-id="id"
+        :type="data.type"
+        :total-size="200"
+        :file-list="data.games_list"
+        :file-id-list="data.games_id_list"
+        :label-text="labelText"
+        :accept-file-type="acceptFileType"
+        :icon-class="iconClass"
+        :limit="1"
+        :single-size="200"
+        @updateFileList="updateFileList"
+      />
+    </template>
+  </ModuleBase>
+</template>
+
+<script>
+import ModuleMixin from '../../common/ModuleMixin';
+import UploadFile from '../common/UploadFile.vue';
+import { getH5GamesData } from '@/views/book/courseware/data/h5Games';
+
+export default {
+  name: 'H5GamesPage',
+  components: { UploadFile },
+  mixins: [ModuleMixin],
+  data() {
+    return {
+      data: getH5GamesData(),
+      labelText: '压缩包',
+      acceptFileType: '.zip',
+      iconClass: 'zip',
+    };
+  },
+  watch: {},
+  methods: {
+    updateFileList({ file_list, file_id_list }) {
+      this.data.games_list = file_list;
+      this.data.games_id_list = file_id_list;
+    },
+  },
+};
+</script>
+<style lang="scss" scoped></style>

+ 34 - 0
src/views/book/courseware/create/components/base/h5_games/H5GamesSetting.vue

@@ -0,0 +1,34 @@
+<template>
+  <div>
+    <el-form :model="property" label-width="72px" label-position="left">
+      <SerailNumber :property="property" />
+    </el-form>
+  </div>
+</template>
+
+<script>
+import SettingMixin from '@/views/book/courseware/create/components/common/SettingMixin';
+
+import { getH5GamesProperty } from '@/views/book/courseware/data/h5Games';
+import { isEnable } from '@/views/book/courseware/data/common';
+
+export default {
+  name: 'H5GamesSetting',
+  mixins: [SettingMixin],
+  data() {
+    return {
+      isEnable,
+      property: getH5GamesProperty(),
+    };
+  },
+  methods: {},
+};
+</script>
+
+<style lang="scss" scoped>
+@use '@/styles/mixin.scss' as *;
+
+.el-form {
+  @include setting-base;
+}
+</style>

+ 11 - 0
src/views/book/courseware/data/bookType.js

@@ -57,6 +57,8 @@ import WriteBase from '../create/components/base/write_base/WriteBase.vue';
 import WriteBaseSetting from '../create/components/base/write_base/WriteBaseSetting.vue';
 import ImageText from '../create/components/question/image_text/ImageText.vue';
 import ImageTextSetting from '../create/components/question/image_text/ImageTextSetting.vue';
+import H5Games from '../create/components/base/h5_games/H5Games.vue';
+import H5GamesSetting from '../create/components/base/h5_games/H5GamesSetting.vue';
 
 // 预览组件页面列表
 import AudioPreview from '@/views/book/courseware/preview/components/audio/AudioPreview.vue';
@@ -89,6 +91,7 @@ import InputPreview from '../preview/components/input/InputPreview.vue';
 import JudgePreview from '../preview/components/judge/JudgePreview.vue';
 import WriteBasePreview from '../preview/components/write_base/WriteBasePreview.vue';
 import ImageTextPreview from '../preview/components/image_text/ImageTextPreview.vue';
+import H5GamesPreview from '../preview/components/h5_games/H5GamesPreview.vue';
 
 export const bookTypeOption = [
   {
@@ -200,6 +203,14 @@ export const bookTypeOption = [
         set: WriteBaseSetting,
         preview: WriteBasePreview,
       },
+      {
+        value: 'h5_games',
+        label: 'H5游戏',
+        icon: 'games',
+        component: H5Games,
+        set: H5GamesSetting,
+        preview: H5GamesPreview,
+      },
     ],
   },
   {

+ 30 - 0
src/views/book/courseware/data/h5Games.js

@@ -0,0 +1,30 @@
+import {
+  displayList,
+  serialNumberTypeList,
+  serialNumberPositionList,
+  isEnable,
+} from '@/views/book/courseware/data/common';
+
+export { isEnable };
+
+export function getH5GamesProperty() {
+  return {
+    serial_number: 1,
+    sn_type: serialNumberTypeList[0].value,
+    sn_position: serialNumberPositionList[3].value,
+    sn_display_mode: displayList[0].value,
+  };
+}
+
+export function getH5GamesData() {
+  return {
+    type: 'h5_games',
+    title: 'H5游戏',
+    property: getH5GamesProperty(),
+    games_list: [],
+    games_id_list:[],
+    answer: {
+      answer_list: [],
+    },
+  };
+}

+ 92 - 0
src/views/book/courseware/preview/components/h5_games/H5GamesPreview.vue

@@ -0,0 +1,92 @@
+<!-- eslint-disable vue/no-v-html -->
+<template>
+  <div class="imageText-preview" :style="getAreaStyle()">
+    <SerialNumberPosition v-if="isEnable(data.property.sn_display_mode)" :property="data.property" />
+    <div ref="fullscreenElement">
+      <el-button
+        type="primary"
+        :class="[full_type ? 'exit-btn' : '']"
+        @click="toggleFullScreen"
+        style="margin-bottom: 10px"
+        >{{ full_type ? '退出全屏' : '进入全屏' }}</el-button
+      >
+      <iframe :src="games_url" width="100%" :height="full_type ? '100%' : '580px'" style="border: none"></iframe>
+    </div>
+  </div>
+</template>
+
+<script>
+import PreviewMixin from '../common/PreviewMixin';
+import { getH5GamesData } from '@/views/book/courseware/data/h5Games';
+import { H5StartupFile } from '@/api/app';
+export default {
+  name: 'H5GamesPreview',
+
+  components: {},
+  mixins: [PreviewMixin],
+  data() {
+    return {
+      data: getH5GamesData(),
+      games_url: '',
+      full_type: false,
+    };
+  },
+  created() {
+    this.initData();
+  },
+  mounted() {},
+  methods: {
+    initData() {
+      this.games_url =
+        'https://file-kf.helxsoft.cn/CSFileStore/003/00301/D-TVLONKXT3IRWYEMCJK/F-702XHW9VPAU8QVS8NF/index.html';
+      this.data.games_list.forEach((item) => {
+        H5StartupFile({ file_id: item.file_id, index_file_name: 'index.html' }).then((res) => {
+          this.games_url = res.file_url;
+        });
+      });
+    },
+    toggleFullScreen() {
+      const elem = this.$refs.fullscreenElement; // 获取需要全屏的元素
+      if (!document.fullscreenElement) {
+        this.full_type = true;
+        if (elem.requestFullscreen) {
+          elem.requestFullscreen(); // 现代浏览器,如Chrome, Firefox, Opera, Safari等
+        } else if (elem.mozRequestFullScreen) {
+          // Firefox
+          elem.mozRequestFullScreen();
+        } else if (elem.webkitRequestFullscreen) {
+          // Chrome, Safari等
+          elem.webkitRequestFullscreen();
+        } else if (elem.msRequestFullscreen) {
+          // IE/Edge
+          elem.msRequestFullscreen();
+        }
+      } else {
+        this.full_type = false;
+        if (document.exitFullscreen) {
+          document.exitFullscreen(); // 退出全屏模式
+        } else if (document.mozCancelFullScreen) {
+          // Firefox
+          document.mozCancelFullScreen();
+        } else if (document.webkitExitFullscreen) {
+          // Chrome, Safari等
+          document.webkitExitFullscreen();
+        } else if (document.msExitFullscreen) {
+          // IE/Edge
+          document.msExitFullscreen();
+        }
+      }
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+@use '@/styles/mixin.scss' as *;
+
+.exit-btn {
+  position: fixed;
+  top: 10px;
+  left: 10px;
+}
+</style>

+ 1 - 0
src/views/book/courseware/preview/components/image_text/ImageTextPreview.vue

@@ -1,6 +1,7 @@
 <!-- eslint-disable vue/no-v-html -->
 <template>
   <div class="imageText-preview" :style="getAreaStyle()">
+    <SerialNumberPosition v-if="isEnable(data.property.sn_display_mode)" :property="data.property" />
     <template v-if="data.mp3_list && data.mp3_list.length > 0 && mp3_url">
       <AudioLine
         ref="audioLine"

+ 35 - 1
src/views/personal_workbench/project/ProductionResourceManage.vue

@@ -1,15 +1,21 @@
 <template>
   <div class="production-resource">
     <MenuPage cur-key="project" />
+
+    <div class="production-resource-main">
+      <div class="textbook-container"></div>
+      <div class="textbook-chapter"></div>
+    </div>
   </div>
 </template>
 
 <script>
 import {} from '@/api/book';
+import MenuPage from '../common/menu.vue';
 
 export default {
   name: 'ProjectResourceManager',
-  components: {},
+  components: { MenuPage },
   data() {
     return {
       book_id: this.$route.params.id,
@@ -26,5 +32,33 @@ export default {
 
 .production-resource {
   @include page-content(true);
+
+  .production-resource-main {
+    display: flex;
+    flex: 1;
+    width: 100%;
+    height: 100%;
+    border-top: $border;
+
+    .textbook-container {
+      display: flex;
+      flex-direction: column;
+      width: 450px;
+      border-right: $border;
+
+      .textbook-list {
+        display: flex;
+        flex-direction: column;
+        height: calc(100vh - 184px);
+        overflow: auto;
+      }
+    }
+
+    .textbook-chapter {
+      display: flex;
+      flex: 1;
+      flex-direction: column;
+    }
+  }
 }
 </style>