Browse Source

简繁转换问题

dsy 2 weeks ago
parent
commit
be8d648f06
2 changed files with 93 additions and 27 deletions
  1. 52 27
      src/components/PinyinText.vue
  2. 41 0
      src/web_preview/index.vue

+ 52 - 27
src/components/PinyinText.vue

@@ -17,9 +17,13 @@
             }"
             @click="correctPinyin(item, i, j, k)"
           >
-            <span v-if="pinyinPosition === 'top'" class="pinyin">{{ item.pinyin.replace(/\s+/g, '') }}</span>
-            <span class="py-char" :style="{ ...item.activeTextStyle }">{{ item.text }}</span>
-            <span v-if="pinyinPosition !== 'top'" class="pinyin">{{ item.pinyin.replace(/\s+/g, '') }}</span>
+            <span v-if="pinyinPosition === 'top'" class="pinyin" :style="{ 'font-size': pinyinSize }">{{
+              item.pinyin.replace(/\s+/g, '')
+            }}</span>
+            <span class="py-char" :style="textStyle(item)">{{ convertText(item.text) }}</span>
+            <span v-if="pinyinPosition !== 'top'" class="pinyin" :style="{ 'font-size': pinyinSize }">{{
+              item.pinyin.replace(/\s+/g, '')
+            }}</span>
           </span>
         </span>
       </span>
@@ -36,11 +40,10 @@
       ref="optimizedDialog"
       title=""
       :visible.sync="noteDialogVisible"
-      width="90%"
+      width="680px"
       :style="dialogStyle"
       :close-on-click-modal="false"
       destroy-on-close
-      class="center-dialog"
       @close="noteDialogVisible = false"
     >
       <span v-html="sanitizeHTML(note)"></span>
@@ -57,6 +60,7 @@ export default {
   components: {
     CorrectPinyin,
   },
+  inject: ['convertText'],
   props: {
     paragraphList: {
       type: Array,
@@ -66,6 +70,18 @@ export default {
       type: String,
       required: true,
     },
+    fontFamily: {
+      type: String,
+      default: '',
+    },
+    fontSize: {
+      type: String,
+      default: '12pt',
+    },
+    pinyinSize: {
+      type: String,
+      default: '12pt',
+    },
     pinyinOverallPosition: {
       type: String,
       default: 'left',
@@ -96,9 +112,40 @@ export default {
         left: '0',
         margin: '0',
       },
+      isAllSetting: false,
     };
   },
+  computed: {
+    styleWatch() {
+      return {
+        fontSize: this.fontSize,
+        fontFamily: this.fontFamily,
+      };
+    },
+  },
+  watch: {
+    styleWatch: {
+      handler() {
+        this.isAllSetting = true;
+      },
+      immediate: true,
+      deep: true,
+    },
+  },
+
   methods: {
+    textStyle(item) {
+      const styles = { ...item.activeTextStyle };
+      styles['font-size'] = styles.fontSize;
+      styles['font-family'] = styles.fontFamily;
+
+      // if (this.fontSize) styles['font-size'] = this.fontSize;
+      // if (this.fontFamily) styles['font-family'] = this.fontFamily;
+      if (this.isAllSetting || !styles.fontSize) styles['font-size'] = this.fontSize;
+      if (this.isAllSetting || !styles.fontFamily) styles['font-family'] = this.fontFamily;
+      this.isAllSetting = false;
+      return styles;
+    },
     // 校对拼音
     correctPinyin(item, i, j, k) {
       if (this.isPreview) {
@@ -217,26 +264,4 @@ export default {
 .pinyin-area + .pinyin-area {
   margin-top: 4px;
 }
-
-.center-dialog .el-dialog {
-  position: fixed !important;
-  top: 50% !important;
-  left: 50% !important;
-  max-width: 90vw !important;
-  max-height: 90vh !important;
-  margin: 0 !important;
-  transition: none !important; /* 禁用过渡 */
-  transform: translate(-50%, -50%) !important;
-  animation: none !important; /* 禁用动画 */
-}
-
-/* 禁用对话框的动画类 */
-.center-dialog .el-dialog {
-  animation-duration: 0s !important;
-}
-
-/* 如果需要,也可以禁用整个对话框的动画 */
-.center-dialog {
-  animation: none !important;
-}
 </style>

+ 41 - 0
src/web_preview/index.vue

@@ -985,11 +985,52 @@ export default {
      */
     convertText(text) {
       if (this.chinese === 'zh-Hant' && this.opencc) {
+        try {
+          if (/<[a-z][\s\S]*>/i.test(text)) {
+            return this.convertHtmlPreserveAttributes(text);
+          }
+        } catch (e) {
+          return text;
+        }
         return this.opencc(text);
       }
       return text;
     },
 
+    /**
+     * 使用OpenCC解析HTML并仅转换文本节点,保留属性(包括内联样式/font-family)保持不变。防止字体名称像“微软雅黑' 正在转换为'微軟雅黑'.
+     */
+    convertHtmlPreserveAttributes(html) {
+      try {
+        const parser = new DOMParser();
+        const doc = parser.parseFromString(html, 'text/html');
+
+        // 跳过这些标记内的转换
+        const skipTags = new Set(['SCRIPT', 'STYLE']);
+
+        const walker = doc.createTreeWalker(doc.body, NodeFilter.SHOW_TEXT, null, false);
+        let node = walker.nextNode();
+        while (node) {
+          const parent = node.parentNode;
+          if (parent && !skipTags.has(parent.nodeName)) {
+            const v = node.nodeValue;
+            if (v && v.trim()) {
+              node.nodeValue = this.opencc(v);
+            }
+          }
+          node = walker.nextNode();
+        }
+
+        return doc.body.innerHTML;
+      } catch (err) {
+        try {
+          return this.opencc(html);
+        } catch (e) {
+          return html;
+        }
+      }
+    },
+
     simulateAnswer(disabled = true) {
       this.$refs.courserware.simulateAnswer(this.isJudgeCorrect, this.isShowAnswer, disabled);
     },