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

This commit is contained in:
shiziyuan9527 2020-09-17 18:03:05 +08:00
parent 77ebb23127
commit 92f91fcb48
14 changed files with 878 additions and 3 deletions

View File

@ -0,0 +1,14 @@
package io.metersphere.base.mapper.ext;
import io.metersphere.track.dto.TestCaseReviewDTO;
import io.metersphere.track.request.testreview.QueryCaseReviewRequest;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ExtTestCaseReviewMapper {
List<TestCaseReviewDTO> list(@Param("request") QueryCaseReviewRequest params);
List<TestCaseReviewDTO> listByWorkspaceId(@Param("workspaceId") String workspaceId);
}

View File

@ -0,0 +1,30 @@
<?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.ExtTestCaseReviewMapper">
<select id="list" resultType="io.metersphere.track.dto.TestCaseReviewDTO" parameterType="io.metersphere.track.request.testcase.QueryTestPlanRequest">
select test_case_review.* from test_case_review
<where>
<if test="request.name != null">
and test_case_review.name like CONCAT('%', #{request.name},'%')
</if>
<if test="request.id != null">
AND test_case_review.id = #{request.id}
</if>
</where>
<if test="request.orders != null and request.orders.size() > 0">
order by
<foreach collection="request.orders" separator="," item="order">
test_case_review.${order.name} ${order.type}
</foreach>
</if>
</select>
<select id="listByWorkspaceId" resultType="io.metersphere.track.dto.TestCaseReviewDTO" parameterType="io.metersphere.track.request.testcase.QueryTestPlanRequest">
select distinct test_case_review.*
from test_case_review, project, test_case_review_project
where test_case_review.id = test_case_review_project.review_id
and test_case_review_project.project_id = project.id
and project.workspace_id = #{workspaceId}
</select>
</mapper>

View File

@ -0,0 +1,5 @@
package io.metersphere.commons.constants;
public enum TestCaseReviewStatus {
Prepare, Underway, Completed
}

View File

@ -0,0 +1,73 @@
package io.metersphere.track.controller;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.Project;
import io.metersphere.base.domain.TestCaseReview;
import io.metersphere.base.domain.User;
import io.metersphere.commons.constants.RoleConstants;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.track.dto.TestCaseReviewDTO;
import io.metersphere.track.request.testreview.QueryCaseReviewRequest;
import io.metersphere.track.request.testreview.SaveTestCaseReviewRequest;
import io.metersphere.track.service.TestCaseReviewService;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@RequestMapping("/test/case/review")
@RestController
public class TestCaseReviewController {
@Resource
TestCaseReviewService testCaseReviewService;
@PostMapping("/list/{goPage}/{pageSize}")
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
public Pager<List<TestCaseReviewDTO>> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryCaseReviewRequest request) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, testCaseReviewService.listCaseReview(request));
}
@PostMapping("/save")
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
public void saveCaseReview(@RequestBody SaveTestCaseReviewRequest reviewRequest) {
testCaseReviewService.saveTestCaseReview(reviewRequest);
}
@PostMapping("/project")
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
public List<Project> getProjectByReviewId(@RequestBody TestCaseReview request) {
return testCaseReviewService.getProjectByReviewId(request);
}
@PostMapping("/reviewer")
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
public List<User> getUserByReviewId(@RequestBody TestCaseReview request) {
return testCaseReviewService.getUserByReviewId(request);
}
@GetMapping("/recent/{count}")
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
public List<TestCaseReviewDTO> recentTestPlans(@PathVariable int count) {
String currentWorkspaceId = SessionUtils.getCurrentWorkspaceId();
PageHelper.startPage(1, count, true);
return testCaseReviewService.recent(currentWorkspaceId);
}
@PostMapping("/edit")
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
public void editCaseReview(@RequestBody TestCaseReview testCaseReview) {
testCaseReviewService.editCaseReview(testCaseReview);
}
@GetMapping("/delete/{reviewId}")
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
public void deleteCaseReview(@PathVariable String reviewId) {
testCaseReviewService.deleteCaseReview(reviewId);
}
}

View File

@ -0,0 +1,13 @@
package io.metersphere.track.dto;
import io.metersphere.base.domain.TestCaseReview;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class TestCaseReviewDTO extends TestCaseReview {
private String projectName;
private String reviewerName;
}

