1. Во вкладке "Файлы и примечания" необходимо Панель инструментов перенести вниз. Прилагаю изображения "как есть" и "как нужно".

 

2. Если файл/ таблица, размещенная там большая по размеру, то появляется прокручивание. Можно ли отображать все полностью без прокручивания? ( Прилагаю изображения "как есть" )

Нравится

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

Этот редактор реализован на стороннем компоненте CKEditor.

Согласно его документации, для переключения панели вниз нужно изменить одно свойство с top на bottom:

config.toolbarLocation = 'bottom';

Этот компонент реализован в js-файле ядра, как он меняется, написано тут. Но тогда поменяется всюду по системе, да и правки ядра не всегда возможны и не очень правильны.

По прокрутке аналогично, тут и тут, это задаётся в CSS.

Лучше будет переопределить свойства на уровне схемы в конфигурации.

 

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

Спасибо большое! Попробуем воспользоваться) 

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

Мне с удаленного сервера  приходит файл, который я хочу сохранить в creatio, каким образом это реализовать и куда сохранять, когда получу его?

Нравится

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

Дмитрий, где именно Вы хотите это выполнять?

Если извне, то есть стандартный FileApiService, примеры работы с ним см. тут. Перед этим нужно ещё выполнить авторизацию.

 

Если же Вы хотите это делать это в серверной логике 7.Х, то нужно делать примерно то, что делается внутри этого сервиса, писать данные в поле Data записи о файле в таблице ...File от нужного раздела. См. пояснение в комментарии тут

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

Добрый день!

Считаю, что была бы полезной функция наглядного наличия вложенного файла в Обращении,

например, такого вида:

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

Если реализовывать самостоятельно такую логику, проще всего будет доработать присвоение номера при создании обращения или добавить его изменение. Скрепку можно выводить как символ: ?.Только учесть, чтобы не сломалась привязка писем по номеру обращения в них.

Или, чтобы не трогать номер, вывести в реестр ещё одну текстовую колонку, куда и писать при помощи БП эту скрепу. Но тогда не будет видно в справочном поле со ссылкой на обращение, а только в реестре раздела или детали.

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

Доброго времени суток.

Желательно присутствие бывалых Одинов, которые повидали многое в данном продукте.
В продолжение предыдущего поста было принято решения не отходить от стандартной реализации отправления файла, используя FileAPI.

На данный момент были созданы на основе базовых схем, следующие схемы:
аналог FileUploadInfo,
аналог IFileUploadInfo,
KmFileUploadService - аналог сервиса FileApiService,
аналог FileUploader аналог.

Так же была заимствована логика подготовки и отправки файла до FileAPI из FileDetailV2 и ConfigurationFileApi.

При выборе некого файла (если помните ранее писал про кнопку Selec file, клик которой создает скрытый input с type = file и реализует клик по нему) после логики схем FileDetailV2 и ConfigurationFileApi файл попадает в FileAPI, где на мой взгляд происходит его подготовка и разбиение на Chunk (далее Чанки).
После всех манипуляций дынный Api посылает его в KmFileUploadService
 , который вызывает унаследованный FileUploader, конкретно метод Upload, где происходит проверка размера файла, а далее ведется проверка связанная с Чанками (!fileUploadInfo.IsChunkedUpload || fileUploadInfo.IsFirstChunk) и в зависимости от проверки запускается метод Save или AppendData.

Как только текущий Чанк попадает в Save, исходя из нашей логики я организовываю запросы на Ftp по созданию файла (ничего такого, чего нет на MSDN).
Далее как я понимаю идёт обратный запрос к FileAPI который в свою очередь отдает нам следующий Чанк, который попадает в AppendData.

Базовая реализация этого метода подразумевает вызов метода DBLobUtilities.AppendBlob.
В нашем случае мы не используем этот метод, так как сохранение файла в базу у нас не велось. Мы используем аналогичный подход как в нашем Save только указываем WebRequestMethods.Ftp.AppendFile ,который должен нам исходя из следующего Чанка дописать ранее созданный экземпляр файла. По завершению этого действия по идее должен быть обратный ответ от FileAPI, который вышлет нам следующий Чанк и так далее пока все Чанки не кончатся, но этого не происходит. См. приложенный скриншот.

