From 6d4e9ccb34e0292bfadba7bfd678231cb37ae8c0 Mon Sep 17 00:00:00 2001
From: qx <1084500556@qq.com>
Date: 星期三, 02 七月 2025 15:45:16 +0800
Subject: [PATCH] :qx

---
 src/views/111111.vue |  335 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 335 insertions(+), 0 deletions(-)

diff --git a/src/views/111111.vue b/src/views/111111.vue
new file mode 100644
index 0000000..039340f
--- /dev/null
+++ b/src/views/111111.vue
@@ -0,0 +1,335 @@
+<template>
+  <div>
+    <h3>鍓嶇 Word 缂栬緫鍣紙TinyMCE锛�</h3>
+    <div class="actions">
+      <input type="file" accept=".docx" @change="importWord" ref="fileInput" style="margin-right: 10px;" />
+      <button @click="exportToWord">瀵煎嚭 Word</button>
+      <button @click="exportToPDF">瀵煎嚭 PDF</button>
+    </div>
+    <editor v-model="content" :init="editorInit" :api-key="apiKey"></editor>
+  </div>
+</template>
+<script>
+import Editor from '@tinymce/tinymce-vue';
+import { Document, Packer, Paragraph, TextRun, ImageRun, Table as DocxTable, TableRow as DocxTableRow, TableCell as DocxTableCell } from 'docx';
+import { saveAs } from 'file-saver';
+import jsPDF from 'jspdf';
+import html2canvas from 'html2canvas';
+import mammoth from 'mammoth';
+
+export default {
+  components: { Editor },
+  data() {
+    return {
+      apiKey: '3ceaxd5ckw4te35xj38vj3p5rmmeyv0x8pq2yrr92rwdiqzp',
+      content: '',
+      editorInit: {
+        height: 500,
+        menubar: true,
+        plugins: [
+          'advlist autolink lists link image charmap print preview anchor',
+          'searchreplace visualblocks code fullscreen',
+          'insertdatetime media table paste code help wordcount'
+        ],
+        toolbar:
+          'undo redo | formatselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | image table | removeformat | help',
+        images_upload_handler: (blobInfo, success, failure) => {
+          const reader = new FileReader();
+          reader.onload = () => success(reader.result);
+          reader.onerror = () => failure('鍥剧墖涓婁紶澶辫触');
+          reader.readAsDataURL(blobInfo.blob());
+        },
+        content_style: 'body { font-family: SimSun, Arial; font-size: 14px; }',
+        table_default_attributes: { border: 1 },
+        readonly: false,
+        language: 'zh-CN',
+      },
+    };
+  },
+  methods: {
+    /** 瀵煎叆 Word 鏂囨。 */
+    importWord(event) {
+      const file = event.target.files[0];
+      if (!file) {
+        this.$message.error('璇烽�夋嫨涓�涓� .docx 鏂囦欢');
+        return;
+      }
+      if (!file.name.endsWith('.docx')) {
+        this.$message.error('璇蜂笂浼� .docx 鏍煎紡鐨勬枃浠�');
+        return;
+      }
+
+      const reader = new FileReader();
+      reader.onload = async (e) => {
+        try {
+          const arrayBuffer = e.target.result;
+          const result = await mammoth.convertToHtml({ arrayBuffer });
+          this.content = result.value || '<p>鏃犲唴瀹�</p>';
+          this.$message.success('Word 鏂囨。瀵煎叆鎴愬姛');
+          this.$refs.fileInput.value = '';
+        } catch (err) {
+          console.error('瀵煎叆 Word 澶辫触锛�', err);
+          this.$message.error('瀵煎叆 Word 鏂囨。澶辫触锛�' + err.message);
+        }
+      };
+      reader.onerror = () => {
+        this.$message.error('璇诲彇鏂囦欢澶辫触');
+      };
+      reader.readAsArrayBuffer(file);
+    },
+
+    /** 瀵煎嚭涓� Word */
+    exportToWord() {
+      if (!this.content || this.content.trim() === '') {
+        this.$message.error('缂栬緫鍣ㄥ唴瀹逛负绌猴紝鏃犳硶瀵煎嚭');
+        return;
+      }
+      this.parseHtmlToDocx(this.content).then((elements) => {
+        const doc = new Document({
+          sections: [{ properties: {}, children: elements }],
+        });
+
+        Packer.toBlob(doc).then((blob) => {
+          saveAs(blob, '鏂囨。.docx');
+          this.$message.success('瀵煎嚭 Word 鎴愬姛');
+        }).catch((err) => {
+          console.error('鐢熸垚 Word 澶辫触锛�', err);
+          this.$message.error('鐢熸垚 Word 澶辫触锛�' + err.message);
+        });
+      }).catch((err) => {
+        console.error('瑙f瀽 HTML 澶辫触锛�', err);
+        this.$message.error('瑙f瀽 HTML 澶辫触锛�' + err.message);
+      });
+    },
+
+    /** 瑙f瀽 HTML 涓� docx 鍏冪礌 */
+    parseHtmlToDocx(html) {
+      return new Promise((resolve, reject) => {
+        if (!html || typeof html !== 'string') {
+          reject(new Error('鏃犳晥鐨� HTML 鍐呭'));
+          return;
+        }
+
+        console.log('Input HTML:', html); // 璋冭瘯杈撳叆 HTML
+
+        const parser = new DOMParser();
+        const doc = parser.parseFromString(html, 'text/html');
+        if (!doc || !doc.body) {
+          reject(new Error('HTML 瑙f瀽澶辫触锛氭枃妗g粨鏋勬棤鏁�'));
+          return;
+        }
+
+        const elements = [];
+        const imagePromises = [];
+
+        const processNode = (node) => {
+          if (node.nodeType !== Node.ELEMENT_NODE) {
+            return;
+          }
+
+          console.log('Processing node:', node.tagName); // 璋冭瘯鑺傜偣
+
+          if (node.tagName === 'P') {
+            const childNodes = node.childNodes ? Array.from(node.childNodes) : [];
+            const textRuns = childNodes.map((child) => {
+              if (child.nodeType === Node.TEXT_NODE) {
+                return new TextRun({ text: child.textContent || '' });
+              } else if (child.tagName === 'B') {
+                return new TextRun({ text: child.textContent || '', bold: true });
+              } else if (child.tagName === 'I') {
+                return new TextRun({ text: child.textContent || '', italics: true });
+              } else if (child.tagName === 'IMG') {
+                const promise = this.getImageBase64FromUrl(child.src).then(({ base64, width, height }) => {
+                  return new ImageRun({
+                    data: base64,
+                    transformation: { width, height },
+                  });
+                }).catch((err) => {
+                  console.error('鍥剧墖鍔犺浇澶辫触锛�', err, 'URL:', child.src);
+                  return new TextRun(`[鍥剧墖: ${child.alt || '鍥惧儚'}]`);
+                });
+                imagePromises.push(promise);
+                return promise;
+              }
+              return new TextRun({ text: child.textContent || '' });
+            }).filter(Boolean);
+            if (textRuns.length) {
+              elements.push(new Paragraph({ children: textRuns }));
+            }
+          } else if (node.tagName === 'H1') {
+            elements.push(new Paragraph({ text: node.textContent || '', heading: 'Heading1' }));
+          } else if (node.tagName === 'UL' || node.tagName === 'OL') {
+            const children = node.children ? Array.from(node.children) : [];
+            children.forEach((li) => {
+              elements.push(
+                new Paragraph({
+                  text: li.textContent || '',
+                  bullet: node.tagName === 'UL' ? { level: 0 } : { level: 0, number: true },
+                })
+              );
+            });
+          } else if (node.tagName === 'TABLE') {
+            const rows = node.querySelectorAll('tr') ? Array.from(node.querySelectorAll('tr')) : [];
+            const tableRows = rows.map((tr) => {
+              const cells = tr.querySelectorAll('td, th') ? Array.from(tr.querySelectorAll('td, th')) : [];
+              const tableCells = cells.map((cell) => {
+                return new DocxTableCell({
+                  children: [new Paragraph(cell.textContent || '')],
+                });
+              });
+              return new DocxTableRow({ children: tableCells });
+            });
+            if (tableRows.length) {
+              elements.push(new DocxTable({ rows: tableRows }));
+            }
+          }
+          const children = node.children ? Array.from(node.children) : [];
+          children.forEach(processNode);
+        };
+
+        const nodes = doc.body.childNodes ? Array.from(doc.body.childNodes) : [];
+        if (nodes.length === 0) {
+          console.warn('HTML 鏂囨。鏃犳湁鏁堣妭鐐�');
+          resolve(elements);
+          return;
+        }
+
+        nodes.forEach(processNode);
+
+        Promise.all(imagePromises).then((imageRuns) => {
+          let imageIndex = 0;
+          elements.forEach((element, index) => {
+            if (!(element instanceof Paragraph)) {
+              console.log('Skipping non-Paragraph element at index', index, 'type:', element.constructor.name);
+              return; // 璺宠繃闈� Paragraph 鍏冪礌
+            }
+            if (!Array.isArray(element.children)) {
+              console.warn('Element at index', index, 'has invalid children:', element.children);
+              element.children = []; // 鍒濆鍖栦负绌烘暟缁�
+              return;
+            }
+            console.log('Processing element at index', index, 'children:', element.children);
+            element.children = element.children.map((child, childIndex) => {
+              if (child instanceof Promise) {
+                const imageRun = imageRuns[imageIndex++] || new TextRun('[鍥剧墖鍔犺浇澶辫触]');
+                console.log('Replacing Promise at child index', childIndex, 'with:', imageRun);
+                return imageRun;
+              }
+              return child;
+            });
+          });
+          resolve(elements);
+        }).catch((err) => {
+          console.error('鍥剧墖澶勭悊澶辫触锛�', err);
+          reject(new Error('鍥剧墖澶勭悊澶辫触锛�' + err.message));
+        });
+      });
+    },
+
+    /** 鑾峰彇鍥剧墖鐨� Base64 鏁版嵁鍜屽昂瀵� */
+    getImageBase64FromUrl(url) {
+      return new Promise((resolve, reject) => {
+        if (!url) {
+          reject(new Error('鍥剧墖 URL 涓虹┖'));
+          return;
+        }
+
+        console.log('Fetching image:', url);
+
+        if (url.startsWith('data:image/')) {
+          const base64 = url.split(',')[1];
+          const img = new Image();
+          img.onload = () => {
+            const maxWidth = 200;
+            const maxHeight = 200;
+            let { width, height } = img;
+            if (width > maxWidth || height > maxHeight) {
+              const ratio = Math.min(maxWidth / width, maxHeight / height);
+              width = Math.round(width * ratio);
+              height = Math.round(height * ratio);
+            }
+            resolve({ base64, width, height });
+          };
+          img.onerror = () => reject(new Error('Base64 鍥剧墖鍔犺浇澶辫触'));
+          img.src = url;
+          return;
+        }
+
+        fetch(url, { mode: 'cors' })
+          .then((response) => {
+            if (!response.ok) throw new Error('缃戠粶鍥剧墖鍔犺浇澶辫触');
+            return response.blob();
+          })
+          .then((blob) => {
+            const reader = new FileReader();
+            reader.onloadend = () => {
+              const base64 = reader.result.split(',')[1];
+              const img = new Image();
+              img.onload = () => {
+                const maxWidth = 200;
+                const maxHeight = 200;
+                let { width, height } = img;
+                if (width > maxWidth || height > maxHeight) {
+                  const ratio = Math.min(maxWidth / width, maxHeight / height);
+                  width = Math.round(width * ratio);
+                  height = Math.round(height * ratio);
+                }
+                resolve({ base64, width, height });
+              };
+              img.onerror = () => reject(new Error('鍥剧墖璇诲彇澶辫触'));
+              img.src = reader.result;
+            };
+            reader.onerror = () => reject(new Error('鍥剧墖璇诲彇澶辫触'));
+            reader.readAsDataURL(blob);
+          })
+          .catch((err) => reject(err));
+      });
+    },
+
+    /** 瀵煎嚭涓� PDF */
+    exportToPDF() {
+      if (!this.content || this.content.trim() === '') {
+        this.$message.error('缂栬緫鍣ㄥ唴瀹逛负绌猴紝鏃犳硶瀵煎嚭');
+        return;
+      }
+      const contentElement = document.createElement('div');
+      contentElement.innerHTML = this.content;
+      contentElement.style.padding = '10px';
+      document.body.appendChild(contentElement);
+
+      html2canvas(contentElement, { scale: 2 })
+        .then((canvas) => {
+          const doc = new jsPDF();
+          const imgData = canvas.toDataURL('image/png');
+          doc.addImage(imgData, 'PNG', 10, 10, 190, 0);
+          doc.save('鏂囨。.pdf');
+          this.$message.success('瀵煎嚭 PDF 鎴愬姛');
+          document.body.removeChild(contentElement);
+        })
+        .catch((err) => {
+          console.error('鐢熸垚 PDF 澶辫触锛�', err);
+          this.$message.error('鐢熸垚 PDF 澶辫触锛�' + err.message);
+          document.body.removeChild(contentElement);
+        });
+    },
+  },
+};
+</script>
+<style>
+.actions {
+  margin-top: 10px;
+  margin-bottom: 10px;
+}
+.actions button {
+  padding: 8px 16px;
+  margin-right: 10px;
+  background-color: #409eff;
+  color: white;
+  border: none;
+  border-radius: 4px;
+  cursor: pointer;
+}
+.actions button:hover {
+  background-color: #66b1ff;
+}
+</style>
\ No newline at end of file

--
Gitblit v1.8.0