This commit is contained in:
2025-01-23 10:32:14 +08:00
parent 1f169dc517
commit 85fbbd84f2
22 changed files with 3164 additions and 3263 deletions

View File

@@ -2,7 +2,7 @@ import Vue from 'vue';
import JSZip from 'jszip';
import Common from '@/components/common/common'
import Tiff from 'tiff.js';
var mediaUrl = Common.mediaUrl+'articleImage/';
var mediaUrl = Common.mediaUrl + 'articleImage/';
// var mediaUrl1 = 'https://submission.tmrjournals.com/public/articleImage/';
const fs = require('fs');
@@ -24,7 +24,7 @@ export default {
// 获取单元格的 HTML 内容
let htmlContent = cell.innerHTML.trim();
str = this.transformHtmlString(htmlContent)
// 创建一个临时的 DOM 元素来解析 HTML
const div = document.createElement('div');
div.innerHTML = htmlContent;
@@ -55,7 +55,7 @@ export default {
// 创建临时 DOM 容器
const tempDiv = document.createElement("div");
tempDiv.innerHTML = pastedHtml; // 插入粘贴的 HTML 内容
// 获取表格
const tables = tempDiv.querySelectorAll("table");
if (tables.length === 0) {
@@ -63,31 +63,31 @@ export default {
callback([]);
return;
}
const allTables = []; // 存储所有表格的二维数组
for (const table of tables) {
const rows = table.querySelectorAll("tr");
const tableArray = []; // 当前表格的二维数组
// 存储合并单元格信息
const mergeMap = {};
rows.forEach((row, rowIndex) => {
const cells = row.querySelectorAll("td, th");
const rowArray = [];
let colIndex = 0;
cells.forEach((cell) => {
// 跳过被合并的单元格
while (mergeMap[`${rowIndex},${colIndex}`]) {
colIndex++;
}
// 获取单元格内容,如果为空则设置为默认值
let cellText = cell.innerText.trim() || " "; // 处理空值
// 处理样式
if (cell.style.fontWeight === "bold") {
cellText = `<b>${cellText}</b>`;
@@ -101,18 +101,18 @@ export default {
if (cell.style.verticalAlign === "sub") {
cellText = `<sub>${cellText}</sub>`;
}
// 检查合并单元格属性
const colspan = parseInt(cell.getAttribute("colspan") || "1", 10);
const rowspan = parseInt(cell.getAttribute("rowspan") || "1", 10);
// 保存当前单元格信息
rowArray[colIndex] = {
text: cellText,
colspan: colspan,
rowspan: rowspan,
};
// 更新合并单元格信息
if (rowspan > 1 || colspan > 1) {
for (let i = 0; i < rowspan; i++) {
@@ -122,16 +122,16 @@ export default {
}
}
}
colIndex++; // 移动到下一列
});
tableArray.push(rowArray); // 添加当前行到表格数组
});
allTables.push(tableArray); // 添加当前表格到所有表格数组
}
console.log("解析后的表格数组:", allTables);
callback(allTables); // 返回处理后的数组
} catch (error) {
@@ -139,7 +139,7 @@ export default {
callback([]);
}
},
async extractWordTablesToArrays(file, callback) {
const Zip = new JSZip();
try {
@@ -445,23 +445,23 @@ export default {
console.log('numberingMap at line 232:', numberingMap)
// 提取表格
// 获取所有的段落
const paragraphs = xmlDoc.getElementsByTagName("w:p");
// 获取所有的表格
const tables = xmlDoc.getElementsByTagName("w:tbl");
const paragraphs = xmlDoc.getElementsByTagName("w:p");
// 获取所有的表格
const tables = xmlDoc.getElementsByTagName("w:tbl");
// 找到表格前的段落
let previousParagraphs = [];
let tableIndex = 0;
// 找到表格前的段落
let previousParagraphs = [];
let tableIndex = 0;
// 遍历段落,找到第一个表格之前的段落
for (let i = 0; i < paragraphs.length; i++) {
if (tableIndex < tables.length && paragraphs[i].nextSibling === tables[tableIndex]) {
break; // 找到表格
// 遍历段落,找到第一个表格之前的段落
for (let i = 0; i < paragraphs.length; i++) {
if (tableIndex < tables.length && paragraphs[i].nextSibling === tables[tableIndex]) {
break; // 找到表格
}
previousParagraphs.push(paragraphs[i]);
}
previousParagraphs.push(paragraphs[i]);
}
// 将前一段的内容转化为 HTML 或文本
const previousHtml = this.convertParagraphsToHtml(previousParagraphs);
// 将前一段的内容转化为 HTML 或文本
const previousHtml = this.convertParagraphsToHtml(previousParagraphs);
console.log('tables at line 17:', previousHtml)
const tableHtml = this.convertTablesToHtml(tables, numberingMap);
console.log('tableHtml at line 18:', tableHtml)
@@ -478,45 +478,45 @@ const previousHtml = this.convertParagraphsToHtml(previousParagraphs);
callback("<p>文件解析失败,请检查文件格式。</p>");
}
},
// 转换段落为 HTML
convertParagraphsToHtml(paragraphs) {
let html = "";
paragraphs.forEach(p => {
let paragraphHtml = "";
// 处理段落中的所有子元素
const runs = p.getElementsByTagName("w:r"); // 获取段落中的所有文本运行(可能包含上标、下标等)
Array.from(runs).forEach(run => {
let text = "";
// 获取文本内容
const textNodes = run.getElementsByTagName("w:t");
Array.from(textNodes).forEach(t => {
text += t.textContent || t.text;
// 转换段落为 HTML
convertParagraphsToHtml(paragraphs) {
let html = "";
paragraphs.forEach(p => {
let paragraphHtml = "";
// 处理段落中的所有子元素
const runs = p.getElementsByTagName("w:r"); // 获取段落中的所有文本运行(可能包含上标、下标等)
Array.from(runs).forEach(run => {
let text = "";
// 获取文本内容
const textNodes = run.getElementsByTagName("w:t");
Array.from(textNodes).forEach(t => {
text += t.textContent || t.text;
});
// 检查是否为上标或下标
const isSuperscript = run.getElementsByTagName("w:vertAlign")[0] ? run.getElementsByTagName("w:vertAlign")[0].getAttribute("w:val") === "superscript" : "";
const isSubscript = run.getElementsByTagName("w:vertAlign")[0] ? run.getElementsByTagName("w:vertAlign")[0].getAttribute("w:val") === "subscript" : '';
if (isSuperscript) {
text = `<sup>${text}</sup>`;
} else if (isSubscript) {
text = `<sub>${text}</sub>`;
}
// 拼接到段落 HTML 中
paragraphHtml += text;
});
// 检查是否为上标或下标
const isSuperscript = run.getElementsByTagName("w:vertAlign")[0]?run.getElementsByTagName("w:vertAlign")[0].getAttribute("w:val") === "superscript":"";
const isSubscript = run.getElementsByTagName("w:vertAlign")[0]?run.getElementsByTagName("w:vertAlign")[0].getAttribute("w:val") === "subscript":'';
if (isSuperscript) {
text = `<sup>${text}</sup>`;
} else if (isSubscript) {
text = `<sub>${text}</sub>`;
}
// 拼接到段落 HTML 中
paragraphHtml += text;
// 将运行的文本拼接成完整的段落
html += `<p>${paragraphHtml}</p>`;
});
// 将运行的文本拼接成完整的段落
html += `<p>${paragraphHtml}</p>`;
});
return html;
}
,
return html;
}
,
convertTablesToHtml(tables, numberingMap) {
const namespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
let html = "";
@@ -774,7 +774,7 @@ convertParagraphsToHtml(paragraphs) {
if (['jpg', 'jpeg', 'png'].includes(extension)) {
thumbnailContent = `<img src="${mediaUrl + img.image}" alt="Image ${index}" style="width: 100%; height: auto;">`;
} else if (extension === 'tif') {
thumbnailContent = `<canvas id="tiff-canvas-${index} ${img.article_image_id?`tiff-canvas-${img.article_image_id}`:''}" style="width: 100%; height: auto;"></canvas>`;
thumbnailContent = `<canvas id="tiff-canvas-${index} ${img.article_image_id ? `tiff-canvas-${img.article_image_id}` : ''}" style="width: 100%; height: auto;"></canvas>`;
} else {
thumbnailContent = `<a href="${mediaUrl + img.image}" style="color: #75abf1;width:100%; height: 100%;">
<div
@@ -948,7 +948,7 @@ convertParagraphsToHtml(paragraphs) {
//更新传入所有表格样式
updateTableStyles(container, type, setTopBottomBorder) {
var typesettingType = type ? type : 1
const tables = container.querySelectorAll('table');
tables.forEach((table) => {
@@ -1151,8 +1151,8 @@ convertParagraphsToHtml(paragraphs) {
},
initEditorButton(vueInstance,ed) {
initEditorButton(vueInstance, ed) {
ed.ui.registry.addMenuButton('customDropdown', {
text: 'Set Title', // 下拉框标题
fetch: function (callback) {
@@ -1197,6 +1197,26 @@ convertParagraphsToHtml(paragraphs) {
callback(menuItems);
}
});
ed.ui.registry.addButton('addRow', {
icon:'duplicate-row',
text: 'Add Row', // 下拉框标题
onAction: function () {
var edSelection = ed.selection;
const selectedNode = edSelection.getNode(); // 获取选中的节点
let outerDiv = selectedNode;
while (outerDiv && outerDiv.tagName !== 'DIV') {
outerDiv = outerDiv.parentNode;
}
// 如果找到的 div 节点存在
if (outerDiv) {
const dataId = outerDiv.getAttribute('main-id');
console.log('dataId at line 1258:', dataId)
vueInstance.$emit('onAddRow', dataId);
}
}
});
// 添加自定义菜单项
ed.ui.registry.addButton('Save', {
icon: 'checkmark',
@@ -1215,11 +1235,11 @@ convertParagraphsToHtml(paragraphs) {
var content;
console.log('outerDiv at line 663:', outerDiv.innerHTML);
content = outerDiv.innerHTML.replace(/<(?!\/?(img|b|i|sub|sup|span|strong|em |blue)\b)[^>]+>/g, '');
content =content.replace(/<([a-zA-Z]+)>\s*<\/\1>/g, '');
content = content.replace(/&nbsp;/g, ' ');
content = content.replace(/\s*style="[^"]*"/g, '');
content = content.replace(/<([a-zA-Z]+)>\s*<\/\1>/g, '');
content = content.replace(/&nbsp;/g, ' ');
content = content.replace(/\s*style="[^"]*"/g, '');
var div = document.createElement('div');
div.innerHTML = content; // 将 HTML 字符串加载到 div 中
// 替换所有 <strong> 为 <b>
@@ -1243,6 +1263,72 @@ convertParagraphsToHtml(paragraphs) {
}
}
});
ed.ui.registry.addButton('level1', {
// icon: 'highlight-bg-color',
text: 'First level title',
onAction: function () {
var edSelection = ed.selection;
const selectedNode = edSelection.getNode(); // 获取选中的节点
let outerDiv = selectedNode;
while (outerDiv && outerDiv.tagName !== 'DIV') {
outerDiv = outerDiv.parentNode;
}
// 如果找到的 div 节点存在
if (outerDiv) {
const dataId = outerDiv.getAttribute('main-id');
console.log('dataId at line 1258:', dataId)
vueInstance.$emit('onEditTitle', {
mainId: dataId,
value: 1
});
}
}
});
ed.ui.registry.addButton('level2', {
// icon: 'highlight-bg-color',
text: 'Second level Title',
onAction: function () {
var edSelection = ed.selection;
const selectedNode = edSelection.getNode(); // 获取选中的节点
let outerDiv = selectedNode;
while (outerDiv && outerDiv.tagName !== 'DIV') {
outerDiv = outerDiv.parentNode;
}
// 如果找到的 div 节点存在
if (outerDiv) {
const dataId = outerDiv.getAttribute('main-id');
console.log('dataId at line 1258:', dataId)
vueInstance.$emit('onEditTitle', {
mainId: dataId,
value: 2
});
}
}
});
ed.ui.registry.addButton('level3', {
// icon: 'highlight-bg-color',
text: 'Third level title',
onAction: function () {
var edSelection = ed.selection;
const selectedNode = edSelection.getNode(); // 获取选中的节点
let outerDiv = selectedNode;
while (outerDiv && outerDiv.tagName !== 'DIV') {
outerDiv = outerDiv.parentNode;
}
// 如果找到的 div 节点存在
if (outerDiv) {
const dataId = outerDiv.getAttribute('main-id');
console.log('dataId at line 1258:', dataId)
vueInstance.$emit('onEditTitle', {
mainId: dataId,
value: 3
});
}
}
});
ed.ui.registry.addButton('Edit', {
icon: 'highlight-bg-color',
text: 'Edit',
@@ -1277,15 +1363,87 @@ convertParagraphsToHtml(paragraphs) {
// 如果找到的 div 节点存在
if (outerDiv) {
const dataId = outerDiv.getAttribute('main-id');
let selectedText = edSelection.getContent({ format: 'text' });
vueInstance.$emit('onAddComment', {
mainId: dataId,
label: selectedText ? selectedText : ''
const type = outerDiv.getAttribute('type');
console.log('type:', type);
// 获取选中的内容HTML格式
let selectedContent = edSelection.getContent({ format: 'html' });
// 创建一个临时容器来处理 HTML
const tempDiv = document.createElement('div');
tempDiv.innerHTML = selectedContent;
// 检查是否包含 <img> 标签
const hasImage = tempDiv.querySelector('img') !== null;
if (hasImage) {
vueInstance.$message.error(vueInstance.$t('commonTable.selectComment'));
return; // 如果包含图片,停止处理
}
// 获取清理后的纯文本内容
let selectedText = tempDiv.innerText.trim(); // 使用 trim() 清理前后的空格
// 处理文本中的多余空格:替换多个连续空格为一个空格
selectedText = selectedText.replace(/\s+/g, ' ');
// 确保保留的标签
const allowedTags = ['sup', 'sub', 'strong', 'em', 'b', 'i', 'blue', 'tr', 'td'];
// 遍历选中的节点并保留需要的标签
function preserveTags(node) {
if (node.nodeType === 3) { // 文本节点
return node.nodeValue;
}
if (node.nodeType === 1 && allowedTags.includes(node.nodeName.toLowerCase())) {
return node.outerHTML; // 保留整个标签
}
return '';
}
let preservedContent = '';
Array.from(tempDiv.childNodes).forEach((childNode) => {
preservedContent += preserveTags(childNode);
});
// 检查选中的内容是否已经包含嵌套批注
const containsPositionRemark = tempDiv.querySelector('.positionRemarkIndex');
if (containsPositionRemark) {
vueInstance.$message.error(vueInstance.$t('commonTable.alreadyCommented'));
return; // 如果已有嵌套批注,停止处理
}
// 如果内容不为空,发送批注请求
if (type == 0) {
if (selectedText !== '') {
vueInstance.$emit('onAddComment', {
mainId: dataId,
label: preservedContent // 发送保留标签的内容
});
} else {
vueInstance.$message.error(vueInstance.$t('commonTable.selectComment'));
}
} else if (type == 1) {
vueInstance.$emit('onAddComment', {
mainId: dataId,
label: preservedContent // 发送保留标签的内容
});
} else if (type == 2) {
vueInstance.$emit('onAddComment', {
mainId: dataId,
label: preservedContent // 发送保留标签的内容
});
}
}
}
}
});
ed.ui.registry.addButton('delete', {
icon: 'remove',
text: 'Delete',
@@ -1301,10 +1459,10 @@ convertParagraphsToHtml(paragraphs) {
// 如果找到的 div 节点存在
if (outerDiv) {
const dataId = outerDiv.getAttribute('main-id');
vueInstance.$emit('onDelete',dataId);
vueInstance.$emit('onDelete', dataId);
}
}
}
});
@@ -1320,6 +1478,8 @@ convertParagraphsToHtml(paragraphs) {
ed.ui.registry.addButton('customBlue', {
text: 'Blue', // 按钮文本
className: 'custom-button-blue', // 添加自定义类
// shortcut: "Ctrl+J",
onAction: function () {
// 在选中的文本周围包裹 <blue> 标签
var selectedText = ed.selection.getContent();
@@ -1369,7 +1529,39 @@ convertParagraphsToHtml(paragraphs) {
}
});
},
inTinymceButtonClass() {
setTimeout(function () {
// 查找该按钮并添加 className
const commentaddbutton = document.querySelector('.tox-toolbar .tox-toolbar__group .tox-tbtn[data-mce-name="commentadd"]');
if (commentaddbutton) {
commentaddbutton.classList.add('tinymce-custom-button-commentadd');
}
const addrowbutton = document.querySelector('.tox-toolbar .tox-toolbar__group .tox-tbtn[data-mce-name="addrow"]');
if (addrowbutton) {
addrowbutton.classList.add('tinymce-custom-button-addrow');
}
const deletebutton = document.querySelector('.tox-toolbar .tox-toolbar__group .tox-tbtn[data-mce-name="delete"]');
if (deletebutton) {
deletebutton.classList.add('tinymce-custom-button-delete');
}
const editbutton = document.querySelector('.tox-toolbar .tox-toolbar__group .tox-tbtn[data-mce-name="edit"]');
if (editbutton) {
editbutton.classList.add('tinymce-custom-button-edit');
}
const savebutton = document.querySelector('.tox-toolbar .tox-toolbar__group .tox-tbtn[data-mce-name="save"]');
if (savebutton) {
savebutton.classList.add('tinymce-custom-button-save');
}
const button = document.querySelector('.tox-toolbar .tox-toolbar__group .tox-tbtn[data-mce-name="customblue"]');
if (button) {
button.classList.add('tinymce-custom-button-blue');
}
const removebutton = document.querySelector('.tox-toolbar .tox-toolbar__group .tox-tbtn[data-mce-name="removeblue"]');
if (removebutton) {
removebutton.classList.add('tinymce-custom-button-removeblue');
}
}, 100); // 延迟执行,确保按钮渲染完成
}
// 通用递归方法