自动化

This commit is contained in:
2024-12-22 17:11:36 +08:00
parent 3d658f030d
commit dcea82e412
47 changed files with 174271 additions and 5675 deletions

View File

@@ -1071,3 +1071,108 @@ a {
color: #fff !important;
line-height: 24px;
} */
.wordTableHtml b span {
font-weight: bold !important;
}
.wordTableHtml i span {
font-style: italic !important;
}
.wordTableHtml sub span {
vertical-align: sub;
}
.wordTableHtml sup span {
vertical-align: super;
}
.wordTableHtml sub {
vertical-align: sub !important;
}
.wordTableHtml sup {
vertical-align: super !important;
}
.wordTableHtml span[style*='vertical-align: super'] {
vertical-align: super !important;
}
.wordTableHtml span[style*='vertical-align: sub'] {
vertical-align: sub !important;
}
.wordTableHtml table {
border: 0px !important;
border-collapse: collapse; /* 去除单元格间隙 */
width: auto;
margin: 0 auto !important;
table-layout: auto; /* 自动调整列宽 */
text-align: left;
font-family: 'Charis SIL' !important;
font-size: 7.5pt !important;
mso-font-kerning: 1pt !important;
line-height: 10pt !important;
mos-line-height: 10pt !important;
}
.wordTableHtml table td,
.wordTableHtml table th{
padding: 5px;
text-align: left !important;
word-wrap: break-word; /* 长单词自动换行 */
word-break: break-word;
font-family: 'Charis SIL' !important;
font-size: 7.5pt !important;
mso-font-kerning: 1pt !important;
line-height: 10pt !important;
mos-line-height: 10pt !important;
}
.wordTableHtml table tbody tr td {
text-align: left !important;
border-left: none !important;
mso-border-left-alt: none !important;
border-right: none !important;
mso-border-right-alt: none !important;
border-top: none;
mso-border-top-alt: none !important;
border-bottom: none !important;
mso-border-bottom-alt: none !important;
border: 1px dashed #dcdfe6 !important;
border-left: 1px dashed #dcdfe6 !important;
border-right: 1px dashed #dcdfe6 !important;
word-break: keep-all !important;
/* text-align: justify !important; */
}
.wordTableHtml table tr td p {
display: flex;
text-align: left !important;
align-items: center;
margin: 0;
font-family: 'Charis SIL' !important;
font-size: 7.5pt !important;
mso-font-kerning: 1pt !important;
line-height: 10pt !important;
mos-line-height: 10pt !important;
}
.wordTableHtml table span {
color: #000000;
text-align: left !important;
font-family: 'Charis SIL' !important;
font-size: 7.5pt !important;
mso-font-kerning: 1pt !important;
line-height: 10pt !important;
mos-line-height: 10pt !important;
}
.wordTableHtml table .color-highlight {
color: rgb(0, 130, 170) !important;
font-family: 'Charis SIL' !important;
font-size: 7.5pt !important;
mso-font-kerning: 1pt !important;
line-height: 10pt !important;
mos-line-height: 10pt !important;
}
.wordTableHtml table tr:first-child td {
border-top: 1px solid #000 !important;
border-bottom: 1px solid #000 !important;
}
.wordTableHtml table tr:last-of-type td {
border-bottom: 1px solid #000 !important;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
src/assets/img/huifu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

BIN
src/assets/img/isRemark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 583 B

BIN
src/assets/img/pizhu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 850 B

BIN
src/assets/img/upload.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

View File

@@ -0,0 +1,205 @@
SET UTF-8
TRY esianrtolcdugmphbyfvkwzESIANRTOLCDUGMPHBYFVKWZ'
ICONV 1
ICONV '
NOSUGGEST !
# ordinal numbers
COMPOUNDMIN 1
# only in compounds: 1th, 2th, 3th
ONLYINCOMPOUND c
# compound rules:
# 1. [0-9]*1[0-9]th (10th, 11th, 12th, 56714th, etc.)
# 2. [0-9]*[02-9](1st|2nd|3rd|[4-9]th) (21st, 22nd, 123rd, 1234th, etc.)
COMPOUNDRULE 2
COMPOUNDRULE n*1t
COMPOUNDRULE n*mp
WORDCHARS 0123456789
PFX A Y 1
PFX A 0 re .
PFX I Y 1
PFX I 0 in .
PFX U Y 1
PFX U 0 un .
PFX C Y 1
PFX C 0 de .
PFX E Y 1
PFX E 0 dis .
PFX F Y 1
PFX F 0 con .
PFX K Y 1
PFX K 0 pro .
SFX V N 2
SFX V e ive e
SFX V 0 ive [^e]
SFX N Y 3
SFX N e ion e
SFX N y ication y
SFX N 0 en [^ey]
SFX X Y 3
SFX X e ions e
SFX X y ications y
SFX X 0 ens [^ey]
SFX H N 2
SFX H y ieth y
SFX H 0 th [^y]
SFX Y Y 1
SFX Y 0 ly .
SFX G Y 2
SFX G e ing e
SFX G 0 ing [^e]
SFX J Y 2
SFX J e ings e
SFX J 0 ings [^e]
SFX D Y 4
SFX D 0 d e
SFX D y ied [^aeiou]y
SFX D 0 ed [^ey]
SFX D 0 ed [aeiou]y
SFX T N 4
SFX T 0 st e
SFX T y iest [^aeiou]y
SFX T 0 est [aeiou]y
SFX T 0 est [^ey]
SFX R Y 4
SFX R 0 r e
SFX R y ier [^aeiou]y
SFX R 0 er [aeiou]y
SFX R 0 er [^ey]
SFX Z Y 4
SFX Z 0 rs e
SFX Z y iers [^aeiou]y
SFX Z 0 ers [aeiou]y
SFX Z 0 ers [^ey]
SFX S Y 4
SFX S y ies [^aeiou]y
SFX S 0 s [aeiou]y
SFX S 0 es [sxzh]
SFX S 0 s [^sxzhy]
SFX P Y 3
SFX P y iness [^aeiou]y
SFX P 0 ness [aeiou]y
SFX P 0 ness [^y]
SFX M Y 1
SFX M 0 's .
SFX B Y 3
SFX B 0 able [^aeiou]
SFX B 0 able ee
SFX B e able [^aeiou]e
SFX L Y 1
SFX L 0 ment .
REP 90
REP a ei
REP ei a
REP a ey
REP ey a
REP ai ie
REP ie ai
REP alot a_lot
REP are air
REP are ear
REP are eir
REP air are
REP air ere
REP ere air
REP ere ear
REP ere eir
REP ear are
REP ear air
REP ear ere
REP eir are
REP eir ere
REP ch te
REP te ch
REP ch ti
REP ti ch
REP ch tu
REP tu ch
REP ch s
REP s ch
REP ch k
REP k ch
REP f ph
REP ph f
REP gh f
REP f gh
REP i igh
REP igh i
REP i uy
REP uy i
REP i ee
REP ee i
REP j di
REP di j
REP j gg
REP gg j
REP j ge
REP ge j
REP s ti
REP ti s
REP s ci
REP ci s
REP k cc
REP cc k
REP k qu
REP qu k
REP kw qu
REP o eau
REP eau o
REP o ew
REP ew o
REP oo ew
REP ew oo
REP ew ui
REP ui ew
REP oo ui
REP ui oo
REP ew u
REP u ew
REP oo u
REP u oo
REP u oe
REP oe u
REP u ieu
REP ieu u
REP ue ew
REP ew ue
REP uff ough
REP oo ieu
REP ieu oo
REP ier ear
REP ear ier
REP ear air
REP air ear
REP w qu
REP qu w
REP z ss
REP ss z
REP shun tion
REP shun sion
REP shun cion
REP size cise

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,8 +2,12 @@
//记得切换
//正式
const mediaUrl = '/public/';
const baseUrl = '/';
// const mediaUrl = '/public/';
// const baseUrl = '/api';
const mediaUrl = 'https://submission.tmrjournals.com/public/';
const baseUrl = '/api';
//本地(正式环境 )

View File

@@ -354,6 +354,9 @@ const en = {
},
commonTable: {
add: 'Add',
preview: 'Preview',
link: 'Positioning',
Typed: 'Typed',
edit: 'Edit',
rows: 'rows',
columns: 'columns',
@@ -361,9 +364,15 @@ const en = {
headerPlaceholder: 'Fill in the header',
typesettingType2: 'Horizontal A4',
typesettingType1: 'Vertical A4',
AnnotationList: 'Annotation List',
Annotations: 'Annotations',
exportWord: 'Export Word',
exportImg: 'Export PNG',
PaperRotation: 'Paper Rotation',
removeAnnotations:'Are you sure you want to delete this Annotation?',
removeContent:'Are you sure you want to delete this content?',
reContent:'Are you sure you want to restore this content?',
uploadImageInfo:'Figures can only upload files in JPG, JPEG, and PNG formats!'
},
}

View File

@@ -347,16 +347,25 @@ const zh = {
},
commonTable: {
add: '新增',
preview: '预览',
positioning: '定位',
edit: '编辑',
Typed: '已排版',
rows: '行',
columns: '列',
table: '表格',
headerPlaceholder: '填写表头',
typesettingType2: '横向 A4',
typesettingType1: '竖向 A4',
AnnotationList: '批注列表',
Annotations: '批注',
exportWord: '导出 Word',
exportImg: '导出 图片',
PaperRotation: '纸张方向',
removeAnnotations:'确定要删除这条批注吗?',
removeContent:'确定要删除这条内容吗?',
reContent:'确定要恢复这条内容吗?',
uploadImageInfo:'Figures 只能上传 JPG、JPEG 和 PNG 格式的文件'
},
}

View File

@@ -20,7 +20,7 @@
<span v-else class="el-icon-pie-chart notPass status"> Pending</span>
</h5>
<div class="con">
<h4>Generate charts </h4>
<h4>HTML Proofread </h4>

View File

