65 lines
2.5 KiB
TypeScript
65 lines
2.5 KiB
TypeScript
|
|
// АРМ курсанта: приём вызова и разговор голосом.
|
|||
|
|
// Карточка КИО — lct-10, таймеры — lct-11.
|
|||
|
|
|
|||
|
|
import { useCall } from "@/features/call/useCall";
|
|||
|
|
import { sessionIdFromUrl } from "@/shared/api/session";
|
|||
|
|
|
|||
|
|
const STATUS_LABEL: Record<string, string> = {
|
|||
|
|
connecting: "подключение",
|
|||
|
|
open: "на связи",
|
|||
|
|
reconnecting: "связь потеряна, переподключение",
|
|||
|
|
closed: "отключено",
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
export function Call() {
|
|||
|
|
const sessionId = sessionIdFromUrl();
|
|||
|
|
const call = useCall(sessionId);
|
|||
|
|
|
|||
|
|
if (!sessionId) {
|
|||
|
|
return (
|
|||
|
|
<main className="page">
|
|||
|
|
<h1>АРМ курсанта</h1>
|
|||
|
|
<p className="warn">В адресе нет номера занятия: откройте ссылку вида /trainee?session=…</p>
|
|||
|
|
</main>
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<main className="page">
|
|||
|
|
<h1>АРМ оператора 112</h1>
|
|||
|
|
<table className="grid">
|
|||
|
|
<tbody>
|
|||
|
|
<tr><th>Канал</th><td className={call.status === "open" ? "" : "warn"}>{STATUS_LABEL[call.status]}</td></tr>
|
|||
|
|
<tr><th>Вызов</th><td>{call.incoming ? `${call.incoming.caller_number} · сценарий ${call.incoming.scenario_id} · режим ${call.incoming.mode}` : "ожидание"}</td></tr>
|
|||
|
|
<tr><th>Гарнитура</th><td>{call.micOn ? "микрофон включён" : "выключен"}</td></tr>
|
|||
|
|
<tr><th>Звонящий</th><td>{call.callerSpeaking ? "говорит" : "молчит"}</td></tr>
|
|||
|
|
</tbody>
|
|||
|
|
</table>
|
|||
|
|
|
|||
|
|
<p>
|
|||
|
|
{call.phase === "incoming" && !call.micOn && (
|
|||
|
|
<button type="button" onClick={() => void call.answer()}>Ответить</button>
|
|||
|
|
)}
|
|||
|
|
{call.micOn && <button type="button" onClick={call.hangup}>Завершить вызов</button>}{" "}
|
|||
|
|
{call.micOn && call.incoming?.mode !== "exam" && (
|
|||
|
|
<button type="button" onClick={call.hint}>Подсказка</button>
|
|||
|
|
)}
|
|||
|
|
</p>
|
|||
|
|
|
|||
|
|
{call.error && <p className="violated">{call.error}</p>}
|
|||
|
|
|
|||
|
|
<h2>Разговор</h2>
|
|||
|
|
<table className="grid">
|
|||
|
|
<tbody>
|
|||
|
|
{call.lines.map((line, index) => (
|
|||
|
|
<tr key={index}>
|
|||
|
|
<th>{line.speaker === "caller" ? "звонящий" : "оператор"}</th>
|
|||
|
|
<td className={line.partial ? "warn" : ""}>{line.text}</td>
|
|||
|
|
</tr>
|
|||
|
|
))}
|
|||
|
|
{call.lines.length === 0 && <tr><td colSpan={2}>—</td></tr>}
|
|||
|
|
</tbody>
|
|||
|
|
</table>
|
|||
|
|
</main>
|
|||
|
|
);
|
|||
|
|
}
|