Files
veeam/Шаблон_запроса_РК.html
T

534 lines
23 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">
<title>Шаблон запроса на резервное копирование</title>
<style>
:root {
--primary: #1a56db;
--bg: #f8fafc;
--border: #d1d5db;
--radius: 8px;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif;
background: var(--bg);
padding: 30px;
color: #1f2937;
}
.container { max-width: 1000px; margin: 0 auto; }
h1 {
font-size: 22px; margin-bottom: 4px; color: #111827;
}
.subtitle {
color: #6b7280; font-size: 13px; margin-bottom: 24px;
}
.doc-ref {
font-size: 12px; color: #9ca3af; margin-bottom: 20px;
}
.card {
background: #fff;
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 20px 24px;
margin-bottom: 16px;
}
.card h2 {
font-size: 15px; font-weight: 600; margin-bottom: 14px;
color: var(--primary); text-transform: uppercase; letter-spacing: 0.5px;
}
.row { display: flex; gap: 16px; flex-wrap: wrap; margin-bottom: 12px; }
.field { flex: 1; min-width: 200px; }
.field label {
display: block; font-size: 12px; font-weight: 500;
color: #374151; margin-bottom: 4px;
}
.field input, .field select, .field textarea {
width: 100%; padding: 8px 10px; font-size: 14px;
border: 1px solid var(--border); border-radius: 6px;
background: #fff; transition: border-color 0.2s;
}
.field input:focus, .field select:focus { outline: none; border-color: var(--primary); }
.field input[readonly] { background: #f3f4f6; color: #4b5563; cursor: default; }
.field textarea { resize: vertical; min-height: 60px; font-family: monospace; font-size: 13px; }
.field .hint {
font-size: 11px; color: #9ca3af; margin-top: 3px;
}
.auto-badge {
display: inline-block; font-size: 10px; background: #dbeafe; color: var(--primary);
padding: 1px 6px; border-radius: 4px; margin-left: 6px; font-weight: 500;
}
.params-grid {
display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 10px; margin-top: 8px;
}
.param-card {
background: #f0f4ff; border-radius: 6px; padding: 10px 14px;
border-left: 3px solid var(--primary);
}
.param-card .label { font-size: 11px; color: #6b7280; text-transform: uppercase; }
.param-card .value { font-size: 16px; font-weight: 700; color: var(--primary); margin-top: 2px; }
.param-card .value.green { color: #059669; }
.param-card .value.orange { color: #d97706; }
.param-card .value.red { color: #dc2626; }
.gen-name {
font-family: 'Courier New', monospace; font-size: 13px;
background: #1f2937; color: #e5e7eb; padding: 10px 14px;
border-radius: 6px; word-break: break-all; margin-top: 6px;
white-space: pre-wrap;
}
.btn-group { display: flex; gap: 10px; margin-top: 20px; }
.btn {
padding: 10px 24px; border: none; border-radius: 6px;
font-size: 14px; font-weight: 500; cursor: pointer; transition: 0.2s;
}
.btn-primary { background: var(--primary); color: #fff; }
.btn-primary:hover { background: #1d4ed8; }
.btn-secondary { background: #e5e7eb; color: #374151; }
.btn-secondary:hover { background: #d1d5db; }
.btn-danger { background: #fee2e2; color: #dc2626; }
.btn-danger:hover { background: #fecaca; }
.output-section { margin-top: 12px; }
.output-section textarea { min-height: 120px; font-family: monospace; font-size: 13px; }
.warning {
background: #fffbeb; border: 1px solid #fde68a; border-radius: 6px;
padding: 10px 14px; font-size: 13px; color: #92400e; margin-top: 8px;
}
@media print {
body { background: #fff; padding: 0; }
.btn-group, .doc-ref { display: none; }
.card { border: 1px solid #ddd; break-inside: avoid; }
}
</style>
</head>
<body>
<div class="container">
<h1>Шаблон запроса на резервное копирование ИТ-системы</h1>
<p class="subtitle">М НСП-НТ-03-02 26-09-2025 «Методика резервного копирования ИТ-систем»</p>
<p class="doc-ref">Номер заявки: <span id="reqId"></span> &nbsp;|&nbsp; Дата: <span id="reqDate"></span></p>
<!-- 1. Общая информация -->
<div class="card">
<h2>1. Общая информация об ИТ-системе</h2>
<div class="row">
<div class="field">
<label>Наименование ИТ-системы</label>
<input type="text" id="sysName" placeholder="Введите наименование">
</div>
<div class="field">
<label>Идентификатор в EATool</label>
<input type="text" id="eaToolId" placeholder="IS000XXXX" maxlength="10">
<div class="hint">Формат: IS000XXXX. Для систем без ID — IS0000000</div>
</div>
</div>
<div class="row">
<div class="field">
<label>Ответственный за эксплуатацию ИТ-системы</label>
<input type="text" id="responsible" placeholder="ФИО / должность">
</div>
<div class="field">
<label>Подразделение</label>
<input type="text" id="department" placeholder="Наименование подразделения">
</div>
</div>
<div class="row">
<div class="field">
<label>Класс критичности ИТ-системы</label>
<select id="criticality" onchange="autoFill()">
<option value="">— Выберите класс критичности —</option>
<option value="max">Максимальный</option>
<option value="high">Высокий</option>
<option value="medium">Средний</option>
<option value="low">Низкий</option>
</select>
</div>
<div class="field">
<label>Тип данных</label>
<select id="dataType" onchange="autoFill()">
<option value="">— Выберите тип данных —</option>
<option value="vm">Виртуальная машина</option>
<option value="fs">Файловая система</option>
<option value="db">База данных / Приложение</option>
</select>
</div>
</div>
</div>
<!-- 2. Класс резервирования (авто) -->
<div class="card" id="classCard" style="display:none">
<h2>2. Класс резервирования и параметры восстановления <span class="auto-badge">авто</span></h2>
<div class="params-grid" id="paramsGrid"></div>
</div>
<!-- 3. Параметры резервного копирования -->
<div class="card" id="backupParamsCard" style="display:none">
<h2>3. Параметры резервного копирования</h2>
<div class="row">
<div class="field">
<label>Класс резервирования (КР)</label>
<input type="text" id="krClass" readonly>
</div>
<div class="field">
<label>Периодичность резервного копирования</label>
<input type="text" id="backupPeriod" readonly>
</div>
</div>
<div class="row">
<div class="field">
<label>RTO (целевое время восстановления)</label>
<input type="text" id="rto" readonly>
</div>
<div class="field">
<label>RPO (целевая точка восстановления)</label>
<input type="text" id="rpo" readonly>
</div>
</div>
<div class="row">
<div class="field">
<label>Срок хранения — ежедневные копии (S)</label>
<input type="text" id="storeDaily" readonly>
</div>
<div class="field">
<label>Срок хранения — еженедельные копии (F)</label>
<input type="text" id="storeWeekly" readonly>
</div>
<div class="field">
<label>Срок хранения — ежемесячные копии (G)</label>
<input type="text" id="storeMonthly" readonly>
</div>
</div>
<div class="row">
<div class="field">
<label>Место хранения резервных копий</label>
<input type="text" id="storageLocation" readonly>
</div>
<div class="field">
<label>Наличие удалённой реплики</label>
<input type="text" id="hasReplica" readonly>
</div>
</div>
<div class="row" id="dbDetailsRow" style="display:none">
<div class="field">
<label>Периодичность копирования транзакционных журналов БД</label>
<input type="text" id="tlogPeriod" readonly>
</div>
</div>
<div class="field" style="margin-top:8px">
<label>Согласованное изменение параметров (если применимо)</label>
<textarea id="agreedChanges" placeholder="Решение ответственного за эксплуатацию ИТ-системы и ответственного за эксплуатацию СРК (если периодичность/сроки изменены)"></textarea>
</div>
</div>
<!-- 4. Детали объекта -->
<div class="card" id="detailsCard" style="display:none">
<h2>4. Детали объекта резервирования</h2>
<div class="row">
<div class="field">
<label>Тип объекта РК</label>
<select id="rkType">
<option value="">— Выберите —</option>
<option value="zVirt">zVirt</option>
<option value="HyperV">Hyper-V</option>
<option value="VMware">VMware</option>
<option value="File">File</option>
<option value="Block">Block</option>
<option value="MSSQL">MSSQL</option>
<option value="PSQL">Postgres</option>
<option value="Mongo">Mongo</option>
<option value="DB2">DB2</option>
<option value="Exchange">Exchange</option>
<option value="SP">SharePoint</option>
<option value="Oracle">Oracle</option>
<option value="SAP">SAP HANA</option>
<option value="Sybase">Sybase</option>
<option value="K8s">Kubernetes</option>
</select>
</div>
<div class="field">
<label>Схема резервного копирования (F-I-D)</label>
<select id="fidScheme" onchange="toggleF1Warning()">
<option value="">— Выберите —</option>
<option value="F">F — только полное</option>
<option value="F1">F1 — разовое полное</option>
<option value="I">I — всегда инкрементальное</option>
<option value="FI">FI — полное + инкрементальное</option>
<option value="FD">FD — полное + дифференциальное</option>
<option value="SF">SF — синтетическое полное</option>
<option value="FDI">FDI — полное + дифференциальное + инкрементальное</option>
<option value="TLB">TLB — транзакционные логи</option>
</select>
</div>
</div>
<div id="f1Warning" class="warning" style="display:none">
Внимание! Для схемы F1 требуется ежеквартальная ревизия актуальности. По итогам ревизии план защиты и соответствующие файлы РК могут быть удалены.
</div>
<div class="row">
<div class="field">
<label>Имя сервера / ресурса (Hostname/FQDN)</label>
<input type="text" id="hostname" placeholder="server-name.domain.local">
<div class="hint">Верхний регистр — Windows, нижний — Unix. Группа серверов: GrSrv-&lt;NAME&gt;</div>
</div>
<div class="field">
<label>Объём резервируемых данных (Гб)</label>
<input type="number" id="volumeGb" placeholder="0" min="0" step="0.1">
</div>
</div>
<div class="row">
<div class="field">
<label>Допустимое окно резервного копирования</label>
<input type="text" id="backupWindow" placeholder="например: 22:00–06:00">
</div>
<div class="field">
<label>Порядковый номер политики (X)</label>
<input type="text" id="policyNum" placeholder="1, 2, ... (опционально)">
<div class="hint">При одинаковых названиях, но разных расписаниях</div>
</div>
</div>
<div class="row">
<div class="field">
<label>Прогнозируемый объём на конец года (Гб)</label>
<input type="number" id="volumeMaxGb" placeholder="0" min="0" step="0.1">
</div>
<div class="field">
<label>Коэффициент дедупликации</label>
<input type="text" id="dedupFactor" placeholder="Например: 2:1, 3:1">
</div>
</div>
</div>
<!-- 5. Сгенерированное наименование плана защиты -->
<div class="card" id="nameCard" style="display:none">
<h2>5. Наименование плана защиты / политики РК <span class="auto-badge">авто</span></h2>
<p style="font-size:12px; color:#6b7280; margin-bottom:6px;">
Шаблон: <code>&lt;IS000XXXX&gt;_&lt;Объект-РК&gt;_&lt;Тип РК&gt;_&lt;F-I-D&gt;_&lt;X&gt;</code>
</p>
<div class="gen-name" id="generatedName">—</div>
<div class="field" style="margin-top:8px">
<label>Примечание (для служебных / тестовых политик)</label>
<select id="policyNote" onchange="updateGeneratedName()">
<option value="">— Стандартная политика —</option>
<option value="Test">Test — тестовая политика</option>
<option value="System">System — служебная (сбор логов, скрипты) — для КиберБэкап</option>
</select>
</div>
</div>
<!-- 6. Полный вывод -->
<div class="card" id="outputCard" style="display:none">
<h2>6. Спецификация резервного копирования (сводка)</h2>
<div class="output-section">
<textarea id="fullOutput" readonly></textarea>
</div>
<div class="btn-group">
<button class="btn btn-primary" onclick="copyOutput()">Копировать спецификацию</button>
<button class="btn btn-secondary" onclick="window.print()">Печать</button>
<button class="btn btn-danger" onclick="resetForm()">Сбросить</button>
</div>
</div>
</div>
<script>
const KR_CONFIG = {
max: {
kr: 1, period: '2 ч.', rto: '2 ч.', rpo: '2 ч.',
storeDaily: '1 нед.', storeWeekly: '1 м.', storeMonthly: '1 г.',
location: 'ОЦОД + РЦОД + ЛБ', replica: 'Да',
tlog: '2 ч.', color: 'red'
},
high: {
kr: 2, period: '8 ч.', rto: '8 ч.', rpo: '8 ч.',
storeDaily: '1 нед.', storeWeekly: '1 м.', storeMonthly: '1 г.',
location: 'ОЦОД + РЦОД + ЛБ', replica: 'Да',
tlog: '8 ч.', color: 'orange'
},
medium: {
kr: 3, period: '16 ч.', rto: '16 ч.', rpo: '16 ч.',
storeDaily: '1 нед.', storeWeekly: '1 м.', storeMonthly: '1 г.',
location: 'ОЦОД', replica: 'Нет',
tlog: '16 ч.', color: 'green'
},
low: {
kr: 4, period: '24 ч.', rto: '24 ч.', rpo: '24 ч.',
storeDaily: '1 нед.', storeWeekly: '1 м.', storeMonthly: '1 г.',
location: 'ОЦОД', replica: 'Нет',
tlog: '24 ч.', color: 'green'
}
};
const CRIT_NAMES = { max: 'Максимальный', high: 'Высокий', medium: 'Средний', low: 'Низкий' };
const DATA_TYPES = { vm: 'Виртуальная машина', fs: 'Файловая система', db: 'База данных / Приложение' };
function get(id) { return document.getElementById(id); }
function autoFill() {
const crit = get('criticality').value;
const dt = get('dataType').value;
if (!crit || !dt) return;
const cfg = KR_CONFIG[crit];
get('classCard').style.display = 'block';
get('backupParamsCard').style.display = 'block';
get('detailsCard').style.display = 'block';
get('nameCard').style.display = 'block';
get('outputCard').style.display = 'block';
// Параметры восстановления
const labels = {
max: { label: 'КР 1 — Максимальный', desc: 'RTO 2ч / RPO 2ч' },
high: { label: 'КР 2 — Высокий', desc: 'RTO 8ч / RPO 8ч' },
medium: { label: 'КР 3 — Средний', desc: 'RTO 16ч / RPO 16ч' },
low: { label: 'КР 4 — Низкий', desc: 'RTO 24ч / RPO 24ч' }
};
get('paramsGrid').innerHTML = `
<div class="param-card"><div class="label">Класс резервирования</div><div class="value ${cfg.color}">КР ${cfg.kr}</div></div>
<div class="param-card"><div class="label">Периодичность</div><div class="value">${cfg.period}</div></div>
<div class="param-card"><div class="label">RTO</div><div class="value">${cfg.rto}</div></div>
<div class="param-card"><div class="label">RPO</div><div class="value">${cfg.rpo}</div></div>
<div class="param-card"><div class="label">Хранение (ежедн/еженед/ежемес)</div><div class="value">${cfg.storeDaily} / ${cfg.storeWeekly} / ${cfg.storeMonthly}</div></div>
<div class="param-card"><div class="label">Место хранения</div><div class="value">${cfg.location}</div></div>
<div class="param-card"><div class="label">Удалённая реплика</div><div class="value ${cfg.replica === 'Да' ? 'red' : 'green'}">${cfg.replica}</div></div>
`;
get('krClass').value = 'КР ' + cfg.kr;
get('backupPeriod').value = cfg.period;
get('rto').value = cfg.rto;
get('rpo').value = cfg.rpo;
get('storeDaily').value = cfg.storeDaily;
get('storeWeekly').value = cfg.storeWeekly;
get('storeMonthly').value = cfg.storeMonthly;
get('storageLocation').value = cfg.location;
get('hasReplica').value = cfg.replica;
// Показываем/скрываем строку TLog
get('dbDetailsRow').style.display = (dt === 'db') ? 'flex' : 'none';
if (dt === 'db') {
get('tlogPeriod').value = 'каждые ' + cfg.tlog;
}
updateGeneratedName();
updateFullOutput();
}
function toggleF1Warning() {
get('f1Warning').style.display = (get('fidScheme').value === 'F1') ? 'block' : 'none';
updateGeneratedName();
}
function updateGeneratedName() {
const eaId = get('eaToolId').value || 'IS0000000';
const host = get('hostname').value || '<Имя_сервера>';
const rkType = get('rkType').value || '<Тип_РК>';
const fid = get('fidScheme').value || '<F-I-D>';
const num = get('policyNum').value;
const note = get('policyNote').value;
let base = eaId + '_' + host + '_' + rkType + '_' + fid;
if (num) base += '_' + num;
if (note) base = note + '_' + base;
get('generatedName').textContent = base;
updateFullOutput();
}
function updateFullOutput() {
const crit = get('criticality').value;
const cfg = crit ? KR_CONFIG[crit] : null;
const dt = get('dataType').value;
let o = '=== СПЕЦИФИКАЦИЯ РЕЗЕРВНОГО КОПИРОВАНИЯ ИТ-СИСТЕМЫ ===\n';
o += 'Методика: М НСП-НТ-03-02 26-09-2025\n\n';
o += '1. ИТ-СИСТЕМА\n';
o += ' Наименование: ' + (get('sysName').value || '(не указано)') + '\n';
o += ' ID EATool: ' + (get('eaToolId').value || 'IS0000000') + '\n';
o += ' Ответственный: ' + (get('responsible').value || '(не указано)') + '\n';
o += ' Подразделение: ' + (get('department').value || '(не указано)') + '\n';
o += ' Класс критичности: ' + (CRIT_NAMES[crit] || '(не выбран)') + '\n';
o += ' Тип данных: ' + (DATA_TYPES[dt] || '(не выбран)') + '\n\n';
if (cfg) {
o += '2. КЛАСС РЕЗЕРВИРОВАНИЯ\n';
o += ' КР: КР ' + cfg.kr + '\n';
o += ' Периодичность: ' + cfg.period + '\n';
o += ' RTO: ' + cfg.rto + '\n';
o += ' RPO: ' + cfg.rpo + '\n\n';
o += '3. ХРАНЕНИЕ\n';
o += ' Ежедневные (S): ' + cfg.storeDaily + '\n';
o += ' Еженедельные (F): ' + cfg.storeWeekly + '\n';
o += ' Ежемесячные (G): ' + cfg.storeMonthly + '\n\n';
o += '4. РАЗМЕЩЕНИЕ\n';
o += ' Место хранения: ' + cfg.location + '\n';
o += ' Удалённая реплика: ' + cfg.replica + '\n';
if (dt === 'db') {
o += ' Транзакционные логи: каждые ' + cfg.tlog + '\n';
}
o += '\n';
}
o += '5. ОБЪЕКТ РЕЗЕРВИРОВАНИЯ\n';
o += ' Тип объекта РК: ' + (get('rkType').value || '(не выбран)') + '\n';
o += ' Схема F-I-D: ' + (get('fidScheme').value || '(не выбрана)') + '\n';
o += ' Hostname/FQDN: ' + (get('hostname').value || '(не указан)') + '\n';
o += ' Объём (текущий): ' + (get('volumeGb').value || '0') + ' Гб\n';
o += ' Объём (прогноз): ' + (get('volumeMaxGb').value || '0') + ' Гб\n';
o += ' Дедупликация: ' + (get('dedupFactor').value || '(не указан)') + '\n';
o += ' Окно РК: ' + (get('backupWindow').value || '(не указано)') + '\n\n';
o += '6. ПЛАН ЗАЩИТЫ / ПОЛИТИКА РК\n';
o += ' Наименование: ' + get('generatedName').textContent + '\n\n';
if (get('agreedChanges').value.trim()) {
o += '7. СОГЛАСОВАННЫЕ ИЗМЕНЕНИЯ\n';
o += ' ' + get('agreedChanges').value + '\n\n';
}
o += '=== КОНЕЦ СПЕЦИФИКАЦИИ ===';
get('fullOutput').value = o;
}
// Автообновление сводки при любых изменениях
document.querySelectorAll('input, select, textarea').forEach(el => {
el.addEventListener('change', () => { updateGeneratedName(); updateFullOutput(); });
el.addEventListener('input', () => { updateGeneratedName(); updateFullOutput(); });
});
function copyOutput() {
const ta = get('fullOutput');
ta.select();
document.execCommand('copy');
const btn = event.target;
const orig = btn.textContent;
btn.textContent = 'Скопировано!';
setTimeout(() => btn.textContent = orig, 2000);
}
function resetForm() {
if (!confirm('Сбросить все поля?')) return;
document.querySelectorAll('input, textarea').forEach(el => el.value = '');
document.querySelectorAll('select').forEach(el => el.selectedIndex = 0);
['classCard','backupParamsCard','detailsCard','nameCard','outputCard','f1Warning','dbDetailsRow'].forEach(id => {
get(id).style.display = 'none';
});
}
// Инициализация
(function() {
const now = new Date();
const pad = n => String(n).padStart(2, '0');
get('reqDate').textContent = now.getFullYear() + '-' + pad(now.getMonth()+1) + '-' + pad(now.getDate());
get('reqId').textContent = 'ЗРК-' + now.getFullYear() + pad(now.getMonth()+1) + pad(now.getDate()) + '-' + pad(Math.floor(Math.random()*999)+1);
})();
</script>
</body>
</html>