更新
This commit is contained in:
+126
-18
@@ -1156,9 +1156,19 @@
|
|||||||
class="yeji-leadlines-dialog"
|
class="yeji-leadlines-dialog"
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="yeji-unassigned-dialog__head">
|
<div class="yeji-unassigned-dialog__head yeji-leadlines-dialog__head">
|
||||||
<span class="yeji-unassigned-dialog__title">进线数据明细</span>
|
<div class="yeji-leadlines-dialog__head-main">
|
||||||
<p class="yeji-unassigned-dialog__sub">{{ leadLinesSubtitle }}</p>
|
<span class="yeji-unassigned-dialog__title">进线数据明细</span>
|
||||||
|
<p class="yeji-unassigned-dialog__sub">{{ leadLinesSubtitle }}</p>
|
||||||
|
</div>
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
:loading="leadLinesExporting"
|
||||||
|
:disabled="leadLinesLoading || leadLinesExporting || leadLinesCount <= 0"
|
||||||
|
@click="exportLeadLines"
|
||||||
|
>
|
||||||
|
导出
|
||||||
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<p v-if="leadLinesApiNote" class="yeji-unassigned-dialog__note">{{ leadLinesApiNote }}</p>
|
<p v-if="leadLinesApiNote" class="yeji-unassigned-dialog__note">{{ leadLinesApiNote }}</p>
|
||||||
@@ -1630,6 +1640,7 @@ const revisitBreakdownMeta = ref<{ start: string; end: string; revisitSlot: numb
|
|||||||
|
|
||||||
const leadLinesDialogVisible = ref(false)
|
const leadLinesDialogVisible = ref(false)
|
||||||
const leadLinesLoading = ref(false)
|
const leadLinesLoading = ref(false)
|
||||||
|
const leadLinesExporting = ref(false)
|
||||||
const leadLinesSubtitle = ref('')
|
const leadLinesSubtitle = ref('')
|
||||||
const leadLinesApiNote = ref('')
|
const leadLinesApiNote = ref('')
|
||||||
const leadLinesRows = ref<YejiLeadLineRow[]>([])
|
const leadLinesRows = ref<YejiLeadLineRow[]>([])
|
||||||
@@ -3128,28 +3139,79 @@ function onLeadCountCellClick(ev: MouseEvent, tb: YejiTable, row: YejiRow) {
|
|||||||
void openLeadLinesDialog(tb, row)
|
void openLeadLinesDialog(tb, row)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const LEAD_LINES_EXPORT_COLUMNS: { key: keyof YejiLeadLineRow; label: string }[] = [
|
||||||
|
{ key: 'event_time_text', label: '进线时间' },
|
||||||
|
{ key: 'reception_admin_name', label: '接待' },
|
||||||
|
{ key: 'external_contact_name', label: '客户' },
|
||||||
|
{ key: 'external_userid', label: '外部联系人ID' },
|
||||||
|
{ key: 'user_id', label: '企微成员ID' },
|
||||||
|
{ key: 'state', label: '渠道参数' },
|
||||||
|
]
|
||||||
|
|
||||||
|
function buildLeadLinesRequestParams(
|
||||||
|
ctx: { tb: YejiTable; row: YejiRow },
|
||||||
|
page: number,
|
||||||
|
pageSize: number
|
||||||
|
): Record<string, string | number> {
|
||||||
|
const { tb, row } = ctx
|
||||||
|
const p: Record<string, string | number> = {
|
||||||
|
start_date: tb.start_date,
|
||||||
|
end_date: tb.end_date,
|
||||||
|
dept_id: row.dept_id,
|
||||||
|
page,
|
||||||
|
page_size: pageSize,
|
||||||
|
}
|
||||||
|
if (selectedDeptIds.value.length > 0) {
|
||||||
|
p.dept_ids = selectedDeptIds.value.join(',')
|
||||||
|
}
|
||||||
|
if (selectedChannel.value) {
|
||||||
|
p.channel_code = selectedChannel.value
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeLeadLinesCsvCell(value: unknown): string {
|
||||||
|
const s = value == null ? '' : String(value)
|
||||||
|
if (/[",\n\r]/.test(s)) {
|
||||||
|
return `"${s.replace(/"/g, '""')}"`
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildLeadLinesCsv(rows: YejiLeadLineRow[]): string {
|
||||||
|
const header = LEAD_LINES_EXPORT_COLUMNS.map((c) => escapeLeadLinesCsvCell(c.label)).join(',')
|
||||||
|
const body = rows
|
||||||
|
.map((row) => LEAD_LINES_EXPORT_COLUMNS.map((c) => escapeLeadLinesCsvCell(row[c.key])).join(','))
|
||||||
|
.join('\n')
|
||||||
|
return `\uFEFF${header}\n${body}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function downloadLeadLinesCsv(filename: string, content: string) {
|
||||||
|
const blob = new Blob([content], { type: 'text/csv;charset=utf-8;' })
|
||||||
|
const url = URL.createObjectURL(blob)
|
||||||
|
const anchor = document.createElement('a')
|
||||||
|
anchor.href = url
|
||||||
|
anchor.download = filename
|
||||||
|
anchor.click()
|
||||||
|
URL.revokeObjectURL(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildLeadLinesExportFilename(ctx: { tb: YejiTable; row: YejiRow }): string {
|
||||||
|
const { tb, row } = ctx
|
||||||
|
const safeDept = (row.dept_name || `dept${row.dept_id}`).replace(/[\\/:*?"<>|]/g, '_')
|
||||||
|
return `进线数据明细_${safeDept}_${tb.start_date}_${tb.end_date}.csv`
|
||||||
|
}
|
||||||
|
|
||||||
async function fetchLeadLinesPage() {
|
async function fetchLeadLinesPage() {
|
||||||
const ctx = leadLinesContext.value
|
const ctx = leadLinesContext.value
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const { tb, row } = ctx
|
|
||||||
leadLinesLoading.value = true
|
leadLinesLoading.value = true
|
||||||
try {
|
try {
|
||||||
const p: Record<string, string | number> = {
|
const res: any = await yejiStatsLeadLines(
|
||||||
start_date: tb.start_date,
|
buildLeadLinesRequestParams(ctx, leadLinesPage.value, leadLinesPageSize.value) as any
|
||||||
end_date: tb.end_date,
|
)
|
||||||
dept_id: row.dept_id,
|
|
||||||
page: leadLinesPage.value,
|
|
||||||
page_size: leadLinesPageSize.value,
|
|
||||||
}
|
|
||||||
if (selectedDeptIds.value.length > 0) {
|
|
||||||
p.dept_ids = selectedDeptIds.value.join(',')
|
|
||||||
}
|
|
||||||
if (selectedChannel.value) {
|
|
||||||
p.channel_code = selectedChannel.value
|
|
||||||
}
|
|
||||||
const res: any = await yejiStatsLeadLines(p as any)
|
|
||||||
leadLinesRows.value = Array.isArray(res?.lists) ? res.lists : []
|
leadLinesRows.value = Array.isArray(res?.lists) ? res.lists : []
|
||||||
leadLinesCount.value = Number(res?.count ?? 0)
|
leadLinesCount.value = Number(res?.count ?? 0)
|
||||||
leadLinesApiNote.value = typeof res?.note === 'string' ? res.note : ''
|
leadLinesApiNote.value = typeof res?.note === 'string' ? res.note : ''
|
||||||
@@ -3188,6 +3250,40 @@ function onLeadLinesPageSizeChange(size: number) {
|
|||||||
void fetchLeadLinesPage()
|
void fetchLeadLinesPage()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function exportLeadLines() {
|
||||||
|
const ctx = leadLinesContext.value
|
||||||
|
if (!ctx || leadLinesExporting.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
leadLinesExporting.value = true
|
||||||
|
try {
|
||||||
|
const pageSize = 100
|
||||||
|
const firstRes: any = await yejiStatsLeadLines(buildLeadLinesRequestParams(ctx, 1, pageSize) as any)
|
||||||
|
const total = Number(firstRes?.count ?? 0)
|
||||||
|
if (total <= 0) {
|
||||||
|
ElMessage.warning('暂无进线明细可导出')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const allRows: YejiLeadLineRow[] = Array.isArray(firstRes?.lists) ? [...firstRes.lists] : []
|
||||||
|
const totalPages = Math.ceil(total / pageSize)
|
||||||
|
for (let page = 2; page <= totalPages; page++) {
|
||||||
|
const res: any = await yejiStatsLeadLines(buildLeadLinesRequestParams(ctx, page, pageSize) as any)
|
||||||
|
const lists = Array.isArray(res?.lists) ? res.lists : []
|
||||||
|
allRows.push(...lists)
|
||||||
|
}
|
||||||
|
downloadLeadLinesCsv(buildLeadLinesExportFilename(ctx), buildLeadLinesCsv(allRows))
|
||||||
|
ElMessage.success(`已导出 ${allRows.length} 条进线明细`)
|
||||||
|
} catch (e: unknown) {
|
||||||
|
if (axios.isCancel(e)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const any = e as any
|
||||||
|
ElMessage.error(any?.msg || any?.message || '导出进线明细失败')
|
||||||
|
} finally {
|
||||||
|
leadLinesExporting.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function appointmentLinesIndexMethod(index: number) {
|
function appointmentLinesIndexMethod(index: number) {
|
||||||
return (appointmentLinesPage.value - 1) * appointmentLinesPageSize.value + index + 1
|
return (appointmentLinesPage.value - 1) * appointmentLinesPageSize.value + index + 1
|
||||||
}
|
}
|
||||||
@@ -4914,6 +5010,18 @@ tbody tr.total-row:hover .yeji-lead-cell--link {
|
|||||||
color: color-mix(in srgb, var(--yj-brand, #2563eb) 88%, #000);
|
color: color-mix(in srgb, var(--yj-brand, #2563eb) 88%, #000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.yeji-leadlines-dialog__head {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yeji-leadlines-dialog__head-main {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.yeji-leadlines-dialog__pager {
|
.yeji-leadlines-dialog__pager {
|
||||||
margin-top: 14px;
|
margin-top: 14px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
Reference in New Issue
Block a user