refactor(缺陷管理): 重构缺陷管理字段导出抽屉样式以及逻辑

This commit is contained in:
xinxin.wu 2024-07-25 19:04:08 +08:00 committed by 刘瑞斌
parent d889e666d8
commit f038b26fb3
2 changed files with 214 additions and 34 deletions

View File

@ -6,28 +6,42 @@
:width="800" :width="800"
min-width="800px" min-width="800px"
unmount-on-close unmount-on-close
no-content-padding
:show-continue="false" :show-continue="false"
:ok-disabled="!selectedList.length" :ok-disabled="!selectedList.length"
:footer="false"
@confirm="handleDrawerConfirm" @confirm="handleDrawerConfirm"
@cancel="handleDrawerCancel" @cancel="handleDrawerCancel"
> >
<template #title>
<slot name="title"></slot>
</template>
<div class="panel-wrapper"> <div class="panel-wrapper">
<div class="inner-wrapper"> <div class="inner-wrapper">
<div class="optional-field"> <div class="optional-field">
<div class="optional-header"> <div class="optional-header">
<div class="font-medium">{{ <div class="font-medium">
props.titleProps?.selectableTitle || t('system.orgTemplate.optionalField') <a-checkbox :model-value="isCheckedAll" :indeterminate="indeterminate" @change="handleChangeAll">
}}</div> <span class="font-medium text-[var(--color-text-3)]">
<a-checkbox :model-value="isCheckedAll" :indeterminate="indeterminate" @change="handleChangeAll"> {{ props.titleProps?.selectableTitle || t('system.orgTemplate.optionalField') }}
<span class="font-medium text-[var(--color-text-3)]">{{ t('system.orgTemplate.selectAll') }}</span> </span>
</a-checkbox> </a-checkbox>
</div>
</div> </div>
<div class="p-[16px]"> <div class="p-[16px]">
<a-checkbox-group :model-value="selectedIds" @change="handleGroupChange"> <div class="text-[var(--color-text-4)]">
<a-checkbox
:model-value="isCheckedSystemAll"
:indeterminate="systemIndeterminate"
@change="(value) => handleChange(value as boolean, 'system')"
>
<span class="font-medium text-[var(--color-text-4)]">
{{ props.titleProps?.systemTitle || t('ms-export-drawer.systemFiled') }}
</span>
</a-checkbox>
</div>
<a-checkbox-group :model-value="selectedSystemIds" @change="(value) => handleGroupChange(value, 'system')">
<div v-if="systemList.length" class="mb-[32px]"> <div v-if="systemList.length" class="mb-[32px]">
<div class="text-[var(--color-text-4)]">{{
props.titleProps?.systemTitle || t('ms-export-drawer.systemFiled')
}}</div>
<div class="flex flex-row flex-wrap"> <div class="flex flex-row flex-wrap">
<a-checkbox <a-checkbox
v-for="item in systemList" v-for="item in systemList"
@ -42,8 +56,20 @@
</a-checkbox> </a-checkbox>
</div> </div>
</div> </div>
</a-checkbox-group>
<div class="text-[var(--color-text-4)]">
<a-checkbox
:model-value="isCheckedCustomAll"
:indeterminate="customIndeterminate"
@change="(value) => handleChange(value as boolean, 'custom')"
>
<span class="font-medium text-[var(--color-text-4)]">
{{ t('ms-export-drawer.customFiled') }}
</span>
</a-checkbox>
</div>
<a-checkbox-group :model-value="selectedCustomIds" @change="(value) => handleGroupChange(value, 'custom')">
<div v-if="customList.length" class="mb-[32px]"> <div v-if="customList.length" class="mb-[32px]">
<div class="text-[var(--color-text-4)]">{{ t('ms-export-drawer.customFiled') }}</div>
<div class="flex flex-row flex-wrap"> <div class="flex flex-row flex-wrap">
<a-checkbox <a-checkbox
v-for="item in customList" v-for="item in customList"
@ -57,13 +83,27 @@
</a-checkbox> </a-checkbox>
</div> </div>
</div> </div>
<div v-if="otherList.length" class="mb-[32px]"> </a-checkbox-group>
<div class="flex flex-row items-center gap-[4px]"> <div class="flex flex-row items-center gap-[4px]">
<div class="text-[var(--color-text-4)]"> {{ t('ms-export-drawer.otherFiled') }}</div> <div class="text-[var(--color-text-4)]">
<a-checkbox
:model-value="isCheckedOtherAll"
:indeterminate="otherIndeterminate"
@change="(value) => handleChange(value as boolean, 'other')"
>
<span class="font-medium text-[var(--color-text-4)]">
{{ t('ms-export-drawer.otherFiled') }}
</span>
<a-tooltip :content="t('ms-export-drawer.otherTip')" position="right"> <a-tooltip :content="t('ms-export-drawer.otherTip')" position="right">
<icon-question-circle class="text-[rgb(var(--primary-5))]" /> <icon-question-circle
class="ml-[4px] text-[var(--color-text-4)] hover:text-[rgb(var(--primary-5))]"
/>
</a-tooltip> </a-tooltip>
</div> </a-checkbox>
</div>
</div>
<a-checkbox-group :model-value="selectedOtherIds" @change="(value) => handleGroupChange(value, 'other')">
<div v-if="otherList.length" class="mb-[32px]">
<div class="flex flex-row flex-wrap"> <div class="flex flex-row flex-wrap">
<a-checkbox <a-checkbox
v-for="item in otherList" v-for="item in otherList"
@ -82,9 +122,10 @@
</div> </div>
<div> <div>
<div class="optional-header min-w-[270px]"> <div class="optional-header min-w-[270px]">
<div class="font-medium">{{ <div class="font-medium">
props.titleProps?.selectedTitle || t('system.orgTemplate.selectedField') {{ props.titleProps?.selectedTitle || t('system.orgTemplate.selectedField') }}
}}</div> ({{ selectedList.length }})
</div>
<MsButton @click="handleReset">{{ t('system.orgTemplate.clear') }}</MsButton> <MsButton @click="handleReset">{{ t('system.orgTemplate.clear') }}</MsButton>
</div> </div>
<div class="p-[16px]"> <div class="p-[16px]">
@ -110,9 +151,26 @@
</div> </div>
</div> </div>
</div> </div>
<template #title> <div class="footer !ml-[10px] w-[calc(100%-10px)]">
<slot name="title"></slot> <div class="flex items-center">
</template> <slot name="footerLeft"></slot>
</div>
<div class="flex items-center">
<slot name="footerRight">
<a-button type="secondary" :disabled="props.exportLoading" class="mr-[12px]" @click="handleDrawerCancel">
{{ t('common.cancel') }}
</a-button>
<a-button
:loading="props.exportLoading"
type="primary"
:disabled="!selectedList.length"
@click="handleDrawerConfirm"
>
{{ t('common.export') }}
</a-button>
</slot>
</div>
</div>
</MsDrawer> </MsDrawer>
</template> </template>
@ -135,8 +193,6 @@
const { t } = useI18n(); const { t } = useI18n();
const drawerLoading = ref<boolean>(false);
interface MsExportDrawerProps { interface MsExportDrawerProps {
visible: boolean; visible: boolean;
allData: MsExportDrawerMap; allData: MsExportDrawerMap;
@ -150,16 +206,21 @@
systemTitle: string; // | systemTitle: string; // |
selectedTitle: string; // | selectedTitle: string; // |
}; };
disabledCancelKeys?: string[]; //
} }
const props = withDefaults(defineProps<MsExportDrawerProps>(), { const props = withDefaults(defineProps<MsExportDrawerProps>(), {
visible: false, visible: false,
exportLoading: false, exportLoading: false,
defaultSelectedKeys: () => ['name', 'id', 'title', 'status', 'handle_user', 'content'], defaultSelectedKeys: () => ['name', 'id', 'title', 'status', 'handle_user', 'content'],
disabledCancelKeys: () => [],
}); });
const selectedList = ref<MsExportDrawerOption[]>([]); // const selectedList = ref<MsExportDrawerOption[]>([]); //
const selectedIds = ref<string[]>([]); // id
const selectedSystemIds = ref<string[]>([]); // id
const selectedCustomIds = ref<string[]>([]); // id
const selectedOtherIds = ref<string[]>([]); // id
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:visible', value: boolean): void; (e: 'update:visible', value: boolean): void;
@ -240,6 +301,12 @@
return [...systemList.value, ...customList.value, ...otherList.value]; return [...systemList.value, ...customList.value, ...otherList.value];
}); });
const selectSystemIds = computed(() => systemList.value.map((e) => e.key));
const selectCustomIds = computed(() => customList.value.map((e) => e.key));
const selectOtherIds = computed(() => otherList.value.map((e) => e.key));
const handleReset = () => { const handleReset = () => {
selectedList.value = allList.value.filter((item) => props.defaultSelectedKeys.includes(item.key)); selectedList.value = allList.value.filter((item) => props.defaultSelectedKeys.includes(item.key));
}; };
@ -261,11 +328,57 @@
return selectedList.value.length > 0 && selectedList.value.length < allList.value.length; return selectedList.value.length > 0 && selectedList.value.length < allList.value.length;
}); });
//
const isCheckedSystemAll = computed(
() =>
selectedList.value.length > 0 && selectSystemIds.value.every((id) => selectedList.value.some((e) => e.key === id))
);
//
const isCheckedCustomAll = computed(
() =>
selectedList.value.length > 0 && selectCustomIds.value.every((id) => selectedList.value.some((e) => e.key === id))
);
//
const isCheckedOtherAll = computed(() => {
return (
selectedList.value.length > 0 && selectOtherIds.value.every((id) => selectedList.value.some((e) => e.key === id))
);
});
//
const systemIndeterminate = computed(
() =>
selectedList.value.length > 0 &&
selectedList.value.some((e) => selectSystemIds.value.includes(e.key)) &&
!isCheckedSystemAll.value
);
//
const customIndeterminate = computed(
() =>
selectedList.value.length > 0 &&
selectedList.value.some((e) => selectCustomIds.value.includes(e.key)) &&
!isCheckedCustomAll.value
);
//
const otherIndeterminate = computed(() => {
return (
selectedList.value.length > 0 &&
selectedList.value.some((e) => selectOtherIds.value.includes(e.key)) &&
!isCheckedOtherAll.value
);
});
//
const handleChangeAll = (value: boolean | (string | number | boolean)[]) => { const handleChangeAll = (value: boolean | (string | number | boolean)[]) => {
if (value) { if (value) {
selectedList.value = allList.value; selectedList.value = allList.value;
} else { } else {
selectedList.value = []; //
selectedList.value = selectedList.value.filter((e) => props.disabledCancelKeys.includes(e.key));
} }
}; };
@ -273,12 +386,69 @@
selectedList.value = selectedList.value.filter((item) => item.key !== id); selectedList.value = selectedList.value.filter((item) => item.key !== id);
}; };
const handleGroupChange = (value: (string | number | boolean)[]) => { const selectedItemIds = computed(() => [
selectedList.value = allList.value.filter((item) => value.includes(item.key)); ...selectedSystemIds.value,
...selectedCustomIds.value,
...selectedOtherIds.value,
]);
//
function updateSelectedList() {
selectedList.value = allList.value.filter((item) => selectedItemIds.value.includes(item.key));
}
// ids
function getIdsByType(type: string) {
switch (type) {
case 'system':
return selectSystemIds.value;
case 'custom':
return selectCustomIds.value;
case 'other':
return selectOtherIds.value;
default:
return [];
}
}
// ID
function updateSelectedIds(type: string, ids: string[]) {
switch (type) {
case 'system':
selectedSystemIds.value = ids;
break;
case 'custom':
selectedCustomIds.value = ids;
break;
case 'other':
selectedOtherIds.value = ids;
break;
default:
break;
}
updateSelectedList();
}
//
const handleGroupChange = (value: (string | number | boolean)[], type: string) => {
const selectedValue: string[] = value as string[];
updateSelectedIds(type, selectedValue);
}; };
//
function handleChange(value: boolean, type: string) {
//
const ids = value ? getIdsByType(type) : [...props.disabledCancelKeys];
updateSelectedIds(type, ids);
}
watchEffect(() => { watchEffect(() => {
selectedIds.value = selectedList.value.map((item) => item.key); const selectSysIds = selectedList.value.filter((e) => e.columnType === 'system').map((e) => e.key);
const selectCusIds = selectedList.value.filter((e) => e.columnType === 'custom').map((e) => e.key);
const selectOthIds = selectedList.value.filter((e) => e.columnType === 'other').map((e) => e.key);
selectedSystemIds.value = selectSysIds;
selectedCustomIds.value = selectCusIds;
selectedOtherIds.value = selectOthIds;
}); });
watchEffect(() => { watchEffect(() => {
@ -293,7 +463,7 @@
.panel-wrapper { .panel-wrapper {
display: flex; display: flex;
width: 100%; width: 100%;
height: 100%; height: calc(100vh - 112px);
flex-flow: row nowrap; flex-flow: row nowrap;
.inner-wrapper { .inner-wrapper {
display: flex; display: flex;
@ -324,4 +494,11 @@
margin-top: 10px; margin-top: 10px;
margin-right: 20px; margin-right: 20px;
} }
.footer {
@apply flex items-center justify-between;
margin: auto -16px -16px;
padding: 12px 16px;
box-shadow: 0 -1px 4px 0 rgb(31 35 41 / 10%);
}
</style> </style>

View File

@ -127,13 +127,16 @@
v-model:visible="exportVisible" v-model:visible="exportVisible"
:export-loading="exportLoading" :export-loading="exportLoading"
:all-data="exportOptionData" :all-data="exportOptionData"
:disabled-cancel-keys="['name']"
@confirm="exportConfirm" @confirm="exportConfirm"
> >
<template #title> <template #title>
<span class="text-[var(--color-text-1)]">{{ t('bugManagement.exportBug') }}</span> <div>
<span v-if="currentSelectParams.currentSelectCount" class="text-[var(--color-text-4)]" <span class="text-[var(--color-text-1)]">{{ t('bugManagement.exportBug') }}</span>
>({{ t('bugManagement.exportBugCount', { count: currentSelectParams.currentSelectCount }) }})</span <span v-if="currentSelectParams.currentSelectCount" class="text-[var(--color-text-4)]">
> ({{ t('bugManagement.exportBugCount', { count: currentSelectParams.currentSelectCount }) }})
</span>
</div>
</template> </template>
</MsExportDrawer> </MsExportDrawer>
<BugDetailDrawer <BugDetailDrawer