Учёт DEPO: имя базы обязательно, bj базу по серверу не ищет

Имя базы DEPO задаёт клиент — скрипт и подготовка логином администратора
работают только с ней. Автопоиск по серверу убран (экран, скрипт, подготовка,
проверка подключения, старый экран conn), выбор из нескольких найденных баз —
тоже. Вместо поиска — защита от опечатки: скрипт (SQL Server и PostgreSQL),
подготовка и проверка подключения сначала убеждаются, что в названной базе
есть учётные таблицы OD_FACES и OD_RESTS, иначе останавливаются, ничего не
меняя.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
This commit is contained in:
zuevav
2026-10-06 15:18:15 +03:00
parent 237203f29a
commit 35f70a1b49
8 changed files with 118 additions and 219 deletions
@@ -78,7 +78,7 @@
.dq-sql { margin-top:14px; }
.dq-sql-head { display:flex; align-items:center; gap:8px; margin:0 0 6px; justify-content:flex-start; }
.dq-sql-st { flex:1; font-size:12.5px; color:var(--muted); }
.dq-sql-st.bad { color:var(--warn); }
.dq-sql pre:empty::before { content:attr(data-msg); color:var(--muted); font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif; font-size:13px; }
.dq-sql pre { max-height:380px; min-height:140px; font-size:12px; margin:0; transition:opacity .2s; }
.dq-sql pre.dq-busy { opacity:.5; }
.dq.is-pg [data-ms], .dq:not(.is-pg) [data-pg] { display:none !important; }
@@ -179,10 +179,9 @@
<div class="dq-grid dq-srv">
<label>Адрес сервера<input type="text" name="server" value="{{.Settings.Fancy.Server}}" placeholder="IP-адрес или имя\экземпляр" required autofocus spellcheck="false"></label>
<label>Порт<input type="text" name="port" value="{{if .Settings.Fancy.Port}}{{.Settings.Fancy.Port}}{{else if $pg}}5432{{else}}1433{{end}}" inputmode="numeric"></label>
{{if .DepoCands}}<label>Имя базы <span class="dq-opt">— выберите</span><select name="depo_database">{{range .DepoCands}}<option>{{.}}</option>{{end}}</select></label>
{{else}}<label>Имя базы <span class="dq-opt" data-ms>— необязательно</span><input type="text" name="depo_database" value="{{.Settings.Fancy.DepoDatabase}}" placeholder="bj найдёт сам" pattern="[A-Za-z][A-Za-z0-9_]*" title="латинские буквы, цифры и _, начинается с буквы" spellcheck="false" {{if $pg}}required{{end}}></label>{{end}}
<label>Имя базы<input type="text" name="depo_database" value="{{.Settings.Fancy.DepoDatabase}}" placeholder="как называется на сервере" required pattern="[A-Za-z][A-Za-z0-9_]*" title="латинские буквы, цифры и _, начинается с буквы" spellcheck="false"></label>
</div>
<p class="dq-note">{{if .DepoCands}}Логину bj видны несколько баз DEPO — выберите нужную.{{else}}<span data-ms>Не знаете имя базы — оставьте пустым: bj найдёт её сам по учётным таблицам OD_FACES и OD_RESTS.</span><span data-pg>Для PostgreSQL имя базы нужно указать.</span>{{end}}</p>
<p class="dq-note">Точное имя базы учёта DEPO — bj будет работать только с ней. Перед подготовкой bj проверит, что в ней есть учётные таблицы DEPO, и в чужую базу ничего не запишет.</p>
</section>
<section class="dq-s">
@@ -221,9 +220,9 @@
<div class="dq-sql-head copy-bar">
<span class="dq-sql-st" id="wiz-depo-st">Скрипт собирается из ответов выше и обновляется сам.</span>
<button type="button" id="wiz-depo-copy">Скопировать</button>
<button type="submit" formaction="/admin/setup/wizard-depo/script.sql" formnovalidate>Скачать файлом</button>
<button type="submit" formaction="/admin/setup/wizard-depo/script.sql">Скачать файлом</button>
</div>
<pre class="copyable" id="wiz-depo-sql"></pre>
<pre class="copyable" id="wiz-depo-sql" data-msg="Впишите имя базы DEPO — скрипт появится здесь."></pre>
</div>
<p class="dq-note"><span data-ms>Администратор выполняет скрипт в SSMS или sqlcmd под логином с правами sysadmin.</span><span data-pg>Администратор выполняет скрипт в psql суперпользователем (postgres).</span> Когда выполнит — нажмите «Проверить подключение».</p>
{{template "letterCard" (letter "dba")}}
@@ -240,13 +239,12 @@
</section>
</form>
<script>(function(){
var f=document.getElementById('wiz-depo'), pre=document.getElementById('wiz-depo-sql'), st=document.getElementById('wiz-depo-st');
var f=document.getElementById('wiz-depo'), pre=document.getElementById('wiz-depo-sql');
var timer=0, seq=0, last='';
function sync(){ // СУБД меняет подсказки, порт и обязательность имени базы; способ — какую панель показать
var pg=f.db_type.value==='postgres', m=f.mode.value, db=f.querySelector('input[name=depo_database]');
var pg=f.db_type.value==='postgres', m=f.mode.value;
f.classList.toggle('is-pg', pg);
if(pg&&f.port.value==='1433') f.port.value='5432'; else if(!pg&&f.port.value==='5432') f.port.value='1433';
if(db){ db.required=pg; db.placeholder=pg?'обязательно':'bj найдёт сам'; }
f.admin_user.placeholder=pg?'postgres':'sa';
['auto','script','existing'].forEach(function(k){ document.getElementById('wiz-depo-'+k).hidden=m!==k; });
}
@@ -259,9 +257,9 @@
fetch('/admin/setup/wizard-depo/script.sql',{method:'POST',body:body,headers:{'Content-Type':'application/x-www-form-urlencoded'},cache:'no-store'})
.then(function(r){return r.text().then(function(t){return {ok:r.ok,t:t}})})
.then(function(x){ if(my!==seq) return; pre.classList.remove('dq-busy');
if(x.ok){ pre.textContent=x.t; st.textContent='Скрипт собирается из ответов выше и обновляется сам.'; st.classList.remove('bad'); }
else { st.textContent=x.t.trim().replace(/^./,function(c){return c.toUpperCase()})+' — скрипт обновится, когда поправите.'; st.classList.add('bad'); } })
.catch(function(){ if(my!==seq) return; last=''; pre.classList.remove('dq-busy'); st.textContent='Не получилось собрать скрипт — обновите страницу.'; st.classList.add('bad'); });
if(x.ok){ pre.textContent=x.t; }
else { pre.textContent=''; pre.dataset.msg=x.t.trim().replace(/^./,function(c){return c.toUpperCase()})+' — скрипт появится здесь.'; } })
.catch(function(){ if(my!==seq) return; last=''; pre.classList.remove('dq-busy'); pre.textContent=''; pre.dataset.msg='Не получилось собрать скрипт — обновите страницу.'; });
}
function changed(){ sync(); clearTimeout(timer); timer=setTimeout(load, 350); }
f.addEventListener('input', changed); f.addEventListener('change', changed);