feat(ui): 所有列表页加CSV导出按钮(全量拉取+中文BOM兼容Excel)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ElMessage, type TabPaneName } from 'element-plus'
|
||||
import { Download } from '@element-plus/icons-vue'
|
||||
import { getCalls } from '@/api'
|
||||
import type { CallChannel, PhoneCall } from '@/api/types'
|
||||
import {
|
||||
@@ -12,6 +13,7 @@ import {
|
||||
formatTime,
|
||||
} from '@/utils/format'
|
||||
import { buildCallSections, readField } from '@/utils/callFields'
|
||||
import { exportListToCsv } from '@/utils/csvExport'
|
||||
import VoiceClipModal from '@/components/VoiceClipModal.vue'
|
||||
|
||||
// Calls aren't tied to a messaging channel — `channel` on a call is the call
|
||||
@@ -91,6 +93,38 @@ function onTabChange(_name: TabPaneName): void {
|
||||
load()
|
||||
}
|
||||
|
||||
// ---- header 导出:当前 tab 通话类型全量记录 CSV ----
|
||||
const exporting = ref(false)
|
||||
|
||||
async function exportCalls(): Promise<void> {
|
||||
if (total.value === 0) {
|
||||
ElMessage.warning('当前列表为空,无数据可导出')
|
||||
return
|
||||
}
|
||||
exporting.value = true
|
||||
try {
|
||||
const channel = callType.value
|
||||
const result = await exportListToCsv({
|
||||
fetchPage: (page, pageSize) => getCalls({ channel, page, page_size: pageSize }),
|
||||
columns: [
|
||||
{ key: 'user_id_name', label: '员工', format: (r) => r.user_id_name ?? r.user_id ?? '' },
|
||||
{ key: 'call_number', label: '客户', format: (r) => r.call_number ?? '' },
|
||||
{ key: 'call_status', label: '状态', format: (r) => callStatusLabel(r.call_status, r.channel) },
|
||||
{ key: 'incoming_call', label: '方向', format: (r) => callDirectionLabel(r.incoming_call) },
|
||||
{ key: 'call_duration', label: '通话时长', format: (r) => formatCallDuration(r.call_duration) },
|
||||
{ key: 'start_call_time', label: '通话时间', format: (r) => (r.start_call_time ? formatTime(r.start_call_time) : '') },
|
||||
{ key: 'record', label: '有无录音', format: (r) => (r.record_media_hash || r.record_file ? '有' : '无') },
|
||||
],
|
||||
filename: `${tabs.find((t) => t.value === callType.value)?.label ?? '通话'}记录`,
|
||||
})
|
||||
ElMessage.success(`已导出 ${result.rows} 条`)
|
||||
} catch (e) {
|
||||
ElMessage.error(`导出失败:${(e as Error).message}`)
|
||||
} finally {
|
||||
exporting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前表格要渲染的行。非 voice_call tab 原样返回;voice_call tab 按 voiceScope
|
||||
* 依 isRoom(0=好友, 1=群)做页内过滤。云客 isRoom 可能是 number/string/boolean,
|
||||
@@ -217,6 +251,11 @@ onMounted(load)
|
||||
共 {{ total }} 条 · 类型:{{ tabs.find(t => t.value === callType)?.label }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="yk-calls__actions">
|
||||
<el-button size="small" :loading="exporting" @click="exportCalls">
|
||||
<el-icon><Download /></el-icon> 导出
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-tabs v-model="callType" class="yk-calls__tabs" @tab-change="onTabChange">
|
||||
@@ -490,6 +529,13 @@ onMounted(load)
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.yk-calls__actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.yk-cell__sub {
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
|
||||
Reference in New Issue
Block a user