feat(测试跟踪): 用例评审

This commit is contained in:
shiziyuan9527 2020-09-19 23:52:09 +08:00
parent b9579d61a0
commit ef33833794
9 changed files with 209 additions and 28 deletions

View File

@ -0,0 +1,27 @@
package io.metersphere.track.controller;
import io.metersphere.base.domain.TestCaseComment;
import io.metersphere.track.request.testreview.SaveCommentRequest;
import io.metersphere.track.service.TestCaseCommentService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@RequestMapping("/test/case/comment")
@RestController
public class TestCaseCommentController {
@Resource
TestCaseCommentService testCaseCommentService;
@PostMapping("/save")
public void saveComment(@RequestBody SaveCommentRequest request) {
testCaseCommentService.saveComment(request);
}
@GetMapping("/list/{caseId}")
public List<TestCaseComment> getComments(@PathVariable String caseId) {
return testCaseCommentService.getComments(caseId);
}
}

View File

@ -0,0 +1,11 @@
package io.metersphere.track.request.testreview;
import io.metersphere.base.domain.TestCaseComment;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class SaveCommentRequest extends TestCaseComment {
}

View File

@ -0,0 +1,49 @@
package io.metersphere.track.service;
import io.metersphere.base.domain.TestCaseComment;
import io.metersphere.base.domain.TestCaseCommentExample;
import io.metersphere.base.domain.User;
import io.metersphere.base.mapper.TestCaseCommentMapper;
import io.metersphere.base.mapper.UserMapper;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.track.request.testreview.SaveCommentRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
import java.util.UUID;
@Service
@Transactional(rollbackFor = Exception.class)
public class TestCaseCommentService {
@Resource
TestCaseCommentMapper testCaseCommentMapper;
@Resource
UserMapper userMapper;
public void saveComment(SaveCommentRequest request) {
TestCaseComment testCaseComment = new TestCaseComment();
testCaseComment.setId(UUID.randomUUID().toString());
testCaseComment.setAuthor(SessionUtils.getUser().getId());
testCaseComment.setCaseId(request.getCaseId());
testCaseComment.setCreateTime(System.currentTimeMillis());
testCaseComment.setUpdateTime(System.currentTimeMillis());
testCaseComment.setDescription(request.getDescription());
testCaseCommentMapper.insert(testCaseComment);
}
public List<TestCaseComment> getComments(String caseId) {
TestCaseCommentExample testCaseCommentExample = new TestCaseCommentExample();
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);
testCaseComment.setAuthor(user.getName());
});
return testCaseComments;
}
}

View File

