chengmw
9 days ago 96f4f1ea3a088d315a60c65bae50b5074441bf4c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
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;