Merge branch 'master' of https://gitee.com/wjl2008_admin/tougao_web into pay
This commit is contained in:
@@ -3,7 +3,14 @@
|
||||
registry: 'https://registry.npmmirror.com',
|
||||
pkgs: [
|
||||
{
|
||||
name: 'spellchecker',
|
||||
name: 'tinymce',
|
||||
version: 'latest',
|
||||
type: 'tag',
|
||||
alias: undefined,
|
||||
arg: [Result]
|
||||
},
|
||||
{
|
||||
name: 'tinymce-kityformula-editor',
|
||||
version: 'latest',
|
||||
type: 'tag',
|
||||
alias: undefined,
|
||||
@@ -15,7 +22,7 @@
|
||||
cacheDir: 'C:\\Users\\Administrator\\.npminstall_tarball',
|
||||
env: {
|
||||
npm_config_registry: 'https://registry.npmmirror.com',
|
||||
npm_config_argv: '{"remain":[],"cooked":["--fix-bug-versions","--china","--userconfig=C:\\\\Users\\\\Administrator\\\\.cnpmrc","--disturl=https://cdn.npmmirror.com/binaries/node","--registry=https://registry.npmmirror.com","spellchecker"],"original":["--fix-bug-versions","--china","--userconfig=C:\\\\Users\\\\Administrator\\\\.cnpmrc","--disturl=https://cdn.npmmirror.com/binaries/node","--registry=https://registry.npmmirror.com","spellchecker"]}',
|
||||
npm_config_argv: '{"remain":[],"cooked":["--fix-bug-versions","--china","--userconfig=C:\\\\Users\\\\Administrator\\\\.cnpmrc","--disturl=https://cdn.npmmirror.com/binaries/node","--registry=https://registry.npmmirror.com","tinymce","tinymce-kityformula-editor"],"original":["--fix-bug-versions","--china","--userconfig=C:\\\\Users\\\\Administrator\\\\.cnpmrc","--disturl=https://cdn.npmmirror.com/binaries/node","--registry=https://registry.npmmirror.com","tinymce","tinymce-kityformula-editor"]}',
|
||||
npm_config_user_agent: 'npminstall/7.12.0 npm/? node/v16.14.1 win32 x64',
|
||||
npm_config_cache: 'C:\\Users\\Administrator\\.npminstall_tarball',
|
||||
NODE: 'C:\\Program Files\\nodejs\\node.exe',
|
||||
@@ -119,7 +126,10 @@
|
||||
},
|
||||
fsevents: { host: 'https://cdn.npmmirror.com/binaries/fsevents' },
|
||||
nodejieba: { host: 'https://cdn.npmmirror.com/binaries/nodejieba' },
|
||||
canvas: { host: 'https://cdn.npmmirror.com/binaries/canvas' },
|
||||
canvas: {
|
||||
host: 'https://cdn.npmmirror.com/binaries/canvas',
|
||||
remote_path: 'v{version}'
|
||||
},
|
||||
'skia-canvas': { host: 'https://cdn.npmmirror.com/binaries/skia-canvas' },
|
||||
'flow-bin': {
|
||||
replaceHost: 'https://github.com/facebook/flow/releases/download/v',
|
||||
|
||||
@@ -25,7 +25,9 @@
|
||||
"html2canvas": "^1.4.1",
|
||||
"install": "^0.13.0",
|
||||
"jszip": "^3.10.1",
|
||||
"katex": "^0.16.21",
|
||||
"mammoth": "^1.5.1",
|
||||
"mathlive": "^0.104.0",
|
||||
"mavon-editor": "^2.6.17",
|
||||
"multi-items-input": "^0.2.0",
|
||||
"pizzip": "^3.1.7",
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body><script src="<%=BASE_URL %>/tinymce/tinymce.min.js"></script>
|
||||
|
||||
<script async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
|
||||
<script src="/js/global-math.js"></script>
|
||||
<script src="https://www.paypal.com/sdk/js?client-id=ATqBigrhcNdqR8J83aDjTOoJHsAVz0U45JRY4H0stcEcv0mQrMDHQmyrydQInYd1w4lJ1ee3Wsblm2WP"></script>
|
||||
|
||||
</html>
|
||||
|
||||
108
public/js/global-math.js
Normal file
108
public/js/global-math.js
Normal file
@@ -0,0 +1,108 @@
|
||||
// 确保 MathJax 配置正确
|
||||
window.MathJax = window.MathJax || {
|
||||
loader: {
|
||||
load: ['[tex]/ams', '[tex]/newcommand']
|
||||
},
|
||||
tex: {
|
||||
inlineMath: [['$', '$'], ['\\(', '\\)']],
|
||||
displayMath: [['$$', '$$'], ['\\[', '\\]']]
|
||||
},
|
||||
a11y: {
|
||||
// 启用 MathJax 可访问性功能,确保使用 aria-label
|
||||
texHints: true,
|
||||
screenReader: true,
|
||||
mathml: {
|
||||
enable: true,
|
||||
},
|
||||
label: {
|
||||
// 公式的 aria-label 配置
|
||||
enable: true,
|
||||
texClass: 'MathJax-Label',
|
||||
form: 'LaTeX'
|
||||
}
|
||||
},
|
||||
svg: { fontCache: 'global' }
|
||||
};
|
||||
|
||||
// **定义全局渲染方法**
|
||||
window.renderMathJax = function (tinymceId) {
|
||||
if (window.MathJax && typeof window.MathJax.typesetPromise === "function") {
|
||||
console.log("正在渲染 MathJax 公式...");
|
||||
|
||||
// 如果提供了 TinyMCE 编辑器 ID
|
||||
if (tinymceId) {
|
||||
const editorInstance = window.tinymce.get(tinymceId); // 根据 ID 获取 TinyMCE 实例
|
||||
if (!editorInstance) return;
|
||||
|
||||
const editorBody = editorInstance.getBody();
|
||||
|
||||
// 获取所有 <wmath> 元素
|
||||
const wmathElements = editorBody.querySelectorAll('wmath');
|
||||
|
||||
if (wmathElements.length > 0) {
|
||||
wmathElements.forEach((element) => {
|
||||
const latexContent = element.getAttribute('data-latex');
|
||||
if (latexContent) {
|
||||
// 将公式内容填入标签内部
|
||||
element.innerHTML = latexContent;
|
||||
|
||||
// 使用 MathJax 渲染该元素
|
||||
window.MathJax.typesetPromise([element]).catch((err) => {
|
||||
console.warn("TinyMCE MathJax 渲染失败:", err);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 渲染 <math>(MathML)标签,如果有的话
|
||||
const mathElements = editorBody.querySelectorAll('math');
|
||||
if (mathElements.length > 0) {
|
||||
window.MathJax.typesetPromise(Array.from(mathElements)).catch((err) => {
|
||||
console.warn("MathML 渲染失败:", err);
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 处理全局文档中的 <wmath> 标签
|
||||
const wmathElements = document.querySelectorAll('wmath');
|
||||
wmathElements.forEach((element) => {
|
||||
// 检查 <wmath> 标签是否包含有效的 data-latex 属性值
|
||||
const latexContent = element.getAttribute('data-latex');
|
||||
if (latexContent) {
|
||||
// 将元素的内部内容替换为 data-latex 的值
|
||||
element.innerHTML = latexContent;
|
||||
|
||||
// 渲染 MathJax 公式
|
||||
window.MathJax.typesetPromise([element]).catch((err) => {
|
||||
console.warn("MathJax 渲染失败:", err);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 处理全局文档中的 <math> 标签(MathML 内容)
|
||||
const mathElements = document.querySelectorAll('math');
|
||||
mathElements.forEach((element) => {
|
||||
// 渲染 MathJax 公式
|
||||
window.MathJax.typesetPromise([element]).catch((err) => {
|
||||
console.warn("MathJax 渲染失败:", err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
} else {
|
||||
console.warn("MathJax 未正确加载!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1115,10 +1115,10 @@ a {
|
||||
/* 自动调整列宽 */
|
||||
text-align: left;
|
||||
font-family: 'Charis SIL' !important;
|
||||
font-size: 7.5pt !important;
|
||||
font-size: 12px !important;
|
||||
mso-font-kerning: 1pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
|
||||
.wordTableHtml table td,
|
||||
@@ -1131,10 +1131,10 @@ a {
|
||||
word-break: normal;
|
||||
|
||||
font-family: 'Charis SIL' !important;
|
||||
font-size: 7.5pt !important;
|
||||
font-size: 12px !important;
|
||||
mso-font-kerning: 1pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
|
||||
.wordTableHtml table tbody tr td {
|
||||
@@ -1160,38 +1160,38 @@ a {
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
font-family: 'Charis SIL' !important;
|
||||
font-size: 7.5pt !important;
|
||||
font-size: 12px !important;
|
||||
mso-font-kerning: 1pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
|
||||
.wordTableHtml table span {
|
||||
color: #000000;
|
||||
text-align: left !important;
|
||||
font-family: 'Charis SIL' !important;
|
||||
font-size: 7.5pt !important;
|
||||
mso-font-kerning: 1pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
font-size: 12px !important;
|
||||
|
||||
line-height: 20px !important;
|
||||
|
||||
}
|
||||
|
||||
.wordTableHtml table .color-highlight {
|
||||
color: rgb(0, 130, 170) !important;
|
||||
font-family: 'Charis SIL' !important;
|
||||
font-size: 7.5pt !important;
|
||||
font-size: 12px !important;
|
||||
mso-font-kerning: 1pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
|
||||
.wordTableHtml table blue {
|
||||
color: rgb(0, 130, 170) !important;
|
||||
font-family: 'Charis SIL' !important;
|
||||
font-size: 7.5pt !important;
|
||||
font-size: 12px !important;
|
||||
mso-font-kerning: 1pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
|
||||
.wordTableHtml table tr:first-child td {
|
||||
@@ -1213,7 +1213,7 @@ a {
|
||||
|
||||
/* 给最后一个 table-header-row(第二行)加样式 */
|
||||
.wordTableHtml table tr.table-header-row:nth-of-type(2) td {
|
||||
border-bottom: 1px solid #000 !important;
|
||||
border-bottom: 1px solid #000 !important;
|
||||
}
|
||||
|
||||
.word-container b span {
|
||||
@@ -1258,10 +1258,10 @@ a {
|
||||
/* 自动调整列宽 */
|
||||
text-align: left;
|
||||
font-family: 'Charis SIL' !important;
|
||||
font-size: 7.5pt !important;
|
||||
font-size: 14px !important;
|
||||
mso-font-kerning: 1pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
|
||||
.word-container table td,
|
||||
@@ -1274,10 +1274,10 @@ a {
|
||||
/* 长单词自动换行 */
|
||||
word-break: normal;
|
||||
font-family: 'Charis SIL' !important;
|
||||
font-size: 7.5pt !important;
|
||||
font-size: 14px !important;
|
||||
mso-font-kerning: 1pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
|
||||
.word-container table tbody tr td {
|
||||
@@ -1294,7 +1294,7 @@ a {
|
||||
border-left: 1px dashed #dcdfe6 !important;
|
||||
border-right: 1px dashed #dcdfe6 !important;
|
||||
word-break: keep-all !important;
|
||||
white-space: pre-wrap !important;
|
||||
white-space: pre-wrap !important;
|
||||
/* text-align: justify !important; */
|
||||
}
|
||||
|
||||
@@ -1303,29 +1303,29 @@ a {
|
||||
|
||||
margin: 0;
|
||||
font-family: 'Charis SIL' !important;
|
||||
font-size: 7.5pt !important;
|
||||
font-size: 14px !important;
|
||||
mso-font-kerning: 1pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
|
||||
.word-container table span {
|
||||
color: #000000;
|
||||
text-align: left !important;
|
||||
font-family: 'Charis SIL' !important;
|
||||
font-size: 7.5pt !important;
|
||||
font-size: 14px !important;
|
||||
mso-font-kerning: 1pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
|
||||
.word-container table .color-highlight {
|
||||
color: rgb(0, 130, 170) !important;
|
||||
font-family: 'Charis SIL' !important;
|
||||
font-size: 7.5pt !important;
|
||||
font-size: 14px !important;
|
||||
mso-font-kerning: 1pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
|
||||
.word-container table tr:first-child td {
|
||||
@@ -1433,4 +1433,20 @@ a {
|
||||
/* 设置字体颜色 */
|
||||
text-decoration: line-through !important;
|
||||
/* 设置字体颜色 */
|
||||
}
|
||||
|
||||
mjx-container {
|
||||
font-size: 14px !important;
|
||||
}
|
||||
|
||||
wmath {
|
||||
width: 100%;
|
||||
display: block;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/* 强制 MathLive 虚拟键盘浮在最顶层 */
|
||||
.ML__keyboard {
|
||||
z-index: 99999 !important;
|
||||
position: fixed !important;
|
||||
}
|
||||
BIN
src/assets/img/ai.png
Normal file
BIN
src/assets/img/ai.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 99 KiB |
BIN
src/assets/img/repeat.png
Normal file
BIN
src/assets/img/repeat.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
@@ -1,4 +1,5 @@
|
||||
import Vue from 'vue';
|
||||
import katex from 'katex';
|
||||
import JSZip from 'jszip';
|
||||
import Common from '@/components/common/common'
|
||||
import Tiff from 'tiff.js';
|
||||
@@ -18,16 +19,106 @@ const capitalizeFirstLetter = function (text) {
|
||||
});
|
||||
};
|
||||
export default {
|
||||
extractLatexFromMathJax() {
|
||||
// 获取所有 MathJax 渲染的公式容器
|
||||
const mathContainers = document.querySelectorAll('mjx-container');
|
||||
|
||||
mathContainers.forEach(container => {
|
||||
// 查找每个渲染公式对应的 MathML 部分
|
||||
const mathElement = container.querySelector('mjx-math');
|
||||
console.log('mathElement at line 28:', mathElement)
|
||||
|
||||
if (mathElement) {
|
||||
// 获取 MathJax 渲染的公式对象
|
||||
const jax = window.MathJax.getJaxFor(mathElement);
|
||||
console.log('jax at line 32:', jax)
|
||||
|
||||
if (jax) {
|
||||
// 使用 MathJax API 获取公式的 LaTeX 代码
|
||||
const latex = jax.getLiteral(); // 获取 LaTeX 表达式
|
||||
console.log('提取到的 LaTeX 公式:', latex); // 输出 LaTeX 代码
|
||||
} else {
|
||||
console.warn('MathJax 对象未找到');
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
replaceWMathContent(inputHtml, callback) {
|
||||
// 使用正则表达式查找所有 <wmath> 标签,并提取 data-latex 的内容
|
||||
var str = inputHtml.replace(/<wmath data-latex="([^"]+)">[^<]*<\/wmath>/g, function (match, latexContent) {
|
||||
// 返回 <wmath> 标签,内容替换为 data-latex 的值
|
||||
return `<wmath data-latex="${latexContent}">${latexContent}</wmath>`;
|
||||
});
|
||||
|
||||
// 调用回调函数并传递处理后的结果
|
||||
callback(str);
|
||||
|
||||
// 输出结果到控制台
|
||||
console.log('Processed HTML:', str);
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
// **解析 MathJax 公式,获取 LaTeX**
|
||||
async extractMathJaxLatex(cell, callback) {
|
||||
console.log('cell at line 67:', cell)
|
||||
return new Promise((resolve, reject) => {
|
||||
// Step 1: First, process the math content and extract LaTeX from <wmath> tags
|
||||
let updatedContent = cell.innerHTML; // Start with the cell's inner HTML
|
||||
console.log('cell content at the start:', updatedContent);
|
||||
|
||||
// Find all <wmath> elements
|
||||
const wmathElements = cell.querySelectorAll('wmath');
|
||||
wmathElements.forEach((element) => {
|
||||
// Get the LaTeX content from the data-latex attribute
|
||||
const latexContent = element.getAttribute('data-latex');
|
||||
console.log('LaTeX content from data-latex:', latexContent);
|
||||
|
||||
// Replace the <wmath> tag with its LaTeX content wrapped in $$...$$
|
||||
updatedContent = updatedContent.replace(element.outerHTML, `<wmath data-latex="${latexContent}">${latexContent}</wmath>`);
|
||||
});
|
||||
|
||||
console.log('updatedContent after processing wmath tags:', updatedContent);
|
||||
|
||||
// Step 2: Now extract content without the outer <span> tags
|
||||
updatedContent = this.extractContentWithoutOuterSpan(updatedContent);
|
||||
console.log('updatedContent after extractContentWithoutOuterSpan:', updatedContent);
|
||||
|
||||
// Step 3: Call the callback function with the final updated content
|
||||
// callback(updatedContent);
|
||||
|
||||
// Resolve the promise with the final content
|
||||
resolve(updatedContent);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
renderLatex(latexString) {
|
||||
return katex.renderToString(latexString, {
|
||||
throwOnError: false
|
||||
});
|
||||
},
|
||||
decodeHtml(html) {
|
||||
var txt = document.createElement('textarea');
|
||||
txt.innerHTML = html;
|
||||
return txt.value;
|
||||
},
|
||||
},
|
||||
//去掉最外层自定义的span标签
|
||||
extractContentWithoutOuterSpan(cell) {
|
||||
console.log('cell at line 90:', cell)
|
||||
var str = ''
|
||||
if (!cell) {
|
||||
return ''
|
||||
}
|
||||
// 获取单元格的 HTML 内容
|
||||
let htmlContent = cell.innerHTML.trim();
|
||||
let htmlContent = cell.trim();
|
||||
|
||||
console.log('htmlContent at line 94:', htmlContent)
|
||||
|
||||
str = this.transformHtmlString(htmlContent)
|
||||
|
||||
@@ -52,12 +143,12 @@ export default {
|
||||
const regex = /\[(\d+(?:–\d+)?(?:, ?\d+(?:–\d+)?)*)\]/g;
|
||||
|
||||
str = str.replace(/<blue>/g, '').replace(/<\/blue>/g, ''); // 先去掉所有的 <blue> 标签
|
||||
|
||||
|
||||
if (regex.test(str)) {
|
||||
str = str.replace(regex, function(match) {
|
||||
str = str.replace(regex, function (match) {
|
||||
// 提取出方括号中的内容,并进行匹配
|
||||
const content = match.slice(1, match.length - 1); // 去掉方括号
|
||||
|
||||
|
||||
// 判断是否符合条件,纯数字、逗号后有空格、连字符
|
||||
if (/^\d+$/.test(content) || /, ?/.test(content) || /–/.test(content)) {
|
||||
return `<blue>${match}</blue>`; // 如果符合条件则加上蓝色标签
|
||||
@@ -65,12 +156,13 @@ export default {
|
||||
return match; // 如果不符合条件,则保持原样
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
console.log('str at line 141:', str)
|
||||
// 如果没有 <span> 标签,直接返回原始 HTML 内容
|
||||
return str;
|
||||
|
||||
},
|
||||
async extractPastedWordTablesToArrays(pastedHtml, callback) {
|
||||
try {
|
||||
@@ -161,90 +253,140 @@ export default {
|
||||
callback([]);
|
||||
}
|
||||
},
|
||||
|
||||
async extractWordTablesToArrays(file, callback) {
|
||||
const Zip = new JSZip();
|
||||
const namespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
|
||||
try {
|
||||
// 解压 Word 文档
|
||||
const Zip = new JSZip();
|
||||
const zip = await Zip.loadAsync(file);
|
||||
const documentXml = await zip.file("word/document.xml").async("string");
|
||||
|
||||
// 解析 XML
|
||||
console.log("解压后的文件:", Object.keys(zip.files));
|
||||
|
||||
const documentFile = zip.file("word/document.xml");
|
||||
if (!documentFile) {
|
||||
console.error("❌ 找不到 word/document.xml,无法解析 Word 文件");
|
||||
return;
|
||||
}
|
||||
|
||||
const documentXml = await documentFile.async("string");
|
||||
const parser = new DOMParser();
|
||||
const documentDoc = parser.parseFromString(documentXml, "application/xml");
|
||||
|
||||
// 获取命名空间
|
||||
const namespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
|
||||
const numberingXml = await zip.file("word/numbering.xml").async("string");
|
||||
let numberingDoc = null;
|
||||
if (numberingXml) {
|
||||
numberingDoc = parser.parseFromString(numberingXml, "application/xml");
|
||||
console.log("解析的 XML 结构:", new XMLSerializer().serializeToString(documentDoc));
|
||||
|
||||
const numberingFile = zip.file("word/numbering.xml");
|
||||
let numberingMap = {};
|
||||
if (numberingFile) {
|
||||
const numberingXml = await numberingFile.async("string");
|
||||
const numberingDoc = parser.parseFromString(numberingXml, "application/xml");
|
||||
numberingMap = this.parseNumbering(numberingDoc);
|
||||
} else {
|
||||
console.warn("⚠️ word/numbering.xml 不存在,跳过编号解析");
|
||||
}
|
||||
|
||||
// 获取编号定义
|
||||
const numberingMap = this.parseNumbering(numberingDoc);
|
||||
|
||||
// 获取所有表格
|
||||
const tables = documentDoc.getElementsByTagNameNS(namespace, "tbl");
|
||||
const allTables = []; // 存储所有表格的二维数组
|
||||
const allTables = [];
|
||||
|
||||
if (!tables || tables.length === 0) {
|
||||
console.warn("未找到表格内容,请检查 XML 结构");
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
for (const table of tables) {
|
||||
|
||||
const prevParagraph = table.previousElementSibling;
|
||||
if (prevParagraph) {
|
||||
console.log(`表格前的段落: ${prevParagraph.textContent}`);
|
||||
}
|
||||
const rows = table.getElementsByTagNameNS(namespace, "tr");
|
||||
const tableArray = []; // 当前表格的二维数组
|
||||
const tableArray = [];
|
||||
|
||||
for (const row of rows) {
|
||||
let rowSpanMap = [];
|
||||
|
||||
for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {
|
||||
const row = rows[rowIndex];
|
||||
const cells = row.getElementsByTagNameNS(namespace, "tc");
|
||||
const rowArray = []; // 当前行的数据
|
||||
const rowArray = [];
|
||||
|
||||
// 存储已合并的单元格
|
||||
let colSpanInfo = [];
|
||||
if (!rowSpanMap[rowIndex]) {
|
||||
rowSpanMap[rowIndex] = [];
|
||||
}
|
||||
|
||||
let cellIndex = 0;
|
||||
|
||||
for (let i = 0; i < cells.length; i++) {
|
||||
while (rowSpanMap[rowIndex][cellIndex]) {
|
||||
rowArray.push(null);
|
||||
cellIndex++;
|
||||
}
|
||||
|
||||
const cell = cells[i];
|
||||
let cellText = "";
|
||||
// const paragraphs = cell.getElementsByTagNameNS(namespace, "p");
|
||||
const paragraphs = cell.getElementsByTagName("w:p");
|
||||
// 检查合并单元格属性
|
||||
|
||||
const gridSpan = cell.getElementsByTagNameNS(namespace, "gridSpan")[0];
|
||||
const vMerge = cell.getElementsByTagNameNS(namespace, "vMerge")[0];
|
||||
|
||||
// 获取合并信息
|
||||
let colspan = gridSpan ? parseInt(gridSpan.getAttribute("w:val"), 10) : 1;
|
||||
let rowspan = 1;
|
||||
var colspan = gridSpan ? parseInt(gridSpan.getAttribute("w:val"), 10) : 1;
|
||||
var rowspan = 1;
|
||||
if (vMerge) {
|
||||
if (vMerge.getAttribute("w:val") === "restart") {
|
||||
rowspan = 1; // 初始化 rowspan
|
||||
let nextRowIdx = rowIndex + 1;
|
||||
let maxRowspan = rows.length - rowIndex; // 确保 rowspan 不会超过剩余行数
|
||||
|
||||
if (vMerge && vMerge.getAttribute("w:val") === "restart") {
|
||||
rowspan = 2; // 假设合并两行
|
||||
} else if (vMerge && !vMerge.getAttribute("w:val")) {
|
||||
continue; // 如果是合并单元格的继续部分,则跳过
|
||||
while (nextRowIdx < rows.length) {
|
||||
const nextRowCells = rows[nextRowIdx].getElementsByTagNameNS(namespace, "tc");
|
||||
// console.log(`🔍 检查下一行单元格 at row ${nextRowIdx}, col ${cellIndex}:`, nextRowCells);
|
||||
|
||||
if (nextRowCells.length > cellIndex) {
|
||||
const nextCell = nextRowCells[cellIndex];
|
||||
|
||||
if (!nextCell) {
|
||||
// console.warn(`⚠️ nextCell 未定义 at row ${nextRowIdx}, col ${cellIndex}`);
|
||||
break;
|
||||
}
|
||||
|
||||
const nextVMerge = nextCell.getElementsByTagNameNS(namespace, "vMerge")[0];
|
||||
// console.log(`🔍 检查 nextVMerge at row ${nextRowIdx}, col ${cellIndex}:`, nextVMerge);
|
||||
|
||||
// **如果 nextVMerge 为空,则不应继续增长 rowspan**
|
||||
if (!nextVMerge) {
|
||||
// console.log(`⚠️ nextVMerge 为空 at row ${nextRowIdx}, col ${cellIndex} - 停止扩展`);
|
||||
break;
|
||||
}
|
||||
|
||||
// **解析 nextVMerge 的值**
|
||||
const vMergeVal = nextVMerge.getAttribute("w:val");
|
||||
|
||||
if (!vMergeVal || vMergeVal === "continue") {
|
||||
if (rowspan < maxRowspan) { // 限制 rowspan 最大值
|
||||
rowspan++;
|
||||
// console.log(`✅ rowspan 扩展到: ${rowspan} (row: ${nextRowIdx}, col: ${cellIndex})`);
|
||||
nextRowIdx++;
|
||||
} else {
|
||||
// console.log(`⛔ 最大 rowspan 限制 ${rowspan},在 row ${nextRowIdx} 停止`);
|
||||
break;
|
||||
}
|
||||
} else if (vMergeVal === "restart") {
|
||||
// console.log(`⛔ 停止 rowspan 扩展 at row ${nextRowIdx}, 因为 w:val="restart"`);
|
||||
break;
|
||||
} else {
|
||||
// console.log(`⚠️ 未知 w:val="${vMergeVal}" at row ${nextRowIdx},停止合并`);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// console.warn(`⚠️ Row ${nextRowIdx} 没有足够的列 cellIndex ${cellIndex}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理单元格内容
|
||||
// let cellText = "";
|
||||
|
||||
|
||||
// 为当前单元格初始化计数器
|
||||
console.log('rowspan at line 265:', rowspan)
|
||||
const currentLevelNumbers = {};
|
||||
for (const paragraph of paragraphs) {
|
||||
// 提取段落编号
|
||||
let listPrefix = "";
|
||||
const numPr = paragraph.getElementsByTagName("w:numPr")[0];
|
||||
if (numPr) {
|
||||
console.log('numPr at line 54:', numPr)
|
||||
const numIdElement = numPr.getElementsByTagName("w:numId")[0];
|
||||
console.log('numIdElement at line 56:', numIdElement)
|
||||
const ilvlElement = numPr.getElementsByTagName("w:ilvl")[0];
|
||||
console.log('ilvlElement at line 58:', ilvlElement)
|
||||
if (numIdElement && ilvlElement) {
|
||||
const numId = numIdElement.getAttribute("w:val");
|
||||
const ilvl = ilvlElement.getAttribute("w:val");
|
||||
@@ -252,7 +394,6 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化当前段落文本
|
||||
let paragraphText = listPrefix ? `${listPrefix} ` : "";
|
||||
|
||||
const runs = paragraph.getElementsByTagName("w:r");
|
||||
@@ -263,7 +404,6 @@ export default {
|
||||
textContent += text.textContent;
|
||||
}
|
||||
|
||||
// 检查格式
|
||||
const rPr = run.getElementsByTagName("w:rPr")[0];
|
||||
let formattedText = textContent;
|
||||
|
||||
@@ -288,90 +428,308 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
// 替换负号
|
||||
formattedText = replaceNegativeSign(formattedText);
|
||||
|
||||
// 首字母大写
|
||||
formattedText = capitalizeFirstLetter(formattedText);
|
||||
|
||||
// 添加蓝色标签
|
||||
|
||||
|
||||
|
||||
const regex = /\[(\d+(?:–\d+)?(?:, ?\d+(?:–\d+)?)*)\]/g;
|
||||
formattedText = formattedText.replace(/<blue>/g, '').replace(/<\/blue>/g, '');
|
||||
|
||||
formattedText = formattedText.replace(/<blue>/g, '').replace(/<\/blue>/g, ''); // 先去掉所有的 <blue> 标签
|
||||
|
||||
if (regex.test(formattedText)) {
|
||||
formattedText = formattedText.replace(regex, function(match) {
|
||||
// 提取出方括号中的内容,并进行匹配
|
||||
const content = match.slice(1, match.length - 1); // 去掉方括号
|
||||
|
||||
// 判断是否符合条件,纯数字、逗号后有空格、连字符
|
||||
formattedText = formattedText.replace(regex, function (match) {
|
||||
const content = match.slice(1, match.length - 1);
|
||||
|
||||
if (/^\d+$/.test(content) || /, ?/.test(content) || /–/.test(content)) {
|
||||
return `<blue>${match}</blue>`; // 如果符合条件则加上蓝色标签
|
||||
return `<blue>${match}</blue>`;
|
||||
}
|
||||
return match; // 如果不符合条件,则保持原样
|
||||
return match;
|
||||
});
|
||||
}
|
||||
console.log("After replacement:", formattedText); // 调试:查看替换后的文本
|
||||
|
||||
|
||||
|
||||
|
||||
console.log("After replacement:", formattedText);
|
||||
|
||||
paragraphText += formattedText;
|
||||
}
|
||||
|
||||
// 处理换行符
|
||||
const breaks = paragraph.getElementsByTagName("w:br");
|
||||
for (const br of breaks) {
|
||||
paragraphText += "<br>";
|
||||
paragraphText += "<br/>";
|
||||
}
|
||||
|
||||
cellText += paragraphText; // 将段落文本添加到单元格文本
|
||||
cellText += paragraphText;
|
||||
console.log('cellText at line 366:', cellText)
|
||||
}
|
||||
|
||||
// 更新合并单元格的信息
|
||||
if (colSpanInfo[i]) {
|
||||
colspan = colSpanInfo[i].colspan;
|
||||
}
|
||||
|
||||
// 保存当前单元格信息
|
||||
rowArray.push({
|
||||
text: cellText,
|
||||
colspan: colspan,
|
||||
rowspan: rowspan
|
||||
});
|
||||
|
||||
// 记录跨列合并
|
||||
if (colspan > 1) {
|
||||
for (let j = 1; j < colspan; j++) {
|
||||
colSpanInfo[i + j] = { colspan: 0 }; // 用 0 填充后续的列合并
|
||||
if (rowspan > 1) {
|
||||
for (let j = 1; j < rowspan; j++) {
|
||||
if (!rowSpanMap[rowIndex + j]) {
|
||||
rowSpanMap[rowIndex + j] = [];
|
||||
}
|
||||
rowSpanMap[rowIndex + j][cellIndex] = true;
|
||||
}
|
||||
}
|
||||
|
||||
cellIndex++;
|
||||
}
|
||||
|
||||
tableArray.push(rowArray); // 添加当前行到表格数组
|
||||
tableArray.push(rowArray.filter(item => item !== null));
|
||||
|
||||
}
|
||||
|
||||
allTables.push(tableArray); // 添加当前表格到所有表格数组
|
||||
allTables.push(tableArray);
|
||||
}
|
||||
|
||||
console.log("解析后的二维数组:", allTables);
|
||||
callback(allTables); // 返回处理后的 HTML
|
||||
callback(allTables);
|
||||
|
||||
} catch (error) {
|
||||
console.error("解析 Word 文件失败:", error);
|
||||
return [];
|
||||
callback([]);
|
||||
}
|
||||
},
|
||||
transformHtmlString(inputHtml) {
|
||||
|
||||
inputHtml = inputHtml.replace(/(<[^>]+) style="[^"]*"/g, '$1'); // 移除style属性
|
||||
inputHtml = inputHtml.replace(/(<[^>]+) class="[^"]*"/g, '$1'); // 移除class属性
|
||||
|
||||
// async extractWordTablesToArrays(file, callback) {
|
||||
|
||||
// const namespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
|
||||
// try {
|
||||
// const Zip = new JSZip();
|
||||
// // 解压 ZIP
|
||||
// const zip = await Zip.loadAsync(file);
|
||||
|
||||
// // **检查解压的文件列表**
|
||||
// console.log("解压后的文件:", Object.keys(zip.files));
|
||||
|
||||
// const documentFile = zip.file("word/document.xml");
|
||||
// if (!documentFile) {
|
||||
// console.error("❌ 找不到 word/document.xml,无法解析 Word 文件");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// const documentXml = await documentFile.async("string");
|
||||
// const parser = new DOMParser();
|
||||
// const documentDoc = parser.parseFromString(documentXml, "application/xml");
|
||||
|
||||
// // **打印 XML 结构以检查表格**
|
||||
// console.log("解析的 XML 结构:", new XMLSerializer().serializeToString(documentDoc));
|
||||
|
||||
// // **检查 word/numbering.xml 是否存在**
|
||||
// const numberingFile = zip.file("word/numbering.xml");
|
||||
// let numberingMap = {};
|
||||
// if (numberingFile) {
|
||||
// const numberingXml = await numberingFile.async("string");
|
||||
// const numberingDoc = parser.parseFromString(numberingXml, "application/xml");
|
||||
// numberingMap = parseNumbering(numberingDoc); // 解析编号信息
|
||||
// } else {
|
||||
// console.warn("⚠️ word/numbering.xml 不存在,跳过编号解析");
|
||||
// }
|
||||
|
||||
// const tables = documentDoc.getElementsByTagNameNS(namespace, "tbl");
|
||||
// const allTables = []; // 存储所有表格的二维数组
|
||||
|
||||
// if (!tables || tables.length === 0) {
|
||||
// console.warn("未找到表格内容,请检查 XML 结构");
|
||||
// return [];
|
||||
// }
|
||||
|
||||
|
||||
// for (const table of tables) {
|
||||
|
||||
// const prevParagraph = table.previousElementSibling;
|
||||
// if (prevParagraph) {
|
||||
// console.log(`表格前的段落: ${prevParagraph.textContent}`);
|
||||
// }
|
||||
// const rows = table.getElementsByTagNameNS(namespace, "tr");
|
||||
// const tableArray = []; // 当前表格的二维数组
|
||||
|
||||
// for (const row of rows) {
|
||||
// const cells = row.getElementsByTagNameNS(namespace, "tc");
|
||||
// const rowArray = []; // 当前行的数据
|
||||
|
||||
// // 存储已合并的单元格
|
||||
// let colSpanInfo = [];
|
||||
|
||||
// for (let i = 0; i < cells.length; i++) {
|
||||
// const cell = cells[i];
|
||||
// let cellText = "";
|
||||
// // const paragraphs = cell.getElementsByTagNameNS(namespace, "p");
|
||||
// const paragraphs = cell.getElementsByTagName("w:p");
|
||||
// // 检查合并单元格属性
|
||||
// const gridSpan = cell.getElementsByTagNameNS(namespace, "gridSpan")[0];
|
||||
// const vMerge = cell.getElementsByTagNameNS(namespace, "vMerge")[0];
|
||||
|
||||
// // 获取合并信息
|
||||
// let colspan = gridSpan ? parseInt(gridSpan.getAttribute("w:val"), 10) : 1;
|
||||
// let rowspan = 1;
|
||||
|
||||
// if (vMerge && vMerge.getAttribute("w:val") === "restart") {
|
||||
// rowspan = 4; // 假设合并两行
|
||||
// } else if (vMerge && !vMerge.getAttribute("w:val")) {
|
||||
// continue; // 如果是合并单元格的继续部分,则跳过
|
||||
// }
|
||||
|
||||
// // 处理单元格内容
|
||||
// // let cellText = "";
|
||||
|
||||
|
||||
// // 为当前单元格初始化计数器
|
||||
// const currentLevelNumbers = {};
|
||||
// for (const paragraph of paragraphs) {
|
||||
// // 提取段落编号
|
||||
// let listPrefix = "";
|
||||
// const numPr = paragraph.getElementsByTagName("w:numPr")[0];
|
||||
// if (numPr) {
|
||||
// console.log('numPr at line 54:', numPr)
|
||||
// const numIdElement = numPr.getElementsByTagName("w:numId")[0];
|
||||
// console.log('numIdElement at line 56:', numIdElement)
|
||||
// const ilvlElement = numPr.getElementsByTagName("w:ilvl")[0];
|
||||
// console.log('ilvlElement at line 58:', ilvlElement)
|
||||
// if (numIdElement && ilvlElement) {
|
||||
// const numId = numIdElement.getAttribute("w:val");
|
||||
// const ilvl = ilvlElement.getAttribute("w:val");
|
||||
// listPrefix = this.getListNumber(numId, ilvl, numberingMap, currentLevelNumbers);
|
||||
// }
|
||||
// }
|
||||
|
||||
// // 初始化当前段落文本
|
||||
// let paragraphText = listPrefix ? `${listPrefix} ` : "";
|
||||
|
||||
// const runs = paragraph.getElementsByTagName("w:r");
|
||||
// for (const run of runs) {
|
||||
// let textContent = "";
|
||||
// const texts = run.getElementsByTagName("w:t");
|
||||
// for (const text of texts) {
|
||||
// textContent += text.textContent;
|
||||
// }
|
||||
|
||||
// // 检查格式
|
||||
// const rPr = run.getElementsByTagName("w:rPr")[0];
|
||||
// let formattedText = textContent;
|
||||
|
||||
// if (rPr) {
|
||||
// const bold = rPr.getElementsByTagName("w:b").length > 0;
|
||||
// const italic = rPr.getElementsByTagName("w:i").length > 0;
|
||||
// const vertAlignElement = rPr.getElementsByTagName("w:vertAlign")[0];
|
||||
|
||||
// if (bold) {
|
||||
// formattedText = `<b>${formattedText}</b>`;
|
||||
// }
|
||||
// if (italic) {
|
||||
// formattedText = `<i>${formattedText}</i>`;
|
||||
// }
|
||||
// if (vertAlignElement) {
|
||||
// const vertAlign = vertAlignElement.getAttribute("w:val");
|
||||
// if (vertAlign === "superscript") {
|
||||
// formattedText = `<sup>${formattedText}</sup>`;
|
||||
// } else if (vertAlign === "subscript") {
|
||||
// formattedText = `<sub>${formattedText}</sub>`;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // 替换负号
|
||||
// formattedText = replaceNegativeSign(formattedText);
|
||||
|
||||
// // 首字母大写
|
||||
// formattedText = capitalizeFirstLetter(formattedText);
|
||||
|
||||
// // 添加蓝色标签
|
||||
|
||||
|
||||
|
||||
// const regex = /\[(\d+(?:–\d+)?(?:, ?\d+(?:–\d+)?)*)\]/g;
|
||||
|
||||
// formattedText = formattedText.replace(/<blue>/g, '').replace(/<\/blue>/g, ''); // 先去掉所有的 <blue> 标签
|
||||
|
||||
// if (regex.test(formattedText)) {
|
||||
// formattedText = formattedText.replace(regex, function (match) {
|
||||
// // 提取出方括号中的内容,并进行匹配
|
||||
// const content = match.slice(1, match.length - 1); // 去掉方括号
|
||||
|
||||
// // 判断是否符合条件,纯数字、逗号后有空格、连字符
|
||||
// if (/^\d+$/.test(content) || /, ?/.test(content) || /–/.test(content)) {
|
||||
// return `<blue>${match}</blue>`; // 如果符合条件则加上蓝色标签
|
||||
// }
|
||||
// return match; // 如果不符合条件,则保持原样
|
||||
// });
|
||||
// }
|
||||
// console.log("After replacement:", formattedText); // 调试:查看替换后的文本
|
||||
|
||||
|
||||
|
||||
|
||||
// paragraphText += formattedText;
|
||||
// }
|
||||
|
||||
// // 处理换行符
|
||||
// const breaks = paragraph.getElementsByTagName("w:br");
|
||||
// for (const br of breaks) {
|
||||
// paragraphText += "<br>";
|
||||
// }
|
||||
|
||||
// cellText += paragraphText; // 将段落文本添加到单元格文本
|
||||
// }
|
||||
|
||||
// // 更新合并单元格的信息
|
||||
// if (colSpanInfo[i]) {
|
||||
// colspan = colSpanInfo[i].colspan;
|
||||
// }
|
||||
|
||||
// // 保存当前单元格信息
|
||||
// rowArray.push({
|
||||
// text: cellText,
|
||||
// colspan: colspan,
|
||||
// rowspan: rowspan
|
||||
// });
|
||||
|
||||
// // 记录跨列合并
|
||||
// if (colspan > 1) {
|
||||
// for (let j = 1; j < colspan; j++) {
|
||||
// colSpanInfo[i + j] = { colspan: 0 }; // 用 0 填充后续的列合并
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// tableArray.push(rowArray); // 添加当前行到表格数组
|
||||
// }
|
||||
|
||||
// allTables.push(tableArray); // 添加当前表格到所有表格数组
|
||||
// }
|
||||
|
||||
// console.log("解析后的二维数组:", allTables);
|
||||
// callback(allTables); // 返回处理后的 HTML
|
||||
|
||||
// } catch (error) {
|
||||
// console.error("解析 Word 文件失败:", error);
|
||||
// return [];
|
||||
// }
|
||||
|
||||
// },
|
||||
transformHtmlString(inputHtml) {
|
||||
|
||||
// inputHtml = inputHtml.replace(/(<[^>]+) style="[^"]*"/g, '$1'); // 移除style属性
|
||||
// inputHtml = inputHtml.replace(/(<[^>]+) class="[^"]*"/g, '$1'); // 移除class属性
|
||||
// inputHtml = inputHtml.replace(/<([a-zA-Z0-9]+)[^>]*>/g, '<$1>'); // 删除标签上的所有属性
|
||||
|
||||
inputHtml = inputHtml.replace(/<([a-zA-Z0-9]+)([^>]*)>/g, function (match, tag, attributes) {
|
||||
// 使用正则表达式删除属性(保留 data-latex)
|
||||
let updatedAttributes = attributes.replace(/\s([a-zA-Z0-9-]+)(="[^"]*")?/g, function (attrMatch, attrName) {
|
||||
// 只保留 data-latex 属性,其他属性删除
|
||||
if (attrName === "data-latex") {
|
||||
return attrMatch;
|
||||
}
|
||||
return ''; // 删除其他属性
|
||||
});
|
||||
|
||||
// 返回标签,保留 data-latex 属性
|
||||
return `<${tag}${updatedAttributes}>`;
|
||||
});
|
||||
// 2. 删除所有不需要的标签 (除 `strong`, `em`, `sub`, `sup`, `b`, `i` 外的所有标签)
|
||||
inputHtml = inputHtml.replace(/<(?!\/?(strong|em|sub|sup|b|i|blue))[^>]+>/g, ''); // 删除不需要的标签
|
||||
inputHtml = inputHtml.replace(/<(?!\/?(strong|em|sub|sup|b|i|blue|wmath))[^>]+>/g, ''); // 删除不需要的标签
|
||||
|
||||
// 3. 如果有 `<strong>` 和 `<em>` 标签,去掉内部样式并保留内容
|
||||
inputHtml = inputHtml.replace(/<span[^>]*>/g, '').replace(/<\/span>/g, ''); // 去除span标签
|
||||
@@ -386,26 +744,79 @@ export default {
|
||||
|
||||
},
|
||||
|
||||
cleanAndParseWordContent(content) {
|
||||
// 1️⃣ 解析成 <p> 段落数组
|
||||
let tempDiv = document.createElement('div');
|
||||
tempDiv.innerHTML = content; // 解析 HTML 内容
|
||||
let paragraphs = tempDiv.querySelectorAll("p"); // 选取所有 <p> 作为数据项
|
||||
|
||||
// 2️⃣ 将 <p> 内容转换为数组,并处理内容
|
||||
let parsedData = Array.from(paragraphs).map(p => {
|
||||
let text = p.innerHTML.trim(); // 获取内容,去除两端空格
|
||||
text = this.transformHtmlString(text)
|
||||
// 3️⃣ **正确移除 <o:p>(Word 复制的无效标签)**
|
||||
text = text.replace(/<\/?o:p[^>]*>/g, "");
|
||||
|
||||
// 4️⃣ **移除所有 style="..."**
|
||||
text = text.replace(/\s*style="[^"]*"/gi, "");
|
||||
|
||||
// 5️⃣ **修正标签替换**
|
||||
text = text.replace(/<strong>/gi, "<b>").replace(/<\/strong>/gi, "</b>");
|
||||
text = text.replace(/<em>/gi, "<i>").replace(/<\/em>/gi, "</i>");
|
||||
|
||||
// 6️⃣ **移除空的 span、b、i 标签**
|
||||
text = text.replace(/<span>\s*<\/span>/gi, "");
|
||||
text = text.replace(/<b>\s*<\/b>/gi, "");
|
||||
text = text.replace(/<i>\s*<\/i>/gi, "");
|
||||
|
||||
// 7️⃣ **确保不移除半个标签(修复匹配规则)**
|
||||
text = text.replace(/<[^\/>]+>\s*<\/[^>]+>/gi, match => {
|
||||
return match.trim() === "" ? "" : match;
|
||||
});
|
||||
|
||||
// 8️⃣ **返回最终内容**
|
||||
return text.trim() === "" ? "" : text;
|
||||
});
|
||||
|
||||
console.log(parsedData); // 输出数组,方便调试
|
||||
return parsedData;
|
||||
}
|
||||
|
||||
|
||||
parseTableToArray(tableString, callback) {
|
||||
|
||||
,
|
||||
|
||||
|
||||
async parseTableToArray(tableString, callback) {
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(tableString, 'text/html');
|
||||
const rows = doc.querySelectorAll('table tr'); // 获取所有的行(<tr>)
|
||||
|
||||
callback(Array.from(rows).map(row => {
|
||||
const cells = row.querySelectorAll('th, td'); // 获取每个行中的单元格(包括 <th> 和 <td>)
|
||||
return Array.from(cells).map(cell => ({
|
||||
// 使用 Promise 来处理异步的 MathJax 解析
|
||||
const result = await Promise.all(
|
||||
Array.from(rows).map(async (row) => {
|
||||
const cells = row.querySelectorAll('th, td'); // 获取每个行中的单元格(包括 <th> 和 <td>)
|
||||
return await Promise.all(
|
||||
Array.from(cells).map(async (cell) => {
|
||||
const text = await this.extractMathJaxLatex(cell);
|
||||
return {
|
||||
text,
|
||||
colspan: cell.getAttribute('colspan') ? parseInt(cell.getAttribute('colspan')) : 1, // 提取 colspan,默认值为 1
|
||||
rowspan: cell.getAttribute('rowspan') ? parseInt(cell.getAttribute('rowspan')) : 1 // 提取 rowspan,默认值为 1
|
||||
};
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
console.log('result at line 78611:', result)
|
||||
callback(result)
|
||||
// 返回处理后的数组
|
||||
|
||||
text: this.extractContentWithoutOuterSpan(cell),
|
||||
colspan: cell.getAttribute('colspan') ? parseInt(cell.getAttribute('colspan')) : 1, // 提取 colspan,默认值为 1
|
||||
rowspan: cell.getAttribute('rowspan') ? parseInt(cell.getAttribute('rowspan')) : 1 // 提取 rowspan,默认值为 1
|
||||
}));
|
||||
}));
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
parseNumbering(numberingDoc) {
|
||||
const numberingMap = new Map();
|
||||
if (!numberingDoc) return numberingMap;
|
||||
@@ -1240,7 +1651,7 @@ export default {
|
||||
}
|
||||
});
|
||||
ed.ui.registry.addButton('addRow', {
|
||||
icon:'duplicate-row',
|
||||
icon: 'duplicate-row',
|
||||
text: 'Add Row', // 下拉框标题
|
||||
onAction: function () {
|
||||
var edSelection = ed.selection;
|
||||
@@ -1257,7 +1668,7 @@ export default {
|
||||
vueInstance.$emit('onAddRow', dataId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
// 添加自定义菜单项
|
||||
ed.ui.registry.addButton('Save', {
|
||||
@@ -1300,7 +1711,7 @@ export default {
|
||||
emTags[i].parentNode.replaceChild(iTag, emTags[i]);
|
||||
}
|
||||
content = div.innerHTML;
|
||||
|
||||
|
||||
vueInstance.$emit('saveContent', content, dataId);
|
||||
}
|
||||
}
|
||||
@@ -1390,8 +1801,8 @@ export default {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
ed.ui.registry.addButton('commentAdd', {
|
||||
icon: 'comment-add',
|
||||
text: 'Comment Add',
|
||||
@@ -1519,7 +1930,7 @@ export default {
|
||||
ed.setContent('');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
ed.ui.registry.addButton('customBlue', {
|
||||
text: 'Blue', // 按钮文本
|
||||
@@ -1537,80 +1948,112 @@ export default {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let latexEditorBookmark = null; // 用于记录插入点
|
||||
let activeEditorId = null; // 当前激活的编辑器 ID
|
||||
|
||||
// 在编辑器工具栏中添加 "LateX" 按钮
|
||||
ed.ui.registry.addButton('LateX', {
|
||||
text: 'LateX', // 按钮文本
|
||||
onAction: function () {
|
||||
// 1. 获取当前光标位置
|
||||
const latexEditorBookmark = ed.selection.getBookmark(2); // 获取光标位置
|
||||
const editorId = ed.id; // 保存当前编辑器 ID
|
||||
console.log('activeEditorId:', editorId);
|
||||
|
||||
// 2. 生成一个随机的 ID,用于 wmath 标签
|
||||
const uid = 'wmath-' + Math.random().toString(36).substr(2, 9);
|
||||
|
||||
// 3. 创建一个 <wmath> 标签并插入到光标处
|
||||
const wmathHtml = `<wmath contenteditable="false" data-id="${uid}" data-latex=""></wmath>`;
|
||||
ed.insertContent(wmathHtml); // 在光标位置插入 wmath 标签
|
||||
|
||||
// 4. 打开公式编辑器窗口,并传递光标位置、编辑器 ID 和 wmathId
|
||||
const url = `/LateX?editorId=${editorId}&wmathId=${uid}`;
|
||||
// vueInstance.openLatexEditor({
|
||||
// editorId:editorId,
|
||||
// wmathId:uid,
|
||||
// });
|
||||
window.open(url, '_blank', 'width=1000,height=800,scrollbars=no,resizable=no');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ed.ui.registry.addButton('myuppercase', {
|
||||
text: 'A', // 按钮文本
|
||||
|
||||
|
||||
onAction: function () {
|
||||
// 在选中的文本周围包裹 <blue> 标签
|
||||
var selectedText = ed.selection.getContent({ format: 'html' });
|
||||
|
||||
// 确保选中的文本是单个单词,包括空格
|
||||
if (selectedText.trim() && /^[\s\w]+$/.test(selectedText)) {
|
||||
// 使用正则将选中的文本中的第一个字母大写
|
||||
var capitalizedText = selectedText.replace(/(^|\s)([a-zA-Z])/g, function(match, p1, p2) {
|
||||
return p1 + p2.toUpperCase();
|
||||
});
|
||||
|
||||
// 替换选中的文本,保持空格和其他内容
|
||||
ed.selection.setContent(capitalizedText);
|
||||
} else {
|
||||
vueInstance.$message.error(vueInstance.$t('commonTable.selectWord'));
|
||||
|
||||
}
|
||||
// 使用正则将选中的文本中的第一个字母大写
|
||||
var capitalizedText = selectedText.replace(/(^|\s)([a-zA-Z])/g, function (match, p1, p2) {
|
||||
return p1 + p2.toUpperCase();
|
||||
});
|
||||
|
||||
// 替换选中的文本,保持空格和其他内容
|
||||
ed.selection.setContent(capitalizedText);
|
||||
} else {
|
||||
vueInstance.$message.error(vueInstance.$t('commonTable.selectWord'));
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
ed.ui.registry.addButton('myuppercase', {
|
||||
text: 'A', // 按钮文本
|
||||
|
||||
|
||||
onAction: function () {
|
||||
// 在选中的文本周围包裹 <blue> 标签
|
||||
var selectedText = ed.selection.getContent({ format: 'html' });
|
||||
|
||||
// 确保选中的文本是单个单词,包括空格
|
||||
if (selectedText.trim() && /^[\s\w]+$/.test(selectedText)) {
|
||||
// 使用正则将选中的文本中的第一个字母大写
|
||||
var capitalizedText = selectedText.replace(/(^|\s)([a-zA-Z])/g, function(match, p1, p2) {
|
||||
return p1 + p2.toUpperCase();
|
||||
});
|
||||
|
||||
// 替换选中的文本,保持空格和其他内容
|
||||
ed.selection.setContent(capitalizedText);
|
||||
} else {
|
||||
vueInstance.$message.error(vueInstance.$t('commonTable.selectWord'));
|
||||
|
||||
}
|
||||
// 使用正则将选中的文本中的第一个字母大写
|
||||
var capitalizedText = selectedText.replace(/(^|\s)([a-zA-Z])/g, function (match, p1, p2) {
|
||||
return p1 + p2.toUpperCase();
|
||||
});
|
||||
|
||||
// 替换选中的文本,保持空格和其他内容
|
||||
ed.selection.setContent(capitalizedText);
|
||||
} else {
|
||||
vueInstance.$message.error(vueInstance.$t('commonTable.selectWord'));
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
ed.ui.registry.addButton('myuppercasea', {
|
||||
text: 'a', // 按钮文本(小写字母)
|
||||
onAction: function () {
|
||||
// 获取选中的文本,保留 HTML 格式
|
||||
var selectedText = ed.selection.getContent({ format: 'html' });
|
||||
// 获取选中的文本,保留 HTML 格式
|
||||
var selectedText = ed.selection.getContent({ format: 'html' });
|
||||
|
||||
// 确保选中的文本是单个有效的单词,包括空格
|
||||
if (selectedText.trim() && /^[\s\w]+$/.test(selectedText)) {
|
||||
// 使用正则将选中的文本中的第一个字母转换为小写
|
||||
var lowercasedText = selectedText.replace(/(^|\s)([a-zA-Z])/g, function(match, p1, p2) {
|
||||
return p1 + p2.toLowerCase();
|
||||
});
|
||||
|
||||
// 替换选中的文本,保持空格和其他内容
|
||||
ed.selection.setContent(lowercasedText);
|
||||
} else {
|
||||
vueInstance.$message.error(vueInstance.$t('commonTable.selectWord'));
|
||||
}
|
||||
// 确保选中的文本是单个有效的单词,包括空格
|
||||
if (selectedText.trim() && /^[\s\w]+$/.test(selectedText)) {
|
||||
// 使用正则将选中的文本中的第一个字母转换为小写
|
||||
var lowercasedText = selectedText.replace(/(^|\s)([a-zA-Z])/g, function (match, p1, p2) {
|
||||
return p1 + p2.toLowerCase();
|
||||
});
|
||||
|
||||
// 替换选中的文本,保持空格和其他内容
|
||||
ed.selection.setContent(lowercasedText);
|
||||
} else {
|
||||
vueInstance.$message.error(vueInstance.$t('commonTable.selectWord'));
|
||||
}
|
||||
}
|
||||
});
|
||||
ed.ui.registry.addButton('Line', {
|
||||
text: '−', // 按钮文本
|
||||
onAction: function () {
|
||||
// 插入 `−` 符号到当前光标位置
|
||||
ed.insertContent('−');
|
||||
}
|
||||
});
|
||||
});
|
||||
ed.ui.registry.addButton('Line', {
|
||||
text: '−', // 按钮文本
|
||||
onAction: function () {
|
||||
// 插入 `−` 符号到当前光标位置
|
||||
ed.insertContent('−');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
ed.ui.registry.addButton('removeBlue', {
|
||||
text: 'Blue', // 按钮文本
|
||||
onAction: function () {
|
||||
@@ -1660,7 +2103,7 @@ export default {
|
||||
{ selector: '.tox-tbtn[data-mce-name="customblue"]', className: 'tinymce-custom-button-blue' },
|
||||
{ selector: '.tox-tbtn[data-mce-name="removeblue"]', className: 'tinymce-custom-button-removeblue' }
|
||||
];
|
||||
|
||||
|
||||
// 遍历每个按钮并为每个按钮添加类
|
||||
buttons.forEach(item => {
|
||||
const buttonElements = document.querySelectorAll(item.selector);
|
||||
@@ -1672,7 +2115,7 @@ export default {
|
||||
});
|
||||
}, 100); // 延迟执行,确保按钮渲染完成
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 通用递归方法
|
||||
|
||||
|
||||
@@ -1,31 +1,42 @@
|
||||
<template>
|
||||
<div class="wrapper">
|
||||
<template v-if="!this.$route.meta.hideSidebar">
|
||||
<v-head></v-head>
|
||||
<template v-if="!this.$route.meta.hideTitle"
|
||||
><template v-if="!this.$route.meta.hideSidebar">
|
||||
<v-head></v-head>
|
||||
|
||||
<v-sidebar></v-sidebar>
|
||||
<div class="content-box" :class="{ 'content-collapse': collapse }">
|
||||
<v-tags></v-tags>
|
||||
<div class="content">
|
||||
<transition name="move" mode="out-in">
|
||||
<keep-alive :include="tagsList">
|
||||
<router-view></router-view>
|
||||
</keep-alive>
|
||||
</transition>
|
||||
<el-backtop target=".content"></el-backtop>
|
||||
<v-sidebar></v-sidebar>
|
||||
<div class="content-box" :class="{ 'content-collapse': collapse }">
|
||||
<v-tags></v-tags>
|
||||
<div class="content">
|
||||
<transition name="move" mode="out-in">
|
||||
<keep-alive :include="tagsList">
|
||||
<router-view></router-view>
|
||||
</keep-alive>
|
||||
</transition>
|
||||
<el-backtop target=".content"></el-backtop>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<v-head2 :home="true"></v-head2>
|
||||
<div style="width: 100%; height: calc(100% - 62px); overflow: hidden">
|
||||
<div class="content" style="padding: 0; overflow: hidden">
|
||||
<!-- <transition name="move" mode="out-in"> -->
|
||||
<!-- <keep-alive :include="tagsList"> -->
|
||||
<router-view></router-view>
|
||||
<!-- </keep-alive> -->
|
||||
<!-- </transition> -->
|
||||
<el-backtop target=".content"></el-backtop>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<v-head2 :home="true"></v-head2>
|
||||
<div style="width: 100%;height: calc(100% - 62px);overflow: hidden;">
|
||||
|
||||
<div class="content" style="padding: 0;overflow: hidden;">
|
||||
<!-- <transition name="move" mode="out-in"> -->
|
||||
<!-- <keep-alive :include="tagsList"> -->
|
||||
<router-view></router-view>
|
||||
<!-- </keep-alive> -->
|
||||
<!-- </transition> -->
|
||||
<div style="width: 100%; ">
|
||||
<div class="content" style="padding: 0; overflow: hidden">
|
||||
|
||||
<router-view></router-view>
|
||||
|
||||
<el-backtop target=".content"></el-backtop>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -412,6 +412,16 @@ Information:'Fill in information',
|
||||
|
||||
|
||||
},
|
||||
Formula:{
|
||||
FormulaTemplate:'Formula Template'
|
||||
},
|
||||
AI: {
|
||||
AISummaryAnalysis: 'AI analysis',
|
||||
AIKeywords: 'Keywords',
|
||||
AIAbstract: 'Abstract',
|
||||
AIAbstractInfo: 'Analysis Result',
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -405,6 +405,15 @@ const zh = {
|
||||
|
||||
|
||||
},
|
||||
Formula:{
|
||||
FormulaTemplate:'公式模版'
|
||||
},
|
||||
AI:{
|
||||
AISummaryAnalysis:'AI分析',
|
||||
AIKeywords:'关键词',
|
||||
AIAbstract:'摘要',
|
||||
AIAbstractInfo:'分析结果',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
</common-word-html-type-setting>
|
||||
</div>
|
||||
</div>
|
||||
<div style="width: 100%; width: calc(100% - 285px); float: right;height: calc(100% - 20px);; background-color: #e4e9ed">
|
||||
<div style="width: 100%; width: calc(100% - 285px); float: right; height: calc(100% - 0px); background-color: #e4e9ed">
|
||||
<!-- <div class="toolbar">
|
||||
<div class="toolbar_item" @click="handleImageAdd('img')">
|
||||
<img src="@/assets/img/upload.png" style="object-fit: contain" />
|
||||
@@ -98,7 +98,10 @@
|
||||
@editComment="editComment"
|
||||
@loaded="loadedWord"
|
||||
@onEdit="onEdit"
|
||||
@addContent="onAddContent"
|
||||
@changeSort="changeSort"
|
||||
@onDelete="onDelete"
|
||||
@onDeletes="onDeletes"
|
||||
@refresh="onRefresh"
|
||||
@onComment="onComment"
|
||||
@onAddComment="onAddComment"
|
||||
@@ -148,6 +151,7 @@
|
||||
:isAutomaticUpdate="true"
|
||||
:value="picStyle.note"
|
||||
@getContent="getContent"
|
||||
@openLatexEditor="openLatexEditor"
|
||||
v-if="pictVisible"
|
||||
@updateChange="(res) => updateChange(res, 'imgNote')"
|
||||
:height="120"
|
||||
@@ -167,22 +171,27 @@
|
||||
</el-dialog>
|
||||
|
||||
<!-- 添加表格 -->
|
||||
<el-dialog
|
||||
<el-drawer
|
||||
title="我嵌套了表格!"
|
||||
class="editTableDialog"
|
||||
destroy-on-close
|
||||
v-if="threeVisible"
|
||||
:title="lineStyle.visiTitle"
|
||||
:visible.sync="threeVisible"
|
||||
width="1200px"
|
||||
:wrapperClosable="false"
|
||||
:close-on-click-modal="false"
|
||||
direction="rtl"
|
||||
size="70%"
|
||||
>
|
||||
<el-form ref="editMes" :model="lineStyle" label-width="115px">
|
||||
<el-form-item label="Table Title :">
|
||||
<el-form ref="editMes" :model="lineStyle" label-width="80px">
|
||||
<!-- <common-late-x></common-late-x> -->
|
||||
<el-form-item label="Title:">
|
||||
<common-content
|
||||
:id="`editor-${new Date().getTime()}-${lineStyle.am_id}-${lineStyle.amt_id}-title`"
|
||||
:isAutomaticUpdate="true"
|
||||
:value="lineStyle.title"
|
||||
@getContent="getContent"
|
||||
@openLatexEditor="openLatexEditor"
|
||||
v-if="threeVisible"
|
||||
@updateChange="(res) => updateChange(res, 'title')"
|
||||
:height="120"
|
||||
@@ -193,36 +202,43 @@
|
||||
<el-form-item label="Word">
|
||||
<span slot="label">
|
||||
<font style="color: #f56c6c; margin-right: 5px">*</font>
|
||||
Table :
|
||||
Table:
|
||||
</span>
|
||||
<common-table
|
||||
@getContent="getContent"
|
||||
v-if="threeVisible"
|
||||
ref="commonTable"
|
||||
style="margin-left: -115px"
|
||||
@openLatexEditor="openLatexEditor"
|
||||
:lineStyle="lineStyle"
|
||||
></common-table>
|
||||
</el-form-item>
|
||||
<el-form-item label="Bottom Title :">
|
||||
<el-form-item label="Note:">
|
||||
<common-content
|
||||
:id="`editor-${new Date().getTime()}-${lineStyle.am_id}-${lineStyle.amt_id}-note`"
|
||||
:isAutomaticUpdate="true"
|
||||
:value="lineStyle.note"
|
||||
@getContent="getContent"
|
||||
@openLatexEditor="openLatexEditor"
|
||||
v-if="threeVisible"
|
||||
@updateChange="(res) => updateChange(res, 'note')"
|
||||
:height="120"
|
||||
ref="tinymceChildNote"
|
||||
style="margin-left: -115px"
|
||||
></common-content>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<p style="margin: 20px 0; text-align: right">
|
||||
<p style="margin-top: 20px; text-align: right">
|
||||
<el-button @click="threeVisible = false"> Cancel </el-button>
|
||||
<el-button type="primary" plain @click="handleSaveTable"> save Table </el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
@click="handleSaveTable"
|
||||
style="background-color: #006699 !important; background: #006699 !important; margin-right: 20px; color: #fff !important"
|
||||
>
|
||||
save Table
|
||||
</el-button>
|
||||
</p>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
</el-drawer>
|
||||
<el-dialog
|
||||
destroy-on-close
|
||||
v-if="commentVisible"
|
||||
title="Comment"
|
||||
@@ -232,9 +248,10 @@
|
||||
>
|
||||
<el-form ref="editMes" :model="commentForm" label-width="115px">
|
||||
<el-form-item label="Select Content:" v-if="commentForm.content">
|
||||
<p style="background: #eef0f4; line-height: 20px; padding: 10px; box-sizing: border-box" v-html="commentForm.content">
|
||||
|
||||
</p>
|
||||
<p
|
||||
style="background: #eef0f4; line-height: 20px; padding: 10px; box-sizing: border-box"
|
||||
v-html="commentForm.content"
|
||||
></p>
|
||||
</el-form-item>
|
||||
<el-form-item label="Word">
|
||||
<span slot="label">
|
||||
@@ -278,6 +295,7 @@
|
||||
<common-content
|
||||
:value="currentContent.content"
|
||||
@getContent="getContent"
|
||||
@openLatexEditor="openLatexEditor"
|
||||
v-if="editVisible"
|
||||
ref="commonContent"
|
||||
style="margin-left: -115px"
|
||||
@@ -293,6 +311,40 @@
|
||||
</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
destroy-on-close
|
||||
v-if="addContentVisible"
|
||||
title="Add Content"
|
||||
:visible.sync="addContentVisible"
|
||||
width="1200px"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<el-form ref="editMes" :model="addContent" label-width="115px">
|
||||
<el-form-item label="Word">
|
||||
<span slot="label">
|
||||
<font style="color: #f56c6c; margin-right: 5px">*</font>
|
||||
Content :
|
||||
</span>
|
||||
<common-content
|
||||
:value="addContent.content"
|
||||
@getContent="getContent"
|
||||
@openLatexEditor="openLatexEditor"
|
||||
v-if="addContentVisible"
|
||||
ref="addContent"
|
||||
style="margin-left: -115px"
|
||||
></common-content>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="editVisible = false"> Cancel </el-button>
|
||||
<el-button type="primary" @click="handleSaveAddContent">
|
||||
<!-- <i class="el-icon-finished" style="margin-right: 5px"></i> -->
|
||||
Save
|
||||
</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<common-late-x v-if="showLateX" @close="showLateX = false" @save="saveLateX" :LateXInfo="LateXInfo"></common-late-x>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -306,7 +358,9 @@ import bottomTinymce from '@/components/page/components/Tinymce';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
LateXInfo: {},
|
||||
isEditComment: false,
|
||||
showLateX: false,
|
||||
comments: [],
|
||||
remarkImageUrl: 'https://submission.tmrjournals.com/public/usericon/20241222/4e77ba3f29ce3cf798b36f24dc411b76.png',
|
||||
isFirstComponentLoaded: false,
|
||||
@@ -400,6 +454,8 @@ export default {
|
||||
ChGtpTxt: ''
|
||||
},
|
||||
txtVisible: false,
|
||||
addContentVisible: false,
|
||||
addContent: {},
|
||||
lineStyle: {},
|
||||
contentStyle: {},
|
||||
lineTable: [],
|
||||
@@ -459,6 +515,11 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
openLatexEditor(data) {
|
||||
console.log('data at line 563:', data);
|
||||
this.showLateX = true;
|
||||
this.LateXInfo=data
|
||||
},
|
||||
isShowEditComment() {
|
||||
if (localStorage.getItem('U_role')) {
|
||||
var identity = localStorage.getItem('U_role');
|
||||
@@ -494,15 +555,15 @@ export default {
|
||||
handleSaveContent() {
|
||||
this.$refs.commonContent.getTinymceContent('content');
|
||||
},
|
||||
handleSaveAddContent() {
|
||||
this.$refs.addContent.getTinymceContent('addcontent');
|
||||
},
|
||||
|
||||
async getContent(type, content) {
|
||||
|
||||
console.log('content at line 539:', content);
|
||||
if (type == 'content') {
|
||||
|
||||
content = content.replace(/<(?!\/?(img|b|i|sub|sup|span|strong|em |blue)\b)[^>]+>/g, '');
|
||||
|
||||
content = content.replace(/\s*style="[^"]*"/g, '');
|
||||
|
||||
content = this.$commonJS.transformHtmlString(content);
|
||||
console.log('content at line 604:', content);
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = content; // 将 HTML 字符串加载到 div 中
|
||||
// 替换所有 <strong> 为 <b>
|
||||
@@ -522,27 +583,41 @@ export default {
|
||||
|
||||
// 获取最终修改后的 HTML
|
||||
content = div.innerHTML;
|
||||
|
||||
|
||||
|
||||
this.saveContent(content, this.currentContent.am_id);
|
||||
} else if (type == 'addcontent') {
|
||||
var hasTable = /<table[\s\S]*?>[\s\S]*?<\/table>/i.test(content);
|
||||
|
||||
if (hasTable) {
|
||||
this.$message({
|
||||
type: 'warning',
|
||||
message: 'Table content is not supported!'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
var list = this.$commonJS.cleanAndParseWordContent(content);
|
||||
console.log('list at line 569:', list);
|
||||
|
||||
this.saveContentList(list, this.currentId);
|
||||
} else if (type == 'table') {
|
||||
this.saveTable(content);
|
||||
} else if (type == 'comment') {
|
||||
this.addComment(content);
|
||||
}
|
||||
},
|
||||
async saveContent(content, am_id) {
|
||||
|
||||
},
|
||||
async saveContent(content, am_id) {
|
||||
var that = this;
|
||||
var str = content.replace(/^<p>(.*?)<\/p>$/, '$1') ? content.replace(/^<p>(.*?)<\/p>$/, '$1') : '';
|
||||
if (str == '') {
|
||||
this.$message({
|
||||
type: 'warning',
|
||||
message: 'Please enter the content!'
|
||||
});
|
||||
}
|
||||
str= await that.$commonJS.decodeHtml(str)
|
||||
var str = content.replace(/^<p>\s*(.*?)\s*<\/p>$/, '$1').trim();
|
||||
// var str = content.replace(/^<p>(.*?)<\/p>$/, '$1') ? content.replace(/^<p>(.*?)<\/p>$/, '$1') : '';
|
||||
console.log('str at line 580:', JSON.stringify(str));
|
||||
|
||||
// if (str == '') {
|
||||
// this.$message({
|
||||
// type: 'warning',
|
||||
// message: 'Please enter the content!'
|
||||
// });
|
||||
// }
|
||||
str = await that.$commonJS.decodeHtml(str);
|
||||
await that.$api
|
||||
.post(that.urlList.editContent, {
|
||||
am_id: am_id,
|
||||
@@ -556,6 +631,28 @@ export default {
|
||||
}
|
||||
});
|
||||
},
|
||||
async saveContentList(content, am_id) {
|
||||
if (content.length == 0) {
|
||||
this.$message({
|
||||
type: 'warning',
|
||||
message: 'Please enter the content!'
|
||||
});
|
||||
}
|
||||
|
||||
await this.$api
|
||||
.post('api/Preaccept/addMoreRow', {
|
||||
article_id: this.articleId,
|
||||
am_id: am_id,
|
||||
rows: content
|
||||
})
|
||||
.then(async (res) => {
|
||||
if (res.code == 0) {
|
||||
this.addContentVisible = false;
|
||||
this.getDate();
|
||||
this.getCommentList();
|
||||
}
|
||||
});
|
||||
},
|
||||
deleteComment(comment, index) {
|
||||
console.log('comment at line 480:', comment);
|
||||
if (this.isEditComment) {
|
||||
@@ -582,7 +679,31 @@ export default {
|
||||
.catch(() => {});
|
||||
}
|
||||
},
|
||||
|
||||
saveLateX(data) {
|
||||
console.log('data at line 735:', data)
|
||||
const { editorId, wmathId, latex } = data;
|
||||
const newLatex = latex ? latex.trim() : '';
|
||||
if (!editorId || !wmathId) return;
|
||||
const targetEditor = tinymce.get(editorId);
|
||||
if (!targetEditor) return;
|
||||
const targetWmath = targetEditor.dom.select(`wmath[data-id="${wmathId}"]`, targetEditor.getBody())[0];
|
||||
if (targetWmath) {
|
||||
if (!newLatex) {
|
||||
// ❌ 删除公式
|
||||
targetEditor.dom.remove(targetWmath);
|
||||
} else {
|
||||
// ✅ 更新公式
|
||||
targetWmath.setAttribute('data-latex', newLatex);
|
||||
targetWmath.innerHTML = newLatex;
|
||||
|
||||
setTimeout(() => {
|
||||
if (typeof renderMathJax === 'function') {
|
||||
this.window.renderMathJax(editorId);
|
||||
}
|
||||
}, 10);
|
||||
}
|
||||
}
|
||||
},
|
||||
async huifu(id) {
|
||||
var that = this;
|
||||
await this.$confirm(this.$t('commonTable.reContent'), 'Prompt', {
|
||||
@@ -712,6 +833,56 @@ export default {
|
||||
console.log('err at line 466:', err);
|
||||
});
|
||||
},
|
||||
async onDeletes(dataId) {
|
||||
await this.$confirm(this.$t('commonTable.removeContent'), 'Prompt', {
|
||||
confirmButtonText: 'Submit',
|
||||
cancelButtonText: 'Cancel',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(async () => {
|
||||
var that = this;
|
||||
|
||||
await that.$api
|
||||
.post('/api/Preaccept/delMoreArticleMains', {
|
||||
ids: dataId
|
||||
})
|
||||
.then(async (res) => {
|
||||
if (res.code == 0) {
|
||||
setTimeout(() => {
|
||||
that.getDate();
|
||||
that.getCommentList();
|
||||
that.$refs.commonWordHtmlTypeSetting.refresh('img');
|
||||
that.$refs.commonWordHtmlTypeSetting.refresh('table');
|
||||
that.$forceUpdate();
|
||||
});
|
||||
}
|
||||
});
|
||||
// this.Main_List.splice(
|
||||
// this.Main_List.findIndex((item) => item.p_main_id == dataId),
|
||||
// 1
|
||||
// );
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log('err at line 466:', err);
|
||||
});
|
||||
},
|
||||
async changeSort(type, id) {
|
||||
var that = this;
|
||||
await that.$api
|
||||
.post(type == 'up' ? '/api/Preaccept/upArticleMain' : '/api/Preaccept/downArticleMain', {
|
||||
am_id: id
|
||||
})
|
||||
.then(async (res) => {
|
||||
if (res.code == 0) {
|
||||
setTimeout(() => {
|
||||
that.getDate();
|
||||
that.getCommentList();
|
||||
|
||||
that.$forceUpdate();
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
async addCommentSetting(content) {
|
||||
console.log('content at line 602:', content);
|
||||
await this.$api
|
||||
@@ -850,6 +1021,9 @@ export default {
|
||||
async onEditTitle(data) {
|
||||
var url;
|
||||
switch (data.value) {
|
||||
case 0:
|
||||
url = 'api/Preaccept/changeNormal';
|
||||
break;
|
||||
case 1:
|
||||
url = 'api/Preaccept/changeH1';
|
||||
break;
|
||||
@@ -962,7 +1136,8 @@ export default {
|
||||
}
|
||||
},
|
||||
updateChange(content, type) {
|
||||
console.log('content at line 976:', content)
|
||||
console.log('content at line 1154:', content);
|
||||
// console.log('content at line 976:', content);
|
||||
var str = this.$commonJS.transformHtmlString(content);
|
||||
if (type == 'imgNote') {
|
||||
this.picStyle.note = str;
|
||||
@@ -1005,13 +1180,19 @@ export default {
|
||||
this.lineStyle.visiTitle = 'Edit Table';
|
||||
this.threeVisible = true;
|
||||
} else {
|
||||
data.content = data.content.replace(/<span[^>]*>/g, '').replace(/<\/span>/g, ''); // 去除span标签
|
||||
data.content = data.content.replace(/<span[^>]*>/g, '').replace(/<\/span>/g, ''); // 去除span标签
|
||||
this.currentContent = data;
|
||||
|
||||
|
||||
this.editVisible = true;
|
||||
this.currentId = dataId;
|
||||
}
|
||||
},
|
||||
onAddContent(dataId) {
|
||||
this.addContentVisible = true;
|
||||
this.addContent = {};
|
||||
|
||||
this.currentId = dataId;
|
||||
},
|
||||
async onDrop(event, dataId) {
|
||||
if (event.dataTransfer.getData('image')) {
|
||||
const draggedImage = JSON.parse(event.dataTransfer.getData('image'));
|
||||
@@ -1330,16 +1511,16 @@ export default {
|
||||
},
|
||||
|
||||
// 确定保存图片
|
||||
async savePic() {
|
||||
async savePic() {
|
||||
this.picStyle.picUrl;
|
||||
var str=this.picStyle.note
|
||||
str= await this.$commonJS.decodeHtml(str)
|
||||
var str = this.picStyle.note;
|
||||
str = await this.$commonJS.decodeHtml(str);
|
||||
if (this.picStyle.visiTitle == 'Edit Figure') {
|
||||
this.$api
|
||||
.post(this.urlList.editImage, {
|
||||
ami_id: this.picStyle.ami_id,
|
||||
url: this.picStyle.picUrl,
|
||||
note:str
|
||||
note: str
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
@@ -1391,18 +1572,24 @@ export default {
|
||||
this.$refs.tinymceChildComment.getContent('comment');
|
||||
});
|
||||
},
|
||||
async saveTable(content) {
|
||||
async saveTable(content) {
|
||||
console.log('content at line 998:', content);
|
||||
var strTitle=this.lineStyle.title
|
||||
strTitle= await this.$commonJS.decodeHtml(strTitle)
|
||||
|
||||
var strNote=this.lineStyle.note
|
||||
if(strNote!=''){
|
||||
strNote= await this.$commonJS.decodeHtml(strNote)
|
||||
var strTitle = this.lineStyle.title;
|
||||
strTitle = await this.$commonJS.decodeHtml(strTitle);
|
||||
|
||||
var strNote = this.lineStyle.note;
|
||||
if (strNote != '') {
|
||||
strNote = await this.$commonJS.decodeHtml(strNote);
|
||||
}
|
||||
|
||||
|
||||
if (content && content.table && content.table.length > 0) {
|
||||
if (this.lineStyle.visiTitle == 'Edit Table') {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
text: 'Loading...',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
});
|
||||
this.$api
|
||||
.post(this.urlList.editTable, {
|
||||
amt_id: this.lineStyle.amt_id,
|
||||
|
||||
@@ -286,7 +286,8 @@ export default {
|
||||
// username: this.query.username
|
||||
})
|
||||
.then(async (res) => {
|
||||
this.jourList = res;
|
||||
this.jourList = res.data.journals;
|
||||
console.log('this.jourList at line 289:', this.jourList)
|
||||
// this.currentJournal = this.jourList[0];
|
||||
await this.getDate();
|
||||
})
|
||||
@@ -485,7 +486,7 @@ export default {
|
||||
var that = this;
|
||||
// this.currentJournalStage = data;
|
||||
this.detailForm = {
|
||||
issn: this.currentJournal.issn,
|
||||
issn: this.journal.issn,
|
||||
// stage_icon: '11.jpg',
|
||||
|
||||
// stage_icon: data.stage_icon,
|
||||
@@ -496,12 +497,14 @@ export default {
|
||||
// issue_date: data.issue_date,
|
||||
// stage_icon: data.stage_icon
|
||||
};
|
||||
console.log('this.detailForm at line 487:', this.detailForm)
|
||||
this.editDialogVisible1 = true;
|
||||
// this.$nextTick(() => {
|
||||
// that.$refs.commonClassRef.init();
|
||||
// });
|
||||
},
|
||||
openJournalAgreement(data) {
|
||||
console.log('data at line 505:', data)
|
||||
var that = this;
|
||||
this.currentJournal = data;
|
||||
this.drawerAgreement = true;
|
||||
|
||||
@@ -215,8 +215,7 @@
|
||||
localStorage.setItem('U_role', 'superadmin');
|
||||
localStorage.setItem('U_name', res.userinfo.account);
|
||||
localStorage.setItem('U_id', res.userinfo.user_id);
|
||||
return false
|
||||
// localStorage.setItem('U_id', res.userinfo.admin_id);
|
||||
|
||||
this.$router.push('/');
|
||||
} else if (res.data.roles.includes('editor')) {
|
||||
localStorage.setItem('U_status', '1'); //编辑
|
||||
|
||||
@@ -92,6 +92,10 @@
|
||||
<li>
|
||||
<p>- If you want to discard all references and import a new batch of reference information, please click <el-button type="text" @click="removeAll">Delete and re-import</el-button>.</p>
|
||||
</li>
|
||||
<li >
|
||||
<p style="display: flex;align-items: center">- Please note that if this status exists, <span > <img src="../../assets/img/repeat.png" alt="" style="width: 24px;height: 24px;margin-left: 5px;margin-right: 5px">
|
||||
</span> it indicates that the current reference is duplicated .</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>- Please do not forget to recheck all references in the <span class="status ok float" ><i class="el-icon-circle-check"></i></span> status,especially abbreviated journal title.</p>
|
||||
</li>
|
||||
@@ -100,7 +104,12 @@
|
||||
<div class="refenceCentent mt20">
|
||||
<el-table :data="tableData" ref="multipleTable"
|
||||
empty-text="New messages (0)" :show-header="false" :stripe="false" :highlight-current-row="false">
|
||||
<el-table-column type="index" label="No." width="55" align="center"></el-table-column>
|
||||
<el-table-column type="index" label="No." width="60" align="center">
|
||||
<template slot-scope="scope" >
|
||||
<img src="../../assets/img/repeat.png" v-if="scope.row.is_repeat==1" alt="" style="width: 24px;height: 24px;float: left;">
|
||||
<span>{{scope.$index+1}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="state" width="55" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span class="status ok" v-if="scope.row.refer_type == 'journal' && scope.row.doilink != '' || scope.row.refer_type == 'book' && scope.row.isbn != '' " >
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
</div>
|
||||
|
||||
<div class="manu_add" style="width: 960px" v-loading="loading">
|
||||
<el-form ref="articleform" :model="form" :rules="rules" label-width="160px">
|
||||
<el-form ref="articleform" :model="form" :rules="rules" label-width="120px">
|
||||
<div class="bag_color" v-if="show_step == 1">
|
||||
<div>
|
||||
<h3>Manuscript Information</h3>
|
||||
@@ -56,8 +56,8 @@
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="Research areas :" prop="major">
|
||||
<common-major-list :list="majorValueList" @load="(e)=>this.majorValueList=e"></common-major-list>
|
||||
<el-form-item label="Research areas :" prop="major" label-width="160px">
|
||||
<common-major-list :list="majorValueList" @load="(e) => (this.majorValueList = e)"></common-major-list>
|
||||
<!-- <el-select
|
||||
v-model="form.major_a"
|
||||
placeholder="Please select major"
|
||||
@@ -102,7 +102,7 @@
|
||||
></el-option>
|
||||
</el-select> -->
|
||||
</el-form-item>
|
||||
<el-form-item label="Manuscript Title :" prop="title">
|
||||
<el-form-item label="Manuscript Title :" prop="title" label-width="160px">
|
||||
<el-input v-model="form.title" placeholder="Please enter title"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="Whether ethical approval was obtained ?" prop="approval" label-width="300px">
|
||||
@@ -189,17 +189,19 @@
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="Article Processing Charge :" v-if="ms_alias == null" label-width="180px">
|
||||
<el-form-item label="Article Processing Charge :" v-if="form.journal != 0" label-width="180px">
|
||||
$ {{ getFee(form.journal) }}
|
||||
<div style="color: #8c8d8f"v-if=" getFee(form.journal)&&getFee(form.journal)!='0.00'">
|
||||
<i class="el-icon-warning" style="color: #517fd5; margin-right: 4px"></i>The article processing fee applies to papers submitted and ultimately accepted for publication after January 1, 2025. For authors seeking to apply for fee discounts, please <a
|
||||
<div style="color: #8c8d8f" v-if="getFee(form.journal) && getFee(form.journal) != '0.00'">
|
||||
<i class="el-icon-warning" style="color: #517fd5; margin-right: 4px"></i>The article processing fee
|
||||
applies to papers submitted and ultimately accepted for publication after January 1, 2025. For
|
||||
authors seeking to apply for fee discounts, please
|
||||
<a
|
||||
style="color: rgb(81, 127, 213); cursor: pointer; text-decoration: underline"
|
||||
href="https://www.tmrjournals.com/apc/"
|
||||
target="_blank"
|
||||
>click here</a
|
||||
> to view detailed policies.
|
||||
|
||||
|
||||
>
|
||||
to view detailed policies.
|
||||
</div>
|
||||
</el-form-item>
|
||||
<div style="text-align: center; margin: 40px 0 0 0">
|
||||
@@ -967,7 +969,7 @@
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
majorValueList:[],
|
||||
majorValueList: [],
|
||||
baseUrl: this.Common.baseUrl,
|
||||
usercap: localStorage.getItem('U_role'),
|
||||
ms_alias: localStorage.getItem('ms_journal_alias'),
|
||||
@@ -1008,7 +1010,7 @@ export default {
|
||||
],
|
||||
form: {
|
||||
article_id: 0,
|
||||
journal: localStorage.getItem('ms_journal_alias') ? parseInt(localStorage.getItem('ms_journal_alias')) : 1,
|
||||
journal: localStorage.getItem('ms_journal_alias') ? parseInt(localStorage.getItem('ms_journal_alias')) : '',
|
||||
username: localStorage.getItem('U_name'),
|
||||
user_id: localStorage.getItem('U_id'),
|
||||
title: '',
|
||||
@@ -1196,21 +1198,20 @@ export default {
|
||||
}
|
||||
],
|
||||
major: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
console.log('value at line 1202:', this.form);
|
||||
var major=this.majorValueList.map(item => item.selectedValue[item.selectedValue.length - 1]).toString(',')
|
||||
if (major=='') {
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
console.log('value at line 1202:', this.form);
|
||||
var major = this.majorValueList.map((item) => item.selectedValue[item.selectedValue.length - 1]).toString(',');
|
||||
if (major == '') {
|
||||
callback(new Error('Please select the Research areas'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
// 如果你需要在此处使用 this 访问 Vue 实例的数据,使用箭头函数保持上下文
|
||||
// 其他逻辑
|
||||
}
|
||||
}
|
||||
|
||||
// 如果你需要在此处使用 this 访问 Vue 实例的数据,使用箭头函数保持上下文
|
||||
// 其他逻辑
|
||||
}
|
||||
}
|
||||
],
|
||||
abstrart: [
|
||||
{
|
||||
@@ -1461,12 +1462,17 @@ export default {
|
||||
return false;
|
||||
}
|
||||
this.$refs.articleform.validate((valid) => {
|
||||
if (this.isAbstractTooShort(this.form.abstrart)) {
|
||||
this.$message.error('The abstract should not be less than 200 Chinese characters or English words!');
|
||||
return false;
|
||||
}
|
||||
//验证文档
|
||||
if (this.form.manuscirpt == '') {
|
||||
this.$message.error('Manuscirpt is required');
|
||||
// console.log('file up error');
|
||||
return false;
|
||||
}
|
||||
|
||||
//验证作者
|
||||
let authorlist = this.form.authorList;
|
||||
let Firsta = 0;
|
||||
@@ -1507,9 +1513,11 @@ export default {
|
||||
this.$message.error('First author and corresponding author must be exist');
|
||||
return false;
|
||||
}
|
||||
console.log('this.form.major at line 1512:', this.form.major);
|
||||
//验证文章领域
|
||||
this.form.major = this.majorValueList.map((item) => item.selectedValue[item.selectedValue.length - 1]).toString(',');
|
||||
if (this.form.major == '') {
|
||||
this.$message.error('Major is required');
|
||||
this.$message.error('Please select the Research areas');
|
||||
return false;
|
||||
}
|
||||
//验证选择转投但没选期刊项的情况
|
||||
@@ -1612,7 +1620,17 @@ export default {
|
||||
},
|
||||
|
||||
Submission_of_manuscripts() {
|
||||
// 提交稿件
|
||||
// 提交稿件AI检索
|
||||
this.$api
|
||||
// api/Article/addArticle
|
||||
.post('api/Aireview/review', {
|
||||
article_id: this.form.article_id,
|
||||
abstrart: this.form.abstrart,
|
||||
keywords: this.form.keyWords,
|
||||
api_model: 'gpt-4o'
|
||||
})
|
||||
.then((res) => {});
|
||||
|
||||
this.$api
|
||||
// api/Article/addArticle
|
||||
.post('api/Article/addArticlePart4', this.form)
|
||||
@@ -2509,10 +2527,27 @@ export default {
|
||||
this.form.checkedjours = [];
|
||||
this.form.istransfer = false;
|
||||
this.form.becomeRev = false;
|
||||
if (this.$route.query.id) {
|
||||
this.saveArticle();
|
||||
}
|
||||
this.initMajor();
|
||||
// this.getTopics()
|
||||
},
|
||||
saveArticle() {
|
||||
// api/Article/changeJournal
|
||||
|
||||
this.$api
|
||||
.post('api/Article/changeJournal', {
|
||||
article_id: this.$route.query.id,
|
||||
journal_id: this.form.journal
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
} else {
|
||||
// this.$message.error(res.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
// 点击tab变化
|
||||
StepCode(e) {
|
||||
console.log('🚀 ~ StepCode ~ e111:', e);
|
||||
@@ -2610,14 +2645,21 @@ export default {
|
||||
},
|
||||
|
||||
// 点击进行下一步
|
||||
onStep(e) {
|
||||
|
||||
console.log('this.majorValueList at line 2604:', this.majorValueList)
|
||||
console.log('this.form at line 2622:', this.form)
|
||||
|
||||
onStep(e) {
|
||||
console.log('this.majorValueList at line 2604:', this.majorValueList);
|
||||
console.log('this.form at line 2622:', this.form.abstrart);
|
||||
|
||||
this.$refs.articleform.validate((valid) => {
|
||||
if (valid) {
|
||||
if (this.isAbstractTooShort(this.form.abstrart)) {
|
||||
this.$message.error('The abstract should not be less than 200 Chinese characters or English words!');
|
||||
return false;
|
||||
}
|
||||
if (e == 1) {
|
||||
if (this.form.journal == 0 || !this.form.journal) {
|
||||
this.$message.error('Please select the Journal');
|
||||
return false;
|
||||
}
|
||||
// this.onStaging(1)
|
||||
// setTimeout(() => {
|
||||
// console.log('456')
|
||||
@@ -2633,13 +2675,15 @@ export default {
|
||||
}
|
||||
}
|
||||
this.form.keyWords = fstr == '' ? '' : fstr.substring(0, fstr.length - 1);
|
||||
this.form.major=this.majorValueList.map(item => item.selectedValue[item.selectedValue.length - 1]).toString(',')
|
||||
if(this.form.major==''){
|
||||
this.$message.error('Please select the Research areas')
|
||||
return false
|
||||
}
|
||||
this.form.major = this.majorValueList
|
||||
.map((item) => item.selectedValue[item.selectedValue.length - 1])
|
||||
.toString(',');
|
||||
if (this.form.major == '') {
|
||||
this.$message.error('Please select the Research areas');
|
||||
return false;
|
||||
}
|
||||
|
||||
this.$api.post('api/Article/addArticlePart1', this.form).then((res) => {
|
||||
|
||||
if (res.code == 0) {
|
||||
this.stagingID = res.data.article_id;
|
||||
this.form.article_id = res.data.article_id;
|
||||
@@ -2716,7 +2760,12 @@ export default {
|
||||
onStaging(e) {
|
||||
var that = this;
|
||||
console.log('e at line 2584:', e);
|
||||
console.log('this.form at line 2622:', this.form);
|
||||
if (e == 1) {
|
||||
if (this.form.journal == 0 || !this.form.journal) {
|
||||
this.$message.error('Please select the Journal');
|
||||
return false;
|
||||
}
|
||||
var flist = this.keywordsList;
|
||||
var fstr = '';
|
||||
for (var fu in flist) {
|
||||
@@ -2724,15 +2773,18 @@ export default {
|
||||
fstr += flist[fu].ke.trim() + ',';
|
||||
}
|
||||
}
|
||||
console.log('this.form at line 2707:', this.form)
|
||||
console.log('this.form at line 2707:', this.form.abstrart);
|
||||
this.form.keyWords = fstr == '' ? '' : fstr.substring(0, fstr.length - 1);
|
||||
this.form.major=this.majorValueList.map(item => item.selectedValue[item.selectedValue.length - 1]).toString(',')
|
||||
if(this.form.major==''){
|
||||
this.$message.error('Please select the Research areas')
|
||||
return false
|
||||
}
|
||||
this.form.major = this.majorValueList.map((item) => item.selectedValue[item.selectedValue.length - 1]).toString(',');
|
||||
if (this.form.major == '') {
|
||||
this.$message.error('Please select the Research areas');
|
||||
return false;
|
||||
}
|
||||
if (this.isAbstractTooShort(this.form.abstrart)) {
|
||||
this.$message.error('The abstract should not be less than 200 Chinese characters or English words!');
|
||||
return false;
|
||||
}
|
||||
this.$api.post('api/Article/addArticlePart1', this.form).then((res) => {
|
||||
|
||||
if (res.code == 0) {
|
||||
this.stagingID = res.data.article_id;
|
||||
this.form.article_id = res.data.article_id;
|
||||
@@ -2848,7 +2900,14 @@ export default {
|
||||
});
|
||||
}
|
||||
},
|
||||
isAbstractTooShort(text) {
|
||||
let chineseCount = (text.match(/[\u4e00-\u9fa5]/g) || []).length;
|
||||
let englishCount = (text.match(/[A-Za-z0-9]/g) || []).length;
|
||||
|
||||
const total = chineseCount + englishCount;
|
||||
|
||||
return total < 200; // 不足 200,说明太短
|
||||
},
|
||||
// 读取
|
||||
Temporary() {
|
||||
this.$api
|
||||
@@ -2869,10 +2928,14 @@ export default {
|
||||
console.log(res.data.base);
|
||||
// this.form.topics = res.data.base.topics
|
||||
// 领域
|
||||
this.majorValueList = res.data.majors.map(item => ({
|
||||
|
||||
selectedValue: Array.isArray(item.major) ? item.major : (typeof item.major === 'string' ? item.major.split(',').map(Number) : [item.major])
|
||||
})); console.log('this.majorValueList at line 2853:', this.majorValueList)
|
||||
this.majorValueList = res.data.majors.map((item) => ({
|
||||
selectedValue: Array.isArray(item.major)
|
||||
? item.major
|
||||
: typeof item.major === 'string'
|
||||
? item.major.split(',').map(Number)
|
||||
: [item.major]
|
||||
}));
|
||||
console.log('this.majorValueList at line 2853:', this.majorValueList);
|
||||
// this.$api
|
||||
// .post('api/Major/getMajorForAddArticle', {
|
||||
// journal_id: this.form.journal,
|
||||
@@ -3310,26 +3373,30 @@ export default {
|
||||
}
|
||||
|
||||
.jour_ku_all {
|
||||
font-size: 12px;
|
||||
font-size: 14px;
|
||||
float: left;
|
||||
width: 265px;
|
||||
width: 48%;
|
||||
padding-left: 10px;
|
||||
cursor: pointer;
|
||||
color: #666;
|
||||
line-height: 26px;
|
||||
}
|
||||
|
||||
.jour_ku_all:nth-child(3n + 1) {
|
||||
/* .jour_ku_all:nth-child(3n + 1) {
|
||||
width: 230px;
|
||||
}
|
||||
|
||||
.jour_ku_all:nth-child(3n + 2) {
|
||||
width: 220px;
|
||||
}
|
||||
} */
|
||||
|
||||
.jour_ku_all.B_style {
|
||||
color: #006699;
|
||||
color: #1161ea;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
background: #ebf5ff;
|
||||
border-radius: 4px;
|
||||
/* border: 1px solid #b3d8ff ; */
|
||||
}
|
||||
|
||||
.tally_jour {
|
||||
|
||||
@@ -5,7 +5,12 @@
|
||||
<el-breadcrumb-item> <i class="el-icon-lx-calendar"></i> Manuscript detail </el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
</div>
|
||||
<div class="container_state" v-loading="loading" style="margin: 20px 0 0 0">
|
||||
<div class="container_state" v-loading="loading" style="margin: 10px 0 0 0">
|
||||
<div style="margin-bottom: 10px; margin-top: 0px;overflow: hidden;" v-if="AIcontent!=''">
|
||||
<img src="@/assets/img/ai.png" style="width: 30px; height: 30px; margin-right: 4px;float: left;margin-top: 10px;" />
|
||||
|
||||
<p class="beautiful-gradient"style="float: right;width: calc(100% - 40px);font-size: 13px;line-height: 16px;color: #1d45f2;" >{{ AIcontent }}</p>
|
||||
</div>
|
||||
<el-row :gutter="30">
|
||||
<el-col :span="16">
|
||||
<div class="art_state_">
|
||||
@@ -57,7 +62,7 @@
|
||||
<p v-if="form.special_num > 0">
|
||||
<font>Special Issues :</font><b>{{ form.special_title }}</b>
|
||||
</p>
|
||||
|
||||
|
||||
<el-collapse class="auth_colla auth_collna_ew">
|
||||
<el-collapse-item :title="authorList_name" name="1">
|
||||
<div v-for="(item, index) in form.authorList" class="auth_mess">
|
||||
@@ -108,7 +113,7 @@
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
|
||||
|
||||
<el-collapse class="auth_colla auth_collna_ew" style="margin-top: -15px">
|
||||
<el-collapse-item name="2">
|
||||
<template slot="title">
|
||||
@@ -127,20 +132,16 @@
|
||||
</p>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
<el-collapse class="auth_colla auth_collna_ew" style="margin-top: -15px;">
|
||||
<el-collapse-item title="Research areas" name="1" >
|
||||
|
||||
|
||||
|
||||
<div style="position: relative;height: 30px;">
|
||||
<common-major
|
||||
:articleId="editform.articleId"
|
||||
@load="initMajor()"
|
||||
style="position: absolute; top: 10px; right: 10px"
|
||||
></common-major>
|
||||
|
||||
<el-collapse class="auth_colla auth_collna_ew" style="margin-top: -15px">
|
||||
<el-collapse-item title="Research areas" name="1">
|
||||
<div style="position: relative; height: 30px">
|
||||
<common-major
|
||||
:articleId="editform.articleId"
|
||||
@load="initMajor()"
|
||||
style="position: absolute; top: 10px; right: 10px"
|
||||
></common-major>
|
||||
</div>
|
||||
|
||||
|
||||
<div style="margin: 12px 20px 30px 0px; line-height: 24px; font-size: 14px; position: relative">
|
||||
<div>
|
||||
<!-- 统计数据 -->
|
||||
@@ -164,7 +165,7 @@
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="art_file_">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12" v-if="coverLetterFileList">
|
||||
@@ -552,6 +553,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
AIcontent:'',
|
||||
previewData: {},
|
||||
baseUrl: this.Common.baseUrl,
|
||||
mediaUrl: this.Common.mediaUrl,
|
||||
@@ -623,10 +625,10 @@ export default {
|
||||
state: 6,
|
||||
title: this.$t('artstate.state6')
|
||||
},
|
||||
{
|
||||
state: 5,
|
||||
title: this.$t('artstate.state5')
|
||||
}
|
||||
// {
|
||||
// state: 5,
|
||||
// title: this.$t('artstate.state5')
|
||||
// }
|
||||
],
|
||||
form: {
|
||||
articleId: this.$route.query.id,
|
||||
@@ -672,6 +674,7 @@ export default {
|
||||
};
|
||||
},
|
||||
created: function () {
|
||||
this.getAi();
|
||||
this.initarticle();
|
||||
|
||||
this.initFileList();
|
||||
@@ -807,6 +810,18 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async getAi(){
|
||||
var that = this;
|
||||
await this.$api
|
||||
.post('api/Aireview/get', {
|
||||
article_id: this.$route.query.id
|
||||
})
|
||||
.then(async (res) => {
|
||||
console.log('res at line 819:', res)
|
||||
this.AIcontent = res.data.content?res.data.content:'';
|
||||
|
||||
});
|
||||
},
|
||||
async getWordimgList() {
|
||||
var that = this;
|
||||
await this.$api
|
||||
@@ -1473,4 +1488,21 @@ export default {
|
||||
::v-deep .el-drawer__wrapper .WACContainer {
|
||||
z-index: 10000 !important;
|
||||
}
|
||||
|
||||
.beautiful-gradient {
|
||||
background: linear-gradient(135deg, #f0f9fe, #dce6ff, #d7e9fd);
|
||||
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.01);
|
||||
border-radius: 16px;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
color: #333;
|
||||
font-family: "Segoe UI", sans-serif;
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.beautiful-gradient:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -52,7 +52,19 @@
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleSearch" style="margin: 0 0 10px 0">Search </el-button>
|
||||
</div>
|
||||
<div v-if="!PreAcpVisible">
|
||||
<div v-for="(item, ikgn) in tableData" class="mangu_list">
|
||||
<div v-for="(item, ikgn) in tableData" class="mangu_list" style="position: relative">
|
||||
<img
|
||||
v-if="item.ai_review != '' && item.ai_review"
|
||||
src="@/assets/img/ai.png"
|
||||
@click="openAI(item)"
|
||||
style="cursor: pointer; width: 30px; height: 30px; position: absolute; right: 6px; top: 6px"
|
||||
/>
|
||||
<img
|
||||
v-else
|
||||
src="@/assets/img/ai.png"
|
||||
@click="creatAI(item,ikgn)"
|
||||
style="opacity: 0.5; cursor: pointer; width: 30px; height: 30px; position: absolute; right: 6px; top: 6px"
|
||||
/>
|
||||
<div>
|
||||
<font style="color: #666b7a">ID : </font>
|
||||
<span
|
||||
@@ -253,7 +265,7 @@
|
||||
<div v-if="item.reportList.length > 0" style="text-align: left">
|
||||
<div v-for="(v, i) in item.reportList" style="margin-top: 10px; overflow: hidden">
|
||||
<div style="display: flex; align-items: center; justify-content: space-between">
|
||||
<div style="display: flex; align-items: center;">
|
||||
<div style="display: flex; align-items: center">
|
||||
<span
|
||||
style="
|
||||
float: left;
|
||||
@@ -268,14 +280,20 @@
|
||||
"
|
||||
><i class="el-icon-s-custom"></i
|
||||
></span>
|
||||
<span style="max-width:80%;white-space: nowrap;display: inline-block;
|
||||
<span
|
||||
style="
|
||||
max-width: 80%;
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;">{{ v.author_account.realname }}</span>
|
||||
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
"
|
||||
>{{ v.author_account.realname }}</span
|
||||
>
|
||||
</div>
|
||||
|
||||
<div style="max-width:260px;width:auto;">
|
||||
<div style="max-width: 260px; width: auto">
|
||||
<span style="margin-left: 6px" v-if="v.author_account.wos_time">
|
||||
<span style="font-size: 12px; font-weight: bold">WOS</span> :
|
||||
<span v-html="colorIndex1(v.author_account.wos_index)"></span>
|
||||
@@ -961,7 +979,7 @@
|
||||
"
|
||||
>
|
||||
<el-button type="primary" @click="saveUserIndex(userIndexForm)" style="float: right">{{ $t('citeList.save') }}</el-button>
|
||||
<el-button style="float: right; margin-right: 20px" @click="aiSorbox=false">{{ $t('citeList.cancel') }}</el-button>
|
||||
<el-button style="float: right; margin-right: 20px" @click="aiSorbox = false">{{ $t('citeList.cancel') }}</el-button>
|
||||
</div>
|
||||
</el-drawer>
|
||||
|
||||
@@ -1112,6 +1130,34 @@
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog :title="$t('AI.AISummaryAnalysis')" :visible.sync="isShowAI" width="50%" class="AIDialog">
|
||||
<div class="AISummaryAnalysis">
|
||||
<el-collapse class="auth_colla auth_collna_ew" style="margin-bottom: 0">
|
||||
<el-collapse-item name="1">
|
||||
<template slot="title">
|
||||
Abstract
|
||||
<font v-if="currentArticleData.keywords" style="margin-left: 3px">, Keywords</font>
|
||||
</template>
|
||||
<p>
|
||||
<font>Abstract :</font><b>{{ currentArticleData.abstrart }}</b>
|
||||
</p>
|
||||
<p v-if="currentArticleData.keywords">
|
||||
<font>Keywords :</font><b>{{ currentArticleData.keywords }}</b>
|
||||
</p>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
|
||||
<p style="line-height: 20px">
|
||||
<span>{{ $t('AI.AIAbstractInfo') }} :</span>
|
||||
{{ currentArticleData.ai_review }}
|
||||
</p>
|
||||
</div>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<!-- <el-button @click="isShowAI = false">取 消</el-button> -->
|
||||
<el-button type="primary" @click="isShowAI = false">Close</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1124,6 +1170,8 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isShowAI: false,
|
||||
currentArticleData: {},
|
||||
rules: {},
|
||||
userloading: false,
|
||||
curState: null,
|
||||
@@ -1279,6 +1327,37 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openAI(data) {
|
||||
this.isShowAI = true;
|
||||
this.currentArticleData = { ...data };
|
||||
console.log('this.currentArticleData at line 1312:', this.currentArticleData);
|
||||
|
||||
},
|
||||
creatAI(data,i){
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
text: 'Loading...',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
});
|
||||
console.log('data at line 1336:', data)
|
||||
this.$api
|
||||
// api/Article/addArticle
|
||||
.post('api/Aireview/review', {
|
||||
article_id: data.article_id,
|
||||
|
||||
})
|
||||
.then((res) => {
|
||||
if(res.data.content){
|
||||
this.tableData[i].ai_review=res.data.content
|
||||
loading.close()
|
||||
this.openAI({...data,ai_review:res.data.content});
|
||||
}
|
||||
}).catch((err) => {
|
||||
loading.close()
|
||||
this.$message.error('AI analysis failed')
|
||||
})
|
||||
},
|
||||
// 保存个人信息
|
||||
saveUserIndex() {
|
||||
let link_geo = '';
|
||||
@@ -1802,7 +1881,9 @@ export default {
|
||||
typeName = 'Google';
|
||||
index = this.userMessage.google_time != 0 ? this.userMessage.google_index : '';
|
||||
date = this.userMessage.google_time;
|
||||
website =this.userMessage.g_author?`https://scholar.google.com/citations?hl=en&user=${this.userMessage.g_author}`:'';
|
||||
website = this.userMessage.g_author
|
||||
? `https://scholar.google.com/citations?hl=en&user=${this.userMessage.g_author}`
|
||||
: '';
|
||||
editor = this.userMessage.google_editor;
|
||||
g_author = this.userMessage.g_author;
|
||||
this.bankVisible = false;
|
||||
@@ -2704,4 +2785,42 @@ export default {
|
||||
.userIndexBox .s_rol > div.rol_mess > font {
|
||||
width: auto;
|
||||
}
|
||||
.AISummaryAnalysis p {
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
padding-left: 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.AISummaryAnalysis p span {
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
color: #6157fd;
|
||||
font-weight: bold;
|
||||
}
|
||||
::v-deep .AIDialog .el-dialog__body {
|
||||
padding: 20px !important;
|
||||
}
|
||||
::v-deep .AIDialog .el-dialog__body .auth_collna_ew .el-collapse-item__arrow {
|
||||
padding-left: 0px !important;
|
||||
}
|
||||
::v-deep .AIDialog .el-dialog__body .auth_collna_ew .el-collapse-item__header {
|
||||
padding-left: 30px !important;
|
||||
}
|
||||
::v-deep .AIDialog .el-dialog {
|
||||
/* background: linear-gradient(135deg, #f0f9fe, #dce6ff, #d7e9fd) !important;
|
||||
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.01) !important;
|
||||
border-radius: 16px !important;
|
||||
padding: 10px !important;
|
||||
box-sizing: border-box !important;
|
||||
color: #333 !important;
|
||||
font-family: "Segoe UI", sans-serif !important;
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease !important; */
|
||||
}
|
||||
.beautiful-gradient {
|
||||
}
|
||||
|
||||
.beautiful-gradient:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -200,6 +200,7 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
goEdit() {
|
||||
window.open(this.$router.resolve({ path: '/GenerateCharts',
|
||||
query: {
|
||||
|
||||
@@ -1,531 +0,0 @@
|
||||
<template>
|
||||
<div class="tinymce-container editor-container">
|
||||
<textarea class="tinymce-textarea" :id="tinymceId"></textarea>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { string } from 'html-docx-js/dist/html-docx';
|
||||
import htmlDocx from 'html-docx-js/dist/html-docx.js';
|
||||
import { Document, Packer, PageOrientation, Paragraph, TextRun } from 'docx'; // 引入 docx.js
|
||||
import html2canvas from 'html2canvas';
|
||||
|
||||
const tableStyle = ` b span{
|
||||
font-weight: bold !important;
|
||||
}
|
||||
i span{
|
||||
font-style: italic !important; ;
|
||||
}
|
||||
sub span{
|
||||
vertical-align: sub;
|
||||
}
|
||||
sup span{
|
||||
vertical-align: sup;
|
||||
}
|
||||
sub {
|
||||
vertical-align: sub!important;
|
||||
}
|
||||
sup {
|
||||
vertical-align: sup !important;
|
||||
}
|
||||
span[style*="vertical-align: super"] {
|
||||
vertical-align: super !important;
|
||||
}
|
||||
span[style*="vertical-align: sub"] {
|
||||
vertical-align: sub !important;
|
||||
}
|
||||
table {
|
||||
border:0px !important;
|
||||
border-collapse: collapse; /* 去除单元格间隙 */
|
||||
width: auto;
|
||||
margin : 0 auto !important;
|
||||
table-layout: auto; /* 自动调整列宽 */
|
||||
text-align:left;
|
||||
font-family:'Charis SIL' !important;
|
||||
font-size: 7.5000pt !important;
|
||||
mso-font-kerning: 1.0000pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
}
|
||||
table td, table th {
|
||||
padding: 5px;
|
||||
text-align:left !important;
|
||||
white-space: pre-wrap; /* 保留换行符并换行 */
|
||||
word-wrap: break-word; /* 长单词自动换行 */
|
||||
word-break: break-word;
|
||||
font-family:'Charis SIL' !important;
|
||||
font-size: 7.5000pt !important;
|
||||
mso-font-kerning: 1.0000pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
}
|
||||
table tbody tr td{
|
||||
|
||||
text-align:left !important;
|
||||
border-left:none !important;
|
||||
mso-border-left-alt:none !important;
|
||||
border-right:none !important;
|
||||
mso-border-right-alt:none !important;
|
||||
border-top:none;mso-border-top-alt:none !important;
|
||||
border-bottom:none !important;
|
||||
mso-border-bottom-alt:none !important;
|
||||
|
||||
word-break: keep-all !important;
|
||||
text-align: justify !important; // 设置两端对齐
|
||||
|
||||
|
||||
}
|
||||
table tr td p{
|
||||
|
||||
text-align:left !important;
|
||||
|
||||
margin:0;
|
||||
font-family:'Charis SIL' !important;
|
||||
font-size: 7.5000pt !important;
|
||||
mso-font-kerning: 1.0000pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
}
|
||||
table span{
|
||||
|
||||
color:#000000;text-align:left !important;
|
||||
font-family:'Charis SIL' !important;
|
||||
font-size: 7.5000pt !important;
|
||||
mso-font-kerning: 1.0000pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
}
|
||||
table .color-highlight{
|
||||
color:rgb(0,130,170) !important;
|
||||
font-family:'Charis SIL' !important;
|
||||
font-size: 7.5000pt !important;
|
||||
mso-font-kerning: 1.0000pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
}
|
||||
table tr:first-child td {
|
||||
border-top:1.0000pt solid #000 !important;mso-border-top-alt:0.5000pt solid #000 !important;border-bottom:1.0000pt solid #000 !important;mso-border-bottom-alt:0.5000pt solid #000 !important;
|
||||
}
|
||||
table tr:last-of-type td {
|
||||
border-bottom:1.0000pt solid #000 !important;mso-border-bottom-alt:0.5000pt solid #000 !important;;
|
||||
}
|
||||
|
||||
|
||||
`;
|
||||
export default {
|
||||
name: 'tinymce',
|
||||
components: {},
|
||||
props: {
|
||||
id: {
|
||||
type: String
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
isEdit: {},
|
||||
toolbar: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default() {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
menubar: {
|
||||
default: 'file edit insert view format table '
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 360
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '100%'
|
||||
},
|
||||
isShowArtWorkButton: {
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
typesettingType: 1,
|
||||
typesettingTypeOptions: [
|
||||
{
|
||||
label: this.$t('commonTable.typesettingType1'),
|
||||
value: 1,
|
||||
orientation: 'portrait',
|
||||
pageSize: {
|
||||
width: 11906,
|
||||
height: 16976
|
||||
},
|
||||
pageMargins: {
|
||||
top: 1440,
|
||||
bottom: 1440,
|
||||
left: 1084,
|
||||
right: 1084
|
||||
}
|
||||
},
|
||||
// 1 cm = 144 Twip 上边距(2.54 cm) = 2.54 × 144 = 365.76 Twip
|
||||
{
|
||||
label: this.$t('commonTable.typesettingType2'),
|
||||
value: 2,
|
||||
orientation: 'landscape',
|
||||
pageSize: {
|
||||
width: 16976,
|
||||
height: 11906
|
||||
},
|
||||
pageMargins: {
|
||||
top: 1440,
|
||||
bottom: 1440,
|
||||
left: 1084,
|
||||
right: 1084
|
||||
}
|
||||
}
|
||||
],
|
||||
uploadReset: false,
|
||||
dialogVisible: false,
|
||||
form: {
|
||||
name: '',
|
||||
region: '',
|
||||
date1: '',
|
||||
date2: '',
|
||||
delivery: false,
|
||||
type: [],
|
||||
resource: '',
|
||||
desc: ''
|
||||
},
|
||||
formLabelWidth: '120px',
|
||||
hasChange: false,
|
||||
hasInit: false,
|
||||
|
||||
tinymceId: this.id || 'vue-tinymce-' + +new Date()
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
value(val) {
|
||||
if (!this.hasChange && this.hasInit) {
|
||||
this.$nextTick(() => window.tinymce.get(this.tinymceId).setContent(val));
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.typesettingType = 1;
|
||||
this.initTinymce();
|
||||
},
|
||||
activated() {
|
||||
this.typesettingType = 1;
|
||||
this.initTinymce();
|
||||
},
|
||||
deactivated() {
|
||||
this.destroyTinymce();
|
||||
},
|
||||
methods: {
|
||||
handleSubmit() {
|
||||
this.$refs.uploadImage.handleSubmit();
|
||||
},
|
||||
getDetail(val) {
|
||||
if (this.hasInit == true) {
|
||||
this.$nextTick(() => window.tinymce.get(this.tinymceId).setContent(val));
|
||||
}
|
||||
},
|
||||
//将字符串添加到富文本编辑器中
|
||||
addArtWork(str) {
|
||||
window.tinymce.get(this.tinymceId).insertContent(str);
|
||||
},
|
||||
onClick(e) {
|
||||
this.$emit('onClick', e, tinymce);
|
||||
},
|
||||
|
||||
changeTable() {
|
||||
// 获取所有表格
|
||||
const tables = window.tinymce.get(this.tinymceId).getBody().querySelectorAll('table');
|
||||
console.log('tables at line 110:', tables);
|
||||
|
||||
// 遍历并设置样式
|
||||
tables.forEach((table) => {
|
||||
const editor = window.tinymce.get(this.tinymceId);
|
||||
editor.dom.setStyles(table, {
|
||||
width: this.typesettingType == 1 ? '17.18cm' : '25.88cm'
|
||||
});
|
||||
});
|
||||
|
||||
this.$forceUpdate();
|
||||
},
|
||||
initTinymce() {
|
||||
const _this = this;
|
||||
window.tinymce.init({
|
||||
selector: `#${this.tinymceId}`,
|
||||
content_css: false, // 禁用默认样式
|
||||
table_resize_bars: true, // 启用拖动调整功能
|
||||
valid_elements: '*[*]', // 允许所有 HTML 标签
|
||||
|
||||
paste_preprocess: function (plugin, args) {
|
||||
let content = args.content;
|
||||
const container = document.createElement('div');
|
||||
container.innerHTML = content;
|
||||
_this.updateTableStyles(container);
|
||||
args.content = container.innerHTML; // 更新内容
|
||||
},
|
||||
content_style: `${tableStyle}`,
|
||||
formats: {
|
||||
bold: { inline: 'b' },
|
||||
italic: { inline: 'i' }
|
||||
},
|
||||
body_class: 'panel-body ',
|
||||
object_resizing: false,
|
||||
toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
|
||||
menubar: false, // 启用菜单栏并保持必要的项目
|
||||
statusbar: false, // 关闭底部状态栏
|
||||
custom_colors: false,
|
||||
color_map: ['000000', 'Black', '0082AA', 'TMR Blue'],
|
||||
plugins: 'forecolor code paste table image', // 启用 forecolor 和 code 插件
|
||||
end_container_on_empty_block: true,
|
||||
content_css: 'default', // 加载 TinyMCE 默认样式表
|
||||
//设置自定义按钮 myCustomToolbarButton
|
||||
|
||||
setup(ed) {
|
||||
ed.ui.registry.addButton('uploadWord', {
|
||||
text: 'Word',
|
||||
icon: 'import-word', // 使用自定义图标
|
||||
onAction: function () {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'file';
|
||||
input.accept = '.docx'; // 限制为 Word 文件
|
||||
input.addEventListener('change', function () {
|
||||
const file = input.files[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
const arrayBuffer = e.target.result;
|
||||
_this.$commonJS.extractTablesFromWord(arrayBuffer, function (tablesHtml) {
|
||||
console.log('tablesHtml at line 279:', tablesHtml);
|
||||
ed.setContent(tablesHtml);
|
||||
});
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
}
|
||||
});
|
||||
input.click();
|
||||
}
|
||||
});
|
||||
|
||||
ed.ui.registry.addMenuButton('customDropdown', {
|
||||
text: _this.$t('commonTable.PaperRotation'), // 下拉框标题
|
||||
fetch: function (callback) {
|
||||
// 定义下拉框的内容
|
||||
const items = [..._this.typesettingTypeOptions];
|
||||
const menuItems = items.map((item) => ({
|
||||
type: 'menuitem',
|
||||
text: item.label,
|
||||
onAction: function () {
|
||||
_this.typesettingType = item.value;
|
||||
_this.changeTable();
|
||||
// ed.execCommand(item.value); // 执行命令
|
||||
}
|
||||
}));
|
||||
callback(menuItems);
|
||||
}
|
||||
});
|
||||
|
||||
ed.on('init', function () {
|
||||
const editorBody = ed.getBody();
|
||||
// 创建 MutationObserver 监听内容变化
|
||||
const observer = new MutationObserver(() => {
|
||||
console.log('editorBody at line 313:', editorBody);
|
||||
// _this.updateTableStyles(editorBody, _this.typesettingType);
|
||||
// const hasHorizontalScrollbar = editorBody.scrollWidth > editorBody.clientWidth;
|
||||
// if (hasHorizontalScrollbar) {
|
||||
// console.log('TinyMCE 出现横向滚动条');
|
||||
// } else {
|
||||
// console.log('没有横向滚动条');
|
||||
// }
|
||||
});
|
||||
|
||||
// 监听子节点和内容的变化
|
||||
observer.observe(editorBody, { childList: true, subtree: true, characterData: true });
|
||||
});
|
||||
// 定义自定义按钮
|
||||
ed.ui.registry.addButton('clearButton', {
|
||||
text: 'Empty',
|
||||
|
||||
onAction: () => {
|
||||
// 插入自定义表格到编辑器中
|
||||
ed.setContent('');
|
||||
}
|
||||
});
|
||||
|
||||
// 定义自定义按钮
|
||||
ed.ui.registry.addButton('customButtonExportWord', {
|
||||
text: _this.$t('commonTable.exportWord'),
|
||||
onAction: () => {
|
||||
// 插入自定义表格到编辑器中
|
||||
let content = ed.getContent(); // 获取内容
|
||||
content = content.replace(/<strong>/g, '<b>').replace(/<\/strong>/g, '</b>');
|
||||
content = content.replace(/<em>/g, '<i>').replace(/<\/strong>/g, '</i>');
|
||||
const container = document.createElement('div');
|
||||
container.innerHTML = content;
|
||||
|
||||
_this.export('table', _this.$commonJS.updateTableStyles(container, _this.typesettingType, 1));
|
||||
}
|
||||
});
|
||||
// 定义自定义按钮
|
||||
ed.ui.registry.addButton('customButtonExportImg', {
|
||||
text: _this.$t('commonTable.exportImg'),
|
||||
onAction: () => {
|
||||
// 插入自定义表格到编辑器中
|
||||
_this.export('image', ed.getContent());
|
||||
}
|
||||
});
|
||||
ed.ui.registry.addContextToolbar('spacer', {
|
||||
predicate: () => false, // 保持静态
|
||||
items: '',
|
||||
scope: 'node'
|
||||
});
|
||||
ed.on('paste', (event) => {});
|
||||
ed.on('SetContent', function (e) {
|
||||
e.content = e.content.replace(/<strong>/g, '<b>').replace(/<\/strong>/g, '</b>');
|
||||
e.content = e.content.replace(/<em>/g, '<i>').replace(/<\/em>/g, '</i>');
|
||||
});
|
||||
ed.on('GetContent', function (e) {
|
||||
e.content = e.content.replace(/<b>/g, '<strong>').replace(/<\/b>/g, '</strong>');
|
||||
e.content = e.content.replace(/<i>/g, '<em>').replace(/<\/i>/g, '</em>');
|
||||
});
|
||||
},
|
||||
init_instance_callback: (editor) => {
|
||||
if (_this.value) {
|
||||
editor.setContent(_this.value);
|
||||
}
|
||||
_this.hasInit = true;
|
||||
editor.on('NodeChange Change KeyUp SetContent', () => {
|
||||
this.hasChange = true;
|
||||
this.$emit('input', editor.getContent());
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
// 提取 Word 文件中的表格
|
||||
|
||||
updateTableStyles(container) {
|
||||
var html = this.$commonJS.updateTableStyles(container, this.typesettingType);
|
||||
var editor = window.tinymce.activeEditor; // 将外部 DOM 内容更新到编辑器
|
||||
const container1 = document.createElement('div');
|
||||
container1.innerHTML = html; // html 是更新后的 HTML 内容
|
||||
editor.setContent(container1.innerHTML); // 更新编辑器内容
|
||||
editor.focus(); // 聚焦到编辑器// 触发编辑器内容变化后,如果需要,可能还要设置编辑器的样式
|
||||
},
|
||||
//销毁富文本
|
||||
destroyTinymce() {
|
||||
if (window.tinymce.get(this.tinymceId)) {
|
||||
window.tinymce.get(this.tinymceId).destroy();
|
||||
}
|
||||
},
|
||||
//设置内容
|
||||
setContent(value) {
|
||||
window.tinymce.get(this.tinymceId).setContent(value);
|
||||
},
|
||||
//获取内容
|
||||
getContent(type) {
|
||||
this.$emit('getContent', type, window.tinymce.get(this.tinymceId).getContent());
|
||||
console.log('window.tinymce.get(this.tinymceId).getContent() at line 431:', window.tinymce.get(this.tinymceId).getContent());
|
||||
},
|
||||
|
||||
async export(type, data) {
|
||||
if (type == 'table') {
|
||||
var tableHtml = `<html xmlns:w="urn:schemas-microsoft-com:office:word">
|
||||
<head>
|
||||
<style>
|
||||
|
||||
${tableStyle}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
${data}
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
const converted = htmlDocx.asBlob(tableHtml, {
|
||||
orientation: this.typesettingTypeOptions[this.typesettingType - 1].orientation,
|
||||
pageSize: {
|
||||
...this.typesettingTypeOptions[this.typesettingType - 1].pageSize
|
||||
},
|
||||
pageMargins: {
|
||||
...this.typesettingTypeOptions[this.typesettingType - 1].pageMargins
|
||||
}
|
||||
});
|
||||
// const converted = htmlDocx.asBlob(tableHtml); // 将 HTML 转换为 Word Blob
|
||||
// 触发文件下载
|
||||
const link = document.createElement('a');
|
||||
link.href = URL.createObjectURL(converted);
|
||||
link.download = 'table.docx';
|
||||
link.click();
|
||||
} else if (type == 'image') {
|
||||
const hiddenContainer = document.createElement('div');
|
||||
hiddenContainer.style.position = 'absolute';
|
||||
hiddenContainer.style.left = '-9999ppx';
|
||||
hiddenContainer.style.top = '0';
|
||||
hiddenContainer.innerHTML = data;
|
||||
const style = document.createElement('style');
|
||||
style.innerHTML = `${tableStyle}`;
|
||||
document.head.appendChild(style);
|
||||
document.body.appendChild(hiddenContainer);
|
||||
// 使用 html2canvas 捕获表格内容
|
||||
const table = hiddenContainer.querySelector('table'); // 找到表格
|
||||
table.style.border = 'none';
|
||||
// 使用 html2canvas 将内容转为图片
|
||||
html2canvas(hiddenContainer, {
|
||||
scale: 2, // 提高图片的分辨率,默认为1,设置为2可以使图片更清晰
|
||||
logging: false, // 禁用日志输出
|
||||
useCORS: true, // 允许跨域图像
|
||||
allowTaint: true // 允许污染 canvas,解决图片链接不可用问题
|
||||
})
|
||||
// 清空现有内容,显示图片
|
||||
.then((canvas) => {
|
||||
const imgData = canvas.toDataURL('image/png'); // 创建一个图片对象
|
||||
const link = document.createElement('a'); // 创建一个链接并下载图片
|
||||
link.href = imgData;
|
||||
link.download = 'image.png';
|
||||
link.click();
|
||||
});
|
||||
}
|
||||
},
|
||||
inlineStyles(element) {
|
||||
const styles = window.getComputedStyle(element);
|
||||
for (let style in styles) {
|
||||
if (styles.hasOwnProperty(style)) {
|
||||
element.style[style] = styles[style];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
//获取上传图片后的地址,并设置图片样式
|
||||
tableSuccessCBK(arr) {
|
||||
console.log(arr, '222');
|
||||
const _this = this;
|
||||
window.tinymce.get(_this.tinymceId).insertContent(arr);
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
this.destroyTinymce();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
::v-deep .tox-tinymce-aux {
|
||||
z-index: 9999 !important;
|
||||
}
|
||||
::v-deep .tox .tox-menu {
|
||||
z-index: 9999 !important;
|
||||
}
|
||||
/* 自定义按钮样式 */
|
||||
.custom-btn {
|
||||
background-color: #28a745 !important;
|
||||
color: #fff !important;
|
||||
border-radius: 4px;
|
||||
padding: 5px 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.custom-btn:hover {
|
||||
background-color: #218838 !important;
|
||||
}
|
||||
</style>
|
||||
@@ -41,10 +41,10 @@ const tableStyle = ` b span{
|
||||
table-layout: auto; /* 自动调整列宽 */
|
||||
text-align:left;
|
||||
font-family:'Charis SIL' !important;
|
||||
font-size: 7.5000pt !important;
|
||||
font-size: 14px !important;
|
||||
mso-font-kerning: 1.0000pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
table td, table th {
|
||||
padding: 5px;
|
||||
@@ -53,10 +53,10 @@ const tableStyle = ` b span{
|
||||
word-wrap: break-word; /* 长单词自动换行 */
|
||||
word-break: break-word;
|
||||
font-family:'Charis SIL' !important;
|
||||
font-size: 7.5000pt !important;
|
||||
font-size: 14px !important;
|
||||
mso-font-kerning: 1.0000pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
table tbody tr td{
|
||||
|
||||
@@ -82,27 +82,27 @@ const tableStyle = ` b span{
|
||||
|
||||
margin:0;
|
||||
font-family:'Charis SIL' !important;
|
||||
font-size: 7.5000pt !important;
|
||||
font-size: 14px !important;
|
||||
mso-font-kerning: 1.0000pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
table span{
|
||||
|
||||
color:#000000;text-align:left !important;
|
||||
font-family:'Charis SIL' !important;
|
||||
font-size: 7.5000pt !important;
|
||||
font-size: 14px !important;
|
||||
mso-font-kerning: 1.0000pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
table .color-highlight{
|
||||
color:rgb(0,130,170) !important;
|
||||
font-family:'Charis SIL' !important;
|
||||
font-size: 7.5000pt !important;
|
||||
font-size: 14px !important;
|
||||
mso-font-kerning: 1.0000pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
table tr:first-child td {
|
||||
border-top:1.0000pt solid #000 !important;mso-border-top-alt:0.5000pt solid #000 !important;border-bottom:1.0000pt solid #000 !important;mso-border-bottom-alt:0.5000pt solid #000 !important;
|
||||
@@ -118,7 +118,18 @@ const tableStyle = ` b span{
|
||||
.wordTableHtml table tr.table-header-row:nth-of-type(2) td {
|
||||
border-bottom: 1px solid #000 !important;
|
||||
}
|
||||
|
||||
mjx-container {
|
||||
font-size: 14px !important;
|
||||
;
|
||||
}
|
||||
wmath{
|
||||
width: 100%;
|
||||
display: block;
|
||||
display: flex;
|
||||
}
|
||||
Info{
|
||||
color:#ff8f25;
|
||||
}
|
||||
`;
|
||||
export default {
|
||||
name: 'tinymce',
|
||||
@@ -148,7 +159,7 @@ export default {
|
||||
height: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 360
|
||||
default: 400
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
@@ -220,9 +231,12 @@ export default {
|
||||
},
|
||||
watch: {
|
||||
value(val) {
|
||||
console.log('val at line 208:', val);
|
||||
// console.log('val at line 208:', val);
|
||||
if (!this.hasChange && this.hasInit) {
|
||||
this.$nextTick(() => window.tinymce.get(this.tinymceId).setContent(val));
|
||||
this.$nextTick(() => {
|
||||
window.tinymce.get(this.tinymceId).setContent(val);
|
||||
// window.renderMathJax(); // 主动触发 MathJax 渲染
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -238,6 +252,10 @@ export default {
|
||||
this.destroyTinymce();
|
||||
},
|
||||
methods: {
|
||||
openLatexEditor(data) {
|
||||
this.$emit('openLatexEditor', data);
|
||||
console.log('at line 254:', '打开数字公式');
|
||||
},
|
||||
handleSubmit() {
|
||||
this.$refs.uploadImage.handleSubmit();
|
||||
},
|
||||
@@ -269,26 +287,25 @@ export default {
|
||||
|
||||
this.$forceUpdate();
|
||||
},
|
||||
|
||||
generateUniqueId() {
|
||||
return 'wmath-' + Math.random().toString(36).substr(2, 9);
|
||||
},
|
||||
initTinymce() {
|
||||
var _this = this;
|
||||
window.tinymce.init({
|
||||
inline: false, // 使用 iframe 模式
|
||||
selector: `#${this.tinymceId}`,
|
||||
// noneditable_regexp: "/<wmath>.*?<\/wmath>/g",
|
||||
content_css: false, // 禁用默认样式
|
||||
table_resize_bars: true, // 启用拖动调整功能
|
||||
valid_elements: this.type == 'table' ? '*[*]' : 'img[src|alt|width|height],strong,em,sub,sup,blue,table,b,i', // 允许的标签和属性
|
||||
valid_elements: this.type == 'table' ? '*[*]' : 'img[src|alt|width|height],strong,em,sub,sup,blue,table,b,i,wmath', // 允许的标签和属性
|
||||
// valid_elements: '*[*]', // 允许所有 HTML 标签
|
||||
|
||||
noneditable_editable_class: 'MathJax',
|
||||
height: this.height,
|
||||
paste_preprocess: function (plugin, args) {
|
||||
let content = args.content;
|
||||
|
||||
// 创建一个临时 div 元素来解析粘贴的 HTML
|
||||
let content = args.content; // 获取粘贴的内容
|
||||
let tempDiv = document.createElement('div');
|
||||
tempDiv.innerHTML = content;
|
||||
|
||||
// 检查粘贴的内容是否包含 <table> 元素
|
||||
if (tempDiv.querySelector('table')) {
|
||||
console.log('粘贴的内容包含表格');
|
||||
if (_this.type == 'table') {
|
||||
@@ -324,27 +341,49 @@ export default {
|
||||
// _this.updateTableStyles(container); // 根据需要应用额外的样式
|
||||
args.content = container.innerHTML; // 更新处理后的内容
|
||||
});
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
if (_this.isAutomaticUpdate) {
|
||||
args.content = _this.$commonJS.transformHtmlString(args.content); // 更新处理后的内容
|
||||
}
|
||||
console.log('粘贴的内容不包含表格');
|
||||
console.log('Original content:', content); // 输出原始粘贴内容
|
||||
|
||||
// 改进的正则表达式,匹配 $$...$$ 格式的 LaTeX 公式
|
||||
const mathRegex = /\$\$([^$]+)\$\$/g;
|
||||
|
||||
// 如果粘贴的内容包含 $$...$$ 格式的公式,进行处理
|
||||
content = content.replace(mathRegex, function (match, formula) {
|
||||
console.log('Matched formula:', formula); // 输出每个匹配的公式
|
||||
// 将公式包裹在 <wmath> 标签中,保留 $$...$$ 结构
|
||||
return `<wmath data-latex="${match}">${match}</wmath>`;
|
||||
});
|
||||
|
||||
console.log('Processed content:', content); // 输出处理后的内容
|
||||
}
|
||||
// 阻止默认的粘贴行为
|
||||
|
||||
// 更新 args.content 为处理后的内容
|
||||
|
||||
// 阻止默认的粘贴行为,确保自定义处理优先执行
|
||||
if (args.event) {
|
||||
args.event.preventDefault(); // 阻止默认的粘贴处理
|
||||
args.event.stopPropagation(); // 阻止事件冒泡,确保自定义处理优先执行
|
||||
args.event.preventDefault();
|
||||
args.event.stopPropagation();
|
||||
}
|
||||
|
||||
if (_this.isAutomaticUpdate) {
|
||||
args.content = _this.$commonJS.transformHtmlString(content); // 更新处理后的内容
|
||||
} else {
|
||||
args.content = content;
|
||||
}
|
||||
setTimeout(() => {
|
||||
window.renderMathJax(_this.tinymceId);
|
||||
}, 10);
|
||||
},
|
||||
|
||||
content_style: `
|
||||
${tableStyle}
|
||||
${_this.wordStyle}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
`,
|
||||
|
||||
formats: {
|
||||
@@ -359,7 +398,7 @@ export default {
|
||||
custom_colors: false,
|
||||
color_map: ['0082AA', 'TMR Blue'],
|
||||
|
||||
plugins: 'texttransform', // 启用 forecolor 和 code 插件
|
||||
plugins: 'texttransform kityformula-editor noneditable', // 启用 forecolor 和 code 插件
|
||||
// plugins: 'forecolor code paste table image mathType searchreplace raw', // 启用 forecolor 和 code 插件
|
||||
end_container_on_empty_block: true,
|
||||
content_css: 'default', // 加载 TinyMCE 默认样式表
|
||||
@@ -372,6 +411,43 @@ export default {
|
||||
setup(ed) {
|
||||
_this.$commonJS.initEditorButton(_this, ed);
|
||||
|
||||
var currentWmathElement = null;
|
||||
|
||||
ed.on('click', function (e) {
|
||||
const wmathElement = e.target.closest('wmath');
|
||||
|
||||
if (wmathElement) {
|
||||
currentWmathElement = wmathElement; // 👈 保存当前点击的元素
|
||||
|
||||
const latexContentRaw = wmathElement.getAttribute('data-latex') || '';
|
||||
console.log('at line 488: raw =', latexContentRaw);
|
||||
|
||||
// 去除所有 $ 符号
|
||||
const latexContent = latexContentRaw.replace(/\$/g, '').trim();
|
||||
console.log('at line 489: cleaned =', latexContent);
|
||||
|
||||
// 编码后用于传递到弹窗
|
||||
const encoded = encodeURIComponent(latexContent);
|
||||
|
||||
// 给 wmath 添加唯一 data-id,方便后续精准替换
|
||||
let wmathId = wmathElement.getAttribute('data-id');
|
||||
if (!wmathId) {
|
||||
wmathId = 'wmath-' + Math.random().toString(36).substr(2, 9);
|
||||
wmathElement.setAttribute('data-id', wmathId);
|
||||
}
|
||||
|
||||
// 当前编辑器 ID 也保存下来(如果你有多个编辑器)
|
||||
const editorId = ed.id;
|
||||
|
||||
// 打开编辑窗口并传参(传递 data-id + 内容)
|
||||
window.open(
|
||||
`/LateX?id=${encoded}&wmathId=${wmathId}&editorId=${editorId}`,
|
||||
'_blank',
|
||||
'width=1000,height=800,scrollbars=no,resizable=no'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
ed.ui.registry.addButton('uploadWord', {
|
||||
text: 'Word',
|
||||
icon: 'import-word', // 使用自定义图标
|
||||
@@ -397,36 +473,23 @@ export default {
|
||||
}
|
||||
});
|
||||
|
||||
// ed.ui.registry.addMenuButton('customDropdown', {
|
||||
// text: _this.$t('commonTable.PaperRotation'), // 下拉框标题
|
||||
// fetch: function (callback) {
|
||||
// // 定义下拉框的内容
|
||||
// const items = [..._this.typesettingTypeOptions];
|
||||
// const menuItems = items.map((item) => ({
|
||||
// type: 'menuitem',
|
||||
// text: item.label,
|
||||
// onAction: function () {
|
||||
// _this.typesettingType = item.value;
|
||||
// _this.changeTable();
|
||||
// // ed.execCommand(item.value); // 执行命令
|
||||
// }
|
||||
// }));
|
||||
// callback(menuItems);
|
||||
// }
|
||||
// });
|
||||
|
||||
ed.on('init', function () {
|
||||
_this.$commonJS.inTinymceButtonClass();
|
||||
const editorBody = ed.getBody();
|
||||
|
||||
// 监听点击事件来确保用户可以删除<wmath>元素
|
||||
|
||||
// 创建 MutationObserver 监听内容变化
|
||||
const observer = new MutationObserver(() => {
|
||||
const currentContent = ed.getContent();
|
||||
// console.log('currentContent at line 447:', currentContent);
|
||||
|
||||
if (_this.isAutomaticUpdate) {
|
||||
|
||||
|
||||
// _this.$emit('updateChange', _this.$commonJS.decodeHtml(currentContent));
|
||||
_this.$emit('updateChange',currentContent);
|
||||
_this.$commonJS.replaceWMathContent(currentContent, (res) => {
|
||||
console.log('res at line 451:', res);
|
||||
_this.$emit('updateChange', res);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -472,6 +535,11 @@ export default {
|
||||
});
|
||||
|
||||
ed.on('SetContent', function (e) {
|
||||
const editorBody = ed.getBody();
|
||||
ed.dom.select('wmath', editorBody).forEach(function (wmathElement) {
|
||||
ed.dom.setAttrib(wmathElement, 'contenteditable', 'false');
|
||||
// ed.dom.addClass(wmathElement, 'non-editable-wmath');
|
||||
});
|
||||
e.content = e.content.replace(/<strong>/g, '<b>').replace(/<\/strong>/g, '</b>');
|
||||
e.content = e.content.replace(/<em>/g, '<i>').replace(/<\/em>/g, '</i>');
|
||||
});
|
||||
@@ -483,14 +551,72 @@ export default {
|
||||
init_instance_callback: (editor) => {
|
||||
if (_this.value) {
|
||||
editor.setContent(_this.value);
|
||||
|
||||
console.log('at line 489:', ' 页面');
|
||||
setTimeout(() => {
|
||||
window.renderMathJax(_this.tinymceId); // 初始化时渲染 MathJax
|
||||
}, 10);
|
||||
}
|
||||
_this.hasInit = true;
|
||||
editor.on('NodeChange Change KeyUp SetContent', () => {
|
||||
this.hasChange = true;
|
||||
this.$emit('input', editor.getContent());
|
||||
|
||||
console.log('at line 518:', '改变');
|
||||
// setTimeout(() => {
|
||||
// window.renderMathJax(); // 初始化时渲染 MathJax
|
||||
// }, 50);
|
||||
});
|
||||
}
|
||||
});
|
||||
if (!window._wmath_listener_registered) {
|
||||
// 💾 新增公式插入点记录
|
||||
let latexEditorBookmark = null;
|
||||
let activeEditorId = null;
|
||||
|
||||
// 👂 message 监听器:处理编辑 + 新增两种情况
|
||||
window.addEventListener('message', function (event) {
|
||||
const data = event.data;
|
||||
console.log('data at line 648:', data);
|
||||
// ✅ 编辑现有公式:替换或删除
|
||||
if (data && data.type === 'update-wmath') {
|
||||
const { editorId, wmathId, latex } = data;
|
||||
const newLatex = latex ? latex.trim() : '';
|
||||
|
||||
if (!editorId || !wmathId) return;
|
||||
const targetEditor = tinymce.get(editorId);
|
||||
if (!targetEditor) return;
|
||||
|
||||
const targetWmath = targetEditor.dom.select(`wmath[data-id="${wmathId}"]`, targetEditor.getBody())[0];
|
||||
|
||||
if (targetWmath) {
|
||||
if (!newLatex) {
|
||||
// ❌ 删除公式
|
||||
targetEditor.dom.remove(targetWmath);
|
||||
} else {
|
||||
// ✅ 更新公式
|
||||
targetWmath.setAttribute('data-latex', newLatex);
|
||||
targetWmath.innerHTML = newLatex;
|
||||
|
||||
setTimeout(() => {
|
||||
if (typeof renderMathJax === 'function') {
|
||||
this.window.renderMathJax(editorId);
|
||||
}
|
||||
}, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 🚩 标记为已注册,防止重复
|
||||
window._wmath_listener_registered = true;
|
||||
|
||||
// 🧠 导出保存位置函数(你可以在按钮点击时调用它)
|
||||
window._recordLatexInsertContext = function (editorInstance) {
|
||||
latexEditorBookmark = editorInstance.selection.getBookmark(2);
|
||||
activeEditorId = editorInstance.id;
|
||||
};
|
||||
}
|
||||
},
|
||||
// 提取 Word 文件中的表格
|
||||
|
||||
@@ -513,16 +639,16 @@ export default {
|
||||
window.tinymce.get(this.tinymceId).setContent(value);
|
||||
},
|
||||
//获取内容
|
||||
async getContent(type) {
|
||||
async getContent(type) {
|
||||
var content = window.tinymce.get(this.tinymceId).getContent();
|
||||
content = content.replace(/<span[^>]*>/g, '').replace(/<\/span>/g, ''); // 去除span标签
|
||||
|
||||
|
||||
console.log('content at line 627:', content);
|
||||
content = content.replace(/<span[^>]*>/g, '').replace(/<\/span>/g, ''); // 去除span标签
|
||||
|
||||
content = content.replace(/<strong>/g, '<b>').replace(/<\/strong>/g, '</b>');
|
||||
content = content.replace(/<em>/g, '<i>').replace(/<\/em>/g, '</i>');
|
||||
content = content.replace(/ /g, ' '); // 将所有 替换为空格
|
||||
this.$emit('getContent', type, content);
|
||||
|
||||
console.log('content at line 632:', content);
|
||||
this.$emit('getContent', type, content);
|
||||
},
|
||||
|
||||
async export(type, data) {
|
||||
|
||||
@@ -58,7 +58,8 @@ export default {
|
||||
watch: {
|
||||
list: {
|
||||
handler(e) {
|
||||
this.fields=[...this.list]
|
||||
|
||||
this.fields=this.list.length>0?[...this.list]:[{}]
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
|
||||
151
src/components/page/components/table/LateX copy.vue
Normal file
151
src/components/page/components/table/LateX copy.vue
Normal file
@@ -0,0 +1,151 @@
|
||||
<template>
|
||||
<div style="position: fixed;top: 0;left: 0;background-color: #f8f8f8; width: 100%; height: 100%; overflow: hidden; background: linear-gradient(to top, #fbfffe, #ebf9ff);">
|
||||
<div class="navbar-default">
|
||||
<div class="nav commonWidth" style="height: 100%">
|
||||
<div class="title">Digital Formula Editor</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="commonWidth" style="padding:40px 20px; box-sizing: border-box;">
|
||||
<!-- <div style="margin-bottom: 20px;font-size: 20px;">Numerical formula:</div> -->
|
||||
<div style="display: flex;align-items: center;justify-content: space-between;">
|
||||
<div ref="mathField" class="math-container" style="width: calc(100% - 100px);"></div>
|
||||
<span @click="copyLatex" style="font-size: 20px;width: 80px;cursor: pointer;">📋 Copy </span>
|
||||
</div>
|
||||
|
||||
<!-- 公式显示框 -->
|
||||
<div class="formula-box" :style="{ opacity: showLatex ? 1 : 0 }">
|
||||
<p>LaTeX 代码:</p>
|
||||
<textarea ref="latexBox" class="latex-text" readonly>$${{ latex }}$$</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { MathfieldElement } from 'mathlive';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
latex: '', // 默认公式
|
||||
// latex: '\\frac{a}{b} + \\sqrt{x^2 + y^2} + e^{i\\pi}', // 默认公式
|
||||
mathFieldInstance: null,
|
||||
showLatex: false, // 控制 LaTeX 代码框的显示与隐藏
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
if (this.$refs.mathField) {
|
||||
// 创建 MathfieldElement 组件
|
||||
const mf = new MathfieldElement();
|
||||
mf.style.width = '100%';
|
||||
mf.virtualKeyboardMode = 'manual'; // 显示虚拟键盘
|
||||
mf.value = this.latex; // 设置默认值
|
||||
|
||||
// 监听输入变化,更新 LaTeX 代码
|
||||
mf.addEventListener('input', (event) => {
|
||||
this.latex = event.target.value;
|
||||
});
|
||||
|
||||
// 挂载到 DOM
|
||||
this.$refs.mathField.appendChild(mf);
|
||||
this.mathFieldInstance = mf;
|
||||
|
||||
// 强制显示虚拟键盘并保持显示
|
||||
mf.executeCommand('showVirtualKeyboard');
|
||||
|
||||
// 保证虚拟键盘持续显示
|
||||
this.keepKeyboardVisible(mf);
|
||||
} else {
|
||||
console.error('MathLive 未正确加载');
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
keepKeyboardVisible(mf) {
|
||||
// 每秒确保虚拟键盘显示
|
||||
setInterval(() => {
|
||||
mf.executeCommand('showVirtualKeyboard');
|
||||
}, 20); // 每秒确保键盘显示
|
||||
},
|
||||
copyLatex() {
|
||||
if (this.$refs.latexBox) {
|
||||
this.$refs.latexBox.select(); // 选中文本
|
||||
document.execCommand('copy'); // 复制到剪贴板
|
||||
setTimeout(( )=>{
|
||||
window.close();
|
||||
},100)
|
||||
|
||||
}
|
||||
},
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.mathFieldInstance = null; // 组件销毁时清除实例
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.commonWidth {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.title {
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
line-height: 80px;
|
||||
background-color: #0f4eb6;
|
||||
color: #fff;
|
||||
}
|
||||
.navbar-default {
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
background-color: #0f4eb6;
|
||||
border-color: #e7e7e7;
|
||||
}
|
||||
.math-container {
|
||||
min-height: 40px;
|
||||
border: 1px solid #ccc;
|
||||
padding: 5px;
|
||||
font-size: 18px;
|
||||
/* margin-bottom: 20px; */
|
||||
}
|
||||
|
||||
/* 公式弹出框样式 */
|
||||
.formula-box {
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #f9f9f9;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
/* LaTeX 代码框 */
|
||||
.latex-text {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
font-size: 16px;
|
||||
border: 1px solid #ccc;
|
||||
padding: 5px;
|
||||
margin-bottom: 10px;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
/* 复制按钮 */
|
||||
button {
|
||||
padding: 5px 10px;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
|
||||
/* 防止虚拟键盘覆盖 */
|
||||
::v-deep .ML__virtual-keyboard-toggle {
|
||||
opacity: 1 !important; /* 确保虚拟键盘的按钮可见 */
|
||||
}
|
||||
</style>
|
||||
335
src/components/page/components/table/LateX.vue
Normal file
335
src/components/page/components/table/LateX.vue
Normal file
@@ -0,0 +1,335 @@
|
||||
<template>
|
||||
<div
|
||||
style="
|
||||
background-color: #f8f8f8;
|
||||
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
background: linear-gradient(to top, #fbfffe, #ebf9ff);
|
||||
z-index: 9999;
|
||||
border-radius: 10px 10px 0 0;
|
||||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
|
||||
"
|
||||
>
|
||||
<div class="navbar-default" style="padding: 10px">
|
||||
<div class="nav commonWidth" style="height: 100%">
|
||||
<div class="title" style="padding: 0 0px; box-sizing: border-box">
|
||||
<img src="@/assets/img/logo.png" style="width: 30px; height: 20px; margin-right: 10px" />
|
||||
Digital Formula Editor
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height: calc(100vh - 50px); overflow: hidden; padding-top: 20px; box-sizing: border-box">
|
||||
<div
|
||||
class="commonWidth"
|
||||
style="width: calc(100% - 380px); height: 100%; padding-left: 20px; box-sizing: border-box; float: left"
|
||||
>
|
||||
<p style="padding: 10px 0; color: rgb(51, 51, 51); box-sizing: border-box">Numerical formula:</p>
|
||||
<div ref="mathField" class="math-container" style="width: calc(100%)"></div>
|
||||
|
||||
<!-- 公式显示框 -->
|
||||
<div class="formula-box" style="position: relative; margin-top: 20px">
|
||||
<p style="padding: 10px 0; color: rgb(51, 51, 51); box-sizing: border-box">LaTeX Code:</p>
|
||||
<div style="position: absolute; right: 10px; top: 45px">
|
||||
<span @click="copyLatex" style="font-size: 16px; cursor: pointer; opacity: 0.6" disabled v-if="!this.latex"
|
||||
>📋 Copy
|
||||
</span>
|
||||
<span @click="copyLatex" style="font-size: 16px; cursor: pointer; opacity: 1" v-else>📋 Copy </span>
|
||||
<span style="margin: 0 10px; cursor: pointer">|</span>
|
||||
<span style="color: red; cursor: pointer" @click="handleClear"
|
||||
><i class="el-icon-delete-solid" style="color: red; margin-right: 4px"></i>Clear</span
|
||||
>
|
||||
</div>
|
||||
<textarea ref="latexBox1" class="latexBox1" v-model="latex" @input="changeLatex"></textarea>
|
||||
<textarea ref="latexBox" class="latex-text" readonly :style="{ opacity: showLatex ? 1 : 0 }" style="height: 0">
|
||||
$${{ latex }}$$</textarea
|
||||
>
|
||||
</div>
|
||||
<div style="margin-top: 10px; overflow: hidden">
|
||||
<el-button type="primary" @click="SaveyLatex" style="background-color: #1654f7 !important; float: right"
|
||||
>Submit</el-button
|
||||
>
|
||||
<el-button @click="handleCancel" style="float: right; margin-right: 10px">Cancel</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-default">
|
||||
<p style="padding: 10px; color: #333; box-sizing: border-box">Formula Template</p>
|
||||
<div class="panel-heading">
|
||||
<div v-for="(item, index) in list" @click="changeSelectLateX(item, index)">
|
||||
<p :class="currentSelect == index ? 'isSelect' : ''">
|
||||
<span style="font-size: 12px; display: block; font-weight: bold">{{ item.titleEn }}</span>
|
||||
<span style="font-size: 13px; display: block; font-weight: bold">{{ item.title }}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="math-only"
|
||||
v-for="(item, index) in list"
|
||||
v-show="currentSelect == index"
|
||||
style="height: calc(100% - 200px); overflow-y: auto"
|
||||
>
|
||||
<div
|
||||
style="overflow-x: auto; overflow-y: hidden"
|
||||
v-for="(v, i) in item.data"
|
||||
:key="i"
|
||||
class="math-block"
|
||||
v-html="`$$${v}$$`"
|
||||
@click="handleClick(v)"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { MathfieldElement } from 'mathlive';
|
||||
import formulaTemplates from './formulas.js';
|
||||
export default {
|
||||
props: ['LateXInfo'],
|
||||
data() {
|
||||
return {
|
||||
currentSelect: 0,
|
||||
list: formulaTemplates,
|
||||
latex: '', // 默认公式
|
||||
mathFieldInstance: null,
|
||||
showLatex: false // 控制 LaTeX 代码框的显示与隐藏
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
// 获取并初始化公式
|
||||
if (this.$route.query.id) {
|
||||
this.latex = this.$route.query.id;
|
||||
}
|
||||
if (this.$refs.mathField) {
|
||||
const mf = new MathfieldElement();
|
||||
mf.style.width = '100%';
|
||||
mf.style.height = '100%';
|
||||
mf.virtualKeyboardMode = 'manual'; // 显示虚拟键盘
|
||||
mf.value = this.latex;
|
||||
|
||||
// 监听输入变化,更新 LaTeX 代码
|
||||
mf.addEventListener('input', (event) => {
|
||||
this.latex = event.target.value;
|
||||
});
|
||||
|
||||
this.$refs.mathField.appendChild(mf);
|
||||
this.mathFieldInstance = mf;
|
||||
// mf.executeCommand('showVirtualKeyboard');
|
||||
// this.keepKeyboardVisible(mf);
|
||||
} else {
|
||||
console.error('MathLive 未正确加载');
|
||||
}
|
||||
this.renderMathInScope(); // 首次挂载后也渲染
|
||||
},
|
||||
methods: {
|
||||
handleClick(value) {
|
||||
console.log('value at line 115:', this.mathFieldInstance);
|
||||
|
||||
if (this.$refs.mathField) {
|
||||
this.mathFieldInstance.value = value;
|
||||
}
|
||||
this.latex = value;
|
||||
this.$forceUpdate();
|
||||
},
|
||||
changeLatex() {
|
||||
if (this.$refs.mathField) {
|
||||
this.mathFieldInstance.value = this.latex;
|
||||
}
|
||||
},
|
||||
changeSelectLateX(item, index) {
|
||||
this.currentSelect = index;
|
||||
this.renderMathInScope();
|
||||
// this.mathFieldInstance.value = this.latex;
|
||||
},
|
||||
escapeLaTeX(input) {
|
||||
// 将所有单斜线 \ 替换为双斜线 \\
|
||||
return input.replace(/\\/g, '\\\\');
|
||||
},
|
||||
|
||||
renderMathInScope() {
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
const el = document.querySelector('.math-only');
|
||||
console.log('el at line 121:', el);
|
||||
if (window.MathJax && el) {
|
||||
// MathJax.typesetClear([el]); // 清除旧渲染
|
||||
window.MathJax.typesetPromise([el]).catch((err) => {
|
||||
console.warn('MathJax 渲染失败:', err);
|
||||
});
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
},
|
||||
// keepKeyboardVisible(mf) {
|
||||
// setInterval(() => {
|
||||
// mf.executeCommand('showVirtualKeyboard');
|
||||
// }, 50); // 每秒确保键盘显示
|
||||
// },
|
||||
copyLatex() {
|
||||
if (this.latex == '') {
|
||||
return;
|
||||
}
|
||||
if (this.$refs.latexBox) {
|
||||
this.$refs.latexBox.select(); // 选中文本
|
||||
document.execCommand('copy'); // 复制到剪贴板
|
||||
this.$message({
|
||||
message: 'Replicating Success',
|
||||
type: 'success'
|
||||
});
|
||||
}
|
||||
},
|
||||
handleClear() {
|
||||
this.latex = '';
|
||||
this.mathFieldInstance.value = '';
|
||||
this.$forceUpdate();
|
||||
},
|
||||
handleCancel() {
|
||||
this.$emit('close');
|
||||
},
|
||||
SaveyLatex() {
|
||||
const wmathId = this.$route.query.wmathId;
|
||||
const editorId = this.$route.query.editorId;
|
||||
// this.$emit('save', {
|
||||
// latex: this.latex && this.latex != '' ? `$$${this.latex}$$` : '',
|
||||
// editorId: this.LateXInfo.editorId,
|
||||
// wmathId: this.LateXInfo.wmathId
|
||||
// });
|
||||
|
||||
window.opener.postMessage(
|
||||
{
|
||||
type: 'update-wmath',
|
||||
latex: this.latex && this.latex != '' ? `$$${this.latex}$$` : '',
|
||||
editorId: editorId,
|
||||
wmathId: wmathId
|
||||
},
|
||||
'*'
|
||||
);
|
||||
|
||||
setTimeout(() => {
|
||||
window.close();
|
||||
// this.$emit('close');
|
||||
}, 100);
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.mathFieldInstance = null; // 组件销毁时清除实例
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.commonWidth {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
line-height: 30px;
|
||||
background-color: #0f4eb6;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.navbar-default {
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
background-color: #0f4eb6;
|
||||
border-color: #e7e7e7;
|
||||
}
|
||||
|
||||
.math-container {
|
||||
height: 200px;
|
||||
/* padding: 5px; */
|
||||
font-size: 18px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.formula-box {
|
||||
/* margin-top: 10px;
|
||||
padding: 10px;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #f9f9f9;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start; */
|
||||
}
|
||||
|
||||
.latex-text {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
font-size: 16px;
|
||||
padding: 5px;
|
||||
margin-bottom: 10px;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
::v-deep .ML__virtual-keyboard-toggle {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
li {
|
||||
line-height: none;
|
||||
}
|
||||
.panel-default {
|
||||
width: 360px;
|
||||
height: 100%;
|
||||
float: right;
|
||||
border: 1px solid #ddd;
|
||||
background-color: #fff;
|
||||
}
|
||||
.panel-heading {
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
background-color: #f5f5f5;
|
||||
border-color: #ddd;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.panel-heading div {
|
||||
width: 25%;
|
||||
padding: 5px 0px;
|
||||
line-height: 20px;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.isSelect {
|
||||
color: white !important;
|
||||
background: #333;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.math-block {
|
||||
background-color: #fff;
|
||||
cursor: pointer;
|
||||
background: #f0f0f0;
|
||||
color: #000;
|
||||
display: block;
|
||||
margin: 10px;
|
||||
padding: 6px;
|
||||
|
||||
/* min-height: 40px !important; */
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
::v-deep .math-block mjx-container {
|
||||
font-size: 18px !important;
|
||||
margin: 0 !important;
|
||||
text-align: left !important;
|
||||
}
|
||||
|
||||
.latexBox1 {
|
||||
width: 100%;
|
||||
padding: 10px 140px 10px 10px;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #f9f9f9;
|
||||
font-size: 18px;
|
||||
resize: none;
|
||||
height: 200px;
|
||||
}
|
||||
</style>
|
||||
@@ -11,18 +11,19 @@
|
||||
:wordStyle="wordStyle"
|
||||
:isAutomaticUpdate="isAutomaticUpdate"
|
||||
@getContent="getContent"
|
||||
@openLatexEditor="openLatexEditor"
|
||||
@updateChange="updateChange"
|
||||
:value="value"
|
||||
:typesettingType="typesettingType"
|
||||
class="paste-area text-container"
|
||||
:toolbar="['bold italic|customBlue removeBlue|myuppercase myuppercasea Line|subscript superscript|searchreplace|clearButton']"
|
||||
:toolbar="`['bold italic|customBlue removeBlue|${!isAutomaticUpdate?'LateX|':''} myuppercase myuppercasea Line|subscript superscript|clearButton|searchreplace']`"
|
||||
style="
|
||||
/* white-space: pre-line; */
|
||||
line-height: 12px;
|
||||
max-height: 60vh;
|
||||
overflow: auto;
|
||||
font-size: 12px;
|
||||
font-size: 7.5pt; /* 字体大小 */
|
||||
font-size: 14px; /* 字体大小 */
|
||||
|
||||
margin-top: 0pt; /* 段前间距 */
|
||||
margin-bottom: 0pt; /* 段后间距 */
|
||||
@@ -73,6 +74,10 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openLatexEditor(data) {
|
||||
this.$emit('openLatexEditor',data)
|
||||
console.log('at line 254:', '打开数字公式');
|
||||
},
|
||||
updateChange(content){
|
||||
this.$emit('updateChange',content)
|
||||
},
|
||||
|
||||
@@ -92,10 +92,10 @@ b span{
|
||||
table-layout: auto; /* 自动调整列宽 */
|
||||
text-align:left;
|
||||
font-family:'Charis SIL' !important;
|
||||
font-size: 7.5000pt !important;
|
||||
font-size: 14px !important;
|
||||
mso-font-kerning: 1.0000pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
table td, table th {
|
||||
padding: 5px;
|
||||
@@ -104,10 +104,10 @@ b span{
|
||||
word-wrap: nomarl; /* 长单词自动换行 */
|
||||
word-break: nomarl;
|
||||
font-family:'Charis SIL' !important;
|
||||
font-size: 7.5000pt !important;
|
||||
font-size: 14px !important;
|
||||
mso-font-kerning: 1.0000pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
table tbody tr td{
|
||||
|
||||
@@ -134,27 +134,27 @@ b span{
|
||||
|
||||
margin:0;
|
||||
font-family:'Charis SIL' !important;
|
||||
font-size: 7.5000pt !important;
|
||||
font-size: 14px !important;
|
||||
mso-font-kerning: 1.0000pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
table span{
|
||||
|
||||
color:#000000;text-align:left !important;
|
||||
font-family:'Charis SIL' !important;
|
||||
font-size: 7.5000pt !important;
|
||||
font-size: 14px !important;
|
||||
mso-font-kerning: 1.0000pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
table .color-highlight{
|
||||
color:rgb(0,130,170) !important;
|
||||
font-family:'Charis SIL' !important;
|
||||
font-size: 7.5000pt !important;
|
||||
font-size: 14px !important;
|
||||
mso-font-kerning: 1.0000pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
table tr:first-child td {
|
||||
border-top:1.0000pt solid #000 !important;mso-border-top-alt:0.5000pt solid #000 !important;border-bottom:1.0000pt solid #000 !important;mso-border-bottom-alt:0.5000pt solid #000 !important;
|
||||
|
||||
168
src/components/page/components/table/formulas.js
Normal file
168
src/components/page/components/table/formulas.js
Normal file
@@ -0,0 +1,168 @@
|
||||
|
||||
|
||||
const algebraFormulas = [
|
||||
'\\left(x - 1\\right)\\left(x + 3\\right)', '\\sqrt{a^2 + b^2}',
|
||||
'\\frac{a}{b}',
|
||||
'x = \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}',
|
||||
'(a + b)^2 = a^2 + 2ab + b^2',
|
||||
'a^n \\cdot a^m = a^{n + m}',
|
||||
'a^0 = 1',
|
||||
'\\left(a + b + c\\right)^2',
|
||||
'\\left ( \\frac{a}{b}\\right )^{n}=\\frac{a^{n}}{b^{n}}',
|
||||
'\\frac{a}{b}\\pm \\frac{c}{d}=\\frac{ad \\pm bc}{bd}',
|
||||
'\\frac{1}{\\sqrt{a}}=\\frac{\\sqrt{a}}{a},a\\ge 0\\frac{1}{\\sqrt{a}}=\\frac{\\sqrt{a}}{a},a\\ge 0',
|
||||
'\\sqrt[n]{a^{n}}=\\left ( \\sqrt[n]{a}\\right )^{n}',
|
||||
'a\\geqslant 0,b\\geqslant 0 \\sqrt[n]{\\frac{a}{b}}=\\frac{\\sqrt[n]{a}}{\\sqrt[n]{a}}',
|
||||
'x=a_0+\\frac{1}{\\displaystyle a_1+\\frac{1}{ \\displaystyle a_2+\\frac{ 1}{ \\displaystyle a_3+ a_4}}}',
|
||||
|
||||
];
|
||||
//数列
|
||||
const sequenceFormulas = [
|
||||
'a_{n}=a_{1}q^{n-1}',
|
||||
'S_{n}=\\frac{n \\left( a_{1}+a\\_{n}\\right)}{2}',
|
||||
'S_{n}=na_{1}+\\frac{n \\left( n-1 \\right)}{{2}}d',
|
||||
'a_{n}=a_{1}+\\left( n-1 \\left) d\\right. \\right.',
|
||||
];
|
||||
//矩阵
|
||||
const matrixFormulas = [
|
||||
`A=A^{T}\\
|
||||
A=-A^{T}`
|
||||
];
|
||||
const otherFormulas = [
|
||||
'\\bigcup_{i=1}^{n}{X_i}',
|
||||
'\\bigcap_{i=1}^{n}{X_i}',
|
||||
];
|
||||
|
||||
const geometryFormulas = [
|
||||
'\\overrightarrow{AB}',
|
||||
'\\overleftrightarrow{AB}',
|
||||
'\\widehat{AB}',
|
||||
'\\Delta A B C',
|
||||
'l \\perp \\beta,l \\subset \\alpha \\Rightarrow \\alpha \\perp \\beta',
|
||||
'P \\in \\alpha,P \\in \\beta,\\alpha \\cap \\beta=l \\Rightarrow P \\in l',
|
||||
'\\alpha \\perp \\beta,\\alpha \\cap \\beta=l,a \\subset \\alpha,a \\perp l \\Rightarrow a \\perp \\beta',
|
||||
'A \\in l,B \\in l,A \\in \\alpha,B \\in \\alpha \\Rightarrow l \\subset \\alpha',
|
||||
'\\alpha \\parallel \\beta,\\gamma \\cap \\alpha=a,\\gamma \\cap \\beta=b \\Rightarrow a \\parallel b',
|
||||
'A \\in l,B \\in l,A \\in \\alpha,B \\in \\alpha \\Rightarrow l \\subset \\alpha',
|
||||
|
||||
|
||||
'A = \\pi r^2',
|
||||
'C = 2\\pi r',
|
||||
'a^2 + b^2 = c^2',
|
||||
'\\angle ABC = 90^\\circ',
|
||||
'\\triangle ABC \\cong \\triangle DEF',
|
||||
'V = \\frac{4}{3}\\pi r^3',
|
||||
'P = 4a',
|
||||
'S = \\frac{1}{2}ab\\sin C'
|
||||
];
|
||||
|
||||
const inequalityFormulas = [
|
||||
'a > b',
|
||||
'x \\leq y',
|
||||
'|x| < 1',
|
||||
'\\left|x + y\\right| \\leq \\left|x\\right| + \\left|y\\right|',
|
||||
'\\forall x > 0,\\; x^2 > 0',
|
||||
'\\exists x \\in \\mathbb{R},\\; x < 0',
|
||||
'a^2 + b^2 \\geq 2ab'
|
||||
];
|
||||
|
||||
const equationFormulas = [
|
||||
'y = mx + b',
|
||||
'x^2 - 4 = 0',
|
||||
'x^2 + y^2 = 1',
|
||||
'e^x = \\sum_{n=0}^{\\infty} \\frac{x^n}{n!}',
|
||||
'\\log_b xy = \\log_b x + \\log_b y',
|
||||
'x = \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}',
|
||||
'a_n = a_1 + (n-1)d',
|
||||
`a\\mathop{{x}}\\nolimits^{{2}}+bx+c=0\\
|
||||
\\Delta=\\mathop{{b}}\\nolimits^{{2}}-4ac\\
|
||||
\\mathop{{x}}\\nolimits_{{1,2}}=\\frac{{-b \\pm \\sqrt{{\\mathop{{b}}\\nolimits^{{2}}-4ac}}}}{{2a}}\\
|
||||
\\mathop{{x}}\\nolimits_{{1}}+\\mathop{{x}}\\nolimits_{{2}}=-\\frac{{b}}{{a}}\\
|
||||
\\mathop{{x}}\\nolimits_{{1}}\\mathop{{x}}\\nolimits_{{2}}=\\frac{{c}}{{a}}`,
|
||||
|
||||
`\\frac{x^{2}}{a^{2}}-\\frac{y^{2}}{b^{2}}=1`,
|
||||
`y=kx+b`,
|
||||
`y-y_{1}=k \\left( x-x_{1}\\right)`,
|
||||
|
||||
];
|
||||
|
||||
const trigonometryFormulas = [
|
||||
'\\cos^{-1}\\theta',
|
||||
'\\sin^{-1}\\theta',
|
||||
'e^{i \\theta}',
|
||||
'\\text{sin}^{2}\\frac{\\alpha}{2}=\\frac{1- \\text{cos}\\alpha}{2}',
|
||||
'\\text{sin}^{2}\\frac{\\alpha}{2}=\\frac{1- \\text{cos}\\alpha}{2}',
|
||||
'\\text{cos}^{2}\\frac{\\alpha}{2}=\\frac{1+\\text{cos}\\alpha}{2}',
|
||||
'\\text{tan}\\frac{\\alpha}{2}=\\frac{\\text{sin}\\alpha}{1+\\text{cos}\\alpha}',
|
||||
'\\sin^2\\theta + \\cos^2\\theta = 1',
|
||||
'\\tan\\theta = \\frac{\\sin\\theta}{\\cos\\theta}',
|
||||
'\\sin(2\\theta) = 2\\sin\\theta\\cos\\theta',
|
||||
'\\cos(2\\theta) = \\cos^2\\theta - \\sin^2\\theta',
|
||||
'\\cot\\theta = \\frac{1}{\\tan\\theta}',
|
||||
'\\sec\\theta = \\frac{1}{\\cos\\theta}'
|
||||
];
|
||||
|
||||
const calculusFormulas = [
|
||||
'\\frac{dy}{dx}',
|
||||
'\\int x^2 \\, dx',
|
||||
'\\int_a^b f(x) \\, dx',
|
||||
'\\lim_{x \\to 0} \\frac{\\sin x}{x} = 1',
|
||||
'\\sum_{n=1}^{\\infty} \\frac{1}{n^2} = \\frac{\\pi^2}{6}',
|
||||
'f\'(x) = \\lim_{h \\to 0} \\frac{f(x+h)-f(x)}{h}',
|
||||
'e^x = \\sum_{n=0}^{\\infty} \\frac{x^n}{n!}'
|
||||
];
|
||||
|
||||
const statisticsFormulas = [
|
||||
'\\mu = \\frac{1}{n} \\sum_{i=1}^{n} x_i',
|
||||
'\\sigma = \\sqrt{\\frac{1}{n} \\sum_{i=1}^{n} (x_i - \\mu)^2}',
|
||||
'E(X) = \\sum x \\cdot P(x)',
|
||||
'P(A \\cap B) = P(A)P(B \\mid A)',
|
||||
'\\binom{n}{r} = \\frac{n!}{r!(n-r)!}',
|
||||
'P(A \\cup B) = P(A) + P(B) - P(A \\cap B)'
|
||||
];
|
||||
|
||||
const physicsFormulas = [
|
||||
'\\vec{F}=m\\vec{a}',
|
||||
'e=m c^2',
|
||||
'\\vec{F}=m \\frac{d \\vec{v}}{dt}+\\vec{v}\\frac{dm}{dt}',
|
||||
'\\oint \\vec{F}\\cdot d\\vec{s}=0',
|
||||
'\\vec{F}_g=-F\\frac{m_1 m_2}{r^2}\\vec{e}_r',
|
||||
'\\psi (t)=\\hat{\\psi}e^{i(\\omega t\\,\\pm\,\\theta)}',
|
||||
'\\sum_i \\hat{\\psi_i}cos(\\alpha_i \\pm \\omega t)',
|
||||
'E = mc^2',
|
||||
'F = ma',
|
||||
'v = u + at',
|
||||
's = ut + \\frac{1}{2}at^2',
|
||||
'V = IR',
|
||||
'P = \\frac{W}{t}'
|
||||
];
|
||||
|
||||
const chemistryFormulas = [
|
||||
'_{10}^{5}C^{16}',
|
||||
'2H_2+O_2 \\xrightarrow{n,m}2H_2O',
|
||||
'A\\underset{b}{\\overset{a}{\\longleftrightarrow}}B',
|
||||
'A\\underset{0}{\\overset{a}{\\rightleftarrows}}B',
|
||||
'A\\underset{0^{\\circ}C}{\\overset{100^{\\circ}C}{\\rightleftarrows}}B',
|
||||
'\\ce{H2 + O2 -> H2O}',
|
||||
'\\ce{CO2 + H2O <=> H2CO3}',
|
||||
'\\ce{Na+ + Cl- -> NaCl}',
|
||||
'PV = nRT'
|
||||
];
|
||||
|
||||
const formulaTemplates = [
|
||||
{ title: '代数', data: algebraFormulas, titleEn: 'Algebra' },
|
||||
{ title: '几何', data: geometryFormulas, titleEn: 'Geometry' },
|
||||
{ title: '不等式', data: inequalityFormulas, titleEn: 'Inequalities' },
|
||||
{ title: '方程', data: equationFormulas, titleEn: 'Equations' },
|
||||
{ title: '数列', data: sequenceFormulas, titleEn: 'Sequences' },
|
||||
{ title: '矩阵', data: matrixFormulas, titleEn: 'Matrices' },
|
||||
{ title: '统计学', data: statisticsFormulas, titleEn: 'Statistics' },
|
||||
{ title: '三角', data: trigonometryFormulas, titleEn: 'Trigonometry' },
|
||||
{ title: '物理', data: physicsFormulas, titleEn: 'Physics' },
|
||||
{ title: '化学', data: chemistryFormulas, titleEn: 'Chemistry' },
|
||||
{ title: '微积分', data: calculusFormulas, titleEn: 'Calculus' },
|
||||
{ title: '其他', data: otherFormulas, titleEn: 'Others' },
|
||||
];
|
||||
|
||||
|
||||
export default formulaTemplates;
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<div>
|
||||
|
||||
<!--uploadWord |customButtonExportWord |customButtonExportImg -->
|
||||
|
||||
<tinymce
|
||||
@@ -8,23 +8,25 @@
|
||||
ref="tinymceChild1"
|
||||
:wordStyle="wordStyle"
|
||||
@getContent="getContent"
|
||||
@openLatexEditor="openLatexEditor"
|
||||
:height="calcDynamicWidth()"
|
||||
:value="updatedHtml"
|
||||
:typesettingType="typesettingType"
|
||||
class="paste-area text-container"
|
||||
:toolbar="['bold italic|customBlue removeBlue|myuppercase myuppercasea Line|subscript superscript|table tabledelete| searchreplace |clearButton']"
|
||||
:toolbar="['bold italic|customBlue removeBlue|kityformula-editor|LateX |myuppercase myuppercasea Line|subscript superscript|table tabledelete| searchreplace |clearButton']"
|
||||
style="
|
||||
/* white-space: pre-line; */
|
||||
line-height: 12px;
|
||||
max-height: 60vh;
|
||||
/* max-height: 60vh; */
|
||||
overflow: auto;
|
||||
font-size: 12px;
|
||||
font-size: 7.5pt; /* 字体大小 */
|
||||
font-size: 14px; /* 字体大小 */
|
||||
|
||||
margin-top: 0pt; /* 段前间距 */
|
||||
margin-bottom: 0pt; /* 段后间距 */
|
||||
"
|
||||
></tinymce>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -100,6 +102,15 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openLatexEditor(data) {
|
||||
this.$emit('openLatexEditor',data)
|
||||
console.log('at line 254:', '打开数字公式');
|
||||
},
|
||||
calcDynamicWidth() {
|
||||
const parentWidth = window.innerHeight; // 获取窗口宽度
|
||||
const result = parentWidth - 420; // 计算 `100% - 200px`
|
||||
return result ;
|
||||
},
|
||||
isHeaderRow(rowIndex,table) {
|
||||
|
||||
|
||||
@@ -113,11 +124,12 @@ export default {
|
||||
},
|
||||
getContent(type, content) {
|
||||
if (content) {
|
||||
console.log('content at line 121:', content)
|
||||
const container = document.createElement('div');
|
||||
container.innerHTML = content;
|
||||
this.$commonJS.parseTableToArray(content, (table) => {
|
||||
console.log('res at line 104:', table);
|
||||
|
||||
// return false
|
||||
this.$emit('getContent', type, { html_data: content, table: table });
|
||||
});
|
||||
} else {
|
||||
|
||||
2000
src/components/page/components/table/word copy.vue
Normal file
2000
src/components/page/components/table/word copy.vue
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,9 @@
|
||||
<template>
|
||||
<div class="tinymce-container editor-container word-container" :style="!isPreview ? 'padding:10px 20px 10px 10px;' : 'padding:0px;'" ref="scrollDiv">
|
||||
<div
|
||||
class="tinymce-container editor-container word-container"
|
||||
:style="!isPreview ? 'padding:10px 20px 10px 30px;' : 'padding:0px;'"
|
||||
ref="scrollDiv"
|
||||
>
|
||||
<div
|
||||
style="
|
||||
box-shadow: 0 2px 2px -2px rgba(34, 47, 62, 0.1), 0 8px 8px -4px rgba(34, 47, 62, 0.07);
|
||||
@@ -9,10 +13,101 @@
|
||||
"
|
||||
>
|
||||
<div
|
||||
class=""
|
||||
:style="isPreview ? 'width: 100%;padding: 20px;' : 'width: calc(100% - 300px);padding: 20px 20px 20px 34px;'"
|
||||
v-if="!isPreview"
|
||||
style="
|
||||
border-bottom: 2px solid #c7cdcf;
|
||||
background-color: #fff;
|
||||
position: fixed;
|
||||
top: 60px;
|
||||
left: 285px;
|
||||
z-index: 10;
|
||||
right: 330px;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
width: calc(100% - 285px - 330px);
|
||||
"
|
||||
>
|
||||
<div style="width: auto; display: flex; align-items: center">
|
||||
<!-- <el-checkbox v-model="checked" style="border-right: 1px solid #d8d8d8; padding: 0 20px 0 0;z-index: 10;" size="medium">Select All</el-checkbox> -->
|
||||
<div
|
||||
style="border-right: 1px solid #d8d8d8; padding: 0 20px"
|
||||
:style="currentData.type == 0 ? 'Opacity:1' : 'Opacity:0.6'"
|
||||
>
|
||||
<ul class="HTitleBox">
|
||||
<li
|
||||
:style="currentData.is_h1 == 1 ? 'color:#4d99f1' : 'color:#333'"
|
||||
@click="currentData.is_h1 == 0 ? changeTitle(1) : changeTitle(0)"
|
||||
>
|
||||
H1
|
||||
</li>
|
||||
<li
|
||||
:style="currentData.is_h2 == 1 ? 'color:#4d99f1' : 'color:#333'"
|
||||
@click="currentData.is_h2 == 0 ? changeTitle(2) : changeTitle(0)"
|
||||
>
|
||||
H2
|
||||
</li>
|
||||
<li
|
||||
:style="currentData.is_h3 == 1 ? 'color:#4d99f1' : 'color:#333'"
|
||||
@click="currentData.is_h3 == 0 ? changeTitle(3) : changeTitle(0)"
|
||||
>
|
||||
H3
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div style="border-right: 1px solid #d8d8d8; padding: 0 20px">
|
||||
<ul class="HTitleBox" style="border: none">
|
||||
<li @click="addContent" style="font-size: 14px; padding: 0">
|
||||
<i class="el-icon-document"> </i>
|
||||
Batch Add content
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="border-left: 1px solid #d8d8d8; padding: 0 20px; float: right">
|
||||
<ul class="operateBox">
|
||||
<li
|
||||
v-if="isEditComment"
|
||||
style="height: 40px; background-color: #fff !important; color: #f56c6c; border: 1px solid #f56c6c"
|
||||
@mousedown="cacheSelection"
|
||||
@click="handleSelection"
|
||||
>
|
||||
<i class="el-icon-document-add" style="margin-top: 2px"></i>
|
||||
|
||||
Comment
|
||||
</li>
|
||||
<li
|
||||
style="height: 40px; background-color: #cbccd1 !important; color: #333; border: 1px solid #cbccd1"
|
||||
@click="onAddRow"
|
||||
>
|
||||
<i class="el-icon-document-add" style="margin-top: 2px"></i>
|
||||
|
||||
Row
|
||||
</li>
|
||||
|
||||
<li style="height: 40px" @click="onEdit">
|
||||
<i class="el-icon-edit" style="margin-top: 2px"></i>
|
||||
|
||||
Edit
|
||||
</li>
|
||||
|
||||
<li style="height: 40px; background-color: red !important" @click="onDelete">
|
||||
<i class="el-icon-delete" style="margin-top: 2px"></i>
|
||||
|
||||
Delete
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class=""
|
||||
:style="isPreview ? 'width: 100%;padding: 20px;' : 'width: calc(100% - 300px);padding: 60px 20px 20px 34px;'"
|
||||
style="
|
||||
|
||||
box-sizing: border-box;
|
||||
width: calc(100% - 300px);
|
||||
float: left;
|
||||
@@ -21,7 +116,15 @@
|
||||
position: relative;
|
||||
"
|
||||
>
|
||||
<!-- <common-late-x></common-late-x> -->
|
||||
<template v-for="(item, index) in wordList">
|
||||
<el-checkbox
|
||||
@change="updateUniqueIds"
|
||||
v-if="!isPreview"
|
||||
v-model="item.checked"
|
||||
style="position: absolute; left: -20px; width: 8px; height: 8px; margin-top: 8px"
|
||||
></el-checkbox>
|
||||
|
||||
<span class="isRemark" :remark-main-id="item.am_id" v-if="item.checks && item.checks.length > 0 && !isPreview">
|
||||
><img
|
||||
class="isRemark"
|
||||
@@ -32,98 +135,137 @@
|
||||
|
||||
<span>{{ item.am_id }}</span>
|
||||
</span>
|
||||
<div :class="!isPreview?(item.is_h1?'isTitleH1':item.is_h2?'isTitleH2':item.is_h3?'isTitleH3':''):''" style="line-height: 24px;">
|
||||
<template v-if="!isPreview"> <span class="Htitle Htitle1" v-if="item.is_h1==1">H1</span>
|
||||
<span class="Htitle Htitle2" v-else-if="item.is_h2==1">H2</span>
|
||||
<span class="Htitle Htitle3" v-else-if="item.is_h3==1">H3</span></template>
|
||||
|
||||
<div
|
||||
:key="item.am_id"
|
||||
id="drop-target"
|
||||
:class="highlightImg(item.ami_id, item.checks ? item.checks : [])"
|
||||
:comment-Id="highlightImgCommentId(item.ami_id, item.checks ? item.checks : [])"
|
||||
@dragover="handleDragOver"
|
||||
@dragenter="handleDragEnter"
|
||||
@dragleave="handleDragLeave"
|
||||
@drop="handleDrop"
|
||||
class="MaxPicture pMain myeditabledivImage drop-target"
|
||||
@click="initializeEditor(item.am_id, 'img', item)"
|
||||
v-if="item.type == 1"
|
||||
:main-state="item.state"
|
||||
:remark="item.checks && item.checks.length > 0 ? 1 : 0"
|
||||
:contenteditable="!readonly && !isPreview"
|
||||
:data-id="item.ami_id"
|
||||
:type="item.type"
|
||||
:main-id="item.am_id"
|
||||
:id="'editor' + item.am_id"
|
||||
<div
|
||||
:class="!isPreview ? (item.is_h1 ? 'isTitleH1' : item.is_h2 ? 'isTitleH2' : item.is_h3 ? 'isTitleH3' : '') : ''"
|
||||
style="line-height: 24px"
|
||||
>
|
||||
<template v-if="!isPreview">
|
||||
<span class="Htitle Htitle1" v-if="item.is_h1 == 1">H1</span>
|
||||
<span class="Htitle Htitle2" v-else-if="item.is_h2 == 1">H2</span>
|
||||
<span class="Htitle Htitle3" v-else-if="item.is_h3 == 1">H3</span></template
|
||||
>
|
||||
<img :src="`${mediaUrl + item.image.url}`" />
|
||||
|
||||
<font class="font" :style="`width: ${item.width ? `${item.width}px` : '100%'}`">
|
||||
<span v-html="item.image.note ? highlightText(item.image.note, item.checks ? item.checks : []) : ''"></span>
|
||||
</font>
|
||||
</div>
|
||||
<div
|
||||
id="drop-target"
|
||||
@dragover="handleDragOver"
|
||||
@dragenter="handleDragEnter"
|
||||
@dragleave="handleDragLeave"
|
||||
@drop="handleDrop"
|
||||
@click="initializeEditor(item.am_id, 'table', item)"
|
||||
class="thumbnailTableBox wordTableHtml table_Box pMain myeditabledivTable drop-target"
|
||||
v-else-if="item.type == 2"
|
||||
:main-state="item.state"
|
||||
:remark="item.checks && item.checks.length > 0 ? 1 : 0"
|
||||
:contenteditable="!readonly && !isPreview"
|
||||
:data-id="item.amt_id"
|
||||
:type="item.type"
|
||||
:id="'editor' + item.am_id"
|
||||
:main-id="item.am_id"
|
||||
>
|
||||
<!-- 标题部分 -->
|
||||
<font class="font" :style="`width: ${item.width ? `${item.width}px` : '100%'}`" style="text-align: center;">
|
||||
<span v-html="highlightText(item.table.title || '', item.checks ? item.checks : [])"></span>
|
||||
</font>
|
||||
<div :class="currentId == item.am_id ? 'glowing-border' : ''" style="position: relative">
|
||||
<div
|
||||
v-if="currentId == item.am_id"
|
||||
style="background-color: #fff; z-index: 100; position: absolute; right: 0px; top: -40px"
|
||||
>
|
||||
<el-button
|
||||
v-if="currentId == item.am_id"
|
||||
style="background-color: #006699d1; font-weight: bold; color: #fff; font-size: 16px !important"
|
||||
:style="index == 0 ? ' opacity: 0.2;' : ' opacity: 1;'"
|
||||
size="mini"
|
||||
plain
|
||||
:disabled="index != 0 ? false : true"
|
||||
@click="changeSort('up')"
|
||||
>↑</el-button
|
||||
>
|
||||
<el-button
|
||||
v-if="currentId == item.am_id"
|
||||
style="background-color: #006699d1; font-weight: bold; color: #fff; font-size: 16px !important"
|
||||
size="mini"
|
||||
:style="index == wordList.length - 1 ? ' opacity: 0.2;' : ' opacity: 1;'"
|
||||
plain
|
||||
:disabled="index == wordList.length - 1 ? true : false"
|
||||
@click="changeSort('down')"
|
||||
>↓</el-button
|
||||
>
|
||||
</div>
|
||||
|
||||
<!-- 表格部分 -->
|
||||
<table border="1" style="width: 100%; border-collapse: collapse; text-align: center">
|
||||
<tr v-for="(row, i) in JSON.parse(item.table.table_data)" :key="i" :class="{ 'table-header-row': isHeaderRow(i,item.table.table_data) }">
|
||||
<td
|
||||
v-for="(cell, i1) in row"
|
||||
:key="i1"
|
||||
:colspan="`${cell.colspan || 1}`"
|
||||
:rowspan="`${cell.rowspan || 1}`"
|
||||
<div
|
||||
@dblclick="dblclickEdit(item.am_id, 'img', item, index)"
|
||||
:key="item.am_id"
|
||||
id="drop-target"
|
||||
:class="highlightImg(item.ami_id, item.checks ? item.checks : [])"
|
||||
:comment-Id="highlightImgCommentId(item.ami_id, item.checks ? item.checks : [])"
|
||||
@dragover="handleDragOver"
|
||||
@dragenter="handleDragEnter"
|
||||
@dragleave="handleDragLeave"
|
||||
@drop="handleDrop"
|
||||
class="MaxPicture pMain myeditabledivImage drop-target"
|
||||
@click="initializeEditor(item.am_id, 'img', item, index)"
|
||||
v-if="item.type == 1"
|
||||
:main-state="item.state"
|
||||
:remark="item.checks && item.checks.length > 0 ? 1 : 0"
|
||||
:data-id="item.ami_id"
|
||||
:type="item.type"
|
||||
:main-id="item.am_id"
|
||||
:id="'editor' + item.am_id"
|
||||
>
|
||||
<img :src="`${mediaUrl + item.image.url}`" />
|
||||
|
||||
<font class="font" :style="`width: ${item.width ? `${item.width}px` : '100%'}`">
|
||||
<span
|
||||
v-html="item.image.note ? highlightText(item.image.note, item.checks ? item.checks : []) : ''"
|
||||
></span>
|
||||
</font>
|
||||
</div>
|
||||
<div
|
||||
@dblclick="dblclickEdit(item.am_id, 'table', item, index)"
|
||||
id="drop-target"
|
||||
@dragover="handleDragOver"
|
||||
@dragenter="handleDragEnter"
|
||||
@dragleave="handleDragLeave"
|
||||
@drop="handleDrop"
|
||||
@click="initializeEditor(item.am_id, 'table', item, index)"
|
||||
class="thumbnailTableBox wordTableHtml table_Box pMain myeditabledivTable drop-target"
|
||||
v-else-if="item.type == 2"
|
||||
:main-state="item.state"
|
||||
:remark="item.checks && item.checks.length > 0 ? 1 : 0"
|
||||
:data-id="item.amt_id"
|
||||
:type="item.type"
|
||||
:id="'editor' + item.am_id"
|
||||
:main-id="item.am_id"
|
||||
>
|
||||
<!-- 标题部分 -->
|
||||
<font class="font" :style="`width: ${item.width ? `${item.width}px` : '100%'}`" style="text-align: center">
|
||||
<span v-html="highlightText(item.table.title || '', item.checks ? item.checks : [])"></span>
|
||||
</font>
|
||||
|
||||
<!-- 表格部分 -->
|
||||
<table border="1" style="width: 100%; border-collapse: collapse; text-align: center">
|
||||
<tr
|
||||
v-for="(row, i) in JSON.parse(item.table.table_data)"
|
||||
:key="i"
|
||||
:class="{ 'table-header-row': isHeaderRow(i, item.table.table_data) }"
|
||||
>
|
||||
<span v-html="highlightText(cell.text || '', item.checks ? item.checks : [])"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<td
|
||||
v-for="(cell, i1) in row"
|
||||
:key="i1"
|
||||
:colspan="`${cell.colspan || 1}`"
|
||||
:rowspan="`${cell.rowspan || 1}`"
|
||||
>
|
||||
<span v-html="highlightText(cell.text || '', item.checks ? item.checks : [])"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- 备注部分 -->
|
||||
<font class="font" :style="`width: ${item.width ? `${item.width}px` : '100%'}`">
|
||||
<span v-html="highlightText(item.table.note || '', item.checks ? item.checks : [])"></span>
|
||||
</font>
|
||||
<!-- 备注部分 -->
|
||||
<font class="font" :style="`width: ${item.width ? `${item.width}px` : '100%'}`">
|
||||
<span v-html="highlightText(item.table.note || '', item.checks ? item.checks : [])"></span>
|
||||
</font>
|
||||
</div>
|
||||
|
||||
<div
|
||||
@dblclick="dblclickEdit(item.am_id, 'text', item, index)"
|
||||
v-else
|
||||
id="drop-target"
|
||||
@dragover="handleDragOver"
|
||||
@dragenter="handleDragEnter"
|
||||
@dragleave="handleDragLeave"
|
||||
@drop="handleDrop"
|
||||
@click="initializeEditor(item.am_id, 'text', item, index)"
|
||||
class="pMain myeditablediv drop-target"
|
||||
@blur="clearEditor(item.am_id)"
|
||||
:main-state="item.state"
|
||||
:remark="item.checks && item.checks.length > 0 ? 1 : 0"
|
||||
:data-id="item.am_id"
|
||||
:main-id="item.am_id"
|
||||
:type="item.type"
|
||||
:id="'editor' + item.am_id"
|
||||
v-html="highlightText(item.content, item.checks ? item.checks : [], item.type)"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else
|
||||
id="drop-target"
|
||||
@dragover="handleDragOver"
|
||||
@dragenter="handleDragEnter"
|
||||
@dragleave="handleDragLeave"
|
||||
@drop="handleDrop"
|
||||
@click="initializeEditor(item.am_id)"
|
||||
class="pMain myeditablediv drop-target"
|
||||
@blur="clearEditor(item.am_id)"
|
||||
:main-state="item.state"
|
||||
:remark="item.checks && item.checks.length > 0 ? 1 : 0"
|
||||
:contenteditable="!readonly && !isPreview"
|
||||
:data-id="item.am_id"
|
||||
:main-id="item.am_id"
|
||||
:type="item.type"
|
||||
:id="'editor' + item.am_id"
|
||||
v-html="highlightText(item.content, item.checks ? item.checks : [], item.type)"
|
||||
></div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@@ -146,7 +288,7 @@
|
||||
v-for="(item, index) in commentList"
|
||||
class="comment-item annotation"
|
||||
:data-target="`main-${item.am_id}`"
|
||||
style="width: 100%; margin:0 0 10px; background: #fafafa; box-sizing: border-box"
|
||||
style="width: 100%; margin: 0 0 10px; background: #fafafa; box-sizing: border-box"
|
||||
>
|
||||
<div>
|
||||
<div style="display: flex; align-items: center; justify-content: space-between; background-color: #f3d5d5c2">
|
||||
@@ -162,21 +304,16 @@
|
||||
</el-link>
|
||||
</div>
|
||||
<div
|
||||
style="
|
||||
|
||||
padding:6px 6px;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 1px solid rgba(243, 213, 213);
|
||||
"
|
||||
style="padding: 6px 6px; box-sizing: border-box; border-bottom: 1px solid rgba(243, 213, 213)"
|
||||
:style="commont.estate == 1 ? 'background:#13bc200f;' : ''"
|
||||
v-for="(commont, commentIndex) in item.comment"
|
||||
@click="highlightLeftComment(commont.amc_id, item.am_id)"
|
||||
>
|
||||
<div style="width: 100%; display: flex; align-items: center; justify-content: space-between">
|
||||
<div style="display: flex; align-items: center;line-height: 20px;">
|
||||
<div style="display: flex; align-items: center; line-height: 20px">
|
||||
<span
|
||||
:style="commont.estate == 1 ? 'opacity:0.6;color:rgb(19, 188, 32);' : ''"
|
||||
style="color: #e61a12; font-weight: bold;font-size: 12px;"
|
||||
style="color: #e61a12; font-weight: bold; font-size: 12px"
|
||||
>{{ commentIndex + 1 }}、</span
|
||||
>
|
||||
<span
|
||||
@@ -195,7 +332,7 @@
|
||||
$t('commonTable.Resolved')
|
||||
}}</span>
|
||||
</div>
|
||||
<div style="display: flex; align-items: center; justify-content: center;line-height: 20px;">
|
||||
<div style="display: flex; align-items: center; justify-content: center; line-height: 20px">
|
||||
<span style="color: #b8b7b7; font-size: 12px">{{ getTime(commont.ctime) }}</span
|
||||
><span
|
||||
style="color: #aaa; font-size: 13px; margin: 0 4px"
|
||||
@@ -302,7 +439,10 @@
|
||||
"
|
||||
>
|
||||
<i class="el-icon-user-solid" style="color: #333; padding: 0 4px"></i>
|
||||
<div v-html="commont.author_remark" style="width: calc(100% - 20px); font-size: 13px;line-height: 14px;"></div>
|
||||
<div
|
||||
v-html="commont.author_remark"
|
||||
style="width: calc(100% - 20px); font-size: 13px; line-height: 14px"
|
||||
></div>
|
||||
</div>
|
||||
<i
|
||||
class="el-icon-edit"
|
||||
@@ -373,10 +513,10 @@ b span{
|
||||
table-layout: auto; /* 自动调整列宽 */
|
||||
text-align:left;
|
||||
font-family:'Charis SIL' !important;
|
||||
font-size: 7.5000pt !important;
|
||||
font-size: 14px !important;
|
||||
mso-font-kerning: 1.0000pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
table td, table th {
|
||||
padding: 5px;
|
||||
@@ -385,10 +525,10 @@ b span{
|
||||
word-wrap: nomarl; /* 长单词自动换行 */
|
||||
word-break: nomarl;
|
||||
font-family:'Charis SIL' !important;
|
||||
font-size: 7.5000pt !important;
|
||||
font-size: 14px !important;
|
||||
mso-font-kerning: 1.0000pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
table tbody tr td{
|
||||
|
||||
@@ -413,27 +553,27 @@ b span{
|
||||
|
||||
margin:0;
|
||||
font-family:'Charis SIL' !important;
|
||||
font-size: 7.5000pt !important;
|
||||
font-size: 14px !important;
|
||||
mso-font-kerning: 1.0000pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
table span{
|
||||
|
||||
color:#000000;text-align:left !important;
|
||||
font-family:'Charis SIL' !important;
|
||||
font-size: 7.5000pt !important;
|
||||
font-size: 14px !important;
|
||||
mso-font-kerning: 1.0000pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
table .color-highlight{
|
||||
color:rgb(0,130,170) !important;
|
||||
font-family:'Charis SIL' !important;
|
||||
font-size: 7.5000pt !important;
|
||||
font-size: 14px !important;
|
||||
mso-font-kerning: 1.0000pt !important;
|
||||
line-height: 10pt !important;
|
||||
mos-line-height: 10pt !important;
|
||||
line-height: 20px !important;
|
||||
mos-line-height: 20px !important;
|
||||
}
|
||||
table tr:first-child td {
|
||||
border-top:1.0000pt solid #000 !important;mso-border-top-alt:0.5000pt solid #000 !important;border-bottom:1.0000pt solid #000 !important;mso-border-bottom-alt:0.5000pt solid #000 !important;
|
||||
@@ -510,6 +650,14 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
cachedHtml: '', // 缓存选中的 HTML
|
||||
cachedText: '', // 缓存选中的纯文本
|
||||
cachedMainId: null, // 选中的 main-id
|
||||
cachedType: null, // 选中的 type
|
||||
currentId: null,
|
||||
currentIndex: null,
|
||||
checked: false,
|
||||
currentData: {},
|
||||
imagePath: require('@/assets/img/carriageReturn.png'), // 或者你可以设置其他路径
|
||||
scrollPosition: 0,
|
||||
wordList: [],
|
||||
@@ -556,6 +704,7 @@ export default {
|
||||
}
|
||||
],
|
||||
uploadReset: false,
|
||||
uniqueIds: [],
|
||||
dialogVisible: false,
|
||||
form: {
|
||||
name: '',
|
||||
@@ -582,6 +731,7 @@ export default {
|
||||
if (val) {
|
||||
this.wordList = [...this.contentList];
|
||||
this.$nextTick(() => {
|
||||
window.renderMathJax(); // 主动触发 MathJax 渲染
|
||||
this.getCommentsData();
|
||||
});
|
||||
}
|
||||
@@ -589,12 +739,18 @@ export default {
|
||||
deep: true // 启用深度监听
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
selectedIds() {
|
||||
return this.wordList.filter((item) => item.checked).map((item) => item.am_id);
|
||||
}
|
||||
},
|
||||
updated() {
|
||||
// 恢复子组件的滚动位置
|
||||
// this.$refs.scrollDiv.scrollTop = this.scrollPosition;
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
window.renderMathJax(); // 主动触发 MathJax 渲染
|
||||
this.getCommentsData();
|
||||
if (!this.isPreview && localStorage.getItem('scrollPosition')) {
|
||||
this.$refs.scrollDiv.scrollTop = localStorage.getItem('scrollPosition'); // 滚动到 500px 位置
|
||||
@@ -611,6 +767,7 @@ export default {
|
||||
this.$refs.scrollDiv.addEventListener('scroll', this.divOnScroll, { passive: true });
|
||||
},
|
||||
activated() {
|
||||
window.renderMathJax(); // 主动触发 MathJax 渲染
|
||||
this.isShowEditComment();
|
||||
this.typesettingType = 1;
|
||||
this.editors = {};
|
||||
@@ -623,8 +780,6 @@ export default {
|
||||
this.editors = {};
|
||||
},
|
||||
beforeDestroy() {
|
||||
|
||||
|
||||
for (const key in this.editors) {
|
||||
if (this.editors[key]) {
|
||||
// 确保销毁所有编辑器实例
|
||||
@@ -639,6 +794,142 @@ export default {
|
||||
this.editors = {};
|
||||
},
|
||||
methods: {
|
||||
changeSort(type) {
|
||||
console.log('type at line 782:', type);
|
||||
if (this.currentId) {
|
||||
this.$emit('changeSort', type, this.currentId);
|
||||
}
|
||||
},
|
||||
addContent() {
|
||||
if (this.currentId) {
|
||||
this.$emit('addContent', this.currentId);
|
||||
} else {
|
||||
this.$message.warning('Please select content');
|
||||
}
|
||||
},
|
||||
cacheSelection() {
|
||||
const selection = window.getSelection();
|
||||
if (!selection.rangeCount) {
|
||||
this.clearCache();
|
||||
return;
|
||||
}
|
||||
|
||||
const range = selection.getRangeAt(0);
|
||||
let selectedNode = range.commonAncestorContainer;
|
||||
|
||||
// **向上查找包含 main-id 的最近 div**
|
||||
let outerDiv = selectedNode;
|
||||
while (outerDiv && outerDiv.tagName !== 'DIV') {
|
||||
outerDiv = outerDiv.parentNode;
|
||||
}
|
||||
|
||||
if (!outerDiv) {
|
||||
this.clearCache();
|
||||
return;
|
||||
}
|
||||
|
||||
// **缓存 main-id 和 type**
|
||||
this.cachedMainId = outerDiv.getAttribute('main-id');
|
||||
this.cachedType = outerDiv.getAttribute('type');
|
||||
|
||||
// **创建临时 div 存放选中的 HTML**
|
||||
const tempDiv = document.createElement('div');
|
||||
tempDiv.appendChild(range.cloneContents());
|
||||
|
||||
// **检查是否包含 <img> 标签**
|
||||
if (tempDiv.querySelector('img')) {
|
||||
this.clearCache();
|
||||
this.$message.error(this.$t('commonTable.selectComment'));
|
||||
return;
|
||||
}
|
||||
|
||||
// **获取纯文本**
|
||||
let selectedText = tempDiv.innerText.trim().replace(/\s+/g, ' ');
|
||||
|
||||
// **允许保留的 HTML 标签**
|
||||
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).map(preserveTags).join('');
|
||||
|
||||
// **检查是否已有批注**
|
||||
if (tempDiv.querySelector('.positionRemarkIndex')) {
|
||||
this.clearCache();
|
||||
this.$message.error(this.$t('commonTable.alreadyCommented'));
|
||||
return;
|
||||
}
|
||||
|
||||
// **缓存选区内容**
|
||||
this.cachedHtml = preservedContent;
|
||||
this.cachedText = selectedText;
|
||||
},
|
||||
|
||||
// **点击“添加批注”按钮**
|
||||
handleSelection() {
|
||||
if (!this.cachedText) {
|
||||
this.$message.error(this.$t('commonTable.selectComment'));
|
||||
return;
|
||||
}
|
||||
|
||||
// **发送批注**
|
||||
this.$emit('onAddComment', {
|
||||
mainId: this.cachedMainId,
|
||||
label: this.cachedHtml
|
||||
});
|
||||
|
||||
// **清空缓存**
|
||||
this.clearCache();
|
||||
},
|
||||
|
||||
// **清空缓存**
|
||||
clearCache() {
|
||||
this.cachedHtml = '';
|
||||
this.cachedText = '';
|
||||
this.cachedMainId = null;
|
||||
this.cachedType = null;
|
||||
},
|
||||
updateUniqueIds() {
|
||||
this.currentId = null;
|
||||
this.currentData = {};
|
||||
// this.uniqueIds = [...new Set(this.wordList.filter((item) => item.checked).map((item) => item.am_id))];
|
||||
// console.log('this.uniqueIds at line 839:', this.selectedIds);
|
||||
this.$forceUpdate();
|
||||
},
|
||||
onEdit() {
|
||||
this.currentData = this.currentData;
|
||||
this.$emit('onEdit', this.currentId);
|
||||
},
|
||||
onAddRow() {
|
||||
this.currentData = this.currentData;
|
||||
this.$emit('onAddRow', this.currentId);
|
||||
},
|
||||
onDelete() {
|
||||
// console.log('this.uniqueIds.length at line 866:', this.selectedIds.length);
|
||||
if (this.selectedIds.length > 0) {
|
||||
this.$emit('onDeletes', this.selectedIds.toString());
|
||||
this.$forceUpdate();
|
||||
}
|
||||
|
||||
if (this.currentId) {
|
||||
this.$emit('onDelete', this.currentId);
|
||||
}
|
||||
},
|
||||
|
||||
changeTitle(value) {
|
||||
if (this.currentData.type == 0) {
|
||||
this.$emit('onEditTitle', {
|
||||
mainId: this.currentId,
|
||||
value: value
|
||||
});
|
||||
}
|
||||
},
|
||||
// 右侧批注列点击时,触发高亮左侧对应的批注
|
||||
// 右侧批注列点击时,触发高亮左侧对应的批注
|
||||
highlightLeftComment(commentId) {
|
||||
@@ -689,16 +980,14 @@ export default {
|
||||
if (outerDiv) {
|
||||
}
|
||||
},
|
||||
// 判断是否是表头行
|
||||
isHeaderRow(rowIndex,table) {
|
||||
|
||||
var table=JSON.parse(table)
|
||||
|
||||
var head=table[0]
|
||||
|
||||
|
||||
return rowIndex < head[0].rowspan; // 假设前两行是表头
|
||||
},
|
||||
// 判断是否是表头行
|
||||
isHeaderRow(rowIndex, table) {
|
||||
var table = JSON.parse(table);
|
||||
|
||||
var head = table[0];
|
||||
|
||||
return rowIndex < head[0].rowspan; // 假设前两行是表头
|
||||
},
|
||||
handleDragLeave(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
@@ -959,30 +1248,53 @@ export default {
|
||||
}
|
||||
});
|
||||
},
|
||||
initializeEditor(index, type, data) {
|
||||
if (!this.isPreview) {
|
||||
const editorId = `editor${index}`;
|
||||
// 检查当前编辑器是否已经初始化
|
||||
if (this.editors[editorId]) return;
|
||||
// 销毁所有已初始化的编辑器实例
|
||||
for (const key in this.editors) {
|
||||
if (this.editors[key]) {
|
||||
// 确保销毁所有编辑器实例
|
||||
tinymce.remove(this.editors[key]);
|
||||
this.editors[key] = null; // 清除引用
|
||||
}
|
||||
}
|
||||
|
||||
if (type == 'img') {
|
||||
this.initTinymceImg(editorId);
|
||||
} else if (type == 'table') {
|
||||
this.initTinymceTable(editorId);
|
||||
} else {
|
||||
this.initTinymceContent(editorId);
|
||||
}
|
||||
this.$set(this.editors, editorId, tinymce.get(`editor${index}`));
|
||||
initializeEditor(id, type, data, index) {
|
||||
this.clearHighlight();
|
||||
this.selectedIds = [];
|
||||
this.wordList.forEach((item, index) => {
|
||||
item.checked = false;
|
||||
});
|
||||
if (!this.isPreview) {
|
||||
this.currentId = id;
|
||||
this.currentIndex = index;
|
||||
this.currentData = data;
|
||||
|
||||
// const editorId = `editor${index}`;
|
||||
// // 检查当前编辑器是否已经初始化
|
||||
// if (this.editors[editorId]) return;
|
||||
// // 销毁所有已初始化的编辑器实例
|
||||
// for (const key in this.editors) {
|
||||
// if (this.editors[key]) {
|
||||
// // 确保销毁所有编辑器实例
|
||||
// tinymce.remove(this.editors[key]);
|
||||
// this.editors[key] = null; // 清除引用
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (type == 'img') {
|
||||
// this.initTinymceImg(editorId);
|
||||
// } else if (type == 'table') {
|
||||
// this.initTinymceTable(editorId);
|
||||
// } else {
|
||||
// this.initTinymceContent(editorId);
|
||||
// }
|
||||
// this.$set(this.editors, editorId, tinymce.get(`editor${index}`));
|
||||
}
|
||||
},
|
||||
dblclickEdit(id, type, data, index) {
|
||||
if (!this.isPreview) {
|
||||
this.currentId = id;
|
||||
this.currentIndex = index;
|
||||
this.currentData = data;
|
||||
this.onEdit();
|
||||
}
|
||||
this.clearHighlight();
|
||||
this.selectedIds = [];
|
||||
this.wordList.forEach((item, index) => {
|
||||
item.checked = false;
|
||||
});
|
||||
},
|
||||
deleteComment(data) {
|
||||
this.$emit('deleteComment', data);
|
||||
},
|
||||
@@ -1025,6 +1337,8 @@ export default {
|
||||
},
|
||||
divOnScroll() {
|
||||
if (!this.isPreview) {
|
||||
this.currentId = null;
|
||||
this.currentData = {};
|
||||
// const scrollTop = scrollDiv.scrollTop; // 获取垂直滚动距离
|
||||
this.scrollPosition = this.$refs.scrollDiv.scrollTop;
|
||||
localStorage.setItem('scrollPosition', this.scrollPosition);
|
||||
@@ -1071,16 +1385,11 @@ export default {
|
||||
}
|
||||
},
|
||||
highlightImgCommentId(imgId, annotations) {
|
||||
|
||||
const emptyContentIndexes = annotations
|
||||
const emptyContentIndexes = annotations
|
||||
.map((annotation, index) => (annotation.content === '' ? annotation.amc_id : -1)) // 找到内容为空的批注项的索引,其他项返回 -1
|
||||
.filter((index) => index !== -1) // 过滤掉值为 -1 的项
|
||||
.join(','); // 以逗号连接索引
|
||||
return emptyContentIndexes;
|
||||
|
||||
|
||||
|
||||
|
||||
return emptyContentIndexes;
|
||||
},
|
||||
escapeRegExp(string) {
|
||||
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
@@ -1118,7 +1427,7 @@ export default {
|
||||
style="background-color: ${randomColor};
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
// white-space: nowrap;
|
||||
overflow-wrap: anywhere;
|
||||
border-left: 2px solid #cd5454;
|
||||
border-right: 2px solid #cd5454;"
|
||||
@@ -1134,7 +1443,6 @@ export default {
|
||||
});
|
||||
});
|
||||
if (type == 0 && tempText == '') {
|
||||
|
||||
tempText =
|
||||
tempText +
|
||||
`<img contenteditable="${false}" src="${this.imagePath}" alt="" style="width: 20px;height: 20px;opacity:0.6;">`;
|
||||
@@ -1851,6 +2159,7 @@ export default {
|
||||
.pMain {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
min-height: 30px;
|
||||
}
|
||||
::v-deep .tox.tox-tinymce-inline {
|
||||
z-index: 9999 !important;
|
||||
@@ -1955,18 +2264,17 @@ export default {
|
||||
border: 2px solid #cd5454; /* 高亮边框 */
|
||||
box-shadow: 0 0 10px #f77b7b; /* 高亮阴影 */
|
||||
}
|
||||
.isTitleH1{
|
||||
position: relative;
|
||||
/* border: 1px solid #94c2f7; */
|
||||
.isTitleH1 {
|
||||
position: relative;
|
||||
/* border: 1px solid #94c2f7; */
|
||||
background-color: #dbebfc54;
|
||||
}
|
||||
|
||||
.Htitle{
|
||||
|
||||
color: #4d99f1;
|
||||
background-color: #dbebfca6;
|
||||
/* border: 1px solid #4d99f1; */
|
||||
border-radius: 50%;
|
||||
.Htitle {
|
||||
color: #4d99f1;
|
||||
background-color: #dbebfca6;
|
||||
/* border: 1px solid #4d99f1; */
|
||||
border-radius: 50%;
|
||||
font-weight: bold;
|
||||
position: absolute;
|
||||
|
||||
@@ -1976,25 +2284,85 @@ export default {
|
||||
left: -30px;
|
||||
top: 0px;
|
||||
text-align: center;
|
||||
|
||||
}
|
||||
.Htitle1{
|
||||
.Htitle1 {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
/* font-size: 14px; */
|
||||
}
|
||||
.Htitle2{ width: 24px;
|
||||
.Htitle2 {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
/* font-size: 16px; */
|
||||
}
|
||||
.Htitle3{ width: 24px;
|
||||
.Htitle3 {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
/* font-size: 12px; */
|
||||
}
|
||||
.isTitleH2{position: relative;
|
||||
.isTitleH2 {
|
||||
position: relative;
|
||||
background-color: #dbebfc54;
|
||||
}
|
||||
.isTitleH3{position: relative;
|
||||
.isTitleH3 {
|
||||
position: relative;
|
||||
background-color: #dbebfc54;
|
||||
}
|
||||
.glowing-border {
|
||||
border: 3px solid #006699d1;
|
||||
border-radius: 5px;
|
||||
padding: 4px;
|
||||
animation: glow 1.5s infinite alternate;
|
||||
}
|
||||
@keyframes glow {
|
||||
0% {
|
||||
box-shadow: 0 0 5px #006699d1;
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 0 20px #006699d1;
|
||||
}
|
||||
100% {
|
||||
box-shadow: 0 0 5px #006699d1;
|
||||
}
|
||||
}
|
||||
.HTitleBox {
|
||||
height: 100%;
|
||||
border: 1px solid #c5c5c5;
|
||||
width: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.HTitleBox li {
|
||||
list-style: none;
|
||||
padding: 0 10px;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
}
|
||||
.operateBox {
|
||||
width: auto;
|
||||
display: flex;
|
||||
}
|
||||
.operateBox li {
|
||||
width: 55px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
list-style: none;
|
||||
padding: 2px 10px;
|
||||
margin: 0 10px;
|
||||
color: #8a8a8b;
|
||||
/* font-weight: bold; */
|
||||
font-size: 16px;
|
||||
background-color: rgb(43, 129, 239) !important;
|
||||
color: #fff;
|
||||
border-radius: 4px;
|
||||
}
|
||||
::v-deep .el-checkbox__inner {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
<el-table-column type="index" label="No." width="55" align="center">
|
||||
<template slot-scope="scope">
|
||||
<i v-if="scope.row.is_change == 1" class="itemChanged"></i>
|
||||
<img src="../../assets/img/repeat.png" v-if="scope.row.is_repeat==1" alt="" style="width: 24px;height: 24px;float: left;">
|
||||
<span>{{scope.$index + 1}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
58
src/main.js
58
src/main.js
@@ -15,7 +15,24 @@ import Common from './components/common/common'
|
||||
Vue.prototype.$validateString = function (str) {
|
||||
return /^[a-zA-Z\s\u00C0-\u00FF\u0100-\u017F-]+$/.test(str);
|
||||
}
|
||||
|
||||
window.MathJax = {
|
||||
tex: {
|
||||
inlineMath: [['$', '$'], ['\\(', '\\)']], // 行内公式
|
||||
displayMath: [['$$', '$$'], ['\\[', '\\]']], // 块级公式
|
||||
},
|
||||
svg: { fontCache: 'global' }
|
||||
};
|
||||
|
||||
// 监听 DOM 变化,并自动渲染公式
|
||||
Vue.prototype.$renderMath = function () {
|
||||
if (window.MathJax && window.MathJax.typeset) {
|
||||
setTimeout(() => {
|
||||
window.MathJax.typeset();
|
||||
}, 100); // 延迟防止 Vue 还未完全渲染
|
||||
} else {
|
||||
console.warn('MathJax 未正确加载');
|
||||
}
|
||||
};
|
||||
import VXETable from 'vxe-table'
|
||||
import 'vxe-table/lib/style.css'
|
||||
|
||||
@@ -32,7 +49,7 @@ Vue.use(VueQuillEditor)
|
||||
|
||||
// 时间过滤器
|
||||
// 定义时间过滤器(不含时分秒)
|
||||
Vue.filter('formatDate', function(originVal) {
|
||||
Vue.filter('formatDate', function (originVal) {
|
||||
const dt = new Date(originVal * 1000)
|
||||
const y = dt.getFullYear()
|
||||
const m = (dt.getMonth() + 1 + '').padStart(2, '0')
|
||||
@@ -41,9 +58,9 @@ Vue.filter('formatDate', function(originVal) {
|
||||
const mm = (dt.getMinutes() + '').padStart(2, '0')
|
||||
const ss = (dt.getSeconds() + '').padStart(2, '0')
|
||||
return `${y}-${m}-${d}`
|
||||
})
|
||||
// 含时分秒
|
||||
Vue.filter('formatDatehms', function(originVal) {
|
||||
})
|
||||
// 含时分秒
|
||||
Vue.filter('formatDatehms', function (originVal) {
|
||||
const dt = new Date(originVal * 1000)
|
||||
const y = dt.getFullYear()
|
||||
const m = (dt.getMonth() + 1 + '').padStart(2, '0')
|
||||
@@ -52,7 +69,7 @@ Vue.filter('formatDate', function(originVal) {
|
||||
const mm = (dt.getMinutes() + '').padStart(2, '0')
|
||||
const ss = (dt.getSeconds() + '').padStart(2, '0')
|
||||
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
|
||||
})
|
||||
})
|
||||
// 引入wps文档编辑
|
||||
import mammoth from "mammoth";
|
||||
import commonJS from '@/common/js/commonJS.js'
|
||||
@@ -74,6 +91,8 @@ Vue.component("Editor", Editor);
|
||||
|
||||
import commonTable from '@/components/page/components/table/table.vue'
|
||||
Vue.component('common-table', commonTable);
|
||||
import commonLateX from '@/components/page/components/table/LateX.vue'
|
||||
Vue.component('common-late-x', commonLateX);
|
||||
import commonMajor from '@/components/page/components/major/index.vue'
|
||||
Vue.component('common-major', commonMajor);
|
||||
import commonMajorList from '@/components/page/components/major/list.vue'
|
||||
@@ -103,10 +122,10 @@ Vue.component('common-drag-word', commonDragWord);
|
||||
Vue.use(VueI18n);
|
||||
Vue.use(ElementUI, {
|
||||
size: 'small',
|
||||
locale
|
||||
locale
|
||||
});
|
||||
const i18n = new VueI18n({
|
||||
locale: localStorage.getItem('langs')||'en',
|
||||
locale: localStorage.getItem('langs') || 'en',
|
||||
messages
|
||||
});
|
||||
//使用钩子函数对路由进行权限跳转
|
||||
@@ -114,16 +133,16 @@ router.beforeEach((to, from, next) => {
|
||||
document.title = `${to.meta.title} | Traditional Medicine Research`;
|
||||
const role = localStorage.getItem('U_name');
|
||||
const userrole = localStorage.getItem('U_status');
|
||||
if (!role && to.path!='/register'&&to.path!=='/submission'&&to.path!=='/verification'&&to.path!=='/orcidLink'&&to.path!=='/img'&& to.path !=='/reviewer'&&to.path !=='/thanks' &&to.path !== '/login' &&to.path !== '/refuse' &&to.path !== '/managing'&&to.path.search(/retrieve/i)<0 ) {
|
||||
if (!role && to.path != '/register' && to.path !== '/submission' && to.path !== '/verification' && to.path !== '/orcidLink' && to.path !== '/img' && to.path !== '/reviewer' && to.path !== '/thanks' && to.path !== '/login' && to.path !== '/refuse' && to.path !== '/managing' && to.path.search(/retrieve/i) < 0) {
|
||||
next('/login');
|
||||
// } else if (to.meta.permission) {
|
||||
// // 如果是管理员权限则可进入,这里只是简单的模拟管理员权限而已
|
||||
// // role === 'admin' ? next() : next('/403');
|
||||
// if(userrole == to.meta.permission){
|
||||
// next();
|
||||
// }else{
|
||||
// next('/403');
|
||||
// }
|
||||
// } else if (to.meta.permission) {
|
||||
// // 如果是管理员权限则可进入,这里只是简单的模拟管理员权限而已
|
||||
// // role === 'admin' ? next() : next('/403');
|
||||
// if(userrole == to.meta.permission){
|
||||
// next();
|
||||
// }else{
|
||||
// next('/403');
|
||||
// }
|
||||
|
||||
} else {
|
||||
//审稿人导航
|
||||
@@ -144,5 +163,8 @@ router.beforeEach((to, from, next) => {
|
||||
new Vue({
|
||||
router,
|
||||
i18n,
|
||||
render: h => h(App)
|
||||
render: h => h(App),
|
||||
mounted() {
|
||||
this.$renderMath(); // 页面加载后自动渲染
|
||||
}
|
||||
}).$mount('#app');
|
||||
|
||||
@@ -992,6 +992,15 @@ export default new Router({
|
||||
hideSidebar: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/LateX', //用户端预收录-引用编辑
|
||||
component: () => import('../components/page/components/table/LateX.vue'),
|
||||
meta: {
|
||||
title: 'LateX',
|
||||
hideSidebar: true,
|
||||
hideTitle: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'PreIngestedEditor',
|
||||
path: '/PreIngestedEditor', // 编辑端 - 预收录编辑页面
|
||||
|
||||
Reference in New Issue
Block a user