支持客户、对话记录与统计报告 CSV 导出
- 新增 /customers/export、/sessions/export、/statistics/export - 沿用列表筛选与角色可见范围,UTF-8 BOM 便于 Excel 打开 - 前端三处导出按钮接入真实下载
This commit is contained in:
+35
-1
@@ -1,4 +1,4 @@
|
||||
import { get, post, put, del, getList, postForm } from './request'
|
||||
import { get, post, put, del, getList, postForm, downloadFile } from './request'
|
||||
|
||||
export interface LoginParams { username: string; password: string }
|
||||
export interface LoginResult { token: string; user_id: number; tenant_id: number; nickname: string; role: string }
|
||||
@@ -253,6 +253,40 @@ export const getCustomers = (params?: { search?: string; status?: string; source
|
||||
if (params?.pageSize) search.set('pageSize', String(params.pageSize))
|
||||
return getList<Customer>(`/customers?${search}`)
|
||||
}
|
||||
|
||||
export const exportCustomersCSV = (params?: { search?: string; status?: string; source?: string }) => {
|
||||
const search = new URLSearchParams()
|
||||
if (params?.search) search.set('search', params.search)
|
||||
if (params?.status) search.set('status', params.status)
|
||||
if (params?.source) search.set('source', params.source)
|
||||
const qs = search.toString()
|
||||
return downloadFile(`/customers/export${qs ? `?${qs}` : ''}`, `customers_${Date.now()}.csv`)
|
||||
}
|
||||
|
||||
export const exportSessionsCSV = (params?: {
|
||||
status?: string
|
||||
priority?: string
|
||||
agent_id?: number | string
|
||||
channel_id?: number | string
|
||||
search?: string
|
||||
from?: string
|
||||
to?: string
|
||||
}) => {
|
||||
const search = new URLSearchParams()
|
||||
if (params?.status) search.set('status', params.status)
|
||||
if (params?.priority) search.set('priority', params.priority)
|
||||
if (params?.agent_id != null && params.agent_id !== '') search.set('agent_id', String(params.agent_id))
|
||||
if (params?.channel_id != null && params.channel_id !== '') search.set('channel_id', String(params.channel_id))
|
||||
if (params?.search) search.set('search', params.search)
|
||||
if (params?.from) search.set('from', params.from)
|
||||
if (params?.to) search.set('to', params.to)
|
||||
const qs = search.toString()
|
||||
return downloadFile(`/sessions/export${qs ? `?${qs}` : ''}`, `sessions_${Date.now()}.csv`)
|
||||
}
|
||||
|
||||
export const exportStatisticsCSV = () =>
|
||||
downloadFile('/statistics/export', `statistics_${Date.now()}.csv`)
|
||||
|
||||
export const getCustomer = (id: number) => get<{ customer: Customer; sessions: Session[] }>(`/customers/${id}`)
|
||||
export const createCustomer = (data: Partial<Customer>) => post<Customer>('/customers', data)
|
||||
export const updateCustomer = (id: number, data: Partial<Customer>) => put<Customer>(`/customers/${id}`, data)
|
||||
|
||||
@@ -53,3 +53,38 @@ export const getList = <T>(url: string) => request<ListResponse<T>>(url)
|
||||
export const postForm = <T>(url: string, form: FormData) =>
|
||||
request<Response<T>>(url, { method: 'POST', body: form })
|
||||
|
||||
/** 下载 CSV 等二进制响应(带鉴权) */
|
||||
export async function downloadFile(path: string, fallbackName: string) {
|
||||
const headers: Record<string, string> = {}
|
||||
if (token) headers.Authorization = `Bearer ${token}`
|
||||
const res = await fetch(`${BASE}${path}`, { headers })
|
||||
const ct = res.headers.get('Content-Type') || ''
|
||||
if (!res.ok || ct.includes('application/json')) {
|
||||
let msg = '导出失败'
|
||||
try {
|
||||
const json = await res.json()
|
||||
if (json?.message) msg = json.message
|
||||
} catch { /* ignore */ }
|
||||
throw new Error(msg)
|
||||
}
|
||||
const blob = await res.blob()
|
||||
let filename = fallbackName
|
||||
const cd = res.headers.get('Content-Disposition') || ''
|
||||
const m = /filename\*=UTF-8''([^;]+)|filename="?([^";]+)"?/i.exec(cd)
|
||||
if (m) {
|
||||
try {
|
||||
filename = decodeURIComponent(m[1] || m[2])
|
||||
} catch {
|
||||
filename = m[1] || m[2] || fallbackName
|
||||
}
|
||||
}
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = filename
|
||||
document.body.appendChild(a)
|
||||
a.click()
|
||||
a.remove()
|
||||
URL.revokeObjectURL(url)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user