fix: 缺陷管理bug修复&用例紧急bug修复

This commit is contained in:
xinxin.wu 2024-03-14 11:39:44 +08:00 committed by Craftsman
parent 1faaa395e8
commit 5ceec82c42
14 changed files with 114 additions and 45 deletions

View File

@ -239,3 +239,8 @@ export function cancelAssociation(id: string) {
export function getChangeHistoryList(data: TableQueryParams) { export function getChangeHistoryList(data: TableQueryParams) {
return MSR.post({ url: bugURL.getChangeHistoryListUrl, data }); return MSR.post({ url: bugURL.getChangeHistoryListUrl, data });
} }
// 校验跳转用例权限
export function checkCasePermission(projectId: string, caseType: string) {
return MSR.get({ url: `${bugURL.checkCasePermissionUrl}/${projectId}/${caseType}` });
}

View File

@ -73,3 +73,6 @@ export const getUnrelatedModuleTreeCountUrl = '/bug/case/un-relate/module/count'
// 缺陷管理-变更历史-列表 // 缺陷管理-变更历史-列表
export const getChangeHistoryListUrl = '/bug/history/page'; export const getChangeHistoryListUrl = '/bug/history/page';
// 缺陷用例跳转用例是否具备权限
export const checkCasePermissionUrl = '/bug/case/check-permission';

View File

@ -6,7 +6,7 @@
'commentWrapper': props.isUseBottom, 'commentWrapper': props.isUseBottom,
}" }"
> >
<div v-if="props.isShowAvatar" class="mr-3 inline-block"> <MsAvatar avatar="word"></MsAvatar></div> <div v-if="props.isShowAvatar" class="mr-3 inline-block"> <MsAvatar :avatar="userStore.avatar"></MsAvatar></div>
<div class="w-full items-center"> <div class="w-full items-center">
<a-input <a-input
v-if="!isActive" v-if="!isActive"
@ -37,6 +37,7 @@
import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue'; import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import { useUserStore } from '@/store';
defineOptions({ name: 'MsCommentInput' }); defineOptions({ name: 'MsCommentInput' });
@ -48,9 +49,8 @@
}>(); }>();
const currentContent = defineModel<string>('defaultValue', { default: '' }); const currentContent = defineModel<string>('defaultValue', { default: '' });
const commentIds = defineModel<string[]>('noticeUserIds', { default: [] }); const commentIds = defineModel<string[]>('noticeUserIds', { default: [] });
const userStore = useUserStore();
const emit = defineEmits<{ const emit = defineEmits<{
(event: 'publish', value: string): void; (event: 'publish', value: string): void;
(event: 'cancel'): void; (event: 'cancel'): void;

View File

@ -279,6 +279,7 @@
} from './type'; } from './type';
import type { TableChangeExtra, TableColumnData, TableData } from '@arco-design/web-vue'; import type { TableChangeExtra, TableColumnData, TableData } from '@arco-design/web-vue';
import type { TableOperationColumn } from '@arco-design/web-vue/es/table/interface'; import type { TableOperationColumn } from '@arco-design/web-vue/es/table/interface';
import { log } from 'console';
const batchLeft = ref('10px'); const batchLeft = ref('10px');
const { t } = useI18n(); const { t } = useI18n();
@ -398,6 +399,23 @@
tmpArr = props.columns; tmpArr = props.columns;
} }
currentColumns.value = arr || tmpArr; currentColumns.value = arr || tmpArr;
//
if (props.showSetting) {
const isNoDragColumns = currentColumns.value.filter((item) => item.showDrag).length;
if (!isNoDragColumns) {
currentColumns.value = tmpArr.map((item: any) => {
if (item.slotName === SpecialColumnEnum.OPERATION || item.slotName === SpecialColumnEnum.ACTION) {
return {
...item,
fixed: '',
};
}
return {
...item,
};
});
}
}
} catch (error) { } catch (error) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.error('InitColumn failed', error); console.error('InitColumn failed', error);

View File

