1、需求详情前后端代码完善

2、缺陷管理详情前后端代码完善
This commit is contained in:
pfl
2025-05-30 17:58:46 +08:00
parent 606c3c15ea
commit c6a73afb76
27 changed files with 1011 additions and 9 deletions

View File

@@ -6,7 +6,10 @@ import com.test.common.core.domain.AjaxResult;
import com.test.common.core.page.TableDataInfo;
import com.test.common.enums.BusinessType;
import com.test.common.utils.poi.ExcelUtil;
import com.test.test.domain.TestPlan;
import com.test.test.domain.TestPlanDefect;
import com.test.test.domain.TestProject;
import com.test.test.domain.qo.IDQO;
import com.test.test.domain.qo.TestPlanDefectQO;
import com.test.test.domain.qo.TestPlanDefectRelQO;
import com.test.test.domain.vo.TestPlanDefectVo;
@@ -92,4 +95,26 @@ public class TestPlanDefectController extends BaseController
{
return toAjax(testPlanDefectService.deleteTestPlanDefectByIds(ids));
}
/**
* 查询缺陷关联测试计划列表
*/
@PostMapping("/defectPlanList")
public TableDataInfo defectPlanList(@RequestBody IDQO qo)
{
startPage();
List<TestPlan> list = testPlanDefectService.selectDefectPlanList(qo.getId());
return getDataTable(list);
}
/**
* 查询缺陷关联需求列表
*/
@PostMapping("/defectProjectList")
public TableDataInfo defectProjectList(@RequestBody IDQO qo)
{
startPage();
List<TestProject> list = testPlanDefectService.selectDefectProjectList(qo.getId());
return getDataTable(list);
}
}

View File

@@ -2,6 +2,8 @@ package com.test.test.controller;
import com.test.common.core.controller.BaseController;
import com.test.common.core.page.TableDataInfo;
import com.test.test.domain.TestCase;
import com.test.test.domain.TestDefect;
import com.test.test.domain.qo.IDQO;
import com.test.test.domain.vo.TestPlanProjectVo;
import com.test.test.service.ITestPlanProjectService;
@@ -36,4 +38,34 @@ public class TestPlanProjectController extends BaseController {
List<TestPlanProjectVo> list = testPlanProjectService.selectTestPlanProjectList(qo.getId());
return getDataTable(list);
}
/**
* 查询需求关联测试计划列表
*/
@PostMapping("/relatePlanList")
public TableDataInfo relatePlanList(@RequestBody IDQO qo) {
startPage();
List<TestPlanProjectVo> list = testPlanProjectService.selectRelatePlanList(qo.getId());
return getDataTable(list);
}
/**
* 查询需求关联用例列表
*/
@PostMapping("/relateCaseList")
public TableDataInfo relateCaseList(@RequestBody IDQO qo) {
startPage();
List<TestCase> list = testPlanProjectService.selectRelateCaseList(qo.getId());
return getDataTable(list);
}
/**
* 查询需求关联缺陷列表
*/
@PostMapping("/relateDefectList")
public TableDataInfo relateDefectList(@RequestBody IDQO qo) {
startPage();
List<TestDefect> list = testPlanProjectService.selectRelateDefectList(qo.getId());
return getDataTable(list);
}
}

View File

@@ -1,6 +1,7 @@
package com.test.test.mapper;
import com.test.test.domain.TestCase;
import com.test.test.domain.TestDefect;
import com.test.test.domain.qo.TestCaseListQO;
import java.util.List;
@@ -49,4 +50,9 @@ public interface TestCaseMapper
* 批量删除用例
*/
int deleteTestCaseByIds(Long[] ids);
/**
* 查询关联的用例列表
*/
List<TestCase> selectRelateCaseList(Long projectId);
}

View File

@@ -60,4 +60,9 @@ public interface TestDefectMapper
* @return 结果
*/
public int deleteTestDefectByIds(Long[] ids);
/**
* 查询关联的缺陷列表
*/
List<TestDefect> selectRelateDefectList(Long projectId);
}

View File

@@ -1,5 +1,6 @@
package com.test.test.mapper;
import com.test.test.domain.TestPlan;
import com.test.test.domain.TestPlanDefect;
import com.test.test.domain.qo.TestPlanDefectQO;
import com.test.test.domain.vo.TestPlanDefectVo;
@@ -67,4 +68,11 @@ public interface TestPlanDefectMapper
* @return
*/
List<TestPlanDefect> selectRelList(TestPlanDefect testPlanDefect);
/**
* 查询缺陷关联计划列表
* @param defectId
* @return
*/
List<TestPlan> selectDefectPlanList(Long defectId);
}

