Merge branch 'master' of https://git.nuttyreading.com/wangjinlei/tougao_web into Editorial-Board

This commit is contained in:
2025-12-24 16:22:22 +08:00
7 changed files with 610 additions and 786 deletions

View File

@@ -1149,9 +1149,9 @@ a {
mso-border-top-alt: none !important;
border-bottom: none !important;
mso-border-bottom-alt: none !important;
border: 1px dashed #dcdfe6 !important;
/* border: 1px dashed #dcdfe6 !important;
border-left: 1px dashed #dcdfe6 !important;
border-right: 1px dashed #dcdfe6 !important;
border-right: 1px dashed #dcdfe6 !important; */
word-break: keep-all !important;
/* text-align: justify !important; */
}
@@ -1283,7 +1283,7 @@ a {
}
.word-container table tbody tr td {
text-align: left !important;
text-align: center !important;
border-left: none !important;
mso-border-left-alt: none !important;
border-right: none !important;
@@ -1292,9 +1292,9 @@ a {
mso-border-top-alt: none !important;
border-bottom: none !important;
mso-border-bottom-alt: none !important;
border: 1px dashed #dcdfe6 !important;
/* border: 1px dashed #dcdfe6 !important;
border-left: 1px dashed #dcdfe6 !important;
border-right: 1px dashed #dcdfe6 !important;
border-right: 1px dashed #dcdfe6 !important; */
word-break: keep-all !important;
white-space: pre-wrap !important;
/* text-align: justify !important; */

102
src/common/js/TableUtils.js Normal file
View File

@@ -0,0 +1,102 @@
/**
* 表格数据处理工具
*/
export const TableUtils = {
/**
* 判断是否为表头行
* @param {number} rowIndex
* @param {Array} table
*/
isHeaderRow(rowIndex, table) {
if (!table || table.length === 0) return false;
const head = table[0];
// 健壮性检查确保第一行第一个单元格存在且有rowspan
const headerSpan = (head && head[0] && head[0].rowspan) ? head[0].rowspan : 1;
return rowIndex < headerSpan;
},
/**
* 拆分表头和表体
*/
splitTable(tableList) {
if (!Array.isArray(tableList) || tableList.length === 0) {
return { header: [], content: [] };
}
const header = [];
const content = [];
let cellIdCounter = 0;
tableList.forEach((row, rowIndex) => {
if (Array.isArray(row)) {
row.forEach((cell) => {
if (cell && typeof cell === 'object') {
cell.cellId = `cell-${cellIdCounter++}`;
}
});
}
if (this.isHeaderRow(rowIndex, tableList)) {
header.push(row);
} else {
content.push(row);
}
});
return { header, content };
},
/**
* 处理合并单元格后的逻辑行 ID用于斑马纹等
*/
addRowIdToData(content) {
if (!content || content.length === 0) return { rowData: [], rowIds: [] };
const data = JSON.parse(JSON.stringify(content));
const rowIdMap = {};
const usedRows = new Set();
let idCounter = 0;
// 1. 建立逻辑行映射
for (let i = 0; i < data.length; i++) {
if (usedRows.has(i)) continue;
const rowId = `row-${idCounter++}`;
rowIdMap[i] = rowId;
usedRows.add(i);
const row = data[i];
for (let j = 0; j < row.length; j++) {
const cell = row[j];
if (cell && cell.rowspan > 1) {
for (let k = 1; k < cell.rowspan; k++) {
const nextRowIndex = i + k;
if (nextRowIndex < data.length && !rowIdMap[nextRowIndex]) {
rowIdMap[nextRowIndex] = rowId;
usedRows.add(nextRowIndex);
}
}
}
}
}
// 2. 注入 rowId 并提取唯一 ID 列表
const seenIds = [];
data.forEach((row, i) => {
const rowId = rowIdMap[i];
row.rowId = rowId; // 直接赋值给行对象
row.forEach(cell => {
if (cell) cell.rowId = rowId;
});
if (rowId && !seenIds.includes(rowId)) {
seenIds.push(rowId);
}
});
// 取奇数或偶数 ID 用于斑马纹(根据你的需求 index % 2 === 0
const rowIds = seenIds.filter((_, index) => index % 2 === 0);
return { rowData: data, rowIds };
}
};

View File

@@ -1307,16 +1307,19 @@ export default {
},
handleImageAdd(type) {
this.picStyle = { note: '', picUrl: '', title: '' };
this.picStyle1 = { note: '', picUrl: '', title: '' };
this.picStyle.visiTitle = 'Add Figure';
this.pictVisible = true;
},
handleTableAdd(type) {
this.lineStyle = { note: '', table_data: '', html_data: '' };
this.lineStyle1 = { note: '', table_data: '', html_data: '' };
this.lineStyle.visiTitle = 'Add Table';
this.threeVisible = true;
},
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 };
this.lineStyle.visiTitle = 'Add Table';
this.threeVisible = true;
@@ -1330,13 +1333,18 @@ export default {
this.pictVisible = true;
} else if (type == 'table') {
this.lineStyle = {};
this.lineStyle = {
...data,
table: JSON.parse(data.table_data),
html_data: data.html_data,
note: data.note,
title: data.title
};
this.lineStyle1 = {};
// 1. 提取处理逻辑
const formattedData = {
...data,
table: JSON.parse(data.table_data),
// 如果 data 中已经包含了 html_data, note, title且不需要特殊处理
// 解构赋值 (...data) 其实已经把它们带进来了。
};
// 2. 统一赋值
this.lineStyle = formattedData;
this.lineStyle1 = { ...formattedData }; // 使用浅拷贝确保两个变量指向不同引用(如果需要独立修改)
this.lineStyle.visiTitle = 'Edit Table';
this.threeVisible = true;
}

View File

@@ -135,6 +135,9 @@
<template slot="comment">
<div style="" class="commentList annotations"></div>
</template>
<template slot="refrences">
<div style="" class="" main-id="References">222</div>
</template>
</common-word>
</div>
</div>
@@ -603,6 +606,7 @@ export default {
},
methods: {
async copyArray(data) {
try {
// 将数组内容转换为字符串,使用换行符分隔
@@ -1524,7 +1528,7 @@ export default {
for (let i = 0; i < this.Main_List.length; i++) {
this.Main_List[i].text = this.Main_List[i].content;
this.Main_List[i].getnum = 0;
// this.Main_List[i].checked = false;
}
// setTimeout(async () => {

View File

@@ -1,26 +1,20 @@
<template>
<div
style=""
class="ManuscirptList"
>
<div
style=""
class="arrlist"
>
<ul style="width: 100%; height: auto">
<li >
<div style="">
<div @click="goToListComment(item.am_id,'content')"
v-for="(item, index) in catalogueList"
:class="['catalogue-item', 'level-' + item.level]"
style=""
>
<div class="title-content" v-html="item.content"></div>
</div>
<div class="ManuscirptList">
<div class="arrlist">
<ul class="catalogue-ul">
<li class="catalogue-li">
<div
@click="goToListComment(item.am_id,'content')"
v-for="(item, index) in catalogueList"
:key="index"
:class="['catalogue-item', 'level-' + item.level]"
>
<div class="title-content-wrapper">
<div class="title-content" v-html="item.content"></div>
</div>
</div>
</li>
</ul>
@@ -86,7 +80,7 @@ export default {
this.catalogueList = this.content.filter(item => {
return item.is_h1 == 1 || item.is_h2 == 1 || item.is_h3 == 1;
return item.is_h1 == 1 || item.is_h2 == 1 ;
}).map(item => {
// 增加一个 level 字段进行标记
let level = 1;
@@ -98,8 +92,8 @@ this.catalogueList = this.content.filter(item => {
};
})
this.catalogueList=[...this.catalogueList,{
am_id:'reference',
content:'<b><i>References</i></b>',
am_id:'References',
content:'References',
level:1,
}]
@@ -477,58 +471,147 @@ console.log(this.catalogueList,'catalogueList')
</script>
<style scoped>
.ManuscirptList{
padding-top: 20px;
.ManuscirptList {
height: 100%;
padding: 0;
box-sizing: border-box;
background: #f5f5f5 !important;
background-color: #f5f5f5 !important; /* Word 导航栏通常是白色的 */
border-right: 1px solid #e1e1e1;
display: flex;
flex-direction: column;
}
.catalogue-item{
width: 90%;
white-space: nowrap; /* 强制不换行 */
overflow: hidden; /* 隐藏超出部分 */
text-overflow: ellipsis; /* 超出部分显示... */
box-sizing: border-box;
/* 模拟 Word 导航标题 */
.word-navigation-header {
padding: 12px 16px 0 16px;
font-size: 14px;
color: rgb(51, 51, 51);
color: #333;
font-family: "Segoe UI", "Microsoft YaHei", sans-serif;
}
.word-tabs {
display: flex;
margin-top: 10px;
border-bottom: 1px solid #e1e1e1;
}
.word-tabs span {
padding: 4px 12px;
font-size: 12px;
color: #666;
cursor: pointer;
padding: 4px 0px;
margin-left: 16px;
font-family: "Charis SIL";
word-wrap: break-word;
overflow: hidden;
position: relative;
}
.title-content,
.title-content span,
.title-content b {
display: inline; /* 强制内部标签不换行 */
font-weight: inherit; /* 继承父级的粗细设置,或者根据需要自定 */
font-size: inherit;
.word-tabs span.active {
color: #2b579a; /* Word 经典蓝色 */
font-weight: bold;
}
.word-tabs span.active::after {
content: "";
position: absolute;
bottom: -1px;
left: 0;
right: 0;
height: 2px;
background-color: #2b579a;
}
/* 列表容器 */
.arrlist {
flex: 1;
overflow-y: auto;
padding-top: 8px;
}
.catalogue-ul {
width: 100%;
list-style: none;
padding: 0;
margin: 0;
}
/* 基础条目样式 - 模拟 Word 悬浮效果 */
.catalogue-item {
position: relative;
width: 100%;
padding: 6px 16px;
cursor: pointer;
display: flex;
align-items: flex-start;
box-sizing: border-box;
transition: background-color 0.1s;
}
.catalogue-item:hover {
background-color: #e6f7ff;
color: #1890ff;
background-color: #eff3f9; /* Word 淡淡的选中蓝 */
}
/* 一级标题:加粗,无缩进 */
/* Word 样式的左侧小箭头 */
.word-icon-arrow {
width: 0;
height: 0;
border-left: 5px solid #666;
border-top: 4px solid transparent;
border-bottom: 4px solid transparent;
margin-right: 8px;
margin-top: 6px;
}
.title-content-wrapper {
flex: 1;
overflow: hidden;
}
/* 重点Word 常用排版字体 */
.title-content {
font-weight: bold !important;
font-style: normal !important;
font-size: 15px;
line-height: 1.3;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
/* Times New Roman 增加学术感 */
font-family: "Times New Roman", "Charis SIL", "serif";
color: #333;
}
/* 保持 v-html 内部样式 */
::v-deep .title-content b { font-weight: bold; }
::v-deep .title-content i { font-style: italic; }
/* --- Word 风格的层级缩进 --- */
/* 1级标题 */
.level-1 {
font-weight: bold;
padding-left: 0;
/* margin-top: 8px; */
padding-left: 16px;
/* font-style: italic; */
}
/* 级标题:标准字体,缩进 20px */
/* 2级标题 */
.level-2 {
padding-left: 20px;
color: #555;
padding-left: 36px;
}
.level-2 .title-content {
font-size: 14px;
}
/* 级标题:稍细字体,缩进 40px */
/* 3级标题 */
.level-3 {
padding-left: 40px;
color: #888;
font-style: italic; /* 模仿 Word 的一些三级样式 */
padding-left: 56px;
}
.level-3 .title-content {
font-size: 14px;
color: #666;
}
/* 隐藏滚动条 */
.arrlist::-webkit-scrollbar {
width: 5px;
}
.arrlist::-webkit-scrollbar-thumb {
background: #cdcdcd;
}
</style>

View File

@@ -9,7 +9,10 @@ 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{
const tableStyle = `*{
font-family: 'Charis SIL';
}
b span{
font-weight: bold !important;
}
i span{

File diff suppressed because it is too large Load Diff