580 lines
21 KiB
Vue
580 lines
21 KiB
Vue
<template>
|
||
<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="" v-if="type=='detail'">
|
||
<el-row :gutter="10">
|
||
<el-col :span="24">
|
||
<div class="form-box" style="width: 100%">
|
||
<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>
|
||
</el-form-item>
|
||
<el-form-item label="Reviewer email">
|
||
<span>{{ detailDate.reviewer_email }}</span>
|
||
</el-form-item>
|
||
<el-form-item label="CreateTime">
|
||
<span>{{ formatDate(detailDate.ctime) }}</span>
|
||
</el-form-item>
|
||
<el-form-item label="Disclose name or anonymous" label-width="200px">
|
||
<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">
|
||
<el-button type="primary" @click="createRevision">Re-review</el-button>
|
||
</el-form-item>
|
||
</el-form>
|
||
</div>
|
||
</el-col>
|
||
|
||
</el-row>
|
||
</div>
|
||
<common-review-article v-if="type=='question'"
|
||
type="undeQuestion"
|
||
pagetype="Editor"
|
||
:form="undeQuestion"
|
||
:txt_mess="txt_mess"
|
||
:btn_submit="1"
|
||
:articleId="articleId"
|
||
:journal_id="journal_id"
|
||
></common-review-article>
|
||
|
||
<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">
|
||
<el-radio :label="1" :disabled="ReReviewQuestion.recommend != 1">Accept</el-radio>
|
||
<el-radio :label="2" :disabled="ReReviewQuestion.recommend != 2">Reject</el-radio>
|
||
<!-- 退修改20251119 -->
|
||
<el-radio :label="3" :disabled="ReReviewQuestion.recommend != 3">Revison</el-radio>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
<el-form-item label="Confidential Comments to the Editor" v-if="ReReviewQuestion.recommend == 3">
|
||
<el-input
|
||
readonly
|
||
type="textarea"
|
||
placeholder="please input content"
|
||
v-model="ReReviewQuestion.content"
|
||
:rows="8"
|
||
></el-input>
|
||
</el-form-item>
|
||
</el-form>
|
||
<!-- </el-dialog> -->
|
||
</div>
|
||
<span slot="footer" class="dialog-footer">
|
||
<el-button type="" @click="reviewerVisible = false">Cancal</el-button>
|
||
</span>
|
||
</el-dialog>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
props: {
|
||
reviewerDetail: {
|
||
type: Object,
|
||
default: () => {}
|
||
},
|
||
|
||
},
|
||
data() {
|
||
return {
|
||
type:'',
|
||
|
||
reviewerVisible: false,
|
||
FdialogFormVisible: false,
|
||
dialogFormVisible1: false,
|
||
recordList: [],
|
||
reviewList: [],
|
||
journal_id: null,
|
||
baseUrl: this.Common.baseUrl,
|
||
mediaUrl: this.Common.mediaUrl,
|
||
articleId: this.$route.query.id,
|
||
dateId: '',
|
||
username: localStorage.getItem('U_name'),
|
||
articlefileList: [],
|
||
articlezipList: [],
|
||
dialogFormVisible: false,
|
||
activeNames: ['1', '2', '3', '4', '5', '6', '7'],
|
||
detailDate: {},
|
||
txt_mess: {},
|
||
questionform: { },
|
||
canRepeat: null,
|
||
undeQuestion: {},
|
||
ReReviewQuestion: {},
|
||
repeatItem: {},
|
||
time:"",//审稿时间
|
||
stime:"",//复审回复时间
|
||
};
|
||
},
|
||
created: function () {
|
||
console.log('this.reviewerDetail at line 971:', this.reviewerDetail.art_rev_id);
|
||
},
|
||
|
||
computed: {},
|
||
methods: {
|
||
|
||
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 = {
|
||
editor: localStorage.getItem('U_name'),
|
||
artrevid: art_rev_id,
|
||
article: '',
|
||
reviewer: '',
|
||
reviewer_email: '',
|
||
articlefile: '',
|
||
articlezip: '',
|
||
ctime: '',
|
||
state: ''
|
||
};
|
||
if(type=='detail'){
|
||
this.getDate();
|
||
}
|
||
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,
|
||
act_p_id: art_rev_id,
|
||
type: '1,2',
|
||
account: localStorage.getItem('U_name')
|
||
})
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
},
|
||
maxRepeatReviewCount() {
|
||
if (!this.reviewList || !Array.isArray(this.reviewList)) return null; // 边界处理:无数据返回null
|
||
|
||
// 遍历所有评审者,找到repeat数组长度最大的那条数据
|
||
const maxItem = this.reviewList.reduce((maxItem, currentItem) => {
|
||
// 计算当前项的repeat长度,非数组则视为0
|
||
const currentLen = Array.isArray(currentItem.repeat) ? currentItem.repeat.length : 0;
|
||
// 计算当前最大项的repeat长度,非数组则视为0
|
||
const maxLen = Array.isArray(maxItem.repeat) ? maxItem.repeat.length : 0;
|
||
|
||
// 如果当前项长度更大,则更新最大项
|
||
return currentLen > maxLen ? currentItem : maxItem;
|
||
}, {}); // 初始值设为一个空对象
|
||
// console.log('maxItem at line 2142:', maxItem.repeat.length)
|
||
return maxItem && maxItem.repeat ? maxItem.repeat.length : 0;
|
||
},
|
||
|
||
// 显示复审对话框
|
||
showSecondReview(item) {
|
||
this.FdialogFormVisible = true;
|
||
this.ReReviewQuestion = item;
|
||
},
|
||
// 显示初审对话框
|
||
showUnderReview(item) {
|
||
// this.dialogFormVisible1 = true;
|
||
this.undeQuestion = { ...item };
|
||
this.undeQuestion.qu9 = item.qu9 == 0 ? false : true;
|
||
this.undeQuestion.qu9contents = item.qu9_contents;
|
||
this.undeQuestion.qu10 = item.qu10 == 0 ? false : true;
|
||
this.undeQuestion.qu10contents = item.qu10_contents;
|
||
this.undeQuestion.qu11 = item.qu11 == 0 ? false : true;
|
||
this.undeQuestion.qu11contents = item.qu11_contents;
|
||
this.undeQuestion.qu12 = item.qu12 == 0 ? false : true;
|
||
this.undeQuestion.qu12contents = item.qu12_contents;
|
||
this.undeQuestion.qu13 = item.qu13 == 0 ? false : true;
|
||
this.undeQuestion.qu13contents = item.qu13_contents;
|
||
this.undeQuestion.qu14 = item.qu14 == 0 ? false : true;
|
||
this.undeQuestion.qu14contents = item.qu14_contents;
|
||
this.undeQuestion.qu15 = item.qu15 == 0 ? false : true;
|
||
this.undeQuestion.qu15contents = item.qu15_contents;
|
||
this.undeQuestion.confident = item.confidential;
|
||
this.undeQuestion.comment = item.comments;
|
||
},
|
||
// 关闭初审对话框
|
||
closeUnderDia() {
|
||
this.dialogFormVisible1 = false;
|
||
this.undeQuestion = {};
|
||
},
|
||
closeSecDia() {
|
||
this.FdialogFormVisible = false;
|
||
this.ReReviewQuestion = {};
|
||
},
|
||
// 2. 定义所有必需字段(确保所有数据结构统一)
|
||
|
||
// 3. 核心函数:提取第一个元素,剩余放入 repeat
|
||
splitQuestion(questionArr = []) {
|
||
const requiredFields = [
|
||
'rev_qu_id',
|
||
'art_rev_id',
|
||
'type',
|
||
'art_rev_rep_id',
|
||
'recommend',
|
||
'score',
|
||
'state',
|
||
'reviewer_id',
|
||
'realname',
|
||
'ctime',
|
||
'stime',
|
||
'is_anonymous'
|
||
];
|
||
// 解构数组:firstItem 取第一个元素,restItems 取剩余所有元素
|
||
const [firstItem = {}, ...restItems] = questionArr;
|
||
|
||
// 工具函数:补全单个对象的必需字段(空值用 null 填充)
|
||
const completeFields = (item) => {
|
||
console.log('item at line 1056:', item);
|
||
const result = { question: item };
|
||
requiredFields.forEach((field) => {
|
||
result[field] = item[field] ? item[field] : '';
|
||
});
|
||
return result;
|
||
};
|
||
|
||
// 补全第一个元素的字段
|
||
const firstCompleted = completeFields(firstItem);
|
||
|
||
// 补全剩余元素的字段,存入 repeat 数组
|
||
const repeat = restItems.map((item) => completeFields(item));
|
||
|
||
// 返回结果:按需选择格式(二选一)
|
||
return { ...firstCompleted, repeat: repeat };
|
||
},
|
||
|
||
// 创建复审实例
|
||
createRevision() {
|
||
this.$api
|
||
.post('api/Reviewer/startRepeatReviewer', {
|
||
art_rev_id: this.detailDate.artrevid
|
||
})
|
||
.then((res) => {
|
||
//console.log(res)
|
||
if (res.code == 0) {
|
||
this.$message.success('A review invitation was successfully sent!');
|
||
this.getdate();
|
||
} else {
|
||
this.$message.error(res.msg);
|
||
}
|
||
})
|
||
.catch((err) => {
|
||
console.log(err);
|
||
});
|
||
},
|
||
upload_file(type) {
|
||
return this.baseUrl + 'api/reviewer/up_file/type/' + type;
|
||
},
|
||
onSubmit() {
|
||
if (this.detailDate.articlefile == '') {
|
||
this.$message.error('you must upload article file');
|
||
console.log('file up error');
|
||
return false;
|
||
}
|
||
this.$api
|
||
.post('api/Reviewer/articleReviewerUpSubmit/type/editor', this.detailDate)
|
||
.then((res) => {
|
||
if (res.code == 0) {
|
||
this.$message.success('success');
|
||
this.$router.go(0);
|
||
} else {
|
||
this.$message.error('Failed to submit, please contact administrator!');
|
||
console.log(res.msg);
|
||
}
|
||
})
|
||
.catch((err) => {
|
||
console.log(err);
|
||
});
|
||
},
|
||
//初始化详情信息
|
||
getDate() {
|
||
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 ,
|
||
account: localStorage.getItem('U_name')
|
||
})
|
||
.then((res) => {
|
||
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.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();
|
||
console.log(err);
|
||
});
|
||
},
|
||
|
||
//初始化问卷
|
||
initquesion() {
|
||
const loading = this.$loading({
|
||
lock: true,
|
||
text: 'Loading...',
|
||
spinner: 'el-icon-loading',
|
||
background: 'rgba(0, 0, 0, 0.7)'
|
||
});
|
||
this.$api
|
||
.post('api/Reviewer/getQuestion', {
|
||
artrevid: this.dateId
|
||
})
|
||
.then((res) => {
|
||
if (res.code == 0) {
|
||
this.time=res.data.ctime;
|
||
this.showUnderReview(res.data)
|
||
this.reviewerVisible = true;
|
||
loading.close();
|
||
}
|
||
}).catch((err) => {
|
||
loading.close();
|
||
console.log(err);
|
||
});
|
||
},
|
||
//检验上传文件的格式
|
||
beforeupload_file(file) {
|
||
// const isWORd =
|
||
// file.type === 'application/msword' ||
|
||
// file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
|
||
// if (!isWORd) {
|
||
// this.$message.error('Only word files can be uploaded(.doc,.docx)');
|
||
// }
|
||
// return isWORd;
|
||
},
|
||
beforeupload_articlezip(file) {
|
||
// const iszip = file.type === 'application/x-zip-compressed' || file.name.split('.')[1] === 'rar';
|
||
// if (!iszip) {
|
||
// this.$message.error('Only compressed files can be uploaded(.rar,.zip)');
|
||
// }
|
||
// return iszip;
|
||
},
|
||
getlinkurl(row) {
|
||
return this.mediaUrl + row.file_url;
|
||
},
|
||
filedateformate(row, column, cellValue, index) {
|
||
return this.formatDate(cellValue);
|
||
},
|
||
uperr_file(err) {
|
||
this.$message.error('上传失败');
|
||
},
|
||
beforeupload() {},
|
||
upSuccess_file(res, file) {
|
||
if (res.code == 0) {
|
||
this.detailDate.articlefile = 'articlefile/' + res.upurl;
|
||
} else {
|
||
this.$message.error('服务器上传错误:' + res.msg);
|
||
}
|
||
},
|
||
upSuccess_articlezip(res, file) {
|
||
if (res.code == 0) {
|
||
this.detailDate.articlezip = 'articlezip/' + res.upurl;
|
||
} else {
|
||
this.$message.error('服务器上传错误:' + res.msg);
|
||
}
|
||
},
|
||
handleClick(item) {
|
||
console.log('item at line 1228:', item);
|
||
this.$router.push({
|
||
path: 'articleReviewerDetail',
|
||
query: {
|
||
id: item.art_rev_id
|
||
}
|
||
});
|
||
},
|
||
formatDate(timestamp) {
|
||
var date = new Date(timestamp * 1000); //时间戳为10位需*1000,时间戳为13位的话不需乘1000
|
||
var Y = date.getFullYear() + '-';
|
||
var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';
|
||
var D = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
|
||
var h = date.getHours() < 10 ? '0' + date.getHours() : date.getHours();
|
||
var m = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes();
|
||
var s = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds();
|
||
return Y + M + D + ' ' + h + ':' + m + ':' + s;
|
||
},
|
||
//超出传送文件个数限制
|
||
alertlimit() {
|
||
this.$message.error('超过最大上传文件个数');
|
||
},
|
||
//清除文件时的事件
|
||
removefilearticlefile(file, fileList) {
|
||
this.detailDate.articlefile = '';
|
||
},
|
||
removefilearticlezip(file, fileList) {
|
||
this.detailDate.articlezip = '';
|
||
},
|
||
mystate(mystate) {
|
||
let str = '';
|
||
switch (mystate) {
|
||
case 0:
|
||
str = 'With reviewer';
|
||
break;
|
||
case 1:
|
||
str = 'Major';
|
||
break;
|
||
case 2:
|
||
str = 'Reject';
|
||
break;
|
||
case 3:
|
||
// str = 'Accept';
|
||
str = 'Minor';
|
||
break;
|
||
}
|
||
return str;
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
.fsheader {
|
||
margin-bottom: 15px;
|
||
}
|
||
.dwnbtn {
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.container {
|
||
min-width: 1000px;
|
||
}
|
||
|
||
.tree_box {
|
||
padding: 15px 10px;
|
||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||
}
|
||
::v-deep .el-dialog__body {
|
||
padding: 10px 20px 20px !important;
|
||
}
|
||
.review_table {
|
||
width: 100%;
|
||
background-color: #fff;
|
||
/* margin-top: 10px; */
|
||
border-collapse: collapse; /* 合并表格边框 */
|
||
}
|
||
|
||
.review_table th,
|
||
td {
|
||
padding: 6px;
|
||
min-width: 70px;
|
||
border: 1px solid #ddd;
|
||
|
||
text-align: left;
|
||
}
|
||
|
||
.review_table th {
|
||
font-size: 14px;
|
||
background-color: #f0f0f0;
|
||
}
|
||
.review_table td {
|
||
font-size: 14px;
|
||
/* background-color: #f0f0f0; */
|
||
}
|
||
.review_table th:first-child,
|
||
.review_table td:first-child {
|
||
width: 100px;
|
||
/* 内容过长时自动换行 */
|
||
word-wrap: break-word;
|
||
/* 强制在单词内换行(针对长单词) */
|
||
word-break: break-all;
|
||
}
|
||
.review_table tr:hover {
|
||
/* background-color: #fff; */
|
||
}
|
||
.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>
|