View File

@@ -40,5 +40,12 @@ public interface TestProjectMapper {
* @return
*/
int updateTestProject(TestProject testProject);
/**
* 查询缺陷关联的测试计划
* @param defectId
* @return
*/
List<TestProject> selectRelateProjectList(Long defectId);
}

View File

@@ -19,4 +19,11 @@ public interface TestProjectPlanMapper {
* @return
*/
List<TestPlanProjectVo> selectTestPlanProjectList(Long planId);
/**
* 查询需求关联计划列表
* @param projectId
* @return
*/
List<TestPlanProjectVo> selectRelatePlanList(Long projectId);
}

View File

@@ -1,7 +1,10 @@
package com.test.test.service;
import com.test.test.domain.TestPlan;
import com.test.test.domain.TestPlanDefect;
import com.test.test.domain.TestProject;
import com.test.test.domain.qo.IDQO;
import com.test.test.domain.qo.TestPlanDefectQO;
import com.test.test.domain.qo.TestPlanDefectRelQO;
import com.test.test.domain.vo.TestPlanDefectVo;
@@ -62,4 +65,18 @@ public interface ITestPlanDefectService
* @return 结果
*/
public int deleteTestPlanDefectById(Long id);
/**
* 查询缺陷关联的测试计划列表
* @param defectId
* @return
*/
List<TestPlan> selectDefectPlanList(Long defectId);
/**
* 查询缺陷关联的需求列表
* @param defectId
* @return
*/
List<TestProject> selectDefectProjectList(Long defectId);
}

View File

@@ -1,5 +1,7 @@
package com.test.test.service;
import com.test.test.domain.TestCase;
import com.test.test.domain.TestDefect;
import com.test.test.domain.vo.TestPlanProjectVo;
import java.util.List;
@@ -14,4 +16,25 @@ public interface ITestPlanProjectService {
* @return
*/
List<TestPlanProjectVo> selectTestPlanProjectList(Long planId);
/**
* 查询需求关联测试计划列表
* @param projectId
* @return
*/
List<TestPlanProjectVo> selectRelatePlanList(Long projectId);
/**
* 查询需求关联用例列表
* @param projectId
* @return
*/
List<TestCase> selectRelateCaseList(Long projectId);
/**
* 查询需求关联缺陷列表
* @param projectId
* @return
*/
List<TestDefect> selectRelateDefectList(Long projectId);
}

View File

@@ -1,11 +1,15 @@
package com.test.test.service.impl;
import com.test.common.utils.DateUtils;
import com.test.test.domain.TestPlan;
import com.test.test.domain.TestPlanDefect;
import com.test.test.domain.TestProject;
import com.test.test.domain.qo.IDQO;
import com.test.test.domain.qo.TestPlanDefectQO;
import com.test.test.domain.qo.TestPlanDefectRelQO;
import com.test.test.domain.vo.TestPlanDefectVo;
import com.test.test.mapper.TestPlanDefectMapper;
import com.test.test.mapper.TestProjectMapper;
import com.test.test.service.ITestPlanDefectService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@@ -25,6 +29,9 @@ public class TestPlanDefectServiceImpl implements ITestPlanDefectService
@Resource
private TestPlanDefectMapper testPlanDefectMapper;
@Resource
private TestProjectMapper testProjectMapper;
/**
* 查询测试计划测试缺陷关联
*
@@ -118,4 +125,24 @@ public class TestPlanDefectServiceImpl implements ITestPlanDefectService
{
return testPlanDefectMapper.deleteTestPlanDefectById(id);
}
/**
* 查询缺陷关联计划列表
* @param defectId
* @return
*/
@Override
public List<TestPlan> selectDefectPlanList(Long defectId) {
return testPlanDefectMapper.selectDefectPlanList(defectId);
}
/**
* 查询缺陷关联需求列表
* @param defectId
* @return
*/
@Override
public List<TestProject> selectDefectProjectList(Long defectId) {
return testProjectMapper.selectRelateProjectList(defectId);
}
}

View File