View File

@ -0,0 +1,14 @@
package io.metersphere.track.request.testreview;
import io.metersphere.base.domain.TestCaseReview;
import io.metersphere.controller.request.OrderRequest;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class QueryCaseReviewRequest extends TestCaseReview {
private List<OrderRequest> orders;
}

View File

@ -0,0 +1,14 @@
package io.metersphere.track.request.testreview;
import io.metersphere.base.domain.TestCaseReview;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class SaveTestCaseReviewRequest extends TestCaseReview {
private List<String> projectIds;
private List<String> userIds;
}

View File

@ -0,0 +1,150 @@
package io.metersphere.track.service;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.ExtTestCaseReviewMapper;
import io.metersphere.commons.constants.TestCaseReviewStatus;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.track.dto.TestCaseReviewDTO;
import io.metersphere.track.request.testreview.QueryCaseReviewRequest;
import io.metersphere.track.request.testreview.SaveTestCaseReviewRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@Service
@Transactional(rollbackFor = Exception.class)
public class TestCaseReviewService {
@Resource
private TestCaseReviewProjectMapper testCaseReviewProjectMapper;
@Resource
private TestCaseReviewUsersMapper testCaseReviewUsersMapper;
@Resource
private TestCaseReviewMapper testCaseReviewMapper;
@Resource
private ExtTestCaseReviewMapper extTestCaseReviewMapper;
@Resource
private ProjectMapper projectMapper;
@Resource
private UserMapper userMapper;
public void saveTestCaseReview(SaveTestCaseReviewRequest reviewRequest) {
checkCaseReviewExist(reviewRequest);
String reviewId = UUID.randomUUID().toString();
List<String> projectIds = reviewRequest.getProjectIds();
List<String> userIds = reviewRequest.getUserIds();
projectIds.forEach(projectId -> {
TestCaseReviewProject testCaseReviewProject = new TestCaseReviewProject();
testCaseReviewProject.setProjectId(projectId);
testCaseReviewProject.setReviewId(reviewId);
testCaseReviewProjectMapper.insertSelective(testCaseReviewProject);
});
userIds.forEach(userId -> {
TestCaseReviewUsers testCaseReviewUsers = new TestCaseReviewUsers();
testCaseReviewUsers.setReviewId(reviewId);
testCaseReviewUsers.setUserId(userId);
testCaseReviewUsersMapper.insert(testCaseReviewUsers);
});
reviewRequest.setId(reviewId);
reviewRequest.setCreateTime(System.currentTimeMillis());
reviewRequest.setUpdateTime(System.currentTimeMillis());
reviewRequest.setCreator(SessionUtils.getUser().getId());
reviewRequest.setStatus(TestCaseReviewStatus.Prepare.name());
testCaseReviewMapper.insert(reviewRequest);
}
public List<TestCaseReviewDTO> listCaseReview(QueryCaseReviewRequest request) {
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
return extTestCaseReviewMapper.list(request);
}
public List<Project> getProjectByReviewId(TestCaseReview request) {
String reviewId = request.getId();
TestCaseReviewProjectExample testCaseReviewProjectExample = new TestCaseReviewProjectExample();
testCaseReviewProjectExample.createCriteria().andReviewIdEqualTo(reviewId);
List<TestCaseReviewProject> testCaseReviewProject = testCaseReviewProjectMapper.selectByExample(testCaseReviewProjectExample);
List<String> projectIds = testCaseReviewProject
.stream()
.map(TestCaseReviewProject::getProjectId)
.collect(Collectors.toList());
ProjectExample projectExample = new ProjectExample();
projectExample.createCriteria().andIdIn(projectIds);
return projectMapper.selectByExample(projectExample);
}
public List<User> getUserByReviewId(TestCaseReview request) {
String reviewId = request.getId();
TestCaseReviewUsersExample testCaseReviewUsersExample = new TestCaseReviewUsersExample();
testCaseReviewUsersExample.createCriteria().andReviewIdEqualTo(reviewId);
List<TestCaseReviewUsers> testCaseReviewUsers = testCaseReviewUsersMapper.selectByExample(testCaseReviewUsersExample);
List<String> userIds = testCaseReviewUsers
.stream()
.map(TestCaseReviewUsers::getUserId)
.collect(Collectors.toList());
UserExample userExample = new UserExample();
userExample.createCriteria().andIdIn(userIds);
return userMapper.selectByExample(userExample);
}
public List<TestCaseReviewDTO> recent(String currentWorkspaceId) {
return extTestCaseReviewMapper.listByWorkspaceId(currentWorkspaceId);
}
public void editCaseReview(TestCaseReview testCaseReview) {
testCaseReview.setUpdateTime(System.currentTimeMillis());
checkCaseReviewExist(testCaseReview);
testCaseReviewMapper.updateByPrimaryKeySelective(testCaseReview);
}
private void checkCaseReviewExist(TestCaseReview testCaseReview) {
if (testCaseReview.getName() != null) {
TestCaseReviewExample example = new TestCaseReviewExample();
TestCaseReviewExample.Criteria criteria = example
.createCriteria()
.andNameEqualTo(testCaseReview.getName());
if (StringUtils.isNotBlank(testCaseReview.getId())) {
criteria.andIdNotEqualTo(testCaseReview.getId());
}
if (testCaseReviewMapper.selectByExample(example).size() > 0) {
MSException.throwException("评审名称已存在");
}
}
}
public void deleteCaseReview(String reviewId) {
deleteCaseReviewProject(reviewId);
deleteCaseReviewUsers(reviewId);
testCaseReviewMapper.deleteByPrimaryKey(reviewId);
}
private void deleteCaseReviewProject(String reviewId) {
TestCaseReviewProjectExample testCaseReviewProjectExample = new TestCaseReviewProjectExample();
testCaseReviewProjectExample.createCriteria().andReviewIdEqualTo(reviewId);
testCaseReviewProjectMapper.deleteByExample(testCaseReviewProjectExample);
}
private void deleteCaseReviewUsers(String reviewId) {
TestCaseReviewUsersExample testCaseReviewUsersExample = new TestCaseReviewUsersExample();
testCaseReviewUsersExample.createCriteria().andReviewIdEqualTo(reviewId);
testCaseReviewUsersMapper.deleteByExample(testCaseReviewUsersExample);
}
}

