При разработке больших диалогов (с количеством полей ~35-37) требуется учитывать человеческий фактор. Важно предусмотреть все вероятные ошибки заполнения полей и обеспечить удобство использования диалога.
В качестве примера рассмотрим диалог настройки модуля «Финансовый архив» версии DIRECTUM 5.6.
Перед тем как приступить к разработке, рекомендуется:
Дополнительно определить список компонент системы, связанных с диалогом. В диалоге настройки модуля «Финансовый архив» мы не только запрашиваем значения констант, ролей, групп, но и проверим корректность заполнения связанных с константами справочников, записей пользователей и прочее.
Проверки делятся на ошибки и предупреждения.
Еще предупреждения используются на вкладке с настройками интеграции с 1С, так как интеграция с 1С может не использоваться в компании. Однако после того, как выбрана интегрированная система, связанные поля будут проверяться на корректность.
В нашем примере после группировки полей получилось 4 вкладки. Для каждой вкладки составлен свой набор проверок. Теперь приступим к разработке.
Ошибки или предупреждения должны отображаться на той же вкладке, где пользователь совершает действия. Таким образом он сразу увидит неточности и своевременно поправит значения полей.
Как можно предупреждать пользователя?
Контрол (как на скриншоте) единый для всех вкладок. И если его использовать в таком виде, то при переключении по вкладкам текст ошибки будет не соответствовать видимым полям. В связи с этим в интерфейсе для проверки вкладок реализованы веб-контролы. Посмотрим, как это сделано.
В нашем примере на вкладку диалога добавлен веб-контрол, который содержит текст ошибки, совершенной на конкретной вкладке:
Веб-контрол не скрывается, потому что иначе пришлось бы изменять размеры формы каждый раз при запуске проверки. А если в диалоге несколько вкладок, то пришлось бы учитывать размеры веб-контролов на каждой вкладке.
Если ошибки при проверке не выявлены, в веб-контроле на зеленом фоне появляется надпись «Настройка выполнена успешна».
Если ошибок много, размер веб-контрола может вырасти на неопределенную высоту. Поэтому в веб-контроле диалога мы выводим только одну ошибку, а с остальными ошибками предлагаем ознакомиться по ссылке:
Полный список ошибок открывается в отдельном окне (немодальном, чтобы удобнее было исправлять):
Для возможности проверки всех вкладок сделали «Общую» вкладку, на которой наличие ошибок отображается иконкой:
Таким образом администратору не потребуется лишний раз переключаться по всем вкладкам, чтобы найти ошибку. Плюс общая вкладка служит для того, чтобы построить некоторый «алгоритм», по которому следует идти при первоначальной настройке: настроить связанные модули, потом пойти последовательно по вкладкам.
Все реализовано через методы. Общая схема выглядит так:
Проверка каждой вкладки выполняется в отдельном методе. Это нужно для возможности вызова отдельной проверки с каждой вкладки и с главной без дублирования кода.
Вычисление действия Общая проверка выглядит так:
IsError = FALSE
ResDoc: IList = Object.OnExecute_CheckDoc
ResIntegr: IList = Object.OnExecute_CheckIntegration(FALSE)
ResRoute: IList = Object.OnExecute_CheckProcesses
ResRole: IList = Object.OnExecute_CheckRole
Object.Form.InplaceHint.Visible = FALSE
CheckResult = CreateList()
// Проверка вкладки "Документы"
ErrorList: IStringList = ResDoc.ValueByName("error")
CheckDoc = IfThen(ErrorList.Count > 0; 'no'; 'yes')
CheckResult.Add("CheckDoc"; CheckDoc)
// Проверка вкладки "Группы и роли"
ErrorList: IStringList = ResRole.ValueByName("error")
CheckRole = IfThen(ErrorList.Count > 0; 'no'; 'yes')
CheckResult.Add("CheckRole"; CheckRole)
// Проверка вкладки "Деловые процессы"
ErrorList: IStringList = ResRoute.ValueByName("error")
CheckProcesses = IfThen(ErrorList.Count > 0; 'no'; 'yes')
CheckResult.Add("CheckProcesses"; CheckProcesses)
// Проверка вкладки "Интеграция с УС"
ErrorList: IStringList = ResIntegr.ValueByName("error")
CheckIntegr = IfThen(ErrorList.Count > 0; 'no'; 'yes')
CheckResult.Add("CheckIntegration"; CheckIntegr)
Index = 0
CountCheck = CheckResult.Count
while Index < CountCheck
if CheckResult.Values(Index) == 'no'
IsError = TRUE
Index = CheckResult.Count
endif
Index = Index + 1
endwhile
Result = IsError
Object.CreateWebControlMain(CheckResult)
Метод CreateWebControlMain изменяет веб-контрол на главной вкладке для того, чтобы обновить иконки.
Если на главной вкладке отмечена вкладка с ошибками, то проще всего на нее перейти с веб-контрола. Для этого сделали функцию Change:
function Change(SLTabSheetName){
var ob = window.external.Form.View.Component;
var NewTab = ob.Form.Controls.FindControl(SLTabSheetName);
NewTab.Activate();
}
В xml-файле этот блок имеет вид:
<point
name = "Документы"
description = "Соответствие видов документов DIRECTUM и систем обмена"
state = "yes"
ref = "javascript:Change("SLTabSheet1");"
/>
Таким образом с главной вкладки можно легко перейти на другие.
Сами проверки и отображение контекстных хинтов реализованы в методах, разных для вкладок. Например, код в методе вкладки Документы выглядит так:
DELIMITER = ';'
ERROR_CONST = "error"
WARNING_CONST = "warning"
DOCKIND_CONTROL_PREFIX = 'DocKind%sT'
WEB_BROWSER_CONTROL_NAME = 'WebBrowserCheckDoc'
Controls = Object.Form.Controls
ResultListDoc = CreateList()
// Список предупреждение
WarningList = CreateStringList()
WarningList.Delimiter = DELIMITER
// Список ошибок
ErrorList = CreateStringList()
ErrorList.Delimiter = DELIMITER
// Результат контекстной проверки
ResultListDoc.Add(ERROR_CONST; ErrorList)
ResultListDoc.Add(WARNING_CONST; WarningList)
// Список реквизитов с ошибками
ReqError = CreateStringList()
ReqError.Delimiter = DELIMITER
// Проверка на заполненность обязательных полей
Index = 0
while Index < 10
RecIndex = IfThen(Index = 0; ''; Index)
ReqName = Format(DOCKIND_CONTROL_PREFIX; RecIndex)
Control = Controls.FindControl(ReqName)
NotCheckReq = Not (ReqName == CheckReqName)
if (not Assigned(Control.Text) and NotCheckReq) or ReqName == AnnulateReqName
TextErr = Object.ReplaceHTMLSpecialSymbols(LoadStringFmt('DIR67E5EDE0_FBCB_479F_86C7_FCF21CC25821'; 'DFA'; Control.Title))
ErrorList.Add(TextErr)
ReqError.Add(ReqName)
endif
Index = Index + 1
endwhile
ReqTypeCard = CreateStringList()
ReqTypeCard.Delimiter = DELIMITER
// Поля для заполнения типов карточек
ReqTypeCard.Add('DocType1')
ReqTypeCard.Add('DocType2')
ReqTypeCard.Add('DocType3')
ReqTypeCard.Add('DocType4')
ReqTypeCard.Add('DocType5')
Object.SetColorAndTooltip(ReqTypeCard; FALSE)
// Проверка на заполненность обязательных полей
Index = 0
while Index < ReqTypeCard.Count
ReqName = ReqTypeCard.Values(Index)
Requisite = Object.FindRequisite(ReqName)
if Assigned(Requisite)
if not Assigned(Requisite.Value)
TextErr = Object.ReplaceHTMLSpecialSymbols(LoadStringFmt('DIR67E5EDE0_FBCB_479F_86C7_FCF21CC25821'; 'DFA'; Requisite.Title))
ErrorList.Add(TextErr)
ReqError.Add(ReqName)
endif
endif
Index = Index + 1
endwhile
// Соответствие видов документов и типов карточек
Constants = CreateList()
// Акт
Constants.Add('DocType1' ;'DocKindT|DocKind1T')
// Накладная
Constants.Add('DocType2';'DocKind2T|DocKind3T')
// Счет-фактура
Constants.Add('DocType3';'DocKind4T|DocKind5T')
// УПД
Constants.Add('DocType4';'DocKind6T|DocKind7T')
// УПД со счетом-фактурой
Constants.Add('DocType5';'DocKind8T|DocKind9T')
// Проверить соответствие типов карточек и видов документов
TypeCardRef = References.SYSREF_EDOCUMENT_CARDS
DocKindRef = References.SYSREF_EDOCUMENT_KINDS
DocKindList = CreateStringList()
DocKindList.Delimiter = '|'
ReqNames = CreateStringList()
ReqNames.Delimiter = '|'
Index = 0
IsErrorFillTypeCard = FALSE
while Index < Constants.Count
DocKindList.DelimitedText = Constants.Values(Index)
Requisite = Object.FindRequisite(Constants.Names(Index))
if Assigned(Requisite)
DocTypeCode = Trim(Requisite.AsString)
Controls.FindControlByRequisite(Requisite).Color.Reset
TextHint = CreateStringList()
TextHint.Delimiter = '; '
foreach DocKind in DocKindList
DataSet = Object.DetailDataSet(1)
I = 1
DataSet.First
while I <= DataSet.ActualRecordCount
Requisite = DataSet.FindRequisite(DocKind)
Controls.FindControlByRequisite(Requisite).Color.Reset
if Assigned(Requisite)
DocKindCode = Trim(Requisite.AsString)
if Assigned(DocKindCode) and Assigned(DocTypeCode)
if not DFACheckIfKindConformsToType(;; DocKindCode; DocTypeCode)
ReqError.Add(DocKind)
TextErr = LoadStringFmt('DIR11E21F92_5A3F_48C7_BA3B_426D687E5F91'; 'DFA'; ArrayOf(DocKindRef.ObjectInfoByCode(DocKindCode).Name; TypeCardRef.ObjectInfoByCode(DocTypeCode).Name))
TextErr = Object.ReplaceHTMLSpecialSymbols(TextErr)
ErrorList.Add(TextErr)
IsErrorFillTypeCard = TRUE
endif
endif
endif
DataSet.Next
I = I+ 1
endwhile
endforeach
if IsErrorFillTypeCard
ReqError.Add(Constants.Names(Index))
IsErrorFillTypeCard = FALSE
endif
Index = Index + 1
endif
endwhile
if ReqError.Count > 0
Object.SetColorAndTooltip(ReqError)
endif
Constants = nil
Result = ResultListDoc
AllErr = ErrorList.Count + WarningList.Count
// Проверить количество всех ошибок и предупреждений. Если ошибка только одна, текст ошибки отобразить в хинте
if AllErr == 1
if ErrorList.Count = 1
Object.CreateWebControlHint(WEB_BROWSER_CONTROL_NAME; ErrorList.Values(0); 'error';; FALSE)
else
Object.CreateWebControlHint(WEB_BROWSER_CONTROL_NAME; WarningList.Values(0); 'warning';; FALSE)
endif
else
if ErrorList.Count > 0
Object.CreateWebControlHint(WEB_BROWSER_CONTROL_NAME; LoadString('DIR63766F90_C203_44A7_B820_731397F734A9'; 'DFA'); 'error'; AllErr)
Object.CreateWebControlDFAError(ResultListDoc; WEB_BROWSER_CONTROL_NAME)
else
if WarningList.Count > 0
Object.CreateWebControlHint(WEB_BROWSER_CONTROL_NAME; LoadString('DIRA4D9413A_46E9_462D_8F7B_F87969AD3147'; 'DFA'); 'warning'; WarningList.Count)
Object.CreateWebControlDFAError(ResultListDoc; WEB_BROWSER_CONTROL_NAME)
else
Object.CreateWebControlHint(WEB_BROWSER_CONTROL_NAME; LoadString('DIR15E77C9B_A599_4B39_800B_A31556314B16'; 'DFA'); 'success')
endif
endif
endif
В вычислениях формируется два разных списка: с ошибками и с предупреждениями. Для отображения хинта используются методы:
· CreateWebControlHint. Для отображения хинта на вкладке.
· CreateWebControlDFAError. Для подготовки информации о полном списке ошибок. Если ошибок несколько, отображает список в отдельном диалоге.
Содержимое метода CreateWebControlHint:
Controls = Object.Form.Controls
TempPath = Format("%sDFADialog\"; GetTempFolder())
CreateFile(TempPath; 'D')
XMLDesc = CreateList()
if ShowDialog
HintArr = ArrayOf(Hint; CheckResult; LoadString('DIRBF1D520B_3D27_4A48_8163_9328059CECA3'; 'DFA'); Format("javascript:DialogShow(%s, "%s");"; ArrayOf(CountError; WebBrowserControlName)))
else
HintArr = ArrayOf(Hint; CheckResult; ''; '')
endif
XMLDesc.Add('point'; HintArr)
FilePath = Object.CreateXMLForWebControl(XMLDesc; "Hint";; WebBrowserControlName)
WebBrowserControl = Controls.FindControl(WebBrowserControlName)
if not VarIsNull(WebBrowserControl)
WebBrowserControl.Navigate(FilePath)
endif
XMLDesc = nil
Метод CreateXMLForWebControl создает непосредственно XML-файл для отображения текстов ошибок. Вычислений там много, и они используется в нескольких местах, поэтому отображение текстов ошибок реализовано в виде отдельного метода с вычислениями:
MAIN_MODE = "Main"
HINT_MODE = "Hint"
XMLDesc: IList = List
if not Assigned(Path)
Path = GetTempFolder() & "DFADialog" & "\"
endif
CreateFile(Path; 'D')
Result = ''
ConstructorDesc = CreateList()
FileName = ''
if Mode == MAIN_MODE
ConstructorDesc.Add('title'; ArrayOf('name'; 'ref'; 'url'))
ConstructorDesc.Add('browser'; ArrayOf('name'; 'ref'; 'url'))
ConstructorDesc.Add('point'; ArrayOf('name'; 'description'; 'state'; 'ref'))
ConstructorDesc.Add('default'; ArrayOf('name'))
FileName = Path & "ReportDFADialog" & ".xml"
else
if Mode == HINT_MODE
ConstructorDesc.Add('point'; ArrayOf('hint';'state'; 'ref'; 'url'))
FileName = Path & "ReportDFADialogHintFor" & WebBrowserControlName & ".xml"
else
ConstructorDesc.Add('point'; ArrayOf('hint';'state'))
FileName = Path & "BrowserError" & WebBrowserControlName & ".xml"
endif
endif
Createfile(FileName)
XMLStringList = CreateStringList()
XMLStringList.Delimiter = CR
XMLStringList.Add('<?xml version="1.0" encoding="windows-1251"?>')
XMLStringList.Add(Format("<?xml-stylesheet type='text/xsl' href='DFADialog%s.xsl'?>"; Mode))
XMLStringList.Add("<Instruction>")
Index = 0
while Index < XMLDesc.Count
NameElement = XMLDesc.Names(Index)
Arr = XMLDesc.Values(Index)
XMLStringList.Add(Format("<%s"; NameElement))
Constructor = ConstructorDesc.ValueByName(NameElement)
Ind = 0
foreach Element in CArrayElement(Constructor)
XMLStringList.Add(Format('%s = "%s"'; ArrayOf(Element; Arr[Ind])))
Ind = Ind + 1
endforeach
XMLStringList.Add("/>")
Index = Index + 1
endwhile
XMLStringList.Add("</Instruction>")
XMLDesc = nil
ConstructorDesc = nil
WriteFile(FileName;; XMLStringList.DelimitedText)
Object.CreateXSLForWebControl(Mode; Path)
Object.CreateCSSForWebControl(Mode; Path)
Result = FileName
CreateXSLForWebControl и CreateCSSForWebControl – это методы, которые формируют css- и xsl-файлы для использования в веб-контроле. Аналогично, но через функции, реализовано создание файлов в отчете по состоянию поручений. В данном случае использование методов предпочтительнее, т.к. разработка сконцентрирована в одной компоненте, что позволяет проще перенести функционал в другую базу.
Авторизуйтесь, чтобы написать комментарий