260 lines
14 KiB
HTML
260 lines
14 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
<title>Служебная записка — генератор</title>
|
||
<style>
|
||
*{box-sizing:border-box;margin:0;padding:0}
|
||
body{font:16px/1.5 "Times New Roman",Georgia,serif;background:#f5f5f0;color:#1a1a1a;padding:40px 24px}
|
||
.container{max-width:900px;margin:0 auto}
|
||
h1{font-size:26px;font-weight:400;letter-spacing:1px;text-transform:uppercase;text-align:center;margin-bottom:4px;color:#222}
|
||
.sub{text-align:center;color:#666;font-size:14px;margin-bottom:40px;font-family:-apple-system,sans-serif}
|
||
.layout{display:grid;grid-template-columns:1fr 1fr;gap:32px;align-items:start}
|
||
|
||
.panel{background:#fff;border:1px solid #ddd;padding:28px;border-radius:2px;box-shadow:0 1px 4px rgba(0,0,0,.04)}
|
||
.panel h2{font-size:16px;font-weight:600;margin-bottom:16px;color:#333;font-family:-apple-system,sans-serif}
|
||
|
||
label{display:block;font-size:12px;font-weight:600;color:#555;margin-bottom:4px;text-transform:uppercase;letter-spacing:.5px;font-family:-apple-system,sans-serif}
|
||
input,textarea{width:100%;padding:10px 12px;border:1px solid #ccc;border-radius:2px;font:inherit;outline:none;transition:.15s}
|
||
input:focus,textarea:focus{border-color:#333}
|
||
textarea{resize:vertical;min-height:160px}
|
||
.form-row{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:12px}
|
||
|
||
button{width:100%;padding:12px;background:#1a1a1a;color:#fff;border:none;font:14px/1.4 -apple-system,sans-serif;font-weight:600;text-transform:uppercase;letter-spacing:1px;cursor:pointer;margin-top:16px;transition:.15s}
|
||
button:hover{background:#333}
|
||
|
||
.result-panel{background:#fff;border:1px solid #ddd;padding:28px;border-radius:2px;box-shadow:0 1px 4px rgba(0,0,0,.04);display:none}
|
||
.result-panel.show{display:block}
|
||
.doc-header{text-align:center;margin-bottom:28px;padding-bottom:20px;border-bottom:2px solid #1a1a1a}
|
||
.doc-header .org{font-size:14px;text-transform:uppercase;letter-spacing:1px;color:#555;margin-bottom:8px}
|
||
.doc-header .title{font-size:20px;font-weight:700;letter-spacing:2px;text-transform:uppercase}
|
||
.doc-meta{margin-bottom:24px}
|
||
.doc-meta .row{display:flex;margin-bottom:6px}
|
||
.doc-meta .row .lbl{width:100px;font-weight:600;color:#555;font-size:13px;text-transform:uppercase}
|
||
.doc-meta .row .val{flex:1;border-bottom:1px solid #ddd;padding-bottom:2px;font-size:15px}
|
||
.doc-body{font-size:15px;text-indent:30px;margin-bottom:24px;white-space:pre-wrap}
|
||
.doc-body i{font-style:italic;color:#555}
|
||
.doc-signature{margin-top:32px;padding-top:16px;border-top:1px solid #ddd}
|
||
.doc-signature .row{display:flex;justify-content:space-between;font-size:14px;color:#555}
|
||
.copy-btn{display:inline-block;margin-top:16px;padding:8px 20px;background:transparent;border:1px solid #999;color:#333;font:12px/1.4 -apple-system,sans-serif;text-transform:uppercase;letter-spacing:1px;cursor:pointer;transition:.15s}
|
||
.copy-btn:hover{background:#eee}
|
||
|
||
.rules-hint{font-size:12px;color:#888;margin-top:8px;line-height:1.4;font-family:-apple-system,sans-serif}
|
||
.rules-hint code{background:#f5f5f0;padding:1px 6px;border-radius:2px}
|
||
|
||
@media(max-width:720px){.layout{grid-template-columns:1fr;gap:24px}body{padding:24px 16px}.form-row{grid-template-columns:1fr}}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<h1>Служебная записка</h1>
|
||
<p class="sub">Перевод текста в официальный стиль</p>
|
||
|
||
<div class="layout">
|
||
<div class="panel">
|
||
<h2>📝 Исходный текст</h2>
|
||
<div class="form-row">
|
||
<div><label>Кому</label><input id="to" placeholder="ФИО / должность"></div>
|
||
<div><label>От кого</label><input id="from" placeholder="ФИО / должность"></div>
|
||
</div>
|
||
<div class="form-row">
|
||
<div><label>Тема</label><input id="subject" placeholder="О чём записка"></div>
|
||
<div><label>Дата</label><input id="date" placeholder="дд.мм.гггг"></div>
|
||
</div>
|
||
<label>Текст детским / простым языком</label>
|
||
<textarea id="inputText" placeholder="Например: Витя из 5А разрисовал парту фломастером. Теперь парта вся в сердечках и надписях. Завуч сказала написать объяснительную."></textarea>
|
||
<div class="rules-hint">
|
||
<strong>Алгоритм перевода:</strong> исправляет орфографию → заменяет разговорные фразы на официальные → выстраивает в структуру служебной записки
|
||
</div>
|
||
<button onclick="generate()">Сформировать записку</button>
|
||
</div>
|
||
|
||
<div>
|
||
<div class="result-panel" id="result">
|
||
<div class="doc-header">
|
||
<div class="org">СЛУЖЕБНАЯ ЗАПИСКА</div>
|
||
<div class="title" id="docSubject"></div>
|
||
</div>
|
||
<div class="doc-meta">
|
||
<div class="row"><span class="lbl">Кому:</span><span class="val" id="docTo"></span></div>
|
||
<div class="row"><span class="lbl">От кого:</span><span class="val" id="docFrom"></span></div>
|
||
<div class="row"><span class="lbl">Дата:</span><span class="val" id="docDate"></span></div>
|
||
</div>
|
||
<div class="doc-body" id="docBody"></div>
|
||
<div class="doc-signature">
|
||
<div class="row">
|
||
<span>___________________</span>
|
||
<span id="docName"></span>
|
||
</div>
|
||
</div>
|
||
<button class="copy-btn" onclick="copyResult()">📋 Копировать</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
const replacements = [
|
||
// Приветствия и обращения
|
||
[/привет|здорово|салют|хай/gi, 'Здравствуйте'],
|
||
[/ребята|пацаны|народ/gi, 'уважаемые коллеги'],
|
||
[/училка|препод|классуха/gi, 'педагогический работник'],
|
||
[/завуч/gi, 'заместитель директора по учебно-воспитательной работе'],
|
||
|
||
// Действия (разговорные → официальные)
|
||
[/(?:на)рисовал|разрисовал|исписал|разукрасил/gi, 'совершил действие по нанесению графических изображений'],
|
||
[/написал|накалякал|начеркал/gi, 'произвёл запись'],
|
||
[/сломал|поломал|разбил|испортил/gi, 'допустил повреждение'],
|
||
[/покрасил/gi, 'произвёл окрашивание'],
|
||
[/потерял|забыл|потерял/gi, 'утратил'],
|
||
[/ударил|толкнул|стукнул/gi, 'применил физическое воздействие'],
|
||
[/обзывал|обозвал/gi, 'допустил некорректные высказывания в адрес'],
|
||
[/подрались|побили/gi, 'вступили в конфликт с применением физической силы'],
|
||
[/списал|сдул/gi, 'допустил нарушение академической честности'],
|
||
[/опоздал/gi, 'допустил нарушение трудовой дисциплины в виде несвоевременного прибытия'],
|
||
[/прогулял/gi, 'не явился без уважительной причины'],
|
||
[/не сделал|не выполнил/gi, 'не исполнил возложенные обязанности'],
|
||
|
||
// Описания
|
||
[/парта|стол/gi, 'объект мебели'],
|
||
[/класс|кабинет/gi, 'учебное помещение'],
|
||
[/школа/gi, 'образовательное учреждение'],
|
||
[/урок/gi, 'учебное занятие'],
|
||
[/перемена|переменка/gi, 'перерыв между учебными занятиями'],
|
||
[/учиться/gi, 'осуществлять образовательную деятельность'],
|
||
[/двойка/gi, 'неудовлетворительная оценка'],
|
||
[/пятёрка/gi, 'отличная оценка'],
|
||
[/домашка/gi, 'домашнее задание'],
|
||
[/контрольная/gi, 'контрольное мероприятие'],
|
||
[/тетрадь/gi, 'рабочая тетрадь'],
|
||
[/дневник/gi, 'дневник успеваемости'],
|
||
[/фломастер|маркер|ручка/gi, 'канцелярская принадлежность'],
|
||
[/сердечки|сердечко/gi, 'изображения символического характера'],
|
||
[/надпись|надписи/gi, 'текстовые изображения'],
|
||
|
||
// Дети и люди
|
||
[/мальчик|мальчишка/gi, 'учащийся мужского пола'],
|
||
[/девочка|девчонка/gi, 'учащаяся женского пола'],
|
||
[/ученик/gi, 'обучающийся'],
|
||
[/ученица/gi, 'обучающаяся'],
|
||
[/директор|дир/gi, 'руководитель учреждения'],
|
||
|
||
// Связки
|
||
[/потому что|потому-то|так как/gi, 'в связи с тем что'],
|
||
[/поэтому/gi, 'в связи с вышеизложенным'],
|
||
[/вдруг|внезапно/gi, 'непредвиденно'],
|
||
[/наверное|наверно/gi, 'предположительно'],
|
||
[/очень/gi, 'в значительной степени'],
|
||
[/потом|после этого/gi, 'впоследствии'],
|
||
[/сейчас|щас/gi, 'в настоящее время'],
|
||
[/вчера/gi, 'в предшествующий день'],
|
||
[/сегодня/gi, 'в текущий день'],
|
||
[/завтра/gi, 'в следующий день'],
|
||
|
||
// Начало предложения
|
||
[/^ну |^ну,|^а |^а,|^и |^и,/gmi, ''],
|
||
[/^вот |^вот,/gmi, ''],
|
||
];
|
||
|
||
const phrases = {
|
||
intro: [
|
||
'Довожу до Вашего сведения, что',
|
||
'Сообщаю, что',
|
||
'Информирую о том, что',
|
||
'Ставлю Вас в известность о том, что',
|
||
'Настоящим докладываю, что',
|
||
'Докладываю следующее:',
|
||
],
|
||
conclusion: [
|
||
'На основании вышеизложенного прошу принять соответствующие меры.',
|
||
'Учитывая изложенное, прошу дать указания по данному вопросу.',
|
||
'Прошу рассмотреть данную ситуацию и принять решение.',
|
||
'В связи с вышеизложенным прошу Вашего распоряжения.',
|
||
'Прошу довести данную информацию до сведения ответственных лиц.',
|
||
],
|
||
request: [
|
||
'Прошу провести беседу с',
|
||
'Прошу принять меры в отношении',
|
||
'Прошу разобраться в сложившейся ситуации',
|
||
'Прошу дать указание',
|
||
],
|
||
};
|
||
|
||
function capitalize(s){
|
||
return s.charAt(0).toUpperCase()+s.slice(1);
|
||
}
|
||
|
||
function applyReplacements(text){
|
||
let t=text;
|
||
replacements.forEach(([re,val])=>{
|
||
// Simple approach: apply replacement, handling case
|
||
t=t.replace(re,val);
|
||
});
|
||
return t;
|
||
}
|
||
|
||
function generate(){
|
||
const to=document.getElementById('to').value.trim()||'Руководителю';
|
||
const from=document.getElementById('from').value.trim()||'Сотрудник';
|
||
const subject=document.getElementById('subject').value.trim()||'Служебная записка';
|
||
const date=document.getElementById('date').value.trim()||new Date().toLocaleDateString('ru-RU');
|
||
const text=document.getElementById('inputText').value.trim();
|
||
|
||
if(!text){
|
||
alert('Введите текст для перевода');
|
||
return;
|
||
}
|
||
|
||
// Apply replacements
|
||
let official=applyReplacements(text);
|
||
|
||
// Build body
|
||
const intro=phrases.intro[Math.floor(Math.random()*phrases.intro.length)];
|
||
const conclusion=phrases.conclusion[Math.floor(Math.random()*phrases.conclusion.length)];
|
||
const request=phrases.request[Math.floor(Math.random()*phrases.request.length)];
|
||
|
||
// Identify subject (first noun/person mentioned)
|
||
const firstPerson=official.match(/(учащийся[^,.]*|обучающийся[^,.]*|сотрудник[^,.]*|педагогический[^,.]*)/gi);
|
||
const personRef=firstPerson?firstPerson[0].toLowerCase():'указанным лицом';
|
||
|
||
let body=`${intro} ${capitalize(official)}
|
||
|
||
${request} ${personRef}. ${conclusion}`;
|
||
|
||
// Clean up
|
||
body=body.replace(/\s+/g,' ').replace(/ ,/g,',').replace(/ \./g,'.').replace(/\.\./g,'.');
|
||
body=body.replace(/ ,/g,',');
|
||
|
||
// Show result
|
||
document.getElementById('docSubject').textContent=subject.toUpperCase();
|
||
document.getElementById('docTo').textContent=to;
|
||
document.getElementById('docFrom').textContent=from;
|
||
document.getElementById('docDate').textContent=date;
|
||
document.getElementById('docBody').textContent=body;
|
||
document.getElementById('docName').textContent=from;
|
||
|
||
document.getElementById('result').classList.add('show');
|
||
}
|
||
|
||
function copyResult(){
|
||
const to=document.getElementById('docTo').textContent;
|
||
const from=document.getElementById('docFrom').textContent;
|
||
const date=document.getElementById('docDate').textContent;
|
||
const subject=document.getElementById('docSubject').textContent;
|
||
const body=document.getElementById('docBody').textContent;
|
||
|
||
const full=`СЛУЖЕБНАЯ ЗАПИСКА\n${subject}\n\nКому: ${to}\nОт кого: ${from}\nДата: ${date}\n\n${body}\n\n___________________\n${from}`;
|
||
|
||
navigator.clipboard.writeText(full).then(()=>{
|
||
const btn=document.querySelector('.copy-btn');
|
||
btn.textContent='✅ Скопировано';
|
||
setTimeout(()=>btn.textContent='📋 Копировать',2000);
|
||
}).catch(()=>{});
|
||
}
|
||
|
||
document.getElementById('inputText').addEventListener('keydown',e=>{if((e.ctrlKey||e.metaKey)&&e.key==='Enter')generate()});
|
||
</script>
|
||
</body>
|
||
</html>
|