@ -19,33 +19,36 @@
<template #titleRight="{ loading }"> <template #titleRight="{ loading }">
<div class="rightButtons flex items-center"> <div class="rightButtons flex items-center">
<MsButton <MsButton
v-permission="['PROJECT_BUG:READ+UPDATE']"
type="icon" type="icon"
status="secondary" status="secondary"
class="mr-4 !rounded-[var(--border-radius-small)]" class="mr-4 !rounded-[var(--border-radius-small)]"
:disabled="loading"
:loading="editLoading" :loading="editLoading"
:disabled="loading"
@click="updateHandler" @click="updateHandler"
> >
<MsIcon type="icon-icon_edit_outlined" class="mr-1 font-[16px]" /> <MsIcon type="icon-icon_edit_outlined" class="mr-1 font-[16px]" />
{{ t('common.edit') }} {{ t('common.edit') }}
</MsButton> </MsButton>
<MsButton <MsButton
v-permission="['PROJECT_BUG:READ+UPDATE']"
type="icon" type="icon"
status="secondary" status="secondary"
class="mr-4 !rounded-[var(--border-radius-small)]" class="mr-4 !rounded-[var(--border-radius-small)]"
:disabled="loading"
:loading="shareLoading" :loading="shareLoading"
:disabled="loading"
@click="shareHandler" @click="shareHandler"
> >
<MsIcon type="icon-icon_share1" class="mr-1 font-[16px]" /> <MsIcon type="icon-icon_share1" class="mr-1 font-[16px]" />
{{ t('caseManagement.featureCase.share') }} {{ t('caseManagement.featureCase.share') }}
</MsButton> </MsButton>
<MsButton <MsButton
v-permission="['PROJECT_BUG:READ+UPDATE']"
type="icon" type="icon"
status="secondary" status="secondary"
class="mr-4 !rounded-[var(--border-radius-small)]" class="mr-4 !rounded-[var(--border-radius-small)]"
:disabled="loading"
:loading="followLoading" :loading="followLoading"
:disabled="loading"
@click="followHandler" @click="followHandler"
> >
<MsIcon <MsIcon
@ -154,7 +157,10 @@
content-class="tags-class" content-class="tags-class"
> >
<a-form-item field="tags" :label="t('system.orgTemplate.tags')"> <a-form-item field="tags" :label="t('system.orgTemplate.tags')">
<MsTagsInput v-model:model-value="tags" /> <MsTagsInput
v-model:model-value="tags"
:disabled="!hasAnyPermission(['PROJECT_BUG:READ+UPDATE'])"
/>
</a-form-item> </a-form-item>
</a-form> </a-form>
@ -213,6 +219,7 @@
import useModal from '@/hooks/useModal'; import useModal from '@/hooks/useModal';
import { useAppStore } from '@/store'; import { useAppStore } from '@/store';
import { characterLimit } from '@/utils'; import { characterLimit } from '@/utils';
import { hasAnyPermission } from '@/utils/permission';
import { BugEditCustomField, BugEditFormObject, BugTemplateRequest } from '@/models/bug-management'; import { BugEditCustomField, BugEditFormObject, BugTemplateRequest } from '@/models/bug-management';
import { SelectValue } from '@/models/projectManagement/menuManagement'; import { SelectValue } from '@/models/projectManagement/menuManagement';
@ -274,6 +281,7 @@
props: { props: {
modelValue: valueObj[item.fieldId], modelValue: valueObj[item.fieldId],
options: item.platformOptionJson ? JSON.parse(item.platformOptionJson) : item.options, options: item.platformOptionJson ? JSON.parse(item.platformOptionJson) : item.options,
disabled: !hasAnyPermission(['PROJECT_BUG:READ+UPDATE']),
}, },
}; };
}); });

View File

