refactor(缺陷管理): 缺陷管理创建缺陷创建组件抽离&重构

This commit is contained in:
xinxin.wu 2024-08-22 11:37:34 +08:00 committed by Craftsman
parent 00f4cf449c
commit 01a912b399
5 changed files with 441 additions and 363 deletions

View File

@ -32,7 +32,7 @@ const BugManagement: AppRouteRecordRaw = {
{
path: 'detail/:mode?',
name: BugManagementRouteEnum.BUG_MANAGEMENT_DETAIL,
component: () => import('@/views/bug-management/edit.vue'),
component: () => import('@/views/bug-management/createAndEditBug.vue'),
meta: {
locale: 'bugManagement.editBug',
roles: ['PROJECT_BUG:READ+ADD', 'PROJECT_BUG:READ+UPDATE'],

View File

@ -0,0 +1,156 @@
<template>
<MsCard
has-breadcrumb
:title="title"
:loading="loading"
:is-edit="isEdit"
@save="saveHandler(false)"
@save-and-continue="saveHandler(true)"
>
<template v-if="!isEdit" #headerRight>
<a-select
v-model="bugTemplateId"
class="w-[240px]"
:options="templateOption"
allow-search
:placeholder="t('bugManagement.edit.defaultSystemTemplate')"
/>
</template>
<BugDetail ref="bugDetailRef" v-model:template-id="bugTemplateId" :bug-id="bugId" @save-params="saveParams" />
</MsCard>
</template>
<script setup lang="ts">
import { useRoute } from 'vue-router';
import { Message } from '@arco-design/web-vue';
import MsCard from '@/components/pure/ms-card/index.vue';
import BugDetail from './edit.vue';
import { createOrUpdateBug, getTemplateOption } from '@/api/modules/bug-management';
import { useI18n } from '@/hooks/useI18n';
import useLeaveUnSaveTip from '@/hooks/useLeaveUnSaveTip';
import useVisit from '@/hooks/useVisit';
import router from '@/router';
import { useAppStore } from '@/store';
import { BugEditFormObject } from '@/models/bug-management';
import { BugManagementRouteEnum } from '@/enums/routeEnum';
defineOptions({ name: 'BugEditPage' });
const { setIsSave } = useLeaveUnSaveTip();
setIsSave(false);
const { t } = useI18n();
interface TemplateOption {
label: string;
value: string;
}
const appStore = useAppStore();
const route = useRoute();
const templateOption = ref<TemplateOption[]>([]);
const bugTemplateId = ref<string>('');
const loading = ref(false);
const isEdit = computed(() => !!route.query.id && route.params.mode === 'edit');
const bugId = computed(() => route.query.id as string | undefined);
const isCopy = computed(() => route.params.mode === 'copy');
const visitedKey = 'doNotNextTipCreateBug';
const { getIsVisited } = useVisit(visitedKey);
const title = computed(() => {
if (isCopy.value) {
return t('bugManagement.copyBug');
}
return isEdit.value ? t('bugManagement.editBug') : t('bugManagement.createBug');
});
const getTemplateOptions = async () => {
try {
loading.value = true;
const res = await getTemplateOption(appStore.currentProjectId);
templateOption.value = res.map((item) => {
if (item.enableDefault && !isEdit.value) {
//
bugTemplateId.value = item.id;
}
return {
label: item.name,
value: item.id,
};
});
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
loading.value = false;
}
};
const bugDetailRef = ref<InstanceType<typeof BugDetail>>();
async function saveParams(isContinue: boolean, params: { request: BugEditFormObject; fileList: File[] }) {
try {
loading.value = true;
const res = await createOrUpdateBug(params);
if (isEdit.value) {
setIsSave(true);
Message.success(t('common.updateSuccess'));
router.push({
name: BugManagementRouteEnum.BUG_MANAGEMENT_INDEX,
});
} else {
Message.success(t('common.createSuccess'));
if (isContinue) {
setIsSave(false);
bugDetailRef.value?.resetForm();
} else {
setIsSave(true);
//
if (getIsVisited()) {
router.push({
name: BugManagementRouteEnum.BUG_MANAGEMENT_INDEX,
});
return;
}
router.push({
name: BugManagementRouteEnum.BUG_MANAGEMENT_CREATE_SUCCESS,
query: {
...route.query,
id: res.data.id,
},
});
}
}
} catch (error) {
console.log(error);
} finally {
loading.value = false;
}
}
const saveHandler = async (isContinue = false) => {
bugDetailRef.value?.saveHandler(isContinue);
};
const initDefaultFields = async () => {
await getTemplateOptions();
};
onBeforeMount(() => {
initDefaultFields();
});
</script>
<style lang="less" scoped>
:deep(.arco-form-item-extra) {
font-size: 14px;
color: var(--color-text-4);
}
:deep(.arco-form-item-content) {
overflow-wrap: anywhere;
}
</style>

View File

@ -1,22 +1,4 @@
<template>
<MsCard
has-breadcrumb
:title="title"
:loading="loading"
:is-edit="isEdit"
@save="saveHandler(false)"
@save-and-continue="saveHandler(true)"
>
<template v-if="!isEdit" #headerRight>
<a-select
v-model="form.templateId"
class="w-[240px]"
:options="templateOption"
allow-search
:placeholder="t('bugManagement.edit.defaultSystemTemplate')"
@change="templateChange"
/>
</template>
<a-form ref="formRef" :model="form" layout="vertical">
<div class="flex flex-row">
<div class="left mt-[16px] w-[calc(100%-428px)] grow">
@ -159,12 +141,7 @@
</a-skeleton>
<a-form v-else :model="form" layout="vertical">
<div style="display: inline-block; width: 100%; word-wrap: break-word">
<MsFormCreate
ref="formCreateRef"
v-model:formItem="formItem"
v-model:api="fApi"
:form-rule="formRules"
/>
<MsFormCreate ref="formCreateRef" v-model:formItem="formItem" v-model:api="fApi" :form-rule="formRules" />
</div>
<a-form-item v-if="!isPlatformDefaultTemplate" field="tag" :label="t('bugManagement.tag')">
@ -179,7 +156,6 @@
</div>
</div>
</a-form>
</MsCard>
<div>
<MsUpload
v-model:file-list="fileList"
@ -211,7 +187,6 @@
import { Message } from '@arco-design/web-vue';
import MsButton from '@/components/pure/ms-button/index.vue';
import MsCard from '@/components/pure/ms-card/index.vue';
import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
import { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue';
@ -225,13 +200,11 @@
import {
checkFileIsUpdateRequest,
createOrUpdateBug,
downloadFileRequest,
editorUploadFile,
getAssociatedFileList,
getBugDetail,
getTemplateById,
getTemplateOption,
previewFile,
transferFileRequest,
updateFile,
@ -240,9 +213,6 @@
import { getModules, getModulesCount } from '@/api/modules/project-management/fileManagement';
import { EditorPreviewFileUrl } from '@/api/requrls/bug-management';
import { useI18n } from '@/hooks/useI18n';
import useLeaveUnSaveTip from '@/hooks/useLeaveUnSaveTip';
import useVisit from '@/hooks/useVisit';
import router from '@/router';
import { useAppStore } from '@/store';
import useUserStore from '@/store/modules/user';
import { downloadByteFile } from '@/utils';
@ -260,24 +230,29 @@
import { TableQueryParams } from '@/models/common';
import { SelectValue } from '@/models/projectManagement/menuManagement';
import type { CustomField } from '@/models/setting/template';
import { BugManagementRouteEnum } from '@/enums/routeEnum';
import { convertToFile } from '../case-management/caseManagementFeature/components/utils';
import { convertToFileByBug } from './utils';
const props = defineProps<{
bugId?: string;
templateId: string;
}>();
const emit = defineEmits<{
(e: 'saveParams', isContinue: boolean, params: { request: BugEditFormObject; fileList: File[] }): void;
}>();
const innerTemplateId = defineModel<string>('templateId', {
required: true,
});
defineOptions({ name: 'BugEditPage' });
const { setIsSave } = useLeaveUnSaveTip();
setIsSave(false);
const { t } = useI18n();
interface TemplateOption {
label: string;
value: string;
}
const appStore = useAppStore();
const route = useRoute();
const templateOption = ref<TemplateOption[]>([]);
const form = ref<BugEditFormObject>({
projectId: appStore.currentProjectId,
title: '',
@ -314,7 +289,7 @@
const acceptType = ref('none'); // -
const userStore = useUserStore();
const isEdit = computed(() => !!route.query.id && route.params.mode === 'edit');
const bugId = computed(() => route.query.id || '');
const bugId = ref<string | undefined>(props.bugId);
const isEditOrCopy = computed(() => !!bugId.value);
const isCopy = computed(() => route.params.mode === 'copy');
const isPlatformDefaultTemplate = ref(false);
@ -324,15 +299,7 @@
const descriptionFileIds = ref<string[]>([]);
// -/ID
const descriptionFileIdMap = ref<Record<string, string[]>>({});
const visitedKey = 'doNotNextTipCreateBug';
const { getIsVisited } = useVisit(visitedKey);
const title = computed(() => {
if (isCopy.value) {
return t('bugManagement.copyBug');
}
return isEdit.value ? t('bugManagement.editBug') : t('bugManagement.createBug');
});
const isLoading = ref<boolean>(true);
const rowLength = ref<number>(0);
@ -462,29 +429,6 @@
}
};
const getTemplateOptions = async () => {
try {
loading.value = true;
const res = await getTemplateOption(appStore.currentProjectId);
templateOption.value = res.map((item) => {
if (item.enableDefault && !isEdit.value) {
//
form.value.templateId = item.id;
templateChange(item.id);
}
return {
label: item.name,
value: item.id,
};
});
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
loading.value = false;
}
};
//
async function handlePreview(item: MsFileItem) {
try {
@ -568,14 +512,8 @@
return fileIds;
}
//
const saveHandler = async (isContinue = false) => {
formRef.value.validate((error: any) => {
if (!error) {
fApi.value.validate(async (valid: any) => {
if (valid === true) {
try {
loading.value = true;
function makeParams() {
//
const customFields: BugEditCustomFieldItem[] = [];
if (formItem.value && formItem.value.length) {
formItem.value.forEach((item: FormRuleItem) => {
@ -619,7 +557,6 @@
};
});
}
const tmpObj: BugEditFormObject = {
...form.value,
customFields,
@ -632,18 +569,14 @@
}
//
const localFiles = fileList.value.filter((item) => item.local && item.status === 'init');
//
const res = await createOrUpdateBug({ request: tmpObj, fileList: localFiles as unknown as File[] });
if (isEdit.value) {
setIsSave(true);
Message.success(t('common.updateSuccess'));
router.push({
name: BugManagementRouteEnum.BUG_MANAGEMENT_INDEX,
});
} else {
Message.success(t('common.createSuccess'));
if (isContinue) {
setIsSave(false);
return {
request: tmpObj,
fileList: localFiles as unknown as File[],
};
}
async function resetForm() {
//
const { templateId } = form.value;
//
@ -658,30 +591,15 @@
await templateChange(templateId);
//
fileList.value = [];
} else {
setIsSave(true);
//
if (getIsVisited()) {
router.push({
name: BugManagementRouteEnum.BUG_MANAGEMENT_INDEX,
});
return;
}
router.push({
name: BugManagementRouteEnum.BUG_MANAGEMENT_CREATE_SUCCESS,
query: {
...route.query,
id: res.data.id,
},
});
}
}
} catch (err) {
// eslint-disable-next-line no-console
console.log(err);
} finally {
loading.value = false;
}
//
const saveHandler = async (isContinue = false) => {
formRef.value.validate((error: any) => {
if (!error) {
fApi.value.validate(async (valid: any) => {
if (valid === true) {
emit('saveParams', isContinue, makeParams());
}
});
}
@ -812,10 +730,6 @@
loading.value = false;
};
const initDefaultFields = async () => {
await getTemplateOptions();
};
// formCreate
watch(
() => formRules.value,
@ -846,12 +760,29 @@
return data;
}
onMounted(async () => {
await initDefaultFields();
if (isEditOrCopy.value) {
//
await getDetailInfo();
watch(
() => innerTemplateId.value,
(val) => {
if (val) {
form.value.templateId = val;
templateChange(val);
}
},
{
immediate: true,
}
);
onMounted(() => {
if (isEditOrCopy.value) {
//
getDetailInfo();
}
});
defineExpose({
saveHandler,
resetForm,
});
</script>

View File

@ -18,7 +18,8 @@
@loaded="loadedCase"
>
<template #titleName>
<div :class="`case-title flex items-center ${isEditTitle ? 'w-full' : ''}`">
<div :class="`case-title flex items-center gap-[8px] ${isEditTitle ? 'w-full' : ''}`">
<div v-if="!isEditTitle" class="flex items-center"><caseLevel :case-level="caseLevels" /></div>
<a-input
v-if="isEditTitle"
v-model="titleName"
@ -30,7 +31,7 @@
@keydown.enter="handleEditName"
/>
<div v-else class="flex items-center">
<div> {{ detailInfo?.num }} </div>
<div> [ {{ detailInfo?.num }} ] </div>
<div
:class="`${
hasAnyPermission(['FUNCTIONAL_CASE:READ+UPDATE']) ? 'hover-title-name' : ''
@ -41,9 +42,6 @@
</div>
</div>
</template>
<template #titleLeft>
<div v-if="!isEditTitle" class="flex items-center"><caseLevel :case-level="caseLevels" /></div>
</template>
<template #titleRight="{ loading }">
<div class="rightButtons flex items-center">
<MsButton

View File

@ -1,7 +1,23 @@
<template>
<div>
<div class="flex items-center justify-between">
<div v-if="showType === 'link'" class="flex">
<div class="mb-[16px] flex items-center justify-between">
<div>
<a-radio-group v-model:model-value="showType" type="button" size="medium">
<a-radio value="link">{{ t('caseManagement.featureCase.directLink') }}</a-radio>
<a-radio value="testPlan">{{ t('caseManagement.featureCase.testPlan') }}</a-radio>
</a-radio-group>
<a-input-search
v-model:model-value="keyword"
:placeholder="t('caseManagement.featureCase.searchByName')"
allow-clear
class="mx-[8px] w-[240px]"
@search="getFetch"
@press-enter="getFetch"
@clear="resetFetch"
@input="changeHandler"
></a-input-search>
</div>
<div v-if="showType === 'link'" class="flex items-center">
<a-tooltip v-if="!total">
<template #content>
{{ t('caseManagement.featureCase.noAssociatedDefect') }}
@ -32,29 +48,6 @@
>{{ t('testPlan.featureCase.noBugDataNewBug') }}
</a-button>
</div>
<div v-else v-permission="['FUNCTIONAL_CASE:READ+UPDATE']" class="font-medium">{{
t('caseManagement.featureCase.testPlanLinkList')
}}</div>
<div class="mb-4">
<a-radio-group v-model:model-value="showType" type="button" class="file-show-type ml-[4px]">
<a-radio value="link" class="show-type-icon p-[2px]">{{
t('caseManagement.featureCase.directLink')
}}</a-radio>
<a-radio value="testPlan" class="show-type-icon p-[2px]">{{
t('caseManagement.featureCase.testPlan')
}}</a-radio>
</a-radio-group>
<a-input-search
v-model:model-value="keyword"
:placeholder="t('caseManagement.featureCase.searchByName')"
allow-clear
class="mx-[8px] w-[240px]"
@search="getFetch"
@press-enter="getFetch"
@clear="resetFetch"
@input="changeHandler"
></a-input-search>
</div>
</div>
<BugList
v-if="showType === 'link'"