Merge branch 'v1.4' into master

This commit is contained in:
Captain.B 2020-10-27 13:26:00 +08:00
commit 32f130c05e
17 changed files with 176 additions and 37 deletions

View File

@ -0,0 +1,17 @@
package io.metersphere.base.mapper.ext;
import io.metersphere.track.dto.TestCaseCommentDTO;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface ExtTestCaseCommentMapper {
/**
* 获取用例的评论
* @param caseId
* @return
*/
List<TestCaseCommentDTO> getCaseComments(@Param("caseId") String caseId);
}

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="io.metersphere.base.mapper.ext.ExtTestCaseCommentMapper">
<select id="getCaseComments" resultType="io.metersphere.track.dto.TestCaseCommentDTO"
parameterType="java.lang.String">
select *, user.name as authorName from test_case_comment, user
where test_case_comment.author = user.id and case_id = #{caseId}
order by test_case_comment.update_time desc
</select>
</mapper>

View File

@ -1,6 +1,6 @@
package io.metersphere.track.controller; package io.metersphere.track.controller;
import io.metersphere.base.domain.TestCaseComment; import io.metersphere.track.dto.TestCaseCommentDTO;
import io.metersphere.track.request.testreview.SaveCommentRequest; import io.metersphere.track.request.testreview.SaveCommentRequest;
import io.metersphere.track.service.TestCaseCommentService; import io.metersphere.track.service.TestCaseCommentService;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -13,7 +13,7 @@ import java.util.List;
public class TestCaseCommentController { public class TestCaseCommentController {
@Resource @Resource
TestCaseCommentService testCaseCommentService; private TestCaseCommentService testCaseCommentService;
@PostMapping("/save") @PostMapping("/save")
public void saveComment(@RequestBody SaveCommentRequest request) { public void saveComment(@RequestBody SaveCommentRequest request) {
@ -21,7 +21,17 @@ public class TestCaseCommentController {
} }
@GetMapping("/list/{caseId}") @GetMapping("/list/{caseId}")
public List<TestCaseComment> getComments(@PathVariable String caseId) { public List<TestCaseCommentDTO> getCaseComments(@PathVariable String caseId) {
return testCaseCommentService.getComments(caseId); return testCaseCommentService.getCaseComments(caseId);
}
@GetMapping("/delete/{commentId}")
public void deleteComment(@PathVariable String commentId) {
testCaseCommentService.delete(commentId);
}
@PostMapping("/edit")
public void editComment(@RequestBody SaveCommentRequest request) {
testCaseCommentService.edit(request);
} }
} }

View File

@ -106,7 +106,7 @@ public class TestCaseReviewController {
} }
@PostMapping("/get/{reviewId}") @GetMapping("/get/{reviewId}")
public TestCaseReview getTestReview(@PathVariable String reviewId) { public TestCaseReview getTestReview(@PathVariable String reviewId) {
checkOwnerService.checkTestReviewOwner(reviewId); checkOwnerService.checkTestReviewOwner(reviewId);
return testCaseReviewService.getTestReview(reviewId); return testCaseReviewService.getTestReview(reviewId);

View File

@ -0,0 +1,9 @@
package io.metersphere.track.dto;
import io.metersphere.base.domain.TestCaseComment;
import lombok.Data;
@Data
public class TestCaseCommentDTO extends TestCaseComment {
private String authorName;
}

View File

@ -3,21 +3,23 @@ package io.metersphere.track.service;
import io.metersphere.base.domain.TestCaseComment; import io.metersphere.base.domain.TestCaseComment;
import io.metersphere.base.domain.TestCaseCommentExample; import io.metersphere.base.domain.TestCaseCommentExample;
import io.metersphere.base.domain.TestCaseWithBLOBs; import io.metersphere.base.domain.TestCaseWithBLOBs;
import io.metersphere.base.domain.User;
import io.metersphere.base.mapper.TestCaseCommentMapper; import io.metersphere.base.mapper.TestCaseCommentMapper;
import io.metersphere.base.mapper.TestCaseMapper; import io.metersphere.base.mapper.TestCaseMapper;
import io.metersphere.base.mapper.TestCaseReviewMapper; import io.metersphere.base.mapper.ext.ExtTestCaseCommentMapper;
import io.metersphere.base.mapper.UserMapper;
import io.metersphere.commons.constants.NoticeConstants; import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.SessionUtils; import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.i18n.Translator;
import io.metersphere.notice.domain.MessageDetail; import io.metersphere.notice.domain.MessageDetail;
import io.metersphere.notice.domain.MessageSettingDetail; import io.metersphere.notice.domain.MessageSettingDetail;
import io.metersphere.notice.service.DingTaskService; import io.metersphere.notice.service.DingTaskService;
import io.metersphere.notice.service.MailService; import io.metersphere.notice.service.MailService;
import io.metersphere.notice.service.NoticeService; import io.metersphere.notice.service.NoticeService;
import io.metersphere.notice.service.WxChatTaskService; import io.metersphere.notice.service.WxChatTaskService;
import io.metersphere.track.dto.TestCaseCommentDTO;
import io.metersphere.track.request.testreview.SaveCommentRequest; import io.metersphere.track.request.testreview.SaveCommentRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -33,21 +35,19 @@ import java.util.UUID;
public class TestCaseCommentService { public class TestCaseCommentService {
@Resource @Resource
TestCaseCommentMapper testCaseCommentMapper; private TestCaseCommentMapper testCaseCommentMapper;
@Resource @Resource
private TestCaseReviewMapper testCaseReviewMapper; private MailService mailService;
@Resource @Resource
UserMapper userMapper; private TestCaseMapper testCaseMapper;
@Resource @Resource
MailService mailService; private DingTaskService dingTaskService;
@Resource @Resource
TestCaseMapper testCaseMapper; private WxChatTaskService wxChatTaskService;
@Resource @Resource
DingTaskService dingTaskService; private NoticeService noticeService;
@Resource @Resource
WxChatTaskService wxChatTaskService; private ExtTestCaseCommentMapper extTestCaseCommentMapper;
@Resource
NoticeService noticeService;
public void saveComment(SaveCommentRequest request) { public void saveComment(SaveCommentRequest request) {
@ -86,21 +86,11 @@ public class TestCaseCommentService {
} }
public List<TestCaseComment> getComments(String caseId) { public List<TestCaseCommentDTO> getCaseComments(String caseId) {
TestCaseCommentExample testCaseCommentExample = new TestCaseCommentExample(); return extTestCaseCommentMapper.getCaseComments(caseId);
testCaseCommentExample.setOrderByClause("update_time desc");
testCaseCommentExample.createCriteria().andCaseIdEqualTo(caseId);
List<TestCaseComment> testCaseComments = testCaseCommentMapper.selectByExampleWithBLOBs(testCaseCommentExample);
testCaseComments.forEach(testCaseComment -> {
String authorId = testCaseComment.getAuthor();
User user = userMapper.selectByPrimaryKey(authorId);
String author = user == null ? authorId : user.getName();
testCaseComment.setAuthor(author);
});
return testCaseComments;
} }
public void deleteComment(String caseId) { public void deleteCaseComment(String caseId) {
TestCaseCommentExample testCaseCommentExample = new TestCaseCommentExample(); TestCaseCommentExample testCaseCommentExample = new TestCaseCommentExample();
testCaseCommentExample.createCriteria().andCaseIdEqualTo(caseId); testCaseCommentExample.createCriteria().andCaseIdEqualTo(caseId);
testCaseCommentMapper.deleteByExample(testCaseCommentExample); testCaseCommentMapper.deleteByExample(testCaseCommentExample);
@ -118,4 +108,22 @@ public class TestCaseCommentService {
context = "测试评审任务通知:" + testCaseComment.getAuthor() + "" + start + "" + "'" + testCaseWithBLOBs.getName() + "'" + "添加评论:" + testCaseComment.getDescription(); context = "测试评审任务通知:" + testCaseComment.getAuthor() + "" + start + "" + "'" + testCaseWithBLOBs.getName() + "'" + "添加评论:" + testCaseComment.getDescription();
return context; return context;
} }
public void delete(String commentId) {
checkCommentOwner(commentId);
testCaseCommentMapper.deleteByPrimaryKey(commentId);
}
public void edit(SaveCommentRequest request) {
checkCommentOwner(request.getId());
testCaseCommentMapper.updateByPrimaryKeySelective(request);
}
private void checkCommentOwner(String commentId) {
TestCaseComment comment = testCaseCommentMapper.selectByPrimaryKey(commentId);
if (!StringUtils.equals(comment.getAuthor(), SessionUtils.getUser().getId())) {
MSException.throwException(Translator.get("check_owner_comment"));
}
}
} }

View File

@ -170,7 +170,7 @@ public class TestCaseService {
example.createCriteria().andCaseIdEqualTo(testCaseId); example.createCriteria().andCaseIdEqualTo(testCaseId);
testPlanTestCaseMapper.deleteByExample(example); testPlanTestCaseMapper.deleteByExample(example);
testCaseIssueService.delTestCaseIssues(testCaseId); testCaseIssueService.delTestCaseIssues(testCaseId);
testCaseCommentService.deleteComment(testCaseId); testCaseCommentService.deleteCaseComment(testCaseId);
return testCaseMapper.deleteByPrimaryKey(testCaseId); return testCaseMapper.deleteByPrimaryKey(testCaseId);
} }

View File

@ -0,0 +1,2 @@
ALTER TABLE `test_plan_test_case` ADD INDEX index_name ( `case_id` );
ALTER TABLE `test_case_review_test_case` ADD INDEX index_name ( `case_id` );

View File

@ -164,6 +164,7 @@ check_owner_test=The current user does not have permission to operate this test
check_owner_case=The current user does not have permission to operate this use case check_owner_case=The current user does not have permission to operate this use case
check_owner_plan=The current user does not have permission to operate this plan check_owner_plan=The current user does not have permission to operate this plan
check_owner_review=The current user does not have permission to operate this review check_owner_review=The current user does not have permission to operate this review
check_owner_comment=The current user does not have permission to manipulate this comment
upload_content_is_null=Imported content is empty upload_content_is_null=Imported content is empty
test_plan_notification=Test plan notification test_plan_notification=Test plan notification
task_defect_notification=Task defect notification task_defect_notification=Task defect notification

View File

@ -164,6 +164,7 @@ check_owner_test=当前用户没有操作此测试的权限
check_owner_case=当前用户没有操作此用例的权限 check_owner_case=当前用户没有操作此用例的权限
check_owner_plan=当前用户没有操作此计划的权限 check_owner_plan=当前用户没有操作此计划的权限
check_owner_review=当前用户没有操作此评审的权限 check_owner_review=当前用户没有操作此评审的权限
check_owner_comment=当前用户没有操作此评论的权限
upload_content_is_null=导入内容为空 upload_content_is_null=导入内容为空
test_plan_notification=测试计划通知 test_plan_notification=测试计划通知
task_defect_notification=缺陷任务通知 task_defect_notification=缺陷任务通知

View File

@ -165,6 +165,7 @@ check_owner_test=當前用戶沒有操作此測試的權限
check_owner_case=當前用戶沒有操作此用例的權限 check_owner_case=當前用戶沒有操作此用例的權限
check_owner_plan=當前用戶沒有操作此計劃的權限 check_owner_plan=當前用戶沒有操作此計劃的權限
check_owner_review=當前用戶沒有操作此評審的權限 check_owner_review=當前用戶沒有操作此評審的權限
check_owner_comment=當前用戶沒有操作此評論的權限
upload_content_is_null=導入內容為空 upload_content_is_null=導入內容為空
test_plan_notification=測試計畫通知 test_plan_notification=測試計畫通知
task_defect_notification=缺陷任務通知 task_defect_notification=缺陷任務通知

View File

@ -1,7 +1,10 @@
<template> <template>
<div v-loading="result.loading"> <div v-loading="result.loading">
<div class="comment-list"> <div class="comment-list">
<review-comment-item v-for="(comment,index) in comments" :key="index" :comment="comment"/> <review-comment-item v-for="(comment,index) in comments"
:key="index"
:comment="comment"
@refresh="refresh"/>
<div v-if="comments.length === 0" style="text-align: center"> <div v-if="comments.length === 0" style="text-align: center">
<i class="el-icon-chat-line-square" style="font-size: 15px;color: #8a8b8d;"> <i class="el-icon-chat-line-square" style="font-size: 15px;color: #8a8b8d;">
<span style="font-size: 15px; color: #8a8b8d;"> <span style="font-size: 15px; color: #8a8b8d;">
@ -56,10 +59,13 @@ export default {
} }
this.result = this.$post('/test/case/comment/save', comment, () => { this.result = this.$post('/test/case/comment/save', comment, () => {
this.$success(this.$t('test_track.comment.send_success')); this.$success(this.$t('test_track.comment.send_success'));
this.$emit('getComments'); this.refresh();
this.textarea = ''; this.textarea = '';
}); });
}, },
refresh() {
this.$emit('getComments');
},
} }
} }
</script> </script>

