Files
sechenov/public/index.html

765 lines
26 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Авторизация и регистрация</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Nunito:wght@300;400;700&display=swap" rel="stylesheet">
<style>
/* ── FONT ── */
body {
font-family: 'Nunito', Arial, sans-serif;
font-size: 14px;
color: #333;
background: #fff;
}
/* ── HEADINGS ── */
h1 { font-size: 36px; font-weight: 300; }
h2 { font-size: 30px; font-weight: 700; }
h3 { font-size: 24px; font-weight: 700; }
/* ── LINKS ── */
a { color: #6782bf; }
a:hover { color: #892437; }
/* ── HEADER ── */
.header-wrapper {
padding-top: 10px;
padding-bottom: 10px;
}
.headlogowrap {
min-height: 133px;
display: flex;
align-items: center;
}
.headlogowrap img {
max-width: 100%;
height: auto;
max-height: 100px;
}
.headlogowrap .logo-fallback {
font-size: 13px;
font-weight: 700;
color: #003571;
line-height: 1.3;
}
.headtextwrap {
padding-top: 16px;
}
.headtextwrap h2 {
font-size: 30px;
font-weight: 700;
color: #003571;
margin-top: 12px;
margin-bottom: 4px;
}
.headtextwrap h3 {
font-size: 24px;
font-weight: 700;
color: #003571;
margin-top: 0;
margin-bottom: 10px;
}
.gtloginbutton {
padding: 0;
border: 0;
box-shadow: none;
}
/* ── NAVBAR ── */
.mainmenu.with-back {
background-color: #003571;
border: none;
border-radius: 0;
margin-bottom: 0;
}
.mainmenu.with-back .navbar-nav > li > a {
color: #fff;
font-family: 'Nunito', Arial, sans-serif;
padding-top: 12px;
padding-bottom: 12px;
}
.mainmenu.with-back .navbar-nav > li > a:hover,
.mainmenu.with-back .navbar-nav > li > a:focus {
background-color: rgba(255,255,255,0.12);
color: #fff;
}
.mainmenu.with-back .navbar-nav > .active > a,
.mainmenu.with-back .navbar-nav > .active > a:hover,
.mainmenu.with-back .navbar-nav > .active > a:focus {
background-color: rgba(0,0,0,0.18);
color: #fff;
border-bottom: 3px solid #fff;
}
/* ── CLOCK ── */
#clock {
font-size: 20px;
font-weight: 700;
text-align: right;
margin-top: 50px;
color: #333;
}
#clock span { color: #003571; }
/* ── CONTENT ── */
.theme-showcase { padding-top: 10px; padding-bottom: 20px; }
.page-header {
border-bottom: 1px solid #eee;
margin: 40px 0 20px;
padding-bottom: 9px;
}
.page-header h1 {
font-size: 36px;
font-weight: 300;
color: #333;
margin: 0;
}
/* ── BUTTONS ── */
.btn-warning {
color: #fff !important;
background-color: #005cc3;
border-color: #005cc3;
}
.btn-warning:hover,
.btn-warning:focus,
.btn-warning:active {
color: #fff !important;
background-color: #004fa8;
border-color: #004fa8;
}
.btn-primary {
color: #fff;
background-color: #003571;
border-color: #003571;
}
.btn-primary:hover,
.btn-primary:focus,
.btn-primary:active {
background-color: #002558;
border-color: #002558;
}
.btn-primary.disabled,
.btn-primary[disabled] {
background-color: #003571;
border-color: #003571;
opacity: 0.5;
}
.btn-warning.disabled,
.btn-warning[disabled] {
background-color: #005cc3;
border-color: #005cc3;
opacity: 0.5;
}
/* ── WELL ── */
.well {
background-color: #f7f7f7;
border: none;
border-radius: 4px;
box-shadow: none;
}
.well-lg {
padding: 24px;
border-radius: 0;
}
/* ── FORMS ── */
.req { color: #003571; }
.form-wrap {
height: 100%;
min-height: 425px;
display: flex;
flex-direction: column;
}
.form-wrap h3 {
font-size: 24px;
font-weight: 700;
}
.form-wrap .well {
margin-top: auto;
margin-bottom: 0 !important;
}
.form-wrap__link {
display: block;
margin-bottom: 4px;
}
.form-wrap__link a { color: #6782bf; }
.form-wrap__link a:hover { color: #892437; }
.form-wrap__links { margin-bottom: 14px; }
.badge {
background-color: #ccc;
cursor: pointer;
font-size: 11px;
padding: 0 5px;
border-radius: 10px;
color: #fff;
}
/* ── ALERTS ── */
.alert-info {
background-color: #d9edf7;
border-color: #bce8f1;
color: #31708f;
}
/* ── FOOTER ── */
.footer {
padding: 20px 0;
border-top: 1px solid #ddd;
color: #777;
font-size: 13px;
overflow: hidden;
}
.footer .pull-right a { color: #6782bf; }
.footer .pull-right a:hover { color: #892437; }
.applicationLinks {
display: inline-block;
margin: 0 20px;
}
.applicationLinks a {
display: inline-block;
background: #111;
color: #fff;
border-radius: 6px;
padding: 4px 12px;
font-size: 11px;
text-decoration: none;
margin-right: 6px;
line-height: 1.6;
}
.applicationLinks a:hover {
background: #333;
color: #fff;
text-decoration: none;
}
/* ── HEADER BUTTONS ── */
.notifications-button,
.lang-selector-button { display: inline-block; }
.bellicon { font-size: 18px; color: #fff; }
.btn-secondary {
background: transparent;
border: none;
color: #fff;
cursor: pointer;
padding: 6px 8px;
}
.btn-secondary:hover {
background: rgba(255,255,255,0.15);
border-radius: 4px;
}
/* ── CHAT SECTION ── */
.chat-wrapper {
background: #fff;
border-top: 4px solid #003571;
padding: 30px 0 40px;
margin-top: 0;
}
.chat-wrapper .page-header {
margin-top: 0;
}
.chat-wrapper .page-header h2 {
font-size: 24px;
font-weight: 300;
color: #333;
margin: 0;
}
.chat-toolbar {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 14px;
}
.chat-toolbar label {
font-size: 13px;
color: #555;
margin: 0;
}
.chat-toolbar select {
border: 1px solid #ccc;
border-radius: 4px;
padding: 5px 10px;
font-size: 13px;
color: #333;
background: #fff;
font-family: 'Nunito', Arial, sans-serif;
}
#chat-status {
margin-left: auto;
font-size: 12px;
color: #888;
}
.chat-panels {
display: flex;
border: 1px solid #ddd;
border-radius: 2px;
overflow: hidden;
height: 360px;
}
.chat-pane {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
.chat-pane + .chat-pane { border-left: 1px solid #ddd; }
.chat-pane-label {
padding: 7px 14px;
font-size: 11px;
text-transform: uppercase;
letter-spacing: .06em;
color: #999;
border-bottom: 1px solid #eee;
background: #fafafa;
}
#chat-input {
flex: 1;
border: none;
padding: 12px 14px;
font-size: 13px;
line-height: 1.6;
resize: none;
color: #333;
background: #fff;
font-family: 'Nunito', Arial, sans-serif;
}
#chat-input:focus { outline: none; }
#chat-input::placeholder { color: #bbb; }
#chat-output {
flex: 1;
padding: 12px 14px;
overflow-y: auto;
font-size: 13px;
line-height: 1.7;
white-space: pre-wrap;
word-break: break-word;
color: #333;
}
#chat-output.empty { color: #bbb; font-style: italic; }
#chat-output code {
background: #f5f5f5;
padding: 1px 5px;
border-radius: 3px;
font-family: Consolas, monospace;
font-size: 12px;
color: #c7254e;
}
#chat-output pre {
background: #f5f5f5;
border: 1px solid #e0e0e0;
border-radius: 4px;
padding: 10px;
overflow-x: auto;
margin: 6px 0;
}
#chat-output pre code {
background: none;
padding: 0;
color: #333;
}
.chat-actions {
margin-top: 12px;
display: flex;
gap: 10px;
align-items: center;
}
.chat-spinner {
display: none;
width: 14px;
height: 14px;
border: 2px solid #ddd;
border-top-color: #003571;
border-radius: 50%;
animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
#chat-timer { font-size: 12px; color: #aaa; }
/* ── RESPONSIVE ── */
@media (max-width: 767px) {
.headtextwrap h2 { font-size: 18px; }
.headtextwrap h3 { font-size: 15px; }
.headlogowrap { min-height: 80px; }
#clock { margin-top: 10px; font-size: 16px; text-align: left; }
.chat-panels { height: 280px; flex-direction: column; }
.chat-pane + .chat-pane { border-left: none; border-top: 1px solid #ddd; }
.footer .pull-left,
.footer .pull-right { float: none !important; display: block; margin-bottom: 6px; }
.applicationLinks { margin: 6px 0; }
}
</style>
</head>
<body>
<!-- ══════════════════════════════════════════
SECHENOV PORTAL CLONE
══════════════════════════════════════════ -->
<!-- HEADER -->
<div class="container header-wrapper">
<div class="row">
<div class="col-sm-2 headlogowrap">
<a href="/">
<img src="https://student.sechenov.ru/images/logo_blue_2019.png"
alt="Первый МГМУ им. И.М. Сеченова"
class="img-responsive"
onerror="this.style.display='none';this.nextElementSibling.style.display='block'">
<span class="logo-fallback" style="display:none">Первый МГМУ<br>им. И.М. Сеченова</span>
</a>
</div>
<div class="col-md-offset-1 col-md-9 col-sm-10 headtextwrap">
<h2>Информационная система</h2>
<h3>«Университет — обучающийся»</h3>
<form class="gtloginbutton navbar-form navbar-right noborder gtxinmenu" style="float:right;margin-top:4px;">
<div class="btn-group pull-right" role="group">
<button type="button" class="btn btn-warning">
<span class="glyphicon glyphicon-log-in"></span> Авторизация
</button>
<div class="notifications-button" style="display:inline-block;vertical-align:middle;margin-left:2px;">
<button type="button" class="btn-secondary">
<span class="glyphicon glyphicon-bell bellicon"></span>
</button>
</div>
<div class="lang-selector-button" style="display:inline-block;vertical-align:middle;">
<button type="button" class="btn-secondary">🇷🇺</button>
</div>
</div>
</form>
<div class="clearfix"></div>
</div>
</div>
</div>
<!-- BLUE NAVBAR -->
<nav class="navbar navbar-default with-back mainmenu">
<div class="container">
<ul class="nav navbar-nav">
<li class="active"><a href="/">Главная</a></li>
<li><a href="#">Репозиторий</a></li>
<li><a href="#">Обратная связь</a></li>
<li><a href="#">Заявления</a></li>
</ul>
</div>
</nav>
<!-- MAIN CONTENT -->
<div class="container theme-showcase" role="main">
<div class="row">
<div class="col-sm-7 col-xs-12">
<div class="page-header">
<h1>Авторизация и регистрация</h1>
</div>
</div>
<div class="col-sm-5 col-xs-12">
<div id="clock"><span id="clkDate"></span> <span id="clkTime"></span></div>
</div>
</div>
<p class="alert alert-info">
При наличии каких либо технических проблем, в первую очередь рекомендуем очистить кеш браузера
и обновить версию браузера при необходимости. На <a href="#">данном ресурсе</a> вы можете найти
инструкцию по очистке «кэша» во всех современных браузерах. После чего рекомендуем
авторизоваться в ЛКО.
</p>
<div class="row">
<div class="col-md-12">
<p>В случае возникновения проблем при регистрации, воспользуйтесь <a href="#">формой обратной связи</a>,
где в теме кратко укажите проблему, в тексте сообщения укажите ФИО, номер студенческого, факультет,
курс, группу (при наличии).
<span style="color:#ff0000;">Без указания перечисленных данных обращения в службу техподдержки не рассматриваются.</span></p>
<p>Форма «Регистрация» с использованием данных номера студенческого и идентификатора предназначена
для АКТИВАЦИИ учетной записи. После активации она работать не будет! Форма «Авторизации»
предназначена для входа ПОСЛЕ активации учетной записи с использованием данных электронного адреса
и пароля, который был отправлен по электронному адресу, указанному при активации или внесенному
в последствии в Профиль.</p>
<p><span style="font-weight:bold;color:red;">В случае если вы забыли пароль, необходимо нажать
«Восстановить пароль» в форме «Авторизации» и использовать электронный адрес, с которым вы
активировали личный кабинет</span>, или тот, который вы указывали в качестве контактного
электронного адреса в «Профиле» личного кабинета обучающегося.
Инструкция доступна по ссылке <a href="#">https://student.sechenov.ru/howto.php</a></p>
<p>При возникновении вопросов/проблем с ЦТ необходимо выбирать соответствующий пункт в причинах
на форме. Письма, отправленные не через форму обратной связи с выбором соответствующей причины,
а по электронной почте рассматриваться не будут.</p>
<br>
<p><span style="color:#ff0000;">Уважаемые первокурсники! Убедительная просьба не блокировать кампусные
карты МИР в личном кабинете Сбербанк Онлайн!</span></p>
</div>
</div>
<div class="row row--forms">
<!-- РЕГИСТРАЦИЯ -->
<div class="col-md-6 form-wrap">
<h3>Регистрация <small style="color:#000;"> Получить пароль от портала </small></h3>
<div class="form-wrap__links">
<span class="form-wrap__link"><a href="#">Как зарегистрироваться в системе/Восстановить пароль?</a></span>
<span class="form-wrap__link"><a href="#">Пароль и результаты ЦТ</a></span>
<span class="form-wrap__link"><a href="#">Предоставление паспортных данных</a></span>
</div>
<div class="well well-lg">
<div class="form-group">
<label>Номер студенческого билета <span class="req">*</span>
<span class="badge">?</span>
</label>
<div class="row">
<div class="col-xs-9">
<input type="text" class="form-control" placeholder="Например, 123456789123">
</div>
</div>
</div>
<div class="form-group">
<label>Идентификатор <span class="req">*</span>
<span class="badge">?</span>
</label>
<div class="row">
<div class="col-xs-9">
<input type="password" class="form-control" placeholder="Например, 1122345678">
</div>
</div>
</div>
<div class="checkbox">
<label>
<input type="checkbox" class="agreement_checkbox"> Даю согласие на передачу и обработку персональных данных
</label>
</div>
<button type="button" class="btn btn-primary btn-block disabled" disabled>Получить пароль</button>
</div>
</div>
<!-- АВТОРИЗАЦИЯ -->
<div class="col-md-6 form-wrap">
<h3>Авторизация <small style="color:#000;"> Я уже активировал профиль </small></h3>
<div class="form-wrap__links">
<span class="form-wrap__link"><a href="#">Восстановить пароль</a></span>
<span class="form-wrap__link"><a href="#">Как зарегистрироваться в системе/Восстановить пароль?</a></span>
</div>
<div class="well well-lg">
<div class="form-group">
<label>Адрес электронной почты <span class="req">*</span>
<span class="badge">?</span>
</label>
<div class="row">
<div class="col-xs-9">
<input type="text" class="form-control" placeholder="ivanov@mail.ru">
</div>
</div>
</div>
<div class="form-group">
<label>Пароль <span class="req">*</span>
<span class="badge">?</span>
</label>
<div class="row">
<div class="col-xs-9">
<input type="password" class="form-control" placeholder="******">
</div>
</div>
</div>
<div class="checkbox">
<label>
<input type="checkbox" class="agreement_checkbox"> Даю согласие на передачу и обработку персональных данных
</label>
</div>
<button type="button" class="btn btn-warning btn-block disabled" disabled>Авторизация</button>
</div>
</div>
</div>
</div>
<!-- FOOTER -->
<div class="container footer">
<div class="pull-left">
&copy; Информационная система «Университет — обучающийся» 20152026
</div>
<div class="applicationLinks">
<a href="#">App Store</a>
<a href="#">Google Play</a>
</div>
<div class="pull-right">
<a href="#">Форма обратной связи</a>
</div>
</div>
<!-- ══════════════════════════════════════════
CLAUDE CHAT (белая тема)
══════════════════════════════════════════ -->
<div class="chat-wrapper">
<div class="container">
<div class="page-header">
<h2>Claude Chat</h2>
</div>
<div class="chat-toolbar">
<label for="modelSel">Модель:</label>
<select id="modelSel">
<option value="sonnet">Sonnet 4.6</option>
<option value="haiku">Haiku 4.5</option>
</select>
<span id="chat-status"></span>
</div>
<div class="chat-panels">
<div class="chat-pane">
<div class="chat-pane-label">Запрос</div>
<textarea id="chat-input" placeholder="Вставьте текст сюда... (Ctrl+Enter — отправить)"></textarea>
</div>
<div class="chat-pane">
<div class="chat-pane-label">Ответ</div>
<div id="chat-output" class="empty">Ответ появится здесь...</div>
</div>
</div>
<div class="chat-actions">
<button id="sendBtn" class="btn btn-primary">Отправить</button>
<button id="clearBtn" class="btn btn-default">Очистить</button>
<div class="chat-spinner" id="spinner"></div>
<span id="chat-timer"></span>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script>
// ── Clock ──
// The spec requires: <span>DD.MM.YYYY</span>[space][time as text node]
// We use two sibling spans but style only #clkDate blue, #clkTime stays dark (inherits #333).
function updateClock() {
const now = new Date();
const dd = String(now.getDate()).padStart(2, '0');
const mm = String(now.getMonth() + 1).padStart(2, '0');
const yyyy = now.getFullYear();
const hh = String(now.getHours()).padStart(2, '0');
const mi = String(now.getMinutes()).padStart(2, '0');
const ss = String(now.getSeconds()).padStart(2, '0');
document.getElementById('clkDate').textContent = dd + '.' + mm + '.' + yyyy;
document.getElementById('clkTime').textContent = hh + ':' + mi + ':' + ss;
}
updateClock();
setInterval(updateClock, 1000);
// ── Checkbox → enable submit button ──
document.querySelectorAll('.agreement_checkbox').forEach(function(cb) {
cb.addEventListener('change', function() {
var btn = this.closest('.well').querySelector('button');
if (this.checked) {
btn.classList.remove('disabled');
btn.removeAttribute('disabled');
} else {
btn.classList.add('disabled');
btn.setAttribute('disabled', 'disabled');
}
});
});
// ── Chat ──
var inputEl = document.getElementById('chat-input');
var outputEl = document.getElementById('chat-output');
var sendBtn = document.getElementById('sendBtn');
var clearBtn = document.getElementById('clearBtn');
var modelSel = document.getElementById('modelSel');
var statusEl = document.getElementById('chat-status');
var spinnerEl = document.getElementById('spinner');
var timerEl = document.getElementById('chat-timer');
var timerInterval = null;
function setLoading(on) {
sendBtn.disabled = on;
spinnerEl.style.display = on ? 'inline-block' : 'none';
if (on) {
var start = Date.now();
timerInterval = setInterval(function() {
timerEl.textContent = ((Date.now() - start) / 1000).toFixed(1) + 's';
}, 100);
} else {
clearInterval(timerInterval);
}
}
function renderMarkdown(text) {
var html = text
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
html = html.replace(/```[\w]*\n?([\s\S]*?)```/g, function(_, c) {
return '<pre><code>' + c.trim() + '</code></pre>';
});
html = html.replace(/`([^`]+)`/g, '<code>$1</code>');
html = html.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
return html;
}
async function send() {
var text = inputEl.value.trim();
if (!text) return;
outputEl.className = '';
outputEl.innerHTML = '';
setLoading(true);
statusEl.textContent = 'Генерирую...';
var fullText = '';
try {
var resp = await fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text: text, model: modelSel.value }),
});
var reader = resp.body.getReader();
var decoder = new TextDecoder();
var buf = '';
while (true) {
var result = await reader.read();
if (result.done) break;
buf += decoder.decode(result.value, { stream: true });
var parts = buf.split('\n\n');
buf = parts.pop();
for (var i = 0; i < parts.length; i++) {
var part = parts[i];
if (!part.startsWith('data: ')) continue;
var raw = part.slice(6).trim();
if (raw === '[DONE]') continue;
try {
var obj = JSON.parse(raw);
if (obj.error) {
outputEl.innerHTML += '<span style="color:#a94442">' + obj.error + '</span>';
} else if (obj.text) {
fullText += obj.text;
outputEl.innerHTML = renderMarkdown(fullText);
outputEl.scrollTop = outputEl.scrollHeight;
}
} catch(e) {}
}
}
} catch(e) {
outputEl.innerHTML = '<span style="color:#a94442">Ошибка: ' + e.message + '</span>';
} finally {
setLoading(false);
statusEl.textContent = fullText ? (fullText.length + ' символов') : '';
}
}
sendBtn.addEventListener('click', send);
inputEl.addEventListener('keydown', function(e) {
if (e.ctrlKey && e.key === 'Enter') send();
});
clearBtn.addEventListener('click', function() {
inputEl.value = '';
outputEl.innerHTML = 'Ответ появится здесь...';
outputEl.className = 'empty';
statusEl.textContent = '';
timerEl.textContent = '';
});
</script>
</body>
</html>