refactor(功能用例&缺陷管理): 功能用例基本信息和缺陷管理基本信息调整
This commit is contained in:
parent
bfe7789e78
commit
28b2e9197f
|
@ -265,6 +265,7 @@
|
|||
excludeIds: [...excludeKeys].concat(...(props.associatedIds || [])),
|
||||
selectIds: selectorStatus === 'all' ? [] : [...selectedKeys],
|
||||
selectAll: selectorStatus === 'all',
|
||||
associateApiType: 'API_CASE',
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -240,6 +240,7 @@
|
|||
excludeIds: [...excludeKeys].concat(...(props.associatedIds || [])),
|
||||
selectIds: selectorStatus === 'all' ? [] : [...selectedKeys],
|
||||
selectAll: selectorStatus === 'all',
|
||||
associateApiType: 'API',
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,22 +1,14 @@
|
|||
<template>
|
||||
<TreeFolderAll
|
||||
v-if="props.activeTab === CaseLinkEnum.API"
|
||||
v-model:selectedProtocols="selectedProtocols"
|
||||
:active-folder="activeFolder"
|
||||
:folder-name="props.folderName"
|
||||
:all-count="allCount"
|
||||
:show-expand-api="false"
|
||||
:not-show-operation="props.activeTab !== 'API'"
|
||||
@set-active-folder="setActiveFolder"
|
||||
@selected-protocols-change="selectedProtocolsChange"
|
||||
/>
|
||||
<MsFolderAll
|
||||
v-else
|
||||
:active-folder="activeFolder"
|
||||
:folder-name="props.folderName"
|
||||
:all-count="allCount"
|
||||
@set-active-folder="setActiveFolder"
|
||||
>
|
||||
</MsFolderAll>
|
||||
<a-divider class="my-[8px] mt-0" />
|
||||
<div class="mb-[8px] flex items-center gap-[8px]">
|
||||
<a-input
|
||||
|
|
|
@ -368,7 +368,6 @@
|
|||
activeFolderName.value = name ?? '';
|
||||
}
|
||||
|
||||
const isAddAssociatedCase = ref<boolean>(false);
|
||||
const functionalTableRef = ref<InstanceType<typeof CaseTable>>();
|
||||
const apiTableRef = ref<InstanceType<typeof ApiTable>>();
|
||||
const caseTableRef = ref<InstanceType<typeof ApiCaseTable>>();
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { ReviewItem, ReviewResult, ReviewStatus } from '@/models/caseManagement/caseReview';
|
||||
import type { DetailCase } from '@/models/caseManagement/featureCase';
|
||||
|
||||
// 评审结果
|
||||
export type ReviewResultMap = Record<
|
||||
|
@ -106,3 +107,24 @@ export const minderTagMap = {
|
|||
EXPECTED_RESULT: 'minder.tag.expect',
|
||||
DESCRIPTION: 'minder.tag.remark',
|
||||
};
|
||||
|
||||
export const defaultCaseDetail: DetailCase = {
|
||||
id: '',
|
||||
projectId: '',
|
||||
templateId: '',
|
||||
name: '',
|
||||
prerequisite: '', // prerequisite
|
||||
caseEditType: '', // 编辑模式:步骤模式/文本模式
|
||||
steps: '',
|
||||
textDescription: '',
|
||||
expectedResult: '', // 预期结果
|
||||
description: '',
|
||||
publicCase: false, // 是否公共用例
|
||||
moduleId: '',
|
||||
versionId: '',
|
||||
tags: [],
|
||||
customFields: [], // 自定义字段集合
|
||||
relateFileMetaIds: [], // 关联文件ID集合
|
||||
functionalPriority: '',
|
||||
reviewStatus: 'UN_REVIEWED',
|
||||
};
|
||||
|
|
|
@ -0,0 +1,290 @@
|
|||
<template>
|
||||
<a-spin :loading="loading" class="w-full">
|
||||
<div class="form-item-container">
|
||||
<!-- 所属平台一致, 详情展示 -->
|
||||
<div v-if="props.currentPlatform === detailInfo.platform" class="h-full w-full">
|
||||
<!-- 自定义字段开始 -->
|
||||
<div class="inline-block w-full break-words">
|
||||
<MsFormCreate
|
||||
v-if="props.formRule.length"
|
||||
ref="formCreateRef"
|
||||
v-model:form-item="innerFormItem"
|
||||
v-model:api="fApi"
|
||||
v-model:form-rule="innerFormRules"
|
||||
class="w-full"
|
||||
:option="options"
|
||||
@change="handelFormCreateChange"
|
||||
/>
|
||||
<!-- 自定义字段结束 -->
|
||||
<div
|
||||
v-if="!props.isPlatformDefaultTemplate && hasAnyPermission(['PROJECT_BUG:READ+UPDATE'])"
|
||||
class="baseItem"
|
||||
>
|
||||
<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="innerTags"
|
||||
:disabled="!hasAnyPermission(['PROJECT_BUG:READ+UPDATE'])"
|
||||
@blur="changeTag"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 内置基础信息结束 -->
|
||||
</div>
|
||||
<!-- 所属平台不一致, 详情不展示, 展示空面板 -->
|
||||
<div v-else>
|
||||
<a-empty> {{ $t('messageBox.noContent') }} </a-empty>
|
||||
</div>
|
||||
</div>
|
||||
</a-spin>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { cloneDeep, debounce } from 'lodash-es';
|
||||
|
||||
import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
|
||||
import type { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
|
||||
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
||||
|
||||
import { createOrUpdateBug } from '@/api/modules/bug-management';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { useAppStore } from '@/store';
|
||||
import { hasAnyPermission } from '@/utils/permission';
|
||||
|
||||
import { BugEditCustomField, BugEditFormObject } from '@/models/bug-management';
|
||||
|
||||
import { makeCustomFieldsParams } from '../utils';
|
||||
|
||||
const appStore = useAppStore();
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps<{
|
||||
detail: Record<string, any>;
|
||||
currentPlatform: string;
|
||||
formRule: FormItem[];
|
||||
isPlatformDefaultTemplate: boolean;
|
||||
platformSystemFields: BugEditCustomField[]; // 平台系统字段
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:tags', val: string[]): void;
|
||||
(e: 'updateSuccess'): void;
|
||||
}>();
|
||||
|
||||
const loading = ref<boolean>(false);
|
||||
|
||||
const detailInfo = ref<Record<string, any>>({ match: [] }); // 存储当前详情信息,通过loadBug 获取
|
||||
const fApi = ref<any>(null);
|
||||
|
||||
const innerFormRules = defineModel<FormItem[]>('formRule', { default: [] });
|
||||
const innerFormItem = defineModel<FormRuleItem[]>('formItem', { default: [] });
|
||||
const innerTags = defineModel<string[]>('tags', { default: [] });
|
||||
// 表单配置项
|
||||
const options = {
|
||||
resetBtn: false, // 不展示默认配置的重置和提交
|
||||
submitBtn: false,
|
||||
on: false, // 取消绑定on事件
|
||||
form: {
|
||||
layout: 'horizontal',
|
||||
labelAlign: 'left',
|
||||
labelColProps: {
|
||||
span: 9,
|
||||
},
|
||||
wrapperColProps: {
|
||||
span: 15,
|
||||
},
|
||||
},
|
||||
// 暂时默认
|
||||
row: {
|
||||
gutter: 0,
|
||||
},
|
||||
wrap: {
|
||||
'asterisk-position': 'end',
|
||||
'validate-trigger': ['change'],
|
||||
},
|
||||
};
|
||||
|
||||
async function makeParams() {
|
||||
const customFields = await makeCustomFieldsParams(innerFormItem.value);
|
||||
if (props.isPlatformDefaultTemplate) {
|
||||
// 平台系统默认字段插入自定义集合
|
||||
props.platformSystemFields.forEach((item) => {
|
||||
customFields.push({
|
||||
id: item.fieldId,
|
||||
name: item.fieldName,
|
||||
type: item.type,
|
||||
value: item.defaultValue,
|
||||
});
|
||||
});
|
||||
}
|
||||
const params: BugEditFormObject = {
|
||||
projectId: appStore.currentProjectId,
|
||||
id: detailInfo.value.id,
|
||||
templateId: detailInfo.value.templateId,
|
||||
tags: innerTags.value,
|
||||
deleteLocalFileIds: [],
|
||||
unLinkRefIds: [],
|
||||
linkFileIds: [],
|
||||
customFields,
|
||||
richTextTmpFileIds: [],
|
||||
};
|
||||
if (!props.isPlatformDefaultTemplate) {
|
||||
params.description = detailInfo.value.description;
|
||||
params.title = detailInfo.value.title;
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
function saveHandler() {
|
||||
try {
|
||||
fApi.value?.validate().then(async (valid: any) => {
|
||||
if (valid === true) {
|
||||
loading.value = true;
|
||||
const requestParams = await makeParams();
|
||||
await createOrUpdateBug({ request: requestParams, fileList: [] as unknown as File[] });
|
||||
Message.success(t('common.editSuccess'));
|
||||
emit('updateSuccess');
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
const handelFormCreateChange = debounce(() => {
|
||||
saveHandler();
|
||||
}, 300);
|
||||
|
||||
const changeTag = debounce(() => {
|
||||
emit('update:tags', innerTags.value);
|
||||
saveHandler();
|
||||
}, 300);
|
||||
|
||||
watchEffect(() => {
|
||||
detailInfo.value = cloneDeep(props.detail);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.form-item-container {
|
||||
max-width: 50%;
|
||||
.baseItem {
|
||||
margin-bottom: 16px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
@apply flex;
|
||||
.label {
|
||||
width: 84px;
|
||||
color: var(--color-text-3);
|
||||
}
|
||||
}
|
||||
:deep(.arco-form-item-layout-horizontal) {
|
||||
margin-bottom: 16px !important;
|
||||
}
|
||||
:deep(.arco-form-item-label-col) {
|
||||
padding-right: 0;
|
||||
}
|
||||
:deep(.arco-col-9) {
|
||||
flex: 0 0 84px;
|
||||
width: 84px;
|
||||
}
|
||||
:deep(.arco-col-15) {
|
||||
flex: 0 0 calc(100% - 84px);
|
||||
width: calc(100% - 84px);
|
||||
}
|
||||
:deep(.arco-form-item-label::after) {
|
||||
color: red !important;
|
||||
}
|
||||
: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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -2,7 +2,7 @@
|
|||
<MsDetailDrawer
|
||||
ref="detailDrawerRef"
|
||||
v-model:visible="showDrawerVisible"
|
||||
:width="1200"
|
||||
:width="900"
|
||||
:footer="false"
|
||||
:title="t('bugManagement.detail.title', { id: detailInfo?.num, name: detailInfo?.title })"
|
||||
:tooltip-text="(detailInfo && detailInfo.title) || null"
|
||||
|
@ -91,7 +91,7 @@
|
|||
</MsButton>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="{ loading }">
|
||||
<template #default="{ detail }">
|
||||
<div
|
||||
ref="wrapperRef"
|
||||
:class="[
|
||||
|
@ -113,23 +113,12 @@
|
|||
class="no-content relative border-b"
|
||||
/>
|
||||
</div>
|
||||
<MsSplitBox
|
||||
expand-direction="right"
|
||||
:size="0.8"
|
||||
:max="0.7"
|
||||
:min="0.6"
|
||||
direction="horizontal"
|
||||
class="!h-[calc(100%-48px)]"
|
||||
:class="{ 'left-bug-detail': activeTab === 'comment' }"
|
||||
>
|
||||
<template #first>
|
||||
<div class="leftWrapper h-full">
|
||||
<a-spin :loading="detailLoading" class="w-full">
|
||||
<div class="tab-pane-container p-4">
|
||||
<div class="tab-pane-container">
|
||||
<BugDetailTab
|
||||
v-if="activeTab === 'detail'"
|
||||
ref="bugDetailTabRef"
|
||||
:form-item="formItem"
|
||||
:allow-edit="hasAnyPermission(['PROJECT_BUG:READ+UPDATE'])"
|
||||
:detail-info="detailInfo"
|
||||
:is-platform-default-template="isPlatformDefaultTemplate"
|
||||
|
@ -137,6 +126,17 @@
|
|||
:current-platform="props.currentPlatform"
|
||||
@update-success="detailDrawerRef?.initDetail()"
|
||||
/>
|
||||
<BasicInfo
|
||||
v-if="activeTab === 'basicInfo'"
|
||||
v-model:tags="tags"
|
||||
:form-rule="formRules"
|
||||
:detail="detail"
|
||||
:current-platform="props.currentPlatform"
|
||||
:is-platform-default-template="isPlatformDefaultTemplate"
|
||||
:loading="rightLoading"
|
||||
:platform-system-fields="platformSystemFields"
|
||||
@update-success="detailDrawerRef?.initDetail()"
|
||||
/>
|
||||
|
||||
<BugCaseTab
|
||||
v-else-if="activeTab === 'case'"
|
||||
|
@ -150,69 +150,6 @@
|
|||
</div>
|
||||
</a-spin>
|
||||
</div>
|
||||
</template>
|
||||
<template #second>
|
||||
<a-spin :loading="rightLoading" class="w-full">
|
||||
<!-- 所属平台一致, 详情展示 -->
|
||||
<div v-if="props.currentPlatform === detailInfo.platform" class="rightWrapper h-full p-4">
|
||||
<!-- 自定义字段开始 -->
|
||||
<div class="inline-block w-full break-words">
|
||||
<a-skeleton v-if="rightLoading" class="w-full" :loading="rightLoading" :animation="true">
|
||||
<a-space direction="vertical" class="w-[100%]" size="large">
|
||||
<a-skeleton-line :rows="14" :line-height="30" :line-spacing="30" />
|
||||
</a-space>
|
||||
</a-skeleton>
|
||||
<div v-if="!rightLoading" class="mb-4 font-medium">
|
||||
<strong>
|
||||
{{ t('bugManagement.detail.basicInfo') }}
|
||||
</strong>
|
||||
</div>
|
||||
<MsFormCreate
|
||||
v-if="!rightLoading"
|
||||
ref="formCreateRef"
|
||||
v-model:form-item="formItem"
|
||||
v-model:api="fApi"
|
||||
:form-rule="formRules"
|
||||
class="w-full"
|
||||
:option="options"
|
||||
@change="handelFormCreateChange"
|
||||
/>
|
||||
<!-- 自定义字段结束 -->
|
||||
<div
|
||||
v-if="!isPlatformDefaultTemplate && hasAnyPermission(['PROJECT_BUG:READ+UPDATE']) && !loading"
|
||||
class="baseItem"
|
||||
>
|
||||
<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"
|
||||
:disabled="!hasAnyPermission(['PROJECT_BUG:READ+UPDATE'])"
|
||||
@blur="changeTag"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 内置基础信息结束 -->
|
||||
</div>
|
||||
<!-- 所属平台不一致, 详情不展示, 展示空面板 -->
|
||||
<div v-else>
|
||||
<a-empty> {{ $t('messageBox.noContent') }} </a-empty>
|
||||
</div>
|
||||
</a-spin>
|
||||
</template>
|
||||
</MsSplitBox>
|
||||
</div>
|
||||
<CommentInput
|
||||
v-if="activeTab === 'comment' && hasAnyPermission(['PROJECT_BUG:READ+COMMENT'])"
|
||||
|
@ -235,20 +172,17 @@
|
|||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useClipboard } from '@vueuse/core';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { debounce } from 'lodash-es';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
|
||||
import type { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
|
||||
import type { FormItem } from '@/components/pure/ms-form-create/types';
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
|
||||
import MsTab from '@/components/pure/ms-tab/index.vue';
|
||||
import type { MsPaginationI } from '@/components/pure/ms-table/type';
|
||||
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
|
||||
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
||||
import CommentInput from '@/components/business/ms-comment/input.vue';
|
||||
import { CommentParams } from '@/components/business/ms-comment/types';
|
||||
import MsDetailDrawer from '@/components/business/ms-detail-drawer/index.vue';
|
||||
import BasicInfo from './basicInfo.vue';
|
||||
import BugCaseTab from './bugCaseTab.vue';
|
||||
import BugDetailTab from './bugDetailTab.vue';
|
||||
import BugHistoryTab from './bugHistoryTab.vue';
|
||||
|
@ -302,9 +236,8 @@
|
|||
const commentContent = ref('');
|
||||
const commentRef = ref();
|
||||
const noticeUserIds = ref<string[]>([]); // 通知人ids
|
||||
const fApi = ref();
|
||||
const formRules = ref<FormItem[]>([]); // 表单规则
|
||||
const formItem = ref<FormRuleItem[]>([]); // 表单项
|
||||
|
||||
const currentProjectId = computed(() => appStore.currentProjectId);
|
||||
const showDrawerVisible = defineModel<boolean>('visible', { default: false });
|
||||
const bugDetailTabRef = ref();
|
||||
|
@ -463,6 +396,10 @@
|
|||
}
|
||||
|
||||
const tabList = [
|
||||
{
|
||||
value: 'basicInfo',
|
||||
label: t('bugManagement.detail.basicInfo'),
|
||||
},
|
||||
{
|
||||
value: 'detail',
|
||||
label: t('bugManagement.detail.detail'),
|
||||
|
@ -577,54 +514,6 @@
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 单独更新字段
|
||||
*/
|
||||
async function updateFieldHandler() {
|
||||
try {
|
||||
rightLoading.value = true;
|
||||
await bugDetailTabRef.value?.handleSave();
|
||||
rightLoading.value = false;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
rightLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
const handelFormCreateChange = debounce(() => {
|
||||
updateFieldHandler();
|
||||
}, 300);
|
||||
|
||||
const changeTag = debounce(() => {
|
||||
detailInfo.value.tags = tags.value;
|
||||
updateFieldHandler();
|
||||
}, 300);
|
||||
|
||||
// 表单配置项
|
||||
const options = {
|
||||
resetBtn: false, // 不展示默认配置的重置和提交
|
||||
submitBtn: false,
|
||||
on: false, // 取消绑定on事件
|
||||
form: {
|
||||
layout: 'horizontal',
|
||||
labelAlign: 'left',
|
||||
labelColProps: {
|
||||
span: 9,
|
||||
},
|
||||
wrapperColProps: {
|
||||
span: 15,
|
||||
},
|
||||
},
|
||||
// 暂时默认
|
||||
row: {
|
||||
gutter: 0,
|
||||
},
|
||||
wrap: {
|
||||
'asterisk-position': 'end',
|
||||
'validate-trigger': ['change'],
|
||||
},
|
||||
};
|
||||
const uploadFileIds = ref<string[]>([]);
|
||||
async function publishHandler(currentContent: string) {
|
||||
try {
|
||||
|
@ -794,14 +683,9 @@
|
|||
justify-content: flex-start !important;
|
||||
}
|
||||
.tab-pane-container {
|
||||
@apply flex-1 overflow-y-auto px-4;
|
||||
@apply flex-1 overflow-y-auto p-4;
|
||||
.ms-scroll-bar();
|
||||
}
|
||||
//:deep(.w-full .arco-form-item-label) {
|
||||
// display: inline-block;
|
||||
// width: 100%;
|
||||
// word-wrap: break-word;
|
||||
//}
|
||||
:deep(.arco-form-item-content) {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
|
|
@ -202,7 +202,6 @@
|
|||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import { FormRuleItem } from '@/components/pure/ms-form-create/types';
|
||||
import MsIconfont from '@/components/pure/ms-icon-font/index.vue';
|
||||
import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue';
|
||||
import MsFileList from '@/components/pure/ms-upload/fileList.vue';
|
||||
|
@ -232,7 +231,6 @@
|
|||
import { useAppStore } from '@/store';
|
||||
import { downloadByteFile, sleep } from '@/utils';
|
||||
import { hasAnyPermission } from '@/utils/permission';
|
||||
import { findParents, Option } from '@/utils/recursion';
|
||||
|
||||
import { BugEditCustomField, BugEditCustomFieldItem, BugEditFormObject } from '@/models/bug-management';
|
||||
import { AssociatedList, AttachFileInfo } from '@/models/caseManagement/featureCase';
|
||||
|
@ -248,7 +246,7 @@
|
|||
|
||||
const props = defineProps<{
|
||||
detailInfo: BugEditFormObject;
|
||||
formItem: FormRuleItem[];
|
||||
// formItem: FormRuleItem[];
|
||||
allowEdit?: boolean; // 是否允许编辑
|
||||
isPlatformDefaultTemplate: boolean; // 是否是平台默认模板
|
||||
platformSystemFields: BugEditCustomField[]; // 平台系统字段
|
||||
|
@ -453,26 +451,22 @@
|
|||
return fileIds;
|
||||
}
|
||||
|
||||
function getDetailCustomFields() {
|
||||
return props.detailInfo.customFields.map((item: any) => {
|
||||
return {
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
type: item.type,
|
||||
value: item.value,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// 保存操作
|
||||
async function handleSave() {
|
||||
try {
|
||||
confirmLoading.value = true;
|
||||
const { formItem } = props;
|
||||
const customFields: BugEditCustomFieldItem[] = [];
|
||||
if (formItem && formItem.length) {
|
||||
formItem.forEach((item: FormRuleItem) => {
|
||||
let itemVal = item.value;
|
||||
if (item.sourceType === 'CASCADER') {
|
||||
itemVal = findParents(item.options as Option[], item.value as string, []) || '';
|
||||
}
|
||||
customFields.push({
|
||||
id: item.field as string,
|
||||
name: item.title as string,
|
||||
type: item.sourceType as string,
|
||||
value: Array.isArray(itemVal) ? JSON.stringify(itemVal) : (itemVal as string),
|
||||
});
|
||||
});
|
||||
}
|
||||
const customFields: BugEditCustomFieldItem[] = getDetailCustomFields();
|
||||
if (props.isPlatformDefaultTemplate) {
|
||||
// 平台系统默认字段插入自定义集合
|
||||
props.platformSystemFields.forEach((item) => {
|
||||
|
|
|
@ -4,9 +4,13 @@
|
|||
* @param {stafileInfotus} 文件file
|
||||
*/
|
||||
|
||||
import { FormRuleItem } from '@/components/pure/ms-form-create/types';
|
||||
import { getFileEnum } from '@/components/pure/ms-upload/iconMap';
|
||||
import { MsFileItem } from '@/components/pure/ms-upload/types';
|
||||
|
||||
import { findParents, Option } from '@/utils/recursion';
|
||||
|
||||
import { BugEditCustomFieldItem } from '@/models/bug-management';
|
||||
import { AssociatedList } from '@/models/caseManagement/featureCase';
|
||||
|
||||
export function convertToFileByBug(fileInfo: AssociatedList): MsFileItem {
|
||||
|
@ -68,3 +72,22 @@ export function convertToFileByDetail(fileInfo: AssociatedList): MsFileItem {
|
|||
associateId,
|
||||
};
|
||||
}
|
||||
|
||||
export function makeCustomFieldsParams(formItem: FormRuleItem[]) {
|
||||
const customFields: BugEditCustomFieldItem[] = [];
|
||||
if (formItem && formItem.length) {
|
||||
formItem.forEach((item: FormRuleItem) => {
|
||||
let itemVal = item.value;
|
||||
if (item.sourceType === 'CASCADER') {
|
||||
itemVal = findParents(item.options as Option[], item.value as string, []) || '';
|
||||
}
|
||||
customFields.push({
|
||||
id: item.field as string,
|
||||
name: item.title as string,
|
||||
type: item.sourceType as string,
|
||||
value: Array.isArray(itemVal) ? JSON.stringify(itemVal) : (itemVal as string),
|
||||
});
|
||||
});
|
||||
}
|
||||
return customFields;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<MsDetailDrawer
|
||||
ref="detailDrawerRef"
|
||||
v-model:visible="showDrawerVisible"
|
||||
:width="1200"
|
||||
:width="960"
|
||||
:footer="false"
|
||||
:mask="false"
|
||||
:title="t('caseManagement.featureCase.caseDetailTitle', { id: detailInfo?.num, name: detailInfo?.name })"
|
||||
|
@ -100,30 +100,17 @@
|
|||
class="no-content relative border-b"
|
||||
@change="clickMenu"
|
||||
/>
|
||||
<span class="absolute bottom-0 right-4 top-4 my-auto text-[var(--color-text-2)]" @click="showMenuSetting">{{
|
||||
<span class="display-setting h-full text-[var(--color-text-2)]" @click="showMenuSetting">{{
|
||||
t('caseManagement.featureCase.detailDisplaySetting')
|
||||
}}</span>
|
||||
</div>
|
||||
<MsSplitBox
|
||||
:size="0.8"
|
||||
:max="0.7"
|
||||
:min="0.6"
|
||||
direction="horizontal"
|
||||
expand-direction="right"
|
||||
class="!h-[calc(100%-48px)]"
|
||||
>
|
||||
<template #first>
|
||||
<div class="leftWrapper h-full">
|
||||
<div class="leftContent w-full pl-[16px] pr-[24px] pt-4">
|
||||
<div class="w-full p-[16px] pt-4">
|
||||
<template v-if="activeTab === 'detail'">
|
||||
<TabDetail
|
||||
ref="tabDetailRef"
|
||||
:form="detailInfo"
|
||||
:allow-edit="true"
|
||||
:form-rules="formItem"
|
||||
:form-api="fApi"
|
||||
@update-success="updateSuccess"
|
||||
/>
|
||||
<TabDetail :form="detailInfo" :allow-edit="true" :form-rules="formItem" @update-success="updateSuccess" />
|
||||
</template>
|
||||
<template v-if="activeTab === 'basicInfo'">
|
||||
<BasicInfo :loading="loading" :detail="detail" @update-success="updateSuccess" />
|
||||
</template>
|
||||
<template v-if="activeTab === 'requirement'">
|
||||
<TabDemand :case-id="detail.id" />
|
||||
|
@ -151,81 +138,6 @@
|
|||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #second>
|
||||
<div class="rightWrapper h-full p-4">
|
||||
<a-skeleton v-if="loading" class="w-full" :loading="loading" :animation="true">
|
||||
<a-space direction="vertical" class="w-[100%]" size="large">
|
||||
<a-skeleton-line :rows="14" :line-height="30" :line-spacing="30" />
|
||||
</a-space>
|
||||
</a-skeleton>
|
||||
<div v-else>
|
||||
<div class="mb-4 font-medium">{{ t('caseManagement.featureCase.basicInfo') }}</div>
|
||||
<div class="baseItem">
|
||||
<span class="label"> {{ t('caseManagement.featureCase.tableColumnModule') }}</span>
|
||||
<span class="w-[calc(100%-36%)]">
|
||||
<a-tree-select
|
||||
v-model="detailInfo.moduleId"
|
||||
:data="caseTree"
|
||||
class="w-full"
|
||||
:allow-search="true"
|
||||
:filter-tree-node="filterTreeNode"
|
||||
:field-names="{
|
||||
title: 'name',
|
||||
key: 'id',
|
||||
children: 'children',
|
||||
}"
|
||||
:tree-props="{
|
||||
virtualListProps: {
|
||||
height: 200,
|
||||
},
|
||||
}"
|
||||
@change="handleChangeModule"
|
||||
>
|
||||
<template #tree-slot-title="node">
|
||||
<a-tooltip :content="`${node.name}`" position="tl">
|
||||
<div class="one-line-text w-[300px] text-[var(--color-text-1)]">{{ node.name }}</div>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</a-tree-select>
|
||||
</span>
|
||||
</div>
|
||||
<!-- 自定义字段开始 -->
|
||||
<MsFormCreate
|
||||
v-if="formRules.length"
|
||||
ref="formCreateRef"
|
||||
v-model:api="fApi"
|
||||
v-model:form-item="formItem"
|
||||
:form-rule="formRules"
|
||||
class="w-full"
|
||||
:option="options"
|
||||
@change="changeHandler"
|
||||
/>
|
||||
<!-- 自定义字段结束 -->
|
||||
<div class="baseItem">
|
||||
<span class="label"> {{ t('caseManagement.featureCase.tableColumnCreateUser') }}</span>
|
||||
<a-tooltip
|
||||
v-if="translateTextToPX(detailInfo?.createUserName) > 200"
|
||||
:content="detailInfo?.createUserName"
|
||||
>
|
||||
<span class="one-line-text" style="max-width: 200px">{{ detailInfo?.createUserName }}</span>
|
||||
</a-tooltip>
|
||||
<span v-else class="value">{{ detailInfo?.createUserName }}</span>
|
||||
</div>
|
||||
<div class="baseItem">
|
||||
<span class="label"> {{ t('caseManagement.featureCase.tableColumnCreateTime') }}</span>
|
||||
<span class="value">{{ dayjs(detailInfo?.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
|
||||
</div>
|
||||
<div class="baseItem">
|
||||
<span class="label"> {{ t('caseManagement.featureCase.tableColumnTag') }}</span>
|
||||
<span class="value">
|
||||
<MsTag v-for="item of detailInfo.tags" :key="item"> {{ item }} </MsTag>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</MsSplitBox>
|
||||
<inputComment
|
||||
ref="commentInputRef"
|
||||
v-model:content="content"
|
||||
|
@ -250,21 +162,19 @@
|
|||
import { computed, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useClipboard } from '@vueuse/core';
|
||||
import { Message, TreeNodeData } from '@arco-design/web-vue';
|
||||
import dayjs from 'dayjs';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
|
||||
import type { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
|
||||
import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
|
||||
import MsTab from '@/components/pure/ms-tab/index.vue';
|
||||
import type { MsPaginationI } from '@/components/pure/ms-table/type';
|
||||
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
|
||||
import caseLevel from '@/components/business/ms-case-associate/caseLevel.vue';
|
||||
import type { CaseLevel } from '@/components/business/ms-case-associate/types';
|
||||
import inputComment from '@/components/business/ms-comment/input.vue';
|
||||
import { CommentParams } from '@/components/business/ms-comment/types';
|
||||
import MsDetailDrawer from '@/components/business/ms-detail-drawer/index.vue';
|
||||
import BasicInfo from './tabContent/basicInfo.vue';
|
||||
import SettingDrawer from './tabContent/settingDrawer.vue';
|
||||
|
||||
import {
|
||||
|
@ -276,21 +186,19 @@
|
|||
getCaseModuleTree,
|
||||
} from '@/api/modules/case-management/featureCase';
|
||||
import { PreviewEditorImageUrl } from '@/api/requrls/case-management/featureCase';
|
||||
import { defaultCaseDetail } from '@/config/caseManagement';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useModal from '@/hooks/useModal';
|
||||
import { useAppStore } from '@/store';
|
||||
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
||||
import useUserStore from '@/store/modules/user';
|
||||
import { characterLimit } from '@/utils';
|
||||
import { translateTextToPX } from '@/utils/css';
|
||||
|
||||
import type { CustomAttributes, DetailCase, TabItemType } from '@/models/caseManagement/featureCase';
|
||||
import { ModuleTreeNode } from '@/models/common';
|
||||
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
|
||||
|
||||
import { getCaseLevels, initFormCreate } from './utils';
|
||||
import { LabelValue } from '@arco-design/web-vue/es/tree-select/interface';
|
||||
import debounce from 'lodash-es/debounce';
|
||||
// 异步加载组件
|
||||
const TabDefect = defineAsyncComponent(() => import('./tabContent/tabBug/tabDefect.vue'));
|
||||
const TabCaseTable = defineAsyncComponent(() => import('./tabContent/tabCase/tabCaseTable.vue'));
|
||||
|
@ -351,26 +259,6 @@
|
|||
break;
|
||||
}
|
||||
}
|
||||
const initDetail: DetailCase = {
|
||||
id: '',
|
||||
projectId: '',
|
||||
templateId: '',
|
||||
name: '',
|
||||
prerequisite: '', // prerequisite
|
||||
caseEditType: '', // 编辑模式:步骤模式/文本模式
|
||||
steps: '',
|
||||
textDescription: '',
|
||||
expectedResult: '', // 预期结果
|
||||
description: '',
|
||||
publicCase: false, // 是否公共用例
|
||||
moduleId: '',
|
||||
versionId: '',
|
||||
tags: [],
|
||||
customFields: [], // 自定义字段集合
|
||||
relateFileMetaIds: [], // 关联文件ID集合
|
||||
functionalPriority: '',
|
||||
reviewStatus: 'UN_REVIEWED',
|
||||
};
|
||||
|
||||
const caseTree = ref<ModuleTreeNode[]>([]);
|
||||
|
||||
|
@ -382,7 +270,7 @@
|
|||
}
|
||||
}
|
||||
const route = useRoute();
|
||||
const detailInfo = ref<DetailCase>({ ...initDetail });
|
||||
const detailInfo = ref<DetailCase>(cloneDeep(defaultCaseDetail));
|
||||
const customFields = ref<CustomAttributes[]>([]);
|
||||
const caseLevels = ref<CaseLevel>('P0');
|
||||
|
||||
|
@ -451,8 +339,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
const followLoading = ref<boolean>(false);
|
||||
// 关注
|
||||
const followLoading = ref<boolean>(false);
|
||||
async function followHandler() {
|
||||
followLoading.value = true;
|
||||
try {
|
||||
|
@ -506,50 +394,12 @@
|
|||
const formRules = ref<FormItem[]>([]);
|
||||
const formItem = ref<FormRuleItem[]>([]);
|
||||
|
||||
// 表单配置项
|
||||
const options = {
|
||||
resetBtn: false, // 不展示默认配置的重置和提交
|
||||
submitBtn: false,
|
||||
on: false, // 取消绑定on事件
|
||||
form: {
|
||||
layout: 'horizontal',
|
||||
labelAlign: 'left',
|
||||
labelColProps: {
|
||||
span: 9,
|
||||
},
|
||||
wrapperColProps: {
|
||||
span: 15,
|
||||
},
|
||||
contentClass: 'contentClass',
|
||||
autoLabelWidth: true,
|
||||
},
|
||||
// 暂时默认
|
||||
row: {
|
||||
gutter: 0,
|
||||
},
|
||||
wrap: {
|
||||
'asterisk-position': 'end',
|
||||
'validate-trigger': ['change'],
|
||||
'hide-asterisk': true,
|
||||
},
|
||||
};
|
||||
|
||||
const fApi = ref(null);
|
||||
// 初始化表单
|
||||
function initForm() {
|
||||
formRules.value = initFormCreate(customFields.value, ['FUNCTIONAL_CASE:READ+UPDATE']);
|
||||
}
|
||||
|
||||
const tabDetailRef = ref();
|
||||
function handleChangeModule(value: string | number | LabelValue | Array<string | number> | LabelValue[] | undefined) {
|
||||
detailInfo.value.moduleId = value as string;
|
||||
tabDetailRef.value.handleOK();
|
||||
}
|
||||
|
||||
function filterTreeNode(searchValue: string, nodeValue: TreeNodeData) {
|
||||
return (nodeValue as ModuleTreeNode).name.toLowerCase().indexOf(searchValue.toLowerCase()) > -1;
|
||||
}
|
||||
|
||||
function getTotal(key: string) {
|
||||
switch (key) {
|
||||
case 'detail':
|
||||
|
@ -568,7 +418,9 @@
|
|||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
const settingDrawerRef = ref();
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(val) => {
|
||||
|
@ -621,17 +473,20 @@
|
|||
isActive.value = !isActive.value;
|
||||
}
|
||||
|
||||
const changeHandler = debounce(() => {
|
||||
tabDetailRef.value.handleOK();
|
||||
}, 300);
|
||||
|
||||
const tabDefaultSettingList: TabItemType[] = [
|
||||
{
|
||||
value: 'basicInfo',
|
||||
label: t('caseManagement.featureCase.basicInfo'),
|
||||
canHide: false,
|
||||
isShow: true,
|
||||
},
|
||||
{
|
||||
value: 'detail',
|
||||
label: t('caseManagement.featureCase.detail'),
|
||||
canHide: false,
|
||||
isShow: true,
|
||||
},
|
||||
|
||||
{
|
||||
value: 'case',
|
||||
label: t('caseManagement.featureCase.case'),
|
||||
|
@ -724,6 +579,13 @@
|
|||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.display-setting {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 16px;
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
}
|
||||
:deep(.arco-menu-light) {
|
||||
height: 50px;
|
||||
background: none !important;
|
||||
|
@ -739,116 +601,6 @@
|
|||
border-bottom: 1px solid var(--color-text-n8);
|
||||
}
|
||||
}
|
||||
.rightWrapper {
|
||||
.baseItem {
|
||||
margin-bottom: 16px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
@apply flex;
|
||||
.label {
|
||||
flex-shrink: 0;
|
||||
width: 84px;
|
||||
color: var(--color-text-3);
|
||||
}
|
||||
.value {
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
:deep(.arco-form-item-layout-horizontal) {
|
||||
margin-bottom: 16px !important;
|
||||
}
|
||||
:deep(.arco-form-item-label-col) {
|
||||
padding-right: 0;
|
||||
}
|
||||
:deep(.arco-col-9) {
|
||||
flex: 0 0 84px;
|
||||
width: 84px;
|
||||
}
|
||||
:deep(.arco-col-15) {
|
||||
flex: 0 0 calc(100% - 84px);
|
||||
width: calc(100% - 84px);
|
||||
}
|
||||
:deep(.arco-form-item-label::after) {
|
||||
color: red !important;
|
||||
}
|
||||
:deep(.arco-form-item-label-col > .arco-form-item-label) {
|
||||
overflow: hidden;
|
||||
width: 84px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
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,
|
||||
:hover > .arco-icon {
|
||||
|
|
|
@ -0,0 +1,318 @@
|
|||
<template>
|
||||
<a-spin class="w-full" :loading="loading">
|
||||
<div class="h-full w-full">
|
||||
<div class="basic-container">
|
||||
<div class="baseItem">
|
||||
<span class="label"> {{ t('caseManagement.featureCase.tableColumnModule') }}</span>
|
||||
<span class="w-full">
|
||||
<a-tree-select
|
||||
v-model="detailInfo.moduleId"
|
||||
:data="caseTree"
|
||||
class="w-full"
|
||||
:allow-search="true"
|
||||
:filter-tree-node="filterTreeNode"
|
||||
:field-names="{
|
||||
title: 'name',
|
||||
key: 'id',
|
||||
children: 'children',
|
||||
}"
|
||||
:tree-props="{
|
||||
virtualListProps: {
|
||||
height: 200,
|
||||
},
|
||||
}"
|
||||
@change="handleChangeModule"
|
||||
>
|
||||
<template #tree-slot-title="node">
|
||||
<a-tooltip :content="`${node.name}`" position="tl">
|
||||
<div class="one-line-text w-[300px] text-[var(--color-text-1)]">{{ node.name }}</div>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</a-tree-select>
|
||||
</span>
|
||||
</div>
|
||||
<MsFormCreate
|
||||
v-if="formRules.length"
|
||||
ref="formCreateRef"
|
||||
v-model:api="fApi"
|
||||
v-model:form-item="formItem"
|
||||
:form-rule="formRules"
|
||||
class="w-full"
|
||||
:option="options"
|
||||
@change="changeHandler"
|
||||
/>
|
||||
<div class="baseItem">
|
||||
<span class="label"> {{ t('caseManagement.featureCase.tableColumnCreateUser') }}</span>
|
||||
<a-tooltip v-if="translateTextToPX(detailInfo?.createUserName) > 200" :content="detailInfo?.createUserName">
|
||||
<span class="one-line-text" style="max-width: 200px">{{ detailInfo?.createUserName }}</span>
|
||||
</a-tooltip>
|
||||
<span v-else class="value">{{ detailInfo?.createUserName }}</span>
|
||||
</div>
|
||||
<div class="baseItem">
|
||||
<span class="label"> {{ t('caseManagement.featureCase.tableColumnCreateTime') }}</span>
|
||||
<span class="value">{{ dayjs(detailInfo?.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
|
||||
</div>
|
||||
<div class="baseItem">
|
||||
<span class="label"> {{ t('caseManagement.featureCase.tableColumnTag') }}</span>
|
||||
<span class="value">
|
||||
<MsTag v-for="item of detailInfo.tags" :key="item"> {{ item }} </MsTag>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-spin>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { Message, TreeNodeData } from '@arco-design/web-vue';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
|
||||
import type { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
|
||||
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
|
||||
|
||||
import { getCaseModuleTree, updateCaseRequest } from '@/api/modules/case-management/featureCase';
|
||||
import { defaultCaseDetail } from '@/config/caseManagement';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { useAppStore } from '@/store';
|
||||
import { translateTextToPX } from '@/utils/css';
|
||||
|
||||
import type { CustomAttributes, DetailCase } from '@/models/caseManagement/featureCase';
|
||||
import { ModuleTreeNode } from '@/models/common';
|
||||
|
||||
import { initFormCreate } from '../utils';
|
||||
import { LabelValue } from '@arco-design/web-vue/es/tree-select/interface';
|
||||
import debounce from 'lodash-es/debounce';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps<{
|
||||
detail: DetailCase;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'updateSuccess'): void;
|
||||
}>();
|
||||
|
||||
const appStore = useAppStore();
|
||||
|
||||
const detailInfo = ref<DetailCase>(cloneDeep(defaultCaseDetail));
|
||||
|
||||
const options = {
|
||||
resetBtn: false, // 不展示默认配置的重置和提交
|
||||
submitBtn: false,
|
||||
on: false, // 取消绑定on事件
|
||||
form: {
|
||||
layout: 'horizontal',
|
||||
labelAlign: 'left',
|
||||
labelColProps: {
|
||||
span: 9,
|
||||
},
|
||||
wrapperColProps: {
|
||||
span: 15,
|
||||
},
|
||||
},
|
||||
row: {
|
||||
gutter: 0,
|
||||
},
|
||||
wrap: {
|
||||
'asterisk-position': 'end',
|
||||
'validate-trigger': ['change'],
|
||||
},
|
||||
};
|
||||
|
||||
const formRules = ref<FormItem[]>([]);
|
||||
const formItem = ref<FormRuleItem[]>([]);
|
||||
function getParams() {
|
||||
const customFieldsArr = (formItem.value || []).map((item: any) => {
|
||||
return {
|
||||
fieldId: item.field,
|
||||
value: Array.isArray(item.value) ? JSON.stringify(item.value) : item.value,
|
||||
};
|
||||
});
|
||||
return {
|
||||
request: {
|
||||
...detailInfo.value,
|
||||
deleteFileMetaIds: [], // 删除本地文件id
|
||||
unLinkFilesIds: [], // 取消关联文件id
|
||||
newAssociateFileListIds: [], // 新关联文件id
|
||||
customFields: customFieldsArr,
|
||||
caseDetailFileIds: [],
|
||||
},
|
||||
fileList: [], // 总文件列表
|
||||
};
|
||||
}
|
||||
const fApi = ref<any>(null);
|
||||
const loading = ref<boolean>(false);
|
||||
|
||||
function updateHandler() {
|
||||
try {
|
||||
fApi.value?.validate().then(async (valid: any) => {
|
||||
if (valid === true) {
|
||||
loading.value = true;
|
||||
await updateCaseRequest(getParams());
|
||||
loading.value = false;
|
||||
Message.success(t('caseManagement.featureCase.editSuccess'));
|
||||
emit('updateSuccess');
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleChangeModule(value: string | number | LabelValue | Array<string | number> | LabelValue[] | undefined) {
|
||||
detailInfo.value.moduleId = value as string;
|
||||
updateHandler();
|
||||
}
|
||||
|
||||
function filterTreeNode(searchValue: string, nodeValue: TreeNodeData) {
|
||||
return (nodeValue as ModuleTreeNode).name.toLowerCase().indexOf(searchValue.toLowerCase()) > -1;
|
||||
}
|
||||
|
||||
const changeHandler = debounce(() => {
|
||||
updateHandler();
|
||||
}, 300);
|
||||
|
||||
const caseTree = ref<ModuleTreeNode[]>([]);
|
||||
|
||||
async function getCaseTree() {
|
||||
try {
|
||||
caseTree.value = await getCaseModuleTree({ projectId: appStore.currentProjectId });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
// 初始化表单
|
||||
function initForm() {
|
||||
const { customFields } = detailInfo.value;
|
||||
formRules.value = initFormCreate(customFields as CustomAttributes[], ['FUNCTIONAL_CASE:READ+UPDATE']);
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
detailInfo.value = props.detail;
|
||||
initForm();
|
||||
});
|
||||
|
||||
onBeforeMount(() => {
|
||||
getCaseTree();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.basic-container {
|
||||
max-width: 50%;
|
||||
.baseItem {
|
||||
margin-bottom: 16px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
@apply flex;
|
||||
.label {
|
||||
flex-shrink: 0;
|
||||
width: 84px;
|
||||
color: var(--color-text-3);
|
||||
}
|
||||
.value {
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
:deep(.arco-form-item-layout-horizontal) {
|
||||
margin-bottom: 16px !important;
|
||||
}
|
||||
:deep(.arco-form-item-label-col) {
|
||||
padding-right: 0;
|
||||
}
|
||||
:deep(.arco-col-9) {
|
||||
flex: 0 0 84px;
|
||||
width: 84px;
|
||||
}
|
||||
:deep(.arco-col-15) {
|
||||
flex: 0 0 calc(100% - 84px);
|
||||
width: calc(100% - 84px);
|
||||
}
|
||||
:deep(.arco-form-item-label::after) {
|
||||
color: red !important;
|
||||
}
|
||||
:deep(.arco-form-item-label-col > .arco-form-item-label) {
|
||||
overflow: hidden;
|
||||
width: 84px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -4,15 +4,7 @@
|
|||
<span type="text" class="one-line-text cursor-pointer px-0 text-[rgb(var(--primary-5))]">{{ record.num }}</span>
|
||||
</template>
|
||||
<template #name="{ record }">
|
||||
<a-tooltip :content="record.name">
|
||||
<div class="one-line-text max-w-[calc(100%-32px)]"> {{ record.name }}</div>
|
||||
</a-tooltip>
|
||||
<a-popover class="bug-content-popover" title="" position="right" style="width: 480px">
|
||||
<span class="ml-1 text-[rgb(var(--primary-5))]">{{ t('caseManagement.featureCase.preview') }}</span>
|
||||
<template #content>
|
||||
<div v-dompurify-html="record.content" class="markdown-body bug-content"> </div>
|
||||
</template>
|
||||
</a-popover>
|
||||
<BugNamePopover :name="record.name" :content="record.content" />
|
||||
</template>
|
||||
<template #statusName="{ record }">
|
||||
<div class="one-line-text">{{ record.statusName || '-' }}</div>
|
||||
|
@ -59,6 +51,7 @@
|
|||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
import type { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
import BugNamePopover from '@/views/case-management/caseManagementFeature/components/tabContent/tabBug/bugNamePopover.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { useAppStore } from '@/store';
|
||||
|
@ -157,7 +150,7 @@
|
|||
});
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
<!-- <style lang="less">
|
||||
.bug-content-popover {
|
||||
.arco-popover-content {
|
||||
overflow: auto;
|
||||
|
@ -165,4 +158,4 @@
|
|||
.ms-scroll-bar();
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style> -->
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<template>
|
||||
<div class="one-line-text max-w-[calc(100%-32px)]"> {{ props.name }}</div>
|
||||
<a-popover class="bug-content-popover" title="" position="right" style="width: 480px" tri>
|
||||
<span class="ml-1 text-[rgb(var(--primary-5))]">{{ t('caseManagement.featureCase.preview') }}</span>
|
||||
<template #content>
|
||||
<div v-dompurify-html="props.content" class="markdown-body bug-content"> </div>
|
||||
</template>
|
||||
</a-popover>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps<{
|
||||
name: string;
|
||||
content: string;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.bug-content-popover {
|
||||
.arco-popover-content {
|
||||
overflow: auto;
|
||||
max-height: 400px;
|
||||
.ms-scroll-bar();
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -38,17 +38,7 @@
|
|||
v-on="propsEvent"
|
||||
>
|
||||
<template #name="{ record }">
|
||||
<div class="flex flex-nowrap items-center">
|
||||
<div class="one-line-text max-w-[200px] flex-auto items-center"> {{ characterLimit(record.name) }}</div>
|
||||
<a-popover class="bug-content-popover" title="" position="right" style="width: 480px">
|
||||
<div class="ml-1 flex-auto text-[rgb(var(--primary-5))]">{{
|
||||
t('caseManagement.featureCase.preview')
|
||||
}}</div>
|
||||
<template #content>
|
||||
<div v-dompurify-html="record.content" class="markdown-body"> </div>
|
||||
</template>
|
||||
</a-popover>
|
||||
</div>
|
||||
<BugNamePopover :name="record.name" :content="record.content" />
|
||||
</template>
|
||||
</ms-base-table>
|
||||
</div>
|
||||
|
@ -62,11 +52,11 @@
|
|||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
import type { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
import BugNamePopover from '@/views/case-management/caseManagementFeature/components/tabContent/tabBug/bugNamePopover.vue';
|
||||
|
||||
import { getDrawerDebugPage } from '@/api/modules/case-management/featureCase';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { useAppStore } from '@/store';
|
||||
import { characterLimit } from '@/utils';
|
||||
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
|
||||
|
@ -104,10 +94,7 @@
|
|||
title: 'caseManagement.featureCase.defectName',
|
||||
slotName: 'name',
|
||||
dataIndex: 'name',
|
||||
showInTable: true,
|
||||
showTooltip: true,
|
||||
width: 300,
|
||||
ellipsis: true,
|
||||
showDrag: false,
|
||||
},
|
||||
|
||||
|
|
|
@ -67,21 +67,14 @@
|
|||
:load-params="{
|
||||
caseId: props.caseId,
|
||||
}"
|
||||
:can-edit="true"
|
||||
@link="linkDefect"
|
||||
@new="createDefect"
|
||||
@cancel-link="cancelLink"
|
||||
/>
|
||||
<ms-base-table v-else v-bind="testPlanPropsRes" ref="planTableRef" v-on="testPlanTableEvent">
|
||||
<template #name="{ record }">
|
||||
<div class="flex flex-nowrap items-center">
|
||||
<div class="one-line-text">{{ characterLimit(record.name) }}</div>
|
||||
<a-popover title="" position="right" style="width: 480px">
|
||||
<div class="ml-1 text-[rgb(var(--primary-5))]">{{ t('caseManagement.featureCase.preview') }}</div>
|
||||
<template #content>
|
||||
<div v-dompurify-html="record.content" class="markdown-body" style="margin-left: 48px"> </div>
|
||||
</template>
|
||||
</a-popover>
|
||||
</div>
|
||||
<BugNamePopover :name="record.name" :content="record.content" />
|
||||
</template>
|
||||
<template #handleUserName="{ record }">
|
||||
<a-tooltip :content="record.handleUserName">
|
||||
|
@ -145,6 +138,7 @@
|
|||
import AddDefectDrawer from './addDefectDrawer.vue';
|
||||
import BugList from './bugList.vue';
|
||||
import LinkDefectDrawer from './linkDefectDrawer.vue';
|
||||
import BugNamePopover from '@/views/case-management/caseManagementFeature/components/tabContent/tabBug/bugNamePopover.vue';
|
||||
import TableFilter from '@/views/case-management/caseManagementFeature/components/tableFilter.vue';
|
||||
|
||||
import { getBugList, getCustomOptionHeader } from '@/api/modules/bug-management';
|
||||
|
@ -194,20 +188,14 @@
|
|||
title: 'caseManagement.featureCase.tableColumnID',
|
||||
dataIndex: 'num',
|
||||
width: 100,
|
||||
showInTable: true,
|
||||
showTooltip: true,
|
||||
showDrag: false,
|
||||
fixed: 'left',
|
||||
},
|
||||
{
|
||||
title: 'caseManagement.featureCase.defectName',
|
||||
slotName: 'name',
|
||||
dataIndex: 'name',
|
||||
showInTable: true,
|
||||
showTooltip: false,
|
||||
width: 300,
|
||||
ellipsis: true,
|
||||
showDrag: false,
|
||||
},
|
||||
{
|
||||
title: 'caseManagement.featureCase.defectState',
|
||||
|
@ -217,19 +205,13 @@
|
|||
options: [],
|
||||
labelKey: 'text',
|
||||
},
|
||||
showInTable: true,
|
||||
width: 150,
|
||||
ellipsis: true,
|
||||
showDrag: false,
|
||||
},
|
||||
{
|
||||
title: 'common.creator',
|
||||
slotName: 'createUserName',
|
||||
dataIndex: 'createUserName',
|
||||
showInTable: true,
|
||||
showTooltip: true,
|
||||
width: 200,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: 'caseManagement.featureCase.updateUser',
|
||||
|
@ -239,19 +221,14 @@
|
|||
options: [],
|
||||
labelKey: 'text',
|
||||
},
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: 'caseManagement.featureCase.defectSource',
|
||||
slotName: 'source',
|
||||
dataIndex: 'source',
|
||||
showInTable: true,
|
||||
showTooltip: true,
|
||||
width: 100,
|
||||
ellipsis: true,
|
||||
showDrag: false,
|
||||
},
|
||||
{
|
||||
title: 'caseManagement.featureCase.tableColumnActions',
|
||||
|
@ -259,8 +236,6 @@
|
|||
dataIndex: 'operation',
|
||||
fixed: 'right',
|
||||
width: 100,
|
||||
showInTable: true,
|
||||
showDrag: false,
|
||||
},
|
||||
]);
|
||||
|
||||
|
@ -278,31 +253,21 @@
|
|||
title: 'caseManagement.featureCase.defectName',
|
||||
slotName: 'name',
|
||||
dataIndex: 'name',
|
||||
showInTable: true,
|
||||
showTooltip: true,
|
||||
width: 250,
|
||||
ellipsis: true,
|
||||
showDrag: false,
|
||||
},
|
||||
{
|
||||
title: 'caseManagement.featureCase.planName',
|
||||
slotName: 'testPlanName',
|
||||
dataIndex: 'testPlanName',
|
||||
showInTable: true,
|
||||
showTooltip: true,
|
||||
width: 200,
|
||||
ellipsis: true,
|
||||
showDrag: false,
|
||||
},
|
||||
{
|
||||
title: 'caseManagement.featureCase.defectState',
|
||||
slotName: 'defectState',
|
||||
dataIndex: 'defectState',
|
||||
showInTable: true,
|
||||
showTooltip: true,
|
||||
width: 150,
|
||||
ellipsis: true,
|
||||
showDrag: false,
|
||||
},
|
||||
{
|
||||
title: 'caseManagement.featureCase.updateUser',
|
||||
|
@ -312,10 +277,8 @@
|
|||
options: [],
|
||||
labelKey: 'text',
|
||||
},
|
||||
showInTable: true,
|
||||
showTooltip: true,
|
||||
width: 200,
|
||||
ellipsis: true,
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
v-if="caseEnable"
|
||||
v-permission="['FUNCTIONAL_CASE:READ+ADD', 'FUNCTIONAL_CASE:READ+UPDATE', 'FUNCTIONAL_CASE:READ+DELETE']"
|
||||
type="primary"
|
||||
class="mr-2"
|
||||
@click="associatedDemand"
|
||||
>
|
||||
{{ t('caseManagement.featureCase.associatedDemand') }}</a-button
|
||||
>
|
||||
<a-button
|
||||
v-permission="['FUNCTIONAL_CASE:READ+ADD', 'FUNCTIONAL_CASE:READ+UPDATE', 'FUNCTIONAL_CASE:READ+DELETE']"
|
||||
class="mx-3"
|
||||
type="outline"
|
||||
@click="addDemand"
|
||||
>
|
||||
|
|
|
@ -303,7 +303,6 @@
|
|||
form: DetailCase;
|
||||
allowEdit?: boolean; // 是否允许编辑
|
||||
formRules?: FormRuleItem[]; // 编辑表单
|
||||
formApi?: any;
|
||||
isTestPlan?: boolean; // 测试计划页面的
|
||||
isDisabledTestPlan?: boolean; // 测试计划页面-已归档
|
||||
}>(),
|
||||
|
@ -485,16 +484,12 @@
|
|||
caseFormRef.value?.validate().then(async (res: any) => {
|
||||
if (!res) {
|
||||
try {
|
||||
props.formApi?.validate().then(async (valid: any) => {
|
||||
if (valid === true) {
|
||||
confirmLoading.value = true;
|
||||
await updateCaseRequest(getParams());
|
||||
confirmLoading.value = false;
|
||||
Message.success(t('caseManagement.featureCase.editSuccess'));
|
||||
isEditPreposition.value = false;
|
||||
emit('updateSuccess');
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
|
|
|
@ -20,8 +20,7 @@
|
|||
<MsStatusTag :status="record.planStatus" />
|
||||
</template>
|
||||
<template #lastExecResult="{ record }">
|
||||
<ExecuteResult v-if="record.lastExecResult" :execute-result="record.lastExecResult" />
|
||||
<span v-else>-</span>
|
||||
<ExecuteResult :execute-result="record.lastExecResult || 'PENDING'" />
|
||||
</template>
|
||||
<template #[FilterSlotNameEnum.CASE_MANAGEMENT_EXECUTE_RESULT]="{ filterContent }">
|
||||
<ExecuteResult :execute-result="filterContent.value" />
|
||||
|
|
|
@ -115,6 +115,13 @@
|
|||
}
|
||||
);
|
||||
|
||||
function reset(val: boolean) {
|
||||
if (!val) {
|
||||
form.value.field = '';
|
||||
formRef.value?.resetFields();
|
||||
}
|
||||
}
|
||||
|
||||
function beforeConfirm(done?: (closed: boolean) => void) {
|
||||
if (loading.value) return;
|
||||
formRef.value?.validate(async (errors) => {
|
||||
|
@ -129,6 +136,7 @@
|
|||
name: form.value.field,
|
||||
});
|
||||
Message.success(t('project.fileManagement.addSubModuleSuccess'));
|
||||
reset(false);
|
||||
emit('addFinish', form.value.field);
|
||||
} else if (props.mode === 'rename') {
|
||||
// 模块重命名
|
||||
|
@ -137,6 +145,7 @@
|
|||
name: form.value.field,
|
||||
});
|
||||
Message.success(t('project.fileManagement.renameSuccess'));
|
||||
reset(false);
|
||||
emit('renameFinish', form.value.field);
|
||||
}
|
||||
if (done) {
|
||||
|
@ -164,13 +173,6 @@
|
|||
callback(t('project.fileManagement.nameExist'));
|
||||
}
|
||||
}
|
||||
|
||||
function reset(val: boolean) {
|
||||
if (!val) {
|
||||
form.value.field = '';
|
||||
formRef.value?.resetFields();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
|
|
|
@ -20,15 +20,7 @@
|
|||
<MsButton type="text" @click="handleShowDetail(record.id)">{{ record.num }}</MsButton>
|
||||
</template>
|
||||
<template #name="{ record }">
|
||||
<a-tooltip :content="record.title">
|
||||
<div class="one-line-text max-w-[calc(100%-32px)]"> {{ record.title }}</div>
|
||||
</a-tooltip>
|
||||
<a-popover class="bug-content-popover" title="" position="right" style="width: 480px">
|
||||
<span class="ml-1 text-[rgb(var(--primary-5))]">{{ t('caseManagement.featureCase.preview') }}</span>
|
||||
<template #content>
|
||||
<div v-dompurify-html="record.content" class="markdown-body bug-content"> </div>
|
||||
</template>
|
||||
</a-popover>
|
||||
<BugNamePopover :name="record.title" :content="record.content" />
|
||||
</template>
|
||||
<template #linkCase="{ record }">
|
||||
<CaseCountPopover :bug-item="record" />
|
||||
|
@ -54,6 +46,7 @@
|
|||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
import CaseCountPopover from './caseCountPopover.vue';
|
||||
import BugDetailDrawer from '@/views/bug-management/components/bug-detail-drawer.vue';
|
||||
import BugNamePopover from '@/views/case-management/caseManagementFeature/components/tabContent/tabBug/bugNamePopover.vue';
|
||||
|
||||
import { getCustomOptionHeader, getPlatform } from '@/api/modules/bug-management';
|
||||
import { planDetailBugPage } from '@/api/modules/test-plan/testPlan';
|
||||
|
|
Loading…
Reference in New Issue