Структурная схема подсистемы Общее Условно подсистему Отчетов можно разделить на следующие части. - Механизм управления. - Отдельный отчет. - Просмотр отчета. Механизм управления Задачи, возлагаемые на эту часть, будут связанны с базой данных. Т.е. это - Хранение списка отчетов. - Изменение прав доступа на отчет - Создание, редактирование, удаление отчетов. - Связь с компонентами отображения. - Механизм оперативной информации (Что-то вроде бегущей строки или доски информации, хотя принципиального отличия от отчета как такового я не вижу, если не считать, что он может использовать результаты других отчетов). При необходимости построить отчет перед пользователем будет выводиться список доступных ему отчетов. После выбора команды построить будет активизироваться д.о. для ввода параметров отчета. После этого идет построение отчета как такового. Результаты построения выводятся в каком-то окне (например просмотр RTF). После этого пользователь выполняет над этим отчетом свои действия (печатает, перегоняет в Excel и т.д.). Структура отчета. Под отчетом понимается совокупность данных, представленная в удобном для пользователя виде. Сам процесс создания отчета подразумевает следующие шаги: - Написание функции определяющей порядок формирования данных. Т.е. получение Датасета с форматированным представлением данных. (Может быть, несколько результирующих Датасетов по которым будет строиться отчет.) Данная функция будет создаваться с помощью Микрософт скриптов. - Создание формы для запроса параметров. Здесь может быть несколько подходов. Один пользователь сам создает форму (опять же с помощью скриптов) и контролы на ней (возможен вариант визуального создания), второй - все необходимые параметры которые необходимо указать перед построением отчета будут браться из входящих параметров функции и д.о. для их ввода будет строиться автоматически с учетом их количества. Второй вариант неудобней в качестве проверки типа параметра, однако более простой для пользователя. - Отображение составляющих отчета. Т.е. создается отчет, в нем находятся данные, и по двойному щелчку по ним выскакивает д.о. для их редактирования (может быть только для просмотра). Такая функция будет доступна опять благодаря скриптам и естественно задача по написанию всех действий по двойному щелчку ложится на пользователя. При хорошем описании объекта структуры данных это не составит большого труда. RTF здесь не подойдет. (Пока данная функция поддерживаться не будет.) - Определение заинтересованных таблиц в отчете. Пока сложно сказать на кого будет возложена эта задача. На пользователя или на программный алгоритм. Последний вариант предпочтительнее, но для этого придется разбирать код скрипта. Этот пункт нужен для отслеживания актуальности отчета. На заинтересованные таблицы будут создаваться триггера для создания и обновления, которые будут менять значение флага для данной таблицы и отчета. После создания отчета эти флаги обнуляются. Таким образом, большие отчеты не надо будет перестраивать без необходимости. - Необходимо задать частоту обновления (обновление при просмотре, час, день, месяц), а также время обновления отчетов (23:00:00 – 5:00:00). Причем этот процесс должен происходить на сервере. - Шаблон для визуального отображения отчета. В идеале шаблон должен представлять собой шаблон структуры, которая будет хранить все данные. После получения результирующих Датасетов, все данные будут переводиться в структуру по этому шаблону. И уже эта структура будет формировать визуальное отображение. После отображения будут известны координаты элемента на экране, и отследить какой именно элемент необходимо активировать после щелчка не составит труда. Функциональность Разобьем данную задачу по модулям. 1. Подготовка результирующих данных для вывода. Под этим подразумевается заполнение одного или несколько Датасетов. Заполнение будет возложено на пользователя (скрипты). 2. Отображение данных. 3. Связь между 1 и 2 модулями. Automation Object Данная структура описывает объект который будет юзать пользователь. Это будет список ДатаСетов которые будет создавать пользователь. TDataSetList property DataSet[Index: Integer]: TgsDataSet; DataSetByName(Name: String): TgsDataSet; Name: String; TgsDataSet property SQL: WideString; Текст запроса Fields: TgsFieldList; Поля пользователь должен иметь возможность создавать свои поля IsResultData: Boolean; Флаг является ли датасет результирующим methods constructor Create(Name: String; IsMemTable: Boolean); Database and Transaction присваивается автоматически. procedure Open; procedure Close; TCustomReport Структура для хранения данных одного отчета. Свойства - Наименование отчета - Описание отчета - Формула подготовки данных - Формула обработки редактирования составляющих - Частота обновления отчета - Временной промежуток отчета - Результат отчета - Шаблон для отображения - Флаг актуальности отчета Свойства ReportKey: Integer; Ключ отчета Name: String; Наименование отчета Description: String; Описание отчета MainFormula: TStrings; Формула отчета. Фактически в базе будет храниться только ссылка на функцию которая производит вычисления. EventFormula: TStrings; Формула обработки событий. Аналогично. ReportResult: TReportResult; Результат отчета ReportTemplate: TReportTemplate; Шаблон для представления данных RefreshFrequency: Integer; Частота обновления StartRefresh: TDateTime; Начало обновления EndRefresh: TDateTime; Конец обновления TxReportStream Вспомогательные типы TReportResult = class(TStringList) Strings[]: String Наименование датасета (используется в шаблоне) Objects[]: TDataSet; Данные TReportTemplate = class(TStream); Компонент наследует свойства от TxReport, но работает с потоками. TxReportStream = class(TxReport) Свойства ReportResult: TReportResult; ReportTemplate: TReportTemplate; Методы procedure Execute; override; TgsCustomReportBase TgsCustomReportBase = class(TComponent) Свойства private FReportList: TObjectList; public Database: TIBDatabase; CurrentReport: TCustomReport; Указатель на компонент базы данных где будут храниться отчеты. Текущий отчет. boScriptControl: TboScriptControl; Возможно стоит создавать самому Методы procedure Execute; Вывод д.о. со списком отчетов. function AddReport; Создание нового отчета function EditReport; Редактирование отчета function DeleteReport; Удаление отчета function ReportByName(): Boolean; Ищем отчет по имени и делаем его текущим procedure CreateCurrentReport; abstract; virtual; TgsRtfReportBase TgsRtfReportBase = class(TgsCustomReportBase) Свойства StreamReport: TxStreamReport; Методы procedure CreateCurrentReport; override; Обзор Одна из проблем с которой необходимо определиться это будет ли отдельный отчет иметь возможность самостоятельно строить отчет, или эту возможность дать только главной компоненте которая хранит список всех отчетов.