Кабинет: поиск клиентов с подсказками, чистая страница документов, ширина настроек
Поиск клиентов (режим сотрудника): - поле поиска вынесено наверх страницы, рядом «Найти» и «Сбросить»; - браузер сам подсказывает выпадающим списком по мере ввода — договоры депозитария отдаются страницей в <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:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user