feat(测试跟踪): 用例评审
This commit is contained in:
parent
b9579d61a0
commit
ef33833794
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -187,8 +187,8 @@ export default {
|
|||
}
|
||||
});
|
||||
},
|
||||
intoReview() {
|
||||
|
||||
intoReview(row) {
|
||||
this.$router.push('/track/review/view/' + row.id);
|
||||
},
|
||||
testCaseReviewCreate() {
|
||||
this.$emit('openCaseReviewEditDialog');
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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("没有关联的评审!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue