dsy hace 5 días
padre
commit
d12e6c9e4c
Se han modificado 23 ficheros con 242 adiciones y 79 borrados
  1. 63 6
      src/views/book/courseware/preview/components/3d_model/3DModelPreview.vue
  2. 15 2
      src/views/book/courseware/preview/components/article/NormalModelChs.vue
  3. 14 2
      src/views/book/courseware/preview/components/article/PhraseModelChs.vue
  4. 7 1
      src/views/book/courseware/preview/components/article/Practicechs.vue
  5. 13 2
      src/views/book/courseware/preview/components/article/WordModelChs.vue
  6. 2 2
      src/views/book/courseware/preview/components/audio/AudioPreview.vue
  7. 7 7
      src/views/book/courseware/preview/components/character/CharacterPreview.vue
  8. 4 4
      src/views/book/courseware/preview/components/character_structure/CharacterStructurePreview.vue
  9. 10 7
      src/views/book/courseware/preview/components/common/AudioPlay.vue
  10. 9 1
      src/views/book/courseware/preview/components/dialogue_article/NormalModelChs.vue
  11. 9 1
      src/views/book/courseware/preview/components/dialogue_article/PhraseModelChs.vue
  12. 7 2
      src/views/book/courseware/preview/components/dialogue_article/Practicechs.vue
  13. 10 2
      src/views/book/courseware/preview/components/dialogue_article/WordModelChs.vue
  14. 1 1
      src/views/book/courseware/preview/components/dialogue_article/index.vue
  15. 28 8
      src/views/book/courseware/preview/components/image_text/components/MagazineSentence.vue
  16. 7 7
      src/views/book/courseware/preview/components/newWord_template/NewWordTemplatePreview.vue
  17. 8 5
      src/views/book/courseware/preview/components/new_word/NewWordPreview.vue
  18. 4 3
      src/views/book/courseware/preview/components/new_word/components/writeTableZoom.vue
  19. 1 1
      src/views/book/courseware/preview/components/notes/NotesPreview.vue
  20. 2 2
      src/views/book/courseware/preview/components/pinyin_base/PinyinBasePreview.vue
  21. 18 12
      src/views/book/courseware/preview/components/table/TablePreview.vue
  22. 1 0
      src/views/book/courseware/preview/components/upload_preview/UploadPreviewPreview.vue
  23. 2 1
      src/views/book/courseware/preview/components/write_base/WriteBasePreview.vue

+ 63 - 6
src/views/book/courseware/preview/components/3d_model/3DModelPreview.vue

@@ -9,6 +9,7 @@
         :size="isFullScreen ? '32px' : '16px'"
         @click="handleToggleFullScreen"
       />
+      <span v-if="!loaded" class="progress">{{ progress }}</span>
     </div>
   </div>
 </template>