Итак самое главное вопросы:
1. Не удалось найти реализацию базового метода DBLobUtilities.AppendBlob, т.е. что он выполняет и каким образом запросы к FileAPI не прерываются. Потому что в нашем случае весь процесс состоит из двух Чанков, + второй Чанк сильно переписывает и ломает тело файла.
2. Хотелось бы узнать существует ли возможность в наш сервис передать кастомное значение типа пункта назначения фолдера, куда сохранять файл. Есть подозрения что нужно будет расширить FileUploadInfo и интерфейс который он использует, и обязательно расширить UI методы который формируют объект для FileAPI.

 

P.s. если не использовать данный подход, а работать с обыкновенным FileReader и читать тело файла readAsDataURL то всё бы ничего, но вот если файл весит свыше 10мб у сервиса начинается батхерт со временем обработки запроса.

Нравится

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

Не понимаю зачем зарывать в такие дебри. У меня сработало так:

1) Создал миксин, обрабатывающий  клик и загрузку.

define("TmUploadMixin", ["MaskHelper", "ConfigurationFileApi"],
	function(MaskHelper) {
 
		Ext.define("Terrasoft.configuration.mixins.TmUploadMixin", {
		alternateClassName: "Terrasoft.TmUploadMixin",
 
		/**FILE_IMPORTER**/
		onFilesSelected: function(file, tag) {
			if (file.length <= 0) {
				return;
			}
			var config = this.getUploadConfig(file, tag);
			this.upload(config);
		},
		getUploadConfig: function(file, tag) {
			return {
				uploadWebServicePath: "TmFilesUploader/Upload", // "FileApiService/Upload"
				scope: this,
				columnName: "columnName",
				parentColumnName: "parentColumnName",
				parentColumnValue: "parentColumnValue",
				onFileComplete: this.onFileComplete,
				entitySchemaName: tag,
				files: file,
				isChunkedUpload: false
			};
		},
		upload: function(config) {
			MaskHelper.ShowBodyMask();
			Terrasoft.ConfigurationFileApi.upload(config);
		},
		onFileComplete: function(error, xhr, file, options) {
			MaskHelper.HideBodyMask();
			//debugger;
			var data = JSON.parse(Terrasoft.decode(xhr.responseText));
			if (data.error !== "False") {
				this.showInformationDialog("Ошибка импорта. Подробнее — в консоли");
				console.log(data.data);
			} else {
				this.showInformationDialog("Записей импортировано: "+data.data);
				//this.reloadGridData();
			}
		}
 
	});
	return Terrasoft.TmUploadMixin;
});

 

2) Создал сервис

namespace Terrasoft.Configuration.TmFilesUploader
{
	using System;
	using System.IO;
	using System.Net;
	using System.Data;
	using System.Runtime;
	using System.Collections.Generic;
	using System.Runtime.Serialization;
	using System.ServiceModel;
	using System.ServiceModel.Web;
	using System.ServiceModel.Activation;
	using System.Web;
	using System.Web.SessionState;
	using Terrasoft.Common;
	using Terrasoft.Core;
	using Terrasoft.Core.Factories;
	using Terrasoft.Core.Entities;
	using Terrasoft.Configuration.FileUpload;
	using Terrasoft.Web.Common;
 
 
	[ServiceContract]
	[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
	public class TmFilesUploader : BaseService, IReadOnlySessionState
	{
		[Obsolete]
		public const string HeaderContentRange = "Content-Range";
		[Obsolete]
		public const string HeaderRange = "Range";
		[Obsolete]
		public const string HeaderContentDisposition = "Content-Disposition";
 
		[OperationContract]
		[WebInvoke(Method = "POST", UriTemplate = "Upload", ResponseFormat = WebMessageFormat.Json)]
		public string Upload(Stream fileContent) {
			string value;
			bool error=false;
			try {
				IFileUploadInfo fileUploadInfo = new FileUploadInfo(fileContent, new HttpRequestWrapper(HttpContext.Current.Request);
				/**стрим будет валяться в fileUploadInfo.Content**/
			} catch (Exception ex) {
				value = ex.Message+"|"+ex.Source+"|"+ex.StackTrace+"|"+ex.InnerException;
				error = true;
			}
 
			return "{\"error\":\"" + error + "\",\"data\":\"" + value + "\"}";
		}
	}
}

И как бы всё... Ну единственно отрубил chunkedUpload и оставил дефолтный террасофтовский метод по проверке веса файла (думаю можно отредактировать если надо)

Варфоломеев Данила пишет:
Варфоломеев Данила

Добрый день/ночь, вот что получаем в итоге при ~20+ мб весом файла, ограничение Террасофта в настройке повысил. Понимаю что файл надо разбить каким-то образом на осмысленные части и грубо говоря из сервиса append'ить эти части между собой. Но мысли пока зашли в тупик.

Есть предположения у Вас коллега? 

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

Добрый день!
Возвращаясь к filestream (топик https://community.terrasoft.ru/forum/topic/5410), можно его все-таки использовать в Террасофте для таблицы файлов или нет?
TS 3.4.1.
SQL 2014
Террасофт умеет работать с данными типа varbinary(max) filestream?

1) включили возможность файстрима на сервере
2)создали файловую группу для базы
3)в качестве проверки функциональности создали новую таблицу через sql, там поле varbinary(max) filestream-засунули туда данные через sql - ну тут все ок
4) добавили в таблицу tbl_Files новое поле FileData1 varbinary(max) filestream; (перед этим пришлось удалить триггер к этой таблице - на instead of delete)
5) Пошли в террасофт администратор, там взяли в таблице tbl_Files, полe FileData сменила на FileData1 (не меняя при этом тип, и не сохраняя в бд потом таблицу (потому как не видим типа varbinary в приложении), пошли в sq_Files - там выбрали FileData1 вместо FileData.
6) Зашли в террасофт, добавили файл, файл даже добавился файловую группу, но террасофт его не может потом прочесть, потому что видимо не подозревает про тип варбинари с признаком файлстрим

