新增功能

This commit is contained in:
Your Name
2026-03-24 16:32:56 +08:00
parent 250d173c2f
commit 9160c36735
248 changed files with 3063 additions and 250 deletions
@@ -934,13 +934,22 @@ class DiagnosisLogic extends BaseLogic
->find();
if ($record) {
$taskId = trim((string)($record['cloud_recording_task_id'] ?? ''));
if ($taskId !== '') {
\app\common\service\TrtcCloudRecordingService::stopRecording(
\app\common\service\TrtcCloudRecordingService::trtcSdkAppId(),
$taskId
);
}
$endTime = time();
$duration = $endTime - $record->start_time;
$record->save([
'status' => 2, // 2-已结束
'end_time' => $endTime,
'duration' => $duration
'duration' => $duration,
'cloud_recording_task_id' => '',
'update_time' => time(),
]);
}
@@ -1019,6 +1028,14 @@ class DiagnosisLogic extends BaseLogic
'update_time' => time(),
]);
$adminId = (int)($params['admin_id'] ?? 0);
if ($adminId > 0) {
self::startCloudRecording([
'diagnosis_id' => $diagnosisId,
'admin_id' => $adminId,
], true);
}
return true;
} catch (\Exception $e) {
self::setError($e->getMessage());
@@ -1026,6 +1043,227 @@ class DiagnosisLogic extends BaseLogic
}
}
/**
* @notes 医生接通并绑定房间后:发起腾讯云云端混流录制(需 CAM 密钥 + 控制台开通录制 + 云点播)
* @param array $params diagnosis_id、admin_id
* @return array|false
*/
/**
* @param bool $silent 为 true 时不写入 BaseLogic 错误(供 bindCallRoom 内自动调用,避免污染绑定接口)
*/
public static function startCloudRecording(array $params, bool $silent = false)
{
try {
$diagnosisId = (int)($params['diagnosis_id'] ?? 0);
$adminId = (int)($params['admin_id'] ?? 0);
if ($diagnosisId <= 0 || $adminId <= 0) {
if (!$silent) {
self::setError('参数错误');
}
return false;
}
$record = \app\common\model\tcm\CallRecord::where('diagnosis_id', $diagnosisId)
->where('caller_id', $adminId)
->where('status', 1)
->order('id', 'desc')
->find();
if (!$record) {
if (!$silent) {
self::setError('没有进行中的通话记录');
}
return false;
}
$roomId = trim((string)($record['room_id'] ?? ''));
if ($roomId === '') {
if (!$silent) {
self::setError('尚未同步房间号,无法开启云端录制');
}
return false;
}
$existingTask = trim((string)($record['cloud_recording_task_id'] ?? ''));
if ($existingTask !== '') {
return [
'started' => true,
'task_id' => $existingTask,
'message' => '已在录制中',
];
}
$prefix = (string)config('trtc.recording_bot_prefix', 'recorder_');
$botUserId = $prefix . $diagnosisId . '_' . (int)$record['id'];
try {
$imService = new \app\common\service\TencentImService();
$imService->importAccount($botUserId, '云端录制');
} catch (\Throwable $e) {
// 导入失败不阻断,部分环境仅 TRTC 亦可进房
}
$botSig = \app\common\service\TrtcCloudRecordingService::makeBotUserSig($botUserId);
$sdkAppId = \app\common\service\TrtcCloudRecordingService::trtcSdkAppId();
$r = \app\common\service\TrtcCloudRecordingService::startMixRecording(
$sdkAppId,
$roomId,
$botUserId,
$botSig
);
if (!$r['ok']) {
return [
'started' => false,
'message' => $r['message'] ?? '开启失败',
];
}
$record->save([
'cloud_recording_task_id' => $r['task_id'],
'recording_status' => 1,
'update_time' => time(),
]);
return [
'started' => true,
'task_id' => $r['task_id'],
'message' => '已发起云端录制',
];
} catch (\Exception $e) {
if (!$silent) {
self::setError($e->getMessage());
}
\think\facade\Log::warning('startCloudRecording: ' . $e->getMessage());
return false;
}
}
/**
* @notes 医生端浏览器本地录制上传后,将文件访问地址合并写入当前诊单下该医生的最近一条通话记录
*/
public static function attachLocalCallRecording(array $params): bool
{
try {
$diagnosisId = (int)($params['diagnosis_id'] ?? 0);
$adminId = (int)($params['admin_id'] ?? 0);
$fileUrl = trim((string)($params['file_url'] ?? ''));
if ($diagnosisId <= 0 || $adminId <= 0 || $fileUrl === '') {
self::setError('参数错误');
return false;
}
$record = \app\common\model\tcm\CallRecord::where('diagnosis_id', $diagnosisId)
->where('caller_id', $adminId)
->order('id', 'desc')
->find();
// 与 startCall 的 caller_id 不一致或竞态时,回退到该诊单最新一条通话记录
if (!$record) {
$record = \app\common\model\tcm\CallRecord::where('diagnosis_id', $diagnosisId)
->order('id', 'desc')
->find();
}
if (!$record) {
self::setError('未找到通话记录');
return false;
}
$prev = [];
if (!empty($record->recording_urls)) {
$prev = json_decode((string)$record->recording_urls, true);
if (!is_array($prev)) {
$prev = [];
}
}
$merged = array_values(array_unique(array_merge($prev, [$fileUrl])));
$record->save([
'recording_urls' => json_encode($merged, JSON_UNESCAPED_UNICODE),
'recording_status' => 2,
'update_time' => time(),
]);
return true;
} catch (\Exception $e) {
self::setError($e->getMessage());
return false;
}
}
/**
* @notes 医助进入当前诊单 TRTC 房间旁观(仅拉流,与医生端 doctor_{id} 账号体系一致)
* @param array $params diagnosis_id、admin_id(当前登录后台用户)
* @return array|false
*/
public static function getAssistantWatchRoomParams(array $params)
{
try {
$diagnosisId = (int)($params['diagnosis_id'] ?? 0);
$adminId = (int)($params['admin_id'] ?? 0);
if ($diagnosisId <= 0 || $adminId <= 0) {
self::setError('参数错误');
return false;
}
$diag = Diagnosis::where('id', $diagnosisId)->where('delete_time', null)->find();
if (!$diag) {
self::setError('诊单不存在');
return false;
}
if ((int)($diag['assistant_id'] ?? 0) !== $adminId) {
self::setError('仅本诊单指派的医助可旁观该通话');
return false;
}
$record = \app\common\model\tcm\CallRecord::where('diagnosis_id', $diagnosisId)
->where('status', 1)
->order('id', 'desc')
->find();
$roomRaw = $record ? trim((string)$record['room_id']) : '';
if ($roomRaw === '') {
self::setError('当前无进行中的通话或尚未同步房间号,请待医生接通后再试');
return false;
}
$config = self::getTrtcConfig();
if (!$config) {
self::setError('请先配置腾讯云TRTC参数');
return false;
}
$doctorUserId = 'doctor_' . $adminId;
self::importDoctorAccountToIm($adminId, $doctorUserId);
$userSig = self::generateUserSig($config['sdkAppId'], $config['secretKey'], $doctorUserId);
if (!$userSig) {
self::setError('生成签名失败');
return false;
}
$payload = [
'sdkAppId' => (int)$config['sdkAppId'],
'userId' => $doctorUserId,
'userSig' => $userSig,
'patientName' => (string)($diag['patient_name'] ?? ''),
];
if (ctype_digit($roomRaw)) {
$payload['roomId'] = (int)$roomRaw;
} else {
$payload['strRoomId'] = $roomRaw;
}
return $payload;
} catch (\Exception $e) {
self::setError($e->getMessage());
return false;
}
}
private static function recordingStatusText(int $status): string
{
$map = [