feat(calls): 前端录音播放本地优先(/api/media/{hash}) + OSS 回退 + drawer

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
浅念
2026-08-07 16:55:49 +08:00
parent 1578db3467
commit 05cc1dfcc4
3 changed files with 17 additions and 6 deletions
+2
View File
@@ -136,6 +136,8 @@ export interface PhoneCall {
sim_phone?: string | null
/** OSS URL of the recording — present only when a recording exists. */
record_file?: string | null
/** sha256 media_hash of the localized recording (NULL until downloaded). */
record_media_hash?: string | null
/**
* Verbatim upstream call record (camelCase keys: id/startCallTime,
* callDuration/callSeconds/ringTime, callStatus/incomingCall, userId/
+8
View File
@@ -211,6 +211,14 @@ export function toDisplayField(c: PhoneCall, camelKey: string): DisplayField {
if (value === null || value === undefined || value === '') {
return { key: camelKey, label, value, render: 'empty', text: '' }
}
// 录音:优先本地化的 media_hash(/api/media/{hash}),否则原 OSS URL
if (camelKey === 'recordFile') {
const local = c.record_media_hash ? `/api/media/${c.record_media_hash}` : null
const url = local ?? (typeof value === 'string' && value ? value : null)
if (url) {
return { key: camelKey, label, value: url, render: 'audio', text: '' }
}
}
if (AUDIO_KEYS.has(camelKey) && typeof value === 'string') {
return { key: camelKey, label, value, render: 'audio', text: '' }
}
+7 -6
View File
@@ -90,10 +90,11 @@ function timeCell(row: PhoneCall, camelKey: string): number | undefined {
}
function playRecord(row: PhoneCall): void {
const local = row.record_media_hash ? `/api/media/${row.record_media_hash}` : null
const file =
(typeof cell(row, 'recordFile') === 'string'
? (cell(row, 'recordFile') as string)
: null) ?? row.record_file
local ??
(typeof cell(row, 'recordFile') === 'string' ? (cell(row, 'recordFile') as string) : null) ??
row.record_file
if (!file) {
ElMessage.info('该通话无录音文件')
return
@@ -185,7 +186,7 @@ onMounted(load)
</el-table-column>
<el-table-column label="通话录音" width="110" align="center">
<template #default="{ row }">
<el-button v-if="row.record_file || cell(row, 'recordFile')" size="small" type="primary" link @click.stop="playRecord(row)">播放</el-button>
<el-button v-if="row.record_media_hash || row.record_file || cell(row, 'recordFile')" size="small" type="primary" link @click.stop="playRecord(row)">播放</el-button>
<span v-else style="color:#c0c4cc">--</span>
</template>
</el-table-column>
@@ -215,7 +216,7 @@ onMounted(load)
<el-table-column label="通话时间和录音" min-width="180">
<template #default="{ row }">
<div>{{ formatTime(row.start_call_time) }}</div>
<el-button v-if="row.record_file || cell(row, 'ossFileName')" size="small" type="primary" link @click.stop="playRecord(row)" style="margin-top:2px">播放录音</el-button>
<el-button v-if="row.record_media_hash || row.record_file || cell(row, 'ossFileName')" size="small" type="primary" link @click.stop="playRecord(row)" style="margin-top:2px">播放录音</el-button>
<span v-else class="yk-cell__sub">无录音</span>
</template>
</el-table-column>
@@ -251,7 +252,7 @@ onMounted(load)
<el-table-column label="录音" width="100" align="center">
<template #default="{ row }">
<el-button
v-if="row.record_file || cell(row, 'recordFile')"
v-if="row.record_media_hash || row.record_file || cell(row, 'recordFile')"
size="small"
type="primary"
link