refactor(功能用例&缺陷管理): 功能用例基本信息和缺陷管理基本信息调整
This commit is contained in:
parent
bfe7789e78
commit
28b2e9197f
|
@ -265,6 +265,7 @@
|
||||||
excludeIds: [...excludeKeys].concat(...(props.associatedIds || [])),
|
excludeIds: [...excludeKeys].concat(...(props.associatedIds || [])),
|
||||||
selectIds: selectorStatus === 'all' ? [] : [...selectedKeys],
|
selectIds: selectorStatus === 'all' ? [] : [...selectedKeys],
|
||||||
selectAll: selectorStatus === 'all',
|
selectAll: selectorStatus === 'all',
|
||||||
|
associateApiType: 'API_CASE',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -240,6 +240,7 @@
|
||||||
excludeIds: [...excludeKeys].concat(...(props.associatedIds || [])),
|
excludeIds: [...excludeKeys].concat(...(props.associatedIds || [])),
|
||||||
selectIds: selectorStatus === 'all' ? [] : [...selectedKeys],
|
selectIds: selectorStatus === 'all' ? [] : [...selectedKeys],
|
||||||
selectAll: selectorStatus === 'all',
|
selectAll: selectorStatus === 'all',
|
||||||
|
associateApiType: 'API',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<TreeFolderAll
|
<TreeFolderAll
|
||||||
v-if="props.activeTab === CaseLinkEnum.API"
|
|
||||||
v-model:selectedProtocols="selectedProtocols"
|
v-model:selectedProtocols="selectedProtocols"
|
||||||
:active-folder="activeFolder"
|
:active-folder="activeFolder"
|
||||||
:folder-name="props.folderName"
|
:folder-name="props.folderName"
|
||||||
:all-count="allCount"
|
:all-count="allCount"
|
||||||
:show-expand-api="false"
|
:show-expand-api="false"
|
||||||
|
:not-show-operation="props.activeTab !== 'API'"
|
||||||
@set-active-folder="setActiveFolder"
|
@set-active-folder="setActiveFolder"
|
||||||
@selected-protocols-change="selectedProtocolsChange"
|
@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" />
|
<a-divider class="my-[8px] mt-0" />
|
||||||
<div class="mb-[8px] flex items-center gap-[8px]">
|
<div class="mb-[8px] flex items-center gap-[8px]">
|
||||||
<a-input
|
<a-input
|
||||||
|
|
|
@ -368,7 +368,6 @@
|
||||||
activeFolderName.value = name ?? '';
|
activeFolderName.value = name ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
const isAddAssociatedCase = ref<boolean>(false);
|
|
||||||
const functionalTableRef = ref<InstanceType<typeof CaseTable>>();
|
const functionalTableRef = ref<InstanceType<typeof CaseTable>>();
|
||||||
const apiTableRef = ref<InstanceType<typeof ApiTable>>();
|
const apiTableRef = ref<InstanceType<typeof ApiTable>>();
|
||||||
const caseTableRef = ref<InstanceType<typeof ApiCaseTable>>();
|
const caseTableRef = ref<InstanceType<typeof ApiCaseTable>>();
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { ReviewItem, ReviewResult, ReviewStatus } from '@/models/caseManagement/caseReview';
|
import { ReviewItem, ReviewResult, ReviewStatus } from '@/models/caseManagement/caseReview';
|
||||||
|
import type { DetailCase } from '@/models/caseManagement/featureCase';
|
||||||
|
|
||||||
// 评审结果
|
// 评审结果
|
||||||
export type ReviewResultMap = Record<
|
export type ReviewResultMap = Record<
|
||||||
|
@ -106,3 +107,24 @@ export const minderTagMap = {
|
||||||
EXPECTED_RESULT: 'minder.tag.expect',
|
EXPECTED_RESULT: 'minder.tag.expect',
|
||||||
DESCRIPTION: 'minder.tag.remark',
|
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
|
<MsDetailDrawer
|
||||||
ref="detailDrawerRef"
|
ref="detailDrawerRef"
|
||||||
v-model:visible="showDrawerVisible"
|
v-model:visible="showDrawerVisible"
|
||||||
:width="1200"
|
:width="900"
|
||||||
:footer="false"
|
:footer="false"
|
||||||
:title="t('bugManagement.detail.title', { id: detailInfo?.num, name: detailInfo?.title })"
|
:title="t('bugManagement.detail.title', { id: detailInfo?.num, name: detailInfo?.title })"
|
||||||
:tooltip-text="(detailInfo && detailInfo.title) || null"
|
:tooltip-text="(detailInfo && detailInfo.title) || null"
|
||||||
|
@ -91,7 +91,7 @@
|
||||||
</MsButton>
|
</MsButton>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #default="{ loading }">
|
<template #default="{ detail }">
|
||||||
<div
|
<div
|
||||||
ref="wrapperRef"
|
ref="wrapperRef"
|
||||||
:class="[
|
:class="[
|
||||||
|
@ -113,23 +113,12 @@
|
||||||
class="no-content relative border-b"
|
class="no-content relative border-b"
|
||||||
/>
|
/>
|
||||||
</div>
|
</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">
|
<div class="leftWrapper h-full">
|
||||||
<a-spin :loading="detailLoading" class="w-full">
|
<a-spin :loading="detailLoading" class="w-full">
|
||||||
<div class="tab-pane-container p-4">
|
<div class="tab-pane-container">
|
||||||
<BugDetailTab
|
<BugDetailTab
|
||||||
v-if="activeTab === 'detail'"
|
v-if="activeTab === 'detail'"
|
||||||
ref="bugDetailTabRef"
|
ref="bugDetailTabRef"
|
||||||
:form-item="formItem"
|
|
||||||
:allow-edit="hasAnyPermission(['PROJECT_BUG:READ+UPDATE'])"
|
:allow-edit="hasAnyPermission(['PROJECT_BUG:READ+UPDATE'])"
|
||||||
:detail-info="detailInfo"
|
:detail-info="detailInfo"
|
||||||
:is-platform-default-template="isPlatformDefaultTemplate"
|
:is-platform-default-template="isPlatformDefaultTemplate"
|
||||||
|
@ -137,6 +126,17 @@
|
||||||
:current-platform="props.currentPlatform"
|
:current-platform="props.currentPlatform"
|
||||||
@update-success="detailDrawerRef?.initDetail()"
|
@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
|
<BugCaseTab
|
||||||
v-else-if="activeTab === 'case'"
|
v-else-if="activeTab === 'case'"
|
||||||
|
@ -150,69 +150,6 @@
|
||||||
</div>
|
</div>
|
||||||
</a-spin>
|
</a-spin>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
<CommentInput
|
<CommentInput
|
||||||
v-if="activeTab === 'comment' && hasAnyPermission(['PROJECT_BUG:READ+COMMENT'])"
|
v-if="activeTab === 'comment' && hasAnyPermission(['PROJECT_BUG:READ+COMMENT'])"
|
||||||
|
@ -235,20 +172,17 @@
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { useClipboard } from '@vueuse/core';
|
import { useClipboard } from '@vueuse/core';
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
import { debounce } from 'lodash-es';
|
|
||||||
|
|
||||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||||
import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
|
import type { FormItem } from '@/components/pure/ms-form-create/types';
|
||||||
import type { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
|
|
||||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
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 MsTab from '@/components/pure/ms-tab/index.vue';
|
||||||
import type { MsPaginationI } from '@/components/pure/ms-table/type';
|
import type { MsPaginationI } from '@/components/pure/ms-table/type';
|
||||||
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
|
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 CommentInput from '@/components/business/ms-comment/input.vue';
|
||||||
import { CommentParams } from '@/components/business/ms-comment/types';
|
import { CommentParams } from '@/components/business/ms-comment/types';
|
||||||
import MsDetailDrawer from '@/components/business/ms-detail-drawer/index.vue';
|
import MsDetailDrawer from '@/components/business/ms-detail-drawer/index.vue';
|
||||||
|
import BasicInfo from './basicInfo.vue';
|
||||||
import BugCaseTab from './bugCaseTab.vue';
|
import BugCaseTab from './bugCaseTab.vue';
|
||||||
import BugDetailTab from './bugDetailTab.vue';
|
import BugDetailTab from './bugDetailTab.vue';
|
||||||
import BugHistoryTab from './bugHistoryTab.vue';
|
import BugHistoryTab from './bugHistoryTab.vue';
|
||||||
|
@ -302,9 +236,8 @@
|
||||||
const commentContent = ref('');
|
const commentContent = ref('');
|
||||||
const commentRef = ref();
|
const commentRef = ref();
|
||||||
const noticeUserIds = ref<string[]>([]); // 通知人ids
|
const noticeUserIds = ref<string[]>([]); // 通知人ids
|
||||||
const fApi = ref();
|
|
||||||
const formRules = ref<FormItem[]>([]); // 表单规则
|
const formRules = ref<FormItem[]>([]); // 表单规则
|
||||||
const formItem = ref<FormRuleItem[]>([]); // 表单项
|
|
||||||
const currentProjectId = computed(() => appStore.currentProjectId);
|
const currentProjectId = computed(() => appStore.currentProjectId);
|
||||||
const showDrawerVisible = defineModel<boolean>('visible', { default: false });
|
const showDrawerVisible = defineModel<boolean>('visible', { default: false });
|
||||||
const bugDetailTabRef = ref();
|
const bugDetailTabRef = ref();
|
||||||
|
@ -463,6 +396,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const tabList = [
|
const tabList = [
|
||||||
|
{
|
||||||
|
value: 'basicInfo',
|
||||||
|
label: t('bugManagement.detail.basicInfo'),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
value: 'detail',
|
value: 'detail',
|
||||||
label: t('bugManagement.detail.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[]>([]);
|
const uploadFileIds = ref<string[]>([]);
|
||||||
async function publishHandler(currentContent: string) {
|
async function publishHandler(currentContent: string) {
|
||||||
try {
|
try {
|
||||||
|
@ -794,14 +683,9 @@
|
||||||
justify-content: flex-start !important;
|
justify-content: flex-start !important;
|
||||||
}
|
}
|
||||||
.tab-pane-container {
|
.tab-pane-container {
|
||||||
@apply flex-1 overflow-y-auto px-4;
|
@apply flex-1 overflow-y-auto p-4;
|
||||||
.ms-scroll-bar();
|
.ms-scroll-bar();
|
||||||
}
|
}
|
||||||
//:deep(.w-full .arco-form-item-label) {
|
|
||||||
// display: inline-block;
|
|
||||||
// width: 100%;
|
|
||||||
// word-wrap: break-word;
|
|
||||||
//}
|
|
||||||
:deep(.arco-form-item-content) {
|
:deep(.arco-form-item-content) {
|
||||||
overflow-wrap: anywhere;
|
overflow-wrap: anywhere;
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,7 +202,6 @@
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
|
|
||||||
import MsButton from '@/components/pure/ms-button/index.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 MsIconfont from '@/components/pure/ms-icon-font/index.vue';
|
||||||
import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue';
|
import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue';
|
||||||
import MsFileList from '@/components/pure/ms-upload/fileList.vue';
|
import MsFileList from '@/components/pure/ms-upload/fileList.vue';
|
||||||
|
@ -232,7 +231,6 @@
|
||||||
import { useAppStore } from '@/store';
|
import { useAppStore } from '@/store';
|
||||||
import { downloadByteFile, sleep } from '@/utils';
|
import { downloadByteFile, sleep } from '@/utils';
|
||||||
import { hasAnyPermission } from '@/utils/permission';
|
import { hasAnyPermission } from '@/utils/permission';
|
||||||
import { findParents, Option } from '@/utils/recursion';
|
|
||||||
|
|
||||||
import { BugEditCustomField, BugEditCustomFieldItem, BugEditFormObject } from '@/models/bug-management';
|
import { BugEditCustomField, BugEditCustomFieldItem, BugEditFormObject } from '@/models/bug-management';
|
||||||
import { AssociatedList, AttachFileInfo } from '@/models/caseManagement/featureCase';
|
import { AssociatedList, AttachFileInfo } from '@/models/caseManagement/featureCase';
|
||||||
|
@ -248,7 +246,7 @@
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
detailInfo: BugEditFormObject;
|
detailInfo: BugEditFormObject;
|
||||||
formItem: FormRuleItem[];
|
// formItem: FormRuleItem[];
|
||||||
allowEdit?: boolean; // 是否允许编辑
|
allowEdit?: boolean; // 是否允许编辑
|
||||||
isPlatformDefaultTemplate: boolean; // 是否是平台默认模板
|
isPlatformDefaultTemplate: boolean; // 是否是平台默认模板
|
||||||
platformSystemFields: BugEditCustomField[]; // 平台系统字段
|
platformSystemFields: BugEditCustomField[]; // 平台系统字段
|
||||||
|
@ -453,26 +451,22 @@
|
||||||
return fileIds;
|
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() {
|
async function handleSave() {
|
||||||
try {
|
try {
|
||||||
confirmLoading.value = true;
|
confirmLoading.value = true;
|
||||||
const { formItem } = props;
|
const customFields: BugEditCustomFieldItem[] = getDetailCustomFields();
|
||||||
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),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (props.isPlatformDefaultTemplate) {
|
if (props.isPlatformDefaultTemplate) {
|
||||||
// 平台系统默认字段插入自定义集合
|
// 平台系统默认字段插入自定义集合
|
||||||
props.platformSystemFields.forEach((item) => {
|
props.platformSystemFields.forEach((item) => {
|
||||||
|
|
|
@ -4,9 +4,13 @@
|
||||||
* @param {stafileInfotus} 文件file
|
* @param {stafileInfotus} 文件file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { FormRuleItem } from '@/components/pure/ms-form-create/types';
|
||||||
import { getFileEnum } from '@/components/pure/ms-upload/iconMap';
|
import { getFileEnum } from '@/components/pure/ms-upload/iconMap';
|
||||||
import { MsFileItem } from '@/components/pure/ms-upload/types';
|
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';
|
import { AssociatedList } from '@/models/caseManagement/featureCase';
|
||||||
|
|
||||||
export function convertToFileByBug(fileInfo: AssociatedList): MsFileItem {
|
export function convertToFileByBug(fileInfo: AssociatedList): MsFileItem {
|
||||||
|
@ -68,3 +72,22 @@ export function convertToFileByDetail(fileInfo: AssociatedList): MsFileItem {
|
||||||
associateId,
|
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
|
<MsDetailDrawer
|
||||||
ref="detailDrawerRef"
|
ref="detailDrawerRef"
|
||||||
v-model:visible="showDrawerVisible"
|
v-model:visible="showDrawerVisible"
|
||||||
:width="1200"
|
:width="960"
|
||||||
:footer="false"
|
:footer="false"
|
||||||
:mask="false"
|
:mask="false"
|
||||||
:title="t('caseManagement.featureCase.caseDetailTitle', { id: detailInfo?.num, name: detailInfo?.name })"
|
:title="t('caseManagement.featureCase.caseDetailTitle', { id: detailInfo?.num, name: detailInfo?.name })"
|
||||||
|
@ -100,30 +100,17 @@
|
||||||
class="no-content relative border-b"
|
class="no-content relative border-b"
|
||||||
@change="clickMenu"
|
@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')
|
t('caseManagement.featureCase.detailDisplaySetting')
|
||||||
}}</span>
|
}}</span>
|
||||||
</div>
|
</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="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'">
|
<template v-if="activeTab === 'detail'">
|
||||||
<TabDetail
|
<TabDetail :form="detailInfo" :allow-edit="true" :form-rules="formItem" @update-success="updateSuccess" />
|
||||||
ref="tabDetailRef"
|
</template>
|
||||||
:form="detailInfo"
|
<template v-if="activeTab === 'basicInfo'">
|
||||||
:allow-edit="true"
|
<BasicInfo :loading="loading" :detail="detail" @update-success="updateSuccess" />
|
||||||
:form-rules="formItem"
|
|
||||||
:form-api="fApi"
|
|
||||||
@update-success="updateSuccess"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
<template v-if="activeTab === 'requirement'">
|
<template v-if="activeTab === 'requirement'">
|
||||||
<TabDemand :case-id="detail.id" />
|
<TabDemand :case-id="detail.id" />
|
||||||
|
@ -151,81 +138,6 @@
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</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
|
<inputComment
|
||||||
ref="commentInputRef"
|
ref="commentInputRef"
|
||||||
v-model:content="content"
|
v-model:content="content"
|
||||||
|
@ -250,21 +162,19 @@
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { useClipboard } from '@vueuse/core';
|
import { useClipboard } from '@vueuse/core';
|
||||||
import { Message, TreeNodeData } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
import dayjs from 'dayjs';
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
|
||||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
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, 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 MsTab from '@/components/pure/ms-tab/index.vue';
|
||||||
import type { MsPaginationI } from '@/components/pure/ms-table/type';
|
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 caseLevel from '@/components/business/ms-case-associate/caseLevel.vue';
|
||||||
import type { CaseLevel } from '@/components/business/ms-case-associate/types';
|
import type { CaseLevel } from '@/components/business/ms-case-associate/types';
|
||||||
import inputComment from '@/components/business/ms-comment/input.vue';
|
import inputComment from '@/components/business/ms-comment/input.vue';
|
||||||
import { CommentParams } from '@/components/business/ms-comment/types';
|
import { CommentParams } from '@/components/business/ms-comment/types';
|
||||||
import MsDetailDrawer from '@/components/business/ms-detail-drawer/index.vue';
|
import MsDetailDrawer from '@/components/business/ms-detail-drawer/index.vue';
|
||||||
|
import BasicInfo from './tabContent/basicInfo.vue';
|
||||||
import SettingDrawer from './tabContent/settingDrawer.vue';
|
import SettingDrawer from './tabContent/settingDrawer.vue';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -276,21 +186,19 @@
|
||||||
getCaseModuleTree,
|
getCaseModuleTree,
|
||||||
} from '@/api/modules/case-management/featureCase';
|
} from '@/api/modules/case-management/featureCase';
|
||||||
import { PreviewEditorImageUrl } from '@/api/requrls/case-management/featureCase';
|
import { PreviewEditorImageUrl } from '@/api/requrls/case-management/featureCase';
|
||||||
|
import { defaultCaseDetail } from '@/config/caseManagement';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useModal from '@/hooks/useModal';
|
import useModal from '@/hooks/useModal';
|
||||||
import { useAppStore } from '@/store';
|
import { useAppStore } from '@/store';
|
||||||
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
||||||
import useUserStore from '@/store/modules/user';
|
import useUserStore from '@/store/modules/user';
|
||||||
import { characterLimit } from '@/utils';
|
import { characterLimit } from '@/utils';
|
||||||
import { translateTextToPX } from '@/utils/css';
|
|
||||||
|
|
||||||
import type { CustomAttributes, DetailCase, TabItemType } from '@/models/caseManagement/featureCase';
|
import type { CustomAttributes, DetailCase, TabItemType } from '@/models/caseManagement/featureCase';
|
||||||
import { ModuleTreeNode } from '@/models/common';
|
import { ModuleTreeNode } from '@/models/common';
|
||||||
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
|
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
|
||||||
|
|
||||||
import { getCaseLevels, initFormCreate } from './utils';
|
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 TabDefect = defineAsyncComponent(() => import('./tabContent/tabBug/tabDefect.vue'));
|
||||||
const TabCaseTable = defineAsyncComponent(() => import('./tabContent/tabCase/tabCaseTable.vue'));
|
const TabCaseTable = defineAsyncComponent(() => import('./tabContent/tabCase/tabCaseTable.vue'));
|
||||||
|
@ -351,26 +259,6 @@
|
||||||
break;
|
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[]>([]);
|
const caseTree = ref<ModuleTreeNode[]>([]);
|
||||||
|
|
||||||
|
@ -382,7 +270,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const detailInfo = ref<DetailCase>({ ...initDetail });
|
const detailInfo = ref<DetailCase>(cloneDeep(defaultCaseDetail));
|
||||||
const customFields = ref<CustomAttributes[]>([]);
|
const customFields = ref<CustomAttributes[]>([]);
|
||||||
const caseLevels = ref<CaseLevel>('P0');
|
const caseLevels = ref<CaseLevel>('P0');
|
||||||
|
|
||||||
|
@ -451,8 +339,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const followLoading = ref<boolean>(false);
|
|
||||||
// 关注
|
// 关注
|
||||||
|
const followLoading = ref<boolean>(false);
|
||||||
async function followHandler() {
|
async function followHandler() {
|
||||||
followLoading.value = true;
|
followLoading.value = true;
|
||||||
try {
|
try {
|
||||||
|
@ -506,50 +394,12 @@
|
||||||
const formRules = ref<FormItem[]>([]);
|
const formRules = ref<FormItem[]>([]);
|
||||||
const formItem = ref<FormRuleItem[]>([]);
|
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);
|
const fApi = ref(null);
|
||||||
// 初始化表单
|
// 初始化表单
|
||||||
function initForm() {
|
function initForm() {
|
||||||
formRules.value = initFormCreate(customFields.value, ['FUNCTIONAL_CASE:READ+UPDATE']);
|
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) {
|
function getTotal(key: string) {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'detail':
|
case 'detail':
|
||||||
|
@ -568,7 +418,9 @@
|
||||||
},
|
},
|
||||||
{ deep: true }
|
{ deep: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
const settingDrawerRef = ref();
|
const settingDrawerRef = ref();
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.visible,
|
() => props.visible,
|
||||||
(val) => {
|
(val) => {
|
||||||
|
@ -621,17 +473,20 @@
|
||||||
isActive.value = !isActive.value;
|
isActive.value = !isActive.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const changeHandler = debounce(() => {
|
|
||||||
tabDetailRef.value.handleOK();
|
|
||||||
}, 300);
|
|
||||||
|
|
||||||
const tabDefaultSettingList: TabItemType[] = [
|
const tabDefaultSettingList: TabItemType[] = [
|
||||||
|
{
|
||||||
|
value: 'basicInfo',
|
||||||
|
label: t('caseManagement.featureCase.basicInfo'),
|
||||||
|
canHide: false,
|
||||||
|
isShow: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
value: 'detail',
|
value: 'detail',
|
||||||
label: t('caseManagement.featureCase.detail'),
|
label: t('caseManagement.featureCase.detail'),
|
||||||
canHide: false,
|
canHide: false,
|
||||||
isShow: true,
|
isShow: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
value: 'case',
|
value: 'case',
|
||||||
label: t('caseManagement.featureCase.case'),
|
label: t('caseManagement.featureCase.case'),
|
||||||
|
@ -724,6 +579,13 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
.display-setting {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 16px;
|
||||||
|
height: 48px;
|
||||||
|
line-height: 48px;
|
||||||
|
}
|
||||||
:deep(.arco-menu-light) {
|
:deep(.arco-menu-light) {
|
||||||
height: 50px;
|
height: 50px;
|
||||||
background: none !important;
|
background: none !important;
|
||||||
|
@ -739,116 +601,6 @@
|
||||||
border-bottom: 1px solid var(--color-text-n8);
|
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 {
|
.rightButtons {
|
||||||
:deep(.ms-button--secondary):hover,
|
:deep(.ms-button--secondary):hover,
|
||||||
:hover > .arco-icon {
|
: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>
|
<span type="text" class="one-line-text cursor-pointer px-0 text-[rgb(var(--primary-5))]">{{ record.num }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template #name="{ record }">
|
<template #name="{ record }">
|
||||||
<a-tooltip :content="record.name">
|
<BugNamePopover :name="record.name" :content="record.content" />
|
||||||
<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>
|
|
||||||
</template>
|
</template>
|
||||||
<template #statusName="{ record }">
|
<template #statusName="{ record }">
|
||||||
<div class="one-line-text">{{ record.statusName || '-' }}</div>
|
<div class="one-line-text">{{ record.statusName || '-' }}</div>
|
||||||
|
@ -59,6 +51,7 @@
|
||||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||||
import type { MsTableColumn } from '@/components/pure/ms-table/type';
|
import type { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||||
import useTable from '@/components/pure/ms-table/useTable';
|
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 { useI18n } from '@/hooks/useI18n';
|
||||||
import { useAppStore } from '@/store';
|
import { useAppStore } from '@/store';
|
||||||
|
@ -157,7 +150,7 @@
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<!-- <style lang="less">
|
||||||
.bug-content-popover {
|
.bug-content-popover {
|
||||||
.arco-popover-content {
|
.arco-popover-content {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
@ -165,4 +158,4 @@
|
||||||
.ms-scroll-bar();
|
.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"
|
v-on="propsEvent"
|
||||||
>
|
>
|
||||||
<template #name="{ record }">
|
<template #name="{ record }">
|
||||||
<div class="flex flex-nowrap items-center">
|
<BugNamePopover :name="record.name" :content="record.content" />
|
||||||
<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>
|
|
||||||
</template>
|
</template>
|
||||||
</ms-base-table>
|
</ms-base-table>
|
||||||
</div>
|
</div>
|
||||||
|
@ -62,11 +52,11 @@
|
||||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||||
import type { MsTableColumn } from '@/components/pure/ms-table/type';
|
import type { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||||
import useTable from '@/components/pure/ms-table/useTable';
|
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 { getDrawerDebugPage } from '@/api/modules/case-management/featureCase';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import { useAppStore } from '@/store';
|
import { useAppStore } from '@/store';
|
||||||
import { characterLimit } from '@/utils';
|
|
||||||
|
|
||||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||||
|
|
||||||
|
@ -104,10 +94,7 @@
|
||||||
title: 'caseManagement.featureCase.defectName',
|
title: 'caseManagement.featureCase.defectName',
|
||||||
slotName: 'name',
|
slotName: 'name',
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
showInTable: true,
|
|
||||||
showTooltip: true,
|
|
||||||
width: 300,
|
width: 300,
|
||||||
ellipsis: true,
|
|
||||||
showDrag: false,
|
showDrag: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -67,21 +67,14 @@
|
||||||
:load-params="{
|
:load-params="{
|
||||||
caseId: props.caseId,
|
caseId: props.caseId,
|
||||||
}"
|
}"
|
||||||
|
:can-edit="true"
|
||||||
@link="linkDefect"
|
@link="linkDefect"
|
||||||
@new="createDefect"
|
@new="createDefect"
|
||||||
@cancel-link="cancelLink"
|
@cancel-link="cancelLink"
|
||||||
/>
|
/>
|
||||||
<ms-base-table v-else v-bind="testPlanPropsRes" ref="planTableRef" v-on="testPlanTableEvent">
|
<ms-base-table v-else v-bind="testPlanPropsRes" ref="planTableRef" v-on="testPlanTableEvent">
|
||||||
<template #name="{ record }">
|
<template #name="{ record }">
|
||||||
<div class="flex flex-nowrap items-center">
|
<BugNamePopover :name="record.name" :content="record.content" />
|
||||||
<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>
|
|
||||||
</template>
|
</template>
|
||||||
<template #handleUserName="{ record }">
|
<template #handleUserName="{ record }">
|
||||||
<a-tooltip :content="record.handleUserName">
|
<a-tooltip :content="record.handleUserName">
|
||||||
|
@ -145,6 +138,7 @@
|
||||||
import AddDefectDrawer from './addDefectDrawer.vue';
|
import AddDefectDrawer from './addDefectDrawer.vue';
|
||||||
import BugList from './bugList.vue';
|
import BugList from './bugList.vue';
|
||||||
import LinkDefectDrawer from './linkDefectDrawer.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 TableFilter from '@/views/case-management/caseManagementFeature/components/tableFilter.vue';
|
||||||
|
|
||||||
import { getBugList, getCustomOptionHeader } from '@/api/modules/bug-management';
|
import { getBugList, getCustomOptionHeader } from '@/api/modules/bug-management';
|
||||||
|
@ -194,20 +188,14 @@
|
||||||
title: 'caseManagement.featureCase.tableColumnID',
|
title: 'caseManagement.featureCase.tableColumnID',
|
||||||
dataIndex: 'num',
|
dataIndex: 'num',
|
||||||
width: 100,
|
width: 100,
|
||||||
showInTable: true,
|
|
||||||
showTooltip: true,
|
showTooltip: true,
|
||||||
showDrag: false,
|
|
||||||
fixed: 'left',
|
fixed: 'left',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'caseManagement.featureCase.defectName',
|
title: 'caseManagement.featureCase.defectName',
|
||||||
slotName: 'name',
|
slotName: 'name',
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
showInTable: true,
|
|
||||||
showTooltip: false,
|
|
||||||
width: 300,
|
width: 300,
|
||||||
ellipsis: true,
|
|
||||||
showDrag: false,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'caseManagement.featureCase.defectState',
|
title: 'caseManagement.featureCase.defectState',
|
||||||
|
@ -217,19 +205,13 @@
|
||||||
options: [],
|
options: [],
|
||||||
labelKey: 'text',
|
labelKey: 'text',
|
||||||
},
|
},
|
||||||
showInTable: true,
|
|
||||||
width: 150,
|
width: 150,
|
||||||
ellipsis: true,
|
|
||||||
showDrag: false,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'common.creator',
|
title: 'common.creator',
|
||||||
slotName: 'createUserName',
|
slotName: 'createUserName',
|
||||||
dataIndex: 'createUserName',
|
dataIndex: 'createUserName',
|
||||||
showInTable: true,
|
|
||||||
showTooltip: true,
|
|
||||||
width: 200,
|
width: 200,
|
||||||
ellipsis: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'caseManagement.featureCase.updateUser',
|
title: 'caseManagement.featureCase.updateUser',
|
||||||
|
@ -239,19 +221,14 @@
|
||||||
options: [],
|
options: [],
|
||||||
labelKey: 'text',
|
labelKey: 'text',
|
||||||
},
|
},
|
||||||
showInTable: true,
|
|
||||||
width: 200,
|
width: 200,
|
||||||
ellipsis: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'caseManagement.featureCase.defectSource',
|
title: 'caseManagement.featureCase.defectSource',
|
||||||
slotName: 'source',
|
slotName: 'source',
|
||||||
dataIndex: 'source',
|
dataIndex: 'source',
|
||||||
showInTable: true,
|
|
||||||
showTooltip: true,
|
showTooltip: true,
|
||||||
width: 100,
|
width: 100,
|
||||||
ellipsis: true,
|
|
||||||
showDrag: false,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'caseManagement.featureCase.tableColumnActions',
|
title: 'caseManagement.featureCase.tableColumnActions',
|
||||||
|
@ -259,8 +236,6 @@
|
||||||
dataIndex: 'operation',
|
dataIndex: 'operation',
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
width: 100,
|
width: 100,
|
||||||
showInTable: true,
|
|
||||||
showDrag: false,
|
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -278,31 +253,21 @@
|
||||||
title: 'caseManagement.featureCase.defectName',
|
title: 'caseManagement.featureCase.defectName',
|
||||||
slotName: 'name',
|
slotName: 'name',
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
showInTable: true,
|
|
||||||
showTooltip: true,
|
|
||||||
width: 250,
|
width: 250,
|
||||||
ellipsis: true,
|
|
||||||
showDrag: false,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'caseManagement.featureCase.planName',
|
title: 'caseManagement.featureCase.planName',
|
||||||
slotName: 'testPlanName',
|
slotName: 'testPlanName',
|
||||||
dataIndex: 'testPlanName',
|
dataIndex: 'testPlanName',
|
||||||
showInTable: true,
|
|
||||||
showTooltip: true,
|
showTooltip: true,
|
||||||
width: 200,
|
width: 200,
|
||||||
ellipsis: true,
|
|
||||||
showDrag: false,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'caseManagement.featureCase.defectState',
|
title: 'caseManagement.featureCase.defectState',
|
||||||
slotName: 'defectState',
|
slotName: 'defectState',
|
||||||
dataIndex: 'defectState',
|
dataIndex: 'defectState',
|
||||||
showInTable: true,
|
|
||||||
showTooltip: true,
|
showTooltip: true,
|
||||||
width: 150,
|
width: 150,
|
||||||
ellipsis: true,
|
|
||||||
showDrag: false,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'caseManagement.featureCase.updateUser',
|
title: 'caseManagement.featureCase.updateUser',
|
||||||
|
@ -312,10 +277,8 @@
|
||||||
options: [],
|
options: [],
|
||||||
labelKey: 'text',
|
labelKey: 'text',
|
||||||
},
|
},
|
||||||
showInTable: true,
|
|
||||||
showTooltip: true,
|
showTooltip: true,
|
||||||
width: 200,
|
width: 200,
|
||||||
ellipsis: true,
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -6,13 +6,13 @@
|
||||||
v-if="caseEnable"
|
v-if="caseEnable"
|
||||||
v-permission="['FUNCTIONAL_CASE:READ+ADD', 'FUNCTIONAL_CASE:READ+UPDATE', 'FUNCTIONAL_CASE:READ+DELETE']"
|
v-permission="['FUNCTIONAL_CASE:READ+ADD', 'FUNCTIONAL_CASE:READ+UPDATE', 'FUNCTIONAL_CASE:READ+DELETE']"
|
||||||
type="primary"
|
type="primary"
|
||||||
|
class="mr-2"
|
||||||
@click="associatedDemand"
|
@click="associatedDemand"
|
||||||
>
|
>
|
||||||
{{ t('caseManagement.featureCase.associatedDemand') }}</a-button
|
{{ t('caseManagement.featureCase.associatedDemand') }}</a-button
|
||||||
>
|
>
|
||||||
<a-button
|
<a-button
|
||||||
v-permission="['FUNCTIONAL_CASE:READ+ADD', 'FUNCTIONAL_CASE:READ+UPDATE', 'FUNCTIONAL_CASE:READ+DELETE']"
|
v-permission="['FUNCTIONAL_CASE:READ+ADD', 'FUNCTIONAL_CASE:READ+UPDATE', 'FUNCTIONAL_CASE:READ+DELETE']"
|
||||||
class="mx-3"
|
|
||||||
type="outline"
|
type="outline"
|
||||||
@click="addDemand"
|
@click="addDemand"
|
||||||
>
|
>
|
||||||
|
|
|
@ -303,7 +303,6 @@
|
||||||
form: DetailCase;
|
form: DetailCase;
|
||||||
allowEdit?: boolean; // 是否允许编辑
|
allowEdit?: boolean; // 是否允许编辑
|
||||||
formRules?: FormRuleItem[]; // 编辑表单
|
formRules?: FormRuleItem[]; // 编辑表单
|
||||||
formApi?: any;
|
|
||||||
isTestPlan?: boolean; // 测试计划页面的
|
isTestPlan?: boolean; // 测试计划页面的
|
||||||
isDisabledTestPlan?: boolean; // 测试计划页面-已归档
|
isDisabledTestPlan?: boolean; // 测试计划页面-已归档
|
||||||
}>(),
|
}>(),
|
||||||
|
@ -485,16 +484,12 @@
|
||||||
caseFormRef.value?.validate().then(async (res: any) => {
|
caseFormRef.value?.validate().then(async (res: any) => {
|
||||||
if (!res) {
|
if (!res) {
|
||||||
try {
|
try {
|
||||||
props.formApi?.validate().then(async (valid: any) => {
|
|
||||||
if (valid === true) {
|
|
||||||
confirmLoading.value = true;
|
confirmLoading.value = true;
|
||||||
await updateCaseRequest(getParams());
|
await updateCaseRequest(getParams());
|
||||||
confirmLoading.value = false;
|
confirmLoading.value = false;
|
||||||
Message.success(t('caseManagement.featureCase.editSuccess'));
|
Message.success(t('caseManagement.featureCase.editSuccess'));
|
||||||
isEditPreposition.value = false;
|
isEditPreposition.value = false;
|
||||||
emit('updateSuccess');
|
emit('updateSuccess');
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
@ -20,8 +20,7 @@
|
||||||
<MsStatusTag :status="record.planStatus" />
|
<MsStatusTag :status="record.planStatus" />
|
||||||
</template>
|
</template>
|
||||||
<template #lastExecResult="{ record }">
|
<template #lastExecResult="{ record }">
|
||||||
<ExecuteResult v-if="record.lastExecResult" :execute-result="record.lastExecResult" />
|
<ExecuteResult :execute-result="record.lastExecResult || 'PENDING'" />
|
||||||
<span v-else>-</span>
|
|
||||||
</template>
|
</template>
|
||||||
<template #[FilterSlotNameEnum.CASE_MANAGEMENT_EXECUTE_RESULT]="{ filterContent }">
|
<template #[FilterSlotNameEnum.CASE_MANAGEMENT_EXECUTE_RESULT]="{ filterContent }">
|
||||||
<ExecuteResult :execute-result="filterContent.value" />
|
<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) {
|
function beforeConfirm(done?: (closed: boolean) => void) {
|
||||||
if (loading.value) return;
|
if (loading.value) return;
|
||||||
formRef.value?.validate(async (errors) => {
|
formRef.value?.validate(async (errors) => {
|
||||||
|
@ -129,6 +136,7 @@
|
||||||
name: form.value.field,
|
name: form.value.field,
|
||||||
});
|
});
|
||||||
Message.success(t('project.fileManagement.addSubModuleSuccess'));
|
Message.success(t('project.fileManagement.addSubModuleSuccess'));
|
||||||
|
reset(false);
|
||||||
emit('addFinish', form.value.field);
|
emit('addFinish', form.value.field);
|
||||||
} else if (props.mode === 'rename') {
|
} else if (props.mode === 'rename') {
|
||||||
// 模块重命名
|
// 模块重命名
|
||||||
|
@ -137,6 +145,7 @@
|
||||||
name: form.value.field,
|
name: form.value.field,
|
||||||
});
|
});
|
||||||
Message.success(t('project.fileManagement.renameSuccess'));
|
Message.success(t('project.fileManagement.renameSuccess'));
|
||||||
|
reset(false);
|
||||||
emit('renameFinish', form.value.field);
|
emit('renameFinish', form.value.field);
|
||||||
}
|
}
|
||||||
if (done) {
|
if (done) {
|
||||||
|
@ -164,13 +173,6 @@
|
||||||
callback(t('project.fileManagement.nameExist'));
|
callback(t('project.fileManagement.nameExist'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function reset(val: boolean) {
|
|
||||||
if (!val) {
|
|
||||||
form.value.field = '';
|
|
||||||
formRef.value?.resetFields();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
<style lang="less" scoped></style>
|
||||||
|
|
|
@ -20,15 +20,7 @@
|
||||||
<MsButton type="text" @click="handleShowDetail(record.id)">{{ record.num }}</MsButton>
|
<MsButton type="text" @click="handleShowDetail(record.id)">{{ record.num }}</MsButton>
|
||||||
</template>
|
</template>
|
||||||
<template #name="{ record }">
|
<template #name="{ record }">
|
||||||
<a-tooltip :content="record.title">
|
<BugNamePopover :name="record.title" :content="record.content" />
|
||||||
<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>
|
|
||||||
</template>
|
</template>
|
||||||
<template #linkCase="{ record }">
|
<template #linkCase="{ record }">
|
||||||
<CaseCountPopover :bug-item="record" />
|
<CaseCountPopover :bug-item="record" />
|
||||||
|
@ -54,6 +46,7 @@
|
||||||
import useTable from '@/components/pure/ms-table/useTable';
|
import useTable from '@/components/pure/ms-table/useTable';
|
||||||
import CaseCountPopover from './caseCountPopover.vue';
|
import CaseCountPopover from './caseCountPopover.vue';
|
||||||
import BugDetailDrawer from '@/views/bug-management/components/bug-detail-drawer.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 { getCustomOptionHeader, getPlatform } from '@/api/modules/bug-management';
|
||||||
import { planDetailBugPage } from '@/api/modules/test-plan/testPlan';
|
import { planDetailBugPage } from '@/api/modules/test-plan/testPlan';
|
||||||
|
|
Loading…
Reference in New Issue