数字公式优化
This commit is contained in:
@@ -1083,6 +1083,33 @@ const en = {
|
||||
importWordMathLoading: 'Importing Word...',
|
||||
importWordMathSuccess: 'Word imported. Formulas converted to LaTeX.',
|
||||
importWordMathFail: 'Word import failed. Please check the file format.',
|
||||
importWordMathNoFormula: 'No math formulas found in the Word file.',
|
||||
importWordMathNoNew: 'All formulas already exist. No new rows added.',
|
||||
importWordMathParsed: 'Word parsed: {parsed} formula(s) found, {added} added.',
|
||||
importWordMathParsedNone: 'Word parsed: {parsed} formula(s) found; all already exist.',
|
||||
mathFormula: 'Latex',
|
||||
mathFormulaMore: 'more formulas',
|
||||
latexDataCopy: 'Copy',
|
||||
latexDataCopied: 'Copied',
|
||||
latexDataClickToCopy: 'Click a formula to copy',
|
||||
latexDataAdd: 'Add',
|
||||
latexDataEdit: 'Edit',
|
||||
latexDataDelete: 'Delete',
|
||||
latexDataDeleteAll: 'Clear all',
|
||||
latexDataDeleteAllConfirm: 'Clear all formulas?',
|
||||
latexDataEmpty: 'No formulas yet. Upload Word or add manually.',
|
||||
latexDataNoFormulaDetected: 'No math formulas detected.',
|
||||
latexDataPlaceholder: 'Enter LaTeX formula',
|
||||
latexMathPlaceholder: 'Enter LaTeX code (e.g., \\frac{a}{b}, x^{2}, \\sqrt{x})',
|
||||
latexMathCopyCode: 'Copy LaTeX code',
|
||||
latexMathCopied: 'Copied',
|
||||
latexMathWrapToInline: 'Change to inline with text',
|
||||
latexMathWrapToBlock: 'Change to block display',
|
||||
latexMathEditorTooltip: 'Insert or edit a LaTeX formula',
|
||||
latexMathConfirm: 'OK',
|
||||
latexDataCancel: 'Cancel',
|
||||
latexDataOk: 'Save',
|
||||
editMathFormulaSuccess: 'Math formulas updated successfully.',
|
||||
selectOne: 'Please select only a single paragraph!',
|
||||
alreadyCommented: 'There are already annotations in the text, please select again!',
|
||||
Multicolumn: 'Multicolumn',
|
||||
|
||||
@@ -1069,6 +1069,33 @@ const zh = {
|
||||
importWordMathLoading: '正在导入 Word...',
|
||||
importWordMathSuccess: 'Word 导入成功,公式已转为 LaTeX',
|
||||
importWordMathFail: 'Word 导入失败,请检查文件格式',
|
||||
importWordMathNoFormula: '未在 Word 中识别到数学公式',
|
||||
importWordMathNoNew: '公式已存在,未新增重复项',
|
||||
importWordMathParsed: 'Word 解析完成:识别 {parsed} 个公式,新增 {added} 个',
|
||||
importWordMathParsedNone: 'Word 解析完成:识别 {parsed} 个公式,均已存在,未新增',
|
||||
mathFormula: 'Latex',
|
||||
mathFormulaMore: '条公式',
|
||||
latexDataCopy: '复制',
|
||||
latexDataCopied: '已复制',
|
||||
latexDataClickToCopy: '点击数字公式即可复制',
|
||||
latexDataAdd: '新增',
|
||||
latexDataEdit: '修改',
|
||||
latexDataDelete: '删除',
|
||||
latexDataDeleteAll: '清空',
|
||||
latexDataDeleteAllConfirm: '确定清空全部公式吗?',
|
||||
latexDataEmpty: '暂无公式,可上传 Word 或手动新增',
|
||||
latexDataNoFormulaDetected: '暂未检测到数字公式',
|
||||
latexDataPlaceholder: '输入 LaTeX 公式',
|
||||
latexMathPlaceholder: '请输入 LaTeX 代码(如 \\frac{a}{b}、x^{2}、\\sqrt{x})',
|
||||
latexMathCopyCode: '复制 LaTeX 代码',
|
||||
latexMathCopied: '已复制',
|
||||
latexMathWrapToInline: '改为行内公式',
|
||||
latexMathWrapToBlock: '改为独立成行',
|
||||
latexMathEditorTooltip: '插入或编辑 LaTeX 公式',
|
||||
latexMathConfirm: '确定',
|
||||
latexDataCancel: '取消',
|
||||
latexDataOk: '保存',
|
||||
editMathFormulaSuccess: '数字公式更新成功',
|
||||
selectOne:'请只勾选单个段落!',
|
||||
alreadyCommented:'文本中已有批注内容请重新选择',
|
||||
Multicolumn:'多列',
|
||||
|
||||
@@ -64,12 +64,14 @@
|
||||
@onAddComment="onAddComment"
|
||||
@addImage="handleImageAdd"
|
||||
@addTable="handleTableAdd"
|
||||
@importWordMath="handleImportWordMath"
|
||||
@handlePaperclip="handlePaperclip"
|
||||
@addComment="addCommentSetting"
|
||||
@goToComment="goToComment"
|
||||
@edit="handleFigureAndTableEdit"
|
||||
@delete="handleFigureAndTableDelete"
|
||||
@goToListComment="goToListComment"
|
||||
@mathFormulasChange="onMathFormulasChange"
|
||||
style="width: 100%; height: 100%; padding: 0 0px; box-sizing: border-box; background-color: #fff"
|
||||
>
|
||||
<template slot="catalogue1">
|
||||
@@ -96,6 +98,7 @@
|
||||
:contentList="Main_List"
|
||||
:comments="comments"
|
||||
:wordStyle="wordStyle"
|
||||
:mathFormulasList="mathFormulasList"
|
||||
@onDrop="onDrop"
|
||||
@onLinkUnbind="handleUnbindLink"
|
||||
@onLinkConfirm="handleConfirmLink"
|
||||
@@ -121,6 +124,8 @@
|
||||
@onEditTitle="onEditTitle"
|
||||
@onAddRow="onAddRow"
|
||||
@changeComment="changeComment"
|
||||
@latexAdded="onLatexAdded"
|
||||
@latexUpdated="onLatexUpdated"
|
||||
style="width: calc(100%); height: calc(100%)"
|
||||
:style="`100%`"
|
||||
>
|
||||
@@ -417,7 +422,7 @@
|
||||
</el-form>
|
||||
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="editVisible = false"> Cancel </el-button>
|
||||
<el-button @click="addContentVisible = false"> Cancel </el-button>
|
||||
<el-button type="primary" @click="handleSaveAddContent">
|
||||
<!-- <i class="el-icon-finished" style="margin-right: 5px"></i> -->
|
||||
Save
|
||||
@@ -434,6 +439,7 @@ import bus from '@/components/common/bus';
|
||||
import { del, isShallow } from 'vue';
|
||||
import Tiff from 'tiff.js';
|
||||
import { mediaUrl } from '@/common/js/commonJS.js'; // 引入通用逻辑
|
||||
import { LATEX_DATA_HTML_DATA, MATH_FORMULA_TABLE_TITLE } from '@/utils/mathFormulaModule';
|
||||
import Tinymce from '@/components/page/components/Tinymce';
|
||||
import bottomTinymce from '@/components/page/components/Tinymce';
|
||||
import catalogue from '@/components/page/components/table/catalogue.vue';
|
||||
@@ -455,6 +461,7 @@ export default {
|
||||
editVisible: false,
|
||||
currentId: null,
|
||||
ManuscirptContent: [],
|
||||
mathFormulasList: [],
|
||||
articleId: this.$route.query.id,
|
||||
isShowComment: false,
|
||||
urlList: {
|
||||
@@ -1526,6 +1533,54 @@ export default {
|
||||
this.lineStyle.visiTitle = 'Add Table';
|
||||
this.threeVisible = true;
|
||||
},
|
||||
onMathFormulasChange(payload) {
|
||||
this.mathFormulasList = (payload && payload.list) || [];
|
||||
},
|
||||
onLatexAdded(data) {
|
||||
if (this.$refs.commonWordHtmlTypeSetting) {
|
||||
this.$refs.commonWordHtmlTypeSetting.onMathFormulaAdded(data);
|
||||
}
|
||||
},
|
||||
onLatexUpdated(data) {
|
||||
if (this.$refs.commonWordHtmlTypeSetting) {
|
||||
this.$refs.commonWordHtmlTypeSetting.onMathFormulaUpdated(data);
|
||||
}
|
||||
},
|
||||
async handleImportWordMath(file) {
|
||||
if (!file) return;
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
text: this.$t('commonTable.importWordMathLoading'),
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
});
|
||||
try {
|
||||
const html = await this.$commonJS.importWordDocumentWithMath(file);
|
||||
const { tableData } = this.$commonJS.extractWmathTableDataFromHtml(html);
|
||||
if (!tableData || tableData.length === 0) {
|
||||
this.$message.warning(this.$t('commonTable.importWordMathNoFormula'));
|
||||
return;
|
||||
}
|
||||
const res = await this.$api.post(this.urlList.addTable, {
|
||||
article_id: this.articleId,
|
||||
table_data: JSON.stringify(tableData),
|
||||
html_data: LATEX_DATA_HTML_DATA,
|
||||
note: '',
|
||||
title: MATH_FORMULA_TABLE_TITLE
|
||||
});
|
||||
if (res.code == 0) {
|
||||
this.$message.success(this.$t('commonTable.importWordMathSuccess'));
|
||||
this.$refs.commonWordHtmlTypeSetting.refresh('addTable', res.data);
|
||||
} else {
|
||||
this.$message.error(res.msg || this.$t('commonTable.importWordMathFail'));
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('handleImportWordMath failed', err);
|
||||
this.$message.error(this.$t('commonTable.importWordMathFail'));
|
||||
} finally {
|
||||
loading.close();
|
||||
}
|
||||
},
|
||||
addUploadWordTable(data) {
|
||||
this.lineStyle = { note: '', table: data.table_data, html_data: data.html_data };
|
||||
this.lineStyle1 = { note: '', table: data.table_data, html_data: data.html_data };
|
||||
@@ -1590,6 +1645,26 @@ export default {
|
||||
this.$message.error(err.msg);
|
||||
});
|
||||
}
|
||||
if (type == 'math') {
|
||||
this.$api
|
||||
.post(this.urlList.deleteTable, {
|
||||
amt_id: data.amt_id,
|
||||
article_id: this.articleId
|
||||
})
|
||||
.then(async (res) => {
|
||||
if (res.status == 1) {
|
||||
loading.close();
|
||||
this.$refs.commonWordHtmlTypeSetting.replacement('math', data.amt_id);
|
||||
} else {
|
||||
loading.close();
|
||||
this.$message.error(res.msg);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
loading.close();
|
||||
this.$message.error(err.msg);
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
// this.$message.error(err.msg);
|
||||
@@ -1602,19 +1677,17 @@ export default {
|
||||
this.picStyle = { ...data, extension: extension, picUrl: data.url };
|
||||
this.picStyle.visiTitle = 'Edit Figure';
|
||||
this.pictVisible = true;
|
||||
} else if (type == 'table') {
|
||||
} else if (type == 'table' || type == 'math') {
|
||||
this.lineStyle = {};
|
||||
this.lineStyle1 = {};
|
||||
// 1. 提取处理逻辑
|
||||
const formattedData = {
|
||||
...data,
|
||||
table: JSON.parse(data.table_data)
|
||||
table: data.table || (data.table_data ? JSON.parse(data.table_data) : [])
|
||||
};
|
||||
|
||||
// 2. 统一赋值
|
||||
this.lineStyle = formattedData;
|
||||
this.lineStyle1 = { ...formattedData }; // 使用浅拷贝确保两个变量指向不同引用(如果需要独立修改)
|
||||
this.lineStyle.visiTitle = 'Edit Table';
|
||||
this.lineStyle1 = { ...formattedData };
|
||||
this.lineStyle.visiTitle = type == 'math' ? 'Edit Math Formula' : 'Edit Table';
|
||||
this.threeVisible = true;
|
||||
}
|
||||
},
|
||||
@@ -2048,7 +2121,7 @@ export default {
|
||||
strTitle = strTitle.replace(/<br\s*\/?>/gi, '');
|
||||
var tableStr=JSON.stringify(cleanedTableList)
|
||||
|
||||
if (this.lineStyle.visiTitle == 'Edit Table') {
|
||||
if (this.lineStyle.visiTitle == 'Edit Table' || this.lineStyle.visiTitle == 'Edit Math Formula') {
|
||||
this.$api
|
||||
.post(this.urlList.editTable, {
|
||||
amt_id: this.lineStyle.amt_id,
|
||||
@@ -2060,7 +2133,11 @@ export default {
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
loading.close();
|
||||
this.$message.success('Successfully edit Table!');
|
||||
this.$message.success(
|
||||
this.lineStyle.visiTitle == 'Edit Math Formula'
|
||||
? this.$t('commonTable.editMathFormulaSuccess')
|
||||
: 'Successfully edit Table!'
|
||||
);
|
||||
this.threeVisible = false;
|
||||
setTimeout(() => {
|
||||
this.$refs.commonWordHtmlTypeSetting.refresh(
|
||||
|
||||
@@ -74,11 +74,13 @@
|
||||
@onAddComment="onAddComment"
|
||||
@addImage="handleImageAdd"
|
||||
@addTable="handleTableAdd"
|
||||
@importWordMath="handleImportWordMath"
|
||||
@handlePaperclip="handlePaperclip"
|
||||
@addComment="addCommentSetting"
|
||||
@goToComment="goToComment"
|
||||
@edit="handleImageEdit"
|
||||
@goToListComment="goToListComment"
|
||||
@mathFormulasChange="onMathFormulasChange"
|
||||
style="width: 100%; height: 100%; padding: 0 0px; box-sizing: border-box; background-color: #fff"
|
||||
>
|
||||
</common-word-html-type-setting>
|
||||
@@ -105,6 +107,8 @@
|
||||
:contentList="Main_List"
|
||||
:comments="comments"
|
||||
:wordStyle="wordStyle"
|
||||
:articleId="articleId"
|
||||
:mathFormulasList="mathFormulasList"
|
||||
@onDrop="onDrop"
|
||||
@saveContent="saveContent"
|
||||
@editComment="editComment"
|
||||
@@ -129,6 +133,8 @@
|
||||
@onEditTitle="onEditTitle"
|
||||
@onAddRow="onAddRow"
|
||||
@changeComment="changeComment"
|
||||
@latexAdded="onLatexAdded"
|
||||
@latexUpdated="onLatexUpdated"
|
||||
style="width: calc(100%); height: calc(100%)"
|
||||
:style="`100%`"
|
||||
>
|
||||
@@ -410,7 +416,7 @@
|
||||
</el-form>
|
||||
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="editVisible = false"> Cancel </el-button>
|
||||
<el-button @click="addContentVisible = false"> Cancel </el-button>
|
||||
<el-button type="primary" @click="handleSaveAddContent">
|
||||
<!-- <i class="el-icon-finished" style="margin-right: 5px"></i> -->
|
||||
Save
|
||||
@@ -427,6 +433,7 @@ import bus from '@/components/common/bus';
|
||||
import { del, isShallow } from 'vue';
|
||||
import Tiff from 'tiff.js';
|
||||
import { mediaUrl } from '@/common/js/commonJS.js'; // 引入通用逻辑
|
||||
import { LATEX_DATA_HTML_DATA, MATH_FORMULA_TABLE_TITLE } from '@/utils/mathFormulaModule';
|
||||
import Tinymce from '@/components/page/components/Tinymce';
|
||||
import bottomTinymce from '@/components/page/components/Tinymce';
|
||||
import catalogue from '@/components/page/components/OnlineProofreading/catalogue.vue';
|
||||
@@ -451,6 +458,7 @@ export default {
|
||||
editVisible: false,
|
||||
currentId: null,
|
||||
ManuscirptContent: [],
|
||||
mathFormulasList: [],
|
||||
articleId: this.$route.query.id,
|
||||
isShowComment: false,
|
||||
urlList: {
|
||||
@@ -1354,6 +1362,54 @@ export default {
|
||||
this.lineStyle.visiTitle = 'Add Table';
|
||||
this.threeVisible = true;
|
||||
},
|
||||
onMathFormulasChange(payload) {
|
||||
this.mathFormulasList = (payload && payload.list) || [];
|
||||
},
|
||||
onLatexAdded(data) {
|
||||
if (this.$refs.commonWordHtmlTypeSetting) {
|
||||
this.$refs.commonWordHtmlTypeSetting.onMathFormulaAdded(data);
|
||||
}
|
||||
},
|
||||
onLatexUpdated(data) {
|
||||
if (this.$refs.commonWordHtmlTypeSetting) {
|
||||
this.$refs.commonWordHtmlTypeSetting.onMathFormulaUpdated(data);
|
||||
}
|
||||
},
|
||||
async handleImportWordMath(file) {
|
||||
if (!file) return;
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
text: this.$t('commonTable.importWordMathLoading'),
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
});
|
||||
try {
|
||||
const html = await this.$commonJS.importWordDocumentWithMath(file);
|
||||
const { tableData } = this.$commonJS.extractWmathTableDataFromHtml(html);
|
||||
if (!tableData || tableData.length === 0) {
|
||||
this.$message.warning(this.$t('commonTable.importWordMathNoFormula'));
|
||||
return;
|
||||
}
|
||||
const res = await this.$api.post(this.urlList.addTable, {
|
||||
article_id: this.articleId,
|
||||
table_data: JSON.stringify(tableData),
|
||||
html_data: LATEX_DATA_HTML_DATA,
|
||||
note: '',
|
||||
title: MATH_FORMULA_TABLE_TITLE
|
||||
});
|
||||
if (res.code == 0) {
|
||||
this.$message.success(this.$t('commonTable.importWordMathSuccess'));
|
||||
this.$refs.commonWordHtmlTypeSetting.refresh('addTable', res.data);
|
||||
} else {
|
||||
this.$message.error(res.msg || this.$t('commonTable.importWordMathFail'));
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('handleImportWordMath failed', err);
|
||||
this.$message.error(this.$t('commonTable.importWordMathFail'));
|
||||
} finally {
|
||||
loading.close();
|
||||
}
|
||||
},
|
||||
addUploadWordTable(data) {
|
||||
this.lineStyle = { note: '', table: data.table_data, html_data: data.html_data };
|
||||
|
||||
@@ -1367,16 +1423,16 @@ export default {
|
||||
this.picStyle = { ...data, extension: extension, picUrl: data.url };
|
||||
this.picStyle.visiTitle = 'Edit Figure';
|
||||
this.pictVisible = true;
|
||||
} else if (type == 'table') {
|
||||
} else if (type == 'table' || type == 'math') {
|
||||
this.lineStyle = {};
|
||||
this.lineStyle = {
|
||||
...data,
|
||||
table: JSON.parse(data.table_data),
|
||||
table: data.table || (data.table_data ? JSON.parse(data.table_data) : []),
|
||||
html_data: data.html_data,
|
||||
note: data.note,
|
||||
title: data.title
|
||||
};
|
||||
this.lineStyle.visiTitle = 'Edit Table';
|
||||
this.lineStyle.visiTitle = type == 'math' ? 'Edit Math Formula' : 'Edit Table';
|
||||
this.threeVisible = true;
|
||||
}
|
||||
},
|
||||
@@ -1757,7 +1813,7 @@ export default {
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
});
|
||||
if (content && cleanedTableList && cleanedTableList.length > 0) {
|
||||
if (this.lineStyle.visiTitle == 'Edit Table') {
|
||||
if (this.lineStyle.visiTitle == 'Edit Table' || this.lineStyle.visiTitle == 'Edit Math Formula') {
|
||||
this.$api
|
||||
.post(this.urlList.editTable, {
|
||||
amt_id: this.lineStyle.amt_id,
|
||||
|
||||
@@ -1882,12 +1882,12 @@
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
|
||||
|
||||
.el-image {
|
||||
|
||||
}
|
||||
.journal-cover.el-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.journal-abbreviation {
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
|
||||
@@ -7,7 +7,24 @@
|
||||
<div class="table-paper-view" @click.stop>
|
||||
<div class="close-icon-top" @click="close">×</div>
|
||||
|
||||
<div v-if="type === 'table' && processedItem" class="thumbnailTableBox wordTableHtml table_Box pMain">
|
||||
<div v-if="type === 'table' && processedItem && isLatexDataPreview" class="latex-data-preview">
|
||||
<div class="tableTitle font">
|
||||
<span v-html="renderText(processedItem.title)"></span>
|
||||
</div>
|
||||
<div
|
||||
v-for="item in latexFormulaItems"
|
||||
:key="item.index"
|
||||
class="latex-preview-row"
|
||||
>
|
||||
<span class="latex-preview-index">{{ item.index }}</span>
|
||||
<span class="latex-preview-content" v-html="item.html"></span>
|
||||
</div>
|
||||
<div v-if="processedItem.note" class="tableNote font">
|
||||
<span v-html="renderText(processedItem.note)"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="type === 'table' && processedItem" class="thumbnailTableBox wordTableHtml table_Box pMain">
|
||||
<div class="tableTitle font">
|
||||
<span v-html="renderText(processedItem.title)"></span>
|
||||
</div>
|
||||
@@ -58,6 +75,7 @@
|
||||
<script>
|
||||
import { TableUtils } from '@/common/js/TableUtils';
|
||||
import { mediaUrl } from '@/common/js/commonJS.js';
|
||||
import { isMathFormulaTableTitle, parseFormulaRowsFromTableData } from '@/utils/mathFormulaModule';
|
||||
|
||||
export default {
|
||||
name: 'TablePreviewer',
|
||||
@@ -70,6 +88,20 @@ export default {
|
||||
mediaUrl,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isLatexDataPreview() {
|
||||
return this.processedItem && isMathFormulaTableTitle(this.processedItem.title);
|
||||
},
|
||||
latexFormulaItems() {
|
||||
if (!this.isLatexDataPreview || !this.processedItem) return [];
|
||||
const raw = this.processedItem.table;
|
||||
const tableList = typeof raw === 'string' ? JSON.parse(raw) : raw;
|
||||
return parseFormulaRowsFromTableData(tableList).map((row, index) => ({
|
||||
index: index + 1,
|
||||
html: row[0] && row[0].text ? row[0].text : ''
|
||||
}));
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async open(type, item,isNoBg) {
|
||||
this.visible = true;
|
||||
@@ -79,16 +111,20 @@ export default {
|
||||
this.loading = true;
|
||||
setTimeout(() => {
|
||||
try {
|
||||
const processed = this.processTableData(item.table);
|
||||
this.processedItem = Object.freeze({
|
||||
...item,
|
||||
table: {
|
||||
...item.table,
|
||||
tableHeader: processed.tableHeader,
|
||||
tableContent: processed.tableContent,
|
||||
oddRowIds: isNoBg ? [] : processed.oddRowIds
|
||||
}
|
||||
});
|
||||
if (isMathFormulaTableTitle(item.title)) {
|
||||
this.processedItem = Object.freeze({ ...item });
|
||||
} else {
|
||||
const processed = this.processTableData(item.table);
|
||||
this.processedItem = Object.freeze({
|
||||
...item,
|
||||
table: {
|
||||
...item.table,
|
||||
tableHeader: processed.tableHeader,
|
||||
tableContent: processed.tableContent,
|
||||
oddRowIds: isNoBg ? [] : processed.oddRowIds
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("解析表格失败", err);
|
||||
} finally {
|
||||
@@ -265,4 +301,45 @@ export default {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.latex-data-preview {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.latex-preview-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 6px 0;
|
||||
border-bottom: 1px solid #f0f2f5;
|
||||
}
|
||||
|
||||
.latex-preview-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.latex-preview-index {
|
||||
flex-shrink: 0;
|
||||
width: 24px;
|
||||
text-align: right;
|
||||
font-size: 14px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.latex-preview-content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: 16px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.latex-preview-content ::v-deep wmath {
|
||||
display: inline !important;
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
.latex-preview-content ::v-deep mjx-container {
|
||||
font-size: 16px !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
</style>
|
||||
1277
src/components/page/components/table/LatexDataPanel.vue
Normal file
1277
src/components/page/components/table/LatexDataPanel.vue
Normal file
File diff suppressed because it is too large
Load Diff
@@ -37,6 +37,35 @@
|
||||
<ul class="operateBox">
|
||||
<div class="base-border base-padding-all" :style="{ '--br': '1px', '--p': '0 20px' }">
|
||||
<ul class="HTitleBox" style="border: none">
|
||||
<li class="latex-toolbar-item">
|
||||
<el-popover
|
||||
v-model="latexPopoverVisible"
|
||||
placement="bottom-start"
|
||||
width="720"
|
||||
trigger="manual"
|
||||
popper-class="latex-toolbar-popover"
|
||||
append-to-body
|
||||
@hide="onLatexPopoverHide"
|
||||
>
|
||||
<latex-data-panel
|
||||
ref="latexDataPanel"
|
||||
:article-id="articleId"
|
||||
:list="mathFormulasList"
|
||||
layout="popover"
|
||||
@added="onLatexAdded"
|
||||
@updated="onLatexUpdated"
|
||||
@close-popover="closeLatexPopover"
|
||||
/>
|
||||
<span
|
||||
slot="reference"
|
||||
class="latex-toolbar-trigger"
|
||||
@click.stop="toggleLatexPopover"
|
||||
>
|
||||
<i class="el-icon-s-data latex-toolbar-icon"></i>
|
||||
{{ $t('commonTable.mathFormula') }}
|
||||
</span>
|
||||
</el-popover>
|
||||
</li>
|
||||
<li
|
||||
@click="addContent"
|
||||
class="base-font-size base-bg-imp base-padding-all"
|
||||
@@ -184,8 +213,8 @@
|
||||
item.is_h1
|
||||
? 'isTitleH1 pMainH1'
|
||||
: item.is_h2
|
||||
? 'isTitleH2'
|
||||
: item.is_h3
|
||||
? 'isTitleH2'
|
||||
: item.is_h3
|
||||
? 'isTitleH3'
|
||||
: ''
|
||||
"
|
||||
@@ -202,10 +231,11 @@
|
||||
|
||||
<div :class="currentId == item.am_id ? 'glowing-border' : ''" style="position: relative">
|
||||
<div
|
||||
class="base-bg base-pos"
|
||||
class="base-bg base-pos paragraph-select-overlay"
|
||||
:style="{ '--p-r': '0px', '--p-t': '-40px' }"
|
||||
v-if="currentId == item.am_id"
|
||||
style="z-index: 100"
|
||||
@click.stop="onParagraphSelectOverlayClick(item)"
|
||||
></div>
|
||||
|
||||
<div
|
||||
@@ -1035,9 +1065,12 @@ const toolbar = 'addImageButton ';
|
||||
import { TableUtils } from '@/common/js/TableUtils';
|
||||
import { debounce, throttle } from '@/common/js/debounce';
|
||||
import { tableStyle, commonWordStyle } from '@/utils/tinymceStyles';
|
||||
import LatexDataPanel from './LatexDataPanel.vue';
|
||||
export default {
|
||||
name: 'tinymce',
|
||||
components: {},
|
||||
components: {
|
||||
LatexDataPanel
|
||||
},
|
||||
props: {
|
||||
id: {
|
||||
type: String
|
||||
@@ -1098,6 +1131,12 @@ export default {
|
||||
wordStyle: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
mathFormulasList: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -1216,7 +1255,10 @@ export default {
|
||||
|
||||
displayList: [],
|
||||
currentTypeText: '',
|
||||
tinymceId: this.id || 'vue-tinymce-' + +new Date()
|
||||
tinymceId: this.id || 'vue-tinymce-' + +new Date(),
|
||||
latexPopoverVisible: false,
|
||||
_latexPopoverScrollHandler: null,
|
||||
_latexPopoverOutsideHandler: null
|
||||
|
||||
};
|
||||
},
|
||||
@@ -1247,6 +1289,17 @@ export default {
|
||||
}
|
||||
},
|
||||
deep: true // 启用深度监听
|
||||
},
|
||||
latexPopoverVisible(val) {
|
||||
if (val) {
|
||||
this.$nextTick(() => {
|
||||
this.bindLatexPopoverScrollListener();
|
||||
setTimeout(() => this.bindLatexPopoverOutsideClick(), 0);
|
||||
});
|
||||
} else {
|
||||
this.unbindLatexPopoverScrollListener();
|
||||
this.unbindLatexPopoverOutsideClick();
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -1362,6 +1415,8 @@ export default {
|
||||
// window.removeEventListener('resize', this.calcMarkers);
|
||||
if (this.resizeObs) this.resizeObs.disconnect();
|
||||
if (this.mutObs) this.mutObs.disconnect();
|
||||
this.unbindLatexPopoverScrollListener();
|
||||
this.unbindLatexPopoverOutsideClick();
|
||||
|
||||
// 页面销毁前清理定时器和事件监听器
|
||||
},
|
||||
@@ -2145,6 +2200,62 @@ export default {
|
||||
return;
|
||||
}
|
||||
},
|
||||
onLatexAdded(data) {
|
||||
this.$emit('latexAdded', data);
|
||||
},
|
||||
onLatexUpdated(data) {
|
||||
this.$emit('latexUpdated', data);
|
||||
},
|
||||
toggleLatexPopover() {
|
||||
this.latexPopoverVisible = !this.latexPopoverVisible;
|
||||
},
|
||||
closeLatexPopover() {
|
||||
this.latexPopoverVisible = false;
|
||||
},
|
||||
onLatexPopoverHide() {
|
||||
const panel = this.$refs.latexDataPanel;
|
||||
if (panel && typeof panel.dismissEditing === 'function') {
|
||||
panel.dismissEditing();
|
||||
}
|
||||
},
|
||||
bindLatexPopoverScrollListener() {
|
||||
this.unbindLatexPopoverScrollListener();
|
||||
this._latexPopoverScrollHandler = () => {
|
||||
if (this.latexPopoverVisible) {
|
||||
this.closeLatexPopover();
|
||||
}
|
||||
};
|
||||
const scrollEl = this.$refs.scroll;
|
||||
if (scrollEl) {
|
||||
scrollEl.addEventListener('scroll', this._latexPopoverScrollHandler, { passive: true });
|
||||
}
|
||||
},
|
||||
unbindLatexPopoverScrollListener() {
|
||||
if (!this._latexPopoverScrollHandler) return;
|
||||
const scrollEl = this.$refs.scroll;
|
||||
if (scrollEl) {
|
||||
scrollEl.removeEventListener('scroll', this._latexPopoverScrollHandler);
|
||||
}
|
||||
this._latexPopoverScrollHandler = null;
|
||||
},
|
||||
bindLatexPopoverOutsideClick() {
|
||||
this.unbindLatexPopoverOutsideClick();
|
||||
this._latexPopoverOutsideHandler = (e) => {
|
||||
if (!this.latexPopoverVisible) return;
|
||||
const target = e.target;
|
||||
if (!target) return;
|
||||
if (target.closest && target.closest('.latex-toolbar-trigger')) return;
|
||||
if (target.closest && target.closest('.latex-toolbar-popover')) return;
|
||||
if (target.closest && target.closest('.latex-toolbar-item')) return;
|
||||
this.closeLatexPopover();
|
||||
};
|
||||
document.addEventListener('mousedown', this._latexPopoverOutsideHandler, true);
|
||||
},
|
||||
unbindLatexPopoverOutsideClick() {
|
||||
if (!this._latexPopoverOutsideHandler) return;
|
||||
document.removeEventListener('mousedown', this._latexPopoverOutsideHandler, true);
|
||||
this._latexPopoverOutsideHandler = null;
|
||||
},
|
||||
|
||||
cacheSelection() {
|
||||
const selection = window.getSelection();
|
||||
@@ -2913,6 +3024,12 @@ export default {
|
||||
}
|
||||
});
|
||||
},
|
||||
onParagraphSelectOverlayClick(item) {
|
||||
if (this.isPreview) return;
|
||||
if (item && item.am_id) {
|
||||
this.$set(this, 'currentId', item.am_id);
|
||||
}
|
||||
},
|
||||
async handleGeneralClick(event, item, index) {
|
||||
// 1. 如果有原有的 span 点击逻辑,先执行(或根据条件判断)
|
||||
if (typeof this.onProofSpanClick === 'function') {
|
||||
@@ -4078,6 +4195,15 @@ export default {
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.HTitleBox li.latex-toolbar-item {
|
||||
padding: 2px 10px;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
background-color: rgb(43, 129, 239);
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
height: 26px;
|
||||
}
|
||||
.operateBox {
|
||||
width: auto;
|
||||
display: flex;
|
||||
@@ -4542,6 +4668,52 @@ font-weight: bold !important;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.latex-toolbar-item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
list-style: none;
|
||||
padding: 2px 10px;
|
||||
margin-left: 10px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background-color: rgb(43, 129, 239);
|
||||
height: 26px;
|
||||
}
|
||||
|
||||
.latex-toolbar-trigger {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
line-height: 1.4;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.latex-toolbar-trigger:hover {
|
||||
opacity: 0.9;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.latex-toolbar-icon {
|
||||
margin-right: 4px;
|
||||
font-size: 13px;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.latex-toolbar-popover {
|
||||
padding: 10px 12px !important;
|
||||
box-sizing: border-box;
|
||||
min-width: 520px;
|
||||
height: 400px;
|
||||
max-height: 400px;
|
||||
overflow: hidden;
|
||||
border-radius: 8px !important;
|
||||
box-shadow: 0 4px 18px rgba(0, 0, 0, 0.12) !important;
|
||||
}
|
||||
</style>
|
||||
<style scoped lang="less">
|
||||
.glowing-border {
|
||||
@@ -4555,6 +4727,18 @@ font-weight: bold !important;
|
||||
.pMain {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.paragraph-select-overlay {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
background: transparent;
|
||||
}
|
||||
::v-deep wmath[data-wrap='inline'] {
|
||||
display: inline-block !important;
|
||||
width: auto !important;
|
||||
|
||||
@@ -473,7 +473,8 @@
|
||||
|
||||
<script>
|
||||
import DynamicTable from './DynamicTable.vue';
|
||||
import { mediaUrl } from '@/common/js/commonJS.js'; // 引入通用逻辑
|
||||
import { mediaUrl } from '@/common/js/commonJS.js';
|
||||
import { isMathFormulaTableTitle, normalizeLatexTableApiResponse } from '@/utils/mathFormulaModule';
|
||||
|
||||
export default {
|
||||
props: ['articleId', 'imgWidth', 'imgHeight', 'scale', 'isEdit', 'isShowEdit', 'urlList', 'content'],
|
||||
@@ -498,8 +499,10 @@ export default {
|
||||
],
|
||||
images: [],
|
||||
tables: [],
|
||||
mathFormulas: [],
|
||||
imagesList: [],
|
||||
tablesList: [],
|
||||
mathFormulasList: [],
|
||||
tablesHtml: [],
|
||||
imagesHtml: [],
|
||||
activeNames: ['images', 'tables']
|
||||
@@ -620,6 +623,12 @@ export default {
|
||||
addTable() {
|
||||
this.$emit('addTable');
|
||||
},
|
||||
onMathFormulaAdded(data) {
|
||||
this.refresh('addTable', normalizeLatexTableApiResponse(data));
|
||||
},
|
||||
onMathFormulaUpdated(data) {
|
||||
this.refresh('editTable', normalizeLatexTableApiResponse(data));
|
||||
},
|
||||
handlePaperclip() {
|
||||
this.$emit('handlePaperclip');
|
||||
},
|
||||
@@ -638,11 +647,7 @@ export default {
|
||||
handleSelectMenu(v) {
|
||||
this.currentMenu = v;
|
||||
this.currentSelectType = '0';
|
||||
// if (v == 1) {
|
||||
// this.getCommentList();
|
||||
// } else {
|
||||
this.filterData();
|
||||
// }
|
||||
},
|
||||
selectType(v) {
|
||||
this.currentSelectType = v.type;
|
||||
@@ -663,14 +668,37 @@ export default {
|
||||
|
||||
}
|
||||
this.filterData('table');
|
||||
} else if (type == 'math') {
|
||||
const indexInList = this.mathFormulas.findIndex((item) => item.amt_id == id);
|
||||
if (indexInList !== -1) {
|
||||
this.mathFormulas.splice(indexInList, 1);
|
||||
}
|
||||
this.filterData('math');
|
||||
}
|
||||
},
|
||||
isMathFormulaTable(item) {
|
||||
return item && isMathFormulaTableTitle(item.title);
|
||||
},
|
||||
splitTablesAndMathFormulas(list) {
|
||||
const tables = [];
|
||||
const mathFormulas = [];
|
||||
(list || []).forEach((item) => {
|
||||
if (this.isMathFormulaTable(item)) {
|
||||
mathFormulas.push(item);
|
||||
} else {
|
||||
tables.push(item);
|
||||
}
|
||||
});
|
||||
return { tables, mathFormulas };
|
||||
},
|
||||
filterData(type) {
|
||||
if (type) {
|
||||
if (type == 'img') {
|
||||
this.imagesList = [...this.images];
|
||||
} else if (type == 'table') {
|
||||
this.tablesList = [...this.tables];
|
||||
} else if (type == 'math') {
|
||||
this.mathFormulasList = [...this.mathFormulas];
|
||||
}
|
||||
} else {
|
||||
if (this.currentMenu == 1) {
|
||||
@@ -689,7 +717,6 @@ export default {
|
||||
switch (this.currentSelectType) {
|
||||
case '0':
|
||||
this.tablesList = [...this.tables];
|
||||
// console.log('this.tablesList at line 393:', this.tablesList);
|
||||
break;
|
||||
case '1':
|
||||
this.tablesList = [...this.tables].filter((e) => e.has_selected == 1);
|
||||
@@ -701,6 +728,13 @@ export default {
|
||||
} else {
|
||||
}
|
||||
}
|
||||
this.mathFormulasList = [...this.mathFormulas];
|
||||
this.emitMathFormulasChange();
|
||||
},
|
||||
emitMathFormulasChange() {
|
||||
this.$emit('mathFormulasChange', {
|
||||
list: [...this.mathFormulasList]
|
||||
});
|
||||
},
|
||||
goToListComment(id, type) {
|
||||
this.$emit('goToListComment', id, type);
|
||||
@@ -717,15 +751,22 @@ export default {
|
||||
})
|
||||
},
|
||||
async refresh(type, newData) {
|
||||
|
||||
const normalized = normalizeLatexTableApiResponse(newData || {});
|
||||
var tableIndex;
|
||||
var mathIndex;
|
||||
var imgIndex;
|
||||
var tableData
|
||||
|
||||
if(newData.amt_id ) {
|
||||
tableIndex = this.tables.findIndex((table) => table.amt_id == newData.amt_id);
|
||||
tableData = newData.table_data?JSON.parse(newData.table_data):[];
|
||||
var tableData = normalized.table || [];
|
||||
|
||||
if (normalized.amt_id) {
|
||||
mathIndex = this.mathFormulas.findIndex((item) => {
|
||||
const itemId = item.amt_id || item.ant_id || item.article_table_id;
|
||||
return itemId != null && String(itemId) === String(normalized.amt_id);
|
||||
});
|
||||
if (mathIndex === -1) {
|
||||
tableIndex = this.tables.findIndex((table) => table.amt_id == normalized.amt_id);
|
||||
}
|
||||
}
|
||||
newData = normalized;
|
||||
if(newData.ami_id) {
|
||||
imgIndex = this.images.findIndex((img) => img.ami_id == newData.ami_id);
|
||||
}
|
||||
@@ -760,13 +801,38 @@ if(newData.ami_id) {
|
||||
|
||||
|
||||
|
||||
this.tables.push({
|
||||
...newData,
|
||||
article_table_id: newData.amt_id,
|
||||
table: tableData
|
||||
});
|
||||
if (this.isMathFormulaTable(newData)) {
|
||||
const mathIdx = this.mathFormulas.findIndex(
|
||||
(item) => item.amt_id == newData.amt_id
|
||||
);
|
||||
const payload = {
|
||||
...newData,
|
||||
article_table_id: newData.amt_id,
|
||||
table: tableData
|
||||
};
|
||||
if (mathIdx !== -1) {
|
||||
this.mathFormulas[mathIdx] = payload;
|
||||
} else if (this.mathFormulas.length > 0) {
|
||||
this.mathFormulas[0] = payload;
|
||||
} else {
|
||||
this.mathFormulas.push(payload);
|
||||
}
|
||||
} else {
|
||||
this.tables.push({
|
||||
...newData,
|
||||
article_table_id: newData.amt_id,
|
||||
table: tableData
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'editTable':
|
||||
if (tableIndex !== -1) {
|
||||
if (mathIndex !== -1) {
|
||||
this.mathFormulas[mathIndex] = {
|
||||
...newData,
|
||||
article_table_id: newData.amt_id,
|
||||
table: tableData
|
||||
};
|
||||
} else if (tableIndex !== -1) {
|
||||
this.tables[tableIndex] = {
|
||||
|
||||
...newData,
|
||||
@@ -793,14 +859,18 @@ if(newData.ami_id) {
|
||||
break;
|
||||
case 'removeTable':
|
||||
|
||||
if (tableIndex !== -1) {
|
||||
if (mathIndex !== -1) {
|
||||
this.mathFormulas[mathIndex].has_selected = 0;
|
||||
} else if (tableIndex !== -1) {
|
||||
this.tables[tableIndex].has_selected = 0;
|
||||
|
||||
}
|
||||
break;
|
||||
case 'positioningTable':
|
||||
|
||||
if (tableIndex !== -1) {
|
||||
if (mathIndex !== -1) {
|
||||
this.mathFormulas[mathIndex].has_selected = 1;
|
||||
} else if (tableIndex !== -1) {
|
||||
this.tables[tableIndex].has_selected = 1;
|
||||
|
||||
}
|
||||
@@ -900,8 +970,9 @@ if(newData.ami_id) {
|
||||
article_id: this.articleId
|
||||
})
|
||||
.then(async (res) => {
|
||||
let parsedList = [];
|
||||
if (this.urlList) {
|
||||
this.tables =
|
||||
parsedList =
|
||||
res.data.list && res.data.list.length > 0
|
||||
? res.data.list.map((e) => {
|
||||
return {
|
||||
@@ -912,7 +983,7 @@ if(newData.ami_id) {
|
||||
})
|
||||
: [];
|
||||
} else {
|
||||
this.tables =
|
||||
parsedList =
|
||||
res.data.list && res.data.list.length > 0
|
||||
? res.data.list.map((e) => {
|
||||
return {
|
||||
@@ -923,7 +994,11 @@ if(newData.ami_id) {
|
||||
})
|
||||
: [];
|
||||
}
|
||||
const split = this.splitTablesAndMathFormulas(parsedList);
|
||||
this.tables = split.tables;
|
||||
this.mathFormulas = split.mathFormulas;
|
||||
await this.filterData('table');
|
||||
await this.filterData('math');
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user