View File

@ -2,30 +2,88 @@
<div class="main"> <div class="main">
<div class="comment-left"> <div class="comment-left">
<div class="icon-title"> <div class="icon-title">
{{ comment.author.substring(0, 1) }} {{ comment.authorName.substring(0, 1) }}
</div> </div>
</div> </div>
<div class="comment-right"> <div class="comment-right">
<span style="font-size: 14px;color: #909399;font-weight: bold">{{ comment.author }}</span> <span style="font-size: 14px;color: #909399;font-weight: bold">{{ comment.authorName }}</span>
<span style="color: #8a8b8d; margin-left: 8px; font-size: 12px"> <span style="color: #8a8b8d; margin-left: 8px; font-size: 12px">
{{ comment.createTime | timestampFormatDate }} {{ comment.createTime | timestampFormatDate }}
</span> </span>
<span class="comment-delete">
<i class="el-icon-edit" style="font-size: 9px;margin-right: 6px;" @click="openEdit"/>
<i class="el-icon-close" @click="deleteComment"/>
</span>
<br/> <br/>
<div class="comment-desc" style="font-size: 10px;color: #303133"> <div class="comment-desc" style="font-size: 10px;color: #303133">
<pre>{{ comment.description }}</pre> <pre>{{ comment.description }}</pre>
</div> </div>
</div> </div>
<el-dialog
:title="$t('commons.edit')"
:visible.sync="visible"
width="30%"
:destroy-on-close="true"
:append-to-body="true"
:close-on-click-modal="false"
show-close>
<el-input
type="textarea"
:rows="5"
v-model="description">
</el-input>
<span slot="footer" class="dialog-footer">
<ms-dialog-footer
@cancel="visible = false"
@confirm="editComment"/>
</span>
</el-dialog>
</div> </div>
</template> </template>
<script> <script>
import MsDialogFooter from "@/business/components/common/components/MsDialogFooter";
import {getCurrentUser} from "@/common/js/utils";
export default { export default {
name: "ReviewCommentItem", name: "ReviewCommentItem",
components: {MsDialogFooter},
props: { props: {
comment: Object comment: Object
}, },
data() { data() {
return {} return {
visible: false,
description: ""
}
},
methods: {
deleteComment() {
if (getCurrentUser().id !== this.comment.author) {
this.$warning(this.$t('test_track.comment.cannot_delete'));
return;
}
this.$parent.result = this.$get("/test/case/comment/delete/" + this.comment.id, () => {
this.$success(this.$t('commons.delete_success'));
this.$emit("refresh");
});
},
openEdit() {
if (getCurrentUser().id !== this.comment.author) {
this.$warning(this.$t('test_track.comment.cannot_edit'));
return;
}
this.description = this.comment.description;
this.visible = true;
},
editComment() {
this.$post("/test/case/comment/edit", {id: this.comment.id, description: this.description}, () => {
this.visible = false;
this.$success(this.$t('commons.modify_success'));
this.$emit("refresh");
});
}
} }
} }
</script> </script>
@ -72,4 +130,10 @@ export default {
pre { pre {
margin: 0 0; margin: 0 0;
} }
.comment-delete {
float: right;
margin-right: 5px;
cursor: pointer;
}
</style> </style>

View File

@ -365,7 +365,7 @@ export default {
}, },
getTestReviewById() { getTestReviewById() {
if (this.reviewId) { if (this.reviewId) {
this.$post('/test/case/review/get/' + this.reviewId, {}, response => { this.$get('/test/case/review/get/' + this.reviewId, response => {
this.testReview = response.data; this.testReview = response.data;
this.refreshTestReviewRecent(); this.refreshTestReviewRecent();
}); });

View File

@ -853,6 +853,8 @@ export default {
relevance_case: "Relevance Case", relevance_case: "Relevance Case",
last_page: "It's the end", last_page: "It's the end",
execute_result: "Result", execute_result: "Result",
cannot_edit: "Cannot edit this comment",
cannot_delete: "Cannot delete this comment",
}, },
module: { module: {
search: "Search module", search: "Search module",

View File

@ -845,6 +845,8 @@ export default {
send: "发送", send: "发送",
description_is_null: "评论内容不能为空!", description_is_null: "评论内容不能为空!",
send_success: "评论成功!", send_success: "评论成功!",
cannot_edit: "无法编辑此评论!",
cannot_delete: "无法删除此评论!",
}, },
review_view: { review_view: {
review: "评审", review: "评审",

View File

@ -845,6 +845,8 @@ export default {
send: "發送", send: "發送",
description_is_null: "評論內容不能為空!", description_is_null: "評論內容不能為空!",
send_success: "評論成功!", send_success: "評論成功!",
cannot_edit: "無法編輯此評論!",
cannot_delete: "無法刪除此評論!",
}, },
review_view: { review_view: {
review: "評審", review: "評審",