feat(缺陷管理): 缺陷列表导出
This commit is contained in:
parent
9c28dd2fa4
commit
13a5c7ebbc
|
@ -44,6 +44,7 @@
|
|||
"@types/color": "^3.0.4",
|
||||
"@vueuse/core": "^10.4.1",
|
||||
"ace-builds": "^1.24.2",
|
||||
"ahooks-vue": "^0.15.1",
|
||||
"axios": "^0.24.0",
|
||||
"dayjs": "^1.11.9",
|
||||
"echarts": "^5.4.3",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import MSR from '@/api/http/index';
|
||||
import * as bugURL from '@/api/requrls/bug-management';
|
||||
|
||||
import { BugListItem } from '@/models/bug-management';
|
||||
import { BugExportParams, BugListItem } from '@/models/bug-management';
|
||||
import { CommonList, TableQueryParams, TemplateOption } from '@/models/common';
|
||||
|
||||
/**
|
||||
|
@ -44,3 +44,13 @@ export function getTemplateById(data: TableQueryParams) {
|
|||
export function getExportConfig(projectId: string) {
|
||||
return MSR.get({ url: `${bugURL.getExportConfigUrl}${projectId}` });
|
||||
}
|
||||
|
||||
// 同步缺陷
|
||||
export function syncBugOpenSource(params: { projectId: string }) {
|
||||
return MSR.get({ url: bugURL.getSyncBugOpenSourceUrl, params });
|
||||
}
|
||||
|
||||
// 导出缺陷
|
||||
export function exportBug(data: BugExportParams) {
|
||||
return MSR.post({ url: bugURL.postExportBugUrl, data });
|
||||
}
|
||||
|
|
|
@ -7,3 +7,5 @@ export const postBatchDeleteBugUrl = '/bug/batch-delete';
|
|||
export const getTemplateUrl = '/bug/template';
|
||||
export const getTemplageOption = '/bug/template/option';
|
||||
export const getExportConfigUrl = '/bug/export/columns/';
|
||||
export const getSyncBugOpenSourceUrl = '/bug/sync/';
|
||||
export const postExportBugUrl = '/bug/export';
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { PropType } from 'vue';
|
||||
import { onClickOutside } from '@vueuse/core';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
|
@ -46,6 +47,8 @@ export default defineComponent({
|
|||
const { mode, options, modelValue, defaultValue } = toRefs(props);
|
||||
const oldModelValue = ref(modelValue.value);
|
||||
const editStatus = ref<EditStatus>('null');
|
||||
const selectRef = ref<HTMLElement | null>(null);
|
||||
const chengeStatus = ref(false);
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
|
@ -54,6 +57,7 @@ export default defineComponent({
|
|||
if (result) {
|
||||
defaultValue.value = v;
|
||||
Message.success(t('common.updateSuccess'));
|
||||
chengeStatus.value = true;
|
||||
} else {
|
||||
Message.error(t('common.updateFail'));
|
||||
modelValue.value = oldModelValue.value;
|
||||
|
@ -69,11 +73,15 @@ export default defineComponent({
|
|||
|
||||
const handleClick = () => {
|
||||
editStatus.value = 'active';
|
||||
if (mode.value === 'select') {
|
||||
selectRef.value?.focus();
|
||||
}
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
editStatus.value = 'null';
|
||||
modelValue.value = oldModelValue.value;
|
||||
chengeStatus.value = false;
|
||||
};
|
||||
|
||||
const handleBlur = () => {
|
||||
|
@ -109,12 +117,22 @@ export default defineComponent({
|
|||
);
|
||||
};
|
||||
|
||||
onClickOutside(selectRef, (event) => {
|
||||
if (editStatus.value === 'active' && !chengeStatus.value) {
|
||||
handleReset();
|
||||
}
|
||||
});
|
||||
|
||||
const renderChild = () => {
|
||||
if (mode.value === 'input') {
|
||||
return <a-input modelValue={modelValue} onKeyDown={handleKeyDown} onBlur={handleBlur} />;
|
||||
}
|
||||
if (mode.value === 'select') {
|
||||
return <a-select modelValue={modelValue} options={options.value} onSelect={handleChange} />;
|
||||
return (
|
||||
<div ref={selectRef}>
|
||||
<a-select modelValue={modelValue} options={options.value} onSelect={handleChange} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (mode.value === 'tagInput') {
|
||||
return <a-input-tag modelValue={modelValue} onKeyDown={handleKeyDown} onBlur={handleBlur} />;
|
||||
|
|
|
@ -109,7 +109,7 @@
|
|||
selectable: false,
|
||||
noDisable: true,
|
||||
showSetting: false,
|
||||
heightUsed: 280,
|
||||
heightUsed: 288,
|
||||
});
|
||||
|
||||
const fetchData = async () => {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { BatchApiParams } from './common';
|
||||
|
||||
export interface BugListItem {
|
||||
id: string; // 缺陷id
|
||||
num: string; // 缺陷编号
|
||||
|
@ -14,4 +16,14 @@ export interface BugListItem {
|
|||
updateTime: string; // 更新时间
|
||||
deleted: boolean; // 删除标志
|
||||
}
|
||||
|
||||
export interface BugExportColumn {
|
||||
key: string; // 字段key
|
||||
text?: string; // 字段名称
|
||||
columnType?: string; // 字段类型
|
||||
}
|
||||
export interface BugExportParams extends BatchApiParams {
|
||||
bugExportColumns: BugExportColumn[]; // 导出字段
|
||||
}
|
||||
|
||||
export default {};
|
||||
|
|
|
@ -4,12 +4,20 @@
|
|||
<template #left>
|
||||
<div class="flex gap-[12px]">
|
||||
<a-button type="primary" @click="handleCreate">{{ t('bugManagement.createBug') }} </a-button>
|
||||
<a-button type="outline" @click="handleSync">{{ t('bugManagement.syncBug') }} </a-button>
|
||||
<a-button :disabled="syncBugLoading" type="outline" @click="handleSync"
|
||||
>{{ t('bugManagement.syncBug') }}
|
||||
</a-button>
|
||||
<a-button type="outline" @click="handleExport">{{ t('common.export') }} </a-button>
|
||||
</div>
|
||||
</template>
|
||||
</MsAdvanceFilter>
|
||||
<MsBaseTable v-bind="propsRes" v-on="propsEvent">
|
||||
<MsBaseTable
|
||||
class="mt-[16px]"
|
||||
v-bind="propsRes"
|
||||
:action-config="tableBatchActions"
|
||||
v-on="propsEvent"
|
||||
@batch-action="handleTableBatch"
|
||||
>
|
||||
<template #name="{ record, rowIndex }">
|
||||
<a-button type="text" class="px-0" @click="handleShowDetail(record.id, rowIndex)">{{ record.name }}</a-button>
|
||||
</template>
|
||||
|
@ -77,7 +85,14 @@
|
|||
<a-date-picker v-model="syncObject.time" show-time class="w-[304px]" />
|
||||
</div>
|
||||
</a-modal>
|
||||
<MsExportDrawer v-model:visible="exportVisible" :all-data="exportOptionData" />
|
||||
<MsExportDrawer v-model:visible="exportVisible" :all-data="exportOptionData" @confirm="exportConfirm">
|
||||
<template #title>
|
||||
<span class="text-[var(--color-text-1)]">{{ t('bugManagement.exportBug') }}</span>
|
||||
<span v-if="currentSelectParams.currentSelectCount" class="text-[var(--color-text-4)]"
|
||||
>({{ t('bugManagement.exportBugCount', { count: currentSelectParams.currentSelectCount }) }})</span
|
||||
>
|
||||
</template>
|
||||
</MsExportDrawer>
|
||||
<BugDetailDrawer
|
||||
v-model:visible="detailVisible"
|
||||
:detail-id="activeDetailId"
|
||||
|
@ -103,9 +118,9 @@
|
|||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||
import MsExportDrawer from '@/components/pure/ms-export-drawer/index.vue';
|
||||
import { MsExportDrawerMap } 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 { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import { BatchActionParams, BatchActionQueryParams, MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
|
||||
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||
|
@ -113,15 +128,24 @@
|
|||
import BugDetailDrawer from './components/bug-detail-drawer.vue';
|
||||
import DeleteModal from './components/deleteModal.vue';
|
||||
|
||||
import { deleteSingleBug, getBugList, getExportConfig } from '@/api/modules/bug-management';
|
||||
import {
|
||||
deleteSingleBug,
|
||||
exportBug,
|
||||
getBugList,
|
||||
getExportConfig,
|
||||
syncBugOpenSource,
|
||||
} from '@/api/modules/bug-management';
|
||||
import { updateOrAddProjectUserGroup } from '@/api/modules/project-management/usergroup';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import router from '@/router';
|
||||
import { useAppStore, useTableStore } from '@/store';
|
||||
import useLicenseStore from '@/store/modules/setting/license';
|
||||
|
||||
import { BugListItem } from '@/models/bug-management';
|
||||
import { ColumnEditTypeEnum, TableKeyEnum } from '@/enums/tableEnum';
|
||||
|
||||
import { useRequest } from 'ahooks-vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const tableStore = useTableStore();
|
||||
|
@ -137,6 +161,20 @@
|
|||
const activeCaseIndex = ref<number>(0);
|
||||
const currentDeleteObj = reactive<{ id: string; name: string }>({ id: '', name: '' });
|
||||
const deleteVisible = ref(false);
|
||||
const keyword = ref('');
|
||||
const licenseStore = useLicenseStore();
|
||||
const isXpack = computed(() => licenseStore.hasLicense());
|
||||
// 当前选择的条数
|
||||
const currentSelectParams = ref<BatchActionQueryParams>({ selectAll: false, currentSelectCount: 0 });
|
||||
|
||||
const { loading: syncBugLoading, run: syncBugRun } = useRequest(
|
||||
() => syncBugOpenSource({ projectId: projectId.value }),
|
||||
{
|
||||
pollingInterval: 1 * 1000,
|
||||
pollingWhenHidden: true,
|
||||
manual: true,
|
||||
}
|
||||
);
|
||||
|
||||
const syncObject = reactive({
|
||||
time: '',
|
||||
|
@ -187,6 +225,7 @@
|
|||
title: 'bugManagement.bugName',
|
||||
editType: ColumnEditTypeEnum.INPUT,
|
||||
dataIndex: 'name',
|
||||
slotName: 'name',
|
||||
showTooltip: true,
|
||||
},
|
||||
{
|
||||
|
@ -267,7 +306,7 @@
|
|||
}
|
||||
};
|
||||
|
||||
const { propsRes, propsEvent, setKeyword, setLoadListParams, setProps } = useTable(
|
||||
const { propsRes, propsEvent, setKeyword, setLoadListParams, setProps, resetSelector } = useTable(
|
||||
getBugList,
|
||||
{
|
||||
tableKey: TableKeyEnum.BUG_MANAGEMENT,
|
||||
|
@ -281,6 +320,24 @@
|
|||
(record) => handleNameChange(record)
|
||||
);
|
||||
|
||||
const tableBatchActions = {
|
||||
baseAction: [
|
||||
{
|
||||
label: 'common.export',
|
||||
eventTag: 'export',
|
||||
},
|
||||
{
|
||||
label: 'common.edit',
|
||||
eventTag: 'edit',
|
||||
},
|
||||
{
|
||||
label: 'common.delete',
|
||||
eventTag: 'delete',
|
||||
danger: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
watchEffect(() => {
|
||||
setProps({ heightUsed: heightUsed.value });
|
||||
});
|
||||
|
@ -339,9 +396,28 @@
|
|||
|
||||
const fetchData = async (v = '') => {
|
||||
setKeyword(v);
|
||||
keyword.value = v;
|
||||
setProps({ data });
|
||||
};
|
||||
|
||||
const exportConfirm = async (option: MsExportDrawerOption[]) => {
|
||||
try {
|
||||
const { selectedIds, selectAll, excludeIds } = currentSelectParams.value;
|
||||
await exportBug({
|
||||
selectIds: selectedIds || [],
|
||||
selectAll,
|
||||
excludeIds,
|
||||
condition: { keyword: keyword.value },
|
||||
bugExportColumns: option.map((item) => item),
|
||||
});
|
||||
Message.success(t('common.exportSuccess'));
|
||||
exportVisible.value = false;
|
||||
resetSelector();
|
||||
} catch (error) {
|
||||
Message.error(t('common.exportFail'));
|
||||
}
|
||||
};
|
||||
|
||||
const handleSingleDelete = (record?: TableData) => {
|
||||
if (record) {
|
||||
currentDeleteObj.id = record.id;
|
||||
|
@ -360,7 +436,12 @@
|
|||
});
|
||||
};
|
||||
const handleSync = () => {
|
||||
syncVisible.value = true;
|
||||
if (isXpack.value) {
|
||||
syncVisible.value = true;
|
||||
} else {
|
||||
// 直接开始轮询
|
||||
syncBugRun();
|
||||
}
|
||||
};
|
||||
|
||||
const handleShowDetail = (id: string, rowIndex: number) => {
|
||||
|
@ -379,9 +460,14 @@
|
|||
console.log('create', record);
|
||||
};
|
||||
|
||||
const handleDelete = (record: BugListItem) => {
|
||||
const handleBatchDelete = (params: BatchActionQueryParams) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('create', record);
|
||||
console.log('create', params);
|
||||
};
|
||||
|
||||
const handleBatchEdit = (params: BatchActionQueryParams) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('create', params);
|
||||
};
|
||||
|
||||
const handleExport = () => {
|
||||
|
@ -456,6 +542,23 @@
|
|||
{ label: t('bugManagement.statusO.refused'), value: 'Refused' },
|
||||
];
|
||||
|
||||
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
|
||||
currentSelectParams.value = params;
|
||||
switch (event.eventTag) {
|
||||
case 'export':
|
||||
handleExport();
|
||||
break;
|
||||
case 'delete':
|
||||
handleBatchDelete(params);
|
||||
break;
|
||||
case 'edit':
|
||||
handleBatchEdit(params);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
setLoadListParams({ projectId: projectId.value });
|
||||
fetchData();
|
||||
|
|
|
@ -28,6 +28,8 @@ export default {
|
|||
batchEdit: '批量编辑',
|
||||
selectProps: '选择属性',
|
||||
batchUpdate: '批量更新为',
|
||||
exportBug: '导出缺陷',
|
||||
exportBugCount: '已选 {count} 条缺陷',
|
||||
edit: {
|
||||
defaultSystemTemplate: '默认为系统模板',
|
||||
content: '缺陷内容',
|
||||
|
|
|
@ -275,6 +275,7 @@
|
|||
selectable: true,
|
||||
showSetting: true,
|
||||
showJumpMethod: true,
|
||||
heightUsed: 288,
|
||||
},
|
||||
(record) => ({
|
||||
...record,
|
||||
|
|
Loading…
Reference in New Issue