Мастер настройки — 4 главы (Сервер, Учёт и организация, НРД, Запуск) вместо 10 шагов: в пути только нужное этой установке — без лицензии учёта DEPO, QUIK и модулей их шагов нет, сделанное установщиком (база, Валидата) показано строкой; общая навигация «Назад/Далее»; раздел «Время и сеть» с часовым поясом; модули по лицензии (кабинет, ЕСИА Финанс, экспорт QUIK, НПР) с переходом в раздел и возвратом в мастер; «Проверить всю цепочку» (DEPO, QUIK, пробная блокировка по желанию, подпись, НРД); готовые письма в НРД, ARQA и администратору DEPO; ИШ с образа без интернета

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-05 18:04:29 +03:00
parent 7a5673e91f
commit f0dec0c238
22 changed files with 1020 additions and 129 deletions
+46 -35
View File
@@ -179,6 +179,15 @@ type WizardData struct {
AutoDone []string // шаги до текущего, уже выполненные без участия пользователя, — с пояснением
Certs []cryptocli.Certificate
Flash string
// главы мастера (wizchapters.go): путь этой установки, соседние шаги, шапка
Path []int
Chapters []WizChapter
Prev, Next int
StepDone bool
StepRequired bool
StepTitle string
ChapterTitle string
Modules []WizModule // глава «Запуск»: модули по лицензии
Done struct {
License bool
Depo bool
@@ -190,6 +199,8 @@ type WizardData struct {
NSD bool
TestRun bool
Alerts bool // оповещения настроены и резервные копии включены
Modules bool // модули по лицензии настроены
Server bool // время сервера синхронизируется
}
}
@@ -247,23 +258,43 @@ func (h *setupHandlers) renderWizard(w http.ResponseWriter, r *http.Request) {
d.Done.NSD = doneNSD(s)
d.Done.TestRun = s.LastTest != nil || (!d.DevMode && readinessDone()) // вне режима разработки — итоговая проверка готовности пройдена
// Мастер идёт по порядку: каждый шаг показывается, даже если он уже выполнен (установщиком,
// лицензией) — на нём написано, что сделано, и пользователь сам нажимает «Далее». Без ?step
// продолжаем со следующего за последним пройденным шагом.
progress := wizardProgress()
step := progress + 1
d.Done.Org = doneOrg(s)
d.Done.Alerts = doneAlerts(s)
d.Done.Quik = !d.DepoLicensed || doneQuik(s)
d.Modules = wizModuleViews(h.rc, s)
d.Done.Server, _ = timeStatus(r.Context())
d.Done.Modules = true
for _, m := range d.Modules {
if !m.Ready {
d.Done.Modules = false
}
}
// Главы (wizchapters.go): в пути только шаги, нужные этой установке — по лицензии и без сделанного
// установщиком. Без ?step — первый несделанный обязательный шаг, а если всё сделано — проверка.
done := map[int]bool{1: d.Done.License, 2: d.Done.Postgres, 3: d.Done.Depo, 4: d.Done.Org, 5: d.Done.Quik, 6: d.Done.Crypto,
7: d.Done.NSD, 8: d.Done.Certs, 9: d.Done.Alerts, 10: d.Done.TestRun, 11: d.Done.Modules, 12: d.Done.Server}
path, _ := wizPath(h.rc, done, 0)
step := wizDefaultStep(path, done)
if v := r.URL.Query().Get("step"); v != "" {
if n, err := strconv.Atoi(v); err == nil && n >= 1 && n <= wizardSteps {
step = n
if n-1 > progress {
setWizardProgress(n - 1)
}
}
}
if step > wizardSteps {
step = wizardSteps
}
d.Step = step
d.Path, d.Chapters = wizPath(h.rc, done, step)
d.Prev, d.Next = wizNeighbours(d.Path, step)
d.StepDone, d.StepRequired, d.StepTitle = done[step], wizRequired[step], wizStepTitles[step]
for _, c := range d.Chapters {
if c.Current {
d.ChapterTitle = c.Title
}
}
if done[2] {
d.AutoDone = append(d.AutoDone, "База bj создана установщиком"+pickStr(" — "+d.PGSummary, ""))
}
if done[6] {
d.AutoDone = append(d.AutoDone, "СКЗИ «Валидата Клиент L» "+d.ValidataVer+" установлена вместе с bj")
}
if step == 4 && strings.TrimSpace(s.Fancy.Server) != "" && !doneOrg(s) && depoDetectResult() == nil {
// организация ещё не задана, а база DEPO подключена — определяем реквизиты сами: карточка
// покажет их заполненными, пользователю остаётся проверить и сохранить
@@ -278,7 +309,7 @@ func (h *setupHandlers) renderWizard(w http.ResponseWriter, r *http.Request) {
}
cancel()
}
if (step >= 3 && step <= 5) || step == 9 { // DEPO, организация, QUIK МНП, оповещения и копии — общие блоки из «Настройки»
if (step >= 3 && step <= 5) || step == 9 || step == 11 { // DEPO, организация, QUIK МНП, оповещения и копии, модули — общие блоки из «Настройки»
fd := h.setupData(w, r, "")
d.Fancy = &fd
}
@@ -288,9 +319,6 @@ func (h *setupHandlers) renderWizard(w http.ResponseWriter, r *http.Request) {
d.Sub = "done"
}
}
d.Done.Org = doneOrg(s)
d.Done.Alerts = doneAlerts(s)
d.Done.Quik = !d.DepoLicensed || doneQuik(s)
if step == 3 && d.DepoLicensed && strings.TrimSpace(s.Fancy.Server) != "" {
// Есть ли у сервера SQL Agent: у Express его нет, у PostgreSQL — тоже; тогда обработку
// запускает сам bj. Иначе по умолчанию джобу SQL Agent создаёт bj.
@@ -334,26 +362,7 @@ func depoServerEdition(ctx context.Context, f FancyMSSQLSettings) (string, bool)
// wizardSteps — шагов в мастере: 1 лицензия, 2 база bj, 3 учёт DEPO, 4 наша организация, 5 QUIK МНП,
// 6 Валидата, 7 шлюз НРД, 8 ключ и сертификаты (ключ ставится в профиль ИШ — после шлюза),
// 9 оповещения и резервные копии, 10 проверка готовности.
const wizardSteps = 10
// wizardProgressFile — номер последнего пройденного шага мастера (переход «Далее» на шаг N
// означает, что шаги до N пройдены).
const wizardProgressFile = "/var/lib/bj/.bj/wizard-progress"
func wizardProgress() int {
b, err := os.ReadFile(wizardProgressFile)
if err != nil {
return 0
}
n, _ := strconv.Atoi(strings.TrimSpace(string(b)))
return n
}
func setWizardProgress(n int) {
if err := os.WriteFile(wizardProgressFile, []byte(strconv.Itoa(n)+"\n"), 0o600); err != nil {
log.Printf("wizard: прогресс мастера не сохранён: %v", err)
}
}
const wizardSteps = 12 // 11 — модули по лицензии (глава «Запуск»), 12 — время и сеть (глава «Сервер»)
// dsnSummary — «host:port, база name» из строки подключения PostgreSQL, без логина и пароля.
func dsnSummary(dsn string) string {
@@ -448,6 +457,7 @@ func (h *setupHandlers) testSignCrypto(w http.ResponseWriter, r *http.Request) {
// SetupData — данные для шаблона admin_setup.html.
type SetupData struct {
page
FromWizard bool // раздел открыт из мастера (настройка модуля) — показать «Вернуться в мастер»
Settings Settings
Suggest *DepoRequisites // предложение реквизитов из DEPO
Readiness []Readiness
@@ -537,6 +547,7 @@ func (h *setupHandlers) setupData(w http.ResponseWriter, req *http.Request, flas
License: licenseStatus(h.rc),
Health: HealthSnapshot(),
AdvancedUnlocked: advancedUnlocked(req),
FromWizard: req.URL.Query().Get("from") == "wizard",
NSDCerts: nsdCertsView(s),
Participants: handbookParticipants(),
OrgINN: orgINN(s),