using ClientModelsPrivate.Main.Menus; using ExtensionModules.Interfaces; using ExtensionModules.Interfaces.Extensions; using System; using System.Collections.Generic; using System.Linq; using FlowControl.Builder.Elements; using ParusClient.Activities; using System.Xml; using System.IO; using CommonActivities.Activities; using Common.Extensions; using CommonActivities.Activities.Common; using FlowControl.Core; using Parus.Database.Specialized; using System.Web; using FlowControl.Extensioins; //"Панели" - расширение для "ПАРУС 8 Онлайн" (библиотека для сервера приложений) namespace P8PanelsParusOnlineExt { //Вспомогательные методы public static class P8PanelUtils { //Имена специальных параметров "встроенных" методов public const string SPECIAL_PRM_CAPTION = "SCAPTION"; public const string SPECIAL_PRM_PANEL = "SPANEL"; public const string SPECIAL_PRM_IDENT = "NIDENT"; //Формирование адреса панели public static string BuildPanelURL(P8PanelConfig config, P8Panel panel, IDictionary parameters = null) { string panelUrl = config.panelsUrlBase; if (!panelUrl.EndsWith("/") && !panel.url.StartsWith("/")) panelUrl += "/"; panelUrl += panel.url; if (parameters != null) { var prms = ""; foreach (KeyValuePair entry in parameters) { if ((entry.Key != SPECIAL_PRM_CAPTION) && (entry.Key != SPECIAL_PRM_PANEL)) prms += entry.Key + "=" + HttpUtility.UrlEncode(Convert.ToString(parameters.SafeValue(entry.Key))) + "&"; } if (!string.IsNullOrEmpty(prms)) panelUrl += "?" + prms; } return panelUrl; } } //Настройки расширения [Serializable] public class P8PanelConfig { private List _menuApps = new List(); private List _menuItems = new List(); private List _panels = new List(); private string _panelsUrlBase; //Конструктор public P8PanelConfig(string confiFileName) { //Читаем указанный файл конфигурации как XML XmlDocument doc = new XmlDocument(); doc.Load(confiFileName); XmlNode section = doc.DocumentElement.SelectSingleNode("/CITK.P8Panels"); //Обходим десериализованный XML foreach (XmlNode sectionNode in section.ChildNodes) { //Настройки пунктов меню приложений if (sectionNode.Name == "MenuItems") { foreach (XmlNode menuAppNode in sectionNode.ChildNodes) { _menuApps.Add(new P8PanelMenuApp() { name = menuAppNode.Attributes["name"].Value }); foreach (XmlNode menuItemsNode in menuAppNode.ChildNodes) { _menuItems.Add(new P8PanelMenuItem() { app = menuAppNode.Attributes["name"].Value, parent = menuItemsNode.Attributes["parent"].Value, separator = menuItemsNode.Attributes["separator"] != null ? bool.Parse(menuItemsNode.Attributes["separator"].Value) : false, name = menuItemsNode.Attributes["name"]?.Value, caption = menuItemsNode.Attributes["caption"]?.Value, url = menuItemsNode.Attributes["url"]?.Value, panelName = menuItemsNode.Attributes["panelName"]?.Value }); } } } //Настройки панелей if (sectionNode.Name == "Panels") { _panelsUrlBase = sectionNode.Attributes["urlBase"].Value; foreach (XmlNode panelNode in sectionNode.ChildNodes) { _panels.Add(new P8Panel() { name = panelNode.Attributes["name"].Value, caption = panelNode.Attributes["caption"].Value, url = panelNode.Attributes["url"].Value, path = panelNode.Attributes["path"].Value, icon = panelNode.Attributes["icon"].Value, showInPanelsList = panelNode.Attributes["showInPanelsList"] != null ? bool.Parse(panelNode.Attributes["showInPanelsList"].Value) : false, }); } } } } //Поиск панели в настройке по наименованию public P8Panel FindPanelByName(string name) { return _panels.Find(panel => panel.name == name); } //Список приложений для подключения панелей public List menuApps { get => _menuApps; } //Список подключаемых к приложениям пунктов меню панелей public List menuItems { get => _menuItems; } //Настройки панелей public List panels { get => _panels; } //Базовый URL к WEB-приложению "Парус 8 - Панели мониторинга" public string panelsUrlBase { get => _panelsUrlBase; } } //Приложение панели [Serializable] public class P8PanelMenuApp { public string name { get; set; } } //Элемент меню панели [Serializable] public class P8PanelMenuItem { public string app { get; set; } public string parent { get; set; } public bool separator { get; set; } public string name { get; set; } public string caption { get; set; } public string url { get; set; } public string panelName { get; set; } } //Параметры панели [Serializable] public class P8Panel { public string name { get; set; } public string caption { get; set; } public string url { get; set; } public string path { get; set; } public string icon { get; set; } public bool showInPanelsList { get; set; } } //Обработчик "встроенного" метода открытия панели public class OpenPanelActivity : OpenExternalLinkActivity { private P8PanelConfig _pconf; private readonly IContextualParusDatabaseFactoryProvider _contextualParusDatabaseFactoryProvider; private string _contextCaption; private string _contextLink; //Конструктор public OpenPanelActivity(string caption, P8PanelConfig pconf, IContextualParusDatabaseFactoryProvider contextualParusDatabaseFactoryProvider) : base(caption, "stub") { _pconf = pconf ?? throw new ArgumentNullException("pconf"); _contextualParusDatabaseFactoryProvider = contextualParusDatabaseFactoryProvider ?? throw new ArgumentNullException("contextualParusDatabaseFactoryProvider"); } //Исполнение действия protected override void InternalExecute(IContext context) { //Читаем параметры из контекста if (context == null) throw new ArgumentNullException("context"); var parameters = context.SafeParameterValue("MethodParameterValues") as IDictionary; var nIdent = parameters.SafeValue(P8PanelUtils.SPECIAL_PRM_IDENT); var sPanel = (string) parameters.SafeValue(P8PanelUtils.SPECIAL_PRM_PANEL); _contextCaption = (string)parameters.SafeValue(P8PanelUtils.SPECIAL_PRM_CAPTION); //Определяем панель, которую будем открывать if (string.IsNullOrEmpty(sPanel)) throw new Exception("Не указан код панели. Проверьте, что задано значение параметра \"SPANEL\"."); P8Panel panel = _pconf.FindPanelByName(name: sPanel); //Если панель определена if (panel != null) { //Если был указан идентификатор отмеченных записей if (nIdent != null) { //Скопируем системный буфер отмеченных в буфер для панелей (чтобы не потерять при завершении транзакции) var parusDatabaseFactory = _contextualParusDatabaseFactoryProvider.GetDatabaseFactory(); using (var connection = parusDatabaseFactory.CreateConnection()) { using (var command = parusDatabaseFactory.CreateProcedure(connection, "PKG_P8PANELS.SELECTLIST_INIT")) { command.Parameters.Add(P8PanelUtils.SPECIAL_PRM_IDENT, (long) nIdent); command.ExecuteNonQuery(); } } } //Если не передали заголовок панели в параметрах - используем её заголовок из конфигурации if (string.IsNullOrEmpty(_contextCaption)) _contextCaption = panel.caption; //Сформируем ссылку на панель _contextLink = P8PanelUtils.BuildPanelURL(config: _pconf, panel: panel, parameters: parameters); } else throw new Exception($"Панель \"{sPanel}\" не определена."); //Выполним алгоритм родительского класса base.InternalExecute(context); } //Переопределение параметров открываемой закладки protected override IDictionary CreateClientParameters(IContext context) { //Сформируем словарь параметров открываемой закладки var clientParameters = base.CreateClientParameters(context); //Если удалось сформировать заголовок - переопределим его if (!string.IsNullOrEmpty(_contextCaption)) clientParameters.AddOrReplace(WellknownOpenMainTabActivityParameterNames.Caption, _contextCaption); //Переопределим адрес панели тем, который сформировали clientParameters.AddOrReplace(WellknownOpenMainTabActivityParameterNames.Url, _contextLink); //Вернём измененный словарь параметров return clientParameters; } } //Точка входа в модуль расширения public class Module : ExtensionModuleBase { private static string _configFile = Path.GetDirectoryName(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile) + "\\Config\\p8panels.config"; private static IList _hooks = new List(); public override string ModuleName => "P8Panels"; public override string AuthorInfo => "ЦИТК"; public override IList Hooks => _hooks; public override bool HasViews => false; //Конструктор public Module() { //Читаем и десериализуем настройки P8PanelConfig pconf = new P8PanelConfig(_configFile); //Вешаем хуки на создание элементов меню для всех упомянутых в настройках приложений pconf.menuApps.ForEach(menuApp => { _hooks.Add(MainMenuProcessorHook.Make(menuApp.name, mainMenu => { pconf.menuItems.ForEach(menuItem => { if (menuItem.app == menuApp.name) { var parentMenuItem = mainMenu.Root?.Children?.First(x => x.Value?.Name == menuItem.parent); parentMenuItem.Children.Add(new MainMenuItemNode { Value = new MainMenuItem { IsSeparator = menuItem.separator, Name = menuItem.name, Caption = menuItem.caption } }); } }); return mainMenu; })); }); //Вешаем хуки на нажатие всех сформированных элементов меню Dictionary> menuItemsActions = new Dictionary>(); pconf.menuItems.ForEach(menuItem => { if (!menuItem.separator) if (menuItem.panelName == null) menuItemsActions.Add(menuItem.name, () => new Sequence().Add(new { caption = menuItem.caption, url = menuItem.url })); else { P8Panel panel = pconf.FindPanelByName(name: menuItem.panelName); if (panel != null) menuItemsActions.Add(menuItem.name, () => new Sequence().Add(new { caption = panel.caption, url = P8PanelUtils.BuildPanelURL(config: pconf, panel: panel) })); else menuItemsActions.Add(menuItem.name, () => new Sequence().Add(new { caption = "Панель не определена", text = $"Панель \"{menuItem.panelName}\" не определена." })); } }); _hooks.Add(MainMenuItemBuilderHook.Make(menuItemsActions)); //Хуки "встроенных" действий с панелями в разделах _hooks.Add(MethodBuilderHook.Make(new Dictionary>{ { "P8PANELS_OPEN", () => new Sequence().Add(new { caption = "Панель", pconf = pconf }) } })); } //Путь к файлу конфигурации расширения public static string configFile { get => _configFile; } } }