@@ -36,10 +37,12 @@ export default {
       camera: null, // 相机
       mixer: null, // 动画混合器
       renderer: null, // 渲染器
+      pmremGenerator: null, // PMREM 生成器,用于环境光照(PBR)
       controls: null, // 轨道控制器
       animationId: null, // 动画帧ID
       isFullScreen: false, // 是否全屏
       loaded: false, // 是否加载完成
+      progress: '0%', // 加载进度
     };
   },
   watch: {
@@ -81,20 +84,30 @@ export default {
       // 创建相机
       const width = container.clientWidth;
       const height = container.clientHeight;
-      this.camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000); // 视角75度
+      this.camera = new THREE.PerspectiveCamera(60, width / height, 0.1, 1000); // 视角75度
       this.camera.position.set(5, 5, 5); // 设置相机位置
 
       // 创建渲染器
       this.renderer = new THREE.WebGLRenderer({ antialias: true }); // 开启抗锯齿
+      // 在高 DPI 屏幕上限制像素比以平衡清晰度与性能
+      this.renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
       this.renderer.setSize(width, height);
       this.renderer.shadowMap.enabled = true; // 启用阴影映射
       this.renderer.shadowMap.type = THREE.PCFSoftShadowMap; // 使用柔和阴影
 
       // 启用颜色管理和正确的色彩空间
       this.renderer.outputColorSpace = THREE.SRGBColorSpace; // 设置输出色彩空间
+      // 启用物理光照计算,使光照强度与光源单位保持一致
+      this.renderer.physicallyCorrectLights = true;
       this.renderer.toneMapping = THREE.ACESFilmicToneMapping; // 使用ACES电影色调映射
       this.renderer.toneMappingExposure = 1.0; // 曝光度
 
+      // 创建 PMREMGenerator,用于从 equirectangular/HDR 贴图生成环境贴图(用于 PBR 材质)
+      if (THREE.PMREMGenerator) {
+        this.pmremGenerator = new THREE.PMREMGenerator(this.renderer); // 创建 PMREM 生成器
+        this.pmremGenerator.compileEquirectangularShader(); // 预编译着色器
+      }
+
       container.appendChild(this.renderer.domElement); // 将渲染器添加到DOM
 
       // 添加光源
@@ -116,6 +129,8 @@ export default {
       this.controls.enableDamping = true; // 启用阻尼效果
       this.controls.dampingFactor = 0.25; // 阻尼系数
 
+      // 绑定 animate 的 this,避免在 requestAnimationFrame 中丢失上下文
+      this.animate = this.animate.bind(this);
       // 开始渲染循环
       this.animate();
 
@@ -128,7 +143,7 @@ export default {
         return;
       }
 
-      const modelUrl = this.data.file_list[0].file_url;
+      const modelUrl = this.data.model_list[0].file_url;
       if (!modelUrl) {
         console.error('模型文件URL不存在');
         return;
@@ -190,7 +205,7 @@ export default {
           }
         },
         (progress) => {
-          console.log('加载进度:', `${(progress.loaded / progress.total) * 100}%`);
+          this.progress = `${((progress.loaded / progress.total) * 100).toFixed(2)}%`;
           if (progress.loaded >= progress.total) {
             this.loaded = true;
           }
@@ -226,7 +241,7 @@ export default {
           this.addModelToScene(fbx);
         },
         (progress) => {
-          console.log('加载进度:', `${(progress.loaded / progress.total) * 100}%`);
+          this.progress = `${((progress.loaded / progress.total) * 100).toFixed(2)}%`;
           if (progress.loaded >= progress.total) {
             this.loaded = true;
           }
@@ -245,9 +260,10 @@ export default {
         this.loadOBJModel(loader, url);
         return;
       }
+
       const mtlLoader = new MTLLoader();
 
-      // 设置材质加载路径
+      // 设置材质和纹理加载路径
       const basePath = mtlUrl.substring(0, mtlUrl.lastIndexOf('/') + 1);
       mtlLoader.setPath(basePath);
       mtlLoader.setResourcePath(basePath);
@@ -264,7 +280,6 @@ export default {
         },
         undefined,
         (error) => {
-          // 材质文件加载失败,使用默认材质
           console.warn('MTL材质文件加载失败,使用默认材质:', error);
           this.loadOBJModel(loader, url);
         },
@@ -283,6 +298,7 @@ export default {
           this.addModelToScene(obj);
         },
         (progress) => {
+          this.progress = `${((progress.loaded / progress.total) * 100).toFixed(2)}%`;
           if (progress.loaded >= progress.total) {
             this.loaded = true;
           }
@@ -316,6 +332,27 @@ export default {
       this.camera.position.set(cameraZ, cameraZ, cameraZ);
       this.camera.lookAt(0, 0, 0);
       this.controls.target.set(0, 0, 0);
+
+      // 计算相机到原点的大致距离并根据模型尺寸调整 far
+      const cameraDistance = Math.sqrt(
+        this.camera.position.x * this.camera.position.x +
+          this.camera.position.y * this.camera.position.y +
+          this.camera.position.z * this.camera.position.z,
+      );
+      const desiredFar = cameraDistance + Math.max(size.x, size.y, size.z) * 2;
+      this.camera.far = Math.max(this.camera.far || 1000, desiredFar);
+      this.camera.updateProjectionMatrix();
+
+      // 为 OrbitControls 设置限制,避免相机飞离或穿透模型
+      if (this.controls) {
+        const minDist = Math.max(0.1, Math.min(maxDim * 0.5, cameraDistance * 0.1));
+        const maxDist = Math.max(cameraDistance * 10, maxDim * 10, cameraZ * 10);
+        this.controls.minDistance = minDist;
+        this.controls.maxDistance = maxDist;
+        // 限制极角,防止视角翻转
+        this.controls.maxPolarAngle = Math.PI - 0.1;
+        this.controls.update();
+      }
     },
 
     animate() {
@@ -364,6 +401,10 @@ export default {
       this.camera.updateProjectionMatrix();
 
       // 更新渲染器尺寸
+      // 同步像素比以适配当前屏幕密度,避免过高开销
+      if (this.renderer.setPixelRatio) {
+        this.renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
+      }
       this.renderer.setSize(width, height);
     },
 
@@ -388,6 +429,14 @@ export default {
       if (this.scene) {
         this.scene.clear();
       }
+
+      // 释放 PMREMGenerator
+      if (this.pmremGenerator) {
+        try {
+          this.pmremGenerator.dispose();
+        } catch (e) {}
+        this.pmremGenerator = null;
+      }
     },
 
     /**
@@ -430,6 +479,14 @@ export default {
       @include spin;
     }
 
+    .progress {
+      position: absolute;
+      top: 10px;
+      right: 28px;
+      font-size: 12px;
+      color: #666;
+    }
+
     .fullscreen-btn {
       position: absolute;
       top: 10px;

+ 15 - 2
src/views/book/courseware/preview/components/article/NormalModelChs.vue

@@ -48,7 +48,12 @@
     </div>
     <template v-if="!config.isHasEN || (config.isHasEN && !config.isShowEN)">
       <template v-if="resArr.length > 0">
-        <div class="NPC-sentences-list">
+        <div
+          class="NPC-sentences-list"
+          :style="{
+            height: curQue.property.content_height ? curQue.property.content_height + 'px' : '',
+          }"
+        >
           <div class="NPC-article-empty">
             <div :class="['empty-left', isHasRemark ? 'hasRemark' : '']"></div>
             <div class="empty-right"></div>
@@ -716,7 +721,12 @@
     <template v-else>
       <template v-if="resObj">
         <!-- 段落对齐方式和备注在此模式里没有写,如果段落里添加了英文后需要在此添加段落对齐和备注、大小图片、生词样式 -->
-        <div class="NPC-sentences-list">
+        <div
+          class="NPC-sentences-list"
+          :style="{
+            height: curQue.property.content_height ? curQue.property.content_height + 'px' : '',
+          }"
+        >
           <div
             v-for="(item, index) in resObj.sentList"
             :key="'detail' + index"
@@ -1466,6 +1476,7 @@ export default {
       let wordTimeList = curQue.wordTime;
       let asIndex = 0;
       let dhaspinyin = false; // 每段是否有拼音
+      this.isHasRemark = false;
       curQue.detail.forEach((dItem, dIndex) => {
         dhaspinyin = false;
         let remarkDetail = dItem.remark;
@@ -1786,6 +1797,8 @@ export default {
   }
 
   .NPC-sentences-list {
+    overflow: auto;
+
     // padding: 24px 0;
     color: rgba(0, 0, 0, 85%);
 

+ 14 - 2
src/views/book/courseware/preview/components/article/PhraseModelChs.vue

@@ -50,7 +50,12 @@
     </div>
     <template v-if="!config.isHasEN || (config.isHasEN && !config.isShowEN)">
       <template v-if="resArr.length > 0">
-        <div class="NPC-sentences-list">
+        <div
+          class="NPC-sentences-list"
+          :style="{
+            height: curQue.property.content_height ? curQue.property.content_height + 'px' : '',
+          }"
+        >
           <div class="NPC-article-empty">
             <div :class="['empty-left', isHasRemark ? 'hasRemark' : '']"></div>
             <div class="empty-right"></div>
@@ -524,7 +529,12 @@
       <template v-if="resObj">
         <!-- 段落对齐方式和备注在此模式里没有写,如果段落里添加了英文后需要在此添加段落对齐和备注 -->
 
-        <div class="NPC-sentences-list">
+        <div
+          class="NPC-sentences-list"
+          :style="{
+            height: curQue.property.content_height ? curQue.property.content_height + 'px' : '',
+          }"
+        >
           <div v-for="(item, index) in resObj.sentList" :key="'detail' + index" :class="['NNPE-detail-box']">
             <div :class="['NNPE-details']">
               <div
@@ -1188,6 +1198,7 @@ export default {
       let leg = this.curQue.detail.length;
       let curQue = JSON.parse(JSON.stringify(this.curQue));
       let dhaspinyin = false; // 每段是否有拼音
+      this.isHasRemark = false;
       curQue.detail.forEach((dItem, dIndex) => {
         dhaspinyin = false;
         let remarkDetail = dItem.remark;
@@ -1767,6 +1778,7 @@ export default {
 
   .NPC-sentences-list {
     // padding: 24px 0;
+    overflow: auto;
 
     .NPC-article-empty {
       display: flex;

+ 7 - 1
src/views/book/courseware/preview/components/article/Practicechs.vue

@@ -65,7 +65,12 @@
     </div>
     <template v-if="resObj">
       <!--  -->
-      <div class="NPC-sentences-list">
+      <div
+        class="NPC-sentences-list"
+        :style="{
+          height: curQue.property.content_height ? curQue.property.content_height + 'px' : '',
+        }"
+      >
         <div
           v-for="(item, index) in resObj.sentList"
           :key="'detail' + index"
@@ -1105,6 +1110,7 @@ export default {
 
   .NPC-sentences-list {
     padding: 16px 0;
+    overflow: auto;
   }
 
   .multilingual {

+ 13 - 2
src/views/book/courseware/preview/components/article/WordModelChs.vue

@@ -50,7 +50,12 @@
     </div>
     <template v-if="!config.isHasEN || (config.isHasEN && !config.isShowEN)">
       <template v-if="resArr.length > 0">
-        <div class="NPC-sentences-list">
+        <div
+          class="NPC-sentences-list"
+          :style="{
+            height: curQue.property.content_height ? curQue.property.content_height + 'px' : '',
+          }"
+        >
           <div
             v-for="(item, index) in resArr"
             :key="'detail' + index"
@@ -489,7 +494,12 @@
     <template v-else>
       <template v-if="resObj">
         <!--  -->
-        <div class="NPC-sentences-list">
+        <div
+          class="NPC-sentences-list"
+          :style="{
+            height: curQue.property.content_height ? curQue.property.content_height + 'px' : '',
+          }"
+        >
           <div
             v-for="(item, index) in resObj.sentList"
             :key="'detail' + index"
@@ -1391,6 +1401,7 @@ export default {
 
   .NPC-sentences-list {
     padding: 24px 0;
+    overflow: auto;
   }
 
   .multilingual {

+ 2 - 2
src/views/book/courseware/preview/components/audio/AudioPreview.vue

@@ -66,7 +66,7 @@
         </el-carousel>
         <div :style="{ height: elementHeight - 140 + 'px', overflowY: viewScroll }">
           <ul class="view-list-bottom">
-            <li v-for="(file, i) in data.file_list" :key="i" @click="handleAudioClick(i, file.file_id)"></li>
+            <li v-for="(file, i) in data.file_list" :key="i" @click="handleAudioClick(i, file.file_id)">
               <AudioPlay
                 :ref="file.file_id"
                 view-size="list"
@@ -188,7 +188,7 @@ export default {
       // 切换到对应索引的文件
       carousel.setActiveItem(index);
       this.curAudioIndex = index;
-      if (this.$refs[id] && this.$refs[id][0]) this.$refs[id][0].changeAudio(id);
+      if (this.$refs[id]&&this.$refs[id][0]) this.$refs[id][0].changeAudio(id);
     },
     changeFile(type) {
       // 获取 Carousel 实例

+ 7 - 7
src/views/book/courseware/preview/components/character/CharacterPreview.vue

@@ -633,7 +633,7 @@ export default {
     width: 80px;
     height: 80px;
     border: 2px solid #346cda;
-    border-radius: 8px;
+    border-radius: 4px;
 
     .character-target-bg,
     .hanzi-writer-img {
@@ -701,7 +701,7 @@ export default {
     height: 80px;
     overflow: hidden;
     border: 2px solid #346cda;
-    border-radius: 8px;
+    border-radius: 4px;
   }
 
   .items-lian {
@@ -729,14 +729,14 @@ export default {
 
     .rightBorderRadius {
       border-radius: 0;
-      border-top-right-radius: 8px;
-      border-bottom-right-radius: 8px;
+      border-top-right-radius: 4px;
+      border-bottom-right-radius: 4px;
     }
 
     .leftBorderRadius {
       border-radius: 0;
-      border-top-left-radius: 8px;
-      border-bottom-left-radius: 8px;
+      border-top-left-radius: 4px;
+      border-bottom-left-radius: 4px;
     }
 
     .NoborderRight {
@@ -853,7 +853,7 @@ export default {
     width: 80px;
     height: 80px;
     border-width: 2px !important;
-    border-radius: 8px;
+    border-radius: 4px;
   }
 
   .words-item {

+ 4 - 4
src/views/book/courseware/preview/components/character_structure/CharacterStructurePreview.vue

@@ -397,7 +397,7 @@ export default {
     flex-wrap: wrap;
     padding: 10px 15px;
     background: #deebff;
-    border-radius: 8px;
+    border-radius: 4px;
 
     .option_one {
       display: flex;
@@ -409,7 +409,7 @@ export default {
       overflow: hidden;
       cursor: pointer;
       background: #9dcaff;
-      border-radius: 8px;
+      border-radius: 4px;
 
       img {
         max-width: 100%;
@@ -433,7 +433,7 @@ export default {
     background: #fff;
     background-size: cover;
     border: 2px solid #346cda;
-    border-radius: 8px;
+    border-radius: 4px;
   }
 
   .one {
@@ -494,7 +494,7 @@ export default {
         height: 80px;
         overflow: hidden;
         border: 2px solid #346cda;
-        border-radius: 8px;
+        border-radius: 4px;
 
         &.right {
           background: #e9f7f2 !important;

+ 10 - 7
src/views/book/courseware/preview/components/common/AudioPlay.vue

@@ -13,7 +13,7 @@
             @change="changeCurrentTime"
           />
           <span class="audio-time">{{ audio_allTime }}</span>
-          <el-select v-model="audio.playbackRate" style="width: 100px" @change="onSpeedChange">
+          <el-select v-model="audio.playbackRate" @change="onSpeedChange" style="width: 100px">
             <el-option
               v-for="speed in playbackRateList.split(' ')"
               :key="speed"
@@ -303,6 +303,9 @@ export default {
       this.pauseAll();
       this.$emit('changeFile', type);
     },
+    changeAudio(id) {
+      this.pauseAll();
+    },
   },
 };
 </script>
@@ -458,14 +461,14 @@ export default {
       }
     }
   }
-}
 
-:deep .el-input .el-input__inner {
-  background-color: rgba(255, 255, 255, 0%);
-  border: none;
+  :deep .el-input .el-input__inner {
+    background-color: rgba(255, 255, 255, 0%);
+    border: none;
 
-  span {
-    display: none !important;
+    span {
+      display: none !important;
+    }
   }
 }
 

+ 9 - 1
src/views/book/courseware/preview/components/dialogue_article/NormalModelChs.vue

@@ -52,7 +52,12 @@
       </div>
     </div>
     <template v-if="resArr.length > 0">
-      <div class="NPC-sentences-list">
+      <div
+        class="NPC-sentences-list"
+        :style="{
+          height: curQue.property.content_height ? curQue.property.content_height + 'px' : '',
+        }"
+      >
         <div class="NPC-article-empty">
           <div :class="['empty-left', isHasRemark ? 'hasRemark' : '']"></div>
           <div class="empty-right"></div>
@@ -928,6 +933,7 @@ export default {
       let wordTimeList = curQue.wordTime;
       let asIndex = 0;
       let dhaspinyin = false; // 每段是否有拼音
+      this.isHasRemark = false;
       curQue.detail.forEach((dItem, dIndex) => {
         dhaspinyin = false;
         let roleDetail = this.getRole(dItem);
@@ -1200,6 +1206,8 @@ export default {
   }
 
   .NPC-sentences-list {
+    overflow: auto;
+
     .NPC-article-empty {
       display: flex;
       align-items: flex-start;

+ 9 - 1
src/views/book/courseware/preview/components/dialogue_article/PhraseModelChs.vue

@@ -50,7 +50,12 @@
       </div>
     </div>
     <template v-if="resArr.length > 0">
-      <div class="NPC-sentences-list">
+      <div
+        class="NPC-sentences-list"
+        :style="{
+          height: curQue.property.content_height ? curQue.property.content_height + 'px' : '',
+        }"
+      >
         <div class="NPC-article-empty">
           <div :class="['empty-left', isHasRemark ? 'hasRemark' : '']"></div>
           <div class="empty-right"></div>
@@ -809,6 +814,7 @@ export default {
       let leg = this.curQue.detail.length;
       let curQue = JSON.parse(JSON.stringify(this.curQue));
       let dhaspinyin = false; // 每段是否有拼音
+      this.isHasRemark = false;
       curQue.detail.forEach((dItem, dIndex) => {
         dhaspinyin = false;
         let roleDetail = this.getRole(dItem);
@@ -1242,6 +1248,8 @@ export default {
   }
 
   .NPC-sentences-list {
+    overflow: auto;
+
     .NPC-article-empty {
       display: flex;
       align-items: flex-start;

+ 7 - 2
src/views/book/courseware/preview/components/dialogue_article/Practicechs.vue

@@ -70,7 +70,12 @@
       <p v-if="curQue.notice" class="notice" style="padding-top: 24px">
         {{ curQue.notice }}
       </p>
-      <div class="NPC-sentences-list">
+      <div
+        class="NPC-sentences-list"
+        :style="{
+          height: curQue.property.content_height ? curQue.property.content_height + 'px' : '',
+        }"
+      >
         <div
           v-for="(item, index) in resObj.sentList"
           :key="'detail' + index"
@@ -1091,7 +1096,6 @@ export default {
         this.mergeWordTime(sentArrTotal, wordTimeList);
       }
       this.resObj = { sentList: resArr };
-      console.log(resArr);
     },
     // 获取角色
     getRole(dItem) {
@@ -1282,6 +1286,7 @@ export default {
 
   .NPC-sentences-list {
     padding: 0 0 24px;
+    overflow: auto;
   }
 
   .multilingual {

+ 10 - 2
src/views/book/courseware/preview/components/dialogue_article/WordModelChs.vue

@@ -50,7 +50,12 @@
       </div>
     </div>
     <template v-if="resArr.length > 0">
-      <div class="NPC-sentences-list">
+      <div
+        class="NPC-sentences-list"
+        :style="{
+          height: curQue.property.content_height ? curQue.property.content_height + 'px' : '',
+        }"
+      >
         <div class="NPC-article-empty">
           <div :class="['empty-left']"></div>
           <div class="empty-right"></div>
@@ -426,7 +431,7 @@
           </div>
         </div>
         <div class="NPC-article-empty NPC-article-empty-bottom">
-          <div :class="['empty-left', isHasRemark ? 'hasRemark' : '']"></div>
+          <div :class="['empty-left']"></div>
           <div class="empty-right"></div>
         </div>
         <template v-for="(items, indexs) in curQue.detail">
@@ -731,6 +736,7 @@ export default {
       let resArr = [];
       let curQue = JSON.parse(JSON.stringify(this.curQue));
       let dhaspinyin = false; // 每段是否有拼音
+      this.isHasRemark = false;
       curQue.detail.forEach((dItem, dIndex) => {
         dhaspinyin = false;
         let roleDetail = this.getRole(dItem);
@@ -1036,6 +1042,8 @@ export default {
   }
 
   .NPC-sentences-list {
+    overflow: auto;
+
     .NPC-article-empty {
       display: flex;
       align-items: flex-start;

+ 1 - 1
src/views/book/courseware/preview/components/dialogue_article/index.vue

@@ -798,7 +798,7 @@ export default {
       box-sizing: border-box;
       background: #fff;
       border: 1px solid rgba(0, 0, 0, 10%);
-      border-radius: 8px;
+      border-radius: 4px;
 
       .aduioLine-box {
         width: 100%;

+ 28 - 8
src/views/book/courseware/preview/components/image_text/components/MagazineSentence.vue

@@ -61,7 +61,12 @@
                 >
                 <span class="NNPE-chs">
                   <template>
-                    <span>{{ itemC.wordsName }}</span>
+                    <span
+                      :style="{
+                        fontFamily: itemC.fontFamily,
+                      }"
+                      >{{ itemC.wordsName }}</span
+                    >
                   </template>
                 </span>
                 <span
@@ -90,9 +95,14 @@
                       : data[sentenceActive].wordsResultList[indexC + 1].pinyin
                   }}</span
                 >
-                <span class="NNPE-chs" style="text-align: left">{{
-                  data[sentenceActive].wordsResultList[indexC + 1].wordsName
-                }}</span>
+                <span
+                  class="NNPE-chs"
+                  style="text-align: left"
+                  :style="{
+                    fontFamily: data[sentenceActive].wordsResultList[indexC + 1].fontFamily,
+                  }"
+                  >{{ data[sentenceActive].wordsResultList[indexC + 1].wordsName }}</span
+                >
                 <span
                   v-if="property.pinyin_position == 'bottom' && property.view_pinyin === 'true'"
                   :class="[
@@ -130,9 +140,14 @@
                       : data[sentenceActive].wordsResultList[indexC + 2].pinyin
                   }}</span
                 >
-                <span class="NNPE-chs" style="text-align: left">{{
-                  data[sentenceActive].wordsResultList[indexC + 2].wordsName
-                }}</span>
+                <span
+                  class="NNPE-chs"
+                  style="text-align: left"
+                  :style="{
+                    fontFamily: data[sentenceActive].wordsResultList[indexC + 2].fontFamily,
+                  }"
+                  >{{ data[sentenceActive].wordsResultList[indexC + 2].wordsName }}</span
+                >
                 <span
                   v-if="property.pinyin_position == 'bottom' && property.view_pinyin === 'true'"
                   :class="[
@@ -167,7 +182,12 @@
                 >
                 <span class="NNPE-chs">
                   <template>
-                    <span>{{ itemC.wordsName }}</span>
+                    <span
+                      :style="{
+                        fontFamily: itemC.fontFamily,
+                      }"
+                      >{{ itemC.wordsName }}</span
+                    >
                   </template>
                 </span>
                 <span

+ 7 - 7
src/views/book/courseware/preview/components/newWord_template/NewWordTemplatePreview.vue

@@ -570,7 +570,7 @@ export default {
     height: 80px;
     overflow: hidden;
     border: 2px solid #346cda;
-    border-radius: 8px;
+    border-radius: 4px;
   }
 
   .items-lian {
@@ -586,7 +586,7 @@ export default {
     min-height: 32px;
     margin-top: 16px;
     overflow: hidden;
-    border-radius: 8px;
+    border-radius: 4px;
 
     :deep .edit-div {
       min-height: 32px;
@@ -597,7 +597,7 @@ export default {
 
       // background-color: #deebff;
       border: 1px solid transparent;
-      border-radius: 8px;
+      border-radius: 4px;
     }
 
     .right {
@@ -645,14 +645,14 @@ export default {
 
     .rightBorderRadius {
       border-radius: 0;
-      border-top-right-radius: 8px;
-      border-bottom-right-radius: 8px;
+      border-top-right-radius: 4px;
+      border-bottom-right-radius: 4px;
     }
 
     .leftBorderRadius {
       border-radius: 0;
-      border-top-left-radius: 8px;
-      border-bottom-left-radius: 8px;
+      border-top-left-radius: 4px;
+      border-bottom-left-radius: 4px;
     }
 
     .NoborderRight {

+ 8 - 5
src/views/book/courseware/preview/components/new_word/NewWordPreview.vue

@@ -829,11 +829,12 @@
                     <div
                       :style="{
                         display: 'flex',
-                        justifyContent:
-                          !(item.collocation && item.liju_list) && item.new_word.length < 4 ? 'center' : 'auto',
+                        justifyContent: 'center',
                         columnGap: '16px',
                       }"
                     >
+                      <!-- 上面的样式 justifyContent:
+                          !(item.collocation && item.liju_list) && item.new_word.length < 4 ? 'center' : 'auto', -->
                       <div v-if="item.hz_info.length > 0" style="width: max-content">
                         <AudioPlay
                           v-if="item.mp3_list"
@@ -1163,8 +1164,10 @@ export default {
     },
   },
   mounted() {
-    let totalWidth = document.querySelector('.newWord-preview').offsetWidth;
-    this.width = `${totalWidth - (this.data.property.sn_display_mode === 'true' ? 15 : 0)}px`;
+    this.$nextTick(() => {
+      let totalWidth = document.querySelector('.newWord-preview').offsetWidth;
+      this.width = `${totalWidth - (this.data.property.sn_display_mode === 'true' ? 15 : 0)}px`;
+    });
 
     this.dataHeight = this.$refs.previewContainer.style.height;
   },
@@ -1494,7 +1497,7 @@ export default {
   .NPC-word-list {
     padding: 20px 24px;
     border: 1px solid rgba(0, 0, 0, 10%);
-    border-radius: 8px;
+    border-radius: 4px;
   }
 
   .detail-icon {

+ 4 - 3
src/views/book/courseware/preview/components/new_word/components/writeTableZoom.vue

@@ -68,10 +68,11 @@
         <div
           :style="{
             display: 'flex',
-            justifyContent: !(data.collocation && data.liju_list) && data.new_word.length < 4 ? 'center' : 'auto',
+            justifyContent: 'center',
             columnGap: '16px',
           }"
         >
+          <!-- justifyContent: !(data.collocation && data.liju_list) && data.new_word.length < 4 ? 'center' : 'auto', -->
           <div v-if="data.hz_info.length > 0" style="width: max-content">
             <AudioPlay
               v-if="data.mp3_list"
@@ -525,7 +526,8 @@ export default {
       }
 
       .hz-box {
-        width: 100%;
+        max-width: 528px; // 内容满屏 多余出滚动条
+        overflow: auto;
 
         .hz-item {
           text-align: center;
@@ -794,7 +796,6 @@ export default {
 
   .hz-box {
     display: flex;
-    flex-flow: wrap;
     width: max-content;
   }
 

+ 1 - 1
src/views/book/courseware/preview/components/notes/NotesPreview.vue

@@ -300,7 +300,7 @@ export default {
     .NPC-notes-list {
       padding: 24px 24px 5px;
       border: 1px solid rgba(0, 0, 0, 10%);
-      border-radius: 8px;
+      border-radius: 4px;
 
       .NPC-notes {
         width: 100%;

+ 2 - 2
src/views/book/courseware/preview/components/pinyin_base/PinyinBasePreview.vue

@@ -681,11 +681,11 @@ export default {
   }
 
   .option-content {
-    padding: 10px 22px;
+    padding: 5px 15px;
     color: #706f78;
     background-color: $content-color;
     border: 1px solid $content-color;
-    border-radius: 40px;
+    border-radius: 4px;
 
     &.all-right {
       background-color: $right-bc-color;

+ 18 - 12
src/views/book/courseware/preview/components/table/TablePreview.vue

@@ -41,20 +41,20 @@
                       : j === row.length - 1
                         ? '2px solid ' + data.property.decoration_color
                         : '1px dotted ' + data.property.border_color,
-                  borderRadius: i === 0 && data.property.first_line_color ? '5px ' : '0',
+                  borderRadius: i === 0 && data.property.first_line_color ? '4px ' : '0',
                   background:
                     i === 0 && data.property.first_line_color
                       ? data.property.first_line_color
                       : j === 0
                         ? data.property.first_column_color
-                        : '',
-
-                  backgroundColor: data.mode === 'short' ? data.styles.bgColor : '',
+                        : data.mode === 'short' && data.styles.bgColor
+                          ? data.styles.bgColor
+                          : '',
                 }"
               >
                 <div :style="[tdStyle, computedRichStyle(col.content)]" class="cell-wrap">
                   <template v-if="isEnable(data.property.view_pinyin)">
-                    <p
+                    <div
                       v-for="(item, index) in col.model_pinyin"
                       :key="index"
                       class="pinyin-text"
@@ -67,7 +67,7 @@
                             v-model="item.value"
                             :disabled="disabled"
                             :class="[...computedAnswerClass(item, i, j)]"
-                            :style="[{ width: Math.max(80, item.value.length * 21.3) + 'px' }]"
+                            :style="[{ width: Math.max(40, item.value.length * 21.3) + 'px' }]"
                           />
                         </template>
                         <template v-else-if="data.property.fill_type === fillTypeList[1].value">
@@ -88,7 +88,7 @@
                               v-model="item.value"
                               :readonly="true"
                               :class="[...computedAnswerClass(item, i, j)]"
-                              :style="[{ width: Math.max(80, item.value.length * 21.3) + 'px' }]"
+                              :style="[{ width: Math.max(40, item.value.length * 21.3) + 'px' }]"
                             />
                           </el-popover>
                         </template>
@@ -130,10 +130,10 @@
                           item.pinyin.replace(/\s+/g, '')
                         }}</span>
                       </template>
-                    </p>
+                    </div>
                   </template>
                   <template v-else>
-                    <p v-for="(item, index) in col.model_essay" :key="index" :style="[tdStyle]">
+                    <div v-for="(item, index) in col.model_essay" :key="index" :style="[tdStyle]">
                       <span
                         v-if="item.type === 'text'"
                         :key="index"
@@ -151,7 +151,7 @@
                             v-model="item.value"
                             :disabled="disabled"
                             :class="[...computedAnswerClass(item, i, j)]"
-                            :style="[{ width: Math.max(80, item.value.length * 21.3) + 'px' }]"
+                            :style="[{ width: Math.max(40, item.value.length * 21.3) + 'px' }]"
                           />
                         </template>
                         <template v-else-if="data.property.fill_type === fillTypeList[1].value">
@@ -172,7 +172,7 @@
                               v-model="item.value"
                               :readonly="true"
                               :class="[...computedAnswerClass(item, i, j)]"
-                              :style="[{ width: Math.max(80, item.value.length * 21.3) + 'px' }]"
+                              :style="[{ width: Math.max(40, item.value.length * 21.3) + 'px' }]"
                             />
                           </el-popover>
                         </template>
@@ -209,7 +209,7 @@
                           {{ computedAnswerText(item, i, j) }}
                         </span>
                       </template>
-                    </p>
+                    </div>
                   </template>
                 </div>
                 <span v-if="showLang" class="multilingual" :style="[tdStyle, computedRichStyle(col.content)]">
@@ -528,6 +528,12 @@ $border-color: #e6e6e6;
           border-radius: 0;
         }
       }
+
+      &-normal {
+        p {
+          width: 100%; // 为了解决换行问题
+        }
+      }
     }
 
     .multilingual {

+ 1 - 0
src/views/book/courseware/preview/components/upload_preview/UploadPreviewPreview.vue

@@ -264,6 +264,7 @@ export default {
         font-size: 14px;
         color: #1d2129;
         background-color: #f7f8fa;
+        border-radius: 4px;
 
         p {
           margin: 0;

+ 2 - 1
src/views/book/courseware/preview/components/write_base/WriteBasePreview.vue

@@ -57,7 +57,7 @@ export default {
     },
   },
   mounted() {
-    this.width = document.getElementsByClassName('write-base-preview')[0].clientWidth - 16;
+    this.width = document.getElementsByClassName('write-base-preview')[0].clientWidth;
     if (!this.isJudgingRightWrong) {
       this.answer.answer_list = this.data.write_base64;
     }
@@ -102,6 +102,7 @@ export default {
     .esign-box {
       position: relative;
       background-color: #f7f8fa;
+      border-radius: 4px;
 
       .btn-box {
         position: absolute;