feat(web-admin): add ListExportDropdown and Excel blob download helper
Support filtered-result primary action and optional export-selected menu. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
eb4233f23f
commit
3643a3b14e
2 files changed
+185
No files matched your search
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<div v-if="hasSelection" class="list-export-dropdown">
|
||||
<el-button
|
||||
class="btn-ghost list-export-dropdown__main"
|
||||
:disabled="disabled"
|
||||
:loading="exporting"
|
||||
@click="handleExportFiltered"
|
||||
>
|
||||
<el-icon><Download /></el-icon>
|
||||
导出筛选结果
|
||||
</el-button>
|
||||
<el-dropdown
|
||||
trigger="click"
|
||||
:disabled="disabled || exporting"
|
||||
@command="handleCommand"
|
||||
>
|
||||
<el-button class="btn-ghost list-export-dropdown__caret" :disabled="disabled || exporting">
|
||||
<el-icon><ArrowDown /></el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="selected" :disabled="!selectedIds?.length">
|
||||
导出已选
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
|
||||
<el-button
|
||||
v-else
|
||||
class="btn-ghost"
|
||||
:disabled="disabled"
|
||||
:loading="exporting"
|
||||
@click="handleExportFiltered"
|
||||
>
|
||||
<el-icon><Download /></el-icon>
|
||||
导出
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { ArrowDown, Download } from '@element-plus/icons-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import {
|
||||
filenameFromContentDisposition,
|
||||
pickBlobFromExportResponse,
|
||||
triggerBlobDownload
|
||||
} from '@/utils/list-export-download'
|
||||
|
||||
defineOptions({ name: 'ListExportDropdown' })
|
||||
|
||||
export type ListExportPayload = Record<string, any> & {
|
||||
ids?: string[]
|
||||
columns?: string[]
|
||||
}
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
exportFn: (payload: ListExportPayload) => Promise<any>
|
||||
getFilterParams: () => Record<string, any>
|
||||
selectedIds?: string[]
|
||||
hasSelection?: boolean
|
||||
visibleColumns?: string[]
|
||||
filename?: string
|
||||
disabled?: boolean
|
||||
}>(),
|
||||
{
|
||||
selectedIds: () => [],
|
||||
hasSelection: false,
|
||||
visibleColumns: undefined,
|
||||
filename: '导出.xlsx',
|
||||
disabled: false
|
||||
}
|
||||
)
|
||||
|
||||
const exporting = ref(false)
|
||||
|
||||
function buildPayload(withIds: boolean): ListExportPayload {
|
||||
const payload: ListExportPayload = { ...props.getFilterParams() }
|
||||
if (props.visibleColumns?.length) {
|
||||
payload.columns = [...props.visibleColumns]
|
||||
}
|
||||
if (withIds) {
|
||||
payload.ids = [...(props.selectedIds || [])]
|
||||
}
|
||||
return payload
|
||||
}
|
||||
|
||||
async function runExport(withIds: boolean) {
|
||||
if (exporting.value || props.disabled) return
|
||||
if (withIds && !(props.selectedIds?.length > 0)) return
|
||||
exporting.value = true
|
||||
try {
|
||||
const res = await props.exportFn(buildPayload(withIds))
|
||||
const { blob, filenameHeader } = pickBlobFromExportResponse(res)
|
||||
const name = filenameFromContentDisposition(filenameHeader, props.filename)
|
||||
triggerBlobDownload(blob, name)
|
||||
ElMessage.success('导出成功')
|
||||
} catch (e: any) {
|
||||
const msg = e?.message || e?.msg || '导出失败'
|
||||
ElMessage.error(msg)
|
||||
} finally {
|
||||
exporting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleExportFiltered() {
|
||||
void runExport(false)
|
||||
}
|
||||
|
||||
function handleCommand(cmd: string) {
|
||||
if (cmd === 'selected') void runExport(true)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.list-export-dropdown {
|
||||
display: inline-flex;
|
||||
align-items: stretch;
|
||||
vertical-align: middle;
|
||||
|
||||
:deep(.el-button) {
|
||||
.el-icon + span,
|
||||
span + .el-icon {
|
||||
margin-left: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list-export-dropdown__main {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
margin-right: -1px;
|
||||
}
|
||||
|
||||
.list-export-dropdown__caret {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
min-width: 36px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user