@@ -1,971 +0,0 @@
<template>
<div style="height: 98%">
<div class="crumbs">
<el-breadcrumb separator="/">
<el-breadcrumb-item> <i class="el-icon-document-copy"></i> Generate Charts </el-breadcrumb-item>
</el-breadcrumb>
</div>
<div
class="container"
style="height: 97%; min-width: calc(1000px - 300px); width: calc(100% - 300px); background-color: #fafafa; padding: 10px 0 0 0"
>
<h3 class="man_Title">
{{ detailTitle }}
</h3>
<div class="type_MTxt" style="box-sizing: border-box">
<div
v-for="(item, index) in Main_List"
@dragover.prevent
:class="item.p_main_img_id ? 'imgBox' : ''"
@drop="onDrop($event, index)"
>
<p v-html="item.text" v-if="!item.p_main_img_id"></p>
<p v-if="item.p_main_img_id" class="MaxPicture">
<img :src="baseUrl + 'public/mainimg/' + item.content" :style="'width:' + item.width + 'px'" />
<font :style="'width:' + item.width + 'px'">{{ item.note }} </font>
</p>
<font v-if="item.getnum != 0" class="chNumer">{{ item.getnum }}</font>
<b
class="MaxBtn"
@click="MTxtEdit(item, index)"
style="background-color: #006699; right: 40px"
v-if="item.p_main_img_id"
>
<i class="el-icon-edit"></i>
</b>
<!-- <b class="MaxBtn" @click="MTxtPic(item, index)" style="background-color: #13bc20; right: 40px">
<svg
t="1684978324047"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="1967"
width="15"
height="15"
>
<path
d="M512 46.208a42.666667 42.666667 0 0 1 4.992 85.077333L512 131.541333H174.208a42.666667 42.666667 0 0 0-42.368 37.717334l-0.298667 4.949333v487.850667L307.2 501.12a88.874667 88.874667 0 0 1 112.042667-6.570667l5.845333 4.608 150.442667 128.896 101.973333-101.888a88.874667 88.874667 0 0 1 110.122667-12.373333l6.058666 4.138667 104.832 78.592V512a42.666667 42.666667 0 0 1 85.077334-4.992l0.298666 4.992v342.698667a128 128 0 0 1-120.490666 127.786666l-7.509334 0.213334H174.208a128 128 0 0 1-127.786667-120.490667l-0.213333-7.509333V174.208a128 128 0 0 1 120.490667-127.786667l7.509333-0.213333H512zM366.378667 563.2l-1.536 0.853333-233.301334 213.76v76.885334a42.666667 42.666667 0 0 0 37.717334 42.368l4.949333 0.298666H855.893333a42.666667 42.666667 0 0 0 42.368-37.717333l0.298667-4.949333v-151.808l-3.285333-2.090667-152.789334-114.602667a3.541333 3.541333 0 0 0-3.2-0.554666l-1.450666 0.853333-97.28 97.28 76.970666 66.048a42.666667 42.666667 0 0 1-51.2 68.010667l-4.309333-3.2-292.437333-250.666667a3.541333 3.541333 0 0 0-3.2-0.768z m415.829333-516.992a42.666667 42.666667 0 0 1 42.410667 37.717333l0.256 4.949334v96h96a42.666667 42.666667 0 0 1 4.992 85.077333l-4.992 0.256h-96v96a42.666667 42.666667 0 0 1-85.034667 4.992l-0.298667-4.992v-96h-96a42.666667 42.666667 0 0 1-4.949333-85.034667l4.949333-0.298666h96v-96a42.666667 42.666667 0 0 1 42.666667-42.666667z"
fill="#ffffff"
p-id="1968"
></path>
</svg>
</b> -->
<!-- <b class="MaxBtn" @click="MTxtTable(item, index)" style="background-color: #e07404; right: 0px">
<i class="el-icon-document-add"></i>
</b> -->
<b
class="MaxBtn"
@click="MTxtDelet(item, index)"
style="background-color: #bc1a13; right: 0px"
v-if="item.p_main_img_id"
>
<i class="el-icon-delete"></i>
</b>
</div>
</div>
<div style="height: 20px" v-if="Art_Doi == undefined"></div>
<div style="margin: 20px 0 0 0; text-align: center; padding-bottom: 30px" v-if="Art_Doi != undefined">
<el-button icon="el-icon-finished" type="primary" style="width: 350px" @click="pushOnline()"> Push Online </el-button>
</div>
</div>
<div
class="right-side"
style="
width: 300px;
position: fixed;
right: 20px;
top: 17vh;
bottom: 10px;
background-color: #fff;
box-shadow: 0 1px 3px rgb(16 17 19 / 6%);
border-radius: 4px;
"
>
<p style="padding: 10px 10px; box-sizing: border-box; font-weight: bold">
Unfettered area
<b class="MaxBtn" @click="MTxtPic()" style="background-color: #13bc20; right: 40px; top: 5px">
<svg
t="1684978324047"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="1967"
width="15"
height="15"
>
<path
d="M512 46.208a42.666667 42.666667 0 0 1 4.992 85.077333L512 131.541333H174.208a42.666667 42.666667 0 0 0-42.368 37.717334l-0.298667 4.949333v487.850667L307.2 501.12a88.874667 88.874667 0 0 1 112.042667-6.570667l5.845333 4.608 150.442667 128.896 101.973333-101.888a88.874667 88.874667 0 0 1 110.122667-12.373333l6.058666 4.138667 104.832 78.592V512a42.666667 42.666667 0 0 1 85.077334-4.992l0.298666 4.992v342.698667a128 128 0 0 1-120.490666 127.786666l-7.509334 0.213334H174.208a128 128 0 0 1-127.786667-120.490667l-0.213333-7.509333V174.208a128 128 0 0 1 120.490667-127.786667l7.509333-0.213333H512zM366.378667 563.2l-1.536 0.853333-233.301334 213.76v76.885334a42.666667 42.666667 0 0 0 37.717334 42.368l4.949333 0.298666H855.893333a42.666667 42.666667 0 0 0 42.368-37.717333l0.298667-4.949333v-151.808l-3.285333-2.090667-152.789334-114.602667a3.541333 3.541333 0 0 0-3.2-0.554666l-1.450666 0.853333-97.28 97.28 76.970666 66.048a42.666667 42.666667 0 0 1-51.2 68.010667l-4.309333-3.2-292.437333-250.666667a3.541333 3.541333 0 0 0-3.2-0.768z m415.829333-516.992a42.666667 42.666667 0 0 1 42.410667 37.717333l0.256 4.949334v96h96a42.666667 42.666667 0 0 1 4.992 85.077333l-4.992 0.256h-96v96a42.666667 42.666667 0 0 1-85.034667 4.992l-0.298667-4.992v-96h-96a42.666667 42.666667 0 0 1-4.949333-85.034667l4.949333-0.298666h96v-96a42.666667 42.666667 0 0 1 42.666667-42.666667z"
fill="#ffffff"
p-id="1968"
></path>
</svg> </b
><b class="MaxBtn" @click="MTxtTable()" style="background-color: #e07404; right: 0px; top: 5px">
<i class="el-icon-document-add"></i>
</b>
</p>
<div class="unfetteredBox">
<div
:style="item.isHidden ? 'opacity:0.2' : 'opacity:1'"
v-for="(item, index) in images"
:key="index"
class="image"
draggable="true"
@dragstart="onDragStart($event, item, index)"
>
<img :src="baseUrl + 'public/mainimg/' + item.content" style="width: 100%; height: 100%; object-fit: cover" />
</div>
</div>
</div>
<!--修改文本 -->
<el-dialog title="Edit Text" :visible.sync="txtVisible" width="800px" :close-on-click-modal="false">
<el-form ref="editMes" :model="txtStyle" label-width="1px">
<p style="margin: 0 5px 15px 5px; line-height: 18px; font-size: 13px; color: #aaa">{{ exegesis }}</p>
<el-form-item label="">
<el-input type="textarea" placeholder="Please enter the table content..." v-model="txtStyle.text" autosize> </el-input>
</el-form-item>
</el-form>
<p class="type_Gbtn" @click="trsanGtp">
<i class="el-icon-document-copy" style="margin-right: 5px" v-if="btnDisble"></i>
<i class="el-icon-loading" style="margin-right: 5px" v-if="!btnDisble"></i>
TMRGTP Proofreading
</p>
<div class="type_CHar" v-if="txtStyle.ChGtpTxt != ''">
<p v-html="txtStyle.ChGtpTxt"></p>
<font class="chReple" @click="replceChGpr(item)">Replace</font>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="txtVisible = false"> Cancel </el-button>
<el-button type="primary" @click="saveTxt">
<i class="el-icon-finished" style="margin-right: 5px"></i>
Save
</el-button>
</span>
</el-dialog>
<!--添加/修改图片 -->
<el-dialog :title="picStyle.visiTitle" :visible.sync="pictVisible" width="800px" :close-on-click-modal="false">
<el-form ref="editMes" :model="picStyle" label-width="150px">
<el-form-item>
<span slot="label">
<font style="color: #f56c6c; margin-right: 5px">*</font>
Picture :
</span>
<el-upload
class="avatar-uploader"
:action="'/api/api/Production/up_mainimg_file'"
:show-file-list="false"
name="mainimg"
:on-success="handleAvatarSuccess"
:on-error="handleAvatarError"
:before-upload="beforeAvatarUpload"
>
<img v-if="picStyle.imageUrl" :src="picStyle.imageUrl" class="avatar" />
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form-item>
<!-- <el-form-item label="Bottom Title :">
<el-input placeholder="Please enter the table title..." v-model="picStyle.titleBot">
</el-input>
</el-form-item> -->
<el-form-item label="Picture Describe :">
<el-input placeholder="Please enter the table describe..." v-model="picStyle.note" type="textarea" :rows="3">
</el-input>
</el-form-item>
</el-form>
<p style="margin: 20px 0; text-align: right">
<el-button
type="warning"
plain
@click="
picStyle.picUrl = '';
picStyle.titleBot = '';
picStyle.note = '';
picStyle.imageUrl = '';
"
>
<i class="el-icon-refresh" style="margin-right: 5px"></i>Empty
</el-button>
</p>
<div class="lineStyle" v-if="picStyle.picUrl != ''">
<div>
<span class="title" style="margin-left: 25px">Picture Width :</span>
<el-input v-model="picStyle.width" style="width: 120px">
<template slot="append">px</template>
</el-input>
</div>
</div>
<div style="padding: 0 20px" v-if="picStyle.picUrl != ''">
<div style="text-align: center">
<img :src="baseUrl + 'public/mainimg/' + picStyle.picUrl" :style="'width:' + picStyle.width + 'px'" />
</div>
<p style="text-align: center; margin: 10px 0 15px 0; font-size: 12px; color: #006699">
<b>{{ picStyle.titleBot }}</b>
</p>
<p
style="text-align: center; margin: 10px auto 0; font-size: 12px; line-height: 22px"
:style="'width:' + picStyle.width + 'px'"
v-html="picStyle.note"
></p>
</div>
<span slot="footer" class="dialog-footer" v-if="picStyle.picUrl != ''">
<el-button @click="pictVisible = false"> Cancel </el-button>
<el-button type="primary" @click="savePic">
<i class="el-icon-finished" style="margin-right: 5px"></i>
Save Picture
</el-button>
</span>
</el-dialog>
<!-- 添加表格 -->
<el-dialog title="Insert Table" :visible.sync="threeVisible" width="1200px" :close-on-click-modal="false" >
<el-form ref="editMes" :model="lineStyle" label-width="115px">
<el-form-item label="Top Title :">
<el-input placeholder="Please enter the table title..." v-model="lineStyle.titleTop"> </el-input>
</el-form-item>
<el-form-item label="Word">
<span slot="label">
<font style="color: #f56c6c; margin-right: 5px">*</font>
Content :
</span>
<common-table ref="commonTable" style="margin-left: -115px;" :lineStyle="lineStyle"></common-table>
</el-form-item>
<el-form-item label="Bottom Title :">
<el-input placeholder="Please enter the table title..." v-model="lineStyle.titleBot"> </el-input>
</el-form-item>
</el-form>
<p style="margin: 20px 0; text-align: right">
<el-button
type="warning"
plain
@click="
lineStyle.textarea = '';
lineStyle.titleTop = '';
lineStyle.titleBot = '';
lineTable = [];
"
>
<i class="el-icon-refresh" style="margin-right: 5px"></i>Empty
</el-button>
<el-button type="primary" plain @click="CopyExcelToTable">
<i class="el-icon-sort" style="margin-right: 5px"></i>Generate Table
</el-button>
</p>
<div class="lineStyle" v-if="lineTable.length != 0">
<div>
<span class="title">Table All Width :</span>
<el-input v-model="lineStyle.tabwith" style="width: 120px">
<template slot="append">%</template>
</el-input>
</div>
<div>
<div v-for="(item, index) in lineStyle.arrwith" class="styArry">
<span class="title"
>Column <b style="color: #006699">{{ index + 1 }}</b> :</span
>
<el-input v-model="lineStyle.arrwith[index]" style="width: 100px">
<template slot="append">%</template>
</el-input>
</div>
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="saveLine" v-if="lineTable.length != 0">
<i class="el-icon-finished" style="margin-right: 5px"></i>
Save Table
</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { del } from 'vue';
export default {
data() {
return {
images: [
{
p_main_img_id: 157,
p_article_id: 2141,
p_main_id: 101853,
pre_id: 0,
width: 500,
content: '20240906/7c4cfd8f431cddf05f33634d4ee2cdca.jpg',
note: 'Figure 1 Oracle bone inscriptions of YANG',
ctime: 0,
state: 0
}
],
baseUrl: this.Common.baseUrl,
baseUrl: 'https://submission.tmrjournals.com/',
mediaUrl: this.Common.mediaUrl,
Art_Id: this.$route.query.id,
Art_Doi: this.$route.query.doi,
Art_web_Id: this.$route.query.artID,
Art_P_Id: '',
btnDisble: true,
detailTitle: '',
Main_List: [],
txtStyle: {
text: '',
ChGtpTxt: ''
},
txtVisible: false,
lineStyle: {
titleTop: '',
titleBot: '',
textarea: '',
tableData: [],
tabwith: '100',
arrwith: []
},
lineTable: [],
threeVisible: false,
picStyle: {
titleBot: '',
note: '',
// picUrl: 'https://www.tmrjournals.cn/public/articleHTML/TMR/TMR20230213002/images/alternativeImage/TMR20230213002-F004.jpg',
picUrl: '',
imageUrl: '',
width: '500'
},
pictVisible: false,
typesettingType: 1,
exegesis: "The following contents'<b></b>,<i></i>'are necessary for the generation phase, please do not delete them!!!"
};
},
created() {
this.getDate();
},
methods: {
onDragStart(event, image, index) {
event.dataTransfer.setData('image', JSON.stringify({ ...image, isNewReformat: true }));
event.dataTransfer.setData('imageIndex', index);
},
onDrop(event, index) {
console.log('index at line 297:', index);
const draggedImage = JSON.parse(event.dataTransfer.getData('image'));
const draggedImageIndex = JSON.parse(event.dataTransfer.getData('imageIndex'));
console.log('draggedImage at line 298:', draggedImage);
this.Main_List.splice(index, 0, draggedImage);
this.images[draggedImageIndex].isHidden = true;
},
// 获取数据
getDate() {
let urlLInk = '';
let urlTask = {};
if (this.Art_Id != undefined) {
urlLInk = 'api/Production/getProductionMains';
urlTask.p_article_id = this.Art_Id;
}
// if (this.Art_Doi != undefined) {
// urlLInk = 'api/Production/getProductionMainsByDoi';
// urlTask.doi = this.Art_Doi;
// }
const loading = this.$loading({
lock: true,
text: 'Loading...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
// 获取文章信息
this.$api
.post(urlLInk, urlTask)
.then((res) => {
if (res.code == 0) {
this.detailTitle = res.data.production.title;
this.Art_P_Id = res.data.production.p_article_id;
this.Main_List = res.data.mains;
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;
}
loading.close();
} else {
this.$message.error(res.msg);
loading.close();
}
})
.catch((err) => {
this.$message.error(err);
loading.close();
});
},
// 修改段落/图片
MTxtEdit(val, num) {
this.picStyle = JSON.parse(JSON.stringify(val));
this.picStyle.picUrl = this.picStyle.content;
this.picStyle.imageUrl = this.baseUrl + 'public/mainimg/' + this.picStyle.content;
this.picStyle.visiTitle = 'Edit Picture';
this.pictVisible = true;
},
// 转化为gpt标准格式
trsanGtp() {
if (this.btnDisble) {
this.btnDisble = false;
this.$api
.post('api/Production/mainGptcheck', {
p_main_id: this.txtStyle.p_main_id
})
.then((res) => {
if (res.code == 0) {
this.txtStyle.ChGtpTxt = res.data.content;
this.btnDisble = true;
// this.$forceUpdate()
this.$message.success('Converting success!');
} else {
this.btnDisble = true;
this.$message.error('Converting fail!');
}
})
.catch((err) => {
this.btnDisble = true;
this.$message.error('Converting fail!');
});
} else {
this.$message.warning('Converting, please wait!');
}
},
// 替换Gtp生成的内容
replceChGpr(val) {
this.txtStyle.text = JSON.parse(JSON.stringify(this.txtStyle.ChGtpTxt));
},
// 确定保存段落修改
saveTxt() {
this.$api
.post('api/Production/editProductionMain', {
p_main_id: this.txtStyle.p_main_id,
content: this.txtStyle.text
})
.then((res) => {
if (res.code == 0) {
this.$message.success('Successfully edit text!');
this.txtVisible = false;
this.getDate();
// this.Main_List[this.txtStyle.index].text = JSON.parse(JSON.stringify(this.txtStyle.text))
} else {
this.$message.error(res.msg);
}
})
.catch((err) => {
this.$message.error(err);
});
},
// 图片段落
MTxtPic(val, num) {
this.picStyle.pre_type = 'img';
// this.picStyle.body = val.p_main_img_id;
this.picStyle.p_article_id = this.Art_P_Id;
this.picStyle.titleBot = '';
this.picStyle.note = '';
this.picStyle.width = '500';
this.picStyle.picUrl = '';
this.picStyle.imageUrl = '';
this.picStyle.visiTitle = 'Insert Picture Backward';
this.pictVisible = true;
},
// 确定保存图片
savePic() {
this.picStyle.content = this.picStyle.picUrl;
this.images.push(this.picStyle);
this.pictVisible = false;
return false;
//要走接口
if (this.picStyle.note == '') {
this.$message.error('Please fill in the picture describe!');
return;
}
this.picStyle.content = this.picStyle.picUrl;
if (this.picStyle.visiTitle == 'Edit Picture') {
this.$api
.post('api/Production/editProductionMainImg', this.picStyle)
.then((res) => {
if (res.code == 0) {
this.$message.success('Successfully edit image!');
this.pictVisible = false;
this.getDate();
} else {
this.$message.error(res.msg);
}
})
.catch((err) => {
this.$message.error(err);
});
} else {
this.$api
.post('api/Production/addProductionMainImg', this.picStyle)
.then((res) => {
if (res.code == 0) {
this.$message.success('Successfully added image!');
this.pictVisible = false;
this.getDate();
} else {
this.$message.error(res.msg);
}
})
.catch((err) => {
this.$message.error(err);
});
}
},
async removeEvent(row) {
// const type = await VXETable.modal.confirm('您确定要删除该数据?')
const $table = this.$refs.xTable;
// if (type === 'confirm') {
$table.remove(row);
// }
},
async insertEvent(row) {
const $table = this.$refs.xTable;
const record = {};
const { row: newRow } = await $table.insertAt(record, row);
await $table.setEditCell(newRow, 'name');
},
// 表格段落
MTxtTable(val, num) {
// this.lineStyle.p_main_id = val.p_main_id;
this.lineStyle.textarea = '';
this.lineStyle.titleCon = '';
this.lineTable = [];
this.threeVisible = true;
this.typesettingType = '1';
this.$forceUpdate();
},
// 表格转化
CopyExcelToTable() {
if (this.lineStyle.textarea == '') {
this.$message.error('Please fill in the table content!');
return;
}
console.log(this.lineStyle.textarea);
let txtRows = this.lineStyle.textarea.split('\n');
let txtColum = [];
for (let i = 0; i < txtRows.length; i++) {
if (txtRows[i] != '') {
let columns = txtRows[i].split('\t');
let dataone = [];
for (let j = 0; j < columns.length; j++) {
dataone.push(columns[j]);
}
txtColum.push(dataone);
}
}
let arrwithNumer = Math.floor(100 / txtColum[0].length) - 2;
this.lineStyle.arrwith = [];
for (let i = 0; i < txtColum[0].length; i++) {
this.lineStyle.arrwith.push(arrwithNumer);
}
this.lineTable = txtColum;
},
// 确定保存表格
saveLine() {
let dataTable = '';
for (let i = 0; i < this.lineTable.length; i++) {
let ArryDr = '';
let listHNem = '';
for (let j = 0; j < this.lineTable[i].length; j++) {
let ArrHtml =
'<div style="width:' +
this.lineStyle.arrwith[j] +
'%;line-height: 22px;vertical-align: middle;display: inline-block;padding: 0 1%;font-size: 14px;color: #606266;word-wrap: break-word;word-break: normal;">' +
this.lineTable[i][j] +
'</div>';
ArryDr = ArryDr + ArrHtml;
}
if (i == 0) {
listHNem =
'<div style="display: flex;border-top: 2px solid #333333;border-bottom: 1px solid #333333;padding: 10px 0;font-weight: bold;margin-bottom: 20px;">' +
ArryDr +
'</div>';
} else if (i == this.lineTable.length - 1) {
listHNem = '<div style="display: flex;border-bottom: 2px solid #333333;padding:0 0 20px 0;">' + ArryDr + '</div>';
ArryDr = ArryDr + listHNem;
} else {
listHNem = '<div style="display: flex;padding:20px 0;">' + ArryDr + '</div>';
}
dataTable = dataTable + listHNem;
}
dataTable = '<div style="width:' + this.lineStyle.tabwith + '%">' + dataTable + '</div>';
if (this.lineStyle.titleTop != '') {
dataTable =
'<p style="text-align: center;margin: 0 0 10px 0;font-size: 12px;color: #006699;"><b>' +
this.lineStyle.titleTop +
'</b></p>' +
dataTable;
}
if (this.lineStyle.titleBot != '') {
dataTable =
dataTable + '<p style="text-align: center;margin: 10px 0 0 0;font-size: 12px;">' + this.lineStyle.titleBot + '</p>';
}
console.log(dataTable);
},
// 删除段落/图片
MTxtDelet(val, index) {
var imageIndex = this.images.findIndex((e) => e.p_main_img_id == val.p_main_img_id);
if (imageIndex > -1) {
delete this.images[imageIndex].isHidden;
} else {
this.images.push(val);
}
this.$forceUpdate();
this.Main_List.splice(index, 1);
console.log('this.images.push at line 654:', this.images);
// this.$api
// .post('api/Production/delProductionMainImg', {
// p_main_img_id: val.p_main_img_id
// })
// .then((res) => {
// if (res.code == 0) {
// this.$message.success('Successfully deleted!');
// this.getDate();
// // this.Main_List.splice(num, 1);
// } else {
// this.$message.error(res.msg);
// }
// })
// .catch((err) => {
// this.$message.error(err);
// });
},
// 推送
pushOnline() {
// 二次确认
this.$confirm('Are you sure you want to push it to the official website?', 'Tips', {
type: 'warning'
})
.then(() => {
this.$api
.post('api/Production/pushMainToWeb', {
article_id: this.Art_web_Id,
p_article_id: this.Art_P_Id
})
.then((res) => {
if (res.code == 0) {
this.$message.success('Successfully push!');
this.getDate();
if (this.Art_Doi != undefined) {
this.$router.push({
path: 'comArtHtmlEdit',
query: {
artID: this.Art_web_Id
}
});
}
} else {
this.$message.error(res.msg);
}
})
.catch((err) => {
this.$message.error(err);
});
})
.catch(() => {});
},
// 上传图片
handleAvatarSuccess(res, file) {
if (res.code == 0) {
this.picStyle.picUrl = res.upurl;
this.$forceUpdate();
} else {
this.$message.error(res.msg);
}
this.picStyle.imageUrl = URL.createObjectURL(file.raw);
},
handleAvatarError(res, file) {},
beforeAvatarUpload(file) {
const isLt2M = file.size / 1024 / 1024 < 1;
if (!isLt2M) {
this.$message.error('Picture size cannot exceed 1M!');
}
return isLt2M;
}
}
};
</script>
<style scoped>
.lineStyle {
border-top: 1px solid #0066994d;
padding: 20px 20px 40px 20px;
}
.lineStyle > div {
}
.lineStyle > div span.title {
font-size: 14px;
color: #606266;
margin: 0px 10px 0px 0px;
}
.lineStyle > div font.mark {
font-size: 14px;
color: #606266;
margin: 0px 0px 0px 10px;
}
.lineStyle .styArry {
display: inline-block;
margin: 15px 40px 0 0;
}
.lineStyle .styArry:nth-last-child(1) {
margin-right: 0;
}
.lineAll {
margin: 0 auto;
}
.lineAll .lineTit {
padding: 0 0 20px 0;
font-size: 14px;
}
.lineAll .lineTit:nth-child(1) {
border-top: 2px solid #333333;
border-bottom: 1px solid #333333;
padding: 10px 0;
font-weight: bold;
}
.lineAll .lineTit:nth-child(2) {
padding-top: 20px;
}
.lineAll .lineTit:nth-last-child(1) {
border-bottom: 2px solid #333333;
}
.lineAll .lineTit > div {
line-height: 22px;
vertical-align: middle;
display: inline-block;
padding: 0 1%;
}
.man_Title {
background-color: #fff;
margin: 0 0 10px 0;
border-bottom: 1px solid #dde1eb;
box-shadow: 0 5px 5px -2px rgb(134 134 134);
padding: 12px 25px 8px 25px;
font-size: 16px;
line-height: 24px;
color: #333;
position: relative;
}
.man_Title button {
position: absolute;
top: 10px;
right: 10px;
}
.type_MTxt {
background-color: #fff;
padding: 0 10px 10px 10px;
box-shadow: 0 1px 3px rgb(16 17 19 / 6%);
position: relative;
}
.type_MTxt > div {
position: relative;
padding: 8px 15px;
min-height: 22px;
border: 2px dashed #fff;
border-radius: 5px;
color: #606266;
}
.type_MTxt > .imgBox:hover {
background-color: rgb(0 102 153 / 10%);
border: 2px dashed rgb(0 102 153 / 50%);
}
.type_MTxt > div > p {
font-size: 14px;
line-height: 22px;
}
.type_MTxt > .imgBox .chNumer {
position: absolute;
top: -2px;
right: -1px;
border-radius: 3px;
font-size: 10px;
background-color: rgb(0 102 153 / 85%);
color: #fff;
padding: 0 6px;
}
.type_MTxt > div .MaxPicture {
text-align: center;
}
.type_MTxt > div .MaxPicture > img {
margin-bottom: 10px;
}
.type_MTxt > div .MaxPicture > font {
display: block;
margin: 0 auto;
font-size: 13px;
}
.MaxBtn {
position: absolute;
right: 0;
top: -1px;
color: #fff;
border-radius: 50px;
font-size: 15.5px;
padding: 6px 7px;
display: none;
opacity: 0.75;
}
.MaxBtn {
display: block;
}
.MaxBtn:hover {
opacity: 1;
cursor: pointer;
}
.type_Gbtn {
color: #fff;
border-color: #006699;
background: #006699;
width: 30%;
text-align: center;
padding: 8px 0;
font-size: 14px;
border-radius: 8px;
font-weight: 500;
margin: 0 auto;
}
.type_Gbtn:hover {
box-shadow: 0 4px 14px rgb(0 102 153 / 30%);
cursor: pointer;
}
.type_CHar {
position: relative;
border-left: 4px solid rgba(0 102 153 / 20%);
border-radius: 5px;
padding: 20px 25px 15px 20px;
background-color: #fff;
margin: 20px 0 0 0;
font-size: 14px;
line-height: 22px;
box-shadow: 0 1px 10px rgb(0 102 153 / 20%);
}
.type_CHar .chReple {
position: absolute;
top: -1px;
right: 1px;
border-radius: 3px;
font-size: 10px;
background-color: rgb(223 109 11);
opacity: 0.85;
color: #fff;
padding: 1px 10px;
}
.type_CHar .chReple:hover {
opacity: 1;
cursor: pointer;
}
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
width: 100px;
height: 100px;
}
.avatar-uploader_small {
height: 100px;
}
.avatar-uploader .el-upload:hover {
border-color: #409eff;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 120px;
height: 120px;
line-height: 120px;
text-align: center;
}
.avatar-uploader_small .el-upload {
width: 80px;
height: 80px;
}
.avatar-uploader_small .avatar-uploader-icon {
line-height: 80px;
margin-left: -30px;
}
.avatar {
width: 120px;
height: 120px;
display: block;
}
.unfetteredBox {
display: flex;
flex-wrap: wrap;
padding: 0 10px;
box-sizing: border-box;
}
.unfetteredBox .image {
margin-top: 10px;
box-shadow: rgba(16, 17, 19, 0.5) 0px 1px 3px;
margin-right: 10px;
height: 60px;
width: 60px;
border-radius: 4px;
overflow: hidden;
}
</style>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -82,7 +82,9 @@
</div>
</el-col>
</el-row>
<common-word-html v-if="articleInfo.article_id" :articleId="articleInfo.article_id" style=" box-sizing: border-box"></common-word-html>
</div>
</div>
<!-- end -->
@@ -97,6 +99,7 @@
<el-radio :label="3">Revison</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="Comments to the authors" v-if="questionform.recommend == 3">
<el-input type="textarea" placeholder="please input content" v-model="questionform.content"
:rows="8"></el-input>

View File

@@ -5,7 +5,9 @@
<el-breadcrumb-item> <i class="el-icon-uthorVisiblelx-cascades"></i> Submit manuscript </el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="step_list" style="width: 960px; position: relative">
<div style="display: flex;justify-content: space-between;">
<div>
<div class="step_list" style="width: 960px; position: relative">
<div v-for="item in listStep" @click="StepCode(item.index)" :class="show_step == item.index ? 'C_style' : ''">
<div>
<i :class="item.icon"></i>
@@ -15,39 +17,8 @@
<p class="bor_der"></p>
</div>
<br clear="both" />
<!-- <p
style="position: absolute;line-height: 20px;color: #999;left:990px;top: 600px;width: 280px;font-size: 14px;">
We encourage authors to upload a Cover Letter file and Highlights is also be encouraged. That will help
authors let editors quickly obtain information and evaluate the
scientific value of their research correctly.
<br>Please remind our editor in the cover letter if you want your manuscript processed quickly.
<br>Please note that manuscripts with at least one of the following characteristics will be included in
the
journal's manuscript fast track:
<br>
<font style="color: #006699;">1.Interest:</font> This manuscript has a novel perspective.
<br>
<font style="color: #006699;">2.Importance:</font> This manuscript belongs to the focus area.
<br>
<font style="color: #006699;">3.Value:</font> This manuscript belongs to the advanced topic and can
attract wide
attention.
</p> -->
<p style="position: absolute; line-height: 20px; color: #999; left: 990px; top: 120px; width: 280px; font-size: 14px">
We highly encourage authors to upload a Cover Letter file and Highlights, as this will assist editors in quickly obtaining
accurate information and evaluating the scientific value of their research. If you would like your manuscript to be
processed quickly, please kindly remind our editor in the cover letter.
<br />Additionally, please take note that manuscripts exhibiting at least one of the following characteristics will be
considered for the journal's fast track process:
<br />
<font style="color: #006699">Interest:</font> The manuscript presents a unique perspective.
<br />
<font style="color: #006699">Importance:</font> The manuscript aligns with the journal's focus area.
<br />
<font style="color: #006699">Value:</font> The manuscript addresses an advanced topic that has the potential to garner
widespread attention.
</p>
</div>
<div class="manu_add" style="width: 960px" v-loading="loading">
<el-form ref="articleform" :model="form" :rules="rules" label-width="160px">
<div class="bag_color" v-if="show_step == 1">
@@ -438,7 +409,7 @@
</el-form-item> -->
<el-form-item label="Manuscirpt :" prop="manuscirpt" label-width="200px">
<el-upload
ref="uploadFile"
ref="uploadFileManuscirpt"
class="upload-demo up_newstyle"
:action="upload_manuscirpt"
accept=".docx"
@@ -452,7 +423,7 @@
:file-list="fileL_manuscirpt"
:on-preview="dowloadFile"
>
<div class="el-upload__text" @click="clearUploadedFile">
<div class="el-upload__text" @click="removefilemanuscirpt">
<em>Upload</em>
</div>
<div class="el-upload__tip" slot="tip">
@@ -733,6 +704,55 @@
</div>
</el-form>
</div>
</div>
<div
style="
padding: 0;
background: none;
margin-top: 30px;
line-height: 20px;
color: #999;
left: 990px;
top: 120px;
width: 400px;
font-size: 14px;
"
>
<p
style="
width: 400px;
border: 1px solid #ebeef5;
font-size: 12px;
line-height: 16px;
background-color: #fff;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
border-radius: 8px;
padding: 10px;
box-sizing: border-box;
"
>
We encourage authors to upload a Cover Letter file and Highlights is also be encouraged. That will help authors let editors
quickly obtain information and evaluate the scientific value of their research correctly.
<br />Please remind our editor in the cover letter if you want your manuscript processed quickly. <br />Please note that
manuscripts with at least one of the following characteristics will be included in the journal's manuscript fast track:
<br />
<font style="color: #006699">1.Interest:</font> This manuscript has a novel perspective.
<br />
<font style="color: #006699">2.Importance:</font> This manuscript belongs to the focus area.
<br />
<font style="color: #006699">3.Value:</font> This manuscript belongs to the advanced topic and can attract wide attention.
</p>
<common-word-html
v-show="show_step == 3"
:articleId="stagingID"
imgHeight="120px"
v-if="isShowCommonWord&&stagingID"
style="margin-top: 10px; box-sizing: border-box; background-color: #fff"
></common-word-html>
</div>
</div>
<el-dialog title="" :visible.sync="licensebox" width="500px">
<span style="word-wrap: break-word; word-break: normal; line-height: 22px">
Creative Commons Licensing<br /><br />
@@ -879,6 +899,7 @@ export default {
usercap: localStorage.getItem('U_role'),
ms_alias: localStorage.getItem('ms_journal_alias'),
stagingID: this.$route.query.id,
isShowCommonWord: false,
move_step: 1, //进行步骤
show_step: 1, //显示内容
items: [],
@@ -1290,10 +1311,20 @@ export default {
value: 'journal_topic_id', // 自定义要映射的键名
label: 'title',
children: 'children'
}
},
tables: [],
wordimgList: [],
tablesHtml: [],
imagesHtml: []
};
},
watch: {
collapseValue: {
handler(e) {
console.log(e);
},
immediate: true
},
form: {
handler(e) {
// console.log(e)
@@ -1313,6 +1344,9 @@ export default {
}
},
computed: {
collapseValue() {
return localStorage.getItem('collapse');
},
upload_articleApproval: function () {
return this.baseUrl + 'api/Article/up_approval_file';
},
@@ -1585,30 +1619,30 @@ export default {
// 邮箱用户模糊搜索
chaMateFit(value, cb, num) {
console.log('num at line 1587:', value)
console.log('num at line 1587:', value);
// var mailRegular = /^\w+([-+._']\w+)*@\w+(\.[a-zA-Z]{2,3}){1,2}$/
var mailRegular = /^\w+([-+._']\w+)*@/;
// if (mailRegular.test(value)) {
this.form.authorList[num].load = true;
// this.$forceUpdate();
this.$api
.post('api/Article/getRelationAuthorByEmail', {
email: value,
page: 1,
limit: 10
})
.then((res) => {
var restaurants = res.data.authors;
for (let i in restaurants) {
restaurants[i].value = restaurants[i].email + ' | ' + restaurants[i].firstname + restaurants[i].lastname;
}
var results = value ? restaurants.filter(this.createMata(value)) : restaurants;
console.log('🚀 ~ .then ~ results177:', results);
// 调用 callback 返回建议列表的数据
cb(results);
this.form.authorList[num].load = false;
this.$forceUpdate();
});
this.form.authorList[num].load = true;
// this.$forceUpdate();
this.$api
.post('api/Article/getRelationAuthorByEmail', {
email: value,
page: 1,
limit: 10
})
.then((res) => {
var restaurants = res.data.authors;
for (let i in restaurants) {
restaurants[i].value = restaurants[i].email + ' | ' + restaurants[i].firstname + restaurants[i].lastname;
}
var results = value ? restaurants.filter(this.createMata(value)) : restaurants;
console.log('🚀 ~ .then ~ results177:', results);
// 调用 callback 返回建议列表的数据
cb(results);
this.form.authorList[num].load = false;
this.$forceUpdate();
});
// }
},
@@ -2062,7 +2096,7 @@ export default {
this.$message.error('Only ZIP files can be uploaded (file format: .zip).');
return false;
}
// const iszip =
// file.type === 'application/x-zip-compressed';
// if (!iszip) {
@@ -2073,12 +2107,14 @@ export default {
},
beforeupload_totalpage(file) {},
beforeupload_manuscirpt(file) {
console.log('file at line 2075:', file);
let flieArr = file.name.split('.');
let fileSuffix = flieArr[flieArr.length - 1];
if (fileSuffix != 'docx') {
this.$message.error('Only word and compressed files can be uploaded(.docx)');
return false;
}
// const ismau =
// file.type === 'application/msword' ||
// file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ||
@@ -2147,12 +2183,48 @@ export default {
this.$message.error('service error' + res.msg);
}
},
upSuccess_manuscirpt(res, file) {
addWordTablesList(tables) {
console.log('tables at line 2187:', tables)
console.log('this.fileMesForm at line 2189:', this.stagingID)
var data = {
article_id: this.stagingID,
list: tables.map(e=>( {
table: JSON.stringify([...e]),
type: 0,
html_data: ''
})),
};
this.$api.post('api/Article/addArticleTable', data).then((res) => {
this.isShowCommonWord=true
});
},
upLoadWordTables() {},
upSuccess_manuscirpt(res, File) {
// console.log('file at line 2174:', file.raw)
if (File) {
var that = this;
const reader = new FileReader();
reader.onload = function (e) {
that.$commonJS.extractWordTablesToArrays(File.raw, function (wordTables) {
console.log('tablesHtml at line 61:', wordTables);
that.addWordTablesList(wordTables);
});
};
reader.readAsArrayBuffer(File.raw);
}
if (res.code == 0) {
this.form.manuscirpt = 'manuscirpt/' + res.upurl;
this.fileL_manuscirpt = [{}];
this.isShowCommonWord=false
this.fileL_manuscirpt[0].name = 'Manuscirpt File';
this.fileL_manuscirpt[0].url = 'manuscirpt/' + res.upurl;
this.onStaging(5);
} else {
this.$message.error('service error: ' + res.msg);
@@ -2197,10 +2269,10 @@ export default {
});
},
removefilepicturesAndTables(file, fileList) {
console.log('file at line 2199:', file)
if(!file){
return false
}
console.log('file at line 2199:', file);
if (!file) {
return false;
}
this.form.picturesAndTables = '';
this.fileL_picturesAndTables = [];
this.$api
@@ -2218,10 +2290,34 @@ return false
removefiletotalpage(file, fileList) {
this.form.totalpage = '';
},
clearFileManuscript() {
this.wordimgList = [];
this.imagesHtml = '';
this.tables = [];
this.tablesHtmlHtml = '';
this.isShowCommonWord=false;
this.$api
.post('api/Article/reloadArticleImages', {
article_id: this.stagingID
})
.then((res) => {});
this.$api
.post('api/Article/reloadArticleTable', {
article_id: this.stagingID
})
.then((res) => {});
},
removefilemanuscirpt(file, fileList) {
console.log('fileList at line 2337:', file, fileList);
if (this.form.manuscirpt != '') {
}
this.form.manuscirpt = '';
this.fileL_manuscirpt = [];
this.$api
this.$refs['uploadFileManuscirpt'].clearFiles();
this.clearFileManuscript();
if(this.form.manuscirptId){
this.$api
.post('api/Article/delArticleFile', {
file_id: this.form.manuscirptId
})
@@ -2232,6 +2328,8 @@ return false
this.$message.error(res.msg);
}
});
}
},
removefilesupplementary() {
this.form.supplementary = '';
@@ -2492,6 +2590,7 @@ return false
// this.$message.error('First author and corresponding author must be exist');
// return;
}
this.move_step = 3; //进行步骤
this.show_step = 3; //显示内容
}
@@ -2517,6 +2616,8 @@ return false
// 暂存
onStaging(e) {
var that = this;
console.log('e at line 2584:', e);
if (e == 1) {
var flist = this.keywordsList;
var fstr = '';
@@ -2538,6 +2639,12 @@ return false
}
});
} else if (e == 2) {
this.isShowCommonWord=false;
setTimeout(() => {
this.isShowCommonWord=true;
// that.getWordTablesList();
// that.getWordimgList();
}, 200);
// for (let i = 0; i < this.form.authorList.length; i++) {
// if (this.form.authorList[i].art_aut_id == undefined) {
// this.form.authorList[i].art_aut_id = 0
@@ -2609,6 +2716,13 @@ return false
.then((res) => {
if (res.code == 0) {
this.form.manuscirptId = res.data.file_id;
console.log('this.form.manuscirpt at line 2652:', this.form.manuscirpt);
console.log('1111111111111111111111111111');
setTimeout(() => {
// that.getWordTablesList();
// that.getWordimgList();
}, 500);
} else {
this.$message.error(res.msg);
}
@@ -3192,4 +3306,7 @@ return false
.partyAry > div > p > font {
color: #777;
}
</style>
::v-deep .el-collapse-item__header {
background-color: transparent !important;
}
</style>

View File

@@ -28,7 +28,7 @@
<font>Title :</font>
<b> {{ form.title }}</b>
</p>
<!-- <p v-show="form.type=='A'">
<font>Ethical Approval :</font><b>{{form.approval?'Yes':'No'}}</b>
</p> -->
@@ -177,14 +177,23 @@
<el-col :span="12">
<h4>Manuscirpt :</h4>
<p class="fi_new">
<a v-for="item in manuscirptFileList" :href="mediaUrl + item.file_url">
<img src="../../assets/img/icon_0.png" />
<span>
<font>Uploader : </font>{{ item.username }}
<i><i class="el-icon-time"></i>{{ formatDate(item.ctime) }}</i>
</span>
<i class="el-icon-download download"></i>
</a>
<template v-for="item in manuscirptFileList">
<a href="#">
<img
src="../../assets/img/icon_0.png"
@click="openDrawer(item, mediaUrl + item.file_url)"
/>
<span @click="openDrawer(item, mediaUrl + item.file_url)">
<font>Uploader : </font>{{ item.username }}
<i><i class="el-icon-time"></i>{{ formatDate(item.ctime) }}</i>
<i class="el-icon-view" style="font-weight: bold; color: #888; margin: 0 0 0 10px"></i>
</span>
<a :href="mediaUrl + item.file_url">
<i class="el-icon-download download"></i>
</a>
</a>
</template>
</p>
<br clear="both" />
</el-col>
@@ -224,6 +233,12 @@
</el-col>
</el-row>
</div>
<common-word-html
:articleId="$route.query.id"
style=" box-sizing: border-box"
></common-word-html>
</div>
<!-- 被拒稿件操作 --->
<div class="art_caozuo_" v-if="opname == 'rejectArticles'">
@@ -445,6 +460,46 @@
<el-button type="primary" @click="saveResubmit">Save</el-button>
</span>
</el-dialog>
<el-drawer
append-to-body
destroy-on-close
:title="previewData.drawerTitle"
:visible.sync="drawer"
direction="rtl"
:before-close="handleClose"
size="1200px"
>
<template #title>
<div style="display: inline-block; vertical-align: top">
Manuscirpt :
<img
src="../../assets/img/icon_0.png"
style="
width: 15px;
margin: 0 5px 0 0;
margin-left: 10px;
"
/>
<span>
<font>Uploader : </font>{{ previewData.username }}
<i style="color: #888; margin: 0 20px; font-style: normal"
><i class="el-icon-time" style="margin-right: 10px"></i>{{ formatDate(previewData.ctime) }}</i
>
<a :href="mediaUrl + previewData.file_url">
<i class="el-icon-download download" style="color: #75abf1; font-weight: bold"></i>
</a>
</span>
</div>
</template>
<iframe
:src="`https://view.officeapps.live.com/op/embed.aspx?src=${previewData.previewUrl}`"
width="100%"
height="98%"
frameborder="0"
></iframe>
</el-drawer>
</div>
</template>
@@ -456,10 +511,12 @@ export default {
},
data() {
return {
previewData: {},
baseUrl: this.Common.baseUrl,
mediaUrl: this.Common.mediaUrl,
now_year: 0,
items: '',
drawer: false,
loading: false,
loading1: false,
loading2: false,
@@ -574,7 +631,10 @@ export default {
},
created: function () {
this.initarticle();
this.initFileList();
this.getWordimgList();
this.getWordTablesList();
},
computed: {
myType: function () {
@@ -705,6 +765,48 @@ export default {
}
},
methods: {
async getWordimgList() {
var that = this;
await this.$api
.post('api/Article/getArticleImages', {
article_id: this.$route.query.id
})
.then(async (res) => {
this.wordimgList = res.data.list;
if (this.wordimgList.length > 0) {
await this.$commonJS.getWordImagesThumbnails(this.wordimgList, function (html) {
that.imagesHtml = html;
});
}
});
},
getWordTablesList() {
this.$api
.post('api/Article/getArticleTable', {
article_id: this.$route.query.id
})
.then((res) => {
console.log('res at line 2210:', res);
var that = this;
that.tables = res.data.list && res.data.list.length > 0 ? JSON.parse(res.data.list[0].table) : [];
if (that.tables.length > 0) {
that.$commonJS.getWordTablesThumbnails(that.tables, function (html) {
that.tablesHtml = html;
});
}
});
},
openDrawer(data, url) {
this.previewData = {
...data,
previewUrl: url,
drawerTitle: 'Uploader : ' + data.username + ' ' + this.formatDate(data.ctime)
};
this.drawer = true;
},
handleClose() {
this.drawer = false;
},
talksave(val) {
this.msgform.ad_content = '';
this.getTalkList();
@@ -1285,4 +1387,14 @@ export default {
.art_state_message p {
margin-left: 15px;
}
::v-deep .el-drawer__header {
margin-bottom: 0;
padding: 15px;
}
::v-deep #wacframe #AppHeaderPanel {
width: 98% !important;
}
::v-deep .el-drawer__wrapper .WACContainer {
z-index: 10000 !important;
}
</style>

View File

@@ -2028,7 +2028,7 @@
background: 'rgba(0, 0, 0, 0.7)'
});
this.$api
.post('api/Production/doTypeSetting', {
.post('api/Production/doTypeSettingNew', {
p_article_id: this.p_article_id
})
.then(res => {

View File

@@ -1898,7 +1898,7 @@
});
this.$api
.post('api/Production/doTypeSetting', {
.post('api/Production/doTypeSettingNew', {
p_article_id: this.p_article_id
})
.then(res => {

View File

@@ -275,7 +275,7 @@
</el-col>
</el-row>
</div>
<el-dialog title="Manuscript Basic Information" :visible.sync="Detailvisible" width="800px">
<el-dialog destroy-on-close title="Manuscript Basic Information" :visible.sync="Detailvisible" width="800px">
<div class="art_state_message">
<p>
<font>Title :</font><b>{{artMes.title}}</b>
@@ -359,6 +359,7 @@
</p>
</el-collapse-item>
</el-collapse>
</div>
<div class="art_file">
@@ -423,6 +424,8 @@
</p>
<br clear="both">
</div>
<common-word-html :articleId="articleId" style="box-sizing: border-box"
></common-word-html>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="Detailvisible=false">OK</el-button>
</span>
@@ -468,7 +471,8 @@
totalpageFileList: [],
manuscirptFileList: [],
supplementaryFileList:[],
fileL_supplementary:[]
fileL_supplementary:[],
wordTables:[],
};
},
created: function() {
@@ -680,8 +684,41 @@
},
// 上传文件
onSubmit() {
addWordTablesList(tables) {
console.log('tables at line 687:', tables)
var data = {
article_id: this.fileMesForm.articleId,
list: tables.map(e=>( {
table: JSON.stringify([...e]),
type: 0,
html_data: ''
})),
};
this.$api.post('api/Article/addArticleTable', data).then((res) => {
});
},
async clearFileManuscript() {
var that=this
await this.$api
.post('api/Article/reloadArticleImages', {
article_id: this.fileMesForm.articleId
})
.then((res) => {});
await this.$api
.post('api/Article/reloadArticleTable', {
article_id: this.fileMesForm.articleId
})
.then((res) => {that. addWordTablesList(that.wordTables);});
},
async onSubmit() {
console.log(this.fileMesForm)
var that=this;
//验证文件
if (this.fileMesForm.manuscirpt == undefined || this.fileMesForm.manuscirpt == '') {
this.$message.error(
@@ -694,19 +731,28 @@
return false;
}
this.loading = true;
this.$api
await this.$api
.post('api/Article/RepairBack', this.fileMesForm)
.then((res) => {
this.loading = false;
.then(async (res) => {
if (res.code == 0) {
await that.clearFileManuscript()
this.$message.success('Upload successful!');
this.loading = false;
setTimeout(()=>{
this.loading = false;
this.$router.push({
path: 'articleProcess',
query: {
id: this.articleId
}
});
},500)
} else {
this.$message.error('Failed to submit, please contact administrator!');
console.log(res.msg);
@@ -765,9 +811,21 @@
// this.fileMesForm.picturesAndTables.push('picturesAndTables/' + url);
// }
},
upSuccess_manuscirpt(res, file) {
upSuccess_manuscirpt(res, File) {
if (res.code == 0) {
this.fileMesForm.manuscirpt = 'manuscirpt/' + res.upurl;
if (File) {
var that = this;
const reader = new FileReader();
reader.onload = function (e) {
that.$commonJS.extractWordTablesToArrays(File.raw, function (wordTables) {
console.log('tablesHtml at line 61:', wordTables);
that.wordTables=wordTables
});
};
reader.readAsArrayBuffer(File.raw);
}
} else {
this.$message.error('service error' + res.msg);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,533 @@
<template>
<div class="tinymce-container editor-container">
<textarea class="tinymce-textarea" :id="tinymceId"></textarea>
</div>
</template>
<script>
import { string } from 'html-docx-js/dist/html-docx';
import htmlDocx from 'html-docx-js/dist/html-docx.js';
import { Document, Packer, PageOrientation, Paragraph, TextRun } from 'docx'; // 引入 docx.js
import html2canvas from 'html2canvas';
const tableStyle = ` b span{
font-weight: bold !important;
}
i span{
font-style: italic !important; ;
}
sub span{
vertical-align: sub;
}
sup span{
vertical-align: sup;
}
sub {
vertical-align: sub!important;
}
sup {
vertical-align: sup !important;
}
span[style*="vertical-align: super"] {
vertical-align: super !important;
}
span[style*="vertical-align: sub"] {
vertical-align: sub !important;
}
table {
border:0px !important;
border-collapse: collapse; /* 去除单元格间隙 */
width: auto;
margin : 0 auto !important;
table-layout: auto; /* 自动调整列宽 */
text-align:left;
font-family:'Charis SIL' !important;
font-size: 7.5000pt !important;
mso-font-kerning: 1.0000pt !important;
line-height: 10pt !important;
mos-line-height: 10pt !important;
}
table td, table th {
padding: 5px;
text-align:left !important;
white-space: pre-wrap; /* 保留换行符并换行 */
word-wrap: break-word; /* 长单词自动换行 */
word-break: break-word;
font-family:'Charis SIL' !important;
font-size: 7.5000pt !important;
mso-font-kerning: 1.0000pt !important;
line-height: 10pt !important;
mos-line-height: 10pt !important;
}
table tbody tr td{
text-align:left !important;
border-left:none !important;
mso-border-left-alt:none !important;
border-right:none !important;
mso-border-right-alt:none !important;
border-top:none;mso-border-top-alt:none !important;
border-bottom:none !important;
mso-border-bottom-alt:none !important;
border:1px dashed #dcdfe6 !important;
border-left:1px dashed #dcdfe6 !important;
border-right:1px dashed #dcdfe6 !important;
word-break: keep-all !important;
text-align: justify !important; // 设置两端对齐
}
table tr td p{
text-align:left !important;
margin:0;
font-family:'Charis SIL' !important;
font-size: 7.5000pt !important;
mso-font-kerning: 1.0000pt !important;
line-height: 10pt !important;
mos-line-height: 10pt !important;
}
table span{
color:#000000;text-align:left !important;
font-family:'Charis SIL' !important;
font-size: 7.5000pt !important;
mso-font-kerning: 1.0000pt !important;
line-height: 10pt !important;
mos-line-height: 10pt !important;
}
table .color-highlight{
color:rgb(0,130,170) !important;
font-family:'Charis SIL' !important;
font-size: 7.5000pt !important;
mso-font-kerning: 1.0000pt !important;
line-height: 10pt !important;
mos-line-height: 10pt !important;
}
table tr:first-child td {
border-top:1.0000pt solid #000 !important;mso-border-top-alt:0.5000pt solid #000 !important;border-bottom:1.0000pt solid #000 !important;mso-border-bottom-alt:0.5000pt solid #000 !important;
}
table tr:last-of-type td {
border-bottom:1.0000pt solid #000 !important;mso-border-bottom-alt:0.5000pt solid #000 !important;;
}
`;
export default {
name: 'tinymce',
components: {},
props: {
id: {
type: String
},
value: {
type: String,
default: ''
},
isEdit: {},
toolbar: {
type: Array,
required: false,
default() {
return [];
}
},
menubar: {
default: 'file edit insert view format table '
},
height: {
type: Number,
required: false,
default: 360
},
width: {
type: String,
required: false,
default: '100%'
},
isShowArtWorkButton: {
default: false
}
},
data() {
return {
typesettingType: 1,
typesettingTypeOptions: [
{
label: this.$t('commonTable.typesettingType1'),
value: 1,
orientation: 'portrait',
pageSize: {
width: 11906,
height: 16976
},
pageMargins: {
top: 1440,
bottom: 1440,
left: 1084,
right: 1084
}
},
// 1 cm = 144 Twip 上边距2.54 cm = 2.54 × 144 = 365.76 Twip
{
label: this.$t('commonTable.typesettingType2'),
value: 2,
orientation: 'landscape',
pageSize: {
width: 16976,
height: 11906
},
pageMargins: {
top: 1440,
bottom: 1440,
left: 1084,
right: 1084
}
}
],
uploadReset: false,
dialogVisible: false,
form: {
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
},
formLabelWidth: '120px',
hasChange: false,
hasInit: false,
tinymceId: this.id || 'vue-tinymce-' + +new Date()
};
},
watch: {
value(val) {
if (!this.hasChange && this.hasInit) {
this.$nextTick(() => window.tinymce.get(this.tinymceId).setContent(val));
}
}
},
mounted() {
this.typesettingType = 1;
this.initTinymce();
},
activated() {
this.typesettingType = 1;
this.initTinymce();
},
deactivated() {
this.destroyTinymce();
},
methods: {
handleSubmit() {
this.$refs.uploadImage.handleSubmit();
},
getDetail(val) {
if (this.hasInit == true) {
this.$nextTick(() => window.tinymce.get(this.tinymceId).setContent(val));
}
},
//将字符串添加到富文本编辑器中
addArtWork(str) {
window.tinymce.get(this.tinymceId).insertContent(str);
},
onClick(e) {
this.$emit('onClick', e, tinymce);
},
changeTable() {
// 获取所有表格
const tables = window.tinymce.get(this.tinymceId).getBody().querySelectorAll('table');
console.log('tables at line 110:', tables);
// 遍历并设置样式
tables.forEach((table) => {
const editor = window.tinymce.get(this.tinymceId);
editor.dom.setStyles(table, {
width: this.typesettingType == 1 ? '17.18cm' : '25.88cm'
});
});
this.$forceUpdate();
},
initTinymce() {
const _this = this;
window.tinymce.init({
selector: `#${this.tinymceId}`,
content_css: false, // 禁用默认样式
table_resize_bars: true, // 启用拖动调整功能
valid_elements: '*[*]', // 允许所有 HTML 标签
paste_preprocess: function (plugin, args) {
let content = args.content;
const container = document.createElement('div');
container.innerHTML = content;
_this.updateTableStyles(container);
args.content = container.innerHTML; // 更新内容
},
content_style: `${tableStyle}`,
formats: {
bold: { inline: 'b' },
italic: { inline: 'i' }
},
body_class: 'panel-body ',
object_resizing: false,
toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
menubar: false, // 启用菜单栏并保持必要的项目
statusbar: false, // 关闭底部状态栏
custom_colors: false,
color_map: ['000000', 'Black', '0082AA', 'TMR Blue'],
plugins: 'forecolor code paste table image', // 启用 forecolor 和 code 插件
end_container_on_empty_block: true,
content_css: 'default', // 加载 TinyMCE 默认样式表
//设置自定义按钮 myCustomToolbarButton
setup(ed) {
ed.ui.registry.addButton('uploadWord', {
text: 'Word',
icon: 'import-word', // 使用自定义图标
onAction: function () {
const input = document.createElement('input');
input.type = 'file';
input.accept = '.docx'; // 限制为 Word 文件
input.addEventListener('change', function () {
const file = input.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function (e) {
const arrayBuffer = e.target.result;
_this.$commonJS.extractTablesFromWord(arrayBuffer, function (tablesHtml) {
console.log('tablesHtml at line 279:', tablesHtml);
ed.setContent(tablesHtml);
});
};
reader.readAsArrayBuffer(file);
}
});
input.click();
}
});
ed.ui.registry.addMenuButton('customDropdown', {
text: _this.$t('commonTable.PaperRotation'), // 下拉框标题
fetch: function (callback) {
// 定义下拉框的内容
const items = [..._this.typesettingTypeOptions];
const menuItems = items.map((item) => ({
type: 'menuitem',
text: item.label,
onAction: function () {
_this.typesettingType = item.value;
_this.changeTable();
// ed.execCommand(item.value); // 执行命令
}
}));
callback(menuItems);
}
});
ed.on('init', function () {
const editorBody = ed.getBody();
// 创建 MutationObserver 监听内容变化
const observer = new MutationObserver(() => {
console.log('editorBody at line 313:', editorBody);
// _this.updateTableStyles(editorBody, _this.typesettingType);
// const hasHorizontalScrollbar = editorBody.scrollWidth > editorBody.clientWidth;
// if (hasHorizontalScrollbar) {
// console.log('TinyMCE 出现横向滚动条');
// } else {
// console.log('没有横向滚动条');
// }
});
// 监听子节点和内容的变化
observer.observe(editorBody, { childList: true, subtree: true, characterData: true });
});
// 定义自定义按钮
ed.ui.registry.addButton('clearButton', {
text: 'Empty',
onAction: () => {
// 插入自定义表格到编辑器中
ed.setContent('');
}
});
// 定义自定义按钮
ed.ui.registry.addButton('customButtonExportWord', {
text: _this.$t('commonTable.exportWord'),
onAction: () => {
// 插入自定义表格到编辑器中
let content = ed.getContent(); // 获取内容
content = content.replace(/<strong>/g, '<b>').replace(/<\/strong>/g, '</b>');
content = content.replace(/<em>/g, '<i>').replace(/<\/strong>/g, '</i>');
const container = document.createElement('div');
container.innerHTML = content;
_this.export('table', _this.$commonJS.updateTableStyles(container, _this.typesettingType, 1));
}
});
// 定义自定义按钮
ed.ui.registry.addButton('customButtonExportImg', {
text: _this.$t('commonTable.exportImg'),
onAction: () => {
// 插入自定义表格到编辑器中
_this.export('image', ed.getContent());
}
});
ed.ui.registry.addContextToolbar('spacer', {
predicate: () => false, // 保持静态
items: '',
scope: 'node'
});
ed.on('paste', (event) => {});
ed.on('SetContent', function (e) {
e.content = e.content.replace(/<strong>/g, '<b>').replace(/<\/strong>/g, '</b>');
e.content = e.content.replace(/<em>/g, '<i>').replace(/<\/em>/g, '</i>');
});
ed.on('GetContent', function (e) {
e.content = e.content.replace(/<b>/g, '<strong>').replace(/<\/b>/g, '</strong>');
e.content = e.content.replace(/<i>/g, '<em>').replace(/<\/i>/g, '</em>');
});
},
init_instance_callback: (editor) => {
if (_this.value) {
editor.setContent(_this.value);
}
_this.hasInit = true;
editor.on('NodeChange Change KeyUp SetContent', () => {
this.hasChange = true;
this.$emit('input', editor.getContent());
});
}
});
},
// 提取 Word 文件中的表格
updateTableStyles(container) {
var html = this.$commonJS.updateTableStyles(container, this.typesettingType);
var editor = window.tinymce.activeEditor; // 将外部 DOM 内容更新到编辑器
const container1 = document.createElement('div');
container1.innerHTML = html; // html 是更新后的 HTML 内容
editor.setContent(container1.innerHTML); // 更新编辑器内容
editor.focus(); // 聚焦到编辑器// 触发编辑器内容变化后,如果需要,可能还要设置编辑器的样式
},
//销毁富文本
destroyTinymce() {
if (window.tinymce.get(this.tinymceId)) {
window.tinymce.get(this.tinymceId).destroy();
}
},
//设置内容
setContent(value) {
window.tinymce.get(this.tinymceId).setContent(value);
},
//获取内容
getContent(type) {
this.$emit('getContent', type, window.tinymce.get(this.tinymceId).getContent());
console.log('window.tinymce.get(this.tinymceId).getContent() at line 431:', window.tinymce.get(this.tinymceId).getContent());
},
async export(type, data) {
if (type == 'table') {
var tableHtml = `<html xmlns:w="urn:schemas-microsoft-com:office:word">
<head>
<style>
${tableStyle}
</style>
</head>
<body>
${data}
</body>
</html>`;
const converted = htmlDocx.asBlob(tableHtml, {
orientation: this.typesettingTypeOptions[this.typesettingType - 1].orientation,
pageSize: {
...this.typesettingTypeOptions[this.typesettingType - 1].pageSize
},
pageMargins: {
...this.typesettingTypeOptions[this.typesettingType - 1].pageMargins
}
});
// const converted = htmlDocx.asBlob(tableHtml); // 将 HTML 转换为 Word Blob
// 触发文件下载
const link = document.createElement('a');
link.href = URL.createObjectURL(converted);
link.download = 'table.docx';
link.click();
} else if (type == 'image') {
const hiddenContainer = document.createElement('div');
hiddenContainer.style.position = 'absolute';
hiddenContainer.style.left = '-9999ppx';
hiddenContainer.style.top = '0';
hiddenContainer.innerHTML = data;
const style = document.createElement('style');
style.innerHTML = `${tableStyle}`;
document.head.appendChild(style);
document.body.appendChild(hiddenContainer);
// 使用 html2canvas 捕获表格内容
const table = hiddenContainer.querySelector('table'); // 找到表格
table.style.border = 'none';
// 使用 html2canvas 将内容转为图片
html2canvas(hiddenContainer, {
scale: 2, // 提高图片的分辨率默认为1设置为2可以使图片更清晰
logging: false, // 禁用日志输出
useCORS: true, // 允许跨域图像
allowTaint: true // 允许污染 canvas解决图片链接不可用问题
})
// 清空现有内容,显示图片
.then((canvas) => {
const imgData = canvas.toDataURL('image/png'); // 创建一个图片对象
const link = document.createElement('a'); // 创建一个链接并下载图片
link.href = imgData;
link.download = 'image.png';
link.click();
});
}
},
inlineStyles(element) {
const styles = window.getComputedStyle(element);
for (let style in styles) {
if (styles.hasOwnProperty(style)) {
element.style[style] = styles[style];
}
}
},
//获取上传图片后的地址,并设置图片样式
tableSuccessCBK(arr) {
console.log(arr, '222');
const _this = this;
window.tinymce.get(_this.tinymceId).insertContent(arr);
}
},
destroyed() {
this.destroyTinymce();
}
};
</script>
<style scoped>
::v-deep .tox-tinymce-aux {
z-index: 9999 !important;
}
::v-deep .tox .tox-menu {
z-index: 9999 !important;
}
/* 自定义按钮样式 */
.custom-btn {
background-color: #28a745 !important;
color: #fff !important;
border-radius: 4px;
padding: 5px 10px;
font-weight: bold;
}
.custom-btn:hover {
background-color: #218838 !important;
}
</style>

View File

@@ -8,8 +8,7 @@ import { string } from 'html-docx-js/dist/html-docx';
import htmlDocx from 'html-docx-js/dist/html-docx.js';
import { Document, Packer, PageOrientation, Paragraph, TextRun } from 'docx'; // 引入 docx.js
import html2canvas from 'html2canvas';
const toolbar =
'uploadWord|undo redo | formatselect | bold italic | forecolor |subscript superscript|table tabledelete |customButtonExportWord |customButtonExportImg |customDropdown | clearButton';
const tableStyle = ` b span{
font-weight: bold !important;
}
@@ -22,11 +21,23 @@ const tableStyle = ` b span{
sup span{
vertical-align: sup;
}
sub {
vertical-align: sub!important;
}
sup {
vertical-align: sup !important;
}
span[style*="vertical-align: super"] {
vertical-align: super !important;
}
span[style*="vertical-align: sub"] {
vertical-align: sub !important;
}
table {
border:0px !important;
border-collapse: collapse; /* 去除单元格间隙 */
width: auto;
margin : 0 auto !important;
margin : 0 auto !important;
table-layout: auto; /* 自动调整列宽 */
text-align:left;
font-family:'Charis SIL' !important;
@@ -47,7 +58,8 @@ const tableStyle = ` b span{
line-height: 10pt !important;
mos-line-height: 10pt !important;
}
table tr td{
table tbody tr td{
text-align:left !important;
border-left:none !important;
mso-border-left-alt:none !important;
@@ -56,14 +68,18 @@ const tableStyle = ` b span{
border-top:none;mso-border-top-alt:none !important;
border-bottom:none !important;
mso-border-bottom-alt:none !important;
border:1px dashed #dcdfe6 !important;
border-left:1px dashed #dcdfe6 !important;
border-right:1px dashed #dcdfe6 !important;
border:1px dashed #dcdfe6 !important;
border-left:1px dashed #dcdfe6 !important;
border-right:1px dashed #dcdfe6 !important;
word-break: keep-all !important;
text-align: justify !important; // 设置两端对齐
}
table tr td p{
display:flex;text-align:left !important;
align-items:center;
text-align:left !important;
margin:0;
font-family:'Charis SIL' !important;
font-size: 7.5000pt !important;
@@ -72,6 +88,7 @@ const tableStyle = ` b span{
mos-line-height: 10pt !important;
}
table span{
color:#000000;text-align:left !important;
font-family:'Charis SIL' !important;
font-size: 7.5000pt !important;
@@ -93,15 +110,23 @@ const tableStyle = ` b span{
table tr:last-of-type td {
border-bottom:1.0000pt solid #000 !important;mso-border-bottom-alt:0.5000pt solid #000 !important;;
}
`;
export default {
name: 'tinymce',
components: {},
props: {
isAutomaticUpdate: {
type: Boolean,
default: false
},
id: {
type: String
},
type: {
type: String
},
value: {
type: String,
default: ''
@@ -188,6 +213,7 @@ export default {
},
watch: {
value(val) {
console.log('val at line 208:', val);
if (!this.hasChange && this.hasInit) {
this.$nextTick(() => window.tinymce.get(this.tinymceId).setContent(val));
}
@@ -244,13 +270,52 @@ export default {
table_resize_bars: true, // 启用拖动调整功能
valid_elements: '*[*]', // 允许所有 HTML 标签
height: this.height,
paste_preprocess: function (plugin, args) {
let content = args.content;
const container = document.createElement('div');
container.innerHTML = content;
_this.updateTableStyles(container);
args.content = container.innerHTML; // 更新内容
// 阻止默认的粘贴行为
if (args.event) {
args.event.preventDefault(); // 阻止默认的粘贴处理
args.event.stopPropagation(); // 阻止事件冒泡,确保自定义处理优先执行
}
if (_this.type == 'table') {
_this.$commonJS.parseTableToArray(content, (tableList) => {
console.log('res at line 104:', tableList);
var contentHtml = `
<div class="thumbnailTableBox wordTableHtml table_Box" style="">
<table border="1" style="width: auto; border-collapse: collapse; text-align: center;">
${tableList
.map((row) => {
return `
<tr>
${row
.map((cell) => {
return `
<td colspan="${cell.colspan || 1}" rowspan="${cell.rowspan || 1}">
<span>${cell.text || ''}</span>
</td>
`;
})
.join('')}
</tr>
`;
})
.join('')}
</table>
</div>
`;
const container = document.createElement('div');
container.innerHTML = contentHtml;
// _this.updateTableStyles(container); // 根据需要应用额外的样式
args.content = container.innerHTML; // 更新处理后的内容
});
} else if (_this.isAutomaticUpdate) {
args.content = _this.$commonJS.transformHtmlString(args.content); // 更新处理后的内容
}
},
content_style: `${tableStyle}`,
formats: {
bold: { inline: 'b' },
@@ -316,14 +381,11 @@ export default {
const editorBody = ed.getBody();
// 创建 MutationObserver 监听内容变化
const observer = new MutationObserver(() => {
console.log('editorBody at line 313:', editorBody);
// _this.updateTableStyles(editorBody, _this.typesettingType);
// const hasHorizontalScrollbar = editorBody.scrollWidth > editorBody.clientWidth;
// if (hasHorizontalScrollbar) {
// console.log('TinyMCE 出现横向滚动条');
// } else {
// console.log('没有横向滚动条');
// }
const currentContent = ed.getContent();
if (_this.isAutomaticUpdate) {
_this.$emit('updateChange', ed.getContent());
}
});
// 监听子节点和内容的变化
@@ -366,7 +428,7 @@ export default {
items: '',
scope: 'node'
});
ed.on('paste', (event) => {});
ed.on('SetContent', function (e) {
e.content = e.content.replace(/<strong>/g, '<b>').replace(/<\/strong>/g, '</b>');
e.content = e.content.replace(/<em>/g, '<i>').replace(/<\/em>/g, '</i>');
@@ -411,6 +473,7 @@ export default {
//获取内容
getContent(type) {
this.$emit('getContent', type, window.tinymce.get(this.tinymceId).getContent());
console.log('window.tinymce.get(this.tinymceId).getContent() at line 431:', window.tinymce.get(this.tinymceId).getContent());
},
async export(type, data) {
@@ -418,7 +481,7 @@ export default {
var tableHtml = `<html xmlns:w="urn:schemas-microsoft-com:office:word">
<head>
<style>
${tableStyle}
</style>
</head>

View File

@@ -0,0 +1,200 @@
<template>
<div style="height: 100%; position: relative">
<div class="comments-section" style="width: calc(300px); height: 100%" v-if="isShowComment">
<h5>{{ $t('commonTable.AnnotationList') }}</h5>
<ul style="margin-top: 10px" v-if="comments.length > 0">
<li v-for="(comment, index) in comments" :key="index" class="comment-item" style="padding: 6px 0">
<div @click.prevent="goToComment(comment.mId)">
<p style="display: flex; align-items: center; justify-content: space-between">
<el-link>
<span style="color: rgb(43, 129, 239)"
><i class="el-icon-chat-dot-square" style="color: rgb(43, 129, 239)"></i> {{ index + 1 }}</span
></el-link
>
<span style="color: #b8b7b7">{{ getTime(comment.time) }}</span>
</p>
<!-- isEditing true 显示可编辑的输入框 -->
<div v-if="isEditing === index">
<el-input
v-focus
type="textarea"
v-model="comment.text"
@blur="saveComment(index)"
style="width: 100%; box-sizing: border-box; padding: 5px"
></el-input>
</div>
<!-- isEditing false 显示评论文本 -->
<div v-else style="display: flex; align-items: center; justify-content: space-between">
<p @click="editComment(index)" style="min-height: 20px; width: calc(100% - 20px)">
{{ comment.text }}
<!-- <span @click="editComment(index)" style="cursor: pointer; color: #007bff; margin-left: 10px;">修改</span> -->
</p>
<i class="el-icon-delete" @click="deleteComment(comment, index)" style="color: #cd5454"></i>
</div>
<!-- 删除按钮 -->
</div>
</li>
</ul>
<ul v-else style="color: #b0b0b0; text-align: center; margin-top: 60px">
No Data
</ul>
</div>
</div>
</template>
<script>
export default {
props: ['articleId'],
data() {
return {
isShowComment: false,
isEditing: null, // 用于跟踪当前正在编辑的批注索引
selectedComment: null, // 存储当前选择的批注内容
comments: [] // 存储所有批注
};
},
directives: {
// 注册一个局部的自定义指令 v-focus
focus: {
// 指令的定义
inserted: function (el) {
console.log('el at line 263:', el);
// 聚焦元素
el.querySelector('textarea').focus();
}
}
},
created() {},
methods: {
changeComment() {
this.isShowComment = !this.isShowComment;
},
// 编辑评论,显示文本框
editComment(index) {
this.isEditing = index; // 设置当前正在编辑的评论索引
},
// 保存评论修改
saveComment(index) {
this.isEditing = null; // 退出编辑模式
},
// 删除评论
deleteComment(comment, index) {
this.$confirm(this.$t('commonTable.removeAnnotations'), 'Prompt', {
confirmButtonText: 'Submit',
cancelButtonText: 'Cancel',
type: 'warning'
})
.then(() => {
this.comments.splice(index, 1); // 删除评论
})
.catch(() => {});
},
getTime(timestamp) {
// 创建一个新的 Date 对象
var date = new Date(timestamp);
// 获取年月日时分格式
var year = date.getFullYear();
var month = date.getMonth() + 1; // 月份从 0 开始,所以要加 1
var day = date.getDate();
var hours = date.getHours();
var minutes = date.getMinutes();
// 格式化输出
var formattedDate =
year +
'-' +
(month < 10 ? '0' + month : month) +
'-' +
(day < 10 ? '0' + day : day) +
' ' +
(hours < 10 ? '0' + hours : hours) +
':' +
(minutes < 10 ? '0' + minutes : minutes);
return formattedDate;
},
goToComment(mainId) {
this.$nextTick(() => {
this.$emit('goToComment',mainId);
});
}
}
};
</script>
<style scoped>
.comments-section {
padding: 10px;
box-sizing: border-box;
border: 1px solid #cecfd3;
border-left: 2px solid #cecfd3;
/* border-radius: 5px; */
background-color: #f9f9f9;
box-shadow: rgba(16, 17, 19, 0.06) 0px 1px 3px;
width: 300px;
background-color: #fafafa;
float: right;
position: absolute;
right: -302px;
top: 0px;
z-index: 999;
}
.comment-item {
padding: 5px 0;
border-bottom: 1px solid #ddd;
cursor: pointer;
box-sizing: border-box;
font-size: 14px;
}
.comment-item:last-child {
border-bottom: none;
}
.comment-details {
margin-top: 20px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
background-color: #f9f9f9;
}
.comment-details h3 {
margin-bottom: 10px;
}
.comment-details p {
margin-bottom: 10px;
}
.comment-details button {
padding: 5px 10px;
background-color: #007bff;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
.comment-details button:hover {
background-color: #0056b3;
}
.comments-section ul,
.comments-section li {
list-style: none;
margin: 0;
padding: 0;
}
</style>

View File

@@ -0,0 +1,148 @@
<template>
<div>
<div>
<tinymce
ref="tinymceChild"
:value="updatedHtml"
:typesettingType="typesettingType"
class="paste-area text-container"
toolbar=" bold italic | forecolor |subscript superscript|table tabledelete |customButtonExportWord |customButtonExportImg |customDropdown | clearButton"
style="
white-space: pre-line;
line-height: 12px;
max-height: 50vh;
overflow: auto;
font-size: 12px;
font-size: 7.5pt; /* 字体大小 */
margin-top: 0pt; /* 段前间距 */
margin-bottom: 0pt; /* 段后间距 */
"
></tinymce>
</div>
</div>
</template>
<script>
import Tinymce from '@/components/page/components/Tinymce';
export default {
props: ['lineStyle'],
components: {
Tinymce
},
data() {
return {
showToolbar: false, // 是否显示工具栏
toolbarStyle: {
top: '0px',
left: '0px'
}, // 工具栏的样式
selectionRange: null, // 保存选区范围
updatedHtml: '',
imgHtml: '',
typesettingTypeOptions: [
{ label: this.$t('commonTable.typesettingType1'), value: 1, pageWidth: 210 },
{ label: this.$t('commonTable.typesettingType2'), value: 2, pageWidth: 297 }
],
transform: null,
typesettingType: 1
};
},
mounted() {
this.typesettingType = 1;
},
methods: {
}
};
</script>
<style scoped>
table {
border-collapse: collapse;
width: 100%;
margin: 20px 0;
}
th,
td {
border: 1px dashed #dcdfe6;
padding: 8px;
text-align: center;
position: relative;
}
table {
border-top: 2px solid #000;
border-bottom: 1px solid #000;
}
th {
border-bottom: 1px solid #000;
}
th input,
td input {
width: 100%;
border: none;
outline: none;
text-align: center;
}
th input,
td input ::placeholder {
color: #aaa !important;
}
.controls {
margin: 0 0 20px;
}
.drag-handle {
cursor: move;
}
::v-deep .paste-area {
height: auto; /* A4纸高度 */
background: white; /* 纸张背景 */
/* padding: 25.4mm 19.1mm; //内边距 */
box-sizing: border-box; /* 确保内边距不会影响整体尺寸 */
transform-origin: top left;
}
::v-deep .paste-area table {
/* border-top: 2px solid #000 !important; */
/* border-bottom: 1px solid #000 !important; */
margin-left: 0 !important;
margin-right: 0 !important;
margin: 0 auto !important;
}
::v-deep .paste-area table td {
border-top: none !important;
border-bottom: none !important;
border: 1px dashed #dcdfe6 !important;
/* display: flex;
align-items: center; */
}
::v-deep .paste-area table td p {
display: flex;
align-items: center;
}
::v-deep .paste-area table .MsoNormal {
max-width: 200px !important; /* 限制容器宽度 */
word-wrap: break-word !important;
overflow-wrap: break-word !important;
}
.text-container {
}
</style>

View File

@@ -1,54 +1,38 @@
<template>
<div>
<!-- 拖拽区域 -->
<div class="drag-drop-area" @dragover.prevent="onDragOver" @dragleave="onDragLeave" @drop.prevent="onDrop" @click="clickUpload">
<p> Word 文件拖拽到此处</p>
<div class="" @dragover.prevent="onDragOver" @dragleave="onDragLeave" @drop.prevent="onDrop" @click="clickUpload">
<img src="@/assets/img/word.png" alt="" style="width: 30px; height: 30px" />
</div>
<el-dialog
<div v-html="tablesHtml" class="wordTableHtml"></div>
<!-- <el-dialog
append-to-body
title="Add Academic Integrity Committee"
:visible.sync="addVisible"
width="660px"
width="80%"
:close-on-click-modal="false"
>
<div v-if="tables.length > 0" class="preview-area">
<div v-for="(table, index) in tables" :key="index" class="table-wrapper">
<h3>Table {{ index + 1 }}</h3>
<div v-html="table.html" class="table-preview"></div>
<div class="table-options">
<label>
页面方向
<select v-model="table.orientation">
<option value="portrait">纵向</option>
<option value="landscape">横向</option>
</select>
</label>
<button @click="confirmTable(index)">确认表格</button>
</div>
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="addVisCancle">Cancel</el-button>
<el-button type="primary" @click="saveAdd()" v-if="dis_able">OK</el-button>
</span>
</el-dialog>
</el-dialog> -->
<!-- 表格预览区 -->
</div>
</template>
<script>
import JSZip from 'jszip';
export default {
data() {
return {
tablesHtml: '',
tables: [], // 保存解析后的表格数据
addVisible: false
};
},
components: {},
methods: {
addVisCancle(){
this.addVisible = false;
addVisCancle() {
this.addVisible = false;
},
clickUpload() {
this.tables = [];
@@ -62,9 +46,16 @@ this.addVisible = false;
const reader = new FileReader();
reader.onload = function (e) {
const arrayBuffer = e.target.result;
that.extractTablesFromWord(arrayBuffer, function (tablesHtml) {
console.log('tablesHtml at line 61:', that.tables);
that.addVisible = true;
that.$commonJS.extractWordTablesToArrays(file, function (wordTables) {
console.log('tablesHtml at line 61:', wordTables);
that.tables = wordTables;
that.$commonJS.getWordTablesThumbnails(wordTables, function (html) {
console.log('html at line 78:', html);
that.tablesHtml = html;
that.addVisible = true;
});
that.$emit('tables', that.tables, html);
});
};
reader.readAsArrayBuffer(file);
@@ -80,44 +71,6 @@ this.addVisible = false;
event.currentTarget.style.borderColor = '#ccc';
},
// 提取 Word 文件中的表格
extractTablesFromWord(arrayBuffer, callback) {
const zip = new JSZip();
var that = this;
zip.loadAsync(arrayBuffer)
.then(function (zip) {
const docXmlPath = 'word/document.xml'; // Word 主文档的 XML 路径
return zip.file(docXmlPath).async('string');
})
.then(function (docXml) {
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(docXml, 'text/xml');
const tables = xmlDoc.getElementsByTagName('w:tbl'); // 查找 Word 表格标签
let html = '';
for (let table of tables) {
var str = that.convertTableToHtml(table);
const container = document.createElement('div');
container.innerHTML = str;
that.tables.push({
html: that.updateTableStyles(container),
orientation: 'portrait' // 默认纵向
});
html += str;
}
if (!html) {
html = '<p>未检测到表格内容。</p>';
}
callback(html);
})
.catch(function (err) {
console.error('解析 Word 文件出错:', err);
callback('<p>文件解析失败,请检查文件格式。</p>');
});
},
async onDrop(event) {
const file = event.dataTransfer.files[0];
if (!file || !file.name.endsWith('.docx')) {
@@ -176,195 +129,9 @@ this.addVisible = false;
reader.readAsArrayBuffer(file);
});
},
// 将 XML 表格转换为 HTML
convertTableToHtml(tableNode) {
const rows = tableNode.getElementsByTagName('w:tr');
let html = '<table border="1" style="border-collapse: collapse;">';
for (let row of rows) {
html += '<tr>';
const cells = row.getElementsByTagName('w:tc');
for (let cell of cells) {
let cellHtml = '';
const paragraphs = cell.getElementsByTagName('w:p'); // 获取单元格内段落
for (let paragraph of paragraphs) {
const texts = paragraph.getElementsByTagName('w:r'); // 获取段落内的文本和样式
for (let run of texts) {
const textNode = run.getElementsByTagName('w:t')[0];
if (textNode) {
const style = this.getStyleFromRun(run); // 提取样式
cellHtml += `<span style="${style}">${textNode.textContent}</span>`;
}
}
cellHtml += '<br>'; // 段落换行
}
html += `<td>${cellHtml}</td>`;
}
html += '</tr>';
}
html += '</table>';
return html;
},
// 提取 w:r 节点中的样式并转换为 CSS
getStyleFromRun(run) {
const styleNode = run.getElementsByTagName('w:rPr')[0];
let style = '';
if (styleNode) {
// 加粗
if (styleNode.getElementsByTagName('w:b').length > 0) {
style += 'font-weight: bold;';
}
// 斜体
if (styleNode.getElementsByTagName('w:i').length > 0) {
style += 'font-style: italic;';
}
// 上标或下标
const vertAlign = styleNode.getElementsByTagName('w:vertAlign')[0];
if (vertAlign) {
const alignVal = vertAlign.getAttribute('w:val');
if (alignVal === 'superscript') {
style += 'vertical-align: super; font-size: smaller;';
} else if (alignVal === 'subscript') {
style += 'vertical-align: sub; font-size: smaller;';
}
}
// 字体颜色
const colorNode = styleNode.getElementsByTagName('w:color')[0];
if (colorNode) {
const colorVal = colorNode.getAttribute('w:val');
style += `color: #${colorVal};`;
}
}
return style;
},
replaceNegativeSign(node) {
if (node.nodeType === Node.TEXT_NODE) {
// 如果是文本节点,替换负号
node.nodeValue = node.nodeValue.replace(/^-(?=\d)/, '');
} else if (node.nodeType === Node.ELEMENT_NODE) {
// 如果是元素节点,递归处理子节点
node.childNodes.forEach(this.replaceNegativeSign);
}
},
capitalizeFirstLetter(node) {
if (node.nodeType === Node.TEXT_NODE) {
// 如果是文本节点,只处理第一个非空字符
node.nodeValue = node.nodeValue.replace(/^\s*([a-zA-Z])/, (match, firstLetter) => {
return firstLetter.toUpperCase();
});
} else if (node.nodeType === Node.ELEMENT_NODE) {
// 递归处理子节点
node.childNodes.forEach(this.capitalizeFirstLetter);
}
},
updateTableStyles(container) {
var _this = this;
// 更新表格样式
const tables = container.querySelectorAll('table');
tables.forEach((table) => {
table.setAttribute(
'style',
`width: ${
this.typesettingType == 1 ? '17.18cm' : '25.88cm'
};border: none; margin: 0 auto !important;border-collapse: collapse; `
);
const cells = table.querySelectorAll('td');
cells.forEach((td) => {
if (/^-?\d+(\.\d+)?$/.test(td.textContent.trim())) {
_this.replaceNegativeSign(td);
}
const hasSupOrSub = _this.containsSupOrSub(td); // 检查当前 td 是否包含上下标
if (!hasSupOrSub) {
// 递归处理单元格内的所有子节点
td.childNodes.forEach(_this.capitalizeFirstLetter);
// 替换 <a> 标签为其内部文本
td.querySelectorAll('a').forEach((a) => {
const textNode = document.createTextNode(a.textContent); // 创建文本节点
a.replaceWith(textNode); // 用文本节点替换 <a> 标签
});
}
// 获取 td 元素中的所有子元素
const childElements = td.querySelectorAll('*');
// 遍历每个子元素
childElements.forEach((element) => {
// 如果元素的文本内容匹配正则表达式
if (/\[\d+(?:,\d+)*\]/g.test(element.textContent)) {
console.log('匹配到带有数字的方括号内容');
// 为匹配的元素添加样式类
element.classList.add('color-highlight');
element.style.color = 'rgb(0,130,170)';
}
});
});
const firstRowTdElements = container.querySelectorAll('tr:first-child td'); // 获取第一个 <tr> 中的所有 <td> 元素
// 遍历所有 <td> 元素,添加上下边框样式
firstRowTdElements.forEach((td) => {
const currentStyle = td.getAttribute('style');
if (currentStyle) {
td.setAttribute(
'style',
currentStyle +
';border-top:1.0000pt solid #000 !important;mso-border-top-alt:0.5000pt solid #000 !important;border-bottom:1.0000pt solid #000 !important;mso-border-bottom-alt:0.5000pt solid #000 !important;'
);
} else {
td.setAttribute(
'style',
'border-top:1.0000pt solid #000 !important;mso-border-top-alt:0.5000pt solid #000 !important;border-bottom:1.0000pt solid #000 !important;mso-border-bottom-alt:0.5000pt solid #000 !important;'
);
}
});
const firstRowTdElementsLast = container.querySelectorAll('tr:last-of-type td');
// 遍历所有 <td> 元素,添加上下边框样式
firstRowTdElementsLast.forEach((td) => {
// 获取当前的 style 属性(如果有)
const currentStyle = td.getAttribute('style');
// 如果已有 style 属性,则追加边框样式;如果没有 style 属性,则设置新的 style
if (currentStyle) {
td.setAttribute(
'style',
currentStyle +
';border-bottom:1.0000pt solid #000 !important;mso-border-bottom-alt:0.5000pt solid #000 !important;'
);
} else {
td.setAttribute(
'style',
'border-bottom:1.0000pt solid #000 !important;mso-border-bottom-alt:0.5000pt solid #000 !important;'
);
}
});
});
console.log('tables.forEach at line 270:', tables);
// var editor = window.tinymce.activeEditor;
var html = '';
tables.forEach((e) => {
html += e.outerHTML;
console.log('html at line 582:', html);
});
this.$forceUpdate();
return html
},
containsSupOrSub(element) {
// 如果当前节点是元素节点
if (element.nodeType === 1) {
// 如果是 <sup> 或 <sub> 标签,返回 true
if (element.tagName === 'SUP' || element.tagName === 'SUB') {
return true;
}
// 否则,递归检查子节点
return Array.from(element.childNodes).some((child) => this.containsSupOrSub(child));
}
// 如果不是元素节点(如文本节点),返回 false
return false;
},
// 确认表格
confirmTable(index) {
const table = this.tables[index];
@@ -403,4 +170,33 @@ this.addVisible = false;
.table-options {
margin-top: 10px;
}
.html-preview {
transform: scale(0.5); /* 缩放比例为 50% */
transform-origin: top left; /* 缩放基准点为左上角 */
display: inline-block; /* 使内容大小随缩放变化 */
}
::v-deep.table-modal-content::-webkit-scrollbar {
width: 12px; /* 垂直滚动条的宽度 */
height: 12px; /* 水平滚动条的高度 */
}
::v-deep.table-modal-content::-webkit-scrollbar-thumb {
background-color: #888; /* 滑块的颜色 */
border-radius: 10px; /* 滑块的圆角 */
border: 3px solid #f1f1f1; /* 滑块的边框颜色 */
}
::v-deep.table-modal-content::-webkit-scrollbar-thumb:hover {
background-color: #555; /* 悬停时的颜色 */
}
::v-deep.table-modal-content::-webkit-scrollbar-track {
background-color: #f1f1f1; /* 滚动条背景色 */
border-radius: 10px;
}
</style>

View File

@@ -1,251 +0,0 @@
<template>
<div>
<div
class="paste-area"
:style="`width: ${210}mm !important;padding: 25.4mm 19.1mm;`"
> <div
class="paste-area"
:style="`width: 100% !important;`"
contenteditable="true"
id="content"
ref="content"
@paste="handlePaste"
></div></div>
<div class="controls" style="overflow: hidden;"> 请在此区域粘贴 Word 表格
<div class="paste-area" contenteditable="true" @paste="handlePaste">
</div>
<!-- <p style="float: left;">Add&nbsp;&nbsp;
<el-input style="width: 50px;" v-model="rowsNumber"></el-input>
<span>&nbsp;&nbsp;{{ $t('commonTable.rows') }} *&nbsp;&nbsp;</span>
<el-input style="width: 50px;" v-model="columnsNumber"></el-input>
<span>&nbsp;&nbsp;{{ $t('commonTable.columns') }}&nbsp;&nbsp;{{ $t('commonTable.table') }}</span>
<el-button style="margin-left: 20px;" @click="Generate">Generate</el-button>
</p> -->
<p style="float: right;">
<el-button @click="addRow">增加行</el-button>
<el-button @click="addColumn">增加列</el-button>
<el-button @click="mergeCells">合并选中单元格</el-button>
</p>
</div>
<table v-if="tableData.length > 0">
<tbody>
<tr v-for="(row, rowIndex) in tableData" :key="rowIndex">
<td v-for="(cell, colIndex) in row" :key="colIndex" contenteditable="true">
{{ cell }}
</td>
</tr>
</tbody>
</table>
<!-- <table>
<thead>
<tr>
<th
v-for="(header, index) in headers"
:key="index"
draggable="true"
@dragstart="startDrag(index)"
@dragover.prevent
@drop="dropColumn(index)"
>
<input v-model="headers[index]" :placeholder="$t('commonTable.headerPlaceholder')" />
</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, rowIndex) in rows" :key="rowIndex">
<td
v-for="(cell, colIndex) in row"
:key="colIndex"
@click="selectCell(rowIndex, colIndex)"
:colspan="cell.colspan"
:rowspan="cell.rowspan"
v-if="!cell.merged"
>
<input v-model="cell.value" placeholder="" />
</td>
</tr>
</tbody>
</table> -->
</div>
</template>
<script>
export default {
data() {
return {
tableData: [], // 表格数据
rowsNumber:'',
columnsNumber:'',
headers: [], // 表头
rows: [
[
{ value: '', rowspan: 1, colspan: 1, merged: false },
{ value: '', rowspan: 1, colspan: 1, merged: false },
{ value: '', rowspan: 1, colspan: 1, merged: false }
]
], // 表格数据
selectedCells: [], // 存储选中的单元格
draggedColumnIndex: null // 拖拽的列索引
};
},
methods: {
handlePaste(event) {
// event.preventDefault(); // 阻止默认粘贴行为
// 获取剪贴板 HTML 内容
// const clipboardData = event.clipboardData || window.clipboardData;
// const htmlData = clipboardData.getData("text/html");
// if (!htmlData) {
// alert("未检测到表格内容!");
// return;
// }
// // 创建 DOM 元素解析 HTML
// const parser = new DOMParser();
// const doc = parser.parseFromString(htmlData, "text/html");
// const table = doc.querySelector("table");
// if (!table) {
// alert("粘贴内容中没有表格!");
// return;
// }
// // 提取表格数据
// const rows = Array.from(table.rows).map(row =>
// Array.from(row.cells).map(cell => cell.innerText.trim()) // innerText 保留换行符
// );
// this.tableData = rows; // 更新表格数据
},
Generate(){
for(let i=0;i<this.columnsNumber;i++){
this.headers.push('')
}
},
addRow() {
const newRow = this.headers.map(() => ({
value: '',
rowspan: 1,
colspan: 1,
merged: false
}));
this.rows.push(newRow);
},
addColumn() {
this.headers.push(`${this.headers.length + 1}`);
this.rows.forEach((row) => {
row.push({ value: '', rowspan: 1, colspan: 1, merged: false });
});
},
startDrag(index) {
this.draggedColumnIndex = index;
},
dropColumn(index) {
if (this.draggedColumnIndex === null || this.draggedColumnIndex === index) return;
const draggedHeader = this.headers.splice(this.draggedColumnIndex, 1)[0];
this.headers.splice(index, 0, draggedHeader);
this.rows.forEach((row) => {
const draggedCell = row.splice(this.draggedColumnIndex, 1)[0];
row.splice(index, 0, draggedCell);
});
this.draggedColumnIndex = null;
},
selectCell(rowIndex, colIndex) {
this.selectedCells.push({ row: rowIndex, col: colIndex });
},
mergeCells() {
if (this.selectedCells.length < 2) return;
const rows = this.selectedCells.map((cell) => cell.row);
const cols = this.selectedCells.map((cell) => cell.col);
const minRow = Math.min(...rows);
const maxRow = Math.max(...rows);
const minCol = Math.min(...cols);
const maxCol = Math.max(...cols);
for (let r = minRow; r <= maxRow; r++) {
for (let c = minCol; c <= maxCol; c++) {
if (r === minRow && c === minCol) {
this.rows[r][c].rowspan = maxRow - minRow + 1;
this.rows[r][c].colspan = maxCol - minCol + 1;
} else {
this.rows[r][c].merged = true;
}
}
}
this.selectedCells = [];
}
}
};
</script>
<style scoped>
table {
border-collapse: collapse;
width: 100%;
margin: 20px 0;
}
th, td {
border: 1px dashed #DCDFE6;
padding: 8px;
text-align: center;
position: relative;
}
table{
border-top: 2px solid #000;
border-bottom: 1px solid #000;
}
th{
border-bottom: 1px solid #000;
}
th input, td input {
width: 100%;
border: none;
outline: none;
text-align: center;
}
th input, td input ::placeholder{
color:#aaa !important;
}
.controls {
margin:0 0 20px;
}
.drag-handle {
cursor: move;
}
::v-deep .paste-area {
width: 100%;
}
::v-deep .paste-area .MsoNormalTable{
border-top: 2px solid #000 !important;
border-bottom: 1px solid #000 !important;
margin-left: 0!important;
margin-right: 0!important;
margin: 0 auto !important;
}
::v-deep .paste-area .MsoNormalTable td{
border-top: none !important;
border-bottom: none !important;
border: 1px dashed #DCDFE6 !important;
}
</style>

View File

@@ -1,45 +1,49 @@
<template>
<div>
<div>
<!-- <el-select v-model="typesettingType">
<el-option v-for="item in typesettingTypeOptions" :key="item.value" :label="item.label" :value="item.value"> </el-option>
</el-select> -->
<!-- <span style="margin-left:10px ;">请在下面区域粘贴 Word 表格</span> -->
<!--uploadWord |customButtonExportWord |customButtonExportImg -->
<tinymce
ref="tinymceChild"
:value="updatedHtml"
:typesettingType="typesettingType"
class="paste-area text-container"
style="
white-space: pre-line;
line-height: 12px;
max-height: 50vh;
overflow: auto;
font-size: 12px;
font-size: 7.5pt; /* 字体大小 */
type="table"
ref="tinymceChild1"
@getContent="getContent"
:value="updatedHtml"
:typesettingType="typesettingType"
class="paste-area text-container"
:toolbar="`undo redo | formatselect | bold italic ${
identity ? '| forecolor' : ''
} |subscript superscript|table tabledelete ${identity ? '| customDropdown' : ''} | clearButton`"
style="
/* white-space: pre-line; */
line-height: 12px;
max-height: 60vh;
overflow: auto;
font-size: 12px;
font-size: 7.5pt; /* 字体大小 */
margin-top: 0pt; /* 段前间距 */
margin-bottom: 0pt; /* 段后间距 */
"
></tinymce>
margin-top: 0pt; /* 段前间距 */
margin-bottom: 0pt; /* 段后间距 */
"
></tinymce>
</div>
</div>
</template>
<script>
import Tinymce from '@/components/page/components/Tinymce';
export default {
props: ['lineStyle'],
components: {
Tinymce
},
watch: {
lineStyle() {}
},
data() {
return {
tableData: [],
identity: localStorage.getItem('U_role'),
showToolbar: false, // 是否显示工具栏
toolbarStyle: {
top: '0px',
@@ -58,15 +62,60 @@ export default {
},
mounted() {
this.typesettingType = 1;
if (this.lineStyle) {
console.log('newVal at line 37:', this.lineStyle);
if (this.lineStyle.table) {
this.tableData = [...this.lineStyle.table];
var modalContent = `
<div class="wordTableHtml" >
<table
border="1"
style="
border-collapse: collapse;
width: 100%;
text-align: center;
table-layout: auto;"
>`;
this.tableData.forEach((row) => {
modalContent += `<tr>`;
row.forEach((cell) => {
modalContent += `
<td
colspan="${cell.colspan || 1}"
rowspan="${cell.rowspan || 1}"
style=""
>
<span>${cell.text}</span>
</td>`;
});
modalContent += `</tr>`;
});
modalContent += `</table></div>`;
console.log('modalContent at line 91:', modalContent);
this.updatedHtml = modalContent;
}
// this.updatedHtml = newVal.html_data;
} else {
this.updatedHtml = '';
}
},
methods: {
getTableContent(type) {
this.$refs.tinymceChild1.getContent(type);
},
getContent(type, content) {
if (content) {
const container = document.createElement("div");
container.innerHTML = content;
this.$commonJS.parseTableToArray(content, (table) => {
console.log('res at line 104:', table);
this.$emit('getContent', type, { html_data: content, table: table });
});
} else {
this.$emit('getContent', type, { html_data: '', table: [] });
}
}
}
};
</script>
@@ -114,7 +163,7 @@ td input ::placeholder {
::v-deep .paste-area {
height: auto; /* A4纸高度 */
background: white; /* 纸张背景 */
/* padding: 25.4mm 19.1mm; //内边距 */
box-sizing: border-box; /* 确保内边距不会影响整体尺寸 */
transform-origin: top left;
@@ -144,8 +193,5 @@ td input ::placeholder {
overflow-wrap: break-word !important;
}
.text-container {
}
</style>

View File

@@ -0,0 +1,39 @@
<template>
<div ref="tiffContainer" class="tiff-container"></div>
</template>
<script>
import Tiff from 'tiff.js';
export default {
props: {
imageSrc: {
type: String,
required: true
}
},
mounted() {
this.loadTiffImage();
},
methods: {
loadTiffImage() {
const xhr = new XMLHttpRequest();
xhr.open('GET', this.imageSrc, true);
xhr.responseType = 'arraybuffer';
xhr.onload = () => {
const tiff = new Tiff({ buffer: xhr.response });
const canvas = tiff.toCanvas();
this.$refs.tiffContainer.appendChild(canvas);
};
xhr.send();
}
}
};
</script>
<style scoped>
.tiff-container {
display: inline-block;
}
</style>

View File

@@ -0,0 +1,840 @@
<template>
<div class="tinymce-container editor-container" style="width: 100%; height: 100%; position: relative">
<textarea class="tinymce-textarea" :id="tinymceId"></textarea>
</div>
</template>
<script>
import { string } from 'html-docx-js/dist/html-docx';
import htmlDocx from 'html-docx-js/dist/html-docx.js';
import { Document, Packer, PageOrientation, Paragraph, TextRun } from 'docx'; // 引入 docx.js
import html2canvas from 'html2canvas';
const toolbar = 'addImageButton ';
const tableStyle = `b span{
font-weight: bold !important;
}
i span{
font-style: italic !important; ;
}
sub span{
vertical-align: sub;
}
sup span{
vertical-align: sup;
}
sub {
vertical-align: sub!important;
}
sup {
vertical-align: sup !important;
}
span[style*="vertical-align: super"] {
vertical-align: super !important;
}
span[style*="vertical-align: sub"] {
vertical-align: sub !important;
}
table {
border:0px !important;
border-collapse: collapse; /* 去除单元格间隙 */
width: auto;
margin : 0 auto !important;
table-layout: auto; /* 自动调整列宽 */
text-align:left;
font-family:'Charis SIL' !important;
font-size: 7.5000pt !important;
mso-font-kerning: 1.0000pt !important;
line-height: 10pt !important;
mos-line-height: 10pt !important;
}
table td, table th {
padding: 5px;
text-align:left !important;
white-space: pre-wrap; /* 保留换行符并换行 */
word-wrap: break-word; /* 长单词自动换行 */
word-break: break-word;
font-family:'Charis SIL' !important;
font-size: 7.5000pt !important;
mso-font-kerning: 1.0000pt !important;
line-height: 10pt !important;
mos-line-height: 10pt !important;
}
table tbody tr td{
text-align:left !important;
border-left:none !important;
mso-border-left-alt:none !important;
border-right:none !important;
mso-border-right-alt:none !important;
border-top:none;mso-border-top-alt:none !important;
border-bottom:none !important;
mso-border-bottom-alt:none !important;
border:1px dashed #dcdfe6 !important;
border-left:1px dashed #dcdfe6 !important;
border-right:1px dashed #dcdfe6 !important;
word-break: keep-all !important;
text-align: justify !important; // 设置两端对齐
}
table tr td p{
text-align:left !important;
margin:0;
font-family:'Charis SIL' !important;
font-size: 7.5000pt !important;
mso-font-kerning: 1.0000pt !important;
line-height: 10pt !important;
mos-line-height: 10pt !important;
}
table span{
color:#000000;text-align:left !important;
font-family:'Charis SIL' !important;
font-size: 7.5000pt !important;
mso-font-kerning: 1.0000pt !important;
line-height: 10pt !important;
mos-line-height: 10pt !important;
}
table .color-highlight{
color:rgb(0,130,170) !important;
font-family:'Charis SIL' !important;
font-size: 7.5000pt !important;
mso-font-kerning: 1.0000pt !important;
line-height: 10pt !important;
mos-line-height: 10pt !important;
}
table tr:first-child td {
border-top:1.0000pt solid #000 !important;mso-border-top-alt:0.5000pt solid #000 !important;border-bottom:1.0000pt solid #000 !important;mso-border-bottom-alt:0.5000pt solid #000 !important;
}
table tr:last-of-type td {
border-bottom:1.0000pt solid #000 !important;mso-border-bottom-alt:0.5000pt solid #000 !important;;
}
table span blue {
color: rgb(0, 130, 170) !important;
}
`;
export default {
name: 'tinymce',
components: {},
props: {
id: {
type: String
},
value: {
type: String,
default: ''
},
isEdit: {},
toolbar: {
type: Array,
required: false,
default() {
return [];
}
},
menubar: {
default: 'file edit insert view format table '
},
height: {
type: Number,
required: false,
default: 360
},
width: {
type: String,
required: false,
default: '100%'
},
isShowArtWorkButton: {
default: false
},
wordStyle: {
type: String,
default: ''
}
},
data() {
return {
lastTag: null,
isEditComment: false,
typesettingType: 1,
typesettingTypeOptions: [
{
label: this.$t('commonTable.typesettingType1'),
value: 1,
orientation: 'portrait',
pageSize: {
width: 11906,
height: 16976
},
pageMargins: {
top: 1440,
bottom: 1440,
left: 1084,
right: 1084
}
},
// 1 cm = 144 Twip 上边距2.54 cm = 2.54 × 144 = 365.76 Twip
{
label: this.$t('commonTable.typesettingType2'),
value: 2,
orientation: 'landscape',
pageSize: {
width: 16976,
height: 11906
},
pageMargins: {
top: 1440,
bottom: 1440,
left: 1084,
right: 1084
}
}
],
uploadReset: false,
dialogVisible: false,
form: {
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
},
formLabelWidth: '120px',
hasChange: false,
hasInit: false,
tinymceId: this.id || 'vue-tinymce-' + +new Date()
};
},
// this.$nextTick(() => window.tinymce.get(this.tinymceId).setContent(newVal));
watch: {
value(newVal) {
this.$nextTick(() => {
window.tinymce.get(this.tinymceId).setContent(newVal);
this.$emit('loaded');
});
// this.destroyTinymce();
// this.$nextTick(() => {
// this.initTinymce();
// });
}
},
mounted() {
this.isShowEditComment();
this.typesettingType = 1;
this.initTinymce();
},
activated() {
this.isShowEditComment();
this.typesettingType = 1;
this.initTinymce();
},
deactivated() {
this.destroyTinymce();
},
methods: {
isShowEditComment() {
if (localStorage.getItem('U_role')) {
var identity = localStorage.getItem('U_role');
if (identity.includes('editor')) {
this.isEditComment = true;
} else {
this.isEditComment = false;
}
}
},
// 查看评论详情
handleSubmit() {
this.$refs.uploadImage.handleSubmit();
},
getDetail(val) {
if (this.hasInit == true) {
this.$nextTick(() => window.tinymce.get(this.tinymceId).setContent(val));
}
},
//将字符串添加到富文本编辑器中
addArtWork(str) {
window.tinymce.get(this.tinymceId).insertContent(str);
},
onClick(e) {
this.$emit('onClick', e, tinymce);
},
changeTable() {
// 获取所有表格
const tables = window.tinymce.get(this.tinymceId).getBody().querySelectorAll('table');
console.log('tables at line 110:', tables);
// 遍历并设置样式
tables.forEach((table) => {
console.log('table at line 360:', table);
const editor = window.tinymce.get(this.tinymceId);
editor.dom.setStyles(table, {
width: this.typesettingType == 1 ? '17.18cm' : '25.88cm'
});
});
this.$forceUpdate();
},
goToComment(mainId) {
var ed = window.tinymce.get(this.tinymceId);
const editorDoc = ed.getDoc(); // 获取 TinyMCE 内部的 document
console.log('Looking for element with main-id:', mainId); // 调试输出
// 在 iframe 内部的 document 中查找带有 main-id 的元素
const commentElement = editorDoc.querySelector(`[main-id="${mainId}"]`);
if (commentElement) {
commentElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
} else {
console.log('没有找到对应的批注元素', mainId); // 调试输出
}
},
initTinymce() {
var deleteButtons = document.querySelectorAll('.wordButtonContainer');
if (deleteButtons) {
deleteButtons.forEach(function (button) {
button.remove(); // 移除每个 wordButtonContainer 按钮
});
}
let isDeleting = false;
let currentParagraph = null; // 用来存储当前选中的 <p> 元素
let wordButtonContainer = null; // 用来存储删除按钮
const _this = this;
window.tinymce.init({
height: '100%',
resize: true,
readonly: true, // 设置为只读模式
selector: `#${this.tinymceId}`,
content_css: false,
table_resize_bars: true,
valid_elements: '*[*]',
paste_preprocess: function (plugin, args) {
let content = args.content;
const container = document.createElement('div');
container.innerHTML = content;
_this.updateTableStyles(container);
args.content = container.innerHTML;
},
content_style: `${tableStyle + this.wordStyle}.tox .tox-edit-area::before{
border:none;
}
.isRemark {
display:flex;
align-items:center;
position:absolute;
top:-12px;
left:-12px;
z-index:2;
cursor: pointer;
}
.isRemark img{
width:15px;
height:15px;
margin-right:4px;
}
.isRemark span{
background-color: #fef0f0;
border-color: #fde2e2;
padding: 0 5px;
line-height: 19px;
color: #f56c6c;
font-size: 12px;display:inline-block;
}
img{
max-width:580px;
}
`,
formats: {
bold: { inline: 'b' },
italic: { inline: 'i' }
},
body_class: 'panel-body ',
object_resizing: false,
toolbar: [],
menubar: false,
statusbar: false,
custom_colors: false,
color_map: ['000000', 'Black', '0082AA', 'TMR Blue'],
plugins: 'forecolor code paste table image resize',
end_container_on_empty_block: true,
content_css: 'default',
setup(ed) {
ed.on('click', function (e) {
// 判断点击的是否是目标元素
const target = e.target;
console.log('target at line 351:', target);
if (target.classList.contains('isRemarkIcon')) {
_this.$emit('onComment', target.getAttribute('main-id'));
}
});
// // 添加批注按钮
ed.ui.registry.addButton('addImageButton', {
text: 'Add Figure',
icon: 'comment',
onAction: function () {
_this.$emit('add', img);
// const selection = ed.selection;
// const selectedNode = selection.getNode(); // 获取选中的节点
// console.log('selectedNode at line 333:', selectedNode);
// if (selectedNode) {
// const comment = prompt('Enter your comment:');
// if (comment) {
// const dataId = selectedNode.getAttribute('main-id');
// _this.comments.push({ text: comment, time: new Date().getTime(), mId: dataId });
// }
// } else {
// alert('Please select some text to comment on.');
// }
}
});
ed.on('dragstart', (e) => {
// 阻止拖动事件
e.preventDefault();
});
// 监听焦点变化并高亮当前选中的元素
ed.on('focus', function () {
if (!isDeleting) {
// 处理正常的焦点逻辑
ed.getBody().style.outline = 'none'; // 当编辑器获取焦点时,移除焦点框
_this.updateCurrentTag(ed);
}
});
// 监听焦点变化并高亮当前选中的元素
ed.on('selectionChange', function () {
_this.updateCurrentTag(ed);
});
ed.on('mouseup', function () {
_this.updateCurrentTag(ed);
});
ed.on('blur', function () {
console.log('_this.lastPTag at line 367:', _this.lastTag);
if (_this.lastTag) {
_this.lastTag.style.backgroundColor = ''; // 清除之前的高亮
_this.lastTag.style.border = '';
_this.lastTag = null;
}
if (wordButtonContainer) {
wordButtonContainer.remove();
wordButtonContainer = null;
}
});
ed.on('drop', (event, index) => {
console.log('event at line 375:', event);
const selection = ed.selection;
const selectedNode = selection.getNode(); // 获取选中的节点
console.log('1899', selectedNode); // 查看光标位置的节点类型
// 向上遍历直到找到带有 main-id 属性的节点
const findParentWithMainId = (node) => {
while (node) {
if (node.hasAttribute && node.classList.contains('pMain')) {
return node; // 找到并返回该节点
}
node = node.parentNode; // 向上遍历父节点
}
return null; // 如果没有找到,返回 null
};
// 查找选中节点的父节点,直到找到带有 main-id 属性的节点
const nodeWithMainId = findParentWithMainId(selectedNode);
console.log('at line 395:', nodeWithMainId);
const dataId = nodeWithMainId.getAttribute('main-id');
event.preventDefault();
hideDeleteButton();
// 获取拖动的数据
_this.$emit('onDrop', event, dataId); // 阻止默认的行为
// 在编辑器中插入数据
// const content = <div class="dropped-item">${itemData}</div>;
// ed.insertContent(content); // 插入文本或HTML
});
// 方法:更新当前选中的 p 标签的样式
_this.updateCurrentTag = function (ed) {
var selection = ed.selection;
var node = selection.getNode();
// 向上查找包含的节点直到找到合适的标签
if (node && !node.classList.contains('pMain')) {
node = node.closest('.pMain'); // 向上找到最近的包含 'aa' 类的标签
}
if (node && node.classList.contains('pMain')) {
// 清除上一个高亮的节点样式
if (_this.lastTag && _this.lastTag !== node) {
_this.lastTag.style.backgroundColor = ''; // 清除上一个高亮的标签样式
_this.lastTag.style.border = '';
}
// 设置当前节点的背景色和边框
node.style.backgroundColor = 'rgb(0 102 153 / 10%)';
node.style.border = '2px dashed rgb(0 102 153 / 50%)';
// 更新选中的节点
var currentNode = node;
// 显示删除按钮
showDeleteButton(currentNode);
// 更新 lastTag
_this.lastTag = node;
} else {
// 如果没有找到包含 'aa' 类的节点,隐藏删除按钮
hideDeleteButton();
}
};
function hideDeleteButton() {
if (wordButtonContainer) {
wordButtonContainer.remove(); // 移除删除按钮
wordButtonContainer = null; // 清空按钮引用
}
}
function showDeleteButton(paragraph) {
if (wordButtonContainer) {
wordButtonContainer.remove(); // 如果已有按钮容器,移除
}
// 获取 <p> 标签的位置信息
const paragraphRect = paragraph.getBoundingClientRect();
const iframe = ed.getDoc().defaultView.frameElement;
const iframeRect = iframe.getBoundingClientRect();
var left = 0;
if (_this.isEditComment) {
left = 100;
} else {
left = 80;
}
// 创建按钮容器 div
wordButtonContainer = document.createElement('div');
wordButtonContainer.style.position = 'absolute';
wordButtonContainer.style.top = `${iframeRect.top + paragraphRect.top + window.scrollY - 20}px`; // 确保按钮容器位于 <p> 标签旁边
wordButtonContainer.style.left = `${iframeRect.left + paragraphRect.left + paragraphRect.width - left}px`;
wordButtonContainer.style.zIndex = '9999'; // 设置更高的值
wordButtonContainer.style.display = 'flex'; // 使用 flex 布局将按钮水平排列
wordButtonContainer.style.alignItems = 'center'; // 垂直居中
// 创建删除按钮
const deleteButton = document.createElement('button');
deleteButton.style.backgroundColor = 'red';
deleteButton.style.color = 'white';
deleteButton.style.border = 'none';
deleteButton.style.borderRadius = '50%';
deleteButton.style.padding = '5px';
deleteButton.style.cursor = 'pointer';
deleteButton.style.marginLeft = '10px'; // 给批注按钮添加间距
const deleteIcon = document.createElement('i');
deleteIcon.classList.add('el-icon-delete'); // 使用 Element UI 删除图标
deleteIcon.style.fontSize = '20px';
deleteIcon.style.color = '#fff'; // 设置图标颜色
deleteButton.appendChild(deleteIcon);
deleteButton.addEventListener('mousedown', function (e) {
e.stopImmediatePropagation();
e.preventDefault();
_this.$emit('onDelete', paragraph.getAttribute('main-id'));
});
// 创建批注按钮
const editButton = document.createElement('button');
editButton.style.backgroundColor = 'rgb(19, 188, 32)';
editButton.style.color = 'white';
editButton.style.border = 'none';
editButton.style.borderRadius = '50%';
editButton.style.padding = '5px';
editButton.style.marginLeft = '10px'; // 给批注按钮添加间距
editButton.style.cursor = 'pointer';
const editIcon = document.createElement('i');
editIcon.classList.add('el-icon-edit'); // 使用 Element UI 批注图标
editIcon.style.fontSize = '20px';
editIcon.style.color = '#fff'; // 设置图标颜色
editButton.appendChild(editIcon);
editButton.addEventListener('mousedown', function (e) {
e.stopImmediatePropagation();
e.preventDefault();
// 触发批注事件
_this.$emit('onEdit', paragraph.getAttribute('main-id'));
});
// 将按钮添加到容器中
wordButtonContainer.appendChild(editButton);
wordButtonContainer.appendChild(deleteButton);
if (_this.isEditComment) {
// 创建批注按钮
const commentButton = document.createElement('button');
commentButton.style.backgroundColor = '#2b81ef';
commentButton.style.color = 'white';
commentButton.style.border = 'none';
commentButton.style.borderRadius = '50%';
commentButton.style.padding = '5px';
commentButton.style.marginLeft = '10px'; // 给批注按钮添加间距
commentButton.style.cursor = 'pointer';
const commentIcon = document.createElement('i');
commentIcon.classList.add('el-icon-chat-dot-square'); // 使用 Element UI 批注图标
commentIcon.style.fontSize = '20px';
commentIcon.style.color = '#fff'; // 设置图标颜色
commentButton.appendChild(commentIcon);
commentButton.addEventListener('mousedown', function (e) {
e.stopImmediatePropagation();
e.preventDefault();
// 触发批注事件
_this.$emit('onAddComment', paragraph.getAttribute('main-id'));
if (wordButtonContainer) {
wordButtonContainer.remove(); // 移除删除按钮
wordButtonContainer = null; // 清空按钮引用
}
});
wordButtonContainer.appendChild(commentButton);
}
wordButtonContainer.classList.add('wordButtonContainer'); // 给按钮
// 将容器添加到页面中
document.body.appendChild(wordButtonContainer);
}
// 获取 TinyMCE iframe 内部的 document 对象
// 监听 TinyMCE iframe 内容区域的滚动事件
ed.on('mousedown', function (e) {
// 检查点击的位置是否是删除按钮或选中的 <p> 标签
if (!currentParagraph || (e.target !== wordButtonContainer && !currentParagraph.contains(e.target))) {
if (wordButtonContainer) {
wordButtonContainer.remove(); // 移除删除按钮
wordButtonContainer = null; // 清空按钮引用
}
}
});
},
init_instance_callback: (editor) => {
if (_this.value) {
editor.setContent(_this.value);
_this.$emit('loaded');
}
_this.hasInit = true;
editor.on('NodeChange Change KeyUp SetContent', () => {
this.hasChange = true;
this.$emit('input', editor.getContent());
});
const iframeDocument = editor.getDoc(); // 使用 ed.getDoc() 获取编辑器的 document
if (iframeDocument) {
iframeDocument.addEventListener('scroll', function () {
if (wordButtonContainer) {
wordButtonContainer.remove();
wordButtonContainer = null;
}
if (_this.lastTag) {
_this.lastTag.style.backgroundColor = ''; // 清除上一个高亮的标签样式
_this.lastTag.style.border = '';
}
});
}
}
});
},
// 显示选中的批注内容
viewCommentDetail(comment) {
this.selectedComment = comment.text;
},
// 关闭批注详情
closeCommentDetails() {
this.selectedComment = null;
},
replacePlaceholderImage(ami_id, realImgSrc) {
console.log('realImgSrc at line 638:', ami_id, realImgSrc);
const iframeDocument = window.tinymce.get(this.tinymceId).getDoc();
console.log('iframeDocument at line 639:', iframeDocument);
const placeholderImg = iframeDocument.querySelector(`img[data-img-id="${ami_id}"]`);
console.log('placeholderImg at line 640:', placeholderImg);
if (placeholderImg) {
placeholderImg.src = realImgSrc; // 替换图片 URL
placeholderImg.removeAttribute('data-img-id'); // 删除标识属性
}
},
// 提取 Word 文件中的表格
updateTableStyles(container) {
var html = this.$commonJS.updateTableStyles(container, this.typesettingType);
var editor = window.tinymce.activeEditor; // 将外部 DOM 内容更新到编辑器
const container1 = document.createElement('div');
container1.innerHTML = html; // html 是更新后的 HTML 内容
editor.setContent(container1.innerHTML); // 更新编辑器内容
editor.focus(); // 聚焦到编辑器// 触发编辑器内容变化后,如果需要,可能还要设置编辑器的样式
},
//销毁富文本
destroyTinymce() {
if (window.tinymce.get(this.tinymceId)) {
window.tinymce.get(this.tinymceId).destroy();
}
},
//设置内容
setContent(value) {
window.tinymce.get(this.tinymceId).setContent(value);
},
//获取内容
getContent(type) {
this.$emit('getContent', type, window.tinymce.get(this.tinymceId).getContent());
},
async export(type, data) {
if (type == 'table') {
var tableHtml = `<html xmlns:w="urn:schemas-microsoft-com:office:word">
<head>
<style>
${tableStyle}
</style>
</head>
<body>
${data}
</body>
</html>`;
const converted = htmlDocx.asBlob(tableHtml, {
orientation: this.typesettingTypeOptions[this.typesettingType - 1].orientation,
pageSize: {
...this.typesettingTypeOptions[this.typesettingType - 1].pageSize
},
pageMargins: {
...this.typesettingTypeOptions[this.typesettingType - 1].pageMargins
}
});
// const converted = htmlDocx.asBlob(tableHtml); // 将 HTML 转换为 Word Blob
// 触发文件下载
const link = document.createElement('a');
link.href = URL.createObjectURL(converted);
link.download = 'table.docx';
link.click();
} else if (type == 'image') {
const hiddenContainer = document.createElement('div');
hiddenContainer.style.position = 'absolute';
hiddenContainer.style.left = '-9999ppx';
hiddenContainer.style.top = '0';
hiddenContainer.innerHTML = data;
const style = document.createElement('style');
style.innerHTML = `${tableStyle}`;
document.head.appendChild(style);
document.body.appendChild(hiddenContainer);
// 使用 html2canvas 捕获表格内容
const table = hiddenContainer.querySelector('table'); // 找到表格
table.style.border = 'none';
// 使用 html2canvas 将内容转为图片
html2canvas(hiddenContainer, {
scale: 2, // 提高图片的分辨率默认为1设置为2可以使图片更清晰
logging: false, // 禁用日志输出
useCORS: true, // 允许跨域图像
allowTaint: true // 允许污染 canvas解决图片链接不可用问题
})
// 清空现有内容,显示图片
.then((canvas) => {
const imgData = canvas.toDataURL('image/png'); // 创建一个图片对象
const link = document.createElement('a'); // 创建一个链接并下载图片
link.href = imgData;
link.download = 'image.png';
link.click();
});
}
},
inlineStyles(element) {
const styles = window.getComputedStyle(element);
for (let style in styles) {
if (styles.hasOwnProperty(style)) {
element.style[style] = styles[style];
}
}
},
//获取上传图片后的地址,并设置图片样式
tableSuccessCBK(arr) {
console.log(arr, '222');
const _this = this;
window.tinymce.get(_this.tinymceId).insertContent(arr);
}
},
destroyed() {
this.destroyTinymce();
}
};
</script>
<style scoped>
::v-deep .tox-tinymce-aux {
z-index: 9999 !important;
}
::v-deep .tox .tox-menu {
z-index: 9999 !important;
}
/* 自定义按钮样式 */
.custom-btn {
background-color: #28a745 !important;
color: #fff !important;
border-radius: 4px;
padding: 5px 10px;
font-weight: bold;
}
.custom-btn:hover {
background-color: #218838 !important;
}
/* 批注的样式 */
.comment {
position: relative;
background-color: #ffeb3b;
color: black;
padding: 2px 5px;
border-radius: 5px;
cursor: pointer;
display: inline-block;
}
.comment::after {
content: attr(title);
position: absolute;
top: -20px;
left: 0;
background-color: #f1f1f1;
padding: 5px;
border-radius: 5px;
font-size: 12px;
display: none;
white-space: nowrap;
max-width: 150px;
word-wrap: break-word;
}
.comment:hover::after {
display: block;
}
</style>

View File

@@ -0,0 +1,749 @@
<template>
<div
style="background-color: transparent !important; margin-top: 0px !important; height: 100%; padding: 0 !important; overflow: hidden"
class="ManuscirptList"
v-show="tables.length > 0 || images.length > 0"
>
<!-- 图片缩略图区域 -->
<div style="width: 100%; padding: 10px; height: 100%; box-sizing: border-box; overflow-y: auto" class="arrlist">
<ul style="width: 100%; height: auto">
<el-collapse v-model="activeNames" @change="changeActiveNames"
><el-collapse-item name="images" style="" v-if="images.length > 0">
<template slot="title">
<p style="font-weight: bold; color: #222 !important">Manuscirpt Figures ( {{ images.length }} )</p>
<!-- <p style="margin-left: 20px">
<i class="header-icon el-icon-info"></i
><span style="margin-left: 5px; color: rgb(153, 153, 153)">Click to open the Figures</span>
</p> -->
</template>
<!-- <p style="margin-bottom: 15px;color: rgb(153, 153, 153);line-height: 16px;"> If you have any questions that need to be addressed to the author, you can leave valuable comments or suggestions below the Figures</p> -->
<li >
<div class="go-content-charts-item-box" style="display: flex; flex-wrap: wrap; gap: 10px; justify-content: start">
<div
class="item_box"
v-for="(img, index) in images"
style="width: 180px; height: auto; position: relative"
:key="index"
>
<div class="list-center go-flex-center go-transition" style="width: 100%">
<div class="title">
<span
>Figure {{ index + 1 }}
<span
@click="openPreview(index, 'img')"
v-if="['jpg', 'jpeg', 'png'].includes(img.image.split('.').pop().toLowerCase())"
>
<!-- <el-tooltip class="item" effect="dark" :content="$t('commonTable.preview')" placement="top"> -->
<i class="el-icon-view" style="font-size: 16px"></i>
<!-- </el-tooltip> -->
</span>
<a :href="mediaUrl + img.image.url" style="color: #000" v-else>
<!-- <el-tooltip class="item" effect="dark" :content="$t('commonTable.preview')" placement="top"> -->
<i class="el-icon-download" style="font-size: 16px"></i>
<!-- </el-tooltip> -->
</a>
</span>
</div>
<span
v-if="img.has_selected == 1"
@click="goToListComment(img.article_image_id, 'img')"
style="
text-align: center;
height: 20px;
padding: 2px 0;
line-height: 20px;
width: 60px;
z-index: 10;
border-radius: 4px;
background-color: #006699d1;
color: #ffff;
font-weight: bold;
position: absolute;
top: 45%;
left: calc((100% - 60px) / 2);
"
>{{ $t('commonTable.Typed') }}</span
>
<div
class="thumbnailBox image list-img"
:style="`
opacity:${img.has_selected == 1 ? '0.6' : '1'};
border: 1px solid #ccccccb5;
width: 100%;
height: auto;
border-radius: 4px;
overflow: hidden;
position: relative;`"
>
<div style="width: 100%; height: 80px; display: flex; justify-content: center; align-items: center">
<!-- 图片内容 -->
<template v-if="['jpg', 'jpeg', 'png'].includes(img.image.split('.').pop().toLowerCase())">
<img
:data-img-id="img.article_image_id"
:src="mediaUrl + img.image"
style="width: 140px; height: 100%; object-fit: cover"
/>
</template>
<template v-else-if="img.image.split('.').pop().toLowerCase() === 'tif'">
<img
:data-img-id="img.article_image_id"
:src="img.dataUrl"
style="width: 140px; height: 100%; object-fit: cover"
/>
</template>
<template v-else>
<div
style="
width: 140px;
height: 100%;
text-align: center;
font-size: 30px;
display: flex;
align-items: center;
justify-content: center;
"
>
{{ img.image.split('.').pop().toUpperCase() }}
<!-- <i class="el-icon-download" style="margin-left: 10px; color: #75abf1"></i> -->
</div>
<!-- </a> -->
</template>
</div>
<!-- 输入框 -->
</div>
</div>
<el-collapse v-if="isShowEdit">
<el-collapse-item name="1" style="margin-top: 4px">
<template slot="title">
<div style="width: 100%; display: flex; align-items: center; justify-content: space-between">
<span style="color: #777">Tables {{ index + 1 }}</span>
<span v-if="isShowEdit"><i class="el-icon-edit" v-if="isEdit"></i>Comments/ Suggestions</span>
</div>
</template>
<el-input
v-if="isShowEdit"
type="textarea"
placeholder="please input content"
:readonly="!isEdit"
:rows="4"
></el-input>
</el-collapse-item>
</el-collapse>
<!-- <p
style="color: #777; margin-top: 6px"
v-else
@click="img.has_selected == 1 ? goToListComment(img.article_image_id, 'img') : ''"
>
<el-link> Figures {{ index + 1 }} </el-link>
</p> -->
</div>
</div>
</li>
</el-collapse-item>
<el-collapse-item name="tables" style="" v-if="tables.length > 0">
<template slot="title">
<p style="font-weight: bold; color: #222">Manuscirpt Tables ( {{ tables.length }} )</p>
<!-- <p style="margin-left: 20px">
<i class="header-icon el-icon-info"></i
><span style="margin-left: 5px; color: rgb(153, 153, 153)">Click to open the Tables</span>
</p> -->
</template>
<!-- <p style="margin-bottom: 15px;color: rgb(153, 153, 153);line-height: 16px;"> If you have any questions that need to be addressed to the author, you can leave valuable comments or suggestions below the Table</p> -->
<!-- 表格缩略图区域 -->
<li >
<div class="go-content-charts-item-box" style="display: flex; flex-wrap: wrap; gap: 10px; justify-content: start; margin-top: 20px">
<div
class="item_box"
v-for="(table, index) in tables"
style="width: 180px; height: auto; position: relative"
:key="index"
>
<div class="list-center go-flex-center go-transition" style="width: 100%">
<div class="title">
<span
>Table {{ index + 1 }}
<span @click="openPreview(index, 'table')">
<el-tooltip class="item" effect="dark" :content="$t('commonTable.preview')" placement="top">
<i class="el-icon-view" style="font-size: 16px"></i>
</el-tooltip> </span
></span>
</div>
<span
v-if="table.has_selected == 1"
@click="goToListComment(table.article_table_id, 'table')"
style="
text-align: center;
height: 20px;
padding: 2px 0;
line-height: 20px;
width: 60px;
z-index: 10;
border-radius: 4px;
background-color: #006699d1;
color: #ffff;
font-weight: bold;
position: absolute;
top: 45%;
left: calc((100% - 60px) / 2);
"
>{{ $t('commonTable.Typed') }}</span
>
<div
class="thumbnailBox image list-img"
:style="`
opacity:${table.has_selected == 1 ? '0.6' : '1'};
border: 1px solid #ccccccb5;
width: 100%;
height: auto;
border-radius: 4px;
overflow: hidden;
position: relative;`"
>
<div style="width: 100%; height: 80px; display: flex; justify-content: center; align-items: center">
<!-- 图片内容 -->
<table
:data-table-id="table.article_table_id"
border="1"
style="
transform: scale(0.5);
width: 140px;
height: auto;
background-color: #fff;
border-collapse: collapse;
text-align: center;
"
>
<tr v-for="(row, rowIndex) in table.table" :key="rowIndex">
<td
v-for="(cell, cellIndex) in row"
:key="cellIndex"
:colspan="cell.colspan || 1"
:rowspan="cell.rowspan || 1"
>
<span v-html="cell.text"> </span>
</td>
</tr>
</table>
</div>
<!-- 输入框 -->
</div>
</div>
<el-collapse v-if="isShowEdit">
<el-collapse-item name="1" style="margin-top: 4px">
<template slot="title">
<div style="width: 100%; display: flex; align-items: center; justify-content: space-between">
<span style="color: #777">Tables {{ index + 1 }}</span>
<span v-if="isShowEdit"><i class="el-icon-edit" v-if="isEdit"></i>Comments/ Suggestions</span>
</div>
</template>
<el-input
v-if="isShowEdit"
type="textarea"
placeholder="please input content"
:readonly="!isEdit"
:rows="4"
></el-input>
</el-collapse-item>
</el-collapse>
<!-- <p
style="color: #777; margin-top: 6px"
v-else
@click="img.has_selected == 1 ? goToListComment(img.article_image_id, 'img') : ''"
>
<el-link> Figures {{ index + 1 }} </el-link>
</p> -->
</div>
</div>
</li>
</el-collapse-item>
</el-collapse>
</ul>
</div>
</div>
</template>
<script>
import { mediaUrl } from '@/common/js/commonJS.js'; // 引入通用逻辑
export default {
props: ['articleId', 'imgWidth', 'imgHeight', 'scale', 'isEdit', 'isShowEdit', 'urlList', 'content'],
data() {
return {
identity: localStorage.getItem('U_role'),
isShowComment: false,
isEditing: null, // 用于跟踪当前正在编辑的批注索引
selectedComment: null, // 存储当前选择的批注内容
comments: [], // 存储所有批注
isFresh: false,
currentSelectType: '0',
currentMenu: 1,
mediaUrl,
statusList: [
{ title: 'ALL', type: '0' },
{ title: 'Typed', type: '1' },
{ title: 'Unfettered', type: '2' }
],
images: [],
tables: [],
imagesList: [],
tablesList: [],
tablesHtml: [],
imagesHtml: [],
activeNames: []
};
},
directives: {
// 注册一个局部的自定义指令 v-focus
focus: {
// 指令的定义
inserted: function (el) {
console.log('el at line 263:', el);
// 聚焦元素
el.querySelector('textarea').focus();
}
}
},
methods: {
add(type) {
this.$emit('add', type);
},
edit(data, type) {
this.$emit('edit', data, type);
},
huifu(id) {
this.$emit('huifu', id);
},
handleSelectMenu(v) {
this.currentMenu = v;
this.currentSelectType = '0';
if (v == 1) {
this.getCommentList();
} else {
this.filterData();
}
},
selectType(v) {
this.currentSelectType = v.type;
this.filterData();
},
filterData(type) {
console.log('type at line 374:', type);
if (type) {
if (type == 'img') {
this.imagesList = [...this.images];
} else if (type == 'table') {
this.tablesList = [...this.tables];
}
} else {
if (this.currentMenu == 2) {
switch (this.currentSelectType) {
case '0':
this.imagesList = [...this.images];
break;
case '1':
this.imagesList = [...this.images].filter((e) => e.has_selected == 1);
break;
case '2':
this.imagesList = [...this.images].filter((e) => e.has_selected == 0);
break;
}
} else if (this.currentMenu == 3) {
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);
break;
case '2':
this.tablesList = [...this.tables].filter((e) => e.has_selected == 0);
break;
}
} else {
}
}
},
goToListComment(id, type) {
this.$emit('goToListComment', id, type);
},
async refresh(type) {
this.isFresh = false;
this.$nextTick(async () => {
if (type == 'img') {
await this.getWordimgList();
await this.handleSelectMenu(2);
} else if (type == 'table') {
await this.getWordTablesList();
}
this.$forceUpdate();
this.isFresh = true;
});
},
changeDataIsHidden(val, status, type) {
console.log('type at line 165:', type);
var index;
this.$nextTick(() => {
if (type == 'img') {
index = this.images.findIndex((element) => element.article_image_id === val.article_image_id);
console.log('index at line 170:', index);
this.images[index].isHidden = status;
} else {
index = this.tables.findIndex((element) => element.id === id);
this.tables[index].isHidden = status;
}
this.$forceUpdate();
});
},
changeIsHidden(index, status, type) {
console.log('type at line 165:', type);
this.$nextTick(() => {
if (type == 'img') {
this.images[index].isHidden = status;
} else {
this.tables[index].isHidden = status;
console.log('this.tables at line 169:', this.tables);
}
this.$forceUpdate();
});
},
onDragStart($event, item, index, type) {
console.log('type at line 192:', index);
this.$emit('onDragStart', $event, item, index, type);
},
changeActiveNames(e) {
console.log('e at line 156:', e);
if (['tables'].includes(e)) {
this.$nextTick(() => {
this.getWordTablesList();
});
}
if (['images'].includes(e)) {
this.$nextTick(() => {
this.getWordimgList();
});
}
},
openPreview(index, type) {
this.$nextTick(() => {
document.getElementById(type + '-modal-' + index).style.display = 'flex';
});
},
async getWordimgList() {
await this.$api
.post(this.urlList ? this.urlList.img : 'api/Article/getArticleImages', {
article_id: this.articleId
})
.then(async (res) => {
var list = [...res.data.list];
if (this.urlList) {
list = list.map((e) => {
return {
...e,
image: e.url,
article_image_id: e.ami_id
};
});
} else {
list = res.data.list;
}
if (list.length > 0) {
list.forEach((img, index) => {
var extension = img.image.split('.').pop().toLowerCase();
if (extension === 'tif' || extension === 'jpg' || extension === 'jpeg' || extension === 'png') {
const modalContent = ['jpg', 'jpeg', 'png'].includes(extension)
? `<img src="${this.mediaUrl + img.image}" alt="Image ${index}" style="width:100%;background:#FFF;" >`
: `<canvas id="tiff-canvas-modal-${index}" ></canvas>`;
this.$commonJS.createImageModal(index, modalContent, 'img');
}
if (extension === 'tif') {
this.$nextTick(() => {
this.$commonJS.renderTiffImage(
this.mediaUrl + img.image,
`tiff-canvas-modal-${index}`,
function (url) {
list[index].dataUrl = url;
},
index,
true
);
});
}
});
}
this.images = list;
this.$emit('loaded');
});
},
async getWordTablesList(callback) {
this.$api
.post(this.urlList ? this.urlList.table : 'api/Article/getArticleTable', {
article_id: this.articleId
})
.then(async (res) => {
if (this.urlList) {
this.tables =
res.data.list && res.data.list.length > 0
? res.data.list.map((e) => {
return {
...e,
article_table_id: e.amt_id,
table: JSON.parse(e.table_data)
};
})
: [];
} else {
this.tables =
res.data.list && res.data.list.length > 0
? res.data.list.map((e) => {
return {
...e,
table: JSON.parse(e.table)
};
})
: [];
}
await this.filterData('table');
if (this.tables.length > 0) {
this.tables.forEach((table, index) => {
var modalContent = `
<div class="wordTableHtml" style="background:#FFF;padding:20px">
<table
border="1"
style="
border-collapse: collapse;
width: 100%;
text-align: center;
table-layout: auto;"
>`;
table.table.forEach((row) => {
modalContent += `<tr>`;
row.forEach((cell) => {
modalContent += `
<td
colspan="${cell.colspan || 1}"
rowspan="${cell.rowspan || 1}"
style=""
>
<span>${cell.text}</span>
</td>`;
});
modalContent += `</tr>`;
});
modalContent += `</table></div>`;
this.$commonJS.createImageModal(index, modalContent, 'table', '');
});
}
console.log('this.tables at line 533:', this.tables);
});
}
},
async created() {
this.isFresh = false;
this.$nextTick(async () => {
await this.getWordimgList();
await this.getWordTablesList();
await this.filterData();
this.isFresh = true;
});
},
async activated() {
this.isFresh = false;
this.$nextTick(async () => {
await this.getWordimgList();
await this.getWordTablesList();
await this.filterData();
this.isFresh = true;
});
},
mounted() {}
};
</script>
<style scoped>
.ManuscirptList {
background-color: none !important;
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0);
color: #333639;
}
.ManuscirptList div {
cursor: pointer;
background-color: none !important;
}
::v-deep .wordTableHtml table {
cursor: pointer;
background-color: #fff !important;
}
.el-menu-vertical-demo {
width: 85px;
}
.el-menu-vertical-demo li {
display: flex;
flex-direction: column;
padding: 10px 6px !important;
font-size: 14px !important;
text-align: center;
}
::v-deep .el-menu-vertical-demo.el-menu-item:focus,
.el-menu-item:hover {
background-color: #f8f8f9 !important;
}
::v-deep .el-menu-item.is-active {
background-color: #2196f32e !important;
}
.isSelectType {
background-color: #2196f32e !important;
color: #006699;
}
li {
list-style: none;
}
.item_box {
background-color: #f2f3f5;
border: 1px solid rgba(0, 0, 0, 0);
border-radius: 6px;
overflow: hidden;
}
.go-transition .title {
background-color: #e5e6eb;
color: #767c82;
font-size: 13px;
padding: 2px 10px;
display: flex;
align-items: center;
justify-content: space-between;
}
.go-transition .list-img {
padding: 6px 0;
background-color: #f2f3f5;
box-sizing: border-box;
}
.go-transition .list-img :hover {
transition: all 0.4s;
}
.go-content-charts-item-box {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: 9px;
transition: all 0.7s linear;
}
.arrlist::-webkit-scrollbar-thumb {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0);
min-height: 12px;
border: 4px solid transparent;
background-clip: content-box;
border-radius: 7px;
background-color: #c8d5e1;
}
.badge {
background-color: #f56c6c;
border-radius: 10px;
color: #fff;
display: inline-block;
font-size: 12px;
height: 18px;
line-height: 18px;
padding: 0 6px;
text-align: center;
white-space: nowrap;
border: 1px solid #fff;
position: absolute;
}
.comments-section {
padding: 10px;
box-sizing: border-box;
border: 1px solid #cecfd3;
border-left: 2px solid #cecfd3;
/* border-radius: 5px; */
background-color: #f9f9f9;
box-shadow: rgba(16, 17, 19, 0.06) 0px 1px 3px;
width: 300px;
background-color: #fafafa;
float: right;
position: absolute;
right: -302px;
top: 0px;
z-index: 999;
}
.comment-item {
padding: 5px 0;
border-bottom: 1px solid #ddd;
cursor: pointer;
box-sizing: border-box;
font-size: 14px;
}
.comment-item:last-child {
border-bottom: none;
}
.comment-details {
margin-top: 20px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
background-color: #f9f9f9;
}
.comment-details h3 {
margin-bottom: 10px;
}
.comment-details p {
margin-bottom: 10px;
}
.comment-details button {
padding: 5px 10px;
background-color: #007bff;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
.comment-details button:hover {
background-color: #0056b3;
}
.comments-section ul,
.comments-section li {
list-style: none;
margin: 0;
padding: 0;
}
</style>

View File

@@ -0,0 +1,955 @@
<template>
<div
style="background-color: transparent !important; margin-top: 0px !important; height: 100%; padding: 0 !important; overflow: hidden"
class="ManuscirptList"
v-show="tables.length > 0 || images.length > 0"
>
<!-- 图片缩略图区域 -->
<el-menu
default-active="1"
style="border: none; height: 100%; float: left"
background-color="#f8f8f9"
active-text-color="#006699"
text-color="#333639"
class="el-menu-vertical-demo"
@select="handleSelectMenu"
>
<el-menu-item index="1">
<i class="el-icon-message-solid" style="margin: 0 auto; color: #fc625d"></i>
<span slot="title" style="line-height: 30px">Annotations</span>
</el-menu-item>
<el-menu-item index="2">
<i class="el-icon-picture" color="#333639" style="margin: 0 auto"></i>
<span slot="title" style="line-height: 20px">Figures</span>
</el-menu-item>
<el-menu-item index="3">
<i class="el-icon-s-grid" color="#333639" style="margin: 0 auto"></i>
<span slot="title" style="line-height: 30px">Tables</span>
</el-menu-item>
<el-menu-item index="4">
<i class="el-icon-delete-solid" color="#333639" style="margin: 0 auto"></i>
<span slot="title" style="line-height: 30px">Recycle Bin</span>
</el-menu-item>
</el-menu>
<!-- <ul style="width: 80px; height: 100%; float: left; padding: 6px; box-sizing: border-box" v-if="currentMenu != 3">
<li
@click="selectType(v)"
:class="`${currentSelectType == v.type ? 'isSelectType' : ''}`"
v-for="(v, i) in statusList"
style="
margin: 8px 0;
cursor: pointer;
padding: 0px 0px !important;
font-size: 13px !important;
line-height: 30px;
text-align: center;
border-radius: 4px;
"
>
<p>{{ v.title }}</p>
</li>
</ul> -->
<div style="width: 200px; float: right; padding: 10px; height: 100%; box-sizing: border-box; overflow-y: auto" class="arrlist">
<ul style="width: 100%; height: auto">
<li v-show="currentMenu == 1">
<div style="display: flex; flex-wrap: wrap; gap: 10px; justify-content: start">
<li v-for="(comment, index) in comments" :key="index" class="comment-item" style="width: 100%; padding: 6px 0">
<div @click.prevent="goToComment(comment.am_id)">
<p style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px">
<el-link class="pizhu">
<span style="color: #fc625d; display: flex; align-items: center">
<img
class="isRemark"
src="@/assets/img/isRemark.png"
alt=""
style="width: 15px; height: 15px; margin-right: 6px"
/>
{{ comment.am_id }}</span
></el-link
>
<span style="color: #b8b7b7;font-size: 12px">{{ getTime(comment.ctime) }}</span>
</p>
<!-- isEditing true 显示可编辑的输入框 -->
<!-- <div v-if="isEditing === index">
<el-input
v-focus
type="textarea"
v-model="comment.remark"
@blur.stop="saveComment(index,comment)"
style="width: 100%; box-sizing: border-box; padding: 5px"
></el-input>
</div> -->
<!-- isEditing false 显示评论文本 -->
<div style="display: flex; align-items: center; justify-content: space-between">
<p style="min-height: 20px; width: calc(100%);white-space: normal;">
{{ comment.remark }}
<!-- <span @click="editComment(index)" style="cursor: pointer; color: #007bff; margin-left: 10px;">修改</span> -->
</p>
<!-- <i
class="el-icon-delete"
v-if="isShowComment"
@click="deleteComment(comment, index)"
style="color: #cd5454"
></i> -->
</div>
<!-- 删除按钮 -->
</div>
</li>
</div>
</li>
<li v-show="currentMenu == 2">
<div style="" class="go-content-charts-item-box">
<div class="item_box" style="width: 100%; height: auto; position: relative">
<el-collapse v-if="isShowEdit">
<el-collapse-item name="1" style="margin-top: 4px">
<template slot="title">
<div style="width: 100%; display: flex; align-items: center; justify-content: space-between">
<span style="color: #777">Tables {{ index + 1 }}</span>
<span v-if="isShowEdit"><i class="el-icon-edit" v-if="isEdit"></i>Comments/ Suggestions</span>
</div>
</template>
<el-input
v-if="isShowEdit"
type="textarea"
placeholder="please input content"
:readonly="!isEdit"
:rows="4"
></el-input>
</el-collapse-item>
</el-collapse>
<!-- <p
style="color: #777; margin-top: 6px"
v-else
@click="img.has_selected == 1 ? goToListComment(img.article_image_id, 'img') : ''"
>
<el-link> Figures {{ index + 1 }} </el-link>
</p> -->
</div>
<div
class="item_box"
v-for="(img, index) in imagesList"
style="width: 100%; height: auto; position: relative"
:key="index"
>
<div class="list-center go-flex-center go-transition" style="width: 100%">
<div class="title">
<span
>Figure {{ index + 1 }}
<span
@click="openPreview(index, 'img')"
v-if="['jpg', 'jpeg', 'png'].includes(img.image.split('.').pop().toLowerCase())"
>
<!-- <el-tooltip class="item" effect="dark" :content="$t('commonTable.preview')" placement="top"> -->
<i class="el-icon-view" style="font-size: 16px"></i>
<!-- </el-tooltip> -->
</span>
<a :href="mediaUrl + img.image.url" style="color: #000" v-else>
<!-- <el-tooltip class="item" effect="dark" :content="$t('commonTable.preview')" placement="top"> -->
<i class="el-icon-download" style="font-size: 16px"></i>
<!-- </el-tooltip> -->
</a>
</span>
<p>
<span style="" @click="edit(img, 'img')">
<i class="el-icon-edit" style="color: #409eff; font-size: 16px"></i>
</span>
</p>
</div>
<span
v-if="img.has_selected == 1"
@click="goToListComment(img.article_image_id, 'img')"
style="
text-align: center;
height: 20px;
padding: 2px 0;
line-height: 20px;
width: 60px;
z-index: 10;
border-radius: 4px;
background-color: #006699d1;
color: #ffff;
font-weight: bold;
position: absolute;
top: 45%;
left: calc((100% - 60px) / 2);
"
>{{ $t('commonTable.Typed') }}</span
>
<div
class="thumbnailBox image list-img"
:style="`
opacity:${img.has_selected == 1 ? '0.6' : '1'};
border: 1px solid #ccccccb5;
width: 100%;
height: auto;
border-radius: 4px;
overflow: hidden;
position: relative;`"
:draggable="img.has_selected == 0 ? true : false"
@dragstart="img.has_selected == 0 ? onDragStart($event, img, index, 'img') : ''"
>
<div style="width: 100%; height: 80px; display: flex; justify-content: center; align-items: center">
<!-- 图片内容 -->
<template v-if="['jpg', 'jpeg', 'png'].includes(img.image.split('.').pop().toLowerCase())">
<img
:data-img-id="img.article_image_id"
:src="mediaUrl + img.image"
style="width: 140px; height: 100%; object-fit: cover"
/>
</template>
<template v-else-if="img.image.split('.').pop().toLowerCase() === 'tif'">
<img
:data-img-id="img.article_image_id"
:src="img.dataUrl"
style="width: 140px; height: 100%; object-fit: cover"
/>
</template>
<template v-else>
<div
style="
width: 140px;
height: 100%;
text-align: center;
font-size: 30px;
display: flex;
align-items: center;
justify-content: center;
"
>
{{ img.image.split('.').pop().toUpperCase() }}
<!-- <i class="el-icon-download" style="margin-left: 10px; color: #75abf1"></i> -->
</div>
<!-- </a> -->
</template>
</div>
<!-- 输入框 -->
</div>
</div>
<el-collapse v-if="isShowEdit">
<el-collapse-item name="1" style="margin-top: 4px">
<template slot="title">
<div style="width: 100%; display: flex; align-items: center; justify-content: space-between">
<span style="color: #777">Tables {{ index + 1 }}</span>
<span v-if="isShowEdit"><i class="el-icon-edit" v-if="isEdit"></i>Comments/ Suggestions</span>
</div>
</template>
<el-input
v-if="isShowEdit"
type="textarea"
placeholder="please input content"
:readonly="!isEdit"
:rows="4"
></el-input>
</el-collapse-item>
</el-collapse>
<!-- <p
style="color: #777; margin-top: 6px"
v-else
@click="img.has_selected == 1 ? goToListComment(img.article_image_id, 'img') : ''"
>
<el-link> Figures {{ index + 1 }} </el-link>
</p> -->
</div>
</div>
</li>
<li v-show="currentMenu == 3">
<div style="" class="go-content-charts-item-box">
<div
class="item_box"
v-for="(table, index) in tablesList"
style="width: 100%; height: auto; position: relative"
:key="index"
>
<div class="list-center go-flex-center go-transition" style="width: 100%">
<div class="title">
<span
>Table {{ index + 1 }}
<span @click="openPreview(index, 'table')">
<el-tooltip class="item" effect="dark" :content="$t('commonTable.preview')" placement="top">
<i class="el-icon-view" style="font-size: 16px"></i>
</el-tooltip> </span
></span>
<p>
<span style="" @click="edit(table, 'table')">
<i class="el-icon-edit" style="color: #409eff; font-size: 16px"></i>
</span>
</p>
</div>
<span
v-if="table.has_selected == 1"
@click="goToListComment(table.article_table_id, 'table')"
style="
text-align: center;
height: 20px;
padding: 2px 0;
line-height: 20px;
width: 60px;
z-index: 10;
border-radius: 4px;
background-color: #006699d1;
color: #ffff;
font-weight: bold;
position: absolute;
top: 45%;
left: calc((100% - 60px) / 2);
"
>{{ $t('commonTable.Typed') }}</span
>
<div
class="thumbnailBox image list-img"
:style="`
opacity:${table.has_selected == 1 ? '0.6' : '1'};
border: 1px solid #ccccccb5;
width: 100%;
height: auto;
border-radius: 4px;
overflow: hidden;
position: relative;`"
:draggable="table.has_selected == 0 ? true : false"
@dragstart="table.has_selected == 0 ? onDragStart($event, table, index, 'table') : ''"
>
<div style="width: 100%; height: 80px; display: flex; justify-content: center; align-items: center">
<!-- 图片内容 -->
<table
:data-table-id="table.article_table_id"
border="1"
style="
transform: scale(0.5);
width: 140px;
height: auto;
background-color: #fff;
border-collapse: collapse;
text-align: center;
"
>
<tr v-for="(row, rowIndex) in table.table" :key="rowIndex">
<td
v-for="(cell, cellIndex) in row"
:key="cellIndex"
:colspan="cell.colspan || 1"
:rowspan="cell.rowspan || 1"
>
<span v-html="cell.text"> </span>
</td>
</tr>
</table>
</div>
<!-- 输入框 -->
</div>
</div>
<el-collapse v-if="isShowEdit">
<el-collapse-item name="1" style="margin-top: 4px">
<template slot="title">
<div style="width: 100%; display: flex; align-items: center; justify-content: space-between">
<span style="color: #777">Tables {{ index + 1 }}</span>
<span v-if="isShowEdit"><i class="el-icon-edit" v-if="isEdit"></i>Comments/ Suggestions</span>
</div>
</template>
<el-input
v-if="isShowEdit"
type="textarea"
placeholder="please input content"
:readonly="!isEdit"
:rows="4"
></el-input>
</el-collapse-item>
</el-collapse>
<!-- <p
style="color: #777; margin-top: 6px"
v-else
@click="img.has_selected == 1 ? goToListComment(img.article_image_id, 'img') : ''"
>
<el-link> Figures {{ index + 1 }} </el-link>
</p> -->
</div>
</div>
</li>
<li v-show="currentMenu == 4">
<div style="display: flex; flex-wrap: wrap; gap: 10px; justify-content: start">
<div
v-for="(item, index) in content"
style="width: calc(100%); display: flex; align-items: center; justify-content: space-between; color: #606266"
>
<div
style="
width: calc(100% - 50px);
white-space: nowrap; /* 防止文本换行 */
overflow: hidden; /* 隐藏超出部分 */
text-overflow: ellipsis;
"
>
<p
v-html="index + 1 + '. ' + item.content"
style="font-size: 14px; width: 100%; overflow: hidden; line-height: 30px"
></p>
</div>
<img src="@/assets/img/huifu.png" style="width: 20px; height: 20px" alt="" @click="huifu(item.am_id)" />
</div>
</div>
</li>
</ul>
</div>
</div>
</template>
<script>
import { mediaUrl } from '@/common/js/commonJS.js'; // 引入通用逻辑
export default {
props: ['articleId', 'imgWidth', 'imgHeight', 'scale', 'isEdit', 'isShowEdit', 'urlList', 'content'],
data() {
return {
isShowComment: false,
isEditComment: false,
isEditing: null, // 用于跟踪当前正在编辑的批注索引
selectedComment: null, // 存储当前选择的批注内容
comments: [], // 存储所有批注
isFresh: false,
currentSelectType: '0',
currentMenu: 1,
mediaUrl,
statusList: [
{ title: 'ALL', type: '0' },
{ title: 'Typed', type: '1' },
{ title: 'Unfettered', type: '2' }
],
images: [],
tables: [],
imagesList: [],
tablesList: [],
tablesHtml: [],
imagesHtml: [],
activeNames: ['images', 'tables']
};
},
directives: {
// 注册一个局部的自定义指令 v-focus
focus: {
// 指令的定义
inserted: function (el) {
console.log('el at line 263:', el);
// 聚焦元素
el.querySelector('textarea').focus();
}
}
},
methods: {
isShowEditComment() {
if (localStorage.getItem('U_role')) {
var identity = localStorage.getItem('U_role');
if (identity.includes('editor')) {
this.isEditComment = true;
} else {
this.isEditComment = false;
}
}
},
changeComment() {
this.isShowComment = !this.isShowComment;
},
// 编辑评论,显示文本框
editComment(index) {
if (this.isEditComment) {
this.isEditing = index; // 设置当前正在编辑的评论索引
}
},
// 保存评论修改
saveComment(index,comment) {
if (this.isEditComment) {
this.$emit('addComment',comment)
this.isEditing = null; // 退出编辑模式
}
},
// 删除评论
deleteComment(comment, index) {
if (this.isShowComment) {
this.$confirm(this.$t('commonTable.removeAnnotations'), 'Prompt', {
confirmButtonText: 'Submit',
cancelButtonText: 'Cancel',
type: 'warning'
})
.then(() => {
this.comments.splice(index, 1); // 删除评论
})
.catch(() => {});
}
},
getTime(timestamp) {
// 创建一个新的 Date 对象
// 转换为 Date 对象(乘以 1000因为 JavaScript 使用毫秒)
const date = new Date(timestamp * 1000);
// 获取年、月、日、时、分、秒
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份是从 0 开始的,所以加 1
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
// 格式化为 年-月-日 时:分:秒
const formattedDate = `${year}-${month}-${day} ${hours}:${minutes}`;
console.log(formattedDate); // 输出: 2025-10-20 15:30:03
return formattedDate;
},
goToComment(mainId) {
this.$nextTick(() => {
this.$emit('goToComment', mainId);
});
},
getCommentList() {
this.$api
.post('api/Preaccept/getNotes', {
article_id: this.articleId
})
.then((res) => {
this.comments = res.data.list;
console.log('this.comments at line 537:', this.comments);
});
},
add(type) {
this.$emit('add', type);
},
edit(data, type) {
this.$emit('edit', data, type);
},
huifu(id) {
this.$emit('huifu', id);
},
handleSelectMenu(v) {
this.currentMenu = v;
this.currentSelectType = '0';
if (v == 1) {
this.getCommentList();
} else {
this.filterData();
}
},
selectType(v) {
this.currentSelectType = v.type;
this.filterData();
},
filterData(type) {
console.log('type at line 374:', type);
if (type) {
if (type == 'img') {
this.imagesList = [...this.images];
} else if (type == 'table') {
this.tablesList = [...this.tables];
}
} else {
if (this.currentMenu == 2) {
switch (this.currentSelectType) {
case '0':
this.imagesList = [...this.images];
break;
case '1':
this.imagesList = [...this.images].filter((e) => e.has_selected == 1);
break;
case '2':
this.imagesList = [...this.images].filter((e) => e.has_selected == 0);
break;
}
} else if (this.currentMenu == 3) {
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);
break;
case '2':
this.tablesList = [...this.tables].filter((e) => e.has_selected == 0);
break;
}
} else {
}
}
},
goToListComment(id, type) {
this.$emit('goToListComment', id, type);
},
async refresh(type) {
this.isFresh = false;
this.$nextTick(async () => {
if (type == 'img') {
await this.getWordimgList();
await this.filterData();
} else if (type == 'table') {
await this.getWordTablesList();
await this.filterData();
}
this.$forceUpdate();
this.isFresh = true;
this.$emit('loaded', this.images);
});
},
changeDataIsHidden(val, status, type) {
console.log('type at line 165:', type);
var index;
this.$nextTick(() => {
if (type == 'img') {
index = this.images.findIndex((element) => element.article_image_id === val.article_image_id);
console.log('index at line 170:', index);
this.images[index].isHidden = status;
} else {
index = this.tables.findIndex((element) => element.id === id);
this.tables[index].isHidden = status;
}
this.$forceUpdate();
});
},
changeIsHidden(index, status, type) {
console.log('type at line 165:', type);
this.$nextTick(() => {
if (type == 'img') {
this.images[index].isHidden = status;
} else {
this.tables[index].isHidden = status;
console.log('this.tables at line 169:', this.tables);
}
this.$forceUpdate();
});
},
onDragStart($event, item, index, type) {
console.log('type at line 192:', index);
this.$emit('onDragStart', $event, item, index, type);
},
changeActiveNames(e) {
console.log('e at line 156:', e);
if (['tables'].includes(e)) {
this.$nextTick(() => {
this.getWordTablesList();
});
}
if (['images'].includes(e)) {
this.$nextTick(() => {
this.getWordimgList();
});
}
},
openPreview(index, type) {
this.$nextTick(() => {
document.getElementById(type + '-modal-' + index).style.display = 'flex';
});
},
async getWordimgList() {
var that = this;
await this.$api
.post(this.urlList ? this.urlList.img : 'api/Article/getArticleImages', {
article_id: this.articleId
})
.then(async (res) => {
var list = [...res.data.list];
if (this.urlList) {
list = list.map((e) => {
return {
...e,
image: e.url,
article_image_id: e.ami_id
};
});
} else {
list = res.data.list;
}
if (list.length > 0) {
list.forEach((img, index) => {
var extension = img.image.split('.').pop().toLowerCase();
if (extension === 'tif' || extension === 'jpg' || extension === 'jpeg' || extension === 'png') {
const modalContent = ['jpg', 'jpeg', 'png'].includes(extension)
? `<img src="${this.mediaUrl + img.image}" alt="Image ${index}" style="width:100%;" >`
: `<canvas id="tiff-canvas-modal-${index}" ></canvas>`;
this.$commonJS.createImageModal(index, modalContent, 'img');
}
if (extension === 'tif') {
this.$nextTick(() => {
this.$commonJS.renderTiffImage(
this.mediaUrl + img.image,
`tiff-canvas-modal-${index}`,
function (url) {
list[index].dataUrl = url;
},
index,
true
);
});
}
});
}
this.images = list;
this.$emit('loaded', this.images);
});
},
async getWordTablesList(callback) {
this.$api
.post(this.urlList ? this.urlList.table : 'api/Article/getArticleTable', {
article_id: this.articleId
})
.then(async (res) => {
if (this.urlList) {
this.tables =
res.data.list && res.data.list.length > 0
? res.data.list.map((e) => {
return {
...e,
article_table_id: e.amt_id,
table: JSON.parse(e.table_data)
};
})
: [];
} else {
this.tables =
res.data.list && res.data.list.length > 0
? res.data.list.map((e) => {
return {
...e,
table: JSON.parse(e.table)
};
})
: [];
}
await this.filterData('table');
if (this.tables.length > 0) {
this.tables.forEach((table, index) => {
var modalContent = `
<div class="wordTableHtml" style="background:#FFF;padding:20px">
<table
border="1"
style="
border-collapse: collapse;
width: 100%;
text-align: center;
table-layout: auto;"
>`;
table.table.forEach((row) => {
modalContent += `<tr>`;
row.forEach((cell) => {
modalContent += `
<td
colspan="${cell.colspan || 1}"
rowspan="${cell.rowspan || 1}"
style=""
>
<span>${cell.text}</span>
</td>`;
});
modalContent += `</tr>`;
});
modalContent += `</table></div>`;
this.$commonJS.createImageModal(index, modalContent, 'table', '');
});
}
console.log('this.tables at line 533:', this.tables);
});
}
},
async created() {
this.isShowEditComment();
this.isFresh = false;
this.$nextTick(async () => {
await this.getCommentList();
await this.getWordimgList();
await this.getWordTablesList();
await this.filterData();
this.isFresh = true;
});
},
async activated() {
this.isFresh = false;
this.isShowEditComment();
this.$nextTick(async () => {
await this.getWordimgList();
await this.getWordTablesList();
await this.filterData();
this.isFresh = true;
});
},
mounted() {}
};
</script>
<style scoped>
.ManuscirptList {
background-color: none !important;
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0);
color: #333639;
}
.ManuscirptList div {
cursor: pointer;
background-color: none !important;
}
::v-deep .wordTableHtml table {
cursor: pointer;
background-color: #fff !important;
}
.el-menu-vertical-demo {
width: 85px;
}
.el-menu-vertical-demo li {
display: flex;
flex-direction: column;
padding: 10px 6px !important;
font-size: 14px !important;
text-align: center;
}
::v-deep .el-menu-vertical-demo.el-menu-item:focus,
.el-menu-item:hover {
background-color: #f8f8f9 !important;
}
::v-deep .el-menu-item.is-active {
background-color: #2196f32e !important;
}
.isSelectType {
background-color: #2196f32e !important;
color: #006699;
}
li {
list-style: none;
}
.item_box {
background-color: #f2f3f5;
border: 1px solid rgba(0, 0, 0, 0);
border-radius: 6px;
overflow: hidden;
}
.go-transition .title {
background-color: #e5e6eb;
color: #767c82;
font-size: 13px;
padding: 2px 10px;
display: flex;
align-items: center;
justify-content: space-between;
}
.go-transition .list-img {
padding: 6px 0;
background-color: #f2f3f5;
box-sizing: border-box;
}
.go-transition .list-img :hover {
transition: all 0.4s;
}
.go-content-charts-item-box {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: 9px;
transition: all 0.7s linear;
}
.arrlist::-webkit-scrollbar-thumb {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0);
min-height: 12px;
border: 4px solid transparent;
background-clip: content-box;
border-radius: 7px;
background-color: #c8d5e1;
}
.badge {
background-color: #f56c6c;
border-radius: 10px;
color: #fff;
display: inline-block;
font-size: 12px;
height: 18px;
line-height: 18px;
padding: 0 6px;
text-align: center;
white-space: nowrap;
border: 1px solid #fff;
position: absolute;
}
.comments-section {
padding: 10px;
box-sizing: border-box;
border: 1px solid #cecfd3;
border-left: 2px solid #cecfd3;
/* border-radius: 5px; */
background-color: #f9f9f9;
box-shadow: rgba(16, 17, 19, 0.06) 0px 1px 3px;
width: 300px;
background-color: #fafafa;
float: right;
position: absolute;
right: -302px;
top: 0px;
z-index: 999;
}
.comment-item {
padding: 5px 0;
border-bottom: 1px solid #ddd;
cursor: pointer;
box-sizing: border-box;
font-size: 14px;
}
.comment-item:last-child {
border-bottom: none;
}
.comment-details {
margin-top: 20px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
background-color: #f9f9f9;
}
.comment-details h3 {
margin-bottom: 10px;
}
.comment-details p {
margin-bottom: 10px;
}
.comment-details button {
padding: 5px 10px;
background-color: #007bff;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
.comment-details button:hover {
background-color: #0056b3;
}
.comments-section ul,
.comments-section li {
list-style: none;
margin: 0;
padding: 0;
}
::v-deep.pizhu.el-link--default:hover {
border-color: #fc625d !important;
}
</style>

View File

@@ -0,0 +1,317 @@
<template>
<div style="background-color: transparent !important" class="ManuscirptList" v-show="tables.length > 0 || images.length > 0">
<!-- 图片缩略图区域 -->
<el-collapse v-model="activeNames" @change="changeActiveNames"
><el-collapse-item name="images" style="" v-if="images.length > 0">
<template slot="title">
<p style="font-weight: bold; color: #222 !important">Manuscirpt Figures ( {{ images.length }} )</p>
<!-- <p style="margin-left: 20px">
<i class="header-icon el-icon-info"></i
><span style="margin-left: 5px; color: rgb(153, 153, 153)">Click to open the Figures</span>
</p> -->
</template>
<!-- <p style="margin-bottom: 15px;color: rgb(153, 153, 153);line-height: 16px;"> If you have any questions that need to be addressed to the author, you can leave valuable comments or suggestions below the Figures</p> -->
<div style="display: flex; flex-wrap: wrap; gap: 10px; justify-content: start">
<div v-for="(img, index) in images" style="width: 30%" :key="index">
<div
class="thumbnailBox image"
:style="`
opacity:${img.isHidden ? '0.3' : '1'};
border: 1px solid #ccccccb5;
width: 100%;
height: ${imgHeight ? imgHeight : '200px'};
border-radius: 4px;
overflow: hidden;
position: relative;`"
:draggable="!img.isHidden ? true : false"
@dragstart="!img.isHidden ? onDragStart($event, img, index, 'img') : ''"
>
<div style="width: 100%; height: 100%; display: flex; justify-content: center; align-items: center">
<!-- 图片内容 -->
<template v-if="['jpg', 'jpeg', 'png'].includes(img.image.split('.').pop().toLowerCase())">
<img :data-img-id="img.ami_id" @click="openPreview(index, 'img')" :src="mediaUrl + img.image" style="width: 100%; height: auto" />
</template>
<template v-else-if="img.image.split('.').pop().toLowerCase() === 'tif'">
<canvas
@click="openPreview(index, 'img')"
:id="`tiff-canvas-${index}`"
:data-img-id="img.article_image_id"
style="width: 100%; height: auto"
></canvas>
</template>
<template v-else>
<a :href="mediaUrl+ img.image" style="color: #75abf1">
<div
style="
text-align: center;
font-size: 40px;
display: flex;
align-items: center;
justify-content: center;
"
>
{{ img.image.split('.').pop().toUpperCase() }}
<i class="el-icon-download" style="margin-left: 10px; color: #75abf1"></i>
</div>
</a>
</template>
</div>
<!-- 输入框 -->
</div>
<el-collapse v-if="isShowEdit">
<el-collapse-item name="1" style="margin-top: 4px">
<template slot="title">
<div style="width: 100%; display: flex; align-items: center; justify-content: space-between">
<span style="color: #777">Tables {{ index + 1 }}</span>
<span v-if="isShowEdit"><i class="el-icon-edit" v-if="isEdit"></i>Comments/ Suggestions</span>
</div>
</template>
<el-input
v-if="isShowEdit"
type="textarea"
placeholder="please input content"
:readonly="!isEdit"
:rows="4"
></el-input>
</el-collapse-item>
</el-collapse>
<p style="color: #777; margin-top: 6px" v-else>Figures {{ index + 1 }}</p>
</div>
</div>
</el-collapse-item>
<el-collapse-item name="tables" style="" v-if="tables.length > 0">
<template slot="title">
<p style="font-weight: bold; color: #222">Manuscirpt Tables ( {{ tables.length }} )</p>
<!-- <p style="margin-left: 20px">
<i class="header-icon el-icon-info"></i
><span style="margin-left: 5px; color: rgb(153, 153, 153)">Click to open the Tables</span>
</p> -->
</template>
<!-- <p style="margin-bottom: 15px;color: rgb(153, 153, 153);line-height: 16px;"> If you have any questions that need to be addressed to the author, you can leave valuable comments or suggestions below the Table</p> -->
<!-- 表格缩略图区域 -->
<div style="display: flex; flex-wrap: wrap; gap: 10px; justify-content: start; margin-top: 20px">
<div v-for="(table, index) in tables" style="width: 48%" :key="index">
<div
class="thumbnailTableBox wordTableHtml tables"
:style="`
opacity:${table.isHidden ? '0.3' : '1'};
border: 1px solid #ccccccb5;
width: 100%;
height: ${imgHeight ? imgHeight : '200px'};
border-radius: 4px;
overflow: hidden;
position: relative;`"
@click="openPreview(index, 'table')"
:draggable="!table.isHidden ? true : false"
@dragstart="!table.isHidden ? onDragStart($event, table, index, 'table') : ''"
>
<table border="1" style="width: auto; border-collapse: collapse; text-align: center; ">
<tr v-for="(row, rowIndex) in table" :key="rowIndex">
<td
v-for="(cell, cellIndex) in row"
:key="cellIndex"
:colspan="cell.colspan || 1"
:rowspan="cell.rowspan || 1"
>
<span v-html="cell.text"> </span>
</td>
</tr>
</table>
</div>
<el-collapse v-if="isShowEdit">
<el-collapse-item name="1" style="margin-top: 4px">
<template slot="title">
<div style="width: 100%; display: flex; align-items: center; justify-content: space-between">
<span style="color: #777">Tables {{ index + 1 }}</span>
<span v-if="isShowEdit"><i class="el-icon-edit" v-if="isEdit"></i>Comments/ Suggestions</span>
</div>
</template>
<el-input
v-if="isShowEdit"
type="textarea"
placeholder="please input content"
:readonly="!isEdit"
:rows="4"
></el-input>
</el-collapse-item>
</el-collapse>
<p style="color: #777; margin-top: 6px" v-else>Table {{ index + 1 }}</p>
</div>
</div>
</el-collapse-item>
</el-collapse>
</div>
</template>
<script>
import { mediaUrl } from '@/common/js/commonJS.js'; // 引入通用逻辑
export default {
props: ['articleId', 'imgWidth', 'imgHeight', 'scale', 'isEdit', 'isShowEdit','urlList'],
data() {
return {
mediaUrl,
tables: [],
images: [],
tablesHtml: [],
imagesHtml: [],
activeNames: ['images', 'tables']
};
},
methods: {
changeDataIsHidden(val, status, type) {
console.log('type at line 165:', type);
var index;
this.$nextTick(() => {
if (type == 'img') {
index= this.images.findIndex((element) => element.article_image_id === val.article_image_id)
console.log('index at line 170:', index)
this.images[index] .isHidden = status;
} else {
index= this.tables.findIndex((element) => element.id === id)
this.tables[index] .isHidden = status;
}
this.$forceUpdate();
});
},
changeIsHidden(index, status, type) {
console.log('type at line 165:', type);
this.$nextTick(() => {
if (type == 'img') {
this.images[index].isHidden = status;
} else {
this.tables[index].isHidden = status;
console.log('this.tables at line 169:', this.tables);
}
this.$forceUpdate();
});
},
onDragStart($event, item, index, type) {
console.log('type at line 192:', index)
this.$emit('onDragStart', $event, item, index, type);
},
changeActiveNames(e) {
console.log('e at line 156:', e);
if (['tables'].includes(e)) {
this.$nextTick(() => {
this.getWordTablesList();
});
}
if (['images'].includes(e)) {
this.$nextTick(() => {
this.getWordimgList();
});
}
},
openPreview(index, type) {
this.$nextTick(() => {
document.getElementById(type + '-modal-' + index).style.display = 'flex';
});
},
async getWordimgList() {
await this.$api
.post(this.urlList?this.urlList.img:'api/Article/getArticleImages', {
article_id: this.articleId
})
.then(async (res) => {
this.images = res.data.list;
if (this.images.length > 0) {
this.images.forEach((img, index) => {
var extension = img.image.split('.').pop().toLowerCase();
if (extension === 'tif' || extension === 'jpg' || extension === 'jpeg' || extension === 'png') {
const modalContent = ['jpg', 'jpeg', 'png'].includes(extension)
? `<img src="${this.mediaUrl + img.image}" alt="Image ${index}" style="width:100%;" >`
: `<canvas id="tiff-canvas-modal-${index}" ></canvas>`;
this.$commonJS.createImageModal(index, modalContent, 'img');
}
if (extension === 'tif') {
this.$nextTick(() => {
this.$commonJS.renderTiffImage(mediaUrl + img.image, `tiff-canvas-modal-${index}`, index, true);
const targetWidth = this.imgWidth || document.getElementsByClassName('thumbnailBox')[0].offsetWidth;
const targetHeight = this.imgHeight || document.getElementsByClassName('thumbnailBox')[0].offsetHeight;
this.$commonJS.renderTiffImage(
mediaUrl + img.image,
`tiff-canvas-${index}`,
index,
true,
targetWidth,
targetHeight
);
});
}
});
}
});
},
getWordTablesList() {
this.$api
.post(this.urlList?this.urlList.table:'api/Article/getArticleTable', {
article_id: this.articleId
})
.then((res) => {
this.tables = res.data.list && res.data.list.length > 0 ? JSON.parse(res.data.list[0].table) : [];
if (this.tables.length > 0) {
this.tables.forEach((table, index) => {
var modalContent = `
<div class="wordTableHtml" style="background:#FFF;padding:20px">
<table
border="1"
style="
border-collapse: collapse;
width: 100%;
text-align: center;
table-layout: auto;"
>`;
table.forEach((row) => {
modalContent += `<tr>`;
row.forEach((cell) => {
modalContent += `
<td
colspan="${cell.colspan || 1}"
rowspan="${cell.rowspan || 1}"
style=""
>
<span>${cell.text}</span>
</td>`;
});
modalContent += `</tr>`;
});
modalContent += `</table></div>`;
this.$commonJS.createImageModal(index, modalContent, 'table', '');
});
}
});
}
},
mounted() {
this.$nextTick(() => {
this.getWordimgList();
this.getWordTablesList();
});
}
};
</script>
<style scoped>
.ManuscirptList {
background-color: none !important;
}
.ManuscirptList div {
cursor: pointer;
background-color: none !important;
}
::v-deep .wordTableHtml table {
cursor: pointer;
background-color: #fff !important;
}
</style>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -310,6 +310,9 @@
v-model="questionform.comment"
:rows="8"
></el-input>
</el-form-item> <el-form-item label="" v-if="articleId">
<common-word-html :articleId="articleId" style="box-sizing: border-box"
></common-word-html>
</el-form-item>
<el-form-item
label="Comments for the Authors"
@@ -323,6 +326,7 @@
:rows="8"
></el-input>
</el-form-item>
<el-form-item label="Confidential Comments to the Editor">
<el-input
type="textarea"
@@ -331,6 +335,7 @@
:rows="8"
></el-input>
</el-form-item>
<el-form-item label="Please choose disclose your name or remain anonymous">
<el-radio-group v-model="questionform.is_anonymous" style="line-height: 30px">
<el-radio :label="0">Disclose name</el-radio>
@@ -363,6 +368,7 @@ export default {
data() {
return {
loading: false,
articleId: null,
Direct_log: this.$route.query.act,
Art_id: this.$route.query.Art_id,
// morShow: false,
@@ -488,6 +494,7 @@ export default {
human: 'reviewer'
})
.then((res) => {
this.articleId=res.article_id
if (res.state != 0) {
this.btn_submit = 1;
}
@@ -532,12 +539,12 @@ export default {
if (pdfOut.substring(pdfOut.lastIndexOf('.') + 1) == 'docx') {
this.pdfUrl =
'https://view.officeapps.live.com/op/view.aspx?src=https://submission.tmrjournals.com/public/' + pdfOut;
'https://view.officeapps.live.com/op/view.aspx?src=https://submission.tmrjournals.com/public/' + pdfOut+`&ui=en-US`;
// this.pdfUrl =
// 'https://view.xdocin.com/view?src=https://submission.tmrjournals.com/public/' +
// pdfOut
} else {
this.pdfUrl = 'https://submission.tmrjournals.com/public/' + pdfOut;
this.pdfUrl = 'https://submission.tmrjournals.com/public/' + pdfOut+`&ui=en-US`;
}
})
.catch((err) => {

View File

@@ -73,6 +73,20 @@ Vue.component("Editor", Editor);
import commonTable from '@/components/page/components/table/table.vue'
Vue.component('common-table', commonTable);
import commonTiff from '@/components/page/components/table/tiff.vue'
Vue.component('common-tiff', commonTiff);
import commonContent from '@/components/page/components/table/content.vue'
Vue.component('common-content', commonContent);
import commonWord from '@/components/page/components/table/word.vue'
Vue.component('common-word', commonWord);
import commonAnnotations from '@/components/page/components/table/annotations.vue'
Vue.component('common-annotations', commonAnnotations);
import commonWordHtml from '@/components/page/components/table/wordHtml.vue'
Vue.component('common-word-html', commonWordHtml);
import commonWordHtmlTypesetting from '@/components/page/components/table/wordHtmlTypesetting.vue'
Vue.component('common-word-html-type-setting', commonWordHtmlTypesetting);
import commonDragWord from '@/components/page/components/table/dragWord.vue'
Vue.component('common-drag-word', commonDragWord);
Vue.use(VueI18n);

View File

@@ -946,7 +946,7 @@ export default new Router({
path: '/GenerateCharts', //用户端预收录-引用编辑
component: () => import('../components/page/GenerateCharts'),
meta: {
title: 'Generate Charts'
title: 'HTML Proofread'
}
},
{