Создание гибкого каталога с фильтрами (list)

Общее устройство каталога List

В проекте можно реализовать несколько универсальных каталогов со своей разметкой и набором фильтров (товары, исполнители, заказы, проекты, портфолио и т.д). 

Расположены каталоги по адресу /list/{code}

Вид каталога по умолчанию такой (слева категории и фильтры, по центру - основные элементы):

Формат URL категории

Формат URL категории с фильтрами

Формат URL товара

Управление выведено в панели управления Администратора в Компоненты / Универсальные каталоги - /aslists

Таблица БД as_lists

См также HOWTO по каталогам List 

Вывод элементов каталога (список) - sp list_{code}_search

На входе: 

На выходе множество SELECT, на основе которых осуществляется вывод каталога: 

SELECT 1 результаты операции 

SELECT 2 Фильтры каталога слева (ID, Code, Title, Tooltip, TypeCode, DefValue, ShowCount, CommaValues, CommaSelected, Options, Placeholder)

SELECT 3 Дерево категорий, показывающих текущее положение в каталоге (ID, Code, Name, Level, URL, ParentID, Count)

SELECT 4 Вложенные категории  (ID, Code, Name, Level, URL, ParentID, Count)

SELECT 5 Элементы каталога (ID, Name, Desc, Price, Url, ImgUrl)

SELECT 6 Параметры элементов каталога  (ID, Code, Name, Value, ItemID)

SELECT 7 Дополнительные атрибуты для вывода на странице поиска  (ID, Code, Name, Value)

SELECT 8 Варианты сортировок (Key, Value)

SELECT 9 Начальное меню категорий (может выводиться наверху перед поиском, например, в самом корне каталога). 

Примечание: 

Пример процедуры search:

CREATE PROCEDURE [dbo].[list_new_search]
	@filters DictionaryParameter READONLY,
	@cats nvarchar(256),
	@sort nvarchar(24),
	@page int,
	@username nvarchar(32)
AS
BEGIN
	-- ПРОЦЕДУРА ПОИСКА ПО УНИВЕРСАЛЬНОМУ КАТАЛОГУ
        /*Определяем какие фильтры есть в url, и с учетом этого
          отбираем элементы для каталога*/

	-- Для пагинации
	declare @PAGE_SIZE int = 10, @total int = 0
        /*Сохраняем ID элементов каталога во временной таблице.
          Подсчитываем сразу полученное количество*/
	declare @itemIDs table (id int)

      /*Находим, на какой категории мы сейчас стоим, в общем дереве категорий
      @cats - это часть url где указаны категории, например для
       /list/suppliers/category1/category1_1/category1_1_3 будет @cats =
      'category1,category1_1,category1_1_3'*/

	CREATE TABLE dbo.#cats (id int, code nvarchar(256), name nvarchar(256), level
                                int, parentID int)
	insert into #cats
	select id, code, name, 1 [level], parentID
        from au_projectCategories
        where code in (select Value from dbo.split(@cats, ','))

	-- Выбранных категорий может быть несколько, с учетом вложенности вложенность
	declare @catCount int
	select @catCount = count(*) from #cats
	/* Находим конечную точку в дереве на которой остановились, то есть
           максимального уровня (в примере выше это будет category1_1_3)*/
	declare @selectedCatID int
	select top 1 @selectedCatID = id from #cats order by level desc

    -- Обработка возможных фильтров
    -- declare @filterCity nvarchar(256)
    -- select @filterCity = Value from @filters where [Key] = 'city'

    --- добавляем сортировку в Динамический запрос SELECT 1
    declare @sortStatement nvarchar(512)
    set @sortStatement = (case @sort
                    when 'rating' then ' order by name '
                    end	)

    -- Итак, что находим учитывая выбранные категории и отмеченные фильтры?
    insert into @itemIDs
    select distinct id
      from (select id, 111 catID
              from au_suppliers) t
    -- Категории поставщика входящие в выбранные категории, или в дочерние категории выбранных категорий
	where (isnull(@cats,'')='' or t.catID = @selectedCatID
            					or (select parentID from au_projectCategories where id = t.catID) = @selectedCatID )

	select @total = count(*) from @itemIDs

	-- SELECT 1 - SearchItemsResult (настройки поиска, общие параметры каталога)
	select 'Не найдено' EmptyText,
		   (case when isnull(@cats,'')='' then 'Каталог поставщиков услуг' else (select name from au_projectCategories where id = @selectedCatID) end) Title,
		   'desc' Text,
		   @sort Sort,
		   @page [Page],
		   @PAGE_SIZE PageSize,
		   @total Total,
		   'DEMO' SeoTitle,
		   'DEMO' SeoDescription,
		   'DEMO' SeoKeywords,
		   ''  HeadSection,
		   ''  BodyBottomSection,
		   1 Result,
  iif(@langID=1, 'SQL Server', 'SQL Server')  BreadcrumbRootTitle,
           iif(@langID=1, 'Home', 'Главная')+'||/' preBreadcrumbs,
            '' rightBreadcrumb,
            '' redirectUrl,
           301 redirectStatusCode,
           '' Msg
	-- SELECT 2 - FilterParameter - Показываем либо все услуги, либо относящиеся к выбранной категории
	select 1
    /*select 0 id,
    	   'Город' title,
		   'Город' tooltip,
		   'city' Code,
		   '' defValue,
		   'checks' typeCode,
		   (select stuff( (
						select ','+ name
						  from (select name from as_geo_regions) t1
						for xml path(''), type
						   ).value('.', 'varchar(max)'), 1, 1, ''
						 )
			) as  commaValues,
		   (select top 1 Value from @filters where [Key] = 'city') commaSelected,
3 showCount
*/

	-- SELECT 3 - Cat  CatChain - Выбранные категории
	select * from #cats order by level
	-- SELECT 4 - Cat  InnerCats - отобразим сбоку либо все категории, либо категории входящие в выбранную
    select *
    from au_projectCategories
	where parentID = @selectedCatID or (parentID is null and @catCount = 0)

	drop table #cats

	-- SELECT 5 - Item (ID, Desc, Price, Name, URL) -- Данные отображаемые в перечне элементов каталога
	select s.id,
		  isnull(surname+' '+firstname+' '+lastname, username) as name,
          '' [desc],
          '0' price,
          '/list/test/'+isnull(c.username,'')+'---'+try_cast(s.id as nvarchar) Url
	 from au_suppliers s join ctr_contacts c on c.id = s.contactID
     where s.id in (select id from @itemIDs)

	-- SELECT 6 - ItemParam
    -- Атрибуты элементов каталога
    -- Структура Атрибута: ID, Name, Code, Value, ItemID
    -- В разметке listItemMakeup атрибут отобразится по {param-code}
	select 1 as ID, 'Категории услуг' as Name, 'categories' as Code,
    	   'value1' as Value, 111 as ItemID
    union

    select 2 as ID,
    'О себе' as Name,
    'description' as Code,
    (select isnull(description,'О себе') from ctr_contacts where id = contactID) as value,
    id as ItemID  from au_suppliers

	-- SELECT 7 - Param общие Атрибуты для каталога (ID, Name, Code, Value)
    -- Атрибуты самого каталога
    -- Структура Атрибута: ID, Name, Code, Value
    -- В разметке listMakeup атрибут отобразится по {param-code}
	select 1

	-- SELECT 8 - DictionaryParameter  Sorts
	select 'rating' [key], 'По рейтингу' Value

	-- select 9 -- Start cats (категории которые показываются на 1 экране каталога как дашборд {catList})
	select id, code, name, 1 level, parentID,'' [Image],
    'fas fa-wrench' iconClass
	  from au_projectCategories where @selectedCatID is null and (parentID is null or parentID in (select id from au_projectCategories where parentID is null) )
END

Вывод карточки элемента каталога на отдельной странице - sp list_{code}_getItem 

Входные параметры: 

  1. @itemID - ID элемента 
  2. @username - текущий пользователь
  3. @parameters ExtendedDictionaryParameter readonly - опционально, содержит langID, falconGuid, url (только часть после /list/{code}/) и другие  параметры в виде Key, Value2

Результат работы процедуры GetItem: 

SELECT 1  Данные по выбранному элементу 

SELECT 2  Иерархия категорий к данному элементу, путь по категориям (ID, Code, Name, Level, URL, ParentID, Count)

SELECT 3  Дополнительные атрибуты элемента в виде таблицы (ID, Code, Name, Value, ItemID)

SELECT 4-8 Кастомные списки (используются только параметры с названиями p1, p2, p3, p4, p5, p6)

Примеры процедуры GetItem https://pastebin.com/WJFMKYTT

Примечание: 

Разметка каркаса страницы каталога - as_lists.listMakeup

 Параметры для вставки в разметку (используются как {name} и заменяются при рендеринге на данные из search процедуры):

Разметка одного элемента в каталоге (на странице поиска) - as_lists.listItemMakeup

Параметры (использовать как {code}):

Разметка карточки элемента (на отдельной странице) - as_lists: itemDetailsMakeup

Параметры (использовать как {code}): 

Примечания по каталогам List

Нюанс выбранной категории при построении адреса URL

Исходный базовый адрес должен учитывать текущую категорию:  

// startUrl - это /list/xx 
var url = $('.cat-cats li:last a').attr('href') || $('.cat-innerCats a.active').attr('href') ||  startUrl;

Либо это последний элемент в cat-cats (цепочка выбранных категорий), либо выбранный элемент из cat-innerCats (если это статичный список и всегода выводтся на странице. active определяется по полю url (текущий адрес включает в себя или нет URL этой категории) в SELECT 4 процедуры list_xx_search).

Если этого не учитывать, то текущая выбранная категория не будет учитываться при построении адреса (при пагинации или сортировке). 

Страница-источник на сайте falconspace.ru