Compare commits

2 Commits

Author SHA1 Message Date
8fc0325f35 提交 2025-11-19 15:55:48 +08:00
9fd6b73850 文章详情 Reviewer detail 打开弹窗 2025-11-19 15:05:07 +08:00
9 changed files with 297 additions and 217 deletions

View File

@@ -5,7 +5,7 @@ import qs from 'qs'
// axios全局配置
axios.defaults.timeout = 1000 * 6 * 2; // 超时时间
axios.defaults.timeout = 1000 * 6 * 10 * 3; // 超时时间
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'; // 配置请求头

View File

@@ -29,7 +29,7 @@ a {
position: absolute;
left: 260px;
right: 0;
top: 40px;
top: 60px;
bottom: 0;
padding-bottom: 30px;
-webkit-transition: left .3s ease-in-out;

View File

@@ -9,6 +9,10 @@ const baseUrl = '/';
// // const mediaUrl = 'http://zmzm.tougao.dev.com/public/';
// const baseUrl = '/api'
// const mediaUrl = 'http://tougaotest.tmrjournals.com/public/';
// // const mediaUrl = 'http://zmzm.tougao.dev.com/public/';
// const baseUrl = '/api'
//本地(正式环境 )
// const mediaUrl = 'https://submission.tmrjournals.com/public/';

View File

@@ -656,7 +656,13 @@
<td class="review_table_index">
Reviewer {{ reviewerIndex + 1 }}
<el-button
style="margin-left: 10px"
type="text"
@click="crateRevision(iken)"
v-if="iken.can_repeat == 1"
>Re-review</el-button
>
</td>
<td style="position: relative; cursor: pointer">
@@ -672,13 +678,14 @@
>( {{ iken.rated }} )</span
>
<span v-if="iken.state != 0"
style="color: #006699;float: right;"
style="color: #888;float: right;margin-right: 20px;"
@click="handleClick(iken,'detail')"
>Detail</span
>
</td>
<!-- 1st review原逻辑不变 -->
<td @click="handleClick(iken,'question')" style="cursor: pointer">
<td style="cursor: pointer">
<span >
<span style="display: inline-block; margin-left: 4px; margin-right: 8px">
<font
v-if="iken.recommend == 1 || iken.recommend == 2"
@@ -718,10 +725,20 @@
<span v-else-if="iken.recommend == 2">Major</span>
<span v-else-if="iken.recommend == 3">reject and resubmission</span>
<span v-else-if="iken.recommend == 4">Reject</span>
</span>
<span v-if="iken.state != 0"
style="color: #888;float: right;margin-right: 20px;"
@click="handleClick(iken,'question')"
>Detail</span
>
</td>
<!-- 关键按最大重复次数遍历而非仅遍历当前iken.repeat -->
<template v-for="(_1, index1) in maxRepeatReviewCount()">
<td>
<td >
<!-- 补全逻辑判断当前评审者的repeat中是否有第index1条数据 -->
<span
v-if="Array.isArray(iken.repeat) && iken.repeat[index1]"
@@ -768,6 +785,12 @@
<span v-else-if="iken.repeat[index1].recommend == 2">Reject</span>
<span v-else-if="iken.repeat[index1].recommend == 3">Revision</span>
<span v-else>No reply</span>
<span v-if="[1,2,3].includes(iken.repeat[index1].recommend)"
style="color: #888;float: right;margin-right: 20px;"
@click="handleClick(iken,'re-review',iken.repeat[index1])"
>Detail</span
>
</span>
<span v-else>
<!-- 无数据:补全空内容(可自定义为“-”“无”等) -->
@@ -843,8 +866,8 @@
<span style="">{{ iken.realname }}</span>
<span
style="color: #006699; float: right;"
<span v-if="[1,2,3].includes(iken.state)"
style="color: #888; float: right;"
@click="handleClickFinal(iken)"
>Detail</span
>
@@ -1726,7 +1749,31 @@ export default {
}
},
methods: {
crateRevision(item) {
// 二次询问
this.$confirm('Do you want to send a review invitation?', 'Tip', {
type: 'warning'
})
.then(() => {
this.$api
.post('api/Reviewer/startRepeatReviewer', {
art_rev_id: item.art_rev_id
})
.then((res) => {
//console.log(res)
if (res.code == 0) {
this.$message.success('A review invitation was successfully sent!');
this.getFinalList()
} else {
this.$message.error(res.msg);
}
})
.catch((err) => {
console.log(err);
});
})
.catch(() => {});
},
handleClickFinal(data) {
this.finalDecisionData={...data}
@@ -1900,12 +1947,12 @@ this.FinalDecisionVisible=true
// console.log('maxItem at line 2142:', maxItem.repeat.length)
return maxItem && maxItem.repeat ? maxItem.repeat.length : 0;
},
handleClick(item,type) {
handleClick(item,type,repeatItem) {
this.reviewerDetail=item
this.reviewerVisible=true
this.$nextTick(()=>{
this.$refs.reviewerDetail.init(item.art_rev_id,type)
this.$refs.reviewerDetail.init(item.art_rev_id,type,repeatItem)
})
@@ -1932,14 +1979,7 @@ this.FinalDecisionVisible=true
this.finalList = [...res.data.final_review];
this.reviewList = res.data.review;
if(this.finalList.length > 0) {
console.log('this.finalList.length at line 1829:', this.finalList.map(item => item.id))
// this.$api
// .post('api/Workbench/updateArticleState', {
// article_id: this.editform.articleId,
// act_id: this.finalList.map(item => item.id),
// type: '3',
// account: localStorage.getItem('U_name')
// })
}
}
}
@@ -2858,7 +2898,7 @@ this.FinalDecisionVisible=true
}
.art_author_ {
padding: 20px 0;
padding: 15px 20px !important;
}
.art_author_ > h2 {

View File

@@ -879,6 +879,16 @@
<p v-if="currentArticleData" class="reviewer-decision-title">
{{ currentArticleData.title }}
</p>
<!-- <div v-if="currentArticleData&&currentArticleData.state!=0" style="overflow: hidden;">
<span style="float: right;">
<b @click.stop="articleReviewer()" class="btnCliArt" style="" >
<i :class="[1,2,4,8].includes(currentArticleData.state) ? 'el-icon-edit' : 'el-icon-view'" style="margin-right: 5px;"></i>Inviting Reviewer {{ [1,2,4,8].includes(currentArticleData.state) ? '' : 'History' }}
</b>
</span>
</div> -->
<div class="art_author_" style="padding: 0;" v-if="reviewList.length > 0">
<div class="fixCard reviewer_decision" style="position: relative">
@@ -921,13 +931,13 @@
>( {{ iken.rated }} )</span
>
<span v-if="iken.state != 0"
style="color: #006699;float: right;"
style="color: #006699;float: right;margin-top: 2px"
@click="handleClick(iken)"
>Detail</span
>
</td>
<!-- 1st review原逻辑不变 -->
<td @click="handleClick(iken)" style="cursor: pointer">
<td style="cursor: pointer">
<span style="display: inline-block; margin-left: 4px; margin-right: 8px">
<font
v-if="iken.recommend == 1 || iken.recommend == 2"
@@ -1032,10 +1042,17 @@
</div>
</div>
</div>
<span style="font-size: 20px; margin-top: 20px; margin-right: 10px; text-align: right; float: right; font-weight: 400">
<div v-if="currentArticleData&&currentArticleData.state!=0" style="overflow: hidden;">
<span style="float: right;">
<span style="font-size: 14px; margin-top: 10px; margin-right: 10px; text-align: right; font-weight: 400">
Average score : <b style="font-size: 18px; color: #db890e">{{ avegeCount(reviewList) }}</b>
</span>
</span>
</div>
</div>
<span slot="footer" class="dialog-footer">
@@ -2033,13 +2050,16 @@ export default {
this.$forceUpdate();
},
//文章送审
articleReviewer(row) {
this.$router.push({
path: 'articleReviewer',
articleReviewer() {
const routeData = this.$router.resolve({
path: 'articleReviewer', // 原路由路径
query: {
id: row.article_id
id: this.currentArticleData.article_id // 原查询参数
}
});
// 新开窗口跳转(第二个参数 '_blank' 表示新窗口)
window.open(routeData.href, '_blank');
},
articleEditorialBoard(row) {
this.$router.push({

View File

@@ -116,8 +116,8 @@
</div> -->
<!-- 对话列表 -->
<div class="kuang_communtion">
<h2>Communication</h2>
<div class="kuang_communtion" >
<h2 >Communication</h2>
<div v-for="item in talkMsgs" class="kuang_communtion_conmt">
<div v-if="item.user_id != artMes.user_id" class="talk_aued">
<p>Editor :</p>

View File

@@ -26,6 +26,7 @@
<el-form-item label="Disclose name or anonymous" label-width="200px">
<span v-if="reviewList.length > 0&&reviewList[0].is_anonymous == 0">Disclose name</span>
<span v-if="reviewList.length > 0&&reviewList[0].is_anonymous == 1">Remain anonymous</span>
<span v-if="reviewList.length== 0">-</span>
</el-form-item>
<!-- <el-form-item label="Status">
<span>{{ mystate(detailDate.state) }}</span>
@@ -1246,6 +1247,8 @@ console.log('at line 1094:', this.reviewList)
this.questionform.comment = res.data.comments;
this.questionform.is_anonymous = res.data.is_anonymous;
this.questionform.type= res.data.type;this.questionform.score = res.data.score;
}else{
}
});
},

View File

@@ -1,14 +1,28 @@
<template>
<el-dialog :title="type=='detail'?'Manuscript reviewer detail':'Feedback questionnaire'" :visible.sync="reviewerVisible" width="1200px" :close-on-click-modal="false">
<el-dialog title="" :visible.sync="reviewerVisible" width="1200px" :close-on-click-modal="false">
<template slot="title" >
<div class="dialog-title">
<p v-if="type=='detail'">Manuscript reviewer detail</p>
<p v-else>Feedback questionnaire
<span style="margin-top: -3px;"> <span v-if="time" class="time">Time{{ formatDate(time) }}</span>
<span v-if="stime" class="time">Response time {{ formatDate(stime) }}</span></span>
</p>
</div>
</template>
<div>
<div class="container" v-if="type=='detail'">
<div class="" v-if="type=='detail'">
<el-row :gutter="10">
<el-col :span="20">
<el-col :span="24">
<div class="form-box" style="width: 100%">
<el-form ref="articleform" :model="detailDate" label-width="130px">
<el-form-item label="Article">
<span>{{ detailDate.article }}</span>
<el-form ref="articleform" :model="detailDate" label-width="140px">
<el-form-item label="Title">
<span style="font-weight: bold;color: #333;">{{ detailDate.article }}</span>
</el-form-item>
<el-form-item label="Reviewer">
<span>{{ detailDate.reviewer }}</span>
@@ -20,8 +34,8 @@
<span>{{ formatDate(detailDate.ctime) }}</span>
</el-form-item>
<el-form-item label="Disclose name or anonymous" label-width="200px">
<span v-if="reviewList.length > 0 && reviewList[0].is_anonymous == 0">Disclose name</span>
<span v-if="reviewList.length > 0 && reviewList[0].is_anonymous == 1">Remain anonymous</span>
<span v-if="detailDate.is_anonymous == 0">Disclose name</span>
<span v-if="detailDate.is_anonymous == 1">Remain anonymous</span>
</el-form-item>
<el-form-item v-if="canRepeat == 1">
@@ -30,60 +44,7 @@
</el-form>
</div>
</el-col>
<el-col :span="8" v-if="recordList && recordList.length > 0">
<div class="clearfix fsheader">
<h4>Peer-review Archive</h4>
</div>
<div class="time">
<el-timeline>
<el-timeline-item
reverse="true"
:timestamp="item.ctime | formatDatehms"
placement="top"
v-for="(item, index) in recordList"
:key="index"
>
<el-card>
<h4></h4>
<div>
<div v-if="index == recordList.length - 1">
<!-- 初审 -->
<el-tag>Under review</el-tag>
<p style="margin-top: 10px">
Comments:
<el-button
style="margin-left: 10px"
type="text"
@click="showUnderReview(item)"
icon="el-icon-view"
>Details</el-button
>
</p>
</div>
<div v-else>
<!-- 复审 -->
<el-tag type="success">Second review</el-tag>
<p style="margin-top: 10px">
Comments:
<el-button
style="margin-left: 10px"
type="text"
@click="showSecondReview(item)"
icon="el-icon-view"
>Details</el-button
>
</p>
<p v-if="item.stime > 0" style="" class="stime">
Response time: {{ item.stime | formatDatehms }}
</p>
<p v-else style="" class="stime">Response time: Re-reviewing...</p>
</div>
</div>
</el-card>
</el-timeline-item>
</el-timeline>
</div>
</el-col>
</el-row>
</div>
<common-review-article v-if="type=='question'"
@@ -96,8 +57,7 @@
:journal_id="journal_id"
></common-review-article>
<!-- <el-dialog title="Second review questionnaire" :visible.sync="FdialogFormVisible" width="900px" @close="closeSecDia" :close-on-click-modal="false"> -->
<el-form :model="ReReviewQuestion" ref="question" label-width="300px" label-position="top">
<el-form :model="ReReviewQuestion" ref="question" label-width="300px" label-position="top" v-if="type=='re-review'">
<el-divider content-position="center">REFEREE'S RECOMMENDATIONS</el-divider>
<el-form-item label="REFEREE'S RECOMMENDATIONS" prop="recommend">
<el-radio-group v-model="ReReviewQuestion.recommend" style="line-height: 30px">
@@ -158,7 +118,10 @@ export default {
questionform: { },
canRepeat: null,
undeQuestion: {},
ReReviewQuestion: {}
ReReviewQuestion: {},
repeatItem: {},
time:"",//审稿时间
stime:"",//复审回复时间
};
},
created: function () {
@@ -167,8 +130,12 @@ export default {
computed: {},
methods: {
init(art_rev_id,type) {
init(art_rev_id,type,repeatItem) {
this.time="";
this.stime="";
this.type=type;
this.repeatItem=repeatItem
if (art_rev_id) {
this.dateId = art_rev_id;
this.detailDate = {
@@ -187,9 +154,13 @@ export default {
}
if(type=='question'){
this. questionform={}
this.initquesion();
}
if(type=='re-review'){
this. ReReviewQuestion={}
this.initReReviewQuestion();
}
this.$api
.post('api/Workbench/updateArticleState', {
article_id: this.articleId,
@@ -349,24 +320,60 @@ export default {
background: 'rgba(0, 0, 0, 0.7)'
});
this.$api
.post('api/Reviewer/getartrevdate', {
revid: this.dateId,
human: 'editor'
.post('api/Workbench/getArticleReviewDetail', {
article_id:this.$route.query.id,
art_rev_id:this.dateId ,
account: localStorage.getItem('U_name')
})
.then((res) => {
this.detailDate.artrevid = res.art_rev_id;
this.detailDate.article = res.article_title;
this.detailDate.reviewer = res.account;
this.detailDate.reviewer_email = res.user_email;
this.detailDate.ctime = res.ctime;
this.detailDate.state = res.state;
if(res.status == 1){
this.detailDate.artrevid = res.data.article_reviewer.art_rev_id;
this.detailDate.article = res.data.article.title;
this.detailDate.reviewer = res.data.article_reviewer.realname;
this.detailDate.reviewer_email = res.data.article_reviewer.email;
this.detailDate.ctime = res.data.article_reviewer.ctime;
this.detailDate.is_anonymous = res.data.article_reviewer.is_anonymous;
this.txt_mess = res;
this.canRepeat = res.can_repeat;
this.journal_id = res.journal_id;
this.articleId = res.article_id;
this.articleId = res.data.article.article_id;
loading.close();
this.reviewerVisible = true;
}else{
loading.close();
this.$message.error(res.msg);
return false;
}
})
.catch((err) => {
loading.close();
console.log(err);
});
},
initReReviewQuestion() {
console.log('this.repeatItem at line 335:', this.repeatItem)
const loading = this.$loading({
lock: true,
text: 'Loading...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
this.$api.post('api/Workbench/getArticleReviewDetail', {
article_id:this.$route.query.id,
art_rev_id:this.dateId,
art_rev_rep_id:this.repeatItem.art_rev_rep_id,
account: localStorage.getItem('U_name')
})
.then((res) => {
if(res.status==1){
this.time=res.data.article_reviewer_repeat.ctime;
this.stime=res.data.article_reviewer_repeat.stime;
this.ReReviewQuestion = res.data.article_reviewer_repeat;
loading.close();
this.reviewerVisible = true;
}
})
.catch((err) => {
loading.close();
@@ -388,6 +395,7 @@ export default {
})
.then((res) => {
if (res.code == 0) {
this.time=res.data.ctime;
this.showUnderReview(res.data)
this.reviewerVisible = true;
loading.close();
@@ -548,4 +556,24 @@ td {
.overflow-x-auto {
overflow-x: auto;
}
.dialog-title {
width: 100%;
line-height: 24px;
font-size: 18px;
color: #303133;
}
.dialog-title p{
width:calc(100% - 30px);
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.time{
color: #888;line-height: 20px;
font-size: 14px;
margin-left: 20px;
display: inline-block
}
</style>

View File

@@ -1,41 +1,33 @@
<!--对话模块-->
<template>
<div class="kuang_communtion" v-loading="loading">
<h2>
Communication
</h2>
<div :style="{'max-height': height+'px'}" style="overflow: auto;">
<h2 :style="{ 'margin-bottom': talkMsgs && talkMsgs.length > 0 ? '15px' : '0' }">Communication</h2>
<div :style="{ 'max-height': height + 'px' }" style="overflow: auto">
<div v-for="(item, index) in talkMsgs" class="kuang_communtion_conmt">
<div v-if="item.user_id == msgform.user_id" class="talk_aued">
<p>
Author :
</p>
<el-card>Dear Editor,
<p style="white-space: pre-wrap;">{{item.ad_content}}</p>
<p>Author :</p>
<el-card
>Dear Editor,
<p style="white-space: pre-wrap">{{ item.ad_content }}</p>
</el-card>
<b>{{formatDate(item.ad_ctime)}}</b>
<b>{{ formatDate(item.ad_ctime) }}</b>
</div>
<div v-if="item.user_id != msgform.user_id" class="talk_aued talk_edit">
<p>
Editor :
</p>
<p>Editor :</p>
<el-card>
<p style="white-space: pre-wrap;">{{item.ad_content}}</p>
<p style="white-space: pre-wrap">{{ item.ad_content }}</p>
</el-card>
<b>{{formatDate(item.ad_ctime)}}</b>
<b>{{ formatDate(item.ad_ctime) }}</b>
</div>
</div>
</div>
<div class="kuang_communtion_input">
<p v-if="talkMsgs"></p>
<el-input type="textarea" rows="3" v-model="msgform.ad_content" placeholder="Editor messages" resize="none">
</el-input>
<el-input type="textarea" rows="3" v-model="msgform.ad_content" placeholder="Editor messages" resize="none"> </el-input>
<div class="kuang_communtion_input_text">
Dear Editor, through this window, you can have informal communication with the author. Please be aware
of the
prompt reply, standard use of English, and no offensive, insulting, discriminatory language.
Dear Editor, through this window, you can have informal communication with the author. Please be aware of the prompt reply,
standard use of English, and no offensive, insulting, discriminatory language.
<el-button type="primary" @click="saveMsg">Send</el-button>
</div>
</div>
@@ -43,8 +35,8 @@
</template>
<script>
import Vue from 'vue'
export default {
import Vue from 'vue';
export default {
props: {
talkMsgs: {
type: Array,
@@ -55,9 +47,8 @@
required: true
},
height: {
type: Number,
},
type: Number
}
// loading: {
// type: Boolean,
// required: true
@@ -67,8 +58,8 @@
data() {
return {
username: localStorage.getItem('U_name'),
loading:false
}
loading: false
};
},
computed: {},
methods: {
@@ -89,23 +80,17 @@
return false;
}
this.loading = true;
this.$api
.post('api/Article/pushArticleDialog', this.msgform)
.then((res) => {
this.$api.post('api/Article/pushArticleDialog', this.msgform).then((res) => {
this.loading = false;
// this.$message.success('Sent successfully');
this.$emit('talksave',true) // 传递成功信号
this.$emit('talksave', true); // 传递成功信号
// setTimeout(()=>{
// this.$router.go(0);
// },1000)
});
},
}
}
};
</script>
<style scoped>
</style>
<style scoped></style>