View File

@ -2,6 +2,7 @@
<el-tooltip :content="tip" <el-tooltip :content="tip"
placement="bottom" placement="bottom"
:enterable="false"
:effect="effect"> :effect="effect">
<el-button @click="exec()" <el-button @click="exec()"
@click.stop="clickStop" @click.stop="clickStop"

View File

@ -2,7 +2,7 @@
<div id="menu-bar" v-if="isRouterAlive"> <div id="menu-bar" v-if="isRouterAlive">
<el-row type="flex"> <el-row type="flex">
<el-col :span="8"> <el-col :span="12">
<el-menu class="header-menu" :unique-opened="true" mode="horizontal" router <el-menu class="header-menu" :unique-opened="true" mode="horizontal" router
:default-active='$route.path'> :default-active='$route.path'>
<el-menu-item :index="'/track/home'"> <el-menu-item :index="'/track/home'">
@ -30,6 +30,16 @@
:title="$t('test_track.case.create_case')"/> :title="$t('test_track.case.create_case')"/>
</el-submenu> </el-submenu>
<el-submenu v-permission="['test_manager','test_user','test_viewer']"
index="8" popper-class="submenu">
<template v-slot:title>用例评审</template>
<ms-recent-list ref="reviewRecent" :options="reviewRecent"/>
<el-divider/>
<ms-show-all :index="'/track/review/all'"/>
<el-menu-item :index="testCaseReviewEditPath" class="blank_item"/>
<ms-create-button v-permission="['test_manager','test_user']" :index="'/track/review/create'" title="创建用例评审"/>
</el-submenu>
<el-submenu v-permission="['test_manager','test_user','test_viewer']" index="7" popper-class="submenu"> <el-submenu v-permission="['test_manager','test_user','test_viewer']" index="7" popper-class="submenu">
<template v-slot:title>{{ $t('test_track.plan.test_plan') }}</template> <template v-slot:title>{{ $t('test_track.plan.test_plan') }}</template>
<ms-recent-list ref="planRecent" :options="planRecent"/> <ms-recent-list ref="planRecent" :options="planRecent"/>
@ -41,7 +51,7 @@
</el-submenu> </el-submenu>
</el-menu> </el-menu>
</el-col> </el-col>
<el-col :span="16"/> <el-col :span="12"/>
</el-row> </el-row>
</div> </div>
@ -61,6 +71,7 @@ export default {
testPlanViewPath: '', testPlanViewPath: '',
isRouterAlive: true, isRouterAlive: true,
testCaseEditPath: '', testCaseEditPath: '',
testCaseReviewEditPath: '',
testCaseProjectPath: '', testCaseProjectPath: '',
isProjectActivation: true, isProjectActivation: true,
projectRecent: { projectRecent: {
@ -82,6 +93,15 @@ export default {
router: function (item) { router: function (item) {
} }
}, },
reviewRecent: {
title: "最近的评审",
url: "/test/case/review/recent/5",
index: function (item) {
return '/test/case/review/' + item.id;
},
router: function (item) {
}
},
planRecent: { planRecent: {
title: this.$t('test_track.recent_plan'), title: this.$t('test_track.recent_plan'),
url: "/test/plan/recent/5", url: "/test/plan/recent/5",

View File

@ -0,0 +1,63 @@
<template>
<ms-container>
<ms-main-container>
<test-case-review-list
@openCaseReviewEditDialog="openCaseReviewEditDialog"
@caseReviewEdit="openCaseReviewEditDialog"
ref="caseReviewList"/>
</ms-main-container>
<test-case-review-edit ref="caseReviewEditDialog" @refresh="refreshCaseReviewList"/>
</ms-container>
</template>
<script>
import TestCaseReviewList from "./components/TestCaseReviewList";
import TestCaseReviewEdit from "./components/TestCaseReviewEdit";
import MsMainContainer from "../../common/components/MsMainContainer";
import MsContainer from "../../common/components/MsContainer";
export default {
name: "TestCaseReview",
components: {
MsMainContainer,
MsContainer,
TestCaseReviewList,
TestCaseReviewEdit
},
data() {
return {
}
},
mounted() {
if (this.$route.path.indexOf("/track/review/create") >= 0){
this.openCaseReviewEditDialog();
this.$router.push('/track/review/all');
}
},
watch: {
'$route'(to) {
if (to.path.indexOf("/track/review/create") >= 0){
this.openCaseReviewEditDialog();
this.$router.push('/track/review/all');
}
}
},
methods: {
openCaseReviewEditDialog(data) {
this.$refs.caseReviewEditDialog.openCaseReviewEditDialog(data);
},
refreshCaseReviewList() {
this.$refs.caseReviewList.condition = {};
this.$refs.caseReviewList.initTableData();
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,245 @@
<template>
<div>
<el-dialog :close-on-click-modal="false"
:title="operationType === 'edit' ? '编辑用例评审' : '创建用例评审'"
:visible.sync="dialogFormVisible"
@close="close"
width="65%">
<el-form :model="form" :rules="rules" ref="reviewForm">
<el-row>
<el-col :span="8" :offset="1">
<el-form-item
placeholder="请输入评审标题"
label="评审标题"
:label-width="formLabelWidth"
prop="name">
<el-input v-model="form.name"/>
</el-form-item>
</el-col>
<el-col :span="11" :offset="2">
<el-form-item :label="$t('test_track.plan.plan_project')" :label-width="formLabelWidth" prop="projectIds">
<el-select
:disabled="(form.status == null) ? false : true"
v-model="form.projectIds"
:placeholder="$t('test_track.plan.input_plan_project')"
multiple
style="width: 100%"
collapse-tags
filterable>
<el-option
v-for="item in projects"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="10" :offset="1">
<el-form-item label="评审人" :label-width="formLabelWidth" prop="principal">
<el-select
v-model="form.userIds"
placeholder="请选择评审人"
filterable multiple
collapse-tags
:disabled="(form.status == null) ? false : true"
>
<el-option
v-for="item in reviewerOptions"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="截止时间" :label-width="formLabelWidth" prop="endTime">
<el-date-picker @change="endTimeChange" type="datetime" :placeholder="$t('commons.select_date')"
v-model="form.endTime"/>
</el-form-item>
</el-col>
</el-row>
<el-row type="flex" justify="left" style="margin-top: 10px;">
<el-col :span="23" :offset="1">
<el-form-item :label="$t('commons.description')" :label-width="formLabelWidth" prop="description">
<el-input v-model="form.description"
type="textarea"
:autosize="{ minRows: 2, maxRows: 4}"
:rows="2"
:placeholder="$t('commons.input_content')"/>
</el-form-item>
</el-col>
</el-row>
<el-row v-if="operationType == 'edit'" type="flex" justify="left" style="margin-top: 10px;">
<el-col :span="19" :offset="1">
<el-form-item label="当前状态" :label-width="formLabelWidth" prop="status">
<test-plan-status-button :status="form.status" @statusChange="statusChange"/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template v-slot:footer>
<div class="dialog-footer">
<el-button @click="dialogFormVisible = false">
{{ $t('test_track.cancel') }}
</el-button>
<el-button type="primary" @click="saveReview">
{{ $t('test_track.confirm') }}
</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script>
import TestPlanStatusButton from "../../plan/common/TestPlanStatusButton";
import {WORKSPACE_ID} from "../../../../../common/js/constants";
import {listenGoBack, removeGoBackListener} from "../../../../../common/js/utils";
export default {
name: "TestCaseReviewEdit",
components: {TestPlanStatusButton},
data() {
return {
dialogFormVisible: false,
form: {
name: '',
projectIds: [],
userIds: [],
stage: '',
description: '',
endTime: ''
},
rules: {
name: [
{required: true, message: this.$t('test_track.plan.input_plan_name'), trigger: 'blur'},
{max: 30, message: this.$t('test_track.length_less_than') + '30', trigger: 'blur'}
],
projectIds: [{required: true, message: this.$t('test_track.plan.input_plan_project'), trigger: 'change'}],
userIds: [{required: true, message: this.$t('test_track.plan.input_plan_principal'), trigger: 'change'}],
stage: [{required: true, message: this.$t('test_track.plan.input_plan_stage'), trigger: 'change'}],
description: [{max: 200, message: this.$t('test_track.length_less_than') + '200', trigger: 'blur'}],
endTime: [{required: true, message: '请选择截止时间', trigger: 'blur'}]
},
formLabelWidth: "120px",
operationType: '',
projects: [],
reviewerOptions: []
};
},
methods: {
openCaseReviewEditDialog(caseReview) {
this.resetForm();
this.getProjects();
this.setReviewerOptions();
this.operationType = 'save';
if (caseReview) {
//
this.operationType = 'edit';
let tmp = {};
Object.assign(tmp, caseReview);
Object.assign(this.form, tmp);
}
listenGoBack(this.close);
this.dialogFormVisible = true;
},
saveReview() {
this.$refs['reviewForm'].validate((valid) => {
if (valid) {
let param = {};
Object.assign(param, this.form);
param.name = param.name.trim();
if (param.name == '') {
this.$warning(this.$t('test_track.plan.input_plan_name'));
return;
}
if (this.operationType === 'save') {
this.compareTime(new Date().getTime(), this.form.endTime);
}
this.$post('/test/case/review/' + this.operationType, param, () => {
this.$success(this.$t('commons.save_success'));
this.dialogFormVisible = false;
this.$emit("refresh");
});
} else {
return false;
}
});
},
getProjects() {
this.$get("/project/listAll", (response) => {
if (response.success) {
this.projects = response.data;
} else {
this.$warning()(response.message);
}
});
},
setReviewerOptions() {
let workspaceId = localStorage.getItem(WORKSPACE_ID);
this.$post('/user/ws/member/tester/list', {workspaceId: workspaceId}, response => {
this.reviewerOptions = response.data;
});
},
statusChange(status) {
this.form.status = status;
this.$forceUpdate();
},
close() {
removeGoBackListener(this.close);
this.dialogFormVisible = false;
},
resetForm() {
//
if (this.$refs['reviewForm']) {
this.$refs['reviewForm'].validate((valid) => {
this.$refs['reviewForm'].resetFields();
this.form.name = '';
this.form.stage = '';
this.form.endTime = '';
this.form.description = '';
this.form.status = null;
this.form.projectIds = [];
this.form.userIds = [];
return true;
});
}
},
endTimeChange(value) {
this.form.endTime = this.form.endTime.getTime();
this.compareTime(new Date().getTime(), value.getTime());
},
compareTime(ts1, ts2) {
if (ts1 > ts2) {
this.form.endTime = '';
this.$warning("截止时间不能早于当前时间!");
}
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,227 @@
<template>
<el-card class="table-card" v-loading="result.loading">
<template v-slot:header>
<ms-table-header :is-tester-permission="true" :condition.sync="condition"
@search="initTableData" @create="testCaseReviewCreate"
create-tip="创建用例评审"
title="用例评审"/>
</template>
<el-table
border
class="adjust-table"
:data="tableData"
@filter-change="filter"
@sort-change="sort"
@row-click="intoReview">
<el-table-column
prop="name"
label="评审名称"
show-overflow-tooltip>
</el-table-column>
<el-table-column
prop="reviewer"
label="评审人"
show-overflow-tooltip>
</el-table-column>
<el-table-column
prop="projectName"
label="所属项目"
show-overflow-tooltip>
</el-table-column>
<el-table-column
prop="creator"
label="发起人"
show-overflow-tooltip>
</el-table-column>
<el-table-column
prop="status"
column-key="status"
:filters="statusFilters"
:label="$t('test_track.plan.plan_status')"
show-overflow-tooltip>
<template v-slot:default="scope">
<span @click.stop="clickt = 'stop'">
<el-dropdown class="test-case-status" @command="statusChange">
<span class="el-dropdown-link">
<plan-status-table-item :value="scope.row.status"/>
</span>
<el-dropdown-menu slot="dropdown" chang>
<el-dropdown-item :disabled="!isTestManagerOrTestUser" :command="{id: scope.row.id, status: 'Prepare'}">
{{ $t('test_track.plan.plan_status_prepare') }}
</el-dropdown-item>
<el-dropdown-item :disabled="!isTestManagerOrTestUser"
:command="{id: scope.row.id, status: 'Underway'}">
{{ $t('test_track.plan.plan_status_running') }}
</el-dropdown-item>
<el-dropdown-item :disabled="!isTestManagerOrTestUser"
:command="{id: scope.row.id, status: 'Completed'}">
{{ $t('test_track.plan.plan_status_completed') }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</span>
</template>
</el-table-column>
<el-table-column
prop="reviewerSize"
label="已评"
show-overflow-tooltip>
</el-table-column>
<el-table-column
prop="resultMap"
label="结果分布"
show-overflow-tooltip>
</el-table-column>
<el-table-column
prop="createTime"
:label="$t('commons.create_time')"
show-overflow-tooltip>
<template v-slot:default="scope">
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
</template>
</el-table-column>
<el-table-column
prop="endTime"
label="截止时间"
show-overflow-tooltip>
<template v-slot:default="scope">
<span>{{ scope.row.endTime | timestampFormatDate }}</span>
</template>
</el-table-column>
<el-table-column
:label="$t('commons.operating')">
<template v-slot:default="scope">
<ms-table-operator :is-tester-permission="true" @editClick="handleEdit(scope.row)"
@deleteClick="handleDelete(scope.row)">
<template v-slot:middle>
<ms-table-operator-button :isTesterPermission="true" type="success" tip="重新发起" icon="el-icon-document"
@exec="reCreate(scope.row)"/>
</template>
</ms-table-operator>
</template>
</el-table-column>
</el-table>
<ms-table-pagination :change="initTableData" :current-page.sync="currentPage" :page-size.sync="pageSize"
:total="total"/>
<ms-delete-confirm title="删除用例评审" @delete="_handleDelete" ref="deleteConfirm"/>
</el-card>
</template>
<script>
import MsDeleteConfirm from "../../../common/components/MsDeleteConfirm";
import MsTableOperator from "../../../common/components/MsTableOperator";
import MsTableOperatorButton from "../../../common/components/MsTableOperatorButton";
import MsDialogFooter from "../../../common/components/MsDialogFooter";
import MsTableHeader from "../../../common/components/MsTableHeader";
import MsCreateBox from "../../../settings/CreateBox";
import MsTablePagination from "../../../common/pagination/TablePagination";
import {_filter, _sort, checkoutTestManagerOrTestUser} from "../../../../../common/js/utils";
import PlanStatusTableItem from "../../common/tableItems/plan/PlanStatusTableItem";
export default {
name: "TestCaseReviewList",
components: {
MsDeleteConfirm,
MsTableOperator,
MsTableOperatorButton,
MsDialogFooter,
MsTableHeader,
MsCreateBox,
MsTablePagination,
PlanStatusTableItem
},
data() {
return {
result: {},
condition: {},
tableData: [],
isTestManagerOrTestUser: false,
currentPage: 1,
pageSize: 10,
total: 0,
statusFilters: [
{text: this.$t('test_track.plan.plan_status_prepare'), value: 'Prepare'},
{text: this.$t('test_track.plan.plan_status_running'), value: 'Underway'},
{text: this.$t('test_track.plan.plan_status_completed'), value: 'Completed'}
],
}
},
watch: {
'$route'(to) {
if (to.path.indexOf("/track/review/all") >= 0) {
this.initTableData();
}
}
},
created() {
this.isTestManagerOrTestUser = checkoutTestManagerOrTestUser();
this.initTableData();
},
methods: {
initTableData() {
this.result = this.$post("/test/case/review/list/" + this.currentPage + "/" + this.pageSize, this.condition, response => {
let data = response.data;
this.total = data.itemCount;
this.tableData = data.listObject;
for (let i = 0; i < this.tableData.length; i++) {
let path = "/test/case/review/project";
this.$post(path, {id: this.tableData[i].id}, res => {
let arr = res.data;
let projectName = arr.map(data => data.name).join("、");
let projectIds = arr.map(data => data.id);
this.$set(this.tableData[i], "projectName", projectName);
this.$set(this.tableData[i], "projectIds", projectIds);
});
this.$post('/test/case/review/reviewer', {id: this.tableData[i].id}, res => {
let arr = res.data;
let reviewer = arr.map(data => data.name).join("、");
let userIds = arr.map(data => data.id);
this.$set(this.tableData[i], "reviewer", reviewer);
this.$set(this.tableData[i], "userIds", userIds);
})
}
});
},
intoReview() {
},
testCaseReviewCreate() {
this.$emit('openCaseReviewEditDialog');
},
handleEdit(caseReview) {
this.$emit('caseReviewEdit', caseReview);
},
statusChange() {
},
handleDelete(caseReview) {
this.$refs.deleteConfirm.open(caseReview);
},
_handleDelete(caseReview) {
let reviewId = caseReview.id;
this.$get('/test/case/review/delete/' + reviewId, () => {
this.initTableData();
this.$success(this.$t('commons.delete_success'));
});
},
filter(filters) {
_filter(filters, this.condition);
this.initTableData();
},
sort(column) {
_sort(column, this.condition);
this.initTableData();
},
reCreate() {
}
}
}
</script>
<style scoped>
</style>

View File

@ -4,6 +4,7 @@ const TestTrack = () => import(/* webpackChunkName: "track" */ '@/business/compo
const TrackHome = () => import(/* webpackChunkName: "track" */ '@/business/components/track/home/TrackHome') const TrackHome = () => import(/* webpackChunkName: "track" */ '@/business/components/track/home/TrackHome')
const TestCase = () => import(/* webpackChunkName: "track" */ '@/business/components/track/case/TestCase') const TestCase = () => import(/* webpackChunkName: "track" */ '@/business/components/track/case/TestCase')
const TestPlan = () => import(/* webpackChunkName: "track" */ '@/business/components/track/plan/TestPlan') const TestPlan = () => import(/* webpackChunkName: "track" */ '@/business/components/track/plan/TestPlan')
const TestCaseReview = () => import(/* webpackChunkName: "track" */ '@/business/components/track/review/TestCaseReview')
const TestPlanView = () => import(/* webpackChunkName: "track" */ '@/business/components/track/plan/view/TestPlanView') const TestPlanView = () => import(/* webpackChunkName: "track" */ '@/business/components/track/plan/view/TestPlanView')
export default { export default {
@ -53,6 +54,11 @@ export default {
path: "project/:type", path: "project/:type",
name: "trackProject", name: "trackProject",
component: MsProject component: MsProject
} },
{
path: "review/:type",
name: "testCaseReview",
component: TestCaseReview
},
] ]
} }