Кабинет: поиск клиентов с подсказками, чистая страница документов, ширина настроек

Поиск клиентов (режим сотрудника):
- поле поиска вынесено наверх страницы, рядом «Найти» и «Сбросить»;
- браузер сам подсказывает выпадающим списком по мере ввода — договоры
  депозитария отдаются страницей в <datalist> (скриптов в кабинете нет,
  CSP остаётся строгой), список кэшируется в ядре на 10 минут;
- по запросу фильтруются и учётки кабинета, и договоры депозитария,
  под формой показывается, сколько найдено;
- шаблон LIKE экранируется, чтобы % и _ в номере договора означали себя.

Документы: убраны пустое табло, «Мои заявки» и форма заказа документа —
остался список готовых документов депозитария и пояснение, куда обращаться.

Настройка: колонка сетки больше не растягивается широкой таблицей
(min-width:0), у страницы пропал горизонтальный ползунок.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4YVo4UMopqT5DzicqpPjL
This commit is contained in:
zuevav
2026-09-18 18:45:54 +03:00
parent 4b80d030ab
commit 683f516d07
7 changed files with 184 additions and 50 deletions
+57 -1
View File
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"strings"
"sync"
"time"
)
@@ -170,7 +171,7 @@ func depoListContracts(ctx context.Context, s FancyMSSQLSettings, search string,
JOIN OD_VALUES v ON v.ID = rst.VALUE_ID AND v.V_TYPE = 2
WHERE CAST(rst.K AS float) <> 0 AND (@p1 = '' OR p.PORT_NUM LIKE @p2)
GROUP BY p.PORT_NUM ORDER BY p.PORT_NUM`, limit)
rows, err := conn.QueryContext(cctx, q, search, "%"+search+"%")
rows, err := conn.QueryContext(cctx, q, search, "%"+likeEscape(search)+"%")
if err != nil {
return nil, err
}
@@ -226,3 +227,58 @@ func likeEscape(v string) string {
r := strings.NewReplacer("[", "[[]", "%", "[%]", "_", "[_]")
return r.Replace(v)
}
// ---- подсказки в поиске клиентов (админка ЛК) ----
// Список договоров нужен на каждой загрузке страницы «Клиенты»: браузер сам
// показывает выпадающий список по мере ввода (<datalist>), без скриптов на
// странице. Запрос дешёвый, но их 1300+, поэтому держим ответ в памяти.
var depoSuggestCache = struct {
mu sync.Mutex
list []string
at time.Time
}{}
// depoSuggestContracts — все номера договоров депозитария для подсказок поиска.
func depoSuggestContracts(ctx context.Context, s FancyMSSQLSettings) []string {
if strings.TrimSpace(s.Server) == "" {
return nil
}
depoSuggestCache.mu.Lock()
if time.Since(depoSuggestCache.at) < 10*time.Minute && depoSuggestCache.list != nil {
list := depoSuggestCache.list
depoSuggestCache.mu.Unlock()
return list
}
depoSuggestCache.mu.Unlock()
conn, err := fancyOpen(s, s.DepoDB())
if err != nil {
return nil
}
defer conn.Close()
cctx, cancel := context.WithTimeout(ctx, 20*time.Second)
defer cancel()
rows, err := conn.QueryContext(cctx,
"SELECT DISTINCT TOP (5000) PORT_NUM FROM OD_CLIENTS_PORTS WHERE PORT_NUM <> '' ORDER BY PORT_NUM")
if err != nil {
return nil
}
defer rows.Close()
var out []string
for rows.Next() {
var v string
if rows.Scan(&v) != nil {
break
}
if v = strings.TrimSpace(v); v != "" {
out = append(out, v)
}
}
if rows.Err() != nil && len(out) == 0 {
return nil
}
depoSuggestCache.mu.Lock()
depoSuggestCache.list, depoSuggestCache.at = out, time.Now()
depoSuggestCache.mu.Unlock()
return out
}