feat(测试跟踪): 测试计划评审缺陷列表添加筛选排序

--story=1007020 --user=陈建星 #12422测试用例自定义字段没有筛选功能 https://www.tapd.cn/55049933/s/1195547
This commit is contained in:
chenjianxing 2022-07-06 17:30:07 +08:00 committed by f2c-ci-robot[bot]
parent a027c4771e
commit bad796ed64
13 changed files with 374 additions and 310 deletions

View File

@ -102,29 +102,31 @@
<if test="request.projectId != null"> <if test="request.projectId != null">
and test_case_review.project_id = #{request.projectId} and test_case_review.project_id = #{request.projectId}
</if> </if>
<if test="request.filters != null and request.filters.size() > 0"> <include refid="filter"/>
<foreach collection="request.filters.entrySet()" index="key" item="values">
<if test="values != null and values.size() > 0">
<choose>
<when test="key=='stage'">
and test_case_review.stage in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<otherwise>
and test_case_review.status in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</otherwise>
</choose>
</if>
</foreach>
</if>
</where> </where>
</sql> </sql>
<sql id="filter">
<if test="request.filters != null and request.filters.size() > 0">
<foreach collection="request.filters.entrySet()" index="key" item="values">
<if test="values != null and values.size() > 0">
<choose>
<when test="key=='stage'">
and test_case_review.stage in
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.filterInWrapper"/>
</when>
<when test="key=='status'">
and test_case_review.status in
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.filterInWrapper"/>
</when>
<when test="key=='creator_name'">
and test_case_review.creator in
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.filterInWrapper"/>
</when>
</choose>
</if>
</foreach>
</if>
</sql>
<select id="listByWorkspaceId" resultType="io.metersphere.track.dto.TestCaseReviewDTO" <select id="listByWorkspaceId" resultType="io.metersphere.track.dto.TestCaseReviewDTO"
parameterType="io.metersphere.track.request.testreview.QueryCaseReviewRequest"> parameterType="io.metersphere.track.request.testreview.QueryCaseReviewRequest">
select distinct test_case_review.* select distinct test_case_review.*

View File

@ -15,8 +15,6 @@ import java.util.Set;
public interface ExtTestPlanMapper { public interface ExtTestPlanMapper {
List<TestPlanDTOWithMetric> list(@Param("request") QueryTestPlanRequest params); List<TestPlanDTOWithMetric> list(@Param("request") QueryTestPlanRequest params);
List<TestPlanDTOWithMetric> listRelate(@Param("request") QueryTestPlanRequest params);
List<TestPlanDTO> planList(@Param("request") QueryTestPlanRequest params); List<TestPlanDTO> planList(@Param("request") QueryTestPlanRequest params);
List<TestPlanDTO> selectByIds(@Param("list") List<String> ids); List<TestPlanDTO> selectByIds(@Param("list") List<String> ids);

View File

@ -180,67 +180,7 @@
<if test="request.id != null"> <if test="request.id != null">
AND test_plan.id = #{request.id} AND test_plan.id = #{request.id}
</if> </if>
<if test="request.filters != null and request.filters.size() > 0"> <include refid="filter"/>
<foreach collection="request.filters.entrySet()" index="key" item="values">
<if test="values != null and values.size() > 0">
<choose>
<when test="key=='stage'">
and test_plan.stage in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
and test_plan.status != 'Archived'
</when>
<when test="key=='status'">
<choose>
<when test="request.executorOrPrincipal != null">
AND (( test_plan_principal.principal_id =
'${@io.metersphere.commons.utils.SessionUtils@getUserId()}' and
test_plan.status in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
)
or
(test_plan_test_case.executor =
'${@io.metersphere.commons.utils.SessionUtils@getUserId()}' and
test_plan_test_case.status in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
))
AND test_plan.status != 'Archived'
</when>
<otherwise>
and test_plan.status in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</otherwise>
</choose>
</when>
<when test="key=='schedule_status'">
and
<foreach collection="values" item="value" separator="or" open="(" close=")">
<if test="value == 'OPEN'">
schedule.`enable` = 1
</if>
<if test="value == 'SHUT'">
schedule.`enable` = 0
</if>
<if test="value == 'NOTSET' ">
schedule.id is null
</if>
</foreach>
and test_plan.status != 'Archived'
</when>
</choose>
</if>
<if test="(values == null or values.size() == 0) and request.filters.get('status') == null">
and test_plan.status != 'Archived'
</if>
</foreach>
</if>
<if test="(request.filters == null or request.filters.size() == 0) and request.byFilter != true "> <if test="(request.filters == null or request.filters.size() == 0) and request.byFilter != true ">
and test_plan.status != 'Archived' and test_plan.status != 'Archived'
</if> </if>
@ -258,9 +198,71 @@
test_plan.${order.name} ${order.type} test_plan.${order.name} ${order.type}
</foreach> </foreach>
</if> </if>
</select> </select>
<sql id="filter">
<if test="request.filters != null and request.filters.size() > 0">
<foreach collection="request.filters.entrySet()" index="key" item="values">
<if test="values != null and values.size() > 0">
<choose>
<when test="key=='status'">
<choose>
<when test="request.executorOrPrincipal != null">
AND (( test_plan_principal.principal_id =
'${@io.metersphere.commons.utils.SessionUtils@getUserId()}' and
test_plan.status in
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.filterInWrapper"/>
)
or
(test_plan_test_case.executor =
'${@io.metersphere.commons.utils.SessionUtils@getUserId()}' and
test_plan_test_case.status in
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.filterInWrapper"/>
))
AND test_plan.status != 'Archived'
</when>
<otherwise>
and test_plan.status in
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.filterInWrapper"/>
</otherwise>
</choose>
</when>
<otherwise>
<choose>
<when test="key=='stage'">
and test_plan.stage in
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.filterInWrapper"/>
</when>
<when test="key=='create_user'">
and test_plan.creator in
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.filterInWrapper"/>
</when>
<when test="key=='schedule_status'">
and
<foreach collection="values" item="value" separator="or" open="(" close=")">
<if test="value == 'OPEN'">
schedule.`enable` = 1
</if>
<if test="value == 'SHUT'">
schedule.`enable` = 0
</if>
<if test="value == 'NOTSET' ">
schedule.id is null
</if>
</foreach>
</when>
</choose>
and test_plan.status != 'Archived'
</otherwise>
</choose>
</if>
<if test="(values == null or values.size() == 0) and request.filters.get('status') == null">
and test_plan.status != 'Archived'
</if>
</foreach>
</if>
</sql>
<select id="planList" resultMap="BaseResultMap" <select id="planList" resultMap="BaseResultMap"
parameterType="io.metersphere.track.request.testcase.QueryTestPlanRequest"> parameterType="io.metersphere.track.request.testcase.QueryTestPlanRequest">
SELECT * FROM test_plan p LEFT JOIN test_plan_project t ON t.test_plan_id=p.ID SELECT * FROM test_plan p LEFT JOIN test_plan_project t ON t.test_plan_id=p.ID
@ -274,25 +276,6 @@
</where> </where>
</select> </select>
<select id="listRelate" resultType="io.metersphere.track.dto.TestPlanDTOWithMetric">
select distinct test_plan.* from test_plan
<where>
test_plan.workspace_id = #{request.workspaceId}
<if test="request.projectId != null">
and test_plan.project_id = #{request.projectId}
</if>
and (test_plan.principal = #{request.principal}
<if test="request.planIds != null and request.planIds.size() > 0">
or test_plan.id in
<foreach collection="request.planIds" item="planId" open="(" close=")" separator=",">
#{planId}
</foreach>
</if>
)
</where>
order by test_plan.update_time desc
</select>
<select id="selectByIds" resultMap="BaseResultMap" parameterType="java.util.List"> <select id="selectByIds" resultMap="BaseResultMap" parameterType="java.util.List">
SELECT * FROM test_plan p where p.id in SELECT * FROM test_plan p where p.id in
<foreach collection="list" item="planId" open="(" close=")" separator=","> <foreach collection="list" item="planId" open="(" close=")" separator=",">

View File

@ -0,0 +1,34 @@
<template>
<span>
<el-tooltip :content="$t('commons.follow')" placement="bottom" effect="dark"
v-if="!row.showFollow">
<i class="el-icon-star-off"
style="color: #783987; font-size: 25px; padding-left: 5px;top: 5px; position: relative; cursor: pointer;width: 28px;height: 28px;"
@click="saveFollow(row)"></i>
</el-tooltip>
<el-tooltip :content="$t('commons.cancel')" placement="bottom" effect="dark"
v-if="row.showFollow">
<i class="el-icon-star-on"
style="color: #783987; font-size: 30px;padding-left: 5px; top: 5px; position: relative; cursor: pointer;width: 28px;height: 28px; "
@click="saveFollow(row)"></i>
</el-tooltip>
</span>
</template>
<script>
export default {
name: "MsTableFollowOperator",
props: {
row: Object
},
methods: {
saveFollow(row) {
this.$emit('saveFollow', row);
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,32 @@
<template>
<ms-table-column
prop="tags"
:field="field"
:fields-width="fieldsWidth"
sortable
:label="$t('api_test.automation.tag')"
min-width="200px">
<template v-slot:default="scope">
<ms-tag v-for="(name, index) in scope.row.tags" :key="index" type="success" effect="plain"
:content="name" style="margin-left: 0px; margin-right: 2px"/>
<span/>
</template>
</ms-table-column>
</template>
<script>
import MsTableColumn from "@/business/components/common/components/table/MsTableColumn";
import MsTag from "@/business/components/common/components/MsTag";
export default {
name: "MsTagsColumn",
components: {MsTag, MsTableColumn},
props: {
field: Object,
fieldsWidth: Object,
}
}
</script>
<style scoped>
</style>

View File

@ -91,11 +91,13 @@
</ms-table-column> </ms-table-column>
<ms-table-column <ms-table-column
sortable
prop="createName" prop="createName"
min-width="120"
:field="item" :field="item"
:fields-width="fieldsWidth" :fields-width="fieldsWidth"
:label="$t('commons.create_user')" :label="$t('commons.create_user')"
min-width="120"/> :filters="userFilter"/>
<test-case-review-status-table-item <test-case-review-status-table-item
:field="item" :field="item"
@ -175,10 +177,10 @@
<template v-slot="scope"> <template v-slot="scope">
<span v-if="field.name === '用例等级'"> <span v-if="field.name === '用例等级'">
<priority-table-item <priority-table-item
:value="getCustomFieldValue(scope.row, field) ? getCustomFieldValue(scope.row, field) : scope.row.priority"/> :value="getCustomFieldValue(scope.row, field, scope.row.priority)"/>
</span> </span>
<span v-else-if="field.name === '用例状态'"> <span v-else-if="field.name === '用例状态'">
{{ getCustomFieldValue(scope.row, field) ? getCustomFieldValue(scope.row, field) : scope.row.status }} {{ getCustomFieldValue(scope.row, field, scope.row.status)}}
</span> </span>
<span v-else> <span v-else>
{{ getCustomFieldValue(scope.row, field) }} {{ getCustomFieldValue(scope.row, field) }}
@ -236,7 +238,7 @@ import ApiStatus from "@/business/components/api/definition/components/list/ApiS
import { import {
buildBatchParam, buildBatchParam,
deepClone, deepClone,
getCustomFieldBatchEditOption, getCustomFieldBatchEditOption, getCustomFieldFilter,
getCustomFieldValue, getCustomFieldValue,
getCustomTableHeader, getCustomTableHeader,
getCustomTableWidth, getCustomTableWidth,
@ -257,7 +259,7 @@ import {
parseTag parseTag
} from "@/common/js/utils"; } from "@/common/js/utils";
import {getTestTemplate} from "@/network/custom-field-template"; import {getTestTemplate} from "@/network/custom-field-template";
import {getProjectMember} from "@/network/user"; import {getProjectMember, getProjectMemberUserFilter} from "@/network/user";
import MsTable from "@/business/components/common/components/table/MsTable"; import MsTable from "@/business/components/common/components/table/MsTable";
import MsTableColumn from "@/business/components/common/components/table/MsTableColumn"; import MsTableColumn from "@/business/components/common/components/table/MsTableColumn";
import BatchMove from "@/business/components/track/case/components/BatchMove"; import BatchMove from "@/business/components/track/case/components/BatchMove";
@ -479,7 +481,8 @@ export default {
fieldsWidth: getCustomTableWidth('TRACK_TEST_CASE'), fieldsWidth: getCustomTableWidth('TRACK_TEST_CASE'),
memberMap: new Map(), memberMap: new Map(),
rowCase: {}, rowCase: {},
rowCaseResult: {} rowCaseResult: {},
userFilter: []
}; };
}, },
props: { props: {
@ -531,6 +534,9 @@ export default {
this.getTemplateField(); this.getTemplateField();
this.$emit('setCondition', this.condition); this.$emit('setCondition', this.condition);
this.initTableData(); this.initTableData();
getProjectMemberUserFilter((data) => {
this.userFilter = data;
});
let redirectParam = this.$route.query.dataSelectRange; let redirectParam = this.$route.query.dataSelectRange;
this.checkRedirectEditPage(redirectParam); this.checkRedirectEditPage(redirectParam);
@ -668,7 +674,7 @@ export default {
}); });
this.$store.commit('setTestCaseDefaultValue', testCaseDefaultValue); this.$store.commit('setTestCaseDefaultValue', testCaseDefaultValue);
}, },
getCustomFieldValue(row, field) { getCustomFieldValue(row, field, defaultVal = '') {
let value = getCustomFieldValue(row, field, this.members); let value = getCustomFieldValue(row, field, this.members);
if (field.name === '用例等级') { if (field.name === '用例等级') {
return row.priority; return row.priority;
@ -677,14 +683,20 @@ export default {
} else if (field.name === '用例状态') { } else if (field.name === '用例状态') {
return row.status; return row.status;
} }
return value ? value : ''; return value ? value : defaultVal;
}, },
getCustomFieldFilter(field) { getCustomFieldFilter(field) {
if (field.type === 'multipleMember' || field.name === '用例状态') { if (field.name === '用例状态') {
return null; let option = [];
field.options.forEach((item) => {
option.push({
text: this.$t(item.text),
value: item.value
})
});
return option;
} }
return Array.isArray(field.options) ? return getCustomFieldFilter(field, this.userFilter);
(field.options.length > 0 ? field.options : null) : null;
}, },
checkRedirectEditPage(redirectParam) { checkRedirectEditPage(redirectParam) {
if (redirectParam != null) { if (redirectParam != null) {

View File

@ -27,12 +27,12 @@
:show-select-all="false" :show-select-all="false"
:screen-height="screenHeight" :screen-height="screenHeight"
:remember-order="true" :remember-order="true"
@handlePageChange="getIssues"
:fields.sync="fields" :fields.sync="fields"
:field-key="tableHeaderKey" :field-key="tableHeaderKey"
@order="getIssues"
@filter="search"
:custom-fields="issueTemplate.customFields" :custom-fields="issueTemplate.customFields"
@filter="search"
@order="getIssues"
@handlePageChange="getIssues"
ref="table" ref="table"
> >
<span v-for="(item) in fields" :key="item.key"> <span v-for="(item) in fields" :key="item.key">
@ -189,7 +189,7 @@ import {checkSyncIssues, getIssuePartTemplateWithProject, getIssues, syncIssues}
import { import {
getCustomFieldValue, getCustomFieldValue,
getCustomTableWidth, getCustomTableWidth,
getPageInfo, getTableHeaderWithCustomFields, getLastTableSortField getPageInfo, getTableHeaderWithCustomFields, getLastTableSortField, getCustomFieldFilter
} from "@/common/js/tableUtils"; } from "@/common/js/tableUtils";
import MsContainer from "@/business/components/common/components/MsContainer"; import MsContainer from "@/business/components/common/components/MsContainer";
import MsMainContainer from "@/business/components/common/components/MsMainContainer"; import MsMainContainer from "@/business/components/common/components/MsMainContainer";
@ -238,6 +238,7 @@ export default {
], ],
issueTemplate: {}, issueTemplate: {},
members: [], members: [],
userFilter: [],
isThirdPart: false, isThirdPart: false,
creatorFilters: [], creatorFilters: [],
}; };
@ -254,6 +255,9 @@ export default {
window.addEventListener('resize', this.tableDoLayout); window.addEventListener('resize', this.tableDoLayout);
getProjectMember((data) => { getProjectMember((data) => {
this.members = data; this.members = data;
this.userFilter = data.map(u => {
return {text: u.name, value: u.id};
});
}); });
getIssuePartTemplateWithProject((template) => { getIssuePartTemplateWithProject((template) => {
this.initFields(template); this.initFields(template);
@ -294,18 +298,16 @@ export default {
return value ? value : defaultVal; return value ? value : defaultVal;
}, },
getCustomFieldFilter(field) { getCustomFieldFilter(field) {
if (field.type === 'multipleMember') { return getCustomFieldFilter(field, this.userFilter);
return null;
}
return Array.isArray(field.options) ?
(field.options.length > 0 ? field.options : null) : null;
}, },
i18nCustomStatus(options) { i18nCustomStatus(options) {
let i18ns = []; let i18ns = [];
options.forEach(option => { if (options) {
option.text = this.$t(option.text); options.forEach(option => {
i18ns.push(option); option.text = this.$t(option.text);
}) i18ns.push(option);
});
}
return i18ns; return i18ns;
}, },
initFields(template) { initFields(template) {

View File

@ -47,6 +47,7 @@
<ms-table-column <ms-table-column
prop="createUser" prop="createUser"
:field="item" :field="item"
:filters="userFilter"
:fields-width="fieldsWidth" :fields-width="fieldsWidth"
:label="$t('commons.create_user')" :label="$t('commons.create_user')"
min-width="200px"> min-width="200px">
@ -173,18 +174,11 @@
:label="$t('test_track.plan.plan_project')" :label="$t('test_track.plan.plan_project')"
min-width="200px"> min-width="200px">
</ms-table-column> </ms-table-column>
<ms-table-column
prop="tags" <ms-tags-column
:field="item" :field="item"
:fields-width="fieldsWidth" :fields-width="fieldsWidth"/>
sortable
:label="$t('api_test.automation.tag')"
min-width="200px">
<template v-slot:default="scope">
<ms-tag v-for="(itemName,index) in scope.row.tags" :key="index" type="success" effect="plain"
:content="itemName" style="margin-left: 0px; margin-right: 2px"></ms-tag>
</template>
</ms-table-column>
<ms-table-column <ms-table-column
prop="testPlanTestCaseCount" prop="testPlanTestCaseCount"
:field="item" :field="item"
@ -369,11 +363,14 @@ import {getPlanStageOption} from "@/network/test-plan";
import MsTableColumn from "@/business/components/common/components/table/MsTableColumn"; import MsTableColumn from "@/business/components/common/components/table/MsTableColumn";
import MsTable from "@/business/components/common/components/table/MsTable"; import MsTable from "@/business/components/common/components/table/MsTable";
import MsTestPlanScheduleBatchSwitch from "@/business/components/track/plan/components/ScheduleBatchSwitch"; import MsTestPlanScheduleBatchSwitch from "@/business/components/track/plan/components/ScheduleBatchSwitch";
import MsTagsColumn from "@/business/components/common/components/table/MsTagsColumn";
import {getProjectMemberUserFilter} from "@/network/user";
export default { export default {
name: "TestPlanList", name: "TestPlanList",
components: { components: {
MsTagsColumn,
TestPlanReportReview, TestPlanReportReview,
MsTag, MsTag,
HeaderLabelOperate, HeaderLabelOperate,
@ -433,6 +430,7 @@ export default {
stageOption: [], stageOption: [],
operators: [], operators: [],
batchButtons: [], batchButtons: [],
userFilter: [],
publicButtons: [ publicButtons: [
{ {
name: this.$t('test_track.plan.test_plan_batch_switch'), name: this.$t('test_track.plan.test_plan_batch_switch'),
@ -490,6 +488,9 @@ export default {
}) })
} }
}); });
getProjectMemberUserFilter((data) => {
this.userFilter = data;
});
this.initTableData(); this.initTableData();
}, },
methods: { methods: {

View File

@ -1,131 +1,95 @@
<template> <template>
<el-card class="table-card" v-loading="result.loading"> <el-card class="table-card" v-loading="page.result.loading">
<template v-slot:header> <template v-slot:header>
<ms-table-header :create-permission="['PROJECT_TRACK_REVIEW:READ+CREATE']" :condition.sync="condition" <ms-table-header :create-permission="['PROJECT_TRACK_REVIEW:READ+CREATE']" :condition.sync="condition"
@search="search" @create="testCaseReviewCreate" @search="search" @create="testCaseReviewCreate"
:create-tip="$t('test_track.review.create_review')"/> :create-tip="$t('test_track.review.create_review')"/>
</template> </template>
<el-table <ms-table
border operator-width="220px"
class="adjust-table" row-key="id"
:data="tableData" :data="tableData"
@filter-change="filter" :condition="condition"
:height="screenHeight" :total="page.total"
@sort-change="sort" :page-size.sync="page.pageSize"
@row-click="intoReview"> :operators="operators"
<template v-for="(item, index) in tableLabel"> :fields.sync="fields"
<el-table-column :screen-height="screenHeight"
v-if="item.id=='name'" :remember-order="true"
:field-key="tableHeaderKey"
:show-select-all="false"
:enable-selection="false"
@order="initTableData"
@filter="search"
@handleRowClick="intoReview">
<span v-for="item in fields" :key="item.key">
<ms-table-column
prop="name" prop="name"
:label="$t('test_track.review.review_name')" :field="item"
show-overflow-tooltip :label="$t('test_track.review.review_name')"/>
:key="index">
</el-table-column> <ms-table-column
<el-table-column prop="reviewer"
v-if="item.id=='reviewer'" :field="item"
prop="reviewer" :label="$t('test_track.review.reviewer')"/>
:label="$t('test_track.review.reviewer')"
show-overflow-tooltip <ms-table-column
:key="index">
</el-table-column>
<el-table-column
v-if="item.id=='projectName'"
prop="projectName" prop="projectName"
:label="$t('test_track.review.review_project')" :field="item"
show-overflow-tooltip :label="$t('test_track.review.review_project')"/>
:key="index">
</el-table-column> <ms-table-column
<el-table-column
v-if="item.id=='creatorName'"
prop="creatorName" prop="creatorName"
:label="$t('test_track.review.creator')" :field="item"
show-overflow-tooltip :filters="userFilter"
:key="index" :label="$t('test_track.review.creator')"/>
>
</el-table-column> <ms-table-column
<el-table-column
v-if="item.id=='status'"
prop="status" prop="status"
column-key="status" :field="item"
:label="$t('test_track.review.review_status')" :filters="statusFilters"
show-overflow-tooltip :label="$t('test_track.review.review_status')">
:key="index" <template v-slot:default="scope">
>
<template v-slot:default="scope">
<span class="el-dropdown-link"> <span class="el-dropdown-link">
<plan-status-table-item :value="scope.row.status"/> <plan-status-table-item :value="scope.row.status"/>
</span> </span>
</template> </template>
</el-table-column> </ms-table-column>
<el-table-column v-if="item.id == 'tags'" prop="tags"
:label="$t('api_test.automation.tag')" :key="index"> <ms-tags-column :field="item"/>
<template v-slot:default="scope">
<ms-tag v-for="(itemName,index) in scope.row.tags" :key="index" type="success" effect="plain" <ms-table-column
:content="itemName" style="margin-left: 0px; margin-right: 2px"></ms-tag>
</template>
</el-table-column>
<el-table-column
v-if="item.id=='follow'"
prop="follow" prop="follow"
:label="$t('test_track.review.review_follow_people')" :field="item"
show-overflow-tooltip :label="$t('test_track.review.review_follow_people')"/>
:key="index"
> <ms-create-time-column
</el-table-column> :field="item"/>
<el-table-column
v-if="item.id=='createTime'" <ms-update-time-column
prop="createTime" :field="item"/>
:label="$t('commons.create_time')"
show-overflow-tooltip <ms-table-column
:key="index"
>
<template v-slot:default="scope">
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
</template>
</el-table-column>
<el-table-column
v-if="item.id=='endTime'"
prop="endTime" prop="endTime"
:label="$t('test_track.review.end_time')" :field="item"
show-overflow-tooltip :label="$t('test_track.review.end_time')">
:key="index">
<template v-slot:default="scope"> <template v-slot:default="scope">
<span>{{ scope.row.endTime | timestampFormatDate }}</span> <span>{{ scope.row.endTime | timestampFormatDate }}</span>
</template> </template>
</el-table-column> </ms-table-column>
</span>
<template v-slot:opt-behind="scope">
<ms-table-follow-operator
:row="scope.row"
@saveFollow="saveFollow"/>
</template> </template>
<el-table-column
min-width="120"
:label="$t('commons.operating')">
<template slot="header">
<header-label-operate @exec="customHeader"/>
</template>
<template v-slot:default="scope">
<div>
<ms-table-operator :edit-permission="['PROJECT_TRACK_REVIEW:READ+EDIT']"
:delete-permission="['PROJECT_TRACK_REVIEW:READ+DELETE']"
@editClick="handleEdit(scope.row)"
@deleteClick="handleDelete(scope.row)">
</ms-table-operator>
<template>
<el-tooltip :content="$t('commons.follow')" placement="bottom" effect="dark" v-if="!scope.row.showFollow">
<i class="el-icon-star-off" style="color: #783987; font-size: 25px; padding-left: 5px;top: 5px; position: relative; cursor: pointer;width: 28px;height: 28px;" @click="saveFollow(scope.row)"></i>
</el-tooltip>
<el-tooltip :content="$t('commons.cancel')" placement="bottom" effect="dark" v-if="scope.row.showFollow">
<i class="el-icon-star-on" style="color: #783987; font-size: 30px;padding-left: 5px; top: 5px; position: relative; cursor: pointer;width: 28px;height: 28px; " @click="saveFollow(scope.row)"></i>
</el-tooltip>
</template>
</div>
</template> </ms-table>
</el-table-column>
<header-custom ref="headerCustom" :initTableData="initTableData" :optionalFields=headerItems
:type=type></header-custom>
</el-table>
<ms-table-pagination :change="initTableData" :current-page.sync="currentPage" :page-size.sync="pageSize" <ms-table-pagination :change="initTableData" :current-page.sync="page.currentPage" :page-size.sync="page.pageSize"
:total="total"/> :total="page.total"/>
<ms-delete-confirm :title="$t('test_track.review.delete')" @delete="_handleDelete" ref="deleteConfirm"/> <ms-delete-confirm :title="$t('test_track.review.delete')" @delete="_handleDelete" ref="deleteConfirm"/>
</el-card> </el-card>
@ -139,7 +103,11 @@ import MsDialogFooter from "../../../common/components/MsDialogFooter";
import MsTableHeader from "../../../common/components/MsTableHeader"; import MsTableHeader from "../../../common/components/MsTableHeader";
import MsTablePagination from "../../../common/pagination/TablePagination"; import MsTablePagination from "../../../common/pagination/TablePagination";
import {getCurrentProjectID, getCurrentUser, getCurrentWorkspaceId} from "@/common/js/utils"; import {getCurrentProjectID, getCurrentUser, getCurrentWorkspaceId} from "@/common/js/utils";
import {_filter, _sort, deepClone, getLabel, getLastTableSortField,saveLastTableSortField} from "@/common/js/tableUtils"; import {
deepClone, getCustomTableHeader, getCustomTableWidth,
getLastTableSortField,
getPageInfo,
} from "@/common/js/tableUtils";
import PlanStatusTableItem from "../../common/tableItems/plan/PlanStatusTableItem"; import PlanStatusTableItem from "../../common/tableItems/plan/PlanStatusTableItem";
import {Test_Case_Review} from "@/business/components/common/model/JsonData"; import {Test_Case_Review} from "@/business/components/common/model/JsonData";
import {TEST_CASE_REVIEW_LIST} from "@/common/js/constants"; import {TEST_CASE_REVIEW_LIST} from "@/common/js/constants";
@ -147,10 +115,23 @@ import HeaderCustom from "@/business/components/common/head/HeaderCustom";
import HeaderLabelOperate from "@/business/components/common/head/HeaderLabelOperate"; import HeaderLabelOperate from "@/business/components/common/head/HeaderLabelOperate";
import MsTag from "@/business/components/common/components/MsTag"; import MsTag from "@/business/components/common/components/MsTag";
import {TEST_REVIEW} from "@/business/components/common/components/search/search-components"; import {TEST_REVIEW} from "@/business/components/common/components/search/search-components";
import {getProjectMemberUserFilter} from "@/network/user";
import MsTable from "@/business/components/common/components/table/MsTable";
import MsTableColumn from "@/business/components/common/components/table/MsTableColumn";
import MsCreateTimeColumn from "@/business/components/common/components/table/MsCreateTimeColumn";
import MsUpdateTimeColumn from "@/business/components/common/components/table/MsUpdateTimeColumn";
import MsTableFollowOperator from "@/business/components/common/components/table/MsTableFollowOperator";
import MsTagsColumn from "@/business/components/common/components/table/MsTagsColumn";
export default { export default {
name: "TestCaseReviewList", name: "TestCaseReviewList",
components: { components: {
MsTagsColumn,
MsTableFollowOperator,
MsUpdateTimeColumn,
MsCreateTimeColumn,
MsTableColumn,
MsTable,
MsTag, MsTag,
HeaderLabelOperate, HeaderLabelOperate,
HeaderCustom, HeaderCustom,
@ -164,25 +145,38 @@ export default {
}, },
data() { data() {
return { return {
page: getPageInfo(),
type: TEST_CASE_REVIEW_LIST, type: TEST_CASE_REVIEW_LIST,
headerItems: Test_Case_Review, headerItems: Test_Case_Review,
tableLabel: [], tableLabel: [],
tableHeaderKey:"TEST_CASE_REVIEW", tableHeaderKey: "TEST_CASE_REVIEW",
result: {},
condition: { condition: {
components: TEST_REVIEW components: TEST_REVIEW
}, },
tableData: [], tableData: [],
isTestManagerOrTestUser: false, isTestManagerOrTestUser: false,
currentPage: 1,
pageSize: 10,
total: 0,
screenHeight: 'calc(100vh - 160px)', screenHeight: 'calc(100vh - 160px)',
userFilter: [],
fields: getCustomTableHeader('TEST_CASE_REVIEW'),
fieldsWidth: getCustomTableWidth('TEST_CASE_REVIEW'),
statusFilters: [ statusFilters: [
{text: this.$t('test_track.plan.plan_status_prepare'), value: 'Prepare'}, {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_running'), value: 'Underway'},
{text: this.$t('test_track.plan.plan_status_completed'), value: 'Completed'} {text: this.$t('test_track.plan.plan_status_completed'), value: 'Completed'}
], ],
operators: [
{
tip: this.$t('commons.edit'),
icon: "el-icon-edit",
exec: this.handleEdit,
permissions: ['PROJECT_TRACK_REVIEW:READ+EDIT'],
},
{
tip: this.$t('commons.delete'), icon: "el-icon-delete", type: "danger",
exec: this.handleDelete,
permission: ['PROJECT_TRACK_REVIEW:READ+DELETE']
},
],
}; };
}, },
watch: { watch: {
@ -195,7 +189,9 @@ export default {
created() { created() {
this.isTestManagerOrTestUser = true; this.isTestManagerOrTestUser = true;
this.condition.orders = getLastTableSortField(this.tableHeaderKey); this.condition.orders = getLastTableSortField(this.tableHeaderKey);
getProjectMemberUserFilter((data) => {
this.userFilter = data;
});
this.initTableData(); this.initTableData();
}, },
computed: { computed: {
@ -211,7 +207,6 @@ export default {
const list = deepClone(this.tableLabel); const list = deepClone(this.tableLabel);
this.$refs.headerCustom.open(list); this.$refs.headerCustom.open(list);
}, },
initTableData() { initTableData() {
let lastWorkspaceId = getCurrentWorkspaceId(); let lastWorkspaceId = getCurrentWorkspaceId();
this.condition.workspaceId = lastWorkspaceId; this.condition.workspaceId = lastWorkspaceId;
@ -219,9 +214,9 @@ export default {
return; return;
} }
this.condition.projectId = this.projectId; this.condition.projectId = this.projectId;
this.result = this.$post("/test/case/review/list/" + this.currentPage + "/" + this.pageSize, this.condition, response => { this.page.result = this.$post("/test/case/review/list/" + this.page.currentPage + "/" + this.page.pageSize, this.condition, response => {
let data = response.data; let data = response.data;
this.total = data.itemCount; this.page.taotal = data.itemCount;
this.tableData = data.listObject; this.tableData = data.listObject;
this.tableData.forEach(item => { this.tableData.forEach(item => {
if (item.tags && item.tags.length > 0) { if (item.tags && item.tags.length > 0) {
@ -249,7 +244,7 @@ export default {
let showFollow = false; let showFollow = false;
if (arr) { if (arr) {
arr.forEach(d => { arr.forEach(d => {
if(this.currentUser().id===d.id){ if (this.currentUser().id === d.id) {
showFollow = true; showFollow = true;
} }
}) })
@ -260,9 +255,8 @@ export default {
}); });
} }
}); });
getLabel(this, TEST_CASE_REVIEW_LIST);
}, },
intoReview(row,column, event) { intoReview(row, column, event) {
if (column.label !== this.$t('commons.operating')) { if (column.label !== this.$t('commons.operating')) {
this.$router.push('/track/review/view/' + row.id); this.$router.push('/track/review/view/' + row.id);
} }
@ -276,9 +270,6 @@ export default {
}, },
handleEdit(caseReview) { handleEdit(caseReview) {
this.$emit('caseReviewEdit', caseReview); this.$emit('caseReviewEdit', caseReview);
},
statusChange() {
}, },
handleDelete(caseReview) { handleDelete(caseReview) {
this.$refs.deleteConfirm.open(caseReview); this.$refs.deleteConfirm.open(caseReview);
@ -290,52 +281,36 @@ export default {
this.$success(this.$t('commons.delete_success')); this.$success(this.$t('commons.delete_success'));
}); });
}, },
filter(filters) {
_filter(filters, this.condition);
this.search();
},
search() { search() {
// //
this.currentPage = 1; this.page.currentPage = 1;
this.initTableData(); this.initTableData();
}, },
sort(column) { saveFollow(row) {
//
if (this.condition.orders) {
this.condition.orders = [];
}
_sort(column, this.condition);
this.saveSortField(this.tableHeaderKey,this.condition.orders);
this.initTableData();
},
saveSortField(key,orders){
saveLastTableSortField(key,JSON.stringify(orders));
},
saveFollow(row){
let param = {}; let param = {};
param.id = row.id; param.id = row.id;
if(row.showFollow){ if (row.showFollow) {
row.showFollow = false; row.showFollow = false;
for (let i = 0; i < row.followIds.length; i++) { for (let i = 0; i < row.followIds.length; i++) {
if(row.followIds[i]===this.currentUser().id){ if (row.followIds[i] === this.currentUser().id) {
row.followIds.splice(i,1) row.followIds.splice(i, 1)
break; break;
} }
} }
param.followIds = row.followIds param.followIds = row.followIds
this.$post('/test/case/review/edit/follows', param,() => { this.$post('/test/case/review/edit/follows', param, () => {
this.$success(this.$t('commons.cancel_follow_success')); this.$success(this.$t('commons.cancel_follow_success'));
}); });
return return
} }
if(!row.showFollow){ if (!row.showFollow) {
row.showFollow = true; row.showFollow = true;
if(!row.followIds){ if (!row.followIds) {
row.followIds = []; row.followIds = [];
} }
row.followIds.push(this.currentUser().id); row.followIds.push(this.currentUser().id);
param.followIds = row.followIds param.followIds = row.followIds
this.$post('/test/case/review/edit/follows', param,() => { this.$post('/test/case/review/edit/follows', param, () => {
this.$success(this.$t('commons.follow_success')); this.$success(this.$t('commons.follow_success'));
}); });
} }

View File

@ -1,5 +1,3 @@
import i18n from "@/i18n/i18n";
export const TEST_CASE_LIST = 'test_case_list'; export const TEST_CASE_LIST = 'test_case_list';
export const CUSTOM_FIELD_LIST = new Set([ export const CUSTOM_FIELD_LIST = new Set([

View File

@ -3,20 +3,20 @@ import i18n from "@/i18n/i18n";
import {AZURE_DEVOPS, JIRA, LOCAL, TAPD, ZEN_TAO} from "@/common/js/constants"; import {AZURE_DEVOPS, JIRA, LOCAL, TAPD, ZEN_TAO} from "@/common/js/constants";
export const CUSTOM_FIELD_TYPE_OPTION = [ export const CUSTOM_FIELD_TYPE_OPTION = [
{value: 'input',text: 'workspace.custom_filed.input'}, {value: 'input', text: 'workspace.custom_filed.input'},
{value: 'textarea',text: 'workspace.custom_filed.textarea'}, {value: 'textarea', text: 'workspace.custom_filed.textarea'},
{value: 'select',text: 'workspace.custom_filed.select'}, {value: 'select', text: 'workspace.custom_filed.select', hasOption: true},
{value: 'multipleSelect',text: 'workspace.custom_filed.multipleSelect'}, {value: 'multipleSelect', text: 'workspace.custom_filed.multipleSelect', hasOption: true},
{value: 'radio',text: 'workspace.custom_filed.radio'}, {value: 'radio', text: 'workspace.custom_filed.radio', hasOption: true},
{value: 'checkbox',text: 'workspace.custom_filed.checkbox'}, {value: 'checkbox', text: 'workspace.custom_filed.checkbox', hasOption: true},
{value: 'member',text: 'workspace.custom_filed.member'}, {value: 'member', text: 'workspace.custom_filed.member', hasOption: true},
{value: 'multipleMember',text: 'workspace.custom_filed.multipleMember'}, {value: 'multipleMember', text: 'workspace.custom_filed.multipleMember', hasOption: true},
{value: 'date',text: 'workspace.custom_filed.date'}, {value: 'date', text: 'workspace.custom_filed.date'},
{value: 'datetime',text: 'workspace.custom_filed.datetime'}, {value: 'datetime', text: 'workspace.custom_filed.datetime'},
{value: 'richText',text: 'workspace.custom_filed.richText'}, {value: 'richText', text: 'workspace.custom_filed.richText'},
{value: 'int',text: 'workspace.custom_filed.int'}, {value: 'int', text: 'workspace.custom_filed.int'},
{value: 'float',text: 'workspace.custom_filed.float'}, {value: 'float', text: 'workspace.custom_filed.float'},
{value: 'multipleInput',text: 'workspace.custom_filed.multipleInput'} {value: 'multipleInput', text: 'workspace.custom_filed.multipleInput'}
]; ];
export function CUSTOM_FIELD_TYPE_FILTERS(_this) { export function CUSTOM_FIELD_TYPE_FILTERS(_this) {
@ -53,11 +53,11 @@ export const UI_ELEMENT_LOCATION_TYPE_OPTION = [
]; ];
export const CUSTOM_FIELD_SCENE_OPTION = [ export const CUSTOM_FIELD_SCENE_OPTION = [
{value: 'TEST_CASE',text: 'workspace.case_template_manage'}, {value: 'TEST_CASE', text: 'workspace.case_template_manage'},
{value: 'ISSUE',text: 'workspace.issue_template_manage'}, {value: 'ISSUE', text: 'workspace.issue_template_manage'},
]; ];
export function CASE_TYPE_OPTION(){ export function CASE_TYPE_OPTION() {
return [ return [
{value: 'functional', text: i18n.t('api_test.home_page.failed_case_list.table_value.case_type.functional')}, {value: 'functional', text: i18n.t('api_test.home_page.failed_case_list.table_value.case_type.functional')},
]; ];
@ -115,7 +115,7 @@ export const ISSUE_STATUS_MAP = {
'resolved': i18n.t('test_track.issue.status_resolved'), 'resolved': i18n.t('test_track.issue.status_resolved'),
'active': i18n.t('test_track.issue.status_active'), 'active': i18n.t('test_track.issue.status_active'),
'delete': i18n.t('test_track.issue.status_delete'), 'delete': i18n.t('test_track.issue.status_delete'),
'created':i18n.t('test_track.issue.status_new') 'created': i18n.t('test_track.issue.status_new')
} }
export const TAPD_ISSUE_STATUS_MAP = { export const TAPD_ISSUE_STATUS_MAP = {
@ -124,11 +124,11 @@ export const TAPD_ISSUE_STATUS_MAP = {
'reopened': i18n.t('test_track.issue.tapd_status_reopened'), 'reopened': i18n.t('test_track.issue.tapd_status_reopened'),
'rejected': i18n.t('test_track.issue.tapd_status_rejected'), 'rejected': i18n.t('test_track.issue.tapd_status_rejected'),
'verified': i18n.t('test_track.issue.tapd_status_verified'), 'verified': i18n.t('test_track.issue.tapd_status_verified'),
'closed':i18n.t('test_track.issue.tapd_status_closed'), 'closed': i18n.t('test_track.issue.tapd_status_closed'),
'resolved':i18n.t('test_track.issue.tapd_status_resolved') 'resolved': i18n.t('test_track.issue.tapd_status_resolved')
} }
export function API_SCENARIO_FILTERS () { export function API_SCENARIO_FILTERS() {
return { return {
STATUS_FILTERS: [ STATUS_FILTERS: [
{text: i18n.t('test_track.plan.plan_status_prepare'), value: 'Prepare'}, {text: i18n.t('test_track.plan.plan_status_prepare'), value: 'Prepare'},
@ -170,7 +170,6 @@ export function API_SCENARIO_FILTERS () {
} }
export const USER_GROUP_SCOPE = { export const USER_GROUP_SCOPE = {
'SYSTEM': 'group.system', 'SYSTEM': 'group.system',
'WORKSPACE': 'group.workspace', 'WORKSPACE': 'group.workspace',

View File

@ -4,6 +4,7 @@ import {updateCustomFieldTemplate} from "@/network/custom-field-template";
import i18n from "@/i18n/i18n"; import i18n from "@/i18n/i18n";
import Sortable from 'sortablejs' import Sortable from 'sortablejs'
import {timestampFormatDate} from "@/common/js/filter"; import {timestampFormatDate} from "@/common/js/filter";
import {CUSTOM_FIELD_TYPE_OPTION} from "@/common/js/table-constants";
export function _handleSelectAll(component, selection, tableData, selectRows, condition) { export function _handleSelectAll(component, selection, tableData, selectRows, condition) {
if (selection.length > 0) { if (selection.length > 0) {
@ -666,3 +667,19 @@ export function handleRowDrop(data, callback) {
}); });
}, 100); }, 100);
} }
export function getCustomFieldFilter(field, userFilter) {
if (field.type === 'multipleMember') {
return null;
}
if (field.type === 'member' && userFilter) {
return userFilter;
}
let optionTypes = CUSTOM_FIELD_TYPE_OPTION
.filter(x => x.hasOption)
.map(x => x.value);
return optionTypes.indexOf(field.type) > -1 && Array.isArray(field.options) ?
(field.options.length > 0 ? field.options : null) : null;
}

View File

@ -14,6 +14,17 @@ export function getProjectMember(callBack) {
}); });
} }
export function getProjectMemberUserFilter(callBack) {
return baseGet('/user/project/member/list', (data) => {
if (callBack) {
let filter = data.map(u => {
return {text: u.name, value: u.id};
});
callBack(filter);
}
});
}
export function getProjectMemberById(projectId, callback) { export function getProjectMemberById(projectId, callback) {
return projectId ? baseGet('/user/project/member/' + projectId, callback) : {}; return projectId ? baseGet('/user/project/member/' + projectId, callback) : {};
} }