import React, { useState, useEffect } from 'react';
|
import { Modal, Spin, Button, message } from 'antd';
|
import { ReloadOutlined } from '@ant-design/icons';
|
import OutboundBotAPIService from '../../services/OutboundBotAPIService';
|
import AudioPlayer from './AudioPlayer';
|
import ConversationList from './ConversationList';
|
import './CallRecordModal.css';
|
|
// 已接通状态值(数字格式)
|
const CONNECTED_STATUSES_NUM = [1, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31];
|
// 已接通状态值(字符串格式,如API返回"Succeeded")
|
const CONNECTED_STATUSES_STR = ['Succeeded', 'succeeded', 'Success', 'success'];
|
|
/**
|
* 判断是否为已接通状态
|
* 兼容数字和字符串两种状态格式
|
*/
|
const isConnectedStatus = (callStatus) => {
|
if (callStatus === null || callStatus === undefined) return false;
|
// 如果是数字
|
if (typeof callStatus === 'number') {
|
return CONNECTED_STATUSES_NUM.includes(callStatus);
|
}
|
// 如果是字符串(可能是"Succeeded"等)
|
if (typeof callStatus === 'string') {
|
return CONNECTED_STATUSES_STR.includes(callStatus);
|
}
|
return false;
|
};
|
|
/**
|
* 获取caseId
|
*/
|
const getCaseId = () => {
|
// 优先从URL参数获取
|
const urlParams = new URLSearchParams(window.location.search);
|
const caseIdFromUrl = urlParams.get('caseId');
|
if (caseIdFromUrl) return caseIdFromUrl;
|
|
// 从localStorage获取
|
try {
|
const timelineData = localStorage.getItem('case_data_timeline');
|
if (timelineData) {
|
const parsed = JSON.parse(timelineData);
|
return parsed.case_id || null;
|
}
|
} catch (e) {
|
console.error('解析localStorage数据失败:', e);
|
}
|
return null;
|
};
|
|
/**
|
* 解析conversations JSON字符串
|
*/
|
const parseConversations = (conversationsStr) => {
|
if (!conversationsStr) return [];
|
try {
|
return JSON.parse(conversationsStr);
|
} catch (e) {
|
console.error('解析对话记录失败:', e);
|
return [];
|
}
|
};
|
|
/**
|
* 通话记录弹窗组件
|
*/
|
const CallRecordModal = ({ visible, onClose, record }) => {
|
const [loading, setLoading] = useState(false);
|
const [error, setError] = useState(null);
|
const [callData, setCallData] = useState(null);
|
const [audioBlob, setAudioBlob] = useState(null);
|
const [audioLoading, setAudioLoading] = useState(false);
|
|
// 获取通话记录数据
|
const fetchCallRecord = async () => {
|
if (!record) return;
|
|
setLoading(true);
|
setError(null);
|
setAudioBlob(null);
|
|
try {
|
const caseId = getCaseId();
|
if (!caseId) {
|
throw new Error('未找到案件ID');
|
}
|
|
const params = {
|
caseId,
|
personId: record.person_id,
|
jobId: record.job_id
|
};
|
|
const response = await OutboundBotAPIService.getConversationLog(params);
|
|
if (response && response.data && response.data.length > 0) {
|
// 取最后一条记录
|
const lastRecord = response.data[response.data.length - 1];
|
console.log('📞 通话记录数据:', lastRecord);
|
console.log('📞 callStatus值:', lastRecord.callStatus, '类型:', typeof lastRecord.callStatus);
|
setCallData(lastRecord);
|
|
// 如果有recordUrl,加载音频文件
|
const recordUrl = lastRecord.record_url || lastRecord.recordUrl;
|
if (recordUrl) {
|
loadAudioFile(recordUrl);
|
}
|
} else {
|
throw new Error('未找到通话记录');
|
}
|
} catch (err) {
|
console.error('获取通话记录失败:', err);
|
setError(err.message || '获取通话记录失败');
|
} finally {
|
setLoading(false);
|
}
|
};
|
|
// 加载音频文件
|
const loadAudioFile = async (recordUrl) => {
|
setAudioLoading(true);
|
try {
|
const blob = await OutboundBotAPIService.getAudioFile(recordUrl);
|
setAudioBlob(blob);
|
} catch (err) {
|
console.error('加载音频文件失败:', err);
|
message.error('加载录音文件失败');
|
} finally {
|
setAudioLoading(false);
|
}
|
};
|
|
// 弹窗打开时加载数据
|
useEffect(() => {
|
if (visible && record) {
|
fetchCallRecord();
|
}
|
}, [visible, record]);
|
|
// 关闭弹窗时重置状态
|
useEffect(() => {
|
if (!visible) {
|
setCallData(null);
|
setError(null);
|
setAudioBlob(null);
|
}
|
}, [visible]);
|
|
// 生成弹窗标题
|
const getModalTitle = () => {
|
if (!record) return '通话记录';
|
const creatorName = record.creator || '当事人';
|
return `AI调解员与${creatorName}的通话`;
|
};
|
|
// 渲染加载状态
|
const renderLoading = () => (
|
<div className="modal-loading">
|
<Spin tip="加载中..." />
|
</div>
|
);
|
|
// 渲染错误状态
|
const renderError = () => (
|
<div className="modal-error">
|
<p className="error-text">{error}</p>
|
<Button
|
type="primary"
|
icon={<ReloadOutlined />}
|
onClick={fetchCallRecord}
|
>
|
重试
|
</Button>
|
</div>
|
);
|
|
// 渲染未接通状态
|
const renderNotConnected = () => (
|
<div className="modal-not-connected">
|
<p>未接通,无通话记录</p>
|
</div>
|
);
|
|
// 渲染通话记录内容
|
const renderContent = () => {
|
if (!callData) {
|
console.log('📞 renderContent: callData为空');
|
return renderNotConnected();
|
}
|
|
const callStatus = callData.call_status ?? callData.callStatus;
|
console.log('📞 renderContent: callStatus=', callStatus, 'isConnected=', isConnectedStatus(callStatus));
|
|
// 未接通状态
|
if (!isConnectedStatus(callStatus)) {
|
return renderNotConnected();
|
}
|
|
// 已接通状态
|
const conversations = parseConversations(callData.conversations);
|
const recordUrl = callData.record_url || callData.recordUrl;
|
const creatorName = record?.creator || '当事人';
|
|
return (
|
<div className="modal-content">
|
{/* 录音播放器 - 根据recordUrl和audioLoading状态显示 */}
|
<AudioPlayer
|
recordUrl={recordUrl}
|
audioBlob={audioBlob}
|
loading={audioLoading}
|
loadingText="正在加载录音..."
|
/>
|
|
{/* 对话记录列表 */}
|
<ConversationList
|
conversations={conversations}
|
contactName={creatorName}
|
/>
|
</div>
|
);
|
};
|
|
return (
|
<Modal
|
className="call-record-modal"
|
title={getModalTitle()}
|
open={visible}
|
onCancel={onClose}
|
footer={null}
|
width={600}
|
centered
|
destroyOnClose
|
>
|
{loading && renderLoading()}
|
{!loading && error && renderError()}
|
{!loading && !error && renderContent()}
|
</Modal>
|
);
|
};
|
|
export default CallRecordModal;
|