@@ -1,6 +1,10 @@
package com.test.test.service.impl;
import com.test.test.domain.TestCase;
import com.test.test.domain.TestDefect;
import com.test.test.domain.vo.TestPlanProjectVo;
import com.test.test.mapper.TestCaseMapper;
import com.test.test.mapper.TestDefectMapper;
import com.test.test.mapper.TestProjectPlanMapper;
import com.test.test.service.ITestPlanProjectService;
import jakarta.annotation.Resource;
@@ -18,6 +22,12 @@ public class TestPlanProjectServiceImpl implements ITestPlanProjectService {
@Resource
private TestProjectPlanMapper testProjectPlanMapper;
@Resource
private TestCaseMapper testCaseMapper;
@Resource
private TestDefectMapper testDefectMapper;
/**
* 查询测试计划需求关联列表
* @param planId
@@ -27,4 +37,34 @@ public class TestPlanProjectServiceImpl implements ITestPlanProjectService {
public List<TestPlanProjectVo> selectTestPlanProjectList(Long planId) {
return testProjectPlanMapper.selectTestPlanProjectList(planId);
}
/**
* 查询需求关联计划列表
* @param projectId
* @return
*/
@Override
public List<TestPlanProjectVo> selectRelatePlanList(Long projectId) {
return testProjectPlanMapper.selectRelatePlanList(projectId);
}
/**
* 查询需求关联用例列表
* @param projectId
* @return
*/
@Override
public List<TestCase> selectRelateCaseList(Long projectId) {
return testCaseMapper.selectRelateCaseList(projectId);
}
/**
* 查询需求关联缺陷列表
* @param projectId
* @return
*/
@Override
public List<TestDefect> selectRelateDefectList(Long projectId) {
return testDefectMapper.selectRelateDefectList(projectId);
}
}

View File

@@ -138,4 +138,24 @@
#{id}
</foreach>
</delete>
<select id="selectRelateCaseList" resultType="TestCase">
SELECT DISTINCT
tc.id,
tc.group_id,
tc.project_id,
tc.name,
tc.importance,
tc.status,
tc.del_flag,
tc.create_by AS createBy,
tc.create_time,
tc.update_by,
tc.update_time
FROM test_project_plan tpp
LEFT JOIN test_plan_case tpc ON tpc.plan_id = tpp.plan_id
LEFT JOIN test_case tc ON tc.id = tpc.case_id
WHERE tpp.project_id = #{projectId}
AND tpc.del_flag = '0'
</select>
</mapper>

View File

@@ -148,4 +148,30 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
#{id}
</foreach>
</delete>
<select id="selectRelateDefectList" resultType="TestDefect">
SELECT DISTINCT
td.id,
td.serial_number AS serialNumber,
td.name,
td.outline,
td.detail,
td.status,
su.user_name AS manager,
td.dev,
td.level,
td.type,
td.reappearance,
td.test,
td.mail,
td.version,
td.del_flag,
td.create_time AS createTime
FROM test_project_plan tpp
LEFT JOIN test_plan_defect tpd ON tpd.plan_id = tpp.plan_id
LEFT JOIN test_defect td ON td.id = tpd.defect_id
LEFT JOIN sys_user su ON su.user_id = td.manager
WHERE tpp.project_id = #{projectId}
AND tpd.del_flag = '0'
</select>
</mapper>

View File

@@ -74,7 +74,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</if>
</select>
<insert id="insertTestPlanDefect" parameterType="TestPlanDefect">
<insert id="insertTestPlanDefect" parameterType="TestPlanDefect">
insert into test_plan_defect
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">id,</if>
@@ -124,4 +124,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
#{id}
</foreach>
</delete>
<select id="selectDefectPlanList" resultType="TestPlan">
SELECT DISTINCT
tp.id,
tp.serial_number AS serialNumber,
tp.name ,
tp.status,
su.user_name AS manager,
tp.create_time AS createTime,
tp.version,
tp.del_flag
FROM test_plan_defect tpd
LEFT JOIN test_plan tp ON tp.id = tpd.plan_id
LEFT JOIN sys_user su ON su.user_id = tp.manager
WHERE tpd.defect_id = #{defectId}
AND tpd.del_flag = '0'
</select>
</mapper>

View File

@@ -155,4 +155,28 @@
<include refid="selectTestProjectVo"/>
WHERE id = #{id}
</select>
<select id="selectRelateProjectList" resultType="TestProject">
SELECT DISTINCT
tp.id,
tp.serial_number AS serialNumber,
tp.name,
tp.outline,
tp.detail,
tp.priority,
tp.estimated_time AS estimatedTime,
tp.source,
tp.type,
tp.status,
su.user_name AS manager,
tp.create_time AS createTime,
tp.version,
tp.del_flag
FROM test_plan_defect tpd
LEFT JOIN test_project_plan tpp ON tpp.plan_id = tpd.plan_id
LEFT JOIN test_project tp ON tp.id = tpp.project_id
LEFT JOIN sys_user su ON su.user_id = tp.manager
WHERE tpd.defect_id = #{defectId}
AND tpp.del_flag = '0'
</select>
</mapper>

