feat(缺陷管理): 删除单个缺陷弹窗&批量编辑组件

This commit is contained in:
RubyLiu 2023-12-08 18:04:28 +08:00 committed by 刘瑞斌
parent 403c2e0e1e
commit 444a0b8c14
8 changed files with 260 additions and 13 deletions

View File

@ -25,8 +25,8 @@ export function createBug(data: TableQueryParams) {
return MSR.post({ url: bugURL.postCreateBugUrl, data });
}
export function deleteBug(data: TableQueryParams) {
return MSR.get({ url: bugURL.getDeleteBugUrl, data });
export function deleteSingleBug(data: TableQueryParams) {
return MSR.get({ url: `${bugURL.getDeleteBugUrl}${data.id}` });
}
export function deleteBatchBug(data: TableQueryParams) {

View File

@ -7,8 +7,10 @@
:indeterminate="indeterminate"
@change="handleCheckChange"
/>
<a-dropdown v-if="showSelectAll" :disable="props.disabled" position="bl" @select="handleSelect">
<MsIcon type="icon-icon_down_outlined" class="dropdown-icon" />
<a-dropdown v-if="props.showSelectAll" :disable="props.disabled" position="bl" @select="handleSelect">
<div>
<MsIcon type="icon-icon_down_outlined" class="dropdown-icon" />
</div>
<template #content>
<a-doption :value="SelectAllEnum.CURRENT">{{ t('msTable.current') }}</a-doption>
<a-doption :value="SelectAllEnum.ALL">{{ t('msTable.all') }}</a-doption>

View File

@ -27,6 +27,8 @@ export default {
'common.updateSuccess': '更新成功',
'common.updateFailed': '更新失败',
'common.deleteConfirm': '确认删除?',
'common.deleteConfirmTitle': '确认删除 {name} 吗',
'common.deleteConfirmContent': '删除后MeterSphere 创建的缺陷进入回收站;第三方平台同步的缺陷将不做回收',
'common.deleteSuccess': '删除成功',
'common.deleteFailed': '删除失败',
'common.addSuccess': '添加成功',

View File

@ -0,0 +1,102 @@
<template>
<a-modal
v-model:visible="currentVisible"
title-align="start"
class="ms-modal-form ms-modal-small"
unmount-on-close
@cancel="handleCancel"
>
<template #title>
<div class="flex flex-row items-center">
<div class="ml-[8px]">{{ t('bugManagement.batchEdit') }}</div>
<div v-if="props.selectCount" class="ml-[8px] text-[var(--color-text-4)]">
{{ t('bugManagement.selectedCount', { count: props.selectCount }) }}
</div>
</div>
</template>
<div class="form">
<a-form ref="formRef" class="rounded-[4px]" :model="form" layout="vertical">
<a-form-item
field="name"
asterisk-position="end"
:label="t('bugManagement.deleteLabel')"
:rules="[{ required: true }]"
>
<a-input v-model:model-value="form.label" />
</a-form-item>
</a-form>
</div>
<template #footer>
<a-button type="secondary" :loading="loading" @click="handleCancel">
{{ t('common.cancel') }}
</a-button>
<a-button type="primary" :loading="loading" :disabled="!form.label" @click="handleConfirm">
{{ t('common.update') }}
</a-button>
</template>
</a-modal>
</template>
<script lang="ts" setup>
import { computed, reactive, ref } from 'vue';
import { type FormInstance, Message, type ValidatedError } from '@arco-design/web-vue';
import { FilterFormItem } from '@/components/pure/ms-advance-filter/type';
import { useI18n } from '@/hooks/useI18n';
const { t } = useI18n();
const props = defineProps<{
visible: boolean;
configList: FilterFormItem[];
selectCount: number;
remoteFunc(params: Record<string, any>): Promise<any>; // Promise
}>();
const emit = defineEmits<{
(e: 'submit'): void;
(e: 'update:visible', value: boolean): void;
}>();
const currentVisible = computed({
get() {
return props.visible;
},
set(value) {
emit('update:visible', value);
},
});
const loading = ref(false);
const form = reactive({
label: '',
value: '',
append: false,
});
const formRef = ref<FormInstance>();
const handleCancel = () => {
currentVisible.value = false;
form.label = '';
loading.value = false;
};
const handleConfirm = () => {
formRef.value?.validate(async (errors: undefined | Record<string, ValidatedError>) => {
if (!errors) {
try {
loading.value = true;
Message.success(t('common.deleteSuccess'));
handleCancel();
emit('submit');
} catch (error) {
// eslint-disable-next-line no-console
console.error(error);
} finally {
loading.value = false;
}
}
});
};
</script>

View File

@ -0,0 +1,118 @@
<template>
<a-modal
v-model:visible="currentVisible"
title-align="start"
class="ms-modal-form ms-modal-small"
unmount-on-close
@cancel="handleCancel"
>
<template #title>
<div class="flex flex-row items-center">
<icon-exclamation-circle-fill class="text-[16px] text-[rgb(var(--danger-6))]" />
<div class="ml-[8px]">{{ t('common.confirmDelete') }}</div>
<a-tooltip :content="props.name">
<div class="one-text-line max-w-[300px] px-[5px]">
{{ props.name }}
</div>
</a-tooltip>
</div>
</template>
<div class="form">
<a-form ref="formRef" class="rounded-[4px]" :model="form" layout="vertical">
<a-form-item
field="name"
asterisk-position="end"
:label="t('bugManagement.deleteLabel')"
:rules="[
{
validator(value, callback) {
if (value !== props.name) {
callback(t('bugManagement.nameIsIncorrect'));
} else {
callback();
}
},
},
]"
>
<a-input v-model:model-value="form.name" />
</a-form-item>
</a-form>
</div>
<template #footer>
<a-button type="secondary" :loading="loading" @click="handleCancel">
{{ t('common.cancel') }}
</a-button>
<a-button type="primary" status="danger" :loading="loading" :disabled="!form.name" @click="handleConfirm">
{{ t('common.confirmDelete') }}
</a-button>
</template>
</a-modal>
</template>
<script lang="ts" setup>
import { computed, reactive, ref } from 'vue';
import { type FormInstance, Message, type ValidatedError } from '@arco-design/web-vue';
import { useI18n } from '@/hooks/useI18n';
const { t } = useI18n();
const props = defineProps<{
visible: boolean;
name: string;
id: string;
remoteFunc(params: Record<string, any>): Promise<any>; // Promise
}>();
const emit = defineEmits<{
(e: 'submit'): void;
(e: 'update:visible', value: boolean): void;
}>();
const currentVisible = computed({
get() {
return props.visible;
},
set(value) {
emit('update:visible', value);
},
});
const loading = ref(false);
const form = reactive({
name: '',
});
const formRef = ref<FormInstance>();
const handleCancel = () => {
currentVisible.value = false;
form.name = '';
loading.value = false;
};
const handleConfirm = () => {
formRef.value?.validate(async (errors: undefined | Record<string, ValidatedError>) => {
if (!errors) {
try {
loading.value = true;
await props.remoteFunc({ id: props.id });
Message.success(t('common.deleteSuccess'));
handleCancel();
emit('submit');
} catch (error) {
// eslint-disable-next-line no-console
console.error(error);
} finally {
loading.value = false;
}
}
});
};
</script>
<style lang="less" scoped>
:deep(.arco-form-item-label) {
color: var(--color-text-2) !important;
}
</style>

View File

@ -86,10 +86,17 @@
:page-change="propsEvent.pageChange"
:pagination="propsRes.msPagination!"
/>
<DeleteModal
:id="currentDeleteObj.name"
v-model:visible="deleteVisible"
:name="currentDeleteObj.name"
:remote-func="deleteSingleBug"
@submit="handleSingleDelete"
/>
</template>
<script lang="ts" setup>
import { Message } from '@arco-design/web-vue';
import { Message, TableData } from '@arco-design/web-vue';
import { MsAdvanceFilter, timeSelectOptions } from '@/components/pure/ms-advance-filter';
import { FilterFormItem, FilterType } from '@/components/pure/ms-advance-filter/type';
@ -104,8 +111,9 @@
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
import MsEditComp from '@/components/business/ms-edit-comp';
import BugDetailDrawer from './components/bug-detail-drawer.vue';
import DeleteModal from './components/deleteModal.vue';
import { getBugList, getExportConfig } from '@/api/modules/bug-management';
import { deleteSingleBug, getBugList, getExportConfig } from '@/api/modules/bug-management';
import { updateOrAddProjectUserGroup } from '@/api/modules/project-management/usergroup';
import { useI18n } from '@/hooks/useI18n';
import router from '@/router';
@ -127,6 +135,8 @@
const detailVisible = ref(false);
const activeDetailId = ref<string>('');
const activeCaseIndex = ref<number>(0);
const currentDeleteObj = reactive<{ id: string; name: string }>({ id: '', name: '' });
const deleteVisible = ref(false);
const syncObject = reactive({
time: '',
@ -332,6 +342,18 @@
setProps({ data });
};
const handleSingleDelete = (record?: TableData) => {
if (record) {
currentDeleteObj.id = record.id;
currentDeleteObj.name = record.name;
deleteVisible.value = true;
} else {
fetchData();
currentDeleteObj.id = '';
currentDeleteObj.name = '';
}
};
const handleCreate = () => {
router.push({
name: 'bugManagementBugEdit',
@ -391,7 +413,7 @@
function handleMoreActionSelect(item: ActionsItem, record: BugListItem) {
if (item.eventTag === 'delete') {
handleDelete(record);
handleSingleDelete(record);
}
}

View File

@ -22,6 +22,12 @@ export default {
syncBugTipRowTwo: '新增缺陷和更新已有的缺陷?',
bugAutoSync: '系统 {name} 自动同步',
syncTime: '同步时间',
deleteLabel: '删除后MeterSphere 创建的缺陷进入回收站;第三方平台同步的缺陷将不做回收',
nameIsIncorrect: '缺陷名称不正确',
selectedCount: '(已选 {count} 条缺陷)',
batchEdit: '批量编辑',
selectProps: '选择属性',
batchUpdate: '批量更新为',
edit: {
defaultSystemTemplate: '默认为系统模板',
content: '缺陷内容',

View File

@ -2,10 +2,7 @@
<MsCard simple>
<MsAdvanceFilter :filter-config-list="filterConfigList" :row-count="filterRowCount">
<template #left>
<div class="flex gap-[12px]">
<a-button type="primary" @click="handleCreate">{{ t('bugManagement.createBug') }} </a-button>
<a-button type="primary" @click="handleSync">{{ t('bugManagement.syncBug') }} </a-button>
</div>
<div></div>
</template>
</MsAdvanceFilter>
<MsBaseTable v-bind="propsRes" v-on="propsEvent">
@ -19,8 +16,6 @@
<MsButton class="!mr-0" @click="handleCopy(record)">{{ t('common.copy') }}</MsButton>
<a-divider direction="vertical" />
<MsButton class="!mr-0" @click="handleEdit(record)">{{ t('common.edit') }}</MsButton>
<a-divider direction="vertical" />
<MsButton class="!mr-0" status="danger" @click="handleDelete(record)">{{ t('common.delete') }}</MsButton>
</div>
</template>
<template #empty> </template>