feat(接口测试): 优化接口测试报告可通过name检索

This commit is contained in:
xinxin.wu 2024-09-18 09:51:21 +08:00 committed by 刘瑞斌
parent ac0c517051
commit b9997f8356
6 changed files with 92 additions and 11 deletions

View File

@ -162,12 +162,17 @@
<!-- 报告明细开始 --> <!-- 报告明细开始 -->
<div class="report-info"> <div class="report-info">
<reportInfoHeader <reportInfoHeader
v-model:keywordName="keywordName"
v-model:keyword="cascaderKeywords" v-model:keyword="cascaderKeywords"
v-model:active-tab="activeTab" v-model:active-tab="activeTab"
show-type="CASE" show-type="CASE"
:is-export="props.isExport" :is-export="props.isExport"
@search="searchHandler"
@reset="resetHandler"
/> />
<TiledList <TiledList
ref="tiledListRef"
v-model:keyword-name="keywordName"
:key-words="cascaderKeywords" :key-words="cascaderKeywords"
show-type="CASE" show-type="CASE"
:active-type="activeTab" :active-type="activeTab"
@ -245,6 +250,7 @@
}); });
const cascaderKeywords = ref<string>(''); const cascaderKeywords = ref<string>('');
const keywordName = ref<string>('');
const getTotalTime = computed(() => { const getTotalTime = computed(() => {
if (detail.value) { if (detail.value) {
@ -401,6 +407,15 @@
}); });
} }
const tiledListRef = ref<InstanceType<typeof TiledList>>();
function searchHandler() {
tiledListRef.value?.updateDebouncedSearch();
}
function resetHandler() {
tiledListRef.value?.initStepTree();
}
watchEffect(() => { watchEffect(() => {
if (props.detailInfo) { if (props.detailInfo) {
detail.value = props.detailInfo; detail.value = props.detailInfo;

View File

@ -36,12 +36,17 @@
<!-- 报告明细开始 --> <!-- 报告明细开始 -->
<div class="report-info"> <div class="report-info">
<reportInfoHeader <reportInfoHeader
v-model:keywordName="keywordName"
v-model:keyword="cascaderKeywords" v-model:keyword="cascaderKeywords"
v-model:active-tab="activeTab" v-model:active-tab="activeTab"
show-type="API" show-type="API"
:is-export="props.isExport" :is-export="props.isExport"
@search="searchHandler"
@reset="resetHandler"
/> />
<TiledList <TiledList
ref="tiledListRef"
v-model:keyword-name="keywordName"
:key-words="cascaderKeywords" :key-words="cascaderKeywords"
show-type="API" show-type="API"
:get-report-step-detail="props.getReportStepDetail" :get-report-step-detail="props.getReportStepDetail"
@ -144,6 +149,7 @@
} }
return ''; return '';
}); });
const keywordName = ref<string>('');
const reportAnalysisList = computed<ReportMetricsItemModel[]>(() => [ const reportAnalysisList = computed<ReportMetricsItemModel[]>(() => [
{ {
@ -319,6 +325,15 @@
}); });
} }
const tiledListRef = ref<InstanceType<typeof TiledList>>();
function searchHandler() {
tiledListRef.value?.updateDebouncedSearch();
}
function resetHandler() {
tiledListRef.value?.initStepTree();
}
watchEffect(() => { watchEffect(() => {
if (props.detailInfo) { if (props.detailInfo) {
detail.value = props.detailInfo; detail.value = props.detailInfo;

View File

@ -8,7 +8,16 @@
</a-radio> </a-radio>
</a-radio-group> </a-radio-group>
</div> </div>
<div v-if="!props.isExport" class="w-[240px]"> <div v-if="!props.isExport" class="grid grid-cols-2">
<a-input-search
v-model:model-value="innerKeywordName"
:placeholder="t('report.detail.api.placeHolderName')"
allow-clear
class="mx-[8px] w-[240px]"
@search="searchList"
@press-enter="searchList"
@clear="reset"
/>
<MsCascader <MsCascader
v-model:model-value="innerKeyword" v-model:model-value="innerKeyword"
mode="native" mode="native"
@ -58,14 +67,24 @@
const props = defineProps<{ const props = defineProps<{
activeTab: 'tiled' | 'tab'; activeTab: 'tiled' | 'tab';
keyword: string; keyword: string;
keywordName: string;
showType: 'API' | 'CASE'; showType: 'API' | 'CASE';
isExport?: boolean; // pdf isExport?: boolean; // pdf
}>(); }>();
const emit = defineEmits(['update:activeTab', 'update:keyword']); const emit = defineEmits(['update:activeTab', 'update:keyword', 'update:keywordName', 'search', 'reset']);
const innerActiveTab = useVModel(props, 'activeTab', emit); const innerActiveTab = useVModel(props, 'activeTab', emit);
const innerKeyword = useVModel(props, 'keyword', emit); const innerKeyword = useVModel(props, 'keyword', emit);
const innerKeywordName = useVModel(props, 'keywordName', emit);
function searchList() {
emit('search');
}
function reset() {
emit('reset');
}
const methods = ref([ const methods = ref([
{ {

View File

@ -82,6 +82,10 @@
const tiledList = ref<ScenarioItemType[]>([]); const tiledList = ref<ScenarioItemType[]>([]);
const innerKeyword = defineModel<string>('keywordName', {
default: '',
});
const isExpandAll = ref(false); // const isExpandAll = ref(false); //
const showStepDrawer = ref<boolean>(false); const showStepDrawer = ref<boolean>(false);
@ -156,21 +160,44 @@
ScenarioStepType.CUSTOM_REQUEST, ScenarioStepType.CUSTOM_REQUEST,
ScenarioStepType.SCRIPT, ScenarioStepType.SCRIPT,
]); ]);
function searchStep() { function searchStep() {
const splitLevel = props.keyWords.split('-'); const splitLevel = props.keyWords.split('-');
const stepTypeStatus = splitLevel[1]; const stepTypeStatus = splitLevel[1] || '';
const stepType = splitLevel[0] === 'CUSTOM_REQUEST' ? ['API', 'API_CASE', 'CUSTOM_REQUEST'] : splitLevel[0]; const stepType = splitLevel[0] === 'CUSTOM_REQUEST' ? ['API', 'API_CASE', 'CUSTOM_REQUEST'] : splitLevel[0];
const nameSearch = innerKeyword.value?.toLowerCase(); // name
const search = (_data: ScenarioItemType[]) => { const search = (_data: ScenarioItemType[]) => {
const result: ScenarioItemType[] = []; const result: ScenarioItemType[] = [];
_data.forEach((item) => { _data.forEach((item) => {
const isStepChildren = item.children && item?.children.length && showApiType.value.includes(item.stepType); const isStepChildren = item.children && item?.children.length && showApiType.value.includes(item.stepType);
if (
stepType.includes(item.stepType) && //
((item.status && item.status === stepTypeStatus && stepTypeStatus !== 'scriptIdentifier') || const matchStepType = stepType.includes(item.stepType);
(stepTypeStatus.includes('scriptIdentifier') && item.scriptIdentifier))
) { //
const matchStepStatus =
(item.status && item.status === stepTypeStatus && stepTypeStatus !== 'scriptIdentifier') ||
(stepTypeStatus.includes('scriptIdentifier') && item.scriptIdentifier);
//
let matchesStepCondition;
// name
if (nameSearch && stepTypeStatus) {
matchesStepCondition = matchStepType && matchStepStatus && item.name?.toLowerCase().includes(nameSearch);
}
// name
else if (nameSearch) {
matchesStepCondition = item.name?.toLowerCase().includes(nameSearch);
}
// name
else {
matchesStepCondition = matchStepType && matchStepStatus;
}
if (matchesStepCondition) {
const resItem = { const resItem = {
...item, ...item,
expanded: false, expanded: false,
@ -189,14 +216,12 @@
if (isStepChildren) { if (isStepChildren) {
filterItem.stepChildren = cloneDeep(item.children); filterItem.stepChildren = cloneDeep(item.children);
filterItem.children = []; filterItem.children = [];
} }
result.push(filterItem); result.push(filterItem);
} }
} }
}); });
return result; return result;
}; };
@ -205,7 +230,7 @@
// //
const updateDebouncedSearch = debounce(() => { const updateDebouncedSearch = debounce(() => {
if (props.keyWords) { if (props.keyWords || innerKeyword.value) {
tiledList.value = searchStep(); tiledList.value = searchStep();
} }
}, 300); }, 300);
@ -220,6 +245,11 @@
} }
} }
); );
defineExpose({
updateDebouncedSearch,
initStepTree,
});
</script> </script>
<style scoped lang="less"> <style scoped lang="less">

View File

@ -73,4 +73,5 @@ export default {
'report.detail.api.caseSaveEnv': 'Case saved environment', 'report.detail.api.caseSaveEnv': 'Case saved environment',
'report.detail.api.scenarioSavedEnv': 'Scenario saved environment', 'report.detail.api.scenarioSavedEnv': 'Scenario saved environment',
'report.detail.api.noResponseContent': 'There is no response', 'report.detail.api.noResponseContent': 'There is no response',
'report.detail.api.placeHolderName': 'To search by name',
}; };

View File

@ -71,4 +71,5 @@ export default {
'report.detail.api.caseSaveEnv': '用例保存的环境', 'report.detail.api.caseSaveEnv': '用例保存的环境',
'report.detail.api.scenarioSavedEnv': '场景保存的环境', 'report.detail.api.scenarioSavedEnv': '场景保存的环境',
'report.detail.api.noResponseContent': '暂无响应内容', 'report.detail.api.noResponseContent': '暂无响应内容',
'report.detail.api.placeHolderName': '通过名称进行搜索',
}; };