@ -95,12 +95,14 @@
import { import {
batchAssociation, batchAssociation,
cancelAssociation, cancelAssociation,
checkCasePermission,
getAssociatedList, getAssociatedList,
getModuleTree, getModuleTree,
getUnAssociatedList, getUnAssociatedList,
} from '@/api/modules/bug-management'; } from '@/api/modules/bug-management';
import { postTabletList } from '@/api/modules/project-management/menuManagement'; import { postTabletList } from '@/api/modules/project-management/menuManagement';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import { NO_RESOURCE_ROUTE_NAME } from '@/router/constants';
import { useAppStore } from '@/store'; import { useAppStore } from '@/store';
import useFeatureCaseStore from '@/store/modules/case/featureCase'; import useFeatureCaseStore from '@/store/modules/case/featureCase';
@ -276,12 +278,21 @@
await loadList(); await loadList();
} }
function openDetail(id: string) { async function openDetail(id: string) {
window.open( try {
`${window.location.origin}#${ const res = await checkCasePermission(currentProjectId.value, 'FUNCTIONAL');
router.resolve({ name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE }).fullPath if (res) {
}?id=${id}` window.open(
); `${window.location.origin}#${
router.resolve({ name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE }).fullPath
}?id=${id}`
);
} else {
window.open(`${window.location.origin}#${router.resolve({ name: NO_RESOURCE_ROUTE_NAME }).fullPath}`);
}
} catch (error) {
console.log(error);
}
} }
onMounted(async () => { onMounted(async () => {

View File

@ -17,7 +17,7 @@
v-model:raw="form.description" v-model:raw="form.description"
v-model:filed-ids="fileIds" v-model:filed-ids="fileIds"
:disabled="!contentEditAble" :disabled="!contentEditAble"
:placeholder="t('bugManagement.edit.contentPlaceholder')" :placeholder="t('editor.placeholder')"
:upload-image="handleUploadImage" :upload-image="handleUploadImage"
/> />
<div v-else v-dompurify-html="form?.description || '-'" class="markdown-body"></div> <div v-else v-dompurify-html="form?.description || '-'" class="markdown-body"></div>
@ -41,7 +41,7 @@
v-if="contentEditAble" v-if="contentEditAble"
v-model:raw="item.defaultValue" v-model:raw="item.defaultValue"
:disabled="!contentEditAble" :disabled="!contentEditAble"
:placeholder="t('bugManagement.edit.contentPlaceholder')" :placeholder="t('editor.placeholder')"
/> />
<div v-else v-dompurify-html="item?.defaultValue || '-'" class="markdown-body"></div> <div v-else v-dompurify-html="item?.defaultValue || '-'" class="markdown-body"></div>
</div> </div>

View File

@ -48,12 +48,11 @@
]; ];
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(getChangeHistoryList, { const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(getChangeHistoryList, {
heightUsed: 240, heightUsed: 380,
columns, columns,
scroll: { x: '100%' }, scroll: { x: '100%' },
selectable: false, selectable: false,
noDisable: false, noDisable: false,
pageSimple: true,
debug: true, debug: true,
}); });

View File

@ -393,6 +393,7 @@
} }
const res = await getTemplateById(param); const res = await getTemplateById(param);
await getFormRules(res.customFields); await getFormRules(res.customFields);
isLoading.value = false;
isPlatformDefaultTemplate.value = res.platformDefault; isPlatformDefaultTemplate.value = res.platformDefault;
if (isPlatformDefaultTemplate.value) { if (isPlatformDefaultTemplate.value) {
const systemFields = res.customFields.filter((field) => field.platformSystemField); const systemFields = res.customFields.filter((field) => field.platformSystemField);
@ -402,16 +403,18 @@
}); });
} }
getFormRules(res.customFields.filter((field) => !field.platformSystemField)); getFormRules(res.customFields.filter((field) => !field.platformSystemField));
isLoading.value = false;
} catch (error) { } catch (error) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(error); console.log(error);
} finally {
loading.value = false;
} }
} }
}; };
const getTemplateOptions = async () => { const getTemplateOptions = async () => {
try { try {
loading.value = true;
const res = await getTemplateOption(appStore.currentProjectId); const res = await getTemplateOption(appStore.currentProjectId);
templateOption.value = res.map((item) => { templateOption.value = res.map((item) => {
if (item.enableDefault && !isEdit.value) { if (item.enableDefault && !isEdit.value) {
@ -427,6 +430,8 @@
} catch (error) { } catch (error) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(error); console.log(error);
} finally {
loading.value = false;
} }
}; };

View File

@ -211,7 +211,6 @@
import { BackEndEnum, FilterFormItem, FilterResult, FilterType } from '@/components/pure/ms-advance-filter/type'; import { BackEndEnum, FilterFormItem, FilterResult, FilterType } from '@/components/pure/ms-advance-filter/type';
import MsButton from '@/components/pure/ms-button/index.vue'; import MsButton from '@/components/pure/ms-button/index.vue';
import MsCard from '@/components/pure/ms-card/index.vue'; import MsCard from '@/components/pure/ms-card/index.vue';
import MsExportDrawer from '@/components/pure/ms-export-drawer/index.vue';
import { MsExportDrawerMap, MsExportDrawerOption } from '@/components/pure/ms-export-drawer/types'; import { MsExportDrawerMap, MsExportDrawerOption } from '@/components/pure/ms-export-drawer/types';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue'; import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import { BatchActionParams, BatchActionQueryParams, MsTableColumn } from '@/components/pure/ms-table/type'; import { BatchActionParams, BatchActionQueryParams, MsTableColumn } from '@/components/pure/ms-table/type';
@ -220,7 +219,6 @@
import { ActionsItem } from '@/components/pure/ms-table-more-action/types'; import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
import BatchEditModal from './components/batchEditModal.vue'; import BatchEditModal from './components/batchEditModal.vue';
import BugDetailDrawer from './components/bug-detail-drawer.vue'; import BugDetailDrawer from './components/bug-detail-drawer.vue';
import DeleteModal from './components/deleteModal.vue';
import TableFilter from '@/views/case-management/caseManagementFeature/components/tableFilter.vue'; import TableFilter from '@/views/case-management/caseManagementFeature/components/tableFilter.vue';
import { import {
@ -246,12 +244,17 @@
downloadByteFile, downloadByteFile,
tableParamsToRequestParams, tableParamsToRequestParams,
} from '@/utils'; } from '@/utils';
import { hasAnyPermission } from '@/utils/permission';
import { BugEditCustomField, BugListItem, BugOptionItem } from '@/models/bug-management'; import { BugEditCustomField, BugListItem, BugOptionItem } from '@/models/bug-management';
import { RouteEnum } from '@/enums/routeEnum'; import { RouteEnum } from '@/enums/routeEnum';
import { TableKeyEnum } from '@/enums/tableEnum'; import { TableKeyEnum } from '@/enums/tableEnum';
import { log } from 'console';
const { t } = useI18n(); const { t } = useI18n();
const MsExportDrawer = defineAsyncComponent(() => import('@/components/pure/ms-export-drawer/index.vue'));
const DeleteModal = defineAsyncComponent(() => import('./components/deleteModal.vue'));
const tableStore = useTableStore(); const tableStore = useTableStore();
const appStore = useAppStore(); const appStore = useAppStore();
@ -355,7 +358,7 @@
title: 'bugManagement.ID', title: 'bugManagement.ID',
dataIndex: 'num', dataIndex: 'num',
slotName: 'num', slotName: 'num',
width: 80, width: 200,
sortable: { sortable: {
sortDirections: ['ascend', 'descend'], sortDirections: ['ascend', 'descend'],
sorter: true, sorter: true,
@ -366,7 +369,7 @@
{ {
title: 'bugManagement.bugName', title: 'bugManagement.bugName',
dataIndex: 'title', dataIndex: 'title',
width: 200, width: 300,
showTooltip: true, showTooltip: true,
sortable: { sortable: {
sortDirections: ['ascend', 'descend'], sortDirections: ['ascend', 'descend'],
@ -484,6 +487,7 @@
showJumpMethod: true, showJumpMethod: true,
noDisable: false, noDisable: false,
showSetting: true, showSetting: true,
heightUsed: 380,
}, },
(record: TableData) => ({ (record: TableData) => ({
...record, ...record,
@ -576,8 +580,15 @@
}; };
const checkSyncStatus = async () => { const checkSyncStatus = async () => {
const { complete } = await getSyncStatus(appStore.currentProjectId); if (!hasAnyPermission(['PROJECT_BUG:READ+UPDATE'])) {
isComplete.value = complete; return;
}
try {
const { complete } = await getSyncStatus(appStore.currentProjectId);
isComplete.value = complete;
} catch (error) {
console.log(error);
}
}; };
/** 同步缺陷 */ /** 同步缺陷 */
const { pause, resume } = useIntervalFn(() => { const { pause, resume } = useIntervalFn(() => {

View File

@ -24,6 +24,7 @@
<template #titleRight="{ loading }"> <template #titleRight="{ loading }">
<div class="rightButtons flex items-center"> <div class="rightButtons flex items-center">
<MsButton <MsButton
v-permission="['FUNCTIONAL_CASE:READ+UPDATE']"
type="icon" type="icon"
status="secondary" status="secondary"
class="mr-4 !rounded-[var(--border-radius-small)]" class="mr-4 !rounded-[var(--border-radius-small)]"
@ -35,6 +36,7 @@
{{ t('common.edit') }} {{ t('common.edit') }}
</MsButton> </MsButton>
<MsButton <MsButton
v-permission="['FUNCTIONAL_CASE:READ+UPDATE']"
type="icon" type="icon"
status="secondary" status="secondary"
class="mr-4 !rounded-[var(--border-radius-small)]" class="mr-4 !rounded-[var(--border-radius-small)]"
@ -46,6 +48,7 @@
{{ t('caseManagement.featureCase.share') }} {{ t('caseManagement.featureCase.share') }}
</MsButton> </MsButton>
<MsButton <MsButton
v-permission="['FUNCTIONAL_CASE:READ+UPDATE']"
type="icon" type="icon"
status="secondary" status="secondary"
class="mr-4 !rounded-[var(--border-radius-small)]" class="mr-4 !rounded-[var(--border-radius-small)]"

View File

@ -398,7 +398,7 @@
value: userStore.id || '', value: userStore.id || '',
}, },
]; ];
if (item.defaultValue === 'CREATE_USER') { if (item.defaultValue === 'CREATE_USER' || item.defaultValue.includes('CREATE_USER')) {
initValue = item.type === 'MEMBER' ? userStore.id : [userStore.id]; initValue = item.type === 'MEMBER' ? userStore.id : [userStore.id];
} }
} }

View File

@ -9,7 +9,12 @@
t('caseManagement.featureCase.createDefect') t('caseManagement.featureCase.createDefect')
}}</span> }}</span>
</template> </template>
<a-button v-permission="['FUNCTIONAL_CASE:READ+UPDATE']" class="mr-3" type="primary" @click="linkDefect"> <a-button
v-permission="hasAnyPermission(['FUNCTIONAL_CASE:READ+UPDATE'])"
class="mr-3"
type="primary"
@click="linkDefect"
>
{{ t('caseManagement.featureCase.linkDefect') }} {{ t('caseManagement.featureCase.linkDefect') }}
</a-button> </a-button>
</a-tooltip> </a-tooltip>
@ -134,12 +139,12 @@
</template> </template>
<template #handleUserFilter="{ columnConfig }"> <template #handleUserFilter="{ columnConfig }">
<TableFilter <TableFilter
v-model:visible="handleUserFilterVisible" v-model:visible="handleUserFilterVisible"
v-model:status-filters="handleUserFilterValue" v-model:status-filters="handleUserFilterValue"
:title="(columnConfig.title as string)" :title="(columnConfig.title as string)"
:list="handleUserFilterOptions" :list="handleUserFilterOptions"
value-key="value" value-key="value"
@search="searchData()" @search="searchData()"
> >
<template #item="{ item }"> <template #item="{ item }">
{{ item.text }} {{ item.text }}
@ -148,12 +153,12 @@
</template> </template>
<template #statusFilter="{ columnConfig }"> <template #statusFilter="{ columnConfig }">
<TableFilter <TableFilter
v-model:visible="statusFilterVisible" v-model:visible="statusFilterVisible"
v-model:status-filters="statusFilterValue" v-model:status-filters="statusFilterValue"
:title="(columnConfig.title as string)" :title="(columnConfig.title as string)"
:list="statusFilterOptions" :list="statusFilterOptions"
value-key="value" value-key="value"
@search="searchData()" @search="searchData()"
> >
<template #item="{ item }"> <template #item="{ item }">
{{ item.text }} {{ item.text }}
@ -163,12 +168,12 @@
<template #severityFilter="{ columnConfig }"> <template #severityFilter="{ columnConfig }">
<TableFilter <TableFilter
v-model:visible="severityFilterVisible" v-model:visible="severityFilterVisible"
v-model:status-filters="severityFilterValue" v-model:status-filters="severityFilterValue"
:title="(columnConfig.title as string)" :title="(columnConfig.title as string)"
:list="severityFilterOptions" :list="severityFilterOptions"
value-key="value" value-key="value"
@search="searchData()" @search="searchData()"
> >
<template #item="{ item }"> <template #item="{ item }">
{{ item.text }} {{ item.text }}
@ -221,6 +226,7 @@
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import { useAppStore } from '@/store'; import { useAppStore } from '@/store';
import useFeatureCaseStore from '@/store/modules/case/featureCase'; import useFeatureCaseStore from '@/store/modules/case/featureCase';
import { hasAnyPermission } from '@/utils/permission';
import { BugOptionItem } from '@/models/bug-management'; import { BugOptionItem } from '@/models/bug-management';
import type { TableQueryParams } from '@/models/common'; import type { TableQueryParams } from '@/models/common';

View File

@ -199,7 +199,7 @@ export function initFormCreate(customFields: CustomAttributes[], permission: str
value: userStore.id || '', value: userStore.id || '',
}, },
]; ];
currentDefaultValue = item.defaultValue; currentDefaultValue = tempValue;
} else { } else {
currentDefaultValue = JSON.parse(item.defaultValue); currentDefaultValue = JSON.parse(item.defaultValue);
} }