Добрый день.

Как можно сделать более красивый DataGrid в Terrasoft 3.x 

В свойствах объекта DataGridСolumn есть возможность изменить цвет самой колонки, а как поменять шрифт и цвет самого текста, как заглавного, так и вывода?

Нравится

1 комментарий

Алексей, в первую очередь нужно уточнить версию софта. При переходе с 3.4.0 на 3.4.1 было добавлено много возможностей со шрифтами. Проверьте, может, получится и то, что хотите.

Если же делать что-то совсем нестандартное, может подойти компонент веб-браузера и программное создание HTML-файла. Именно так для продавцов квартир делалась «шахматка» — схема дома с проданными и непроданными квартирами разных цветов с возможностью открыть карточку квартиры по гиперссылке.

Показать все комментарии

Добрый день.

Подскажите, пожалуйста, как в Терассофт 3.х реализовать запуск функции, допустим нажатия кнопки, через 5 минут при этом не делая зависание программы. Я нажимаю на кнопку и запуская функцию. Работаю далее и через 5 минут мне выскочит сообщение "Привет мир!".

Нравится

2 комментария

Алексей, в 3.Х на карточке есть возможность добавить невизуальный компонент «Таймер». Можно задать в дизайнере или программно ему длительность, включить и добавить в обработчик нужную логику.

Спасибо за подсказку. Нашел решение здесь: https://community.terrasoft.ru/articles/obnovlenie-reestra-zapisei-s-op…

Показать все комментарии

Добрый день.

Подскажите, пожалуйста, есть задача в Terrasoft при нажатии на кнопку создавать массив элементов edit и label с названиями и именами. Плюс, нужно еще edit присвоить событие onchange.

Нравится

5 комментариев
Лучший ответ

Задачу решил так :

function PacientEmailForm(Window) {
    //Создание дополнительных компонентов для вывода массива данных для пациентов   
    try {
        var PacientLabel = null;
        var PacientName = null;
        var PacientDate = null;
        var PacientTest = null;
        var PacientText = null;
        var PacientNumber = 0;
        for (var i = 0; i < 2; i++) {
            //Создание метки для структуризации компонентов - ЗАГОЛОВОК
            PacientLabel = EmailFormWindowValue.CreateComponent('Label','lbPacient'+i);
            fgPacient.Add(PacientLabel);
            PacientLabel.AlignHorizontal = alhCenter;
            PacientLabel.AutoSize = true;
            PacientNumber = i+1;
            PacientLabel.Caption = 'Пациент № '+PacientNumber;
            //Создание поля вывода для имени пациента
            PacientName = EmailFormWindowValue.CreateComponent('Edit','edtPacientName'+i);
            fgPacient.Add(PacientName);
            PacientName.AlignHorizontal = alhClient;
            PacientName.Caption = 'ФИО';
            //Создание поля вывода для даты рождения пациента
            PacientDate = EmailFormWindowValue.CreateComponent('Edit','edtPacientDate'+i);
            fgPacient.Add(PacientDate);
            PacientDate.AlignHorizontal = alhClient;
            PacientDate.EditMask = '99.99.9999';
            PacientDate.Caption = 'Дата рождения';
            //Создание поля вывода для тестов
            PacientTest = EmailFormWindowValue.CreateComponent('Edit','edtPacientTest'+i);
            fgPacient.Add(PacientTest);
            PacientTest.AlignHorizontal = alhClient;
            PacientTest.Caption = 'Тесты и услуги';
            //Создание поля вывода для инвалидности
            PacientText = EmailFormWindowValue.CreateComponent('Edit','edtPacientText'+i);
            fgPacient.Add(PacientText);
            PacientText.AlignHorizontal = alhClient;
            PacientText.Caption = 'Инвалидности';
            //Скрыть все элементы и использовать по надобности
            PacientLabel.isVisible = false;
            PacientName.isVisible = false; 
            PacientDate.isVisible = false; 
            PacientTest.isVisible = false; 
            PacientText.isVisible = false;
        }        
        //var Pacient = Window.CreateComponent('Label','PacientLabel');
        //fgPacient.Add(Pacient); 
        //Pacient.Caption = 'Проверка!';
    } catch(E) {
        Log.Write(mdtError, '[PacientEmailForm] ' + E.message+' ['+E.number+']');
    } finally {}
}

Задачу решил так :