Есть пути решения?

Нравится

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

Работа с filestream обсуждалась тут и тут. Также тут обсуждают альтернативные реализации с хранением в другой базе.

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

Добрый день!

Как в TS 3.X лучше работать с zip-архивами (распаковать файлы, упаковать файлы)?

Нравится

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

Думаю, стоит использовать какой-то COM-объеккт и вызывать его методы. Например, стандартный в Windows объект Shell.Application тоже умеет работать с ZIP.

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

Самый простой способ, это использовать встроенный Zip-архиватор ОС Windows.

Пример использования:

function Main() {
    var zFolder = "c:\\log.zip";
    var eFolder = "c:\\log";
 
    ExtractFileFromZip(zFolder, eFolder);
    CompriseFileToZip(eFolder, zFolder);
}
 
function ExtractFileFromZip(PathFrom, PathTo) {
    var FSO = new ActiveXObject("Scripting.FileSystemObject");
    var App = new ActiveXObject("Shell.Application");
    if (FSO.FolderExists(PathTo)) {
    	FSO.DeleteFolder(PathTo, true);
    }
    FSO.CreateFolder(PathTo);
    var FolderPathTo = FSO.GetFolder(PathTo).Path;
    var FolderPathFrom = App.Namespace(FSO.GetFile(PathFrom).Path);
    var ZipItems = App.Namespace(FolderPathFrom).Items();
    App.Namespace(FolderPathTo).CopyHere(ZipItems);
}
 
function CompriseFileToZip(PathFrom, PathTo) {
    var Str = "PK%05%06%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00";
    var ForWriting = 2;
    var FSO = new ActiveXObject("Scripting.FileSystemObject");
    var App = new ActiveXObject("Shell.Application");
    if (FSO.FileExists(PathTo)) {
    	FSO.DeleteFile(PathTo, true);
    }
 
    var Itm = FSO.OpenTextFile(PathTo, ForWriting, true);
    Itm.Write(unescape(Str));
    Itm.Close();
 
    var Enm = new Enumerator(FSO.GetFolder(PathFrom).Files);
    for (; !Enm.atEnd(); Enm.moveNext()) {
    	Itm = Enm.item();
    	App.Namespace(FSO.GetFile(PathTo).Path).CopyHere(Itm.Path);
	}
}
Показать все комментарии

Добрый день!
Как можно выгрузить все файлы из детали файлы и ссылки в сетевую папку на диск?
Сделать это нужно программно.

Нравится

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

Добрый день, Александр!

bpmonline не предполагает таких операций. Тем не менее данную задачу можно попробовать реализовать через бизнес процесс. Вам необходимо перебрать все записи в соответствующей таблице (объекте). Для каждого раздела объект "Файлы и ссылки" свой (как и таблица в базе данных).

