house-wiring/index.html
2026-06-19 06:30:31 +00:00

205 lines
8.6 KiB
HTML
Raw Permalink 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>
<style>
*{box-sizing:border-box;margin:0;padding:0}
body{font:17px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Inter,system-ui,sans-serif;background:#f0f2f5;color:#0F1218;min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:24px}
.card{background:#fff;border-radius:20px;padding:48px;max-width:520px;width:100%;box-shadow:0 4px 24px rgba(0,0,0,.06)}
h1{font-size:26px;font-weight:800;margin-bottom:4px}
.sub{color:#5B6573;font-size:15px;margin-bottom:24px}
.settings{background:#f6f8fa;border-radius:12px;padding:20px;margin-bottom:24px}
.settings-row{display:flex;gap:12px;margin-bottom:12px}
.settings-row:last-child{margin-bottom:0}
.settings-row label{flex:1;font-size:14px;font-weight:600;color:#5B6573}
.settings-row input{width:100%;padding:10px 14px;font-size:16px;font-weight:600;border:2px solid #d0d5dd;border-radius:8px;outline:none;text-align:center;transition:.15s}
.settings-row input:focus{border-color:#0F1218}
label[for=point]{display:block;font-weight:600;font-size:15px;margin-bottom:8px}
input#point{width:100%;padding:16px 20px;font-size:24px;font-weight:700;border:2px solid #d0d5dd;border-radius:12px;outline:none;transition:.15s;text-align:center}
input#point:focus{border-color:#0F1218}
input#point::placeholder{font-weight:400;color:#9aa3b2;font-size:17px}
button{width:100%;padding:16px;background:#0F1218;color:#fff;border:none;border-radius:12px;font-size:18px;font-weight:700;cursor:pointer;margin-top:16px;transition:.15s}
button:hover{background:#2a2f3a}
button:active{transform:scale(.98)}
.result{padding:24px;background:#f0f2f5;border-radius:12px;margin-top:24px;text-align:center;display:none}
.result.show{display:block}
.result .big{font-size:36px;font-weight:800;color:#0F1218}
.result .big span{color:#0088cc}
.result .detail{font-size:14px;color:#5B6573;margin-top:8px}
.error{color:#e74c3c;font-size:14px;margin-top:8px;display:none}
.error.show{display:block}
.history{margin-top:32px;padding-top:24px;border-top:2px solid #e8eaed;display:none}
.history.show{display:block}
.history h3{font-size:15px;color:#5B6573;font-weight:600;margin-bottom:12px}
.history-item{display:flex;justify-content:space-between;align-items:center;padding:10px 14px;border-radius:8px;cursor:pointer;transition:.1s;font-size:15px}
.history-item:hover{background:#f0f2f5}
.history-item .h-num{font-weight:700}
.history-item .h-result{color:#0088cc;font-weight:600}
.history-item .h-copy{color:#9aa3b2;font-size:13px;cursor:pointer;padding:4px 8px;border-radius:4px}
.history-item .h-copy:hover{background:#d0d5dd;color:#0F1218}
.room-list{margin-top:20px;font-size:14px}
.room-list summary{font-weight:600;color:#5B6573;cursor:pointer;padding:6px 0}
.room-list .rrow{display:flex;justify-content:space-between;padding:4px 8px;border-radius:4px;font-size:13px}
.room-list .rrow:nth-child(odd){background:#f8f9fa}
@media(max-width:480px){.card{padding:24px}.settings-row{flex-direction:column;gap:8px}h1{font-size:22px}input#point{font-size:20px}}
</style>
</head>
<body>
<div class="card">
<h1>🏠 Проводка по дому</h1>
<p class="sub" id="subtitle">Комнаты и точки: расстановка</p>
<div class="settings">
<div class="settings-row">
<label>Комнат <input type="number" id="rooms" min="1" max="99" onchange="applySettings()"></label>
<label>Точек на комнату <input type="number" id="perRoom" min="1" max="99" onchange="applySettings()"></label>
</div>
</div>
<label for="point">Введи номер точки (розетка/выключатель/свет)</label>
<input type="number" id="point" min="1" placeholder="например, 45" autofocus>
<div class="error" id="error">Введи число в диапазоне</div>
<button onclick="calc()">Рассчитать</button>
<div class="result" id="result">
<div class="big" id="output"></div>
<div class="detail" id="detail"></div>
</div>
<div class="room-list" id="roomList"></div>
<div class="history" id="history">
<h3>📋 История</h3>
<div id="historyList"></div>
</div>
</div>
<script>
const MAX_HISTORY=50;
let PER_ROOM=6;
let TOTAL_ROOMS=10;
let TOTAL_POINTS=TOTAL_ROOMS*PER_ROOM;
let history=JSON.parse(localStorage.getItem('hwHistory')||'[]');
const roomNames=[
'Прихожая','Коридор','Гостиная','Кухня','Спальня','Детская','Ванная','Туалет',
'Кладовая','Балкон','Кабинет','Гардеробная','Прачечная','Котельная','Холл','Столовая',
'Гостевая','Спортзал','Бильярдная','Винный погреб'
];
function loadSettings(){
const r=localStorage.getItem('hwRooms');
const p=localStorage.getItem('hwPerRoom');
if(r)document.getElementById('rooms').value=TOTAL_ROOMS=parseInt(r);
if(p)document.getElementById('perRoom').value=PER_ROOM=parseInt(p);
TOTAL_POINTS=TOTAL_ROOMS*PER_ROOM;
}
function saveSettings(){
localStorage.setItem('hwRooms',TOTAL_ROOMS);
localStorage.setItem('hwPerRoom',PER_ROOM);
}
function updateUI(){
document.getElementById('point').max=TOTAL_POINTS;
document.getElementById('point').placeholder=`1${TOTAL_POINTS}`;
document.getElementById('subtitle').textContent=`${TOTAL_ROOMS} комнат${TOTAL_ROOMS%10===1?'а':'ы'} × ${PER_ROOM} точек = 1${TOTAL_POINTS}`;
}
function applySettings(){
const r=parseInt(document.getElementById('rooms').value);
const p=parseInt(document.getElementById('perRoom').value);
if(!r||r<1||!p||p<1)return;
TOTAL_ROOMS=r;
PER_ROOM=p;
TOTAL_POINTS=TOTAL_ROOMS*PER_ROOM;
saveSettings();
updateUI();
document.getElementById('result').classList.remove('show');
renderRoomList();
}
function getRoomName(i){
return roomNames[i%roomNames.length]+(i>=roomNames.length?' '+(Math.floor(i/roomNames.length)+1):'');
}
function calc(){
const input=document.getElementById('point');
const error=document.getElementById('error');
const result=document.getElementById('result');
const output=document.getElementById('output');
const detail=document.getElementById('detail');
const val=parseInt(input.value);
error.classList.remove('show');
result.classList.remove('show');
if(!val||val<1||val>TOTAL_POINTS){
error.textContent=`Введи число от 1 до ${TOTAL_POINTS}`;
error.classList.add('show');
return;
}
const roomIdx=Math.floor((val-1)/PER_ROOM);
const pointInRoom=((val-1)%PER_ROOM)+1;
const roomName=getRoomName(roomIdx);
const firstPoint=roomIdx*PER_ROOM+1;
const lastPoint=(roomIdx+1)*PER_ROOM;
output.innerHTML=`${roomName} <span>— точка ${pointInRoom}</span>`;
detail.textContent=`${val}: точки ${firstPoint}${lastPoint}`;
result.classList.add('show');
addHistory(val,roomName,pointInRoom);
}
function addHistory(num,room,point){
const entry={num,room,point,time:Date.now()};
history.unshift(entry);
if(history.length>MAX_HISTORY)history=history.slice(0,MAX_HISTORY);
localStorage.setItem('hwHistory',JSON.stringify(history));
renderHistory();
}
function renderHistory(){
const el=document.getElementById('history');
const list=document.getElementById('historyList');
if(!history.length){el.classList.remove('show');return}
el.classList.add('show');
list.innerHTML=history.map((h,i)=>`
<div class="history-item" onclick="useHistory(${i})">
<span class="h-num">№${h.num}</span>
<span class="h-result">${h.room} — т.${h.point}</span>
<span class="h-copy" onclick="event.stopPropagation();copyResult(${i})" title="Копировать">📋</span>
</div>
`).join('');
}
function useHistory(i){
document.getElementById('point').value=history[i].num;
calc();
}
function copyResult(i){
const h=history[i];
const text=`${h.num}${h.room} — точка ${h.point}`;
navigator.clipboard.writeText(text).catch(()=>{});
}
function renderRoomList(){
const el=document.getElementById('roomList');
let html='<details><summary>📋 Все комнаты</summary>';
for(let i=0;i<TOTAL_ROOMS;i++){
const first=i*PER_ROOM+1;
const last=(i+1)*PER_ROOM;
html+=`<div class="rrow"><span>${getRoomName(i)}</span><span>точки ${first}${last}</span></div>`;
}
html+='</details>';
el.innerHTML=html;
}
document.getElementById('point').addEventListener('keydown',e=>{if(e.key==='Enter')calc()});
loadSettings();
updateUI();
renderRoomList();
renderHistory();
</script>
</body>
</html>