View File

@@ -45,4 +45,21 @@
WHERE tpp.plan_id = #{planId}
AND tpp.del_flag = '0'
</select>
<select id="selectRelatePlanList" resultType="TestPlanProjectVo">
SELECT
tp.id,
tp.serial_number AS serialNumber,
tp.name ,
tp.status,
su.user_name AS manager,
tp.create_time AS createTime,
tp.version,
tp.del_flag
FROM test_project_plan tpp
LEFT JOIN test_plan tp ON tp.id = tpp.plan_id
LEFT JOIN sys_user su ON su.user_id = tp.manager
WHERE tpp.project_id = #{projectId}
AND tpp.del_flag = '0'
</select>
</mapper>

View File

@@ -5,7 +5,9 @@ const api = {
addBug: 'test/defect/addBug',
delBug: 'test/defect/delBug',
getBugDetail: 'test/defect/bugDetail',
updateBug: 'test/defect/editBug'
updateBug: 'test/defect/editBug',
getDefectPlanList: 'testPlan/defect/defectPlanList',
getDefectProjectList: 'testPlan/defect/defectProjectList',
}
export function getBugList(data) {
@@ -49,3 +51,19 @@ export function updateBug(data) {
})
}
export function getDefectPlanList(id) {
return request({
url: api.getDefectPlanList,
method: 'post',
data: {id}
})
}
export function getDefectProjectList(id) {
return request({
url: api.getDefectProjectList,
method: 'post',
data: {id}
})
}

View File

@@ -6,7 +6,10 @@ const api = {
addProject: 'test/project/addProject',
delProject: 'test/project/delProject',
getProjectDetail: 'test/project/projectDetail',
updateProject: 'test/project/editProject'
updateProject: 'test/project/editProject',
relatePlanList: 'test/testPlanProject/relatePlanList',
relateCaseList: 'test/testPlanProject/relateCaseList',
relateDefectList: 'test/testPlanProject/relateDefectList',
}
export function managerList(data) {
@@ -58,3 +61,27 @@ export function updateProject(data) {
})
}
export function getRelatePlanList(id) {
return request({
url: api.relatePlanList,
method: 'post',
data: {id}
})
}
export function getRelateCaseTableList(id) {
return request({
url: api.relateCaseList,
method: 'post',
data: {id}
})
}
export function getRelateDefectList(id) {
return request({
url: api.relateDefectList,
method: 'post',
data: {id}
})
}

View File

@@ -0,0 +1,136 @@
<template>
<div class="app-container">
<el-form ref="detailForm" :model="detailForm" label-width="110px" label-position="right">
<el-container>
<el-main>
<el-form-item label="缺陷概要" prop="outline">
{{ detailForm.outline }}
</el-form-item>
<!-- 描述 -->
<el-form-item label="描述" prop="detail">
{{ detailForm.detail }}
</el-form-item>
</el-main>
<el-aside width="450px" class="basic-information">
<h3>基础信息</h3>
<el-form-item label="缺陷ID" prop="serialNumber">
{{detailForm.serialNumber}}
</el-form-item>
<el-form-item label="缺陷名称" prop="name">
{{ detailForm.name }}
</el-form-item>
<el-form-item label="经办人" prop="manager">
{{ managerName }}
</el-form-item>
<el-form-item label="严重程度" prop="level">
{{ detailForm.level }}
</el-form-item>
<el-form-item label="缺陷类型" prop="type">
{{ detailForm.type }}
</el-form-item>
<el-form-item label="缺陷状态" prop="status">
{{ detailForm.status }}
</el-form-item>
<el-form-item label="能否复现" prop="reappearance">
{{ reappearanceLabel }}
</el-form-item>
<el-form-item label="开发人" prop="dev">
{{ detailForm.dev }}
</el-form-item>
<el-form-item label="测试人" prop="test">
{{ detailForm.test }}
</el-form-item>
<el-form-item label="版本" prop="version">
{{ detailForm.version }}
</el-form-item>
</el-aside>
</el-container>
</el-form>
</div>
</template>
<script>
import SimpleOptions from "@/components/FormItem/option/SimpleOptions.vue";
import {getBugDetail} from "@/api/test/bug";
export default {
name: 'bugDetail',
components: {SimpleOptions},
dicts: ['severity_level', 'bug_type', 'bug_status'],
props: {
defectId: {
type: Number,
default: 0,
},
managerName: {
type: String,
default: ''
},
managerList: {
type: Array,
default: () => []
}
},
data() {
return {
reappearanceOptions: [{
value: '0',
label: '必然复现'
}, {
value: '1',
label: '偶发复现'
}],
managerList: [],
detailForm: {
outline: '',
detail: '',
serialNumber: '',
name: '',
manager: '',
level: '',
type: '',
status: '',
reappearance: '',
dev: '',
test: '',
version: '',
},
}
},
computed: {
reappearanceLabel() {
const option = this.reappearanceOptions.find(
(opt) => opt.value === this.detailForm.reappearance
);
return option ? option.label : '';
},
},
watch: {
defectId(newVal){
this.getDetail()
}
},
methods: {
getDetail() {
getBugDetail(this.defectId).then(res => {
this.detailForm = res.data;
this.detailForm.level = this.dict.type.severity_level.find(e => e.value === res.data.level).label;
this.detailForm.type = this.dict.type.bug_type.find(e => e.value === res.data.type).label;
this.detailForm.status = this.dict.type.bug_status.find(e => e.value === res.data.status).label;
this.detailForm.dev = this.managerList.find(e => e.value === parseInt(res.data.dev,10)).label;
this.detailForm.test = this.managerList.find(e => e.value === parseInt(res.data.test,10)).label;
})
}
}
}
</script>
<style scoped lang="scss">
.basic-information {
background-color: rgb(248, 248, 249) !important;
}
</style>

