This commit is contained in:
2025-06-25 17:27:34 +08:00
parent ccf62b4bc9
commit f6622a742c
7 changed files with 3492 additions and 330 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,11 @@
<template> <template>
<div style="height: 100%"> <div style="height: 100%">
<el-row style="margin-top: 0%; height: 100%">
<div style="display: flex; align-items: center; height: 100%">
<!-- 左侧 列表 -->
<!-- 右侧 用户列表 -->
<div :class="[drawer ? 'right' : 'right1']" style="height: 100%">
<div <div
class="container" class="container"
style=" style="
@@ -14,6 +20,7 @@
" "
> >
<div <div
v-show="!drawer"
class="right-side" class="right-side"
style=" style="
width: 285px; width: 285px;
@@ -75,7 +82,11 @@
<input type="file" ref="fileInput" style="display: none" @change="handleFileChange" /> <input type="file" ref="fileInput" style="display: none" @change="handleFileChange" />
</div> </div>
</div> </div>
<div style="width: 100%; width: calc(100% - 285px); float: right; height: calc(100% - 0px); background-color: #e4e9ed"> <div
:style="`width: ${
drawer ? '100%' : 'calc(100% - 285px)'
}; float: right; height: calc(100% - 0px); background-color: #e4e9ed`"
>
<!-- <div class="toolbar"> <!-- <div class="toolbar">
<div class="toolbar_item" @click="handleImageAdd('img')"> <div class="toolbar_item" @click="handleImageAdd('img')">
<img src="@/assets/img/upload.png" style="object-fit: contain" /> <img src="@/assets/img/upload.png" style="object-fit: contain" />
@@ -94,6 +105,7 @@
:value="htmlContent" :value="htmlContent"
:contentList="Main_List" :contentList="Main_List"
:comments="comments" :comments="comments"
:drawer="drawer"
:wordStyle="wordStyle" :wordStyle="wordStyle"
@onDrop="onDrop" @onDrop="onDrop"
@saveContent="saveContent" @saveContent="saveContent"
@@ -123,6 +135,48 @@
</common-word> </common-word>
</div> </div>
</div> </div>
</div>
<div :class="[drawer ? 'left' : 'left1']" style="height: 100%">
<div >
<div style="height: 56px; background-color: #fff; padding: 20px; box-sizing: border-box" v-if="currentContent&&currentContent.type == 1">Image</div>
<div style="height: 56px; background-color: #fff; padding: 20px; box-sizing: border-box" v-if="currentContent&&currentContent.type == 2">Table</div>
<div style="height: 56px; background-color: #fff; padding: 20px; box-sizing: border-box" v-if="currentContent&&currentContent.type == 0">Content</div>
<div style="padding: 20px 10px; box-sizing: border-box">
<common-content
:value="currentContent ? currentContent.content : ''"
@getContent="getContent"
@openLatexEditor="openLatexEditor"
ref="commonContent1"
height="78vh"
></common-content>
</div>
<div style="float: right">
<el-button @click="drawer = false"> Cancel </el-button>
<el-button type="primary" @click="handleSaveContent" style="margin-right:20px ;"> Save </el-button>
</div>
</div>
</div>
<!-- 折叠展开图片-->
<!-- <div
style="cursor: pointer; width: 5%;z-index: 9999;"
:class="[drawer ? 'imgright' : 'imgright1']"
@click="clickImg"
>
<img
v-show="!drawer"
style="height: 40px; width: 25px"
src=""
/>
<img
v-show="drawer"
style="height: 40px; width: 25px"
src=""
/>
</div> -->
</div>
</el-row>
<!--添加/修改图片 --> <!--添加/修改图片 -->
<el-dialog :title="picStyle.visiTitle" :visible.sync="pictVisible" width="1200px" :close-on-click-modal="false"> <el-dialog :title="picStyle.visiTitle" :visible.sync="pictVisible" width="1200px" :close-on-click-modal="false">
@@ -271,14 +325,20 @@
<div v-for="(item, i) in uploadWordTables" class="uploadWordTableBox"> <div v-for="(item, i) in uploadWordTables" class="uploadWordTableBox">
<el-button @click="addUploadWordTable(item)" size="mini" class="insertTable"> 插入 </el-button> <el-button @click="addUploadWordTable(item)" size="mini" class="insertTable"> 插入 </el-button>
<div class="thumbnailTableBox wordTableHtml table_Box pMain myeditabledivTable drop-target"> <div class="thumbnailTableBox wordTableHtml table_Box pMain myeditabledivTable drop-target">
<p style="font-size: 12px;padding: 10px;box-sizing: border-box;">Table {{ i + 1 }}</p> <p style="font-size: 12px; padding: 10px; box-sizing: border-box">Table {{ i + 1 }}</p>
<table border="1" :style="`width: 800px;zoom:${zoomNum};border-collapse: collapse; text-align: center`"> <table border="1" :style="`width: 800px;zoom:${zoomNum};border-collapse: collapse; text-align: center`">
<tr <tr
v-for="(row, i) in item.table_data" v-for="(row, i) in item.table_data"
:key="i" :key="i"
:class="{ 'table-header-row': isHeaderRow(i, item.table_data) }" :class="{ 'table-header-row': isHeaderRow(i, item.table_data) }"
> >
<td style="font-size: 20px;"v-for="(cell, i1) in row" :key="i1" :colspan="`${cell.colspan || 1}`" :rowspan="`${cell.rowspan || 1}`"> <td
style="font-size: 20px"
v-for="(cell, i1) in row"
:key="i1"
:colspan="`${cell.colspan || 1}`"
:rowspan="`${cell.rowspan || 1}`"
>
<span v-html="cell.text"></span> <span v-html="cell.text"></span>
</td> </td>
</tr> </tr>
@@ -407,7 +467,8 @@ import bottomTinymce from '@/components/page/components/Tinymce';
export default { export default {
data() { data() {
return { return {
zoomNum:(window.innerWidth * 0.38) / 850, drawer: false,
zoomNum: (window.innerWidth * 0.38) / 850,
uploadWordTables: [], uploadWordTables: [],
tablesHtmlVisible: false, tablesHtmlVisible: false,
tablesHtml: '', tablesHtml: '',
@@ -570,7 +631,9 @@ export default {
}, },
methods: { methods: {
clickImg() {
this.drawer = !this.drawer;
},
async copyArray(data) { async copyArray(data) {
try { try {
// 将数组内容转换为字符串,使用换行符分隔 // 将数组内容转换为字符串,使用换行符分隔
@@ -621,7 +684,7 @@ export default {
// } // }
// }, // },
handleSaveContent() { handleSaveContent() {
this.$refs.commonContent.getTinymceContent('content'); this.$refs.commonContent1.getTinymceContent('content');
}, },
handleSaveAddContent() { handleSaveAddContent() {
this.$refs.addContent.getTinymceContent('addcontent'); this.$refs.addContent.getTinymceContent('addcontent');
@@ -1136,14 +1199,14 @@ export default {
}); });
// 处理文件上传并传递回调函数 // 处理文件上传并传递回调函数
this.$commonJS.handleFileUpload(event, function (tables) { this.$commonJS.handleFileUpload(event, function (tables) {
console.log('tables at line 1138:', tables) console.log('tables at line 1138:', tables);
if(tables.length == 0){ if (tables.length == 0) {
loading.close() loading.close();
that.$message({ that.$message({
type: 'warning', type: 'warning',
message: 'No table found!' message: 'No table found!'
}); });
return false return false;
} }
// 使用 Promise.all 等待所有表格解析完成 // 使用 Promise.all 等待所有表格解析完成
@@ -1152,8 +1215,6 @@ export default {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// 解析每个表格 // 解析每个表格
that.$commonJS.parseTableToArray(table, (tableList) => { that.$commonJS.parseTableToArray(table, (tableList) => {
resolve({ table_data: tableList, html_data: '' }); resolve({ table_data: tableList, html_data: '' });
}); });
}); });
@@ -1162,11 +1223,11 @@ export default {
.then((result) => { .then((result) => {
// 所有表格的解析完成后,处理结果 // 所有表格的解析完成后,处理结果
that.uploadWordTables = result; that.uploadWordTables = result;
loading.close() loading.close();
that.tablesHtmlVisible = true; that.tablesHtmlVisible = true;
}) })
.catch((error) => { .catch((error) => {
loading.close() loading.close();
console.error('Error processing tables:', error); console.error('Error processing tables:', error);
}); });
}); });
@@ -1180,7 +1241,6 @@ export default {
}, },
async onAddRow(mainId) { async onAddRow(mainId) {
await this.$api await this.$api
.post(this.urlList.addRow, { .post(this.urlList.addRow, {
am_id: mainId, am_id: mainId,
@@ -1289,7 +1349,7 @@ export default {
this.currentId = null; this.currentId = null;
this.clearButton(); this.clearButton();
var data = this.Main_List.find((item) => item.am_id == dataId); var data = this.Main_List.find((item) => item.am_id == dataId);
// console.log('data at line 667:', data);
if (data.type == 1) { if (data.type == 1) {
var extension = data.image.url.split('.').pop().toLowerCase(); var extension = data.image.url.split('.').pop().toLowerCase();
if (extension == 'tif') { if (extension == 'tif') {
@@ -1320,9 +1380,13 @@ export default {
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.currentContent = data;
this.editVisible = true; // this.editVisible = true;
this.currentId = dataId; this.currentId = dataId;
} }
this.$nextTick(() => {
this.drawer = true;
this.$refs.commonContent1.setValue();
});
}, },
onAddContent(dataId) { onAddContent(dataId) {
this.addContentVisible = true; this.addContentVisible = true;
@@ -1534,6 +1598,7 @@ export default {
.post(urlLInk, urlTask) .post(urlLInk, urlTask)
.then(async (res) => { .then(async (res) => {
if (res.code == 0) { if (res.code == 0) {
this.drawer = false;
// res.data.list.forEach((data) => { // res.data.list.forEach((data) => {
// if (data.amt_id) { // if (data.amt_id) {
// try { // try {
@@ -2204,10 +2269,10 @@ export default {
::v-deep .wordTableHtml table span blue { ::v-deep .wordTableHtml table span blue {
color: rgb(0, 130, 170) !important; color: rgb(0, 130, 170) !important;
} }
::v-deep .wordTableHtml table span blue sup{ ::v-deep .wordTableHtml table span blue sup {
color: rgb(0, 130, 170) !important; color: rgb(0, 130, 170) !important;
} }
::v-deep .wordTableHtml table span blue sub{ ::v-deep .wordTableHtml table span blue sub {
color: rgb(0, 130, 170) !important; color: rgb(0, 130, 170) !important;
} }
.toolbar { .toolbar {
@@ -2295,7 +2360,7 @@ export default {
width: 38vw; width: 38vw;
position: relative; position: relative;
height: auto; height: auto;
overflow: hidden; overflow: hidden;
padding: 10px; padding: 10px;
box-sizing: border-box; box-sizing: border-box;
box-shadow: rgba(0, 0, 0, 0.1) 0px 2px 12px 0px; box-shadow: rgba(0, 0, 0, 0.1) 0px 2px 12px 0px;
@@ -2304,7 +2369,7 @@ overflow: hidden;
margin-bottom: 0; margin-bottom: 0;
padding: 15px; padding: 15px;
} }
.uploadWordTableBox .insertTable{ .uploadWordTableBox .insertTable {
/* display: none; */ /* display: none; */
position: absolute; position: absolute;
right: 10px; right: 10px;
@@ -2313,4 +2378,24 @@ overflow: hidden;
background-color: #0066990d; background-color: #0066990d;
/* display: block !important; */ /* display: block !important; */
} }
.left {
width: 50vw;
background-color: #f5f5f5;
z-index: 10;
box-sizing: border-box;
/* transition: all 0.2s; */
}
.left1 {
width: 0%;
/* transition: all 0.2s; */
}
.right {
width: 50vw;
/* transition: all 0.2s; */
}
.right1 {
width: 100%;
/* transition: all 0.2s; */
}
</style> </style>

View File

@@ -692,6 +692,14 @@ export default {
//设置内容 //设置内容
setContent(value) { setContent(value) {
window.tinymce.get(this.tinymceId).setContent(value); window.tinymce.get(this.tinymceId).setContent(value);
},
setContent2(value) {
window.tinymce.get(this.tinymceId).setContent(value);
setTimeout(() => {
window.renderMathJax(this.tinymceId);
}, 10);
}, },
//获取内容 //获取内容
async getContent(type) { async getContent(type) {

View File

@@ -0,0 +1,200 @@
<template>
<div >
<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"
src="@/assets/img/isRemark.png"
alt=""
style="width: 15px; height: 15px; margin-right: 6px; margin-left: -14px"
/>
<span>{{ item.am_id }}</span>
</span>
<div
:class="
!isPreview
? item.is_h1
? 'isTitleH1'
: item.is_h2
? 'isTitleH2'
: item.is_h3
? 'isTitleH3'
: ''
: item.is_h1
? 'Ptitle'
: ''
"
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 :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>
<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.stop="initializeEditor($event, 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"
@contextmenu.prevent="openMenu($event, 'img', item.am_id, item, index)"
:id="'editor' + item.am_id"
>
<img :src="`${mediaUrl + item.image.url}`" />
<font class="font imageTitle" :style="`width: ${item.width ? `${item.width}px` : '100%'}`">
<span
v-html="item.image.title ? highlightText(item.image.title, item.checks ? item.checks : []) : ''"
></span>
</font>
<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.stop="initializeEditor($event, 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"
@contextmenu.prevent="openMenu($event, 'table', item.am_id, item, index)"
>
<!-- 标题部分 -->
<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) }"
>
<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>
</div>
<div
@contextmenu.prevent="openMenu($event, 'content', item.am_id, item, index)"
@dblclick="dblclickEdit(item.am_id, 'text', item, index)"
v-else
id="drop-target"
@dragover="handleDragOver"
@dragenter="handleDragEnter"
@dragleave="handleDragLeave"
@drop="handleDrop"
@click.stop="initializeEditor($event, 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>
</div>
</template>
<script>
export default {
props: {
item: Object,
isPreview: Boolean,
readonly: Boolean,
currentId: String,
mediaUrl: String,
isHeaderRow: Function,
highlightImgCommentId: Function,
highlightImg: Function,
highlightText: Function,
dblclickEdit: Function,
updateUniqueIds: Function,
handleDragOver: Function,
handleDragEnter: Function,
handleDragLeave: Function,
handleDrop: Function,
initializeEditor: Function,
openMenu: Function,
},
methods: {
},
};
</script>

View File

@@ -20,7 +20,7 @@
style=" style="
/* white-space: pre-line; */ /* white-space: pre-line; */
line-height: 12px; line-height: 12px;
max-height: 60vh;
overflow: auto; overflow: auto;
font-size: 12px; font-size: 12px;
font-size: 14px; /* 字体大小 */ font-size: 14px; /* 字体大小 */
@@ -74,6 +74,11 @@ export default {
} }
}, },
methods: { methods: {
setValue(){
// 假设编辑器的 ID 是 'editor-id'
this.$refs.tinymceChild1.setContent2(this.value);
},
openLatexEditor(data) { openLatexEditor(data) {
this.$emit('openLatexEditor',data) this.$emit('openLatexEditor',data)
console.log('at line 254:', '打开数字公式'); console.log('at line 254:', '打开数字公式');

View File

@@ -1,6 +1,16 @@
<template> <template>
<div class="tinymce-container editor-container word-container" :style="!isPreview ? 'padding:10px 20px 10px 10px;' : 'padding:0px;'" ref="scrollDiv">
<div <div
@click="
isMenuVisible = false;
currentData = {};
currentId = '';
"
class="tinymce-container editor-container word-container"
:style="!isPreview ? 'padding:10px 20px 10px 30px;' : 'padding:0px;'"
ref="scrollDiv"
>
<div
class=""
style=" style="
box-shadow: 0 2px 2px -2px rgba(34, 47, 62, 0.1), 0 8px 8px -4px rgba(34, 47, 62, 0.07); box-shadow: 0 2px 2px -2px rgba(34, 47, 62, 0.1), 0 8px 8px -4px rgba(34, 47, 62, 0.07);
margin: 0px 0; margin: 0px 0;
@@ -9,10 +19,106 @@
" "
> >
<div <div
class="" v-if="!isPreview"
:style="isPreview ? 'width: 100%;padding: 20px;' : 'width: calc(100% - 300px);padding: 20px 20px 20px 34px;'"
style=" style="
border-bottom: 2px solid #c7cdcf;
background-color: #fff;
position: fixed;
top: 60px;
left: 285px;
z-index: 10;
right: 330px;
height: 46px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 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="padding: 0 0px; float: right">
<ul class="operateBox">
<!-- <li
v-if="isEditComment"
style="background-color: #fff !important; color: #f56c6c; border: 1px solid #f56c6c"
@mousedown="cacheSelection"
@click="handleSelection"
>
<i class="el-icon-document-add" style="margin-top: 2px; float: left"></i>
Comment
</li> -->
<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; background-color: #fff !important; color: #333">
<i class="el-icon-document" style="margin-right: 2px"> </i>
Batch Add content
</li>
</ul>
</div>
<li style="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="" @click="onEdit">
<i class="el-icon-edit" style="margin-top: 2px"></i>
Edit
</li> -->
<li style="background-color: #fc625d !important" @click="onDelete">
<i class="el-icon-delete" style="margin-top: 2px"></i>
Delete
</li>
</ul>
</div>
</div>
<div
class="word-container-box"
:style="isPreview ? 'width: 100%;padding: 20px;' : 'width: calc(100% - 300px);padding: 60px 20px 20px 34px;'"
style="
box-sizing: border-box; box-sizing: border-box;
width: calc(100% - 300px); width: calc(100% - 300px);
float: left; float: left;
@@ -21,7 +127,18 @@
position: relative; position: relative;
" "
> >
<!-- <div v-if="selectedIds.length > 0" class="selected-to-here">
Selected to here: {{ selectedIds[selectedIds.length - 1] }}
</div> -->
<!-- <common-late-x></common-late-x> -->
<template v-for="(item, index) in wordList"> <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"> <span class="isRemark" :remark-main-id="item.am_id" v-if="item.checks && item.checks.length > 0 && !isPreview">
><img ><img
class="isRemark" class="isRemark"
@@ -32,12 +149,57 @@
<span>{{ item.am_id }}</span> <span>{{ item.am_id }}</span>
</span> </span>
<div :class="!isPreview?(item.is_h1?'isTitleH1':item.is_h2?'isTitleH2':item.is_h3?'isTitleH3':''):''" style="line-height: 24px;"> <div
<template v-if="!isPreview"> <span class="Htitle Htitle1" v-if="item.is_h1==1">H1</span> :class="
<span class="Htitle Htitle2" v-else-if="item.is_h2==1">H2</span> !isPreview
<span class="Htitle Htitle3" v-else-if="item.is_h3==1">H3</span></template> ? item.is_h1
? 'isTitleH1'
: item.is_h2
? 'isTitleH2'
: item.is_h3
? 'isTitleH3'
: ''
: item.is_h1
? 'Ptitle'
: ''
"
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 :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>
<div <div
@dblclick="dblclickEdit(item.am_id, 'img', item, index)"
:key="item.am_id" :key="item.am_id"
id="drop-target" id="drop-target"
:class="highlightImg(item.ami_id, item.checks ? item.checks : [])" :class="highlightImg(item.ami_id, item.checks ? item.checks : [])"
@@ -47,47 +209,59 @@
@dragleave="handleDragLeave" @dragleave="handleDragLeave"
@drop="handleDrop" @drop="handleDrop"
class="MaxPicture pMain myeditabledivImage drop-target" class="MaxPicture pMain myeditabledivImage drop-target"
@click="initializeEditor(item.am_id, 'img', item)" @click.stop="initializeEditor($event, item.am_id, 'img', item, index)"
v-if="item.type == 1" v-if="item.type == 1"
:main-state="item.state" :main-state="item.state"
:remark="item.checks && item.checks.length > 0 ? 1 : 0" :remark="item.checks && item.checks.length > 0 ? 1 : 0"
:contenteditable="!readonly && !isPreview"
:data-id="item.ami_id" :data-id="item.ami_id"
:type="item.type" :type="item.type"
:main-id="item.am_id" :main-id="item.am_id"
@contextmenu.prevent="openMenu($event, 'img', item.am_id, item, index)"
:id="'editor' + item.am_id" :id="'editor' + item.am_id"
> >
<img :src="`${mediaUrl + item.image.url}`" /> <img :src="`${mediaUrl + item.image.url}`" />
<font class="font imageTitle" :style="`width: ${item.width ? `${item.width}px` : '100%'}`">
<span
v-html="item.image.title ? highlightText(item.image.title, item.checks ? item.checks : []) : ''"
></span>
</font>
<font class="font" :style="`width: ${item.width ? `${item.width}px` : '100%'}`"> <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> <span
v-html="item.image.note ? highlightText(item.image.note, item.checks ? item.checks : []) : ''"
></span>
</font> </font>
</div> </div>
<div <div
@dblclick="dblclickEdit(item.am_id, 'table', item, index)"
id="drop-target" id="drop-target"
@dragover="handleDragOver" @dragover="handleDragOver"
@dragenter="handleDragEnter" @dragenter="handleDragEnter"
@dragleave="handleDragLeave" @dragleave="handleDragLeave"
@drop="handleDrop" @drop="handleDrop"
@click="initializeEditor(item.am_id, 'table', item)" @click.stop="initializeEditor($event, item.am_id, 'table', item, index)"
class="thumbnailTableBox wordTableHtml table_Box pMain myeditabledivTable drop-target" class="thumbnailTableBox wordTableHtml table_Box pMain myeditabledivTable drop-target"
v-else-if="item.type == 2" v-else-if="item.type == 2"
:main-state="item.state" :main-state="item.state"
:remark="item.checks && item.checks.length > 0 ? 1 : 0" :remark="item.checks && item.checks.length > 0 ? 1 : 0"
:contenteditable="!readonly && !isPreview"
:data-id="item.amt_id" :data-id="item.amt_id"
:type="item.type" :type="item.type"
:id="'editor' + item.am_id" :id="'editor' + item.am_id"
:main-id="item.am_id" :main-id="item.am_id"
@contextmenu.prevent="openMenu($event, 'table', item.am_id, item, index)"
> >
<!-- 标题部分 --> <!-- 标题部分 -->
<font class="font" :style="`width: ${item.width ? `${item.width}px` : '100%'}`" style="text-align: center;"> <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> <span v-html="highlightText(item.table.title || '', item.checks ? item.checks : [])"></span>
</font> </font>
<!-- 表格部分 --> <!-- 表格部分 -->
<table border="1" style="width: 100%; border-collapse: collapse; text-align: center"> <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) }"> <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 <td
v-for="(cell, i1) in row" v-for="(cell, i1) in row"
:key="i1" :key="i1"
@@ -106,18 +280,19 @@
</div> </div>
<div <div
@contextmenu.prevent="openMenu($event, 'content', item.am_id, item, index)"
@dblclick="dblclickEdit(item.am_id, 'text', item, index)"
v-else v-else
id="drop-target" id="drop-target"
@dragover="handleDragOver" @dragover="handleDragOver"
@dragenter="handleDragEnter" @dragenter="handleDragEnter"
@dragleave="handleDragLeave" @dragleave="handleDragLeave"
@drop="handleDrop" @drop="handleDrop"
@click="initializeEditor(item.am_id)" @click.stop="initializeEditor($event, item.am_id, 'text', item, index)"
class="pMain myeditablediv drop-target" class="pMain myeditablediv drop-target"
@blur="clearEditor(item.am_id)" @blur="clearEditor(item.am_id)"
:main-state="item.state" :main-state="item.state"
:remark="item.checks && item.checks.length > 0 ? 1 : 0" :remark="item.checks && item.checks.length > 0 ? 1 : 0"
:contenteditable="!readonly && !isPreview"
:data-id="item.am_id" :data-id="item.am_id"
:main-id="item.am_id" :main-id="item.am_id"
:type="item.type" :type="item.type"
@@ -125,6 +300,7 @@
v-html="highlightText(item.content, item.checks ? item.checks : [], item.type)" v-html="highlightText(item.content, item.checks ? item.checks : [], item.type)"
></div> ></div>
</div> </div>
</div>
</template> </template>
</div> </div>
@@ -146,7 +322,7 @@
v-for="(item, index) in commentList" v-for="(item, index) in commentList"
class="comment-item annotation" class="comment-item annotation"
:data-target="`main-${item.am_id}`" :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>
<div style="display: flex; align-items: center; justify-content: space-between; background-color: #f3d5d5c2"> <div style="display: flex; align-items: center; justify-content: space-between; background-color: #f3d5d5c2">
@@ -162,21 +338,16 @@
</el-link> </el-link>
</div> </div>
<div <div
style=" style="padding: 6px 6px; box-sizing: border-box; border-bottom: 1px solid rgba(243, 213, 213)"
padding:6px 6px;
box-sizing: border-box;
border-bottom: 1px solid rgba(243, 213, 213);
"
:style="commont.estate == 1 ? 'background:#13bc200f;' : ''" :style="commont.estate == 1 ? 'background:#13bc200f;' : ''"
v-for="(commont, commentIndex) in item.comment" v-for="(commont, commentIndex) in item.comment"
@click="highlightLeftComment(commont.amc_id, item.am_id)" @click="highlightLeftComment(commont.amc_id, item.am_id)"
> >
<div style="width: 100%; display: flex; align-items: center; justify-content: space-between"> <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 <span
:style="commont.estate == 1 ? 'opacity:0.6;color:rgb(19, 188, 32);' : ''" :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 >{{ commentIndex + 1 }}</span
> >
<span <span
@@ -195,7 +366,7 @@
$t('commonTable.Resolved') $t('commonTable.Resolved')
}}</span> }}</span>
</div> </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: #b8b7b7; font-size: 12px">{{ getTime(commont.ctime) }}</span
><span ><span
style="color: #aaa; font-size: 13px; margin: 0 4px" style="color: #aaa; font-size: 13px; margin: 0 4px"
@@ -302,7 +473,10 @@
" "
> >
<i class="el-icon-user-solid" style="color: #333; padding: 0 4px"></i> <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> </div>
<i <i
class="el-icon-edit" class="el-icon-edit"
@@ -322,6 +496,54 @@
<!-- </form> --> <!-- </form> -->
<!-- <textarea class="tinymce-textarea" :id="tinymceId"></textarea> --> <!-- <textarea class="tinymce-textarea" :id="tinymceId"></textarea> -->
<div v-if="isMenuVisible" class="context-menu" :style="{ top: `${menuPosition.y}px`, left: `${menuPosition.x}px` }">
<ul>
<!-- {{ menuType }} -->
<div v-if="currentData.type == 0">
<div style="padding: 0 60px 0 20px">
<ul class="HTitleBox" style="border: none">
<li
style="font-size: 16px"
:style="currentData.is_h1 == 1 ? 'color:#4d99f1' : 'color:#333'"
@click="currentData.is_h1 == 0 ? changeTitle(1) : changeTitle(0)"
>
H1
</li>
<li
style="font-size: 16px"
:style="currentData.is_h2 == 1 ? 'color:#4d99f1' : 'color:#333'"
@click="currentData.is_h2 == 0 ? changeTitle(2) : changeTitle(0)"
>
H2
</li>
<li
style="font-size: 16px"
:style="currentData.is_h3 == 1 ? 'color:#4d99f1' : 'color:#333'"
@click="currentData.is_h3 == 0 ? changeTitle(3) : changeTitle(0)"
>
H3
</li>
</ul>
</div>
</div>
<li @click="menuAction('edit')" style="color: rgb(43, 129, 239) !important"><i class="el-icon-edit" style=""></i>Edit</li>
<li v-if="isEditComment" style="color: #f56c6c" @mousedown="cacheSelection" @click="menuAction('comment')">
<i class="el-icon-document-add"></i>Comment
</li>
<li @click="menuAction('up')"><i class="el-icon-arrow-up" style=""></i>Move Up</li>
<li @click="menuAction('down')"><i class="el-icon-arrow-down" style=""></i>Move Down</li>
<li @click="menuAction('row')"><i class="el-icon-plus" style=""></i>Add Row</li>
<li @click="menuAction('addContent')"><i class="el-icon-document"> </i>Batch Add content</li>
<li @click="menuAction('delete')" style="color: red; margin-top: 2px; border-top: 1px solid #e5e6eb">
<i class="el-icon-delete" style=""></i>Delete
</li>
</ul>
</div>
</div> </div>
</template> </template>
<script> <script>
@@ -341,6 +563,12 @@ const tableStyle = `
}blue { }blue {
color: rgb(0, 130, 170) !important; color: rgb(0, 130, 170) !important;
} }
blue sup{
color: rgb(0, 130, 170) !important;
}
blue sub{
color: rgb(0, 130, 170) !important;
}
b span{ b span{
font-weight: bold !important; font-weight: bold !important;
} }
@@ -510,6 +738,17 @@ export default {
}, },
data() { data() {
return { return {
isMenuVisible: false,
menuPosition: { x: 0, y: 0 },
menuType: '', // 用来区分不同的菜单
cachedHtml: '', // 缓存选中的 HTML
cachedText: '', // 缓存选中的纯文本
cachedMainId: null, // 选中的 main-id
cachedType: null, // 选中的 type
currentId: null,
currentIndex: null,
checked: false,
currentData: {},
imagePath: require('@/assets/img/carriageReturn.png'), // 或者你可以设置其他路径 imagePath: require('@/assets/img/carriageReturn.png'), // 或者你可以设置其他路径
scrollPosition: 0, scrollPosition: 0,
wordList: [], wordList: [],
@@ -556,6 +795,7 @@ export default {
} }
], ],
uploadReset: false, uploadReset: false,
uniqueIds: [],
dialogVisible: false, dialogVisible: false,
form: { form: {
name: '', name: '',
@@ -570,7 +810,7 @@ export default {
formLabelWidth: '120px', formLabelWidth: '120px',
hasChange: false, hasChange: false,
hasInit: false, hasInit: false,
// selectedIds:[],
tinymceId: this.id || 'vue-tinymce-' + +new Date() tinymceId: this.id || 'vue-tinymce-' + +new Date()
}; };
}, },
@@ -582,6 +822,7 @@ export default {
if (val) { if (val) {
this.wordList = [...this.contentList]; this.wordList = [...this.contentList];
this.$nextTick(() => { this.$nextTick(() => {
window.renderMathJax(); // 主动触发 MathJax 渲染
this.getCommentsData(); this.getCommentsData();
}); });
} }
@@ -589,12 +830,18 @@ export default {
deep: true // 启用深度监听 deep: true // 启用深度监听
} }
}, },
computed: {
selectedIds() {
return this.wordList.filter((item) => item.checked).map((item) => item.am_id);
}
},
updated() { updated() {
// 恢复子组件的滚动位置 // 恢复子组件的滚动位置
// this.$refs.scrollDiv.scrollTop = this.scrollPosition; // this.$refs.scrollDiv.scrollTop = this.scrollPosition;
}, },
mounted() { mounted() {
this.$nextTick(() => { this.$nextTick(() => {
window.renderMathJax(); // 主动触发 MathJax 渲染
this.getCommentsData(); this.getCommentsData();
if (!this.isPreview && localStorage.getItem('scrollPosition')) { if (!this.isPreview && localStorage.getItem('scrollPosition')) {
this.$refs.scrollDiv.scrollTop = localStorage.getItem('scrollPosition'); // 滚动到 500px 位置 this.$refs.scrollDiv.scrollTop = localStorage.getItem('scrollPosition'); // 滚动到 500px 位置
@@ -611,6 +858,7 @@ export default {
this.$refs.scrollDiv.addEventListener('scroll', this.divOnScroll, { passive: true }); this.$refs.scrollDiv.addEventListener('scroll', this.divOnScroll, { passive: true });
}, },
activated() { activated() {
window.renderMathJax(); // 主动触发 MathJax 渲染
this.isShowEditComment(); this.isShowEditComment();
this.typesettingType = 1; this.typesettingType = 1;
this.editors = {}; this.editors = {};
@@ -623,8 +871,6 @@ export default {
this.editors = {}; this.editors = {};
}, },
beforeDestroy() { beforeDestroy() {
for (const key in this.editors) { for (const key in this.editors) {
if (this.editors[key]) { if (this.editors[key]) {
// 确保销毁所有编辑器实例 // 确保销毁所有编辑器实例
@@ -639,6 +885,184 @@ export default {
this.editors = {}; this.editors = {};
}, },
methods: { methods: {
openMenu(event, type, currentId) {
console.log('event at line 860:', event);
// 获取鼠标点击位置
this.menuPosition.x = event.clientX + 30;
this.menuPosition.y = event.clientY + 40;
this.menuType = type; // 设置菜单类型,根据点击区域不同显示不同菜单
// this.currentId=currentId;
this.isMenuVisible = true;
},
closeMenu() {
this.isMenuVisible = false;
},
menuAction(action) {
console.log(`执行了:${action}`);
switch (action) {
case 'addContent':
this.addContent();
break;
case 'comment':
this.handleSelection();
break;
case 'edit':
this.onEdit();
break;
case 'row':
this.onAddRow('');
break;
case 'up':
this.changeSort('up');
break;
case 'down':
this.changeSort('down');
break;
case 'delete':
this.onDelete();
break;
}
this.closeMenu();
},
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 = {};
console.log('this.selectedIds at line 917:', this.selectedIds);
// 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 && 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) { highlightLeftComment(commentId) {
@@ -690,12 +1114,10 @@ export default {
} }
}, },
// 判断是否是表头行 // 判断是否是表头行
isHeaderRow(rowIndex,table) { isHeaderRow(rowIndex, table) {
var table = JSON.parse(table);
var table=JSON.parse(table)
var head=table[0]
var head = table[0];
return rowIndex < head[0].rowspan; // 假设前两行是表头 return rowIndex < head[0].rowspan; // 假设前两行是表头
}, },
@@ -959,30 +1381,78 @@ export default {
} }
}); });
}, },
initializeEditor(index, type, data) {
if (!this.isPreview) { initializeEditor(event, id, type, data, index) {
const editorId = `editor${index}`; this.clearHighlight();
// 检查当前编辑器是否已经初始化 this.selectedIds = [];
if (this.editors[editorId]) return; // this.menuPosition.x = event.clientX+20;
// 销毁所有已初始化的编辑器实例 // this.menuPosition.y = event.clientY+20;
for (const key in this.editors) {
if (this.editors[key]) { const menuWidth = 180; // 你的菜单宽度(按实际调整)
// 确保销毁所有编辑器实例 const menuHeight = 275; // 你的菜单高度(按实际调整)
tinymce.remove(this.editors[key]);
this.editors[key] = null; // 清除引用 let x = event.clientX + 20;
} let y = event.clientY + 20;
// 判断右侧是否越界
if (x + menuWidth > window.innerWidth) {
x = window.innerWidth - menuWidth - 10; // 留点空隙
} }
if (type == 'img') { // 判断底部是否越界
this.initTinymceImg(editorId); if (y + menuHeight > window.innerHeight) {
} else if (type == 'table') { y = event.clientY - menuHeight - 10; // 改为往上弹
this.initTinymceTable(editorId);
} else {
this.initTinymceContent(editorId);
} }
this.$set(this.editors, editorId, tinymce.get(`editor${index}`));
this.menuPosition.x = x;
this.menuPosition.y = y;
this.menuType = type; // 设置菜单类型,根据点击区域不同显示不同菜单
// this.currentId=currentId;
this.wordList.forEach((item, index) => {
item.checked = false;
});
if (!this.isPreview) {
this.currentId = id;
this.currentIndex = index;
this.currentData = data;
this.isMenuVisible = true;
// 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) { deleteComment(data) {
this.$emit('deleteComment', data); this.$emit('deleteComment', data);
}, },
@@ -1025,6 +1495,9 @@ export default {
}, },
divOnScroll() { divOnScroll() {
if (!this.isPreview) { if (!this.isPreview) {
this.isMenuVisible = false;
this.currentId = null;
this.currentData = {};
// const scrollTop = scrollDiv.scrollTop; // 获取垂直滚动距离 // const scrollTop = scrollDiv.scrollTop; // 获取垂直滚动距离
this.scrollPosition = this.$refs.scrollDiv.scrollTop; this.scrollPosition = this.$refs.scrollDiv.scrollTop;
localStorage.setItem('scrollPosition', this.scrollPosition); localStorage.setItem('scrollPosition', this.scrollPosition);
@@ -1071,16 +1544,11 @@ export default {
} }
}, },
highlightImgCommentId(imgId, annotations) { highlightImgCommentId(imgId, annotations) {
const emptyContentIndexes = annotations const emptyContentIndexes = annotations
.map((annotation, index) => (annotation.content === '' ? annotation.amc_id : -1)) // 找到内容为空的批注项的索引,其他项返回 -1 .map((annotation, index) => (annotation.content === '' ? annotation.amc_id : -1)) // 找到内容为空的批注项的索引,其他项返回 -1
.filter((index) => index !== -1) // 过滤掉值为 -1 的项 .filter((index) => index !== -1) // 过滤掉值为 -1 的项
.join(','); // 以逗号连接索引 .join(','); // 以逗号连接索引
return emptyContentIndexes; return emptyContentIndexes;
}, },
escapeRegExp(string) { escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
@@ -1118,7 +1586,7 @@ export default {
style="background-color: ${randomColor}; style="background-color: ${randomColor};
position: relative; position: relative;
display: inline-block; display: inline-block;
white-space: nowrap; // white-space: nowrap;
overflow-wrap: anywhere; overflow-wrap: anywhere;
border-left: 2px solid #cd5454; border-left: 2px solid #cd5454;
border-right: 2px solid #cd5454;" border-right: 2px solid #cd5454;"
@@ -1134,7 +1602,6 @@ export default {
}); });
}); });
if (type == 0 && tempText == '') { if (type == 0 && tempText == '') {
tempText = tempText =
tempText + tempText +
`<img contenteditable="${false}" src="${this.imagePath}" alt="" style="width: 20px;height: 20px;opacity:0.6;">`; `<img contenteditable="${false}" src="${this.imagePath}" alt="" style="width: 20px;height: 20px;opacity:0.6;">`;
@@ -1851,6 +2318,7 @@ export default {
.pMain { .pMain {
margin-top: 5px; margin-top: 5px;
margin-bottom: 5px; margin-bottom: 5px;
min-height: 30px;
} }
::v-deep .tox.tox-tinymce-inline { ::v-deep .tox.tox-tinymce-inline {
z-index: 9999 !important; z-index: 9999 !important;
@@ -1955,14 +2423,13 @@ export default {
border: 2px solid #cd5454; /* 高亮边框 */ border: 2px solid #cd5454; /* 高亮边框 */
box-shadow: 0 0 10px #f77b7b; /* 高亮阴影 */ box-shadow: 0 0 10px #f77b7b; /* 高亮阴影 */
} }
.isTitleH1{ .isTitleH1 {
position: relative; position: relative;
/* border: 1px solid #94c2f7; */ /* border: 1px solid #94c2f7; */
background-color: #dbebfc54; background-color: #dbebfc54;
} }
.Htitle{ .Htitle {
color: #4d99f1; color: #4d99f1;
background-color: #dbebfca6; background-color: #dbebfca6;
/* border: 1px solid #4d99f1; */ /* border: 1px solid #4d99f1; */
@@ -1976,25 +2443,136 @@ export default {
left: -30px; left: -30px;
top: 0px; top: 0px;
text-align: center; text-align: center;
} }
.Htitle1{ .Htitle1 {
width: 24px; width: 24px;
height: 24px; height: 24px;
/* font-size: 14px; */ /* font-size: 14px; */
} }
.Htitle2{ width: 24px; .Htitle2 {
width: 24px;
height: 24px; height: 24px;
/* font-size: 16px; */ /* font-size: 16px; */
} }
.Htitle3{ width: 24px; .Htitle3 {
width: 24px;
height: 24px; height: 24px;
/* font-size: 12px; */ /* font-size: 12px; */
} }
.isTitleH2{position: relative; .isTitleH2 {
position: relative;
background-color: #dbebfc54; background-color: #dbebfc54;
} }
.isTitleH3{position: relative; .isTitleH3 {
position: relative;
background-color: #dbebfc54; 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;
cursor: pointer;
}
.operateBox {
width: auto;
display: flex;
}
.operateBox li {
min-width: 55px;
display: flex;
/* flex-direction: column; */
justify-content: space-between;
align-items: center;
cursor: pointer;
list-style: none;
padding: 2px 10px;
margin-left: 10px;
color: #8a8a8b;
/* font-weight: bold; */
font-size: 16px;
background-color: rgb(43, 129, 239) !important;
color: #fff;
border-radius: 4px;
height: 26px;
}
::v-deep .el-checkbox__inner {
width: 18px;
height: 18px;
}
/* 悬浮提示的样式 */
.selected-to-here {
position: fixed;
top: 10px;
left: 50%;
transform: translateX(-50%);
background-color: rgba(0, 123, 255, 0.7);
color: white;
padding: 10px 20px;
border-radius: 5px;
font-size: 14px;
z-index: 999;
}
.context-menu {
position: fixed;
width: 180px;
background-color: #fff;
box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
border-radius: 4px;
z-index: 1000;
border: 1px solid #ddd;
border-radius: 4px;
line-height: 28px;
box-sizing: border-box;
}
.context-menu ul {
list-style: none;
padding: 0;
margin: 0;
}
.context-menu li {
padding: 10px;
cursor: pointer;
font-size: 14px;
color: rgb(51, 54, 57);
border-radius: 4px;
padding: 2px 0;
}
.context-menu li i {
margin: 5px 10px 0 10px;
font-size: 18px;
}
.context-menu li:hover {
background-color: #f0f0f0;
}
</style> </style>

View File

@@ -20,14 +20,14 @@
> >
<div <div
v-if="!isPreview" v-if="!isPreview"
style=" :style="
border-bottom: 2px solid #c7cdcf; `border-bottom: 2px solid #c7cdcf;
background-color: #fff; background-color: #fff;
position: fixed; position: fixed;
top: 60px; top: 60px;
left: 285px; left: ${drawer?'0px':'285px'};
z-index: 10; z-index: 10;
right: 330px; right: ${drawer?'50vw':'330px'};
height: 46px; height: 46px;
display: flex; display: flex;
align-items: center; align-items: center;
@@ -35,45 +35,10 @@
padding: 0 10px; padding: 0 10px;
box-sizing: border-box; box-sizing: border-box;
overflow: hidden; overflow: hidden;
width: calc(100% - 285px - 330px); width:${drawer?'50w':'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="padding: 0 0px; float: right"> <div style="padding: 0 0px; float: right">
<ul class="operateBox"> <ul class="operateBox">
@@ -216,7 +181,7 @@
:data-id="item.ami_id" :data-id="item.ami_id"
:type="item.type" :type="item.type"
:main-id="item.am_id" :main-id="item.am_id"
@contextmenu.prevent="openMenu($event, 'img', item.am_id, item, index)"
:id="'editor' + item.am_id" :id="'editor' + item.am_id"
> >
<img :src="`${mediaUrl + item.image.url}`" /> <img :src="`${mediaUrl + item.image.url}`" />
@@ -248,7 +213,7 @@
:type="item.type" :type="item.type"
:id="'editor' + item.am_id" :id="'editor' + item.am_id"
:main-id="item.am_id" :main-id="item.am_id"
@contextmenu.prevent="openMenu($event, 'table', item.am_id, item, index)"
> >
<!-- 标题部分 --> <!-- 标题部分 -->
<font class="font" :style="`width: ${item.width ? `${item.width}px` : '100%'}`" style="text-align: center"> <font class="font" :style="`width: ${item.width ? `${item.width}px` : '100%'}`" style="text-align: center">
@@ -280,7 +245,7 @@
</div> </div>
<div <div
@contextmenu.prevent="openMenu($event, 'content', item.am_id, item, index)"
@dblclick="dblclickEdit(item.am_id, 'text', item, index)" @dblclick="dblclickEdit(item.am_id, 'text', item, index)"
v-else v-else
id="drop-target" id="drop-target"
@@ -306,15 +271,16 @@
<div <div
v-if="!isPreview" v-if="!isPreview"
style=" v-show="drawer"
:style="`
width: 310px; width: 310px;
position: fixed; position: fixed;
top: 70px; top: 70px;
box-sizing: border-box; box-sizing: border-box;
right: 10px; right:10px;
bottom: 0; bottom: 0;
overflow-y: auto; overflow-y: auto;`
" "
class="commentList" class="commentList"
> >
@@ -731,6 +697,9 @@ export default {
isShowArtWorkButton: { isShowArtWorkButton: {
default: false default: false
}, },
drawer: {
default: false
},
wordStyle: { wordStyle: {
type: String, type: String,
default: '' default: ''
@@ -1441,6 +1410,7 @@ export default {
} }
}, },
dblclickEdit(id, type, data, index) { dblclickEdit(id, type, data, index) {
console.log('id at line 1443:', id)
if (!this.isPreview) { if (!this.isPreview) {
this.currentId = id; this.currentId = id;
this.currentIndex = index; this.currentIndex = index;