@ -2,7 +2,9 @@ package io.metersphere.track.service;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.TestCaseReviewTestCaseMapper;
import io.metersphere.base.mapper.TestCaseReviewUsersMapper;
import io.metersphere.base.mapper.ext.ExtTestReviewCaseMapper;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.controller.request.member.QueryMemberRequest;
@ -28,6 +30,8 @@ public class TestReviewTestCaseService {
UserService userService;
@Resource
TestCaseReviewTestCaseMapper testCaseReviewTestCaseMapper;
@Resource
TestCaseReviewUsersMapper testCaseReviewUsersMapper;
public List<TestReviewCaseDTO> list(QueryCaseReviewRequest request) {
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
@ -37,11 +41,33 @@ public class TestReviewTestCaseService {
Map<String, String> userMap = userService.getMemberList(queryMemberRequest)
.stream().collect(Collectors.toMap(User::getId, User::getName));
list.forEach(item -> {
item.setReviewerName(userMap.get(item.getReviewer()));
String reviewId = item.getReviewId();
List<String> userIds = getReviewUserIds(reviewId);
item.setReviewerName(getReviewName(userIds, userMap));
});
return list;
}
private List<String> getReviewUserIds(String reviewId) {
TestCaseReviewUsersExample testCaseReviewUsersExample = new TestCaseReviewUsersExample();
testCaseReviewUsersExample.createCriteria().andReviewIdEqualTo(reviewId);
List<TestCaseReviewUsers> testCaseReviewUsers = testCaseReviewUsersMapper.selectByExample(testCaseReviewUsersExample);
return testCaseReviewUsers.stream().map(TestCaseReviewUsers::getUserId).collect(Collectors.toList());
}
private String getReviewName(List<String> userIds, Map userMap) {
StringBuilder stringBuilder = new StringBuilder();
String name = "";
if (userIds.size() > 0) {
for (String id : userIds) {
stringBuilder.append(userMap.get(id)).append("");
}
name = stringBuilder.toString().substring(0, stringBuilder.length() - 1);
}
return name;
}
public int deleteTestCase(String id) {
return testCaseReviewTestCaseMapper.deleteByPrimaryKey(id);
}
@ -53,6 +79,15 @@ public class TestReviewTestCaseService {
}
public void editTestCase(TestCaseReviewTestCase testCaseReviewTestCase) {
String currentUserId = SessionUtils.getUser().getId();
String reviewId = testCaseReviewTestCase.getReviewId();
TestCaseReviewUsersExample testCaseReviewUsersExample = new TestCaseReviewUsersExample();
testCaseReviewUsersExample.createCriteria().andReviewIdEqualTo(reviewId);
List<TestCaseReviewUsers> testCaseReviewUsers = testCaseReviewUsersMapper.selectByExample(testCaseReviewUsersExample);
List<String> reviewIds = testCaseReviewUsers.stream().map(TestCaseReviewUsers::getUserId).collect(Collectors.toList());
if (!reviewIds.contains(currentUserId)) {
MSException.throwException("非此用例的评审人员!");
}
testCaseReviewTestCase.setStatus(testCaseReviewTestCase.getStatus());
testCaseReviewTestCase.setReviewer(SessionUtils.getUser().getId());
testCaseReviewTestCase.setUpdateTime(System.currentTimeMillis());

View File

@ -1,20 +1,28 @@
<template>
<div>
<div class="main">
<review-comment-item/>
<div v-loading="result.loading">
<div style="height: 60vh;overflow-y: scroll">
<review-comment-item v-for="(comment,index) in comments" :key="index" :comment="comment"/>
<div v-if="comments.length === 0" style="text-align: center">
<i class="el-icon-chat-line-square" style="font-size: 20px;color: #8a8b8d;">
<span style="font-size: 20px; color: #8a8b8d;">
暂无评论
</span>
</i>
</div>
</div>
<div>
<el-input
type="textarea"
placeholder="发表评论"
placeholder="发表评论Ctrl+Enter发送"
v-model="textarea"
maxlength="60"
show-word-limit
resize="none"
:autosize="{ minRows: 4, maxRows: 4}"
@keyup.ctrl.enter.native="sendComment"
>
</el-input>
<el-button type="primary" size="mini" class="send-btn">发送</el-button>
<el-button type="primary" size="mini" class="send-btn" @click="sendComment">发送</el-button>
</div>
</div>
</template>
@ -25,19 +33,37 @@ import ReviewCommentItem from "./ReviewCommentItem";
export default {
name: "ReviewComment",
components: {ReviewCommentItem},
props: {
caseId: String,
comments: Array
},
data() {
return {
commentData: [],
textarea: ''
result: {},
textarea: '',
}
},
methods: {
sendComment() {
let comment = {};
comment.caseId = this.caseId;
comment.description = this.textarea;
if (!this.textarea) {
this.$warning("评论内容不能为空!");
return;
}
this.$post('/test/case/comment/save', comment, () => {
this.$success("评论成功!");
this.$emit('getComments');
this.textarea = '';
});
},
}
}
</script>
<style scoped>
.main {
height: 60vh;
}
.send-btn {
float: right;
margin-top: 5px;

View File

@ -1,36 +1,51 @@
<template>
<div style="height: 60px;">
<div class="main">
<div class="comment-left">
<span>
<i class="el-icon-user-solid review-comment-user"/>
</span>
</div>
<div class="comment-right">
张三 <span style="color: #8a8b8d">9月8日</span><br/>
<span>优先级为2</span>
<span style="font-size: 16px;">{{comment.author}}</span>
<span style="color: #8a8b8d; margin-left: 8px; font-size: 12px">
{{comment.createTime | timestampFormatDate}}
</span>
<br/>
<div style="word-wrap:break-word; word-break:break-all;">{{comment.description}}</div>
</div>
</div>
</template>
<script>
export default {
name: "ReviewCommentItem"
name: "ReviewCommentItem",
props: {
comment: Object
},
data() {
return {}
}
}
</script>
<style scoped>
.main {
overflow-y: scroll
}
.review-comment-user {
font-size: 19px;
}
.comment-left {
float: left;
width: 10%;
height: 100%;
}
.comment-right {
float: left;
width: 90%;
height: 100%;
padding: 0;
line-height: 25px;
}

View File

@ -187,8 +187,8 @@ export default {
}
});
},
intoReview() {
intoReview(row) {
this.$router.push('/track/review/view/' + row.id);
},
testCaseReviewCreate() {
this.$emit('openCaseReviewEditDialog');

View File

@ -132,7 +132,7 @@
:default-sort="{prop: 'num', order: 'ascending'}"
highlight-current-row>
<el-table-column :label="$t('test_track.case.number')" prop="num"
min-width="5%"></el-table-column>
min-width="5%"/>
<el-table-column :label="$t('test_track.case.step_desc')" prop="desc" min-width="21%">
<template v-slot:default="scope">
@ -216,7 +216,7 @@
<el-card>
<el-tabs class="system-setting" v-model="activeName">
<el-tab-pane label="评论" name="comment">
<review-comment/>
<review-comment :comments="comments" :case-id="testCase.caseId" @getComments="getComments"/>
</el-tab-pane>
</el-tabs>
</el-card>
@ -263,7 +263,8 @@ export default {
activeTab: 'detail',
isFailure: true,
users: [],
activeName: 'comment'
activeName: 'comment',
comments: []
};
},
props: {
@ -290,8 +291,8 @@ export default {
saveCase(status) {
let param = {};
param.id = this.testCase.id;
param.reviewId = this.testCase.reviewId;
param.status = status;
this.$post('/test/review/case/edit', param, () => {
this.$success(this.$t('commons.save_success'));
this.updateTestCases(param);
@ -334,6 +335,7 @@ export default {
this.activeTab = 'detail';
listenGoBack(this.handleClose);
this.initData(testCase);
this.getComments(testCase);
},
initTest() {
this.$nextTick(() => {
@ -360,6 +362,17 @@ export default {
saveReport(reportId) {
this.$post('/test/plan/case/edit', {id: this.testCase.id, reportId: reportId});
},
getComments(testCase) {
let id = '';
if (testCase) {
id = testCase.caseId;
} else {
id = this.testCase.caseId;
}
this.result = this.$get('/test/case/comment/list/' + id, res => {
this.comments = res.data;
})
},
initData(testCase) {
this.result = this.$post('/test/review/case/list/all', this.searchParam, response => {
this.testCases = response.data;
@ -374,7 +387,6 @@ export default {
},
getRelatedTest() {
if (this.testCase.method == 'auto' && this.testCase.testId && this.testCase.testId != 'other') {
console.log(this.testCase.type)
this.$get('/' + this.testCase.type + '/get/' + this.testCase.testId, response => {
let data = response.data;
if (data) {

View File

@ -37,7 +37,7 @@
type="selection"/>
<el-table-column width="40" :resizable="false" align="center">
<template v-slot:default="scope">
<show-more-btn :is-show="scope.row.showMore" :buttons="buttons" :size="selectRows.size"/>
<!-- <show-more-btn :is-show="scope.row.showMore" :buttons="buttons" :size="selectRows.size"/>-->
</template>
</el-table-column>
<el-table-column
@ -128,7 +128,9 @@
<el-table-column
prop="reviewerName"
:label="$t('test_track.plan_view.executor')">
label="评审人"
show-overflow-tooltip
>
</el-table-column>
<el-table-column
@ -231,7 +233,7 @@ export default {
pageSize: 10,
total: 0,
selectRows: new Set(),
testPlan: {},
testReview: {},
isReadOnly: false,
isTestManagerOrTestUser: false,
priorityFilters: [
@ -466,7 +468,7 @@ export default {
getTestReviewById() {
if (this.reviewId) {
this.$post('/test/case/review/get/' + this.reviewId, {}, response => {
this.testPlan = response.data;
this.testReview = response.data;
this.refreshTestReviewRecent();
});
}
@ -506,7 +508,11 @@ export default {
});
},
startReview() {
if (this.tableData.length !== 0) {
this.$refs.testReviewTestCaseEdit.openTestCaseEdit(this.tableData[0]);
} else {
this.$warning("没有关联的评审!");
}
}
}
}