View File

@@ -0,0 +1,65 @@
<template>
<div class="app-container">
<el-table v-loading="loading" :data="list" height="500">
<el-table-column prop="statusLabel" label="状态" width="180"></el-table-column>
<el-table-column prop="name" label="计划名称"></el-table-column>
<el-table-column prop="manager" label="负责人"></el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList"></pagination>
</div>
</template>
<script>
import {getDefectPlanList} from "@/api/test/bug";
export default {
name: 'defectPlan',
dicts: ['status'],
props: {
defectId: {
type: Number,
default: '',
},
},
data() {
return {
// 遮罩层
loading: true,
// 总条数
total: 0,
// 表格数据
list: [],
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10
}
}
},
watch: {
defectId(newVal){
this.getList()
}
},
methods: {
getList() {
this.loading = true;
getDefectPlanList(this.defectId).then(response => {
this.list = response.rows.map(item => {
const matched = this.dict.type.status.find(e => e.value === item.status);
return {
...item,
statusLabel: matched ? matched.label : '未知状态'
};
});
this.total = response.total;
this.loading = false;
})
},
}
}
</script>
<style scoped lang="scss">
</style>

View File

@@ -0,0 +1,74 @@
<template>
<div class="app-container">
<el-Table v-loading="loading" :data="list" height="500">
<el-table-column prop="serialNumber" label="ID" align="center"/>
<el-table-column prop="version" label="版本" align="center"/>
<el-table-column prop="outline" label="概要" align="center"/>
<el-table-column prop="priority" label="优先级" align="center">
<template slot-scope="scope">
<el-tag :type="priorityColor[scope.row.priority]">{{ scope.row.priority }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" align="center">
<template #default="{ row }">
<dict-tag :options="dict.type.status" :value="row.status"/>
</template>
</el-table-column>
<el-table-column prop="manager" label="负责人" align="center"/>
<el-table-column prop="createTime" label="创建时间" align="center"/>
</el-Table>
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList"/>
</div>
</template>
<script>
import {getDefectProjectList} from "@/api/test/bug";
export default {
name: 'defectProject',
dicts: ['priority_level', 'project_source', 'project_type', 'status'],
props: {
defectId: {
type: Number,
default: '',
},
},
data() {
return {
list: [],
loading: false,
total: 0,
priorityColor: {
'P0': 'danger',
'P1': 'warning',
'P2': 'info',
'P3': 'success',
},
queryParams: {
pageNum: 1,
pageSize: 10,
}
}
},
watch: {
defectId(newVal){
this.getList()
}
},
methods: {
getList() {
this.loading = true
getDefectProjectList(this.defectId).then(response => {
this.list = response.rows
this.total = response.total
this.loading = false
})
}
}
}
</script>
<style scoped lang="scss">
</style>

View File

@@ -62,7 +62,7 @@
</el-collapse>
<!-- 标签页 -->
<el-Table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
<el-Table v-loading="loading" :data="list" @selection-change="handleSelectionChange" @row-click="handleRowClick">
<el-table-column type="selection"/>
<el-table-column prop="serialNumber" label="ID" align="center"/>
<el-table-column prop="outline" label="概要" align="center"/>
@@ -80,7 +80,7 @@
<el-table-column prop="createTime" label="创建时间" align="center"/>
<el-table-column label="操作" align="left" fixed="right">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleEdit(scope.row.id)">编辑</el-button>
<el-button size="mini" type="text" icon="el-icon-edit" @click.native.stop="handleEdit(scope.row.id)">编辑</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click.native.stop="handleDelete(scope.row.id)">删除
</el-button>
</template>
@@ -237,6 +237,25 @@
<el-button type="primary" @click="editSubmitForm"> </el-button>
</span>
</el-dialog>
<el-dialog :visible.sync="detailOpen" width="90%">
<template #title>
<div class="detail-title">
<el-row>
<span>查看缺陷-{{ title }}</span>
<el-menu :default-active="activeIndex" class="el-menu-demo" mode="horizontal" @select="handleSelect">
<el-menu-item index="1">缺陷详情</el-menu-item>
<el-menu-item index="2">缺陷动态</el-menu-item>
<el-menu-item index="3">已关联测试计划</el-menu-item>
<el-menu-item index="4">已关联需求</el-menu-item>
</el-menu>
</el-row>
<bug-detail :managerList="managerList" :managerName="managerName" :defectId="defectId" v-show="activeIndex === '1'"></bug-detail>
<defect-plan :defectId="defectId" v-show="activeIndex === '3'"></defect-plan>
<defect-project :defectId="defectId" v-show="activeIndex === '4'"></defect-project>
</div>
</template>
</el-dialog>
</div>
</template>
@@ -245,10 +264,13 @@ import {managerList} from "@/api/test/project";
import {addBug, delBug, getBugDetail, getBugList, updateBug} from "@/api/test/bug";
import SimpleOptions from "@/components/FormItem/option/SimpleOptions.vue";
import {requestDownload} from "@/utils/request";
import BugDetail from "@/views/test/bug/components/bugDetail.vue";
import DefectPlan from "@/views/test/bug/components/defectPlan.vue";
import DefectProject from "@/views/test/bug/components/defectProject.vue";
export default {
name: 'defect',
components: {SimpleOptions},
components: {DefectProject, DefectPlan, BugDetail, SimpleOptions},
dicts: ['severity_level', 'bug_type', 'bug_status'],
data() {
return {
@@ -294,6 +316,10 @@ export default {
addOpen: false,
//编辑弹窗
editOpen: false,
detailOpen: false,
activeIndex: '1',
defectId: 0,
managerName: '',
selectedRows: [],
selectedData: [],
managerList: [],
@@ -336,6 +362,16 @@ export default {
},
},
methods: {
handleRowClick(row) {
this.defectId = row.id
this.activeIndex = '1'
this.managerName = row.manager
this.detailOpen = true;
this.title = row.serialNumber;
},
handleSelect(key) {
this.activeIndex = key
},
handleSelectionChange(selection) {
this.selectedRows = selection;
},
@@ -437,6 +473,8 @@ export default {
getBugDetail(id).then((res) => {
this.editForm = res.data
this.editForm.manager = parseInt(res.data.manager, 10);
this.editForm.dev = parseInt(res.data.dev, 10);
this.editForm.test = parseInt(res.data.test, 10);
this.editOpen = true
})
},

View File

@@ -71,7 +71,7 @@
<el-tab-pane :label="'已完成(' + statusCounts.completed + ')'" name="2"></el-tab-pane>
<el-tab-pane :label="'已终止(' + statusCounts.terminated + ')'" name="3"></el-tab-pane>
<el-Table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
<el-Table v-loading="loading" :data="list" @selection-change="handleSelectionChange" @row-click="handleRowClick">
<el-table-column type="selection"/>
<el-table-column prop="serialNumber" label="ID" align="center"/>
<el-table-column prop="version" label="版本" align="center"/>
@@ -90,7 +90,7 @@
<el-table-column prop="createTime" label="创建时间" align="center"/>
<el-table-column label="操作" align="left" fixed="right">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleEdit(scope.row.id)">编辑</el-button>
<el-button size="mini" type="text" icon="el-icon-edit" @click.native.stop="handleEdit(scope.row.id)">编辑</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click.native.stop="handleDelete(scope.row.id)">删除
</el-button>
</template>
@@ -234,6 +234,32 @@
<el-button type="primary" @click="editSubmitForm"> </el-button>
</span>
</el-dialog>
<el-dialog :visible.sync="detailOpen" width="90%">
<template #title>
<div class="detail-title">
<el-row>
<span>查看需求-{{ title }}</span>
<el-menu :default-active="activeIndex" class="el-menu-demo" mode="horizontal" @select="handleSelect">
<el-menu-item index="1">需求详情</el-menu-item>
<el-menu-item index="2">需求动态</el-menu-item>
<el-menu-item index="3">已关联测试计划</el-menu-item>
<el-menu-item index="4">已关联用例</el-menu-item>
<el-menu-item index="5">已关联缺陷</el-menu-item>
<el-menu-item index="6">评审</el-menu-item>
</el-menu>
</el-row>
<project-detail :managerName="managerName" :projectId="projectId" v-show="activeIndex === '1'"></project-detail>
<relate-plan :projectId="projectId" v-show="activeIndex === '3'"></relate-plan>
<relateCaseTable :projectId="projectId" v-show="activeIndex === '4'"></relateCaseTable>
<relateDefectTable :projectId="projectId" v-show="activeIndex === '5'"></relateDefectTable>
</div>
</template>
<span slot="footer" class="dialog-footer">
<el-button @click="detailOpen = false"> </el-button>
</span>
</el-dialog>
</div>
</template>
@@ -241,10 +267,14 @@
import {addProject, delProject, getProjectDetail, getProjectList, managerList, updateProject} from "@/api/test/project";
import SimpleOptions from "@/components/FormItem/option/SimpleOptions.vue";
import {requestDownload} from "@/utils/request";
import ProjectDetail from "@/views/test/project/projectDetail/projectDetail.vue";
import RelatePlan from "@/views/test/project/projectDetail/relatePlan.vue";
import RelateCaseTable from "@/views/test/project/projectDetail/relateCaseTable.vue";
import RelateDefectTable from "@/views/test/project/projectDetail/relateDefectTable.vue";
export default {
name: 'project',
components: {SimpleOptions},
components: {RelatePlan, ProjectDetail, SimpleOptions , RelateCaseTable , RelateDefectTable},
dicts: ['priority_level', 'project_source', 'project_type', 'status'],
data() {
return {
@@ -281,6 +311,8 @@ export default {
total: 0,
list: [],
title: '',
projectId: 0,
managerName: '',
// 遮罩层
loading: false,
editSubmitLoading: false,
@@ -289,9 +321,11 @@ export default {
addOpen: false,
//编辑弹窗
editOpen: false,
detailOpen: false,
selectedRows: [],
selectedData: [],
managerList: [],
activeIndex: '1',
queryParams: {
serialNumber: '',
outline: '',
@@ -327,6 +361,16 @@ export default {
},
},
methods: {
handleRowClick(row) {
this.projectId = row.id
this.activeIndex = '1'
this.managerName = row.manager
this.detailOpen = true;
this.title = row.serialNumber;
},
handleSelect(key) {
this.activeIndex = key
},
handleSelectionChange(selection) {
this.selectedRows = selection;
},

View File

@@ -0,0 +1,109 @@
<template>
<div class="project-detail">
<el-form ref="editForm" :model="detailForm" label-width="110px" label-position="right">
<el-container>
<el-main>
<el-form-item label="需求概要" prop="outline">
{{ detailForm.outline }}
</el-form-item>
<!-- 描述 -->
<el-form-item label="描述" prop="detail">
{{ detailForm.detail }}
</el-form-item>
</el-main>
<el-aside width="450px" class="basic-information">
<h3>基础信息</h3>
<el-form-item label="需求名称" prop="name">
{{ detailForm.name }}
</el-form-item>
<el-form-item label="状态" prop="status">
{{ detailForm.status }}
</el-form-item>
<el-form-item label="负责人" prop="manager">
{{ managerName }}
</el-form-item>
<el-form-item label="优先级" prop="priority">
{{ detailForm.priority }}
</el-form-item>
<el-form-item label="预期完成时间" prop="estimatedTime">
{{ detailForm.estimatedTime }}
</el-form-item>
<el-form-item label="需求来源" prop="source">
{{ detailForm.source }}
</el-form-item>
<el-form-item label="需求类型" prop="type">
{{ detailForm.type }}
</el-form-item>
<el-form-item label="版本" prop="version">
{{ detailForm.version }}
</el-form-item>
</el-aside>
</el-container>
</el-form>
</div>
</template>
<script>
import SimpleOptions from "@/components/FormItem/option/SimpleOptions.vue";
import {getProjectDetail} from "@/api/test/project";
export default {
name: 'projectDetail',
components: {SimpleOptions},
dicts: ['priority_level', 'project_source', 'project_type', 'status'],
props: {
projectId: {
type: Number,
default: 0,
},
managerName: {
type: String,
default: ''
}
},
data() {
return {
detailForm: {
outline: '',
detail: '',
name: '',
status: '',
manager: '',
priority: '',
estimatedTime: '',
source: '',
type: '',
version: ''
},
managerList: [],
editOpen: false,
};
},
created() {
},
watch: {
projectId(newVal){
this.getDetail()
}
},
methods: {
getDetail() {
getProjectDetail(this.projectId).then(res => {
this.detailForm = res.data;
this.detailForm.source = this.dict.type.project_source.find(e => e.value === res.data.source).label;
this.detailForm.type = this.dict.type.project_type.find(e => e.value === res.data.type).label;
this.detailForm.status = this.dict.type.status.find(e => e.value === res.data.status).label;
});
}
}
}
</script>
<style lang="scss" scoped>
.basic-information {
background-color: rgb(248, 248, 249) !important;
}
</style>

View File

@@ -0,0 +1,54 @@
<template>
<div class="app-container">
<el-table v-loading="loading" :data="list" height="500">
<el-table-column prop="name" label="用例名称"></el-table-column>
<el-table-column prop="status" label="用例状态" :formatter="row => ['','草稿', '通过', '不通过'][row.status]"></el-table-column>
<el-table-column prop="createBy" label="创建人"></el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList"/>
</div>
</template>
<script>
import {getRelateCaseTableList} from "@/api/test/project";
export default {
name: 'relateCaseTable',
props: {
projectId: {
type: Number,
default: '',
},
},
data() {
return {
loading: false,
list: [],
total: 0,
queryParams: {
pageNum: 1,
pageSize: 10,
},
}
},
watch: {
projectId(newVal){
this.getList()
}
},
methods: {
getList() {
this.loading = true
getRelateCaseTableList(this.projectId).then(res => {
this.list = res.rows
this.total = res.total
this.loading = false
})
}
},
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,73 @@
<template>
<div class="app-container">
<el-table v-loading="loading" :data="list" height="500">
<el-table-column prop="serialNumber" label="ID"></el-table-column>
<el-table-column prop="outline" label="摘要"></el-table-column>
<el-table-column prop="status" label="缺陷状态">
<template #default="{ row }">
<dict-tag :options="dict.type.bug_status" :value="row.status"/>
</template>
</el-table-column>
<el-table-column prop="manager" label="经办人"></el-table-column>
<el-table-column prop="level" label="严重程度">
<template #default="{ row }">
<dict-tag :options="dict.type.severity_level" :value="row.level"/>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间"></el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList"/>
</div>
</template>
<script>
import {getRelateDefectList} from "@/api/test/project";
export default {
name: 'relateCaseTable',
props: {
projectId: {
type: Number,
default: '',
},
},
dicts: ['severity_level', 'bug_status'],
data() {
return {
// 遮罩层
loading: true,
// 总条数
total: 0,
// 表格数据
list: [],
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
}
}
},
watch: {
projectId(newVal){
this.getList()
}
},
methods: {
getList() {
this.loading = true
getRelateDefectList(this.projectId).then(response => {
this.list = response.rows
this.total = response.total
this.loading = false
})
}
},
}
</script>
<style scoped lang="scss">
</style>

View File

@@ -0,0 +1,63 @@
<template>
<div class="app-container">
<el-table v-loading="loading" :data="list" height="500">
<el-table-column prop="statusLabel" label="状态" width="180"></el-table-column>
<el-table-column prop="name" label="计划名称"></el-table-column>
<el-table-column prop="manager" label="负责人"></el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList"></pagination>
</div>
</template>
<script>
import {getRelatePlanList} from "@/api/test/project";
export default {
name: 'relatePlan',
dicts: ['status'],
props: {
projectId: {
type: Number,
default: '',
},
},
data() {
return {
list: [],
loading: false,
total: 0,
queryParams: {
pageNum: 1,
pageSize: 10,
},
}
},
watch: {
projectId(newVal){
this.getList()
}
},
methods: {
getList() {
this.loading = true;
getRelatePlanList(this.projectId).then(response => {
this.list = response.rows.map(item => {
const matched = this.dict.type.status.find(e => e.value === item.status);
return {
...item,
statusLabel: matched ? matched.label : '未知状态'
};
});
this.total = response.total;
this.loading = false;
})
},
}
}
</script>
<style lang="scss" scoped>
</style>