Требуется реализовать экспорт нескольких документов. Поиск может быть сложным — а значит, придется задействовать прикладную часть. В итоге получаем, что документы будут экспортироваться на сервере, и нужно их скачать на клиент. И скачивать мы будем не кучу документов последовательно, а оформим в аккуратный zip-архив. Его потом и по почте будет удобнее передавать, правда? Если связанных документов нет, то выгрузим хотя бы сам документ. В этом случае никакой архив нам не потребуется. В качестве примера рассмотрим экспорт связанных документов с самим документом из карточки документа. Потом прикрутим возможность экспорта с обложки, а значит реализация будет в прикладном сценарии. Сценарий может быть сколь угодно сложным.
Создадим сценарий, который принимает на вход ИД документа и выгружает его со связанными документами в папку. У меня получилось так:
// Получить параметры
DocID = GetComponentLaunchParam('DocID'; '')
if DocID == ''
Raise(CreateException('WrongRequiredParam'; 'Параметр DocID не передан. Обратитесь к администратору системы.'; ecWarning))
endif
if not IsNumeric(DocID)
Raise(CreateException('WrongRequiredParam'; 'Параметр DocID имеет неверный формат. Обратитесь к администратору системы.'; ecWarning))
endif
Directory = GetComponentLaunchParam('Directory'; '')
if Directory == ''
Raise(CreateException('WrongRequiredParam'; 'Параметр Directory не передан. Обратитесь к администратору системы.'; ecWarning))
endif
Directory = IncludeTrailingPathDelimiter(Directory)
if not DirectoryExists(Directory)
Raise(CreateException('WrongRequiredParam'; 'Параметр Directory имеет неверный формат. Обратитесь к администратору системы.'; ecWarning))
endif
// Выгрузить документ со связанными в папку
DirectList = CreateStringList()
SelectDirectory = Directory & 'Комплект документов ' & DocID & '\'
Doc = EDocuments.GetDocumentNoLock(DocID)
DocInfo = Doc.Info
BoundEDocumentsSearchDescr = Searches.Load("BOUND_EDOCUMENT_SEARCH")
BoundEDocumentsSearchDescr.InitializeSearch(Doc.Info)
DocInfos = BoundEDocumentsSearchDescr.Execute
if DocInfos.Count > 0
FileName = SelectDirectory & ReplaceFileNameSpecialSymbols(Doc.Name) & '.' & DocInfo.Editor.Extension
VersionNumber = GetLastActiveEDocumentVersionNum(Doc)
Doc.Export(VersionNumber; FileName)
foreach DocInfo in DocInfos
DocID = DocInfo.ID
Doc = EDocuments.GetDocumentNoLock(DocID)
FileName = SelectDirectory & ReplaceFileNameSpecialSymbols(Doc.Name) & '.' & DocInfo.Editor.Extension
VersionNumber = GetLastActiveEDocumentVersionNum(Doc)
Doc.Export(VersionNumber; FileName)
endforeach
DirectList.Add(SelectDirectory)
Result = DIRZIP(Directory; DirectList)
else
FileName = ReplaceFileNameSpecialSymbols(Doc.Name) & '.' & DocInfo.Editor.Extension
VersionNumber = GetLastActiveEDocumentVersionNum(Doc)
Doc.Export(VersionNumber; Directory & FileName)
Result = FileName
endif
Обратно в веб вернется имя файла + расширение. Это понадобится для корректной обработки на уровне веб-модуля.
Осталось определиться с загадочной функцией DIRZIP. Я ее использую не только в этом сценарии, поэтому на вход она принимает три параметра:
Как архивируются файлы всем известно, поэтому вряд ли содержимое функции кому-то откроет таинства разработки. Но я все равно приведу содержимое функции DIRZIP:
Result = ''
if not Assigned(FileName)
FileName = Object.Name
endif
ZipFileName = Directory & FileName & '.zip'
// Массив байтов для пустого zip-архива
EmptyZip = ArrayOf(80; 75; 5; 6; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0)
EmptyZipText = ""
foreach CharCode in CArrayElement(EmptyZip)
EmptyZipText = EmptyZipText & Char(CharCode)
endforeach
WriteFile(ZipFileName ; EmptyZipText)
try
WinShell = CreateObject("shell.application")
ZipFile = WinShell.Namespace(ZipFileName)
foreach Folder in DirectList
ZipFile.CopyHere(Folder; 4)
// Для исключения ошибки архивации, необходимо приостанавливать выполнение кода
Sleep(1)
DeleteFile(Folder)
endforeach
Result = FileName & '.zip'
finally
WinShell = nil
endfinally
Действие в прикладной части нам не нужно, поэтому сразу приступаем к доработкам веб-модуля.
В сценарий надо передать физический путь, а для выгрузки понадобится относительный. Поэтому нужно создать следующий веб-метод:
''' <summary>
''' Получить физический и относительный пути для локальной папки пользователя
''' </summary>
''' <returns> Возвращает массив, где нулевой элемент относительный путь, первый элемент физический путь</returns>
<WebMethod()>
Public Function GetUserFolderName() As WebServiceResponse(Of List(Of String))
Dim Result As New List(Of String)
Try
Dim RelativePath = WebSession.Context.TempDirectory.Replace("~", "")
Dim Server = HttpContext.Current.Server
Dim LocalUserFolder = Server.MapPath(WebSession.Context.TempDirectory)
Result.Add(RelativePath)
Result.Add(LocalUserFolder)
Return WebServiceResponse(Of List(Of String)).OK(Result)
Catch ex As Exception
Log.LogException(ex)
Return WebServiceResponse(Of List(Of String)).Fail(ex.Message)
End Try
End Function
На javascript потребуется вызвать сценарий с параметрами, после чего сформированный файл выгрузить. Выглядит это так:
BaseWebAccess.exportBoundDocument = function () {
var id = WA.CR.ID;
// Выгрузить файл в папку на сервере
WA.SRV.call("BaseService.asmx/GetUserFolderName", {}).done(function (data) {
var relativePath = data[0];
var localuserFolder = data[1];
WA.FC.scripts('MyLittleExportDocument').execute({ DocID: id, Directory: localuserFolder }).success(function (path) {
if (path) {
window.open(relativePath + path);
}
})
})
}
В XML в узел для нужного типа карточки (или типов карточек) добавим кнопку для инициации экспорта:
<ToolGroup name="TOOLBAR_EXPORT_IMPORT">
<clear />
<!--Кнопка Экспорт-->
<ToolItem name="MyLittleBoundExport"
icon="documentExport-20"
jsaction="BaseWebAccess.exportBoundDocument()"/>
</ToolGroup>
В результате мы получили действие, которое:
Авторизуйтесь, чтобы написать комментарий