From 887851419d98568a815de95a6a96fbdfb3dfcf38 Mon Sep 17 00:00:00 2001 From: qx <1084500556@qq.com> Date: 星期四, 26 六月 2025 15:21:22 +0800 Subject: [PATCH] qx --- src/views/ceshi.vue | 198 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 198 insertions(+), 0 deletions(-) diff --git a/src/views/ceshi.vue b/src/views/ceshi.vue new file mode 100644 index 0000000..4a8f64d --- /dev/null +++ b/src/views/ceshi.vue @@ -0,0 +1,198 @@ +<template> + <div> + <h3>鍓嶇 Word 缂栬緫鍣紙TinyMCE锛�</h3> + <editor v-model="content" :init="editorInit" :api-key="apiKey"></editor> + <div class="actions"> + <button @click="exportToWord">瀵煎嚭 Word</button> + <button @click="exportToPDF">瀵煎嚭 PDF</button> + </div> + </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'; + +export default { + components: { Editor }, + data() { + return { + apiKey: '3ceaxd5ckw4te35xj38vj3p5rmmeyv0x8pq2yrr92rwdiqzp', // 鎮ㄧ殑 TinyMCE API 瀵嗛挜 + 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', // 灏濊瘯 zh-CN + }, + }; + }, + methods: { + exportToWord() { + this.parseHtmlToDocx(this.content).then((elements) => { + const doc = new Document({ + sections: [{ properties: {}, children: elements }], + }); + + Packer.toBlob(doc).then((blob) => { + saveAs(blob, '鏂囨。.docx'); + }).catch((err) => { + console.error('鐢熸垚 Word 澶辫触锛�', err); + }); + }).catch((err) => { + console.error('瑙f瀽 HTML 澶辫触锛�', err); + }); + }, + parseHtmlToDocx(html) { + return new Promise((resolve, reject) => { + const parser = new DOMParser(); + const doc = parser.parseFromString(html, 'text/html'); + const elements = []; + + const processNode = (node, callback) => { + if (node.nodeType === Node.ELEMENT_NODE) { + if (node.tagName === 'P') { + const textRuns = Array.from(node.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') { + this.getImageBase64FromUrl(child.src).then((base64) => { + callback(null, new ImageRun({ + data: base64, + transformation: { width: 200, height: 200 }, + })); + }).catch((err) => { + console.error('鍥剧墖鍔犺浇澶辫触锛�', err); + callback(null, new TextRun(`[鍥剧墖: ${child.alt || '鍥惧儚'}]`)); + }); + return null; + } + 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') { + Array.from(node.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 = Array.from(node.querySelectorAll('tr')).map((tr) => { + const cells = Array.from(tr.querySelectorAll('td, th')).map((cell) => { + return new DocxTableCell({ + children: [new Paragraph(cell.textContent || '')], + }); + }); + return new DocxTableRow({ children: cells }); + }); + elements.push(new DocxTable({ rows })); + } + Array.from(node.children).forEach((child) => processNode(child, callback)); + } + callback(null); + }; + + const nodes = Array.from(doc.body.childNodes); + let completed = 0; + const checkCompletion = () => { + completed++; + if (completed === nodes.length) { + resolve(elements); + } + }; + + if (nodes.length === 0) { + resolve(elements); + } else { + nodes.forEach((node) => { + processNode(node, checkCompletion); + }); + } + }); + }, + getImageBase64FromUrl(url) { + return new Promise((resolve, reject) => { + fetch(url, { mode: 'cors' }) + .then((response) => { + if (!response.ok) throw new Error('缃戠粶鍥剧墖鍔犺浇澶辫触'); + return response.blob(); + }) + .then((blob) => { + const reader = new FileReader(); + reader.onloadend = () => resolve(reader.result.split(',')[1]); + reader.onerror = () => reject(new Error('鍥剧墖璇诲彇澶辫触')); + reader.readAsDataURL(blob); + }) + .catch((err) => reject(err)); + }); + }, + exportToPDF() { + 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'); + }) + .catch((err) => { + console.error('鐢熸垚 PDF 澶辫触锛�', err); + document.body.removeChild(contentElement); + }); + }, + }, +}; +</script> + +<style> +.actions { + margin-top: 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