1) Начальный элемент
2) Получение данных о файле элементом "Чтение данных"
3) "Исключающее ИЛИ" с двумя условными потоками (если файлов для выгрузки больше нет, то конец процесса), иначе идем дальше.
4) Элемент "Задание-сценарий" с приблизительным кодом:

   public static string SaveDecompressFile(string FileName, SqlBytes CompressedFile)
    {
        if (CompressedFile.IsNull)
        return "Error";
 
        DeflateStream decompress = new DeflateStream(CompressedFile.Stream, CompressionMode.Decompress, true);
 
        try
        {
 
            FileStream file = File.Create(FileName);
 
            int sourcebyte = decompress.ReadByte();
            while (sourcebyte != -1)
            {
                file.WriteByte((byte)sourcebyte);
                sourcebyte = decompress.ReadByte();
            }
 
            file.Close();
        }
 
        catch (Exception)
        {
            return "Error";
        }
 
        finally
        {
            decompress.Close();
            decompress = null;
        }    
 
        return "OK";
    }

(источник)

Далее возвращаемся на элемент "Чтение данных".

В таком бизнес процессе необходимо будет увеличить максимальное число повторений (настраивается в свойствах процесса).

Все оказалось даже проще.
Может кому-то пригодится
Для работоспособности в using нужно добавить System.IO

//получаем stream из Entity 
MemoryStream ms=documentFile.GetStreamValue("Data");
//записываем его в файл
ms.SaveToFile(dir+name);  

ниже приведен полный код метода, используемого в сервисе

 [OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped,
    RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
public void fileUnloadling(
	string documentId, //Id докумена
	string documentNumber
	)
{
	if (System.Diagnostics.Debugger.IsAttached)
	{
	    System.Diagnostics.Debugger.Break();
	}
	var UserConnection = (UserConnection)HttpContext.Current.Session["UserConnection"];
	var dir=Terrasoft.Core.Configuration.SysSettings.GetValue(UserConnection, "SxFilePathForUnloading")+documentNumber+"\\";
	EntitySchema schema = UserConnection.EntitySchemaManager.GetInstanceByName("DocumentFile");
    EntitySchemaQuery esq = new EntitySchemaQuery(schema);
    esq.AddAllSchemaColumns();
    esq.Filters.Add(esq.CreateFilterWithParameters(FilterComparisonType.Equal, "Document", documentId));
    esq.Filters.Add(esq.CreateFilterWithParameters(FilterComparisonType.Equal, "Type", "529BC2F8-0EE0-DF11-971B-001D60E938C6")); //тип файл
 
    EntityCollection documentFileEntities = esq.GetEntityCollection(UserConnection);
    foreach (Entity documentFile in documentFileEntities  )
    {
        var name=documentFile.GetTypedColumnValue<string>("Name");
		MemoryStream ms=documentFile.GetStreamValue("Data");
        try
		{
			if (!Directory.Exists(dir))
                    {
                        Directory.CreateDirectory(dir);
                    }
			ms.SaveToFile(dir+name);  
		}
		catch (Exception e) 
		{
 
		}
    }
 
}    }

Пащенко Александр Сергеевич

а как мы определяем из детали какого объекта файлы и ссылки и какой именно записи это объекта забираем файлы?

Сафронов Иван Александрович,

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

Какая у Вас задача?

Пащенко Александр Сергеевич,

После завершения активности хотелось бы выгружать все приложенные файлы на детали Файлы и ссылки в отдельную папку в хранилище.

Сафронов Иван Александрович,

Тогда можете в БП отловить сигналом завершение активности, а дальше скриптом выгружать из ActivityFile.

Учтите, что в детали еще могут быть ссылки. Нужно в запрос добавить фильтр по типу

Схемы файлов обычно называются по шаблону [название раздела] + "File"

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

bpm 7.2 on-site

Можно ли сделать, чтобы файлы не скачивались, а сразу предлагалось открытие системой?
Или только через ссылки, так можно сделать?

Нравится

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

Здравствуйте, Илья.

Вам необходимо активировать настройку в используемом Вами браузере:

Google Chrome:

http://i62.fastpic.ru/big/2014/0523/33/6e4b9e46c9a40fe7d09b623db5e6dc33.png

Mozilla Firefox:

http://i62.fastpic.ru/big/2014/0523/33/0ce94959f221827fa4b780f59028e133.png

"Соколов Илья Андреевич" написал:файлы не скачивались, а сразу предлагалось открытие системой

Это абсурд в контексте современных представлений о безопасности браузеров

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

Имеется деталь "контакты" и у каждого контакта есть, привязанные к нему файлы. Мне необходимо на другой детали получить список привязанных файлов. В дереве нашел dataset ds_Files (при выводе этих данных на экран все работает - выводятся все файлы для всех контактов). Дело остается за малым - отфильтровать по ContactID, однако данное поля в датасете ds_Files нет. Я не могу найти это самое связующее поле. Кто-нибудь знает?

Нравится

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

Если вдруг кому-нибудь пригодится:

Все файлы хранятся в таблице tbl_Files, информация о принадлежности файла к записям разделов хранится в таблицах развязки (например, tbl_FileInAccount, tbl_FileInContact).

Соответственно, для получения названия файла (колонка Link таблицы tbl_File), Вам необходимо получить идентификатор записи файла из таблицы развязки, отфильтровав записи по идентификатору записи раздела. Затем, получить информацию из таблицы файлов по идентификатору.

Здравствуйте, Александр Сергеевич!

У Вас остались еще вопросы касательно данной темы?

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

Добый день!
Опишу задачу для начала.
В карточке редактирования раздела есть вкладки конкретно "Ежегодная отчетность".
Собственно в ней два контейнера окон.
1. Это Ежегодная отчетность .
2. Это файлы что крепятся к созданным отчетам.
В принципе все работает добавляю запись в первую таблицу к ней могу крепить файлы но! Когда прицепляю файл у меня выскакивает ошибка (см. скриншот) но файлы цепляются
код инстализации вкладки "Ежегодная отчетность"

function InitializeReportingFromPartsnWindow(Window) {
        var  Wnd = wndReportingFromPartsDetail.Window;
        var Dataset = dlData.Dataset;
        var RecordID = Dataset.Values('ID');
        Wnd.Attributes('DatasetUSI') = 'ds_ReportingFromParts';
        Wnd.Attributes('ParentItemFieldName') ='PartsID';
        Wnd.Attributes('ParentItemID') = RecordID;
        Wnd.Prepare();

        var WndDataset = Wnd.ComponentsByName('dlData').Dataset;
        RefreshDetailData(Dataset, 'ID', WndDataset, 'PartsID');


        var WndFiles = wndFilesDetail.Window;
        WndFiles.Attributes('DatasetUSI') = 'ds_FileInItem';
        WndFiles.Attributes('TableUSI') = 'tbl_FileInRepotingFromParts';
        WndFiles.Attributes('InsertLinkUSI') = 'iq_FileInRepotingFromParts';
        WndFiles.Attributes('ParentItemFieldName') = 'ReportingID';
        WndFiles.Attributes('ParentItemID') = WndDataset.ValAsStr('ID');
        WndFiles.Attributes('NotifyObject') = wndReportingFromPartsDetail.Window;
        WndFiles.Attributes('ItemRightsTable') = WndDataset.SelectQuery.Items(0).FromTable.RightsTable;    
        WndFiles.Prepare();
        var WndDatasetFile = WndFiles.ComponentsByName('dlData').Dataset;

        RefreshDetailData(WndDataset, 'ID', WndDatasetFile, 'ItemID');
                if((Dataset.State==3)||((Dataset.State!=3)&&(Dataset.State!=2))){
                Wnd.ComponentsByName('btnAdd').IsEnabled = false;

        }
       
}

Нравится

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

Здравствуйте!

Не могу посмотреть вложение - "нет прав". Можете вставить вложение прямо в пост, или опубликовать где либо на стороннем хостинге?
Лучше всего, конечно, активировать отладчик, и найти строку с ошибкой в Visual Studio.

Скорее всего она в этой строке

WndDataset.SelectQuery.Items(0).FromTable.RightsTable;

[url=http://postimg.org/image/4kphtna3f/][img]http://s17.postimg.org/4kphtna…]
Отладчик не выходит в этот момент.
WndDataset.SelectQuery.Items(0).FromTable.RightsTable; - если дело в этом то даже если эту строку убрать ошибка будет та же. У таблици отчетов нету RightsTable

Рустам, а если закомментировать всё тело функции, ошибка останется (может она и вовсе не в ней)?

Попробуйте после каждой строки написать код:

Log.Write(1, 'строка 0');
..
Log.Write(1, 'строка 1');
..
Log.Write(1, 'строка 2');

таким образом в журнале сообщений увидите какая строка кода выполнялась последней перед ошибкой.

Я думаю это нечего не даст так как этот код идет в инстализации карточки а ошибка происходит уже после ее инстализации в момент когда пытаюсь добавить файл.

В таком случае установите отладчик в функцию-обработчик события нажатия кнопки "Добавить файл" и пройдитесь построчно по коду, чтобы выяснить где ошибка.

Вы были правы ошибка именно в
WndDataset.SelectQuery.Items(0).FromTable.RightsTable; - потому что это null
Возможно ли без этого параметра ?

Спасибо за помощь решил проблему подставил родительский dataset )

Рустам, всегда пожалуйста.

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