fix(缺陷管理): 修改缺陷管理相关bug

This commit is contained in:
xinxin.wu 2024-03-13 18:14:57 +08:00 committed by Craftsman
parent be3be2d442
commit 7191563e9e
18 changed files with 258 additions and 65 deletions

View File

@ -515,7 +515,6 @@
if (!isInit) {
emit('change', { ...defaultParamItem, ...condition.value, assertionBodyType: activeTab.value });
}
break;
default:
break;

View File

@ -132,7 +132,7 @@
import { useI18n } from '@/hooks/useI18n';
import { ExecuteConditionProcessor } from '@/models/apiTest/common';
import { RequestConditionScriptLanguage, ResponseAssertionType } from '@/enums/apiEnum';
import { RequestConditionScriptLanguage, ResponseAssertionType, ResponseBodyAssertionType } from '@/enums/apiEnum';
import { ExecuteAssertion, MsAssertionItem } from './type';
@ -282,7 +282,7 @@
case ResponseAssertionType.RESPONSE_BODY:
assertions.value.push({
...tmpObj,
assertionBodyType: '',
assertionBodyType: ResponseBodyAssertionType.JSON_PATH,
jsonPathAssertion: {
assertions: [],
},

View File

@ -44,7 +44,16 @@
<div :class="getFolderClass('all')" @click="setActiveFolder('all')">
<MsIcon type="icon-icon_folder_filled1" class="folder-icon" />
<div class="folder-name">{{ t('caseManagement.featureCase.allCase') }}</div>
<div class="folder-count">({{ modulesCount['all'] }})</div>
<div class="folder-count">({{ modulesCount.total || 0 }})</div>
</div>
<div class="ml-auto flex items-center">
<a-tooltip
:content="isExpandAll ? t('project.fileManagement.collapseAll') : t('project.fileManagement.expandAll')"
>
<MsButton type="icon" status="secondary" class="!mr-0 p-[4px]" @click="expandHandler">
<MsIcon :type="isExpandAll ? 'icon-icon_folder_collapse1' : 'icon-icon_folder_expansion1'" />
</MsButton>
</a-tooltip>
</div>
</div>
<a-divider class="my-[8px]" />
@ -61,6 +70,7 @@
children: 'children',
count: 'count',
}"
:expand-all="isExpandAll"
block-node
title-tooltip-position="left"
@select="folderNodeSelect"
@ -83,6 +93,7 @@
:search-placeholder="t('caseManagement.caseReview.searchPlaceholder')"
@keyword-search="searchCase"
@adv-search="searchCase"
@refresh="searchCase()"
>
<template #left>
<div class="flex items-center justify-between">
@ -224,6 +235,11 @@
const protocolType = ref('HTTP'); //
const protocolOptions = ref(['HTTP']);
const modulesCount = ref<Record<string, any>>({});
const isExpandAll = ref(false);
//
const expandHandler = () => {
isExpandAll.value = !isExpandAll.value;
};
//
const caseType = computed({
@ -527,7 +543,7 @@
function openDetail(id: string) {
window.open(
`${window.location.origin}#${
router.resolve({ name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE_DETAIL }).fullPath
router.resolve({ name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE }).fullPath
}?id=${id}`
);
}

View File

@ -12,7 +12,7 @@ const BugManagement: AppRouteRecordRaw = {
locale: 'menu.bugManagement',
icon: 'icon-icon_defect',
order: 2,
roles: ['PROJECT_BUG:READ+ADD'],
roles: ['PROJECT_BUG:READ'],
hideChildrenInMenu: true,
},
children: [

View File

@ -353,11 +353,11 @@
<div class="flex flex-row items-center" :class="{ 'justify-end': columnConfig.align === 'right' }">
<a-switch
v-if="columnConfig.hasDisable"
v-model:model-value="record.enable"
v-model="record.enable"
size="small"
type="line"
class="mr-[8px]"
@change="(val) => addTableLine(val as number)"
@change="() => addTableLine(rowIndex)"
/>
<slot name="operationPre" :record="record" :row-index="rowIndex" :column-config="columnConfig"></slot>
<MsTableMoreAction

View File

@ -13,6 +13,7 @@
:table-data="props.tableData"
:page-change="props.pageChange"
show-full-screen
unmount-on-close
@loaded="loadedBug"
>
<template #titleRight="{ loading }">
@ -91,7 +92,7 @@
v-model:active-key="activeTab"
:content-tab-list="contentTabList"
:get-text-func="getTabBadge"
class="no-content relative mb-[8px] border-b border-[var(--color-text-n8)]"
class="no-content relative mb-[8px]"
/>
<div class="tab-pane-container">
<BugDetailTab
@ -137,11 +138,23 @@
@change="handelFormCreateChange"
/>
<!-- 自定义字段结束 -->
<!-- 内置基础信息开始 -->
<div v-if="!isPlatformDefaultTemplate" class="baseItem">
<a-form-item field="tags" :label="t('system.orgTemplate.tags')">
<MsTagsInput v-model:model-value="tags" />
</a-form-item>
<a-form
:model="{}"
:label-col-props="{
span: 9,
}"
:wrapper-col-props="{
span: 15,
}"
label-align="left"
content-class="tags-class"
>
<a-form-item field="tags" :label="t('system.orgTemplate.tags')">
<MsTagsInput v-model:model-value="tags" />
</a-form-item>
</a-form>
<!-- <span class="label"> {{ t('bugManagement.detail.tag') }}</span>-->
<!-- <span style="width: 200px">-->
<!-- <MsTag v-for="item of tags" :key="item"> {{ item }} </MsTag>-->
@ -518,6 +531,11 @@
}
}
);
watchEffect(() => {
if (props.detailIndex) {
activeTab.value = 'detail';
}
});
</script>
<style scoped lang="less">
@ -544,6 +562,76 @@
:deep(.arco-form-item-label-col > .arco-form-item-label) {
color: var(--color-text-3) !important;
}
:deep(.arco-select-view-single) {
border-color: transparent !important;
.arco-select-view-suffix {
visibility: hidden;
}
&:hover {
border-color: rgb(var(--primary-5)) !important;
.arco-select-view-suffix {
visibility: visible !important;
}
}
&:hover > .arco-input {
font-weight: normal;
text-decoration: none;
color: var(--color-text-1);
}
& > .arco-input {
font-weight: 500;
text-decoration: underline;
color: var(--color-text-1);
}
}
:deep(.arco-input-tag) {
border-color: transparent !important;
&:hover {
border-color: rgb(var(--primary-5)) !important;
}
}
:deep(.arco-input-wrapper) {
border-color: transparent !important;
&:hover {
border-color: rgb(var(--primary-5)) !important;
}
}
:deep(.arco-select-view-multiple) {
border-color: transparent !important;
.arco-select-view-suffix {
visibility: hidden;
}
&:hover {
border-color: rgb(var(--primary-5)) !important;
.arco-select-view-suffix {
visibility: visible !important;
}
}
}
:deep(.arco-textarea-wrapper) {
border-color: transparent !important;
&:hover {
border-color: rgb(var(--primary-5)) !important;
}
}
:deep(.arco-input-number) {
border-color: transparent !important;
&:hover {
border-color: rgb(var(--primary-5)) !important;
}
}
:deep(.arco-picker) {
border-color: transparent !important;
.arco-picker-suffix {
visibility: hidden;
}
&:hover {
border-color: rgb(var(--primary-5)) !important;
arco-picker-suffix {
visibility: visible !important;
}
}
}
}
.rightButtons {
:deep(.ms-button--secondary):hover,
@ -564,6 +652,9 @@
:deep(.active .arco-badge-text) {
background: rgb(var(--primary-5));
}
:deep(.tags-class .arco-form-item-label-col) {
justify-content: flex-start !important;
}
.left-bug-detail {
height: 88%;
}

View File

@ -12,6 +12,14 @@
></a-input-search>
</div>
<ms-base-table v-bind="propsRes" v-on="propsEvent">
<template #relateCaseNum="{ record }">
<a-tooltip :content="`${record.relateCaseNum}`">
<!-- TOTO 暂时没有用例id的字段 需要后台加caseId -->
<a-button type="text" class="px-0" @click="openDetail(record.relateCaseId)">
<div class="one-line-text max-w-[168px]">{{ record.relateCaseNum }}</div>
</a-button>
</a-tooltip>
</template>
<template #defectName="{ record }">
<span class="one-line-text max-w[300px]"> {{ record.relateCaseName }}</span
><span class="ml-1 text-[rgb(var(--primary-5))]">{{ t('caseManagement.featureCase.preview') }}</span>
@ -75,6 +83,7 @@
<script setup lang="ts">
import { ref } from 'vue';
import { useRouter } from 'vue-router';
import MsButton from '@/components/pure/ms-button/index.vue';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
@ -96,12 +105,13 @@
import useFeatureCaseStore from '@/store/modules/case/featureCase';
import type { TableQueryParams } from '@/models/common';
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
import Message from '@arco-design/web-vue/es/message';
const appStore = useAppStore();
const featureCaseStore = useFeatureCaseStore();
const router = useRouter();
const { t } = useI18n();
const currentProjectId = computed(() => appStore.currentProjectId);
@ -122,7 +132,8 @@
const columns: MsTableColumn = [
{
title: 'caseManagement.featureCase.tableColumnID',
dataIndex: 'relateCaseId',
dataIndex: 'relateCaseNum',
slotName: 'relateCaseNum',
width: 200,
showInTable: true,
showTooltip: true,
@ -172,7 +183,7 @@
columns,
scroll: { x: '100%' },
heightUsed: 340,
enableDrag: true,
enableDrag: false,
});
const innerVisible = ref(false);
@ -265,6 +276,14 @@
await loadList();
}
function openDetail(id: string) {
window.open(
`${window.location.origin}#${
router.resolve({ name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE }).fullPath
}?id=${id}`
);
}
onMounted(async () => {
getEnabledModules();
getFetch();

View File

@ -338,6 +338,7 @@
//
async function handlePreview(item: MsFileItem) {
try {
imageUrl.value = '';
previewVisible.value = true;
if (item.status !== 'init') {
const res = await previewFile({

View File

@ -1,8 +1,20 @@
<template>
<MsComment :comment-list="commentList" @delete="handleDelete" @update-or-add="handleUpdate" />
<div class="pr-4">
<a-scrollbar
:style="{
overflow: 'auto',
height: 'calc(100vh - 236px)',
width: '100%',
}"
>
<MsEmpty v-if="commentList.length === 0" />
<MsComment v-else :comment-list="commentList" @delete="handleDelete" @update-or-add="handleUpdate" />
</a-scrollbar>
</div>
</template>
<script lang="ts" setup>
import MsEmpty from '@/components/pure/ms-empty/index.vue';
import MsComment from '@/components/business/ms-comment/comment';
import { CommentItem, CommentParams } from '@/components/business/ms-comment/types';

View File

@ -149,16 +149,22 @@
</div>
<a-divider class="ml-[16px]" direction="vertical" />
<div class="right mt-[16px] max-w-[433px] grow pr-[24px]">
<div style="min-width: 250px; overflow: auto">
<MsFormCreate ref="formCreateRef" v-model:formItem="formItem" v-model:api="fApi" :form-rule="formRules" />
<!-- 平台默认模板不展示标签, 与第三方保持一致 -->
<a-form-item v-if="!isPlatformDefaultTemplate" field="tag" :label="t('bugManagement.tag')">
<MsTagsInput
v-model:model-value="form.tags"
:placeholder="t('bugManagement.edit.tagPlaceholder')"
allow-clear
/>
</a-form-item>
<div class="min-w-[250px] overflow-auto">
<a-skeleton v-if="isLoading" :loading="isLoading" :animation="true">
<a-space direction="vertical" class="w-full" size="large">
<a-skeleton-line :rows="rowLength" :line-height="30" :line-spacing="30" />
</a-space>
</a-skeleton>
<a-form v-else :model="form" layout="vertical">
<MsFormCreate ref="formCreateRef" v-model:formItem="formItem" v-model:api="fApi" :form-rule="formRules" />
<a-form-item v-if="!isPlatformDefaultTemplate" field="tag" :label="t('bugManagement.tag')">
<MsTagsInput
v-model:model-value="form.tags"
:placeholder="t('bugManagement.edit.tagPlaceholder')"
allow-clear
/>
</a-form-item>
</a-form>
</div>
</div>
</div>
@ -306,6 +312,8 @@
const title = computed(() => {
return isEdit.value ? t('bugManagement.editBug') : t('bugManagement.createBug');
});
const isLoading = ref<boolean>(true);
const rowLength = ref<number>(0);
//
function getFilesParams() {
@ -371,12 +379,13 @@
const templateChange = async (v: SelectValue, request?: BugTemplateRequest) => {
if (v) {
try {
loading.value = true;
isLoading.value = true;
let param = { projectId: appStore.currentProjectId, id: v };
if (request) {
param = { ...param, ...request };
}
const res = await getTemplateById(param);
await getFormRules(res.customFields);
isPlatformDefaultTemplate.value = res.platformDefault;
if (isPlatformDefaultTemplate.value) {
const systemFields = res.customFields.filter((field) => field.platformSystemField);
@ -386,7 +395,7 @@
});
}
getFormRules(res.customFields.filter((field) => !field.platformSystemField));
loading.value = false;
isLoading.value = false;
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
@ -697,6 +706,15 @@
await getTemplateOptions();
};
// formCreate
watch(
() => formRules.value,
() => {
rowLength.value = formRules.value.length + 2;
},
{ deep: true }
);
//
watch(
() => fileList.value,

View File

@ -14,7 +14,7 @@
<a-button v-permission="['PROJECT_BUG:READ+ADD']" type="primary" @click="handleCreate"
>{{ t('bugManagement.createBug') }}
</a-button>
<a-button v-permission="['PROJECT_BUG:READ+IMPORT']" :loading="!isComplete" type="outline" @click="handleSync"
<a-button :loading="!isComplete" type="outline" @click="handleSync"
>{{ t('bugManagement.syncBug') }}
</a-button>
</div>
@ -33,14 +33,14 @@
<a-button type="text" class="px-0" @click="handleShowDetail(record.id, rowIndex)">{{ record.num }}</a-button>
</template>
<template #operation="{ record }">
<div class="flex flex-row flex-nowrap">
<span v-permission="['PROJECT_BUG:READ+ADD']" class="flex flex-row">
<div class="flex flex-nowrap items-center">
<span v-permission="['PROJECT_BUG:READ+ADD']" class="flex flex-row items-center">
<MsButton class="!mr-0" @click="handleCopy(record)">{{ t('common.copy') }}</MsButton>
<a-divider class="h-[16px]" direction="vertical" />
<a-divider class="!mx-2 h-[12px]" direction="vertical" />
</span>
<span v-permission="['PROJECT_BUG:READ+UPDATE']" class="flex flex-row">
<span v-permission="['PROJECT_BUG:READ+UPDATE']" class="flex flex-row items-center">
<MsButton class="!mr-0" @click="handleEdit(record)">{{ t('common.edit') }}</MsButton>
<a-divider class="h-[16px]" direction="vertical" />
<a-divider class="!mx-2 h-[12px]" direction="vertical" />
</span>
<MsTableMoreAction
v-permission="['PROJECT_BUG:READ+DELETE']"
@ -471,7 +471,7 @@
slotName: 'operation',
dataIndex: 'operation',
fixed: 'right',
width: 158,
width: 200,
},
];
@ -616,6 +616,7 @@
pre: syncObject.operator === 'lt',
createTime: syncObject.time,
});
Message.success(t('bugManagement.syncSuccess'));
isComplete.value = false;
//
resume();

View File

@ -19,6 +19,7 @@ export default {
addBug: 'Create Bug',
editBug: 'Edit Bug',
sync: 'Sync',
syncSuccess: 'Synchronous success',
syncBugTipRowOne: 'Sync third plant bug',
syncBugTipRowTwo: 'Create bug and sync bug',
bugAutoSync: 'System {name} auto sync',

View File

@ -19,6 +19,7 @@ export default {
createTime: '创建时间',
updateTime: '更新时间',
sync: '同步',
syncSuccess: '同步成功',
syncBugTipRowOne: '将第三方的缺陷同步到缺陷管理中,',
syncBugTipRowTwo: '新增缺陷和更新已有的缺陷?',
bugAutoSync: '系统 {name} 自动同步',

View File

@ -685,6 +685,12 @@
border-color: rgb(var(--primary-5)) !important;
}
}
:deep(.arco-input-wrapper) {
border-color: transparent !important;
&:hover {
border-color: rgb(var(--primary-5)) !important;
}
}
:deep(.arco-select-view-multiple) {
border-color: transparent !important;
.arco-select-view-suffix {
@ -709,6 +715,18 @@
border-color: rgb(var(--primary-5)) !important;
}
}
:deep(.arco-picker) {
border-color: transparent !important;
.arco-picker-suffix {
visibility: hidden;
}
&:hover {
border-color: rgb(var(--primary-5)) !important;
arco-picker-suffix {
visibility: visible !important;
}
}
}
}
.rightButtons {
:deep(.ms-button--secondary):hover,

View File

@ -12,7 +12,12 @@
@refresh="fetchData()"
>
<template #left>
<a-tooltip :content="moduleNamePath + '('+(props.modulesCount[props.activeFolder] || 0) +')' " position="bottom" background-color="#FFFFFF" :content-style="{color: '#000000'}">
<a-tooltip
:content="moduleNamePath + '(' + (props.modulesCount[props.activeFolder] || 0) + ')'"
position="bottom"
background-color="#FFFFFF"
:content-style="{ color: '#000000' }"
>
<div class="one-line-text max-h-[32px] max-w-[116px] text-[var(--color-text-1)]"
>{{ moduleNamePath }}
<span class="text-[var(--color-text-4)]"> ({{ props.modulesCount[props.activeFolder] || 0 }})</span></div
@ -198,14 +203,24 @@
</template>
<!-- 渲染自定义字段结束 -->
<template #operation="{ record }">
<MsButton v-permission="['FUNCTIONAL_CASE:READ+UPDATE']" @click="operateCase(record, 'edit')">{{
<MsButton v-permission="['FUNCTIONAL_CASE:READ+UPDATE']" class="!mr-0" @click="operateCase(record, 'edit')">{{
t('common.edit')
}}</MsButton>
<a-divider v-permission="['FUNCTIONAL_CASE:READ+UPDATE']" direction="vertical" :margin="8"></a-divider>
<MsButton v-permission="['FUNCTIONAL_CASE:READ+ADD']" @click="operateCase(record, 'copy')">{{
<a-divider
v-permission="['FUNCTIONAL_CASE:READ+UPDATE']"
class="!mx-2 h-[12px]"
direction="vertical"
:margin="8"
></a-divider>
<MsButton v-permission="['FUNCTIONAL_CASE:READ+ADD']" class="!mr-0" @click="operateCase(record, 'copy')">{{
t('caseManagement.featureCase.copy')
}}</MsButton>
<a-divider v-permission="['FUNCTIONAL_CASE:READ+ADD']" direction="vertical" :margin="8"></a-divider>
<a-divider
v-permission="['FUNCTIONAL_CASE:READ+ADD']"
class="!mx-2 h-[12px]"
direction="vertical"
:margin="8"
></a-divider>
<span v-permission="['FUNCTIONAL_CASE:READ+DELETE']">
<MsTableMoreAction :list="moreActions" @select="handleMoreActionSelect($event, record)" />
</span>
@ -611,7 +626,7 @@
fixed: 'right',
showInTable: true,
showDrag: false,
width: hasOperationPermission.value ? 260 : 50,
width: hasOperationPermission.value ? 200 : 50,
},
];
const platformInfo = ref<Record<string, any>>({});

View File

@ -28,7 +28,7 @@
:upload-image="handleUploadImage"
class="mt-2"
/>
<div v-else v-dompurify-html="detailForm?.prerequisite || '-'"></div>
<div v-else v-dompurify-html="detailForm?.prerequisite || '-'" class="markdown-body"></div>
</a-form-item>
<a-form-item
field="step"
@ -82,7 +82,7 @@
v-model:filed-ids="expectedResultFileIds"
:upload-image="handleUploadImage"
/>
<div v-else v-dompurify-html="detailForm.expectedResult || '-'"></div>
<div v-else v-dompurify-html="detailForm.expectedResult || '-'" class="markdown-body"></div>
</a-form-item>
<a-form-item field="description" :label="t('caseManagement.featureCase.remark')">
<MsRichText
@ -91,7 +91,7 @@
v-model:raw="detailForm.description"
:upload-image="handleUploadImage"
/>
<div v-else v-dompurify-html="detailForm.description || '-'"></div>
<div v-else v-dompurify-html="detailForm.description || '-'" class="markdown-body"></div>
</a-form-item>
<div v-if="isEditPreposition" class="flex justify-end">
<a-button type="secondary" @click="handleCancel">{{ t('common.cancel') }}</a-button>
@ -133,7 +133,7 @@
</div>
</div>
</a-form-item> -->
<div v-permission="['FUNCTIONAL_CASE:READ+UPDATE']">
<div v-permission="['FUNCTIONAL_CASE:READ+UPDATE']">
<AddAttachment v-model:file-list="fileList" multiple @change="handleChange" @link-file="associatedFile" />
</div>
</a-form>

View File

@ -79,7 +79,6 @@
<script lang="ts" setup>
import { Message } from '@arco-design/web-vue';
import { isEqual } from 'lodash-es';
import TabSettingDrawer from './common/TabSettingDrawer.vue';
import AssertTab from './envParams/AssertTab.vue';
@ -88,9 +87,7 @@
import HostTab from './envParams/HostTab.vue';
import HttpTab from './envParams/HttpTab.vue';
import PluginTab from './envParams/PluginTab.vue';
import PostTab from './envParams/PostTab.vue';
import PreAndPostTab from './envParams/preAndPost.vue';
import PreTab from './envParams/PreTab.vue';
import { getEnvPlugin, updateOrAddEnv } from '@/api/modules/project-management/envManagement';
import { useI18n } from '@/hooks/useI18n';
@ -104,7 +101,7 @@
const { setState } = useLeaveUnSaveTip();
setState(false);
const emit = defineEmits<{
(e: 'ok'): void;
(e: 'ok', envId: string | undefined): void;
(e: 'resetEnv'): void;
}>();
@ -206,8 +203,9 @@
store.currentEnvDetailInfo.mock = true;
await updateOrAddEnv({ fileList: [], request: store.currentEnvDetailInfo });
setState(true);
Message.success(t('common.saveSuccess'));
emit('ok');
Message.success(store.currentEnvDetailInfo.id ? t('common.updateSuccess') : t('common.saveSuccess'));
emit('ok', store.currentEnvDetailInfo.id);
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
@ -232,13 +230,6 @@
}
});
// watchEffect(() => {
// if (store.currentEnvDetailInfo) {
// const { currentEnvDetailInfo, backupEnvDetailInfo } = store;
// canSave.value = !isEqual(currentEnvDetailInfo, backupEnvDetailInfo);
// }
// });
const initTab = async () => {
tabSettingVisible.value = false;
const tmpArr = (await store.getContentTabList()) || [];

View File

@ -213,7 +213,7 @@
<EnvParamBox
v-else-if="showType === 'PROJECT' && activeKey !== ALL_PARAM"
@reset-env="resetHandler"
@ok="getDetail"
@ok="successHandler"
/>
<!-- 环境组 -->
<EnvGroupBox v-else-if="showType === 'PROJECT_GROUP'" @save-or-update="handleUpdateEnvGroup" />
@ -287,7 +287,14 @@
const showType = ref<EnvAuthScopeEnum>(EnvAuthScopeEnum.PROJECT); //
const activeKey = computed(() => store.currentId); // id
const activeKey = computed({
get() {
return store.currentId;
},
set(val) {
activeKey.value = val;
},
}); // id
const activeGroupKey = computed(() => store.currentGroupId); // group id
@ -518,8 +525,7 @@
}
await deleteEnv(id);
Message.success(t('common.deleteSuccess'));
store.setCurrentId(envList.value[0].id);
searchData();
initData(keyword.value, true);
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
@ -621,8 +627,12 @@
}
}
function getDetail() {
store.initEnvDetail();
function successHandler(envId: string | undefined) {
if (!envId) {
initData(keyword.value, true);
} else {
store.initEnvDetail();
}
}
onMounted(() => {