function PacientEmailForm(Window) {
    //Создание дополнительных компонентов для вывода массива данных для пациентов   
    try {
        var PacientLabel = null;
        var PacientName = null;
        var PacientDate = null;
        var PacientTest = null;
        var PacientText = null;
        var PacientNumber = 0;
        for (var i = 0; i < 2; i++) {
            //Создание метки для структуризации компонентов - ЗАГОЛОВОК
            PacientLabel = EmailFormWindowValue.CreateComponent('Label','lbPacient'+i);
            fgPacient.Add(PacientLabel);
            PacientLabel.AlignHorizontal = alhCenter;
            PacientLabel.AutoSize = true;
            PacientNumber = i+1;
            PacientLabel.Caption = 'Пациент № '+PacientNumber;
            //Создание поля вывода для имени пациента
            PacientName = EmailFormWindowValue.CreateComponent('Edit','edtPacientName'+i);
            fgPacient.Add(PacientName);
            PacientName.AlignHorizontal = alhClient;
            PacientName.Caption = 'ФИО';
            //Создание поля вывода для даты рождения пациента
            PacientDate = EmailFormWindowValue.CreateComponent('Edit','edtPacientDate'+i);
            fgPacient.Add(PacientDate);
            PacientDate.AlignHorizontal = alhClient;
            PacientDate.EditMask = '99.99.9999';
            PacientDate.Caption = 'Дата рождения';
            //Создание поля вывода для тестов
            PacientTest = EmailFormWindowValue.CreateComponent('Edit','edtPacientTest'+i);
            fgPacient.Add(PacientTest);
            PacientTest.AlignHorizontal = alhClient;
            PacientTest.Caption = 'Тесты и услуги';
            //Создание поля вывода для инвалидности
            PacientText = EmailFormWindowValue.CreateComponent('Edit','edtPacientText'+i);
            fgPacient.Add(PacientText);
            PacientText.AlignHorizontal = alhClient;
            PacientText.Caption = 'Инвалидности';
            //Скрыть все элементы и использовать по надобности
            PacientLabel.isVisible = false;
            PacientName.isVisible = false; 
            PacientDate.isVisible = false; 
            PacientTest.isVisible = false; 
            PacientText.isVisible = false;
        }        
        //var Pacient = Window.CreateComponent('Label','PacientLabel');
        //fgPacient.Add(Pacient); 
        //Pacient.Caption = 'Проверка!';
    } catch(E) {
        Log.Write(mdtError, '[PacientEmailForm] ' + E.message+' ['+E.number+']');
    } finally {}
}

Теперь возник вопрос, как удалить элемент созданный таким образом?

Алексей, если добавляли при помощи CreateComponent, то удалить, соответственно, можно по RemoveComponent. См. примеры в теме.

Зверев Александр,

Спасибо. Так и сделал. Правда со 2 попытки. Первая была DeleteComponent. А не подскажете, как событие присвоить Edit

.OnChange ?

Присваивают обработчики так, см. src_Main:

var MenuItem = Window.CreateComponent('ActionMenuItem', Name);
MenuItem.Caption = CaptionDataField.ValAsStr;
MenuItem.Tag = ParentIDDataField.ValAsStr;
SetObjectEventDispatcher(Window, MenuItem, MenuItem.Name, 'OnExecute',
	'DictionaryMenuItemOnExecute');

Если компонентов будет произвольное количество, можно обработчик сделать один и тот же, а в нём считывать значение свойства Tag, которое перед этим присвоить каждому разное.

Показать все комментарии

Добрый день.

Возникла интересная задача. Можно ли в Terrasoft сделать запуск функции Terrasoft из окна вывода html при событии click? 

Функция alert() обрабатывается нормально. А вот запуск функции, которая лежит в Terrasoft, как сделать? 

К примеру, в php и js связке можно обратится из js к php при помощи ajax. Есть ли тут аналог?

 

Нравится

1 комментарий

Алексей, такое возможно, так работают гиперссылки на разные сущности системы в почте. Ссылки стандартно есть на открытие карточки (open) и на переход в раздел с нужной записью (goto). Увидеть их обе можно, в реестре нажав правую кнопку и выбрав пункт «Копировать ссылку», они скопируются в буфер.

Чтобы сделать другие обработчики, нужно вносить правки в сервис scr_HyperlinkUtils, добавить в функции RunHyperlink дополнительное ветвление к тем двум, что там есть:

function RunHyperlink(Action, Params) {
	Action = Action.toLowerCase();
	switch (Action) {
		case 'goto':
			HyperlinkGotoWorkspace(Params);
			break;
		case 'open':
			HyperlinkOpenCard(Params);
			break;
	}
}

А затем написать аналогичную упомянутым функцию, выполняющую нужные действия в зависимости от параметров. Пример с запуском так БП есть тут.

 

Показать все комментарии

Добрый день.

Как реализовать многострочный заголовок в объекте DataGrid?

Дни недели | Рабочие часы | ФИО сотрудника

превратить в:

Дни       | Рабочие     | ФИО

недели | часы            | сотрудника

Нравится

5 комментариев

Алексей, в свойствах колонки в Dataset такое свойство настраивается, но оно предназначено для другого, общего заголовка для нескольких колонок:

Заголовок у меня есть

 

Но в Grid он не многострочный

 

Эта настройка для другого: если нескольким полям там вписать одинаковое до черты, то они сгруппируются с общей «шапкой». Пример настройки из этой темы:

Немного не то, но за это спасибо. Буду иметь ввиду функционал с |

Алексей, нашёл тему именно по тому, что Вы хотели. Увы, такого не прредумотрено.

Показать все комментарии

Добрый день.

Хочу реализовать такие функции. Данные, которые я планирую получать,  это значения с таблицы. Есть ли в террасофт возможнось напрямую сделать запрос к БД для получения нужных результатов?

К примеру, как на php mysql_query + mysql_feach_array

function FillMemoryDataset(Dataset) {
    var Items = GetAttribute(Dataset, 'Items');
    if (!Assigned(Items)) { return; }
    Dataset.DisableEvents();
    try {
        for (var i = 0; i < Items.length; i++) {
            var Item = Items[i];                    
            Dataset.Append();
            Dataset.ValAsInt('id') = Item['id'];
            Dataset.ValAsStr('type') = Item['type'];
            Dataset.ValAsStr('pricecode') = Item['pricecode'];
            Dataset.ValAsStr('title') = Item['title'];
            Dataset.ValAsStr('text_method') =
                PrepareTestInfoStringToSearch(Item['text_method']);
            Dataset.ValAsStr('material') =
                PrepareTestInfoStringToSearch(Item['material']);                
            Dataset.ValAsStr('is_block') = GetBlockedTestInformation(Item['pricecode']);                
            Dataset.ValAsStr('is_day') = GetDayTestInformation(Item['pricecode']);                
            Dataset.ValAsStr('is_stop') = GetStopedTestInformation(Item['pricecode']);
            Dataset.ValAsBool('is_custom') = (Item['is_custom'] == true);
            Dataset.Post();
        }
    }
    finally {
        Dataset.EnableEvents();  
        Dataset.GoToFirst();
    }
}
function GetBlockedTestInformation(pricecode)
{
    Result = '';

//Тут нужно получить данные из другого запроса sq_
    return Result;
}
function GetDayTestInformation(pricecode)
{
    Result = '';
    return Result;
}
function GetStopedTestInformation(pricecode)
{
    Result = '';
    return Result;
}

Нравится

7 комментариев
Лучший ответ

Сделал так

var ds = Services.GetNewItemByUSI('mds_KsCallInvitroApiTestAdds');
            ApplyDatasetFilter(ds, 'pricecode', Item['pricecode'], true); 
            var IsBlock = '';
            var IsDay = '';
            var IsStop = '';
            ds.Open();                
            IsBlock = ds.ValAsStr('is_block');
            IsDay = ds.ValAsStr('is_day');
            IsStop = ds.ValAsStr('is_stop');            
            ds.close();
            Dataset.ValAsStr('is_block') = IsBlock;                
            Dataset.ValAsStr('is_day') = IsDay;                
            Dataset.ValAsStr('is_stop') = IsStop;

Добрый день.

 

Вы можете реализовать представление (view) и использовать его в Вашем гриде.

 

Посмотрите похожая тема обсуждается здесь.

Возможно ли это функциями Террасофта провернуть без использования Dataset?

Сделал так

var ds = Services.GetNewItemByUSI('mds_KsCallInvitroApiTestAdds');
            ApplyDatasetFilter(ds, 'pricecode', Item['pricecode'], true); 
            var IsBlock = '';
            var IsDay = '';
            var IsStop = '';
            ds.Open();                
            IsBlock = ds.ValAsStr('is_block');
            IsDay = ds.ValAsStr('is_day');
            IsStop = ds.ValAsStr('is_stop');            
            ds.close();
            Dataset.ValAsStr('is_block') = IsBlock;                
            Dataset.ValAsStr('is_day') = IsDay;                
            Dataset.ValAsStr('is_stop') = IsStop;

Для тех кто хочет получить данные из другого dataset это прост отлично подходит

Алексей, кроме предложенного Аллой варианта есть и более простой штатный способ: можно в дизайнере sq настроить колонку-подзапрос или колонку с произвольным SQL-кодом, где и реализовать вычисление нужного значения или вызов SQL-функции.

Спасибо. Но для моей задачи подошел мой вариант. Так как основной dataset формируется не по sql, а с выборки в api и мне нужно было к нему приплюсовать еще и sq.

Алексей, сразу не заметил, что Вам нужно обязательно через программное наполнение полей MemoryDataset.

Если оба источника данных, и основной, и вспомогательный типа MemoryDataset, то так, как Вы написали.

А если вспомогательный — обычный Dataset, считывающий из базы по sq и ds, то его при желании тоже можно программно создать, наложить фильтр, открыть и считать значения полей.

 

Показать все комментарии

Добрый день.

 У мне при работе Выборки выбрасывает значения городов неверно, через LIKE, где мне в функции изменить фильтрацию по строгому соответствию.

function CreateSearchCityFilters(SelectQuery, SearchValue) {
    var FiltersGroupCode = 'SearchFilters';
    var Parameters = SelectQuery.Parameters;
    var Table = SelectQuery.Items(0).FromTable;
    var Filters = SelectQuery.Items(0).Filters;
    var FiltersGroup = Filters.ItemsByCode(FiltersGroupCode);
    if (FiltersGroup != null) {
        Filters.Remove(FiltersGroup);
    }
    FiltersGroup = Filters.CreateFilters();
    FiltersGroup.Code = FiltersGroupCode;
    FiltersGroup.LogicalOperator = lotAnd;
    FiltersGroup.IsNot = false;
    //Parameters.ItemsByName('SearchString').Value = Trim(SearchValue);
    var SearchValues = SearchValue.split(' ');
    var IsAddLikeFilter = false;
    for (var i = 0; i < SearchValues.length; i++) {
        var SearchValue = Trim(SearchValues[i]);
        if (IsEmptyValue(SearchValue)) { continue; }
        if (SearchValue.length < 3) { continue; }        
        var LikeParameterName = 'SearchLikeParameter'+i.toString();
        var LikeParameter = Parameters.ItemsByName(LikeParameterName);
        if (LikeParameter == null) {
            LikeParameter = Parameters.CreateItem();
            LikeParameter.Name = LikeParameterName;
            LikeParameter.DataType = pdtUnicodeString;
            Parameters.Add(LikeParameter);
        }    
        LikeParameter.Value = SearchValue;        
        var LikeFilterCode = 'SearchLikeFilter'+i.toString();
        var LikeFilter = Filters.ItemsByCode(LikeFilterCode);
        if (LikeFilter != null) {
            Filters.Remove(LikeFilter);     
        }
        LikeFilter = Filters.CreateLikeFilter();
        LikeFilter.Code = LikeFilterCode;
        var LikeTestExpression = LikeFilter.CreateFieldFilterExpression();
        var LikeValueExpression = LikeFilter.CreateParamFilterExpression();    
        LikeValueExpression.Parameter = LikeParameter;
        LikeTestExpression.Field = Table.Fields.ItemsByName('Name');
        LikeFilter.TestExpression = LikeTestExpression;
        LikeFilter.ValueExpression = LikeValueExpression;    
        LikeFilter.LikeType = ltContain;
        LikeFilter.IsEnabled = true;  
        FiltersGroup.Add(LikeFilter);
        IsAddLikeFilter = true; 
    }
    Filters.Add(FiltersGroup);
    if (IsAddLikeFilter) {
        return FiltersGroupCode;
    } else { return ''; }    
}

Нравится

2 комментария
Лучший ответ

Алексей, почему сразу неверно? В коде написали CreateLikeFilter, вот он и применяется. А у фильтра параметр типа равен ltContain, означающий поиск по вхождению. Эта константа, как и другие, определена в скрипте scr_SysEnums:

// Constants for enum _LikeTypeEnum
ltEqual = 0x00000000;
ltContain = 0x00000001;
ltStartsWith = 0x00000002;
ltEndsWith = 0x00000003;

Попробуйте для начала заменить ltContain на ltEqual.

 

Алексей, почему сразу неверно? В коде написали CreateLikeFilter, вот он и применяется. А у фильтра параметр типа равен ltContain, означающий поиск по вхождению. Эта константа, как и другие, определена в скрипте scr_SysEnums:

// Constants for enum _LikeTypeEnum
ltEqual = 0x00000000;
ltContain = 0x00000001;
ltStartsWith = 0x00000002;
ltEndsWith = 0x00000003;

Попробуйте для начала заменить ltContain на ltEqual.

 

Спасибо, помогли.

Показать все комментарии

Вопрос:

При входе в Terrasoft 3.X под новыми пользователями выдается ошибка открытия конфигурации «Could not convert variant of type (NULL) into type (olestr)»

В чём может быть проблема?

Ответ:

Такое сообщение «Could not convert variant of type (Null) into type (OleStr)» говорит о том, что у пользователя нет доступа на свой контакт и/или контрагент.

Для решения нужно: 

1)       Авторизуйтесь в системе под администратором, перейдите в Администрирование-Пользователи
2)       Кликните правой кнопкой на пользователе, под которым возникает ошибка входа, Перейти к -> Контакт и Перейти к -> Контрагент
3)       На детали «Доступ» к контакту добавьте пользователя, под которым происходит сбой или группу, в которую он входит.
4)       На детали «Доступ» к контрагенту добавьте пользователя, под которым происходит сбой или группу, в которую он входит.
5)       Проверьте корректность авторизации пользователя.

Нравится

Поделиться

0 комментариев
Показать все комментарии

Добрый день.

Есть кнопка объкет ILookupControl при нажатии на который исполняется следующая функция. Функция открывает окно но выборка в ней проходит не по указанному ListID. На выходе мы получаем хаос.

function edtEmailTypeID1OnPrepareSelectWindow(LookupControl, SelectWindow) {
    SetAttribute(SelectWindow, 'IsReadOnly', true);
    SetAttribute(SelectWindow, 'CanExport', false);
    SetAttribute(SelectWindow, 'CanPrint', false);
    SetAttribute(SelectWindow, 'IsMultiLineData', true);
    var Dataset = LookupControl.LookupDatasetLink.Dataset;
    EnableDatasetFilters(Dataset, true, 'IsVisibleIsTrue'); 
    var CampaignID = GetAttribute(Self, 'CampaignID');
    ApplyDatasetFilter(Dataset, 'CampaignID', CampaignID, true);
    var ListID = '{CC652229-77A5-4179-9D02-1478B31F1A1D}';
    ApplyDatasetFilter(Dataset, 'ListID', ListID, true);
}

Нравится

4 комментария

Алексей, вся логика фильтрации задана в сервисе sq для этого справочника. Проверьте, корректно ли заданы там условия фильтров IsVisibleIsTrue и ListID.

Порождаемый при открытии окна выбора из справочника запрос в базу можно увидеть в профайлере, внешнем или встроенном.

В sq_

SELECT
    [tbl_KsCallInvitroDictEnum].[ID] AS [ID],
    [tbl_KsCallInvitroDictEnum].[Name] AS [Name],
    [tbl_KsCallInvitroDictEnum].[Position] AS [Position]
FROM
    [dbo].[tbl_KsCallInvitroDictEnum] AS [tbl_KsCallInvitroDictEnum]
LEFT OUTER JOIN
    [dbo].[tbl_KsCallInvitroDictList] AS [tbl_KsCallInvitroDictList] ON [tbl_KsCallInvitroDictList].[ID] = [tbl_KsCallInvitroDictEnum].[ListID]
WHERE([tbl_KsCallInvitroDictList].[CampaignID] = :CampaignID AND
    [tbl_KsCallInvitroDictEnum].[ListID] = :ListID)
ORDER BY
    3 ASC,
    2 ASC

А фильтр с названием IsVisibleIsTrue, похоже, так и не включился. Возможно, дело в этом. Не видя всех настроек условий фильтрации в сервисе и без пояснения, что тут означает «хаос», сложно сказать.

Добрый день. Вы были правы. Внес в sq значение и все заработало. Спасибо

Показать все комментарии

Добрый день!

Подскажите можно ли в 3.х поменять сам логин пользователя без пересоздания нового пользователя к контакту?

 

Нравится

1 комментарий

Елена, да, можно, через базу. Я писал об этом статью: Как сменить логин в Terrasoft 3.X.

Показать все комментарии