/
/
МИНИСТЕРСТВО ОБРАЗОВАНИЯ РЕСПУБЛИКИ БЕЛАРУСЬ
Учреждение образования «Гомельский государственный университет имени Франциска Скорины»
Математический факультет
Кафедра вычислительной математики и программирования
Дипломная работа
Разработка клиент-серверного приложения управления персоналом предприятия
Исполнитель Д.Г. Герман
Научный руководитель Л.А. Цурганова
Рецензент Е.И. Сукач
Гомель 2013
Содержание
Введение
1. СУБД Oracle
1.1 Как развивалось Oracle
1.2 Архитектура Oracle
1.3 Основные структуры данных
1.4 Язык Oracle PL/SQL
1.4.1 Типы данных и константы
1.4.2 Управляющие операторы
1.4.3 Циклы в PL/SQL
1.4.4 Обработка исключений
2. Delphi XE
2.1 Создание простого проекта
3. Разработка клиент-серверного приложения
3.1 Постановка задачи
3.2 Разработка базы данных
3.3 Разработка клиент-серверного приложения
3.4 Инструкция работы с приложением «Отдел кадров»
Заключение
Список использованных источников
Приложения
Введение
Сегодня информацию рассматривают как один из основных ресурсов развития общества, а информационные системы и технологии как средство повышения производительности и эффективности работы людей.
Создание современных электронных вычислительных машин позволило автоматизировать обработку данных во многих сферах человеческой деятельности, в том числе на предприятиях. Без современных систем обработки данных трудно представить сегодня передовые производственные технологии, управление экономикой на всех ее уровнях, научные исследования, образование, издательское дело, функционирование средств массовой информации и т.д.
Интегральные системы, предназначенные для работы с базами данных, основаны на двух взаимодействующих компонентах - клиенте, отвечающем за организацию диалога с пользователем и несущем на себе бизнес-логику, и сервере, обеспечивающем многопользовательскую работу с данными и их целостность. Уровень зависимости бизнеса от информационных систем очень высок. Разработчики занимаются задачами реализации адекватной техническим требованиям функциональности и пользовательского интерфейса, оптимизацией обмена данными между различными компонентами системы. Корпоративные системы обладают высоким уровнем сложности, поэтому они должны быть надёжными и легкоуправляемыми. В результате таких требований появляется необходимость выделения из клиентской и серверной части системы компонентов, несущих строго определенную служебную функциональность.
Целью данной дипломной работы является разработка полнофункционального клиент-серверного приложения на языке Delphi XE, реализующего возможность управления персоналом на предприятии. Источником данных для дипломной работы должна стать СУБД Oracle.
1. СУБД Oracle
За последние 30 лет корпорация Oracle из рядового поставщика программного обеспечения в области баз данных выросла в признанного лидера рынка СУБД. Если ранние продукты были типичными для начинающей компании, то теперь качество и глубина СУБД Oracle таковы, что многие считают ее технические возможности передовыми в отрасли. В каждой новой версии совершенствуются масштабируемость, функциональность и средства управления базой данных.
В состав программного обеспечения, предлагаемого корпорацией Oracle, входит сервер приложений Application Server и ПО промежуточного слоя Fusion Middleware, средства бизнес-анализа и бизнес- приложения (E-Business Suite, PeopleSoft, JD Edwards, Siebel, Hyperion и Project Fusion).
1.1 Как развивалось Oracle
В 1983 году компания Relational Software Incorporated была переименована в Oracle Corporation, чтобы ее не путали с компанией Relational Technologies Incorporated. Тогда-то разработчики приняли критически важное решение написать на языке С переносимую версию Oracle (версию 3), которая могла бы работать не только в системе Digital VAX/VMS, но также в UNIX и на других платформах. К 1985 году было заявлено, что Oracle может работать более чем на 30 платформах. Некоторые из них сейчас воспринимаются как исторический курьез, однако другие все еще функционируют. (Помимо VMS, в число операционных систем, поддерживаемых ранними версиями Oracle, входили IBM MVS, HP/UX, IBM AIX и Solaris - вариант UNIX, созданный компанией Sun.) Корпорация Oracle сумела обратить в свою пользу и даже ускорить рост числа мини-компьютеров и UNIX-серверов, наблюдавшийся в 1980-е. Сегодня Oracle перенесена и на такие операционные системы, как Microsoft Windows и Linux. Помимо поддержки многочисленных платформ не потеряли актуальности и другие решения, принятые Oracle в 1980-е, в том числе дополнительные инструменты разработки программного обеспечения и поддержки принятия решений (бизнес-анализ), поддержка стандарта ANSI SQL на всех платформах и возможность работы в стандартных сетях. Начиная с середины 1980-х изменялась и модель развертывания: от выделенных серверов базы данных к архитектуре клиент/сервер и далее к интернет-вычислениям, когда клиенты на базе браузеров обращаются к приложениям базы данных.
По мере изменения моделей вычислений и развертывания корпорация Oracle включала в свою СУБД многие инновационные технические решения (от первой распределенной базы данных до поддержки виртуальной Java-машины в ядре базы данных и реализации grid-вычислений). Oracle предлагает поддержку новых стандартов, например языка XML, имеющего огромное значение для развертывания сервис-ориентированных архитектур (SOA). В таблице 1.1 приведен краткий перечень основных достижений Oracle по годам.
Таблица 1.1 - История достижений Oracle
Год |
Функция |
|
1977 |
Ларри Эллисон, Боб Майнер и Эд Оутс основали компанию Software Development Laboratories |
|
1979 |
Oracle version 2: первая коммерческая реляционная СУБД, в которой применялся язык SQL |
|
1983 |
Oracle version 3: единый набор исходных текстов Oracle для разных платформ |
|
1984 |
Oracle version 4: переносимый набор инструментов, согласованность по чтению |
|
1986 |
Oracle version 5: клиент-серверная реляционная СУБД |
|
1987 |
Инструменты CASE и 4GL |
|
1988 |
Oracle Financial Applications на основе реляционной СУБД |
|
1989 |
Oracle6: блокировка на уровне строк и резервное копирование без остановки работы |
|
1991 |
Oracle Parallel Server на массивно-параллельных платформах Oracle7: оптимизатор по стоимости |
|
1993 |
Oracle version 7.1: распараллеливание операций, включая запросы, загрузку и создание индексов |
|
1994 |
Универсальная база данных с механизмом расширения SQL за счет картриджей, тонким клиентом и сервером приложений |
|
1996 |
Oracle8: объектно-реляционные расширения и поддержка сверхбольших баз данных (Very Large Database, VLDB) |
|
1997 |
Oracle8i: виртуальная Java-машина (JVM) в ядре СУБД |
|
1999 |
Oracle9J Application Server: инструменты Oracle, интегрированные в ПО промежуточного слоя |
|
2001 |
Oracle9J Database Server: кластеры Real Application Cluster, OLAP и добыча данных, реализованные в СУБД |
|
2003 |
Oracle Database 10g и Oracle Application Server 10g: grid-вычисления в Oracle Database 10g автоматизированы ключевые задачи управления |
|
Год |
Функция |
|
2005 |
Oracle приобретает компанию PeopleSoft и объявляет о намерении приобрести компанию Siebel, тем самым расширяя линейку ERP- и CRM- приложений и свои предложения в области систем бизнес-анализа. |
|
2007 |
Oracle Database 11g расширение средств автоматической настройки и сквозного управления изменениями с приобретением компании Hyperion в состав предлагаемых продуктов включена не зависящая от базы данных подсистема OLAP и приложения Financial Performance Management |
1.2 Архитектура Oracle
Многие пользователи Oracle употребляют термины экземпляр и база данных как синонимы. На самом деле это разные (хотя и взаимосвязанные) вещи. Различие существенно, так как проливает свет на архитектуру Oracle.
В Oracle термином база данных описывается физическое хранилище информации, а термином экземпляр - программное обеспечение, работающее на сервере и предоставляющее доступ к информации в базе данных. Экземпляр исполняется на конкретном компьютере или сервере; база данных хранится на дисках, подключенных к этому серверу.
База данных - физическая сущность: она состоит из файлов, хранящихся на дисках. Экземпляр - сущность логическая: он состоит из структур в оперативной памяти и процессов, работающих на сервере. Например, Oracle использует область разделяемой памяти System Global Area (SGA, системная глобальная область) и области памяти в каждом процессе - Program Global Area (PGA, программная глобальная область). Экземпляр может быть частью одной и только одной базы данных. Напротив, с одной базой данных может быть ассоциировано несколько экземпляров. Время жизни экземпляров ограничено, тогда как база данных при должном обслуживании может существовать вечно.
Пользователи не имеют прямого доступа к информации, хранящейся в базе данных Oracle; они должны запрашивать информацию у экземпляра Oracle.
База данных состоит из табличных пространств, управляющих файлов, журналов, архивных журналов, файлов трассировки изменения блоков, ретроспективных журналов и файлов резервных копий (RMAN).
Любые данные, хранящиеся в базе Oracle, должны находиться в каком- то табличном пространстве. Табличное пространство (tablespace) - это логическая структура; нельзя попросить операционную систему показать вам табличное пространство. Каждое табличное пространство состоит из физических структур, называемых файлами данных (data- files). В одном табличном пространстве может быть один или несколько файлов данных, тогда как каждый файл данных принадлежит ровно одному табличному пространству. При создании таблицы можно указать, в какое табличное пространство ее поместить. Тогда Oracle найдет для нее место в одном из файлов данных, составляющих указанное табличное пространство.
Начиная с версии Oracle Database l0g Release 2 для всех типов таблиц по умолчанию подразумеваются локально управляемые табличные пространства. В таком табличном пространстве можно создавать большие файлы, то есть при работе в 64-разрядных системах задействуется возможность создавать сверхбольшие файлы.
В Oracle9i появился механизм файлов, управляемых Oracle (Oracle Managed Files, OMF), позволяющий автоматически создавать, именовать и, если понадобится, удалять все файлы, составляющие базу данных. OMF упрощает обслуживание базы данных, поскольку не нужно помнить имена всех составляющих ее файлов. К тому же не возникают проблемы из-за ошибок человека, ответственного за именование файлов. Начиная с версии Oracle Database 10g сочетание OMF и табличных пространств с большими файлами делает работу с файлами данных совершенно прозрачной.
Максимальное количество файлов данных в базе Oracle - 64 000. Поскольку табличное пространство с большими файлами может содержать файл, который в 1024 раза больше файла в табличном пространстве с малыми файлами, а размер блока в табличном пространстве с большими файлами для 64-разрядных операционных систем составляет 32 Кбайт, общий размер базы данных Oracle может достигать 8 экзабайт (1 экзабайт = 1 000 000 терабайт). Табличные пространства с большими файлами предназначены для использования совместно с подсистемой автоматического управления хранением Automatic Storage Management (ASM), иными менеджерами логических томов, поддерживающими расслоение, и RAID-массивами.
База данных Oracle состоит из физических файлов трех основных типов:
1. управляющие файлы (control files);
2. файлы данных (datafiles);
3. журнальные файлы, или журналы (redo log files).
В управляющем файле хранится информация о местонахождении других физических файлов, составляющих базу данных, - файлов данных и журналов. Там же хранится важнейшая информация о содержимом и состоянии базы данных:
· имя базы данных;
· время создания базы данных;
· имена и местонахождение файлов данных и журнальных файлов;
· информация о табличных пространствах;
· информация о файлах данных в автономном режиме;
· история журналов и информация о порядковом номере текущего журнала;
· информация об архивных журналах;
· информация о наборах и фрагментах резервных копий, файлах данных и журналах;
· информация о копиях файлов данных;
· информация о контрольных точках.
Управляющие файлы не только содержат важную информацию, необходимую при запуске экземпляра, они полезны и при удалении базы данных. Начиная с версии Oracle Database 10g с помощью команды DROP DATABASE можно удалить все файлы, перечисленные в управляющем файле базы данных, а также сам управляющий файл.
При запуске экземпляра Oracle считываются параметры инициализации. Они определяют, как база данных должна использовать физическую инфраструктуру и иную конфигурационную информацию об экземпляре. Параметры инициализации хранятся в файле параметров инициализации экземпляра, который обычно называют просто INIT.ORA или, начиная с версии Огас1е9g, в репозитории, который называется файлом параметров сервера (или SPFILE). Количество обязательных параметров инициализации уменьшается с выходом каждой новой версии Oracle. В дистрибутиве Oracle есть пример файла инициализации, пригодный для запуска базы данных. Либо можно воспользоваться программой Database Configuration Assistant (DCA), которая подскажет обязательные значения.
Для любой базы данных следует хранить по меньшей мере два управляющих файла на разных физических дисках. Без актуальной копии управляющего файла вы рискуете потерять информацию о составляющих вашей базы данных. Утрата управляющих файлов не обязательно фатальна, их можно и воссоздать. Но процедура воссоздания довольно сложна и рискованна, а избежать ее несложно.
Местоположение управляющих файлов определяется параметром инициализации CONTROL_FILES. Он позволяет задать несколько управляющих файлов, например:
control_files = (/u00/oradata/control.001.dbf,
/u01/оradata/control.002.dbf,
/u02/oradata/control.003.dbf)
Этот параметр сообщает экземпляру, где искать управляющие файлы. Oracle гарантирует, что все копии управляющего файла одинаковы, то есть любые изменения вносятся синхронно. Если параметр не задан, Oracle создаст управляющий файл с именем по умолчанию или прибегнет к услугам компонента Oracle Managed Files (если тот активирован).
Многие базы данных Oracle развертываются на том или ином варианте RAID-массива, например RAID-1 или RAID-5, чтобы избежать потери данных в случае выхода диска из строя. Напрашивается вывод, что можно обойтись без нескольких копий, сохранив управляющий файл в защищенной дисковой памяти, и что утрата диска еще не означает утраты управляющего файла. Но этот вывод неправомерен по двум причинам:
Если в массиве с расслоением (striped array) или в зеркальной паре (mirror-pair) отказывает больше одного диска, то все данные, хранящиеся на этих дисках, теряются. Статистически это редкое событие, но все же такое случается, и тогда есть угроза повреждения или утраты управляющего файла. Поскольку вы и так будете по горло заняты восстановлением после множественных сбоев диска, вероятно, лучше при этом избежать хотя бы воссоздания управляющих файлов. Создание дополнительных копий, пусть даже хранящихся в избыточной дисковой памяти, - это дополнительный уровень защиты.
Избыточная дисковая память не поможет защититься от человеческих ошибок. Кто-то может случайно удалить или переименовать управляющий файл, затереть его другим или переместить в другое место. И зеркалированный диск честно отразит эти изменения. А при резервировании управляющих файлов хотя бы одна копия да останется. Не стоит беспокоиться о том, что запись в несколько управляющих файлов понизит производительность. Обновление управляющих файлов - ничто по сравнению с другими операциями дискового ввода/вывода, производимыми Oracle.
В файлах данных находятся собственно данные, хранящиеся в базе: таблицы и индексы, словарь данных, в котором сохраняется информация об этих структурах, и сегменты отката, необходимые для реализации конкурентного доступа.
Каждый файл данных принадлежит только одной базе данных и только одному табличному пространству в ней. Данные считываются с дисков в оперативную память блоками Oracle по мере необходимости, исходя из действий пользователей. Блоки данных переписываются из памяти в файлы данных на диске, когда это требуется для гарантии сохранности внесенных пользователями изменений.
Журнальный файл содержит протокол всех изменений, произведенных в базе данных в результате выполнения транзакций и внутренних операций Oracle. Обычно измененные блоки кэшируются в памяти, поэтому в случае сбоя экземпляра может оказаться, что какие-то блоки не записались в файлы данных. Тогда можно воспользоваться протоколом, хранящимся в журнальных файлах, чтобы воспроизвести изменения, оставшиеся не записанными в момент сбоя, и тем самым обеспечить согласованность транзакции.
Кроме того, журнальные файлы применяются для реализации операций отката (undo), инициируемых командой ROLLBACK. Незафиксированные изменения в базе данных откатываются, так что база остается в том состоянии, в котором находилась в момент последней фиксации.
Экземпляр Oracle можно определить как область разделяемой памяти и набор фоновых процессов. Область разделяемой памяти экземпляра называется системной глобальной областью (System Global Area, SGA). Фактически SGA является не одной большой однородной областью памяти, а состоит из различных компонентов. Все процессы экземпляра, как системные, так и пользовательские, совместно обращаются к SGA. До версии Oracle9i размер SGA устанавливался при запуске экземпляра Oracle. Единственным способом изменения размера SGA или какой- то ее составляющей было изменение соответствующих параметров инициализации, остановка и перезапуск экземпляра. В Oracle9i мож но изменять размер SGA и ее компонентов, не останавливая экземпляр. В Oracle9i также введено понятие гранулы, то есть наименьшего объема памяти, который можно добавить или удалить из SGA.
В версии Oracle Database 10g появился механизм автоматического управления разделяемой памятью (Automatic Shared Memory Management, ASMM), а в Oracle Database 11g- механизм автоматического управления памятью (Automatic Memory Management, AMM) для компонентов SGA и PGA. Если задан параметр инициализации MEMORY_ TARGET (появился в Oracle Database llg) или SGA_TARGET, то база данных автоматически распределяет память между различными компонентами SGA, обеспечивая оптимальное управление памятью. К автоматически распределяемым компонентам относятся разделяемый пул (его размер вручную устанавливается с помощью параметра SHARED_POOL_SIZE), большой пул (LARGE_POOL_SIZE), пул Java (JAVAJPOOL_SIZE), кэш буферов (DB_CACHE_SIZE) и пул Streams (STREAMS_POOL_SIZE). Параметры инициализации, относящиеся к автоматическому управлению памятью, можно задать в Oracle Enterprise Manager.
Фоновые процессы взаимодействуют с операционной системой и между собой, управляя структурами памяти экземпляра. Эти процессы также управляют собственно базой данных на диске и выполняют общие действия по обслуживанию экземпляра.
Во всех версиях Oracle присутствует набор метаданных, описывающих различные структуры данных, например определения таблиц и ограничений целостности. Совокупность таблиц и представлений, в которых хранятся метаданные, называется словарем данных Oracle.
Таблицы словаря данных всегда находятся в табличном пространстве SYSTEM. Имена динамических таблиц начинаются с префиксов V$ или GV$. Имена статических таблиц могут начинаться с одного из префиксов DBA_, ALL_ или USER_, обозначающего область видимости представленных в таблице объектов.
1.3 Основные структуры данных
В этом разделе описаны три основные структуры данных Oracle - таблицы, представления и индексы.
Таблица (table)- это базовая структура данных в любой реляционной СУБД. Таблица представляет собой набор строк. Каждая строка таблицы состоит из одного или нескольких столбцов. Если вы незнакомы с реляционными базами данных, то можете считать таблицу аналогом файла, а строку - аналогом записи в нереляционной базе.
В версии Oracle9i появились внешние таблицы. Как легко понять, данные внешней таблицы хранятся вне базы данных, обычно в плоском (неструктурированном) файле. Внешняя таблица допускает только чтение, обновить находящиеся в ней данные нельзя. Кроме прочего, внешняя таблица удобна для загрузки данных из файла или для выгрузки в файл.
В Oracle Database 11 g добавлена возможность создавать в таблице виртуальные столбцы. Они определяются выражением и, хотя результаты вычисления выражения не хранятся, приложение может обращаться к таким столбцам.
Представлением (view) в Oracle называется структура данных, определяемая SQL-командой. Эта SQL-команда хранится в базе данных. Когда в запросе встречается представление, выполняется определяющий его запрос и пользователю возвращаются данные из базовой таблицы. Сами представления не содержат данных, а лишь позволяют взглянуть на них так, как это определено в запросе.
Представления можно использовать в разных целях:
· Чтобы упростить доступ к данным, хранящимся в разных таблицах;
· Чтобы реализовать специальные требования к безопасности данных в таблице (например, создав представление с предложением WHERE, ограничивающим набор данных, доступных через это представление). Начиная с версии Oracle9i эту задачу можно решить с помощью механизма детального контроля доступа (finegrained access control), позволяющего автоматически ограничивать доступ к данным в зависимости от значения, хранящегося в строке;
· Чтобы скрыть от приложения точную структуру базовых таблиц.
Представление строится над набором базовых таблиц, каждая из которых может быть либо реальной таблицей базы данных, либо другим представлением. Если изменить любую базовую таблицу, так что она перестанет соответствовать определению представления, то само представление окажется непригодным для использования.
В общем случае в одной команде SQL допускается запись в столбец только одной какой-то базовой таблицы, указанной в определении представления. Есть дополнительные ограничения на операции INSERT, UPDATE и DELETE. Кроме того, при наличии в SQL-команде некоторых предложений обновить данные представления вообще невозможно.
Осуществить запись в не обновляемое представление позволяет триггер INSTEAD OF.
В версии Oracle8i появились материализованные представления. По существу, это не представления в описанном выше смысле, а физические таблицы, в которых хранятся заранее агрегированные данные, что позволяет заметно повысить производительность хранилищ данных.
Индекс (index) - это структура данных, ускоряющая доступ к строкам базы данных. Индекс ассоциируется с одной таблицей и содержит данные из одного или нескольких столбцов.
Сервер Oracle автоматически модифицирует хранящиеся в индексе значения при изменении значений в соответствующих столбцах. Поскольку в индексе хранится меньше данных, чем в полной строке таблицы, и поскольку индексы организованы в виде специальной структуры, ускоряющей чтение, для доступа к данным в индексе требуется меньше операций ввода/вывода. Выборка строк по значениям индексированных столбцов может оказаться быстрее выборки по значениям, хранящимся только в базовой таблице. Кроме того, большинство индексов хранятся в отсортированном виде (по возрастанию или убыванию значений в зависимости от способа создания индекса). Из-за этого выборка строк по диапазону значений или возврат строк в отсортированном порядке гораздо быстрее выполняется по проиндексированным столбцам.
Индекс может быть уникальным (то есть в таблице не может быть двух строк с одинаковым значением индексного ключа) или неуникальным. Строки, для которых значение индексного ключа равно NULL, не включаются в индекс.
Индекс в Oracle - это физическая структура, используемая внутри базы данных. Ключом называется логическая сущность, обычно значение, хранящееся в индексе. Как правило, в документации Oracle эти термины взаимозаменяемы.
1.4 Язык Oracle PL/SQL
PL/SQL - это процедурное расширение языка SQL (Structured Query Language - структурированный язык запросов). SQL сегодня является повсеместно распространенным языком для выполнения запросов и изменений (хоть в его названии об этом и не говорится) в реляционных базах данных. Корпорация Oracle ввела в употребление PL/SQL для того, чтобы избавиться от некоторых ограничений, существующих в SQL, а также для того, чтобы иметь возможность предложить более полное программное решение разработчикам жизненно важных приложений, работающих с базами данных Oracle.
Как и в большинстве процедурных языков, в PL/SQL наименьшей значимой единицей группировки кода является блок. Блок - это конструкция, обеспечивающая выполнение фрагмента кода и определяющая границы видимости переменных и область действия обработчиков исключений. PL/SQL позволяет создавать анонимные блоки (блоки кода, не имеющие названия) и именованные блоки (это могут быть процедуры, функции или триггеры).
Блок PL/SQL может включать в себя до четырех разделов, лишь один из которых является обязательным.
<Заголовок>
Is
<раздел объявлений>
begin
<раздел исполнения>
exception
<раздел исключений>
end;
· Заголовок (Необязательный раздел) Используется только для именованных блоков. Заголовок определяет, каким образом будет вызываться именованный блок или программа.
· Раздел объявлений (Необязательный раздел) Определяет переменные, курсоры и подблоки, которые упоминаются в разделах исполнения и исключений.
· Раздел исполнения (Обязательный раздел) Содержит операторы, которые будет выполнять ядро PL/SQL при исполнении блока.
· Раздел исключений (Необязательный раздел) Обрабатывает исключительные (по отношению к нормальной работе) ситуации (предупреждения и ошибки).
Если кто-то хочет сохранить анонимность, он не называет своего имени. Именно так и поступает анонимный блок в PL/SQL, в нем просто отсутствует раздел заголовка, такой блок начинается с DECLARE или BEGIN. Это означает, что его нельзя будет вызвать из какого-то другого блока, так как не на что установить ссылку. Анонимные блоки служат контейнерами для операторов PL/SQL и обычно включают в себя вызовы процедур и функций.
В общем виде синтаксис анонимного блока PL/SQL будет таким:
[ DECLARE...объявления...]
BEGIN
...один или несколько исполняемых операторов ...
[ EXCEPTION...операторы обработки исключений...]
END;
В квадратные скобки заключены необязательные элементы конструкции. В блоке должны быть операторы BEGIN и END, а также хотя бы один исполняемый оператор.
При объявлении переменной или константы вы должны назначить ей тип данных. (PL/SQL за очень небольшими исключениями является языком со строгой типизацией.) PL/SQL предлагает полный набор предопределенных скалярных и составных типов данных, вы также можете создавать собственные пользовательские типы (которые также называют абстрактными типами данных).
1.4.1 Типы данных и константы
Все имеющиеся предопределенные типы данных определены в PL/ SQL-пакете STANDARD. Например, туда включены операторы, определяющие логический тип данных и два числовых типа:
CREATE OR REPLACE PACKAGE STANDARD IS
type BOOLEAN is (FALSE, TRUE);
type NUMBER is NUMBER_BASE;
subtype INTEGER is NUMBER(38,);
PL/SQL поддерживает все привычные типы данных и множество других. В разделе будет приведен лишь краткий обзор разнообразных предопределенных типов данных.
PL/SQL поддерживает строки как фиксированной, так и переменной длины, представленные как в традиционных кодировках, так и в кодировках Unicode. CHAR и NCHAR - это типы строк фиксированной длины, а VARCHAR2 и NVARCHAR2 - типы строк переменной длины. Рассмотрим объявление строки переменной длины, которая может вмещать до 2000 символов: DECLARE stroka VARCHAR2(2000);
Oracle также поддерживает очень длинные символьные строки - типы LONG и LOB. Эти типы данных позволяют хранить и обрабатывать огромные объемы данных: LOB может содержать до 128 терабайт информации в Oracle Database 10g (используйте тип LONG только для совместимости с уже существующим кодом. Будущее за типами LOB!). К символьным типам данных LOB относятся CLOB (character large object - большой символьный объект) и NCLOB (National Language Support character large object - большой символьный объект с поддержкой национальных языков, многобайтный формат).
PL/SQL поддерживает все более широкое множество числовых типов данных. Долгие годы рабочей лошадкой числовых типов данных был тип NUMBER, который можно использовать для десятичных значений с фиксированной и плавающей точкой, а также для целых значений. Приведем несколько примеров объявлений типа NUMBER:
DECLARE
salary NUMBER(9,2); -- фиксированная точка, семь
знаков слева и два справа
raise_factor NUMBER; -- десятичное число с
плавающей точкой
weeks_to_pay NUMBER(2); -- целое число
BEGIN
salary := 1234567.89;
raise_factor := 0.05;
weeks_to_pay := 52;
END;
Десятичная природа типа NUMBER оказывается чрезвычайно полезной при работе с денежными величинами. Вам не придется беспокоиться о возможных ошибках округления при переводе числа в двоичное представление. Например, записывая число 0.95, не стоит бояться, что от него через некоторое время останется только 0.949999968.
До выпуска версии Oracle Database 10g тип NUMBER был единственным числовым типом данных PL/SQL, полностью соответствующим типу данных базы данных. Это одна из причин столь широкого использования типа NUMBER. В Oracle Database 10g появилось еще два двоичных типа с плавающей точкой: BINARY.FLOAT и BINARY.DOUBLE. Как и NUMBER, оба новых типа поддерживаются как в PL/SQL, так и в базе данных. Правильно применяя их, можно добиться значительного повышения производительности за счет того, что математические операции над новыми типами выполняются аппаратной частью (когда это позволяет аппаратная платформа). PL/SQL поддерживает ряд числовых типов и подтипов, которые не соответствуют типам базы данных, но, тем не менее, весьма полезны. Упомянем особо PLS.INTEGER, целочисленный тип, для которого арифметические операции выполняются аппаратно. Счетчики циклов FOR реализованы типом PLS.INTEGER.
До появления версии Oracle9i Database мир дат Oracle ограничивался типом DATE, который позволял хранить как дату, так и время (с точностью до секунд). В Oracle9i Database появились два набора новых связанных типов данных: INTERVAL и TIMESTAMP. Новые типы значительно расширили возможности разработчиков PL/SQL по созданию программ, обрабатывающих и хранящих значения дат и времени с очень высокой точностью, а также вычисляющих и хранящих интервалы времени.
Приведем в качестве примера функцию, вычисляющую возраст человека:
CREATE OR REPLACE FUNCTION age (dob.in IN DATE)
RETURN INTERVAL YEAR TO MONTH
IS retval INTERVAL YEAR TO MONTH;
BEGIN
RETURN (SYSDATE - dob.in) YEAR TO MONTH;
END;
PL/SQL поддерживает настоящий логический (булев) тип данных. Переменная этого типа может иметь лишь одно из трех значений: TRUE, FALSE и NULL.
Логические переменные позволяют сделать код удобочитаемым, даже в том случае, когда он содержит сложные логические выражения. Рас смотрим пример объявления переменной типа Boolean с присваиванием ей значения по умолчанию:
DECLARE
l_eligible_for_discount BOOLEAN :=
customer_in.balance > min_balance AND customer_in.pref_type = 'MOST FAVORED' AND customer_in.disc_eligibility;
При объявлении переменной PL/SQL выделяет память для значения переменной и присваивает этому хранилищу имя, используя которое вы сможете извлекать и изменять данное значение. В объявлении также указывается тип данных переменной, который будет использован для проверки корректности значений, присваиваемых переменной.
Для объявления используется следующая синтаксическая конструкция:
Имя тип_данных [NOT NULL] [значение_по_умолчанию];
имя - это имя объявляемой переменной или константы, а тип_данных - это тип или подтип значений, которые могут присваиваться этой переменной. Включение в объявление выражения NOT NULL означает, что если в коде будет предпринята попытка присвоения вашей переменной значения NULL, то Oracle инициирует исключение. Выражение [значение по умолчанию] позволяет инициализировать переменную; оно необязательно для всех объявлений, кроме объявлений констант.
Для задания значения по умолчанию ключевое слово DEFAULT и оператор присваивания эквиваленты и взаимозаменяемы.
Существует всего два отличия в объявлениях переменных и констант: объявление константы включает в себя ключевое слово CONSTANT, и в нем обязательно указывается значение по умолчанию (которое на самом деле является не значением по умолчанию, а единственно возможным значением). Синтаксис объявления константы будет таким:
имя CONSTANT тип_данных [NOT NULL] := DEFAULT
значение_по_умолчанию;
1.4.2 Управляющие операторы
В PL/SQL существует два вида управляющих операторов: условные операторы и операторы перехода. Условные операторы, направляющие поток выполнения в определенную точку программы в зависимости от некоторого условия, необходимы практически в каждом фрагменте создаваемого кода. К таким операторам относятся IF-THEN-ELSE и CASE (операторы CASE доступны в версиях Oracle9/ Database и Oracle Database 10g) Существенно реже используется оператор безусловного перехода GOTO или явное указание на необходимость «ничего-не-делать» с помощью оператора NULL.
Оператор IF позволяет использовать в программах условную логику. Условие, указанное между IF и THEN, определяет, должно ли быть выполнено множество операторов, находящееся между THEN и END IF. Если условие вычислено как FALSE, то код не выполняется.
Оператор CASE позволяет выбрать для исполнения одну из нескольких последовательностей операторов. Операторы CASE появились в стандарте SQL уже в 1992 году, но Oracle SQL стал поддерживать CASE только в версии Oracle8i Database, а PL/SQL не поддерживал CASE вплоть до версии Oracle9/ Database Release 1.
1.4.3 Циклы в PL/SQL
PL/SQL поддерживает три вида циклов, обеспечивая тем самым возможность создания оптимального кода для решения любой конкретной задачи. В большинстве случаев, требующих использования цикла, применима любая из циклических конструкций. Однако выбор не самой удачной для конкретного случая конструкции может повлечь за собой написание множества дополнительных строк кода. В итоге получившийся модуль будет сложнее для восприятия и дальнейшего сопровождения.
Чтобы показать, как разные виды циклов по-разному решают поставленную перед ними задачу, рассмотрим далее три типа циклов. В каждом случае процедура вызывает display_total_sales для каждого года, номер которого находится в диапазоне между начальным и конечным значением аргумента.
Очевидно, в рассмотренных примерах цикл FOR требует наименьшего объема кода. Но использование данного типа цикла возможно лишь потому, что заранее известно, что тело цикла будет выполняться определенное количество раз. Во множестве других случаев количество проходов цикла должно быть переменным, так что применение цикла FOR будет невозможно.
Простой цикл называется простым, потому что он начинается просто со слова LOOP и заканчивается оператором END LOOP. Цикл завершается при выполнении внутри цикла оператора EXIT, EXIT WHEN или RETURN (или если внутри цикла инициировано исключение):
LOOP EXIT WHEN l_current_year > end_year_in; display_total_sales (l_current_year); l_current_year := l_current_year + 1;
END LOOP;
Oracle поддерживает циклы FOR со счетчиком и с курсором. Для цикла FOR со счетчиком вы указываете начальное и конечное целые значения, а все остальное за вас делает PL/SQL: проходит все значения внутри заданного диапазона и завершает цикл:
FOR l_current_year IN start_year_in..end_year_in
LOOP
display_total_sales (l_current_year);
END LOOP;
Цикл FOR с курсором имеет такую же базовую структуру, только в данном случае вместо указания верхней и нижней границ целочисленного диапазона следует явно задать курсор или использовать оператор SELECT:
FOR l_current_year IN (
SELECT * FROM sales_data
WHERE year BETWEEN start_year_in AND end_year_in)
LOOP
-- Теперь эта процедура принимает запись, неявно
-- объявленную как sales_data%ROWTYPE...
display_total_sales (l_current_year);
END LOOP;
Цикл WHILE очень похож на простой цикл. Его ключевым отличием является то, что цикл WHILE проверяет условие завершения до выполнения тела цикла. Следовательно, тело цикла может не быть выполнено ни разу:
PROCEDURE display_multiple_years (
start_year_in IN PLS_INTEGER ,
end_year_in IN PLS_INTEGER)
IS l_current_year PLS_INTEGER := start_year_in; BEGIN
WHILE (l_current_year <= end_year_in)
LOOP
display_total_sales (l_current_year);
l_current_year := l_current_year + 1;
END LOOP;
END display_multiple_years;
1.4.4 Обработка исключений
В языке PL/SQL ошибки любого рода трактуются как исключения - нештатные ситуации для вашей программы. Исключения могут быть следующих видов:
· Ошибка, инициированная системой (например, «недостаточно памяти» или «повторение значений в индексе»);
· Ошибка, вызванная действиями пользователя;
· Предупреждение, выдаваемое пользователю приложением.
PL/SQL перехватывает ошибки и реагирует на них, используя механизм обработчиков исключений. Обработчики исключений позволяют аккуратно отделить код обработки ошибок от исполняемых операторов. Для обработки ошибок используется событийная модель исполнения кода, а не линейная. Другими словами, вне зависимости от того, где было инициировано исключение, оно будет обработано одним и тем же обработчиком исключений в разделе исключений.
При возникновении ошибки в PL/SQL, будь то системная ошибка или ошибка приложения, инициируется исключение. Обработка в исполняемом разделе текущего PL/SQL-блока прекращается, и управление передается в отдельный раздел исключений текущего блока (если такой существует) для обработки исключения. После завершения обработки исключения вернуться в этот блок невозможно. Управление передается в родительский блок (если он существует).
2. Delphi XE
Среда разработки Delphi является одним из популярнейших инструментов разработки прикладных программ. Она поддерживает так называемую быструю разработку, основанную на технологии визуального проектирования и событийного программирования, суть которой состоит в том, что среда разработки берет на себя большую часть рутины, оставляя программисту работу по созданию диалоговых окон (визуальное проектирование) и процедур обработки событий (событийное программирование). Производительность программиста при этом просто фантастическая!
Delphi -- это среда быстрой разработки приложений (RAD-среда, от Rapid Application Development -- быстрая разработка приложений) на языке Delphi, в основе которого лежит хорошо знакомый многим программистам язык Pascal.
Изначально, вплоть до седьмой версии, Delphi была ориентирована на разработку Win32-приложений. После того как Microsoft стала продвигать технологию .NET, появилась Delphi 8 for The Microsoft .NET Framework -- среда разработки .NET-приложений. Следующие версии Delphi выпускались в двух вариантах: для разработки Win32- и .NET-приложений. Теперь программистам стала доступна очередная версия Delphi -- Embarcadero Delphi ХЕ. Embarcadero -- новое имя выделенного из Borland подразделения (изначально оно называлось CodeGear). отвечающего за инструменты разработки приложений.
Delphi ХЕ существует в трех вариантах: Professional, Enterprise и Architect. Каждый комплект включает набор средств и компонентов, обеспечивающих разработку высокоэффективных приложений различного назначения, в том числе работы с базами данных InterBase, Blackfish SQL, Firebird, MySQL, Microsoft SQL Server, Oracle и др. Чем выше уровень пакета, тем больше возможностей он предоставляет программисту. Так, например, в Enterprise и Architect есть компоненты, позволяющие работать с удаленным сервером Blackfish SQL, а в Professional -- только с локальным.
Среда Delphi ХЕ доступна как отдельный инструмент разработки, а также как элемент Embarcadero RAD Studio ХЕ.
Delphi ХЕ может работать в среде операционных систем Microsoft Windows ХР Home или Professional (SP2 или SP3), Microsoft Windows Vista SP2, Microsoft Windows Server 2003 (SP1) или 2008. а также в Microsoft Windows 7. Особых требований, по современным меркам, к ресурсам компьютера среда не предъявляет: процессор должен быть класса Intel Pentium (или совместимый) с частотой 1.4 ГГц (рекомендуется 2 ГГц и выше), 1 Гбайт оперативной памяти (рекомендуется 2 Гбайт и больше), 3.75 Гбайт свободного места на жестком диске (в том числе 750 Мбайт для Microsoft .NET Framework и Microsoft .NET SDK).
2.1 Работа в Delphi XE
Процесс разработки программы в Delphi рассмотри на примере - создадим приложение (так принято называть прикладную программу), которая будет выводить сообщение о приветствии с пользователем, как показано на рисунке 2.1
Рисунок 2.1 - Окно приложения
Чтобы начать работу над новым приложением, нужно в меню File выбрать команду New - VCL Forms Application-Delphi.
Работа над приложением начинается с создания стартовой формы -- главного окна программы. Сначала нужно установить требуемые значения формы, затем -- поместить на форму необходимые компоненты (поля ввода информации, командные кнопки, поля отображения текста и др.).
Настройка формы (а также компонентов) осуществляется путем изменения значений свойств. Свойства объекта (формы, компонента) определяют его вид и поведение. Например, свойство caption определяет текст заголовка окна, а свойство Position -- положение окна в момент появления на экране.
Для изменения значений свойств объектов используется вкладка Properties окна Object Inspector. В левой колонке этой вкладки перечислены свойства объекта, выбранного в данный момент, в правой -- указаны значения свойств. Имя выбранного объекта отображается в верхней части окна Object Inspector, которое представлено на рисунок 2.2.
Рисунок 2.2 - Окно Object Inspector, вкладка Preporties
Поля редактирования, поля отображения текста, командные кнопки, списки, переключатели и другие элементы, обеспечивающие взаимодействие программы с пользователем, называют компонентами пользовательского интерфейса.
Компоненты, которые программист может использовать в процессе разработки программы, находятся в палитре компонентов (Tool Palette). На вкладках Standard, Additional и Win32 располагаются часто используемые компоненты пользовательского интерфейса
Чтобы на форму добавить компонент, например Edit, надо:
· В палитре компонентов (окно Tool Palette) раскрыть вкладку Standard;
· Сделать щелчок на значке компонента Edit (рис. 2.7). Здесь следует обратить внимание, что в палитре компонентов, рядом со значком указывается тип компонента, а не его название.
· Установить указатель мыши в ту точку формы, в которой должен быть левый верхний угол компонента.
· Сделать щелчок левой кнопкой мыши.
В результате на форме появляется поле редактирования -- компонент Edit, что можно увидеть на рисунок 2.3
Рисунок 2.3 - Форма с полем для редактирования Edit
Каждому добавленному компоненту среда разработки присваивает имя, которое состоит из названия компонента и его порядкового номера. Например, первый компонент Edit получает имя Edit1, второй - Edit2. Программист путем изменения значения свойства Name может поменять имя компонента. Однако в простых программах имена компонентов, как правило, не изменяют.
Вид созданной формы подсказывает, как работает программа. Очевидно, что пользователь должен ввести в поля редактирования исходные данные и сделать щелчок на кнопке «Выполнить». Щелчок на изображении командной кнопки -- это пример того, что называется событием.
Событие (event) -- это то, что происходит во время работы программы. У каждого события есть имя. Например, щелчок кнопкой мыши -- это событие click, двойной щелчок мышью -- событие DblClick.
Следует понимать, что одни и те же действия, но выполненные над различными объектами, вызывают разные события. Например, щелчок (событие click) на кнопке «Выполнить» и щелчок на кнопке «Завершить» -- это два разных события.
Реакцией на событие должно быть какое-либо действие. В Delphi реакция на событие реализуется как процедура обработки события. Таким образом, для того чтобы программа выполняла некоторую работу в ответ на действия пользователя, программист должен написать процедуру обработки соответствующего события.
Методику создания процедуры обработки события рассмотрим на примере обработки события click, которое возникает в результате щелчка на кнопке «Выполнить».
Чтобы приступить к созданию процедуры обработки события, сначала надо выбрать компонент, для которого создается процедура обработки события. Для этого в окне конструктора формы надо сделать щелчок левой кнопкой мыши на нужном компоненте (компонент можно выбрать также в раскрывающемся списке, который находится в верхней части окна Object Inspector). Затем в окне Object Inspector нужно открыть вкладку Events, рисунок 2.4.
Рисунок 2.4 - Окно Object Inspector, вкладка Events
Для того, что бы создать процедуру обработки события, сначала на вкладке Events надо выбрать событие, процедуру обработки которого необходимо создать, затем сделать двойной щелчок левой кнопкой мыши в поле редактирования, которое находится справа от имени события. В результате имя процедуры обработки события сформирует Delphi (имя процедуры обработки события образуется путем объединения имени компонента, для которого создается процедура обработки события, и имени события, например Button1Click), после чего написать тело процедуры.
procedure TForm1.Button1Click(Sender: TObject);
begin
MessageBox(handle, PWideChar('Добрый день: ' + Edit1.Text), 'Приветствие!', MB_ICONINFORMATION + MB_OK);
end;
Пробный запуск программы можно выполнить непосредственно из Delphi, не завершая работу со средой разработки. Для этого в меню Run надо выбрать команду Run или Run Without Debugging. Можно также сделать щелчок на кнопке Run, рисунок 2.5 или нажать клавишу <F9>.
Рисунок 2.5 - Запуск приложения
Команда Run запускает программу в режиме отладки. Команда Run Without Debugging запускает программу в обычном режиме, даже в том случае, если в ней есть информация, необходимая для отладки (заданы точки останова, указаны переменные, значения которых надо контролировать). Следует обратить внимание, что процесс запуска программы командой Run Without Debugging происходит быстрее.
3. Разработка клиент-серверного приложения
3.1 Постановка задачи
Сегодня, наверное, нет ни одного предприятия, на котором нет ни одного сотрудника, хотя бы пару человек, но должно быть. Если сотрудников и всего пару человек, то можно вести учет их на бумажном носителе. А если представить себе предприятие, на котором работает не одна, и даже не две тысячи человек, а, к примеру, тысячи четыре, и таких предприятий достаточно в стране, тогда учет сотрудников вести на бумажном носителе будет затруднительно. Хотя нет, если люди постепенно приходят, то их дела можно оформлять постепенно, и это не создаст большого труда. Но сотрудники не всегда только приходят, они переводятся на другие должности, получают благодарственные письма, так же могут быть и выговоры, все это необходимо заносить в личное дело.
Если представить себе сотрудницу отдела кадров, у которой четыре тысячи дел, и к ней придет служебная записка, что сотрудник «Иванов», переводится на новую должность, и это надо занести в личное дело, поиск этого дела может занять большой промежуток времени. Вот тут как раз и приходят на помощь современные вычислительные системы, а именно, клиент-серверные приложения. Если разобрать всю туже ситуацию с переводом сотрудника «Иванова» на новую должность, но с учетом современных вычислительных систем, то все становится намного проще. Если даже база данных большая, и организованна не совсем правильно, на поиск сотрудника уйдет максимум 10 минут времени, и при этом сотруднице отдела кадров ничего делать не надо, просто сидеть и ждать, пока компьютер сам все сделает.
По итогам всего выше сказанного выбор очевиден, что клиент-серверные приложения, намного упрощают и ускоряют работу. Что, впоследствии, ведет к росту производительности сотрудников, уменьшает время простоя из-за невыполненного распоряжения, а так же благосостояния предприятия, а, следовательно, и его сотрудников.
В ходе выполнения дипломной работы необходимо создать многопользовательское клиент-серверное приложение для управления персоналом предприятия. Приложение должно быть постоянно связанно с базой данных, в которой располагается вся информация о сотрудниках. Позволять пользователям не только просматривать имеющуюся информацию, но добавлять и изменять имеющиеся данные. Так же добавлять новых сотрудников, и удалять существующих.
Получать интересующую информацию в виде отчетов, иметь возможность сохранить отчеты на жесткий диск, либо выводить на печать.
3.2 Разработка базы данных
Для решения поставленной задачи была разработана база данных, в которой будут храниться все данные. Для полноценной работы приложения в СУБД Oracle было создано 30 таблиц (таблица 3.1) Более детальное описание таблиц можно посмотреть в приложении А.
Таблица 3.1 - Список таблиц базы данных
Название таблицы |
Описание таблицы |
|
DOLSHNOST |
Названия всех должностей на предприятии |
|
DOLSHNOST PREFIX |
Возможные префиксы должностей |
|
DOLSHOST SUFIX |
Возможные суффиксы должностей |
|
INVALIDNOST |
Перечень всех сотрудников, у которых имеется та или иная инвалидность |
|
KEM VIDAN |
Список органов, которые могут выдавать паспорта |
|
KONTAKTNIE DANIE |
Контактные данные сотрудников |
|
LICO |
Список всех лиц, которые, так или иначе, относятся к предприятию |
|
MESTO RABOTI |
Перечень всевозможных мест работы |
|
MESTO SHITELSTVA |
Полный адрес места жительства сотрудника |
|
NASELENI PUNKT |
Список населенных пунктов |
|
OBLAST |
Список областей |
|
OBRAZOVANIE |
Сведения об образовании сотрудников |
|
PASPORT |
Паспортные данные на сотрудника |
|
PENSIONERI |
Список пенсионеров предприятия |
|
POL |
Пол сотрудника |
|
PRICHINA VIXODA NA PENSIE |
Причина, по которой сотрудник вышел на пенсию |
|
RABOTA |
Информация о текущем и старом месте работы всех сотрудников предприятия |
|
RAEN |
Список районов |
|
SPECIALNOST |
Название специальности, которую сотрудник получил по окончании обучения |
|
SROCHNAIA SLUSHBA |
Информация о прохождении срочной службы |
|
STRANA |
Список стран |
|
TIP INVALIDNOSTI |
Перечень возможных инвалидностей |
|
TIP NAS PUNKTA |
Перечень типов населенных пунктов |
|
TIP KONTAKT DANNIX |
Перечень возможных контактных данных |
|
TIP MESTA SHITELSTVA |
Перечень возможных мест жительства |
|
TIP PASPORTA |
Перечень возможных типов паспорта |
|
TIP UCH ZAVEDENIA |
Перечень типов учебных заведений |
|
UCHEBNOE ZAVEDENIE |
Список названий учебных заведений |
|
ULICA |
Список улиц |
|
ZVANIE |
Список званий, которые сотрудники получали по окончании срочной службы |
Схему таблиц базы данных можно увидеть на рисунке 3.1
После создания всех таблиц были определенны связи между первичными и вторичными ключами таблиц, что бы база данных полностью соответствовала реляционной модели. Затем на основе первичных ключей таблиц были созданы индексы, для более быстрого поиска данных по первичным ключам. Пример всего выше написанного можно увидеть на листинге 3.1
Рисунок 3.1 - Схема таблиц базы данных
Листинг 3.1 - Создание таблицы, первичного ключа, связей, индекса
CREATE TABLE LICO
ID NUMBER(6) NOT NULL,
FAMILIA VARCHAR2(100 BYTE) NOT NULL,
IMIA VARCHAR2(100 BYTE) NOT NULL,
OTCHESTVO VARCHAR2(100 BYTE) NOT NULL,
DATA_ROSHDENIA DATE NOT NULL,
ID_POL NUMBER(6) NOT NULL,
ID_MESTO_ROSHDENIA NUMBER(6) NOT NULL,
ID_SROCH_SLUSHBA NUMBER(6),
PHOTO BLOB)
ALTER TABLE LICO ADD (
CONSTRAINT LICO_PK
PRIMARY KEY
ALTER TABLE LICO ADD (
CONSTRAINT LICO_MESTO_ROSHDENIA_FK
FOREIGN KEY (ID_MESTO_ROSHDENIA)
REFERENCES NASELENI_PUNKT (ID),
CONSTRAINT LICO_POL_FK
FOREIGN KEY (ID_POL)
REFERENCES POL (ID),
CONSTRAINT LICO_SROCH_SLUSHBA_FK
FOREIGN KEY (ID_SROCH_SLUSHBA)
REFERENCES SROCHNAIA_SLUSHBA (ID));
CREATE UNIQUE INDEX LICO_PK ON LICO
(ID);
Так как в СУБД Oracle нет механизма для автоматической генерации уникальных значений первичных ключей, для этой цели, для каждой таблицы базы данных, были созданы последовательности. Пример создания последовательности для выше описанной таблицы можно увидеть на листинге 3.2
Листинг 3.2 - Создание последовательности
CREATE SEQUENCE SQ_LICO
START WITH 0
MAXVALUE
MINVALUE 0
NOCYCLE
NOCACHE
ORDER;
Теперь у нас таблица, и есть последовательность для генерации уникальных значений первичных ключей, осталось только связать их между собой. Для этого можно пойти двумя путями:
1. создать триггер, который будет выполняться вместо вставки новой записи;
2. создать хранимые процедуры для вставки новых записей в таблицы.
Мы пойдем вторым путем, т.к. наиболее наглядный для дальнейшего разработчика приложения, и ему нет необходимости знать SQL команды, он может просто вызвать хранимую процедуру и передать в нее соответствующие параметры. У этого метода есть еще один плюс, все эти команды будут выполнять на сервере приложения, что значительно ослабит нагрузку на сеть.
Хранимые процедуры были так же созданы для каждой таблицы, в зависимости от процедуры было описано разное количество параметров. Пример хранимой процедуры для добавления данных можно увидеть на листинге 3.3, пример приведен все для той же таблицы LICO. Все процедуры для добавления в новых данных в таблицы были объединены в один пакет INSERT_TO_TABLE, это было сделано для последующего удобства поиска процедур на добавление, ведь теперь они все в одном месте. Но это не главная причина для создания пакета, если вдруг были произведены какие-либо изменения в базе данных, не надо будет искать все процедуры и заново их компилировать на поиск возможных ошибок, достаточно просто перекомпилировать один пакет.
Листинг 3.3 - Создание процедуры для добавления записей в таблицу
PROCEDURE Insert_LICO (
FAMILIA IN VARCHAR2,
IMIA IN VARCHAR2,
OTCHESTVO IN VARCHAR2,
DATA_ROSHDENIA IN DATE,
ID_POL IN NUMBER,
ID_MESTO_ROSHDENIA IN NUMBER,
ID_SLUSHBA IN NUMBER,
P_PHOTO IN BLOB)
IS
BEGIN
INSERT INTO lico
VALUES (sq_lico.NEXTVAL,
familia,
imia,
otchestvo,
data_roshdenia,
id_pol,
id_mesto_roshdenia,
id_slushba,
P_PHOTO);
COMMIT;
END;
Теперь мы можем добавлять данные, но иногда их надо изменять. Для этого создадим еще один пакет, и теперь назовем его UPDATE_TO_TABLE, в этом пакете будут храниться все процедуры на изменения данных в таблицах.
Пример процедуры на изменения данных можно посмотреть на листинге 3.4. Как видно из листинга типы данных переменных не совсем обычные, это не совсем типы данных, это ссылки на типы данных, с которыми мы будем работать. Это сделано для предотвращения возможных ошибок, т.к. таблица может быть обновлена, и, на пример, размер текстового поля в таблице увеличен, и чтобы не редактировать процедуру, она сразу берет тип столбца.
Листинг 3.4 - Создание процедуры для обновления данных в таблице
PROCEDURE UPDATE_LICO (
p_id IN LICO.ID%TYPE,
p_fam IN lico.familia%TYPE,
p_imia IN lico.imia%TYPE,
p_otch IN LICO.OTCHESTVO%TYPE,
p_data_r IN LICO.DATA_ROSHDENIA%TYPE,
p_mesto_r IN LICO.ID_MESTO_ROSHDENIA%TYPE)
AS
BEGIN
UPDATE lico
SET LICO.FAMILIA = p_fam,
LICO.IMIA = p_imia,
LICO.OTCHESTVO = p_otch,
LICO.DATA_ROSHDENIA = p_data_r,
lico.id_mesto_roshdenia = p_mesto_r
WHERE LICO.ID = p_id;
COMMIT;
END UPDATE_LICO;
Для удаления записей в таблицах не было ничего сделано, т.к. СУБД Oracle сама все сделает за нас. Для этого достаточно написать пару слов при создании связей, а именно ON DELETE CASCADE. Пример использования этого оператора можно увидеть на листинге 3.5. Если будет удален сотрудник из базы данных, то вместе с ним удалиться вся информация о нем.
Листинг 3.5 - Создание связи с каскадным удалением данных
CONSTRAINT RABOTA_LICO_FK
FOREIGN KEY (ID_SOTR) REFERENCES LICO (ID)
ON DELETE CASCADE
На этом основная разработка базы данных окончена, осталось наполнить ее тестовой информацией.
В ходе разработки приложения, была выявлена необходимость в создании еще ряда дополнительных объектов базы данных, в частности представлений, т.к. часто необходимо было использовать данные из нескольких таблиц, и каждый раз писать большие запросы нецелесообразно. Всего было создано 13 представлений, список которых можно увидеть в таблице 3.2.
Таблица 3.2 - Список представлений базы данных
Название представления |
Описание представления |
|
VW_FULL_RABOTA |
Полная информация о местах работы |
|
VW_FULL_REPORT |
Полная информация о сотруднике и текущем месте работы |
|
VW_FULL_SOTRUDNIKI |
Полная информация о сотрудниках |
|
VW_INVALIDNOST |
Список сотрудник с инвалидностью |
|
VW_KONTAKTI_SOTR |
Все контакты сотрудников |
|
VW_MESTO_SHITELSTVA |
Места жительства сотрудников |
|
VW_OBRAZOVANIE |
Список полученных и получаемых образований сотрудниками |
|
VW_PASPORTA |
Информация о паспортах сотрудников |
|
VW_PENSIONERI |
Список всех пенсионеров |
|
VW_RABOTA |
Краткая информация о текущем месте работы |
|
VW_RABOTA_PENSIONERI |
Последнее место работы пенсионеров |
|
VW_SLUSHBA |
Список мест службы сотрудников |
|
VW_SOTRUDNIKI |
Краткая информация о сотрудниках |
Пример создания представления можно увидеть на листинге 3.6
Листинг 3.6 - Создание представления
CREATE OR REPLACE FORCE VIEW VW_FULL_RABOTA (
ID,PREF, ID_PREF, DOLSHNOST, ID_DOLSHNOST, SUF, ID_SUF,
MESTO_RAB, ID_MESTO_RABOTI, DATA_PRIEMA, DATA_OKONCHANIA,
ID_SOTR)
AS
SELECT A.ID, A.NAZVANIE AS PREF, A.ID_PREF,
DOLSHNOST.NAZVANIE AS DOLSHNOST,
DOLSHNOST.ID AS ID_DOLSHNOST,
A.NOMER AS SUF, A.ID_SUF,
MESTO_RABOTI.NAZVANIE AS mesto_rab,
MESTO_RABOTI.ID AS ID_MESTO_RABOTI,
RABOTA.DATA_PRIEMA, RABOTA.DATA_OKONCHANIA,
RABOTA.ID_SOTR
FROM (SELECT P.ID,
P.NAZVANIE,
P.ID_PREF,
S.NOMER,
S.ID_SUF
FROM (SELECT RABOTA.ID,
DOLSHNOST_PREFIX.NAZVANIE,
DOLSHNOST_PREFIX.ID AS ID_PREF
FROM rabota
LEFT JOIN
dolshnost_prefix
ON RABOTA.ID_DOLSH_PREF = DOLSHNOST_PREFIX.ID) P
INNER JOIN
(SELECT RABOTA.ID,
DOLSHOST_SUFIX.NOMER,
DOLSHOST_SUFIX.ID AS ID_SUF
FROM rabota
LEFT JOIN
dolshost_sufix
ON RABOTA.ID_DOLSH_SUF = DOLSHOST_SUFIX.ID) S
ON P.ID = S.ID) A,
rabota,
dolshnost,
mesto_raboti
WHERE A.ID = RABOTA.ID
AND RABOTA.ID_DOLSHNOSTI = DOLSHNOST.ID
AND RABOTA.ID_MESTO_RAB = MESTO_RABOTI.ID
ORDER BY RABOTA.DATA_PRIEMA DESC;
Так же было создано еще два пакета с процедурами, для добавления данных и редактирования, ADD_LICO и EDIT_LICO соответственно.
3.3 Разработка клиент-серверного приложения
Разработку клиент-серверного приложения начнем с создания нового проекта, с именем «OtdelKadrov.dproj», а главный модуль приложения назовем «Main.pas».
При окончании создания приложения, она состоит из 18 визуальных модулей, 2 оконных модулей и 2 не визуальных модулей, схему модулей приложения можно увидеть на рисунке 3.2.
Рисунок 3.2 - Схема приложения
Главный модуль приложения Main.pas является главным. Т.к. приложение организованно как MDI приложение, то мы для модуля Main установим свойство FormStyle равным fsMDIForm. Это означает что все формы, у которых свойство FormStyle будет установлено fsMDIChild будут отображаться внутри главной формы, т.е. они будут являться дочерними формами по отношению к главной форме.
Для соединения с базой данных были выбраны драйверы dbExpress, потому что они небольшие по объему и быстрые. Каждый драйвер выполнен в виде dll (на платформе Windows) или как so (shared library на Linux). Драйвер dbExpress предоставляет пять интерфейсов для выборки метаданных, выполнения операторов SQL и хранимых процедур, и возможность чтения записей из выборки в одном направлении (unidirectional cursor). При установке клиента от Oracle для работы с базой данных установлены необходимые dll - библиотеки, а именно dbxora.dll и oci.dll.
Для соединения с БД разработана процедура, пример которой можно увидеть на листинге 3.7
Листинг 3.7 - Соединение с базой данных
with SQLConnection1 do
begin
Close;
LoginPrompt := False;
DriverName := 'Oracle';
with Params do
begin
Clear;
Add('Database=' + DB);
Add('User_name=' + user);
Add('Password=' + pas);
Add('Create=false');
end;
try
Open;
SQLConnection1.ExecuteDirect('alter session set
nls_numeric_characters=' + QuotedStr('.,'));
В данной процедуре происходит соединения с БД, а также необходимая настройка клиента. Соединение происходит при помощи компонента TSQLConnection. Для работы с базой данных одного лишь соединения недостаточно, т.е. доступ к данным есть, но посмотреть их мы не можем. Для просмотра данных необходимо использовать соответствующие компоненты. В данном случае использовались TSQLQuery (выполнение запросов к БД), TSQLStoredProc (выполнение хранимых процедур) и TSimpleDataSet (выполнение процедур, запросов или отображение таблиц).
Так же реализован механизм сохранения учетных данных авторизации сотрудников, небольшой пример кода, реализующего этот механизм можно увидеть на листинге 3.8
Листинг 3.8 - Сохранение данных для авторизации
ini := TInifile.Create(ExtractFileDir(Application.ExeName) +
'Auth.ini');
try
ini.WriteString('Auth', 'DB', DB);
ini.WriteString('Auth', 'user', user);
ini.WriteString('Auth', 'pas', pas);
ini.WriteBool('Auth', 'Check', True);
Для увеличения производительности приложения все формы создаются только в момент потребности в них, при закрытии формы она уничтожается и освобождает занимаемые ими ресурсы, что продемонстрированно на листинге 3.9.
Листинг 3.9 - Динамическое создание формы
try
Form7 := TForm7.Create(Form1);
Form7.ShowModal;
finally
FreeAndNil(Form7);
end;
Все команды управления приложением созданы в менеджере действий «ActionManager». Менеджер действий позволяет организовать логические группы действий, которые впоследствии могут быть повторно использованы в меню, навигационных панелях и панелях кнопок. Такие группы действий становятся доступными автоматически -- по мере их добавления к объекту.
Для приложения выбран тип интерфейса Ribbon. При использовании интерфейса Ribbon большинство функций распределяются по вкладкам новой панели. Некоторые функции перенесены в выпадающие меню, появляющиеся при нажатии на кнопку слева от вкладок (кнопка «Office» в Office 2007 или «Файл» в 2010-м), и дополнительную кнопку в заголовке (меню быстрого вызова). Кнопки функций, которые нужны постоянно (отменить, повторить, сохранить), вынесены в заголовок окна. Для связи интерфейса и менеджера действий в свойстве интерфейса Ribbon, ActionManager установлено значение нашего менеджера действий ActionManager1.
Для группировки сотрудников написана процедура, листинг 3.10, с ее помощью фамилии сотрудников заносятся в ту или иную ветку дерева, а если нет соответствующей ветки, она создается и в нее помещается соответствующий сотрудник. Дерево реализовано с помощью компонента TreeView.
Листинг 3.10 - Формирование дерева сотрудников
with TreeView1.Items do
begin
BeginUpdate;
with SimpleDataSet1 do
begin
First;
while not Eof do
begin
New(obj);
ferst := FieldByName('FAMILIA').AsString[1];
obj^ := FieldByName('ID').AsInteger;
Node := FindNode(ferst);
if Node = nil then
begin
TreeView1.Items.Add(nil, ferst);
Node := FindNode(ferst);
end;
TreeView1.Items.AddChildObject(Node,
FieldByName('FAMILIA').AsString + ' ' +
FieldByName('IMIA').AsString + FieldByName('OTCHESTVO').AsString, obj);
end;
Все узлы компонента TTreeView хранятся в свойстве Items класса TTreeNоdes и имеют тип TTreeNоde. У класса TTreeNоde нас интересуют два свойства Data - данное свойство принадлежит к типу Pоinter и является указателем для связанного с узлом объекта и Text - текст, который выводится в узле. Как видно из листинга 3.10, а именно из метода
AddChildObject(Nоde:TTreeNоde; cоnst S:string; Ptr:Pоinter)
Где Node - узел, в который добавляется запись, S - это наше свойства Text, и Ptr - свойство Data.
В свойство Data мы заносим ID сотрудника, а в Text фамилию имя и отчество. Сделано это, что бы однозначно определить, какой сотрудник сейчас выбран и, конечно, для удобства пользователя, ведь ему нет необходимости знать первичный ключ выбранного сотрудника. Что бы извлечь первичный ключ достаточно выполнить одну строчку
id := integer(Node.Data^);
После чего в переменной id хранится первичный ключ сотрудника, и уже опираясь на это значение, можно получать всю интересующую информацию о сотруднике из базы данных.
Для реализации фильтрации сотрудников на форму был установлен компонент TEdit. Чтобы обновление найденных сотрудников происходило при каждом изменении значения данных в поле ввода, использовалось событие компонента OnChange. Пример обработчика можно увидеть на листинге 3.11. Фильтрация реализуется при помощи свойства Filter и Filtered компонента TSimpleDataSet. В свойстве Filter устанавливается значение фильтра, но фильтрация данных не происходит, для фильтрации и обновления набора данных, необходимо изменить значение свойства Filtered на True. Если же потребность в фильтрации пропадает, достаточно установить свойство Filtered в False.
Листинг 3.11 - Фильтрация данных
// настройка фильтра
case ComboBox1.ItemIndex of
0:
str := 'FAMILIA ';
1:
str := 'IMIA ';
2:
str := 'OTCHESTVO ';
end;
SimpleDataSet1.Filter := str + ' LIKE ' +
QuotedStr(Edit1.Text + '%');
SimpleDataSet1.Filtered := True;
// перестроение списка
if form2.Spisok = Alfavit then
showAlfavit(False, Asceding)
else
ShowMestoRaboti(False, Asceding);
Все отчеты приложения создаются в RaveReport. Для создания отчетов нам понадобятся TRvProject - основной компонент отчета, TRvSystem - для генерации отчетов и вывода их на принтер или в окно просмотра, а так же TRvDataSetConnection - для взаимодействия с источником данных, в нашем случае TSimpleDataSet. Соответственно, следует связать компонент TRvDataSetConnection с TSimpleDataSet, установив у него в свойстве DataSet значение SimpleDataSet1. Что касается компонента TRvProject, то его следует связать с компонентом RvSystem, для чего в свойстве Engine следует установить значение RvSystem1. Так же нас интересует свойство ProjectFile компонента TRvProject, сделано оно для выбора отчета, который будет в данный момент отображен. Для отчетов был создан отдельный каталог «Report», который находится в одном месте с приложением. Пример выполнения отчета можно увидеть на листинге 3.12
Листинг 3.12 - Выполнение отчета
RvProject1.Close;
if FileExists(ExtractFileDir(Application.ExeName) +
'ReportSpisok.rav') then
begin
RvProject1.ProjectFile:=ExtractFileDir(Application.ExeName)
+ 'ReportSpisok.rav';
RvProject1.Execute;
end;
Как видно из листинга 3.12, что бы избежать ненужных ошибок, файлы отчетов ищутся в том же месте, где находится само приложение, если же файл отчета не будет найден, отчет просто не отобразиться.
3.4 Инструкция работы с приложением «Отдел кадров»
Все элементы управления приложением разбиты на три вкладки, рассмотрим их по порядку.
На первой вкладке, которую мы видим сразу при запуске приложения, находятся элементы управления соединения с базой данных, а так же элементы управления дочерними окнами, так как приложение разработано как MDI приложение.
По мере возможности выполнения того или иного действия, становятся доступными соответствующие элементы управления.
Для начала работы с базой данных, с ней необходимо соединиться. Для этого надо выбрать соответствующий пункт меню «Соединиться», после чего на экране появиться форма для соединения с базой данных.
При выборе тех или иных параметров соединения, процесс соединения может отличаться. К примеру, если отметить пункт «Больше не показывать это окно», то при последующем соединении с БД окно авторизации не отобразиться, и соединение будет произведено под сохраненными данными. Эти данные так же можно ввести вручную либо отменить сохранение данных, это можно сделать, вызвав настройки приложения.
Команда «Отсоединиться» наоборот, разрывает связь с базой данных. Остальные команды предназначены для управления дочерними формами, с помощь этих команд можно выполнить одно из действий:
· Расположить все дочерние окна каскадно;
· Расположить все дочерние окна по вертикали;
· Расположить все дочерние окна по горизонтали;
· Свернуть все дочерние окна;
· Закрыть все дочерние окна.
Вся работа с приложением сосредоточена на вкладке «Отдел кадров»
После соединения с базой данных появляется возможность просматривать, редактировать и удалять данные. Рассмотрим предоставленные возможности.
Чтобы просмотреть данные о сотрудниках предприятия, необходимо выбрать соответствующий пункт меню «Сотрудники». После чего на экране отобразиться окно приложения с одноименным названием «Сотрудники». Вместе с тем становятся доступными элементы управления списком сотрудников на панели инструментов приложения.
Для удобства пользования приложением отображение списка организованно не просто в виде списка, а автоматически происходит группировка по первой букве фамилии, как видно на рисунке 3.7. Но этого может оказаться мало, к примеру, мы знаем в каком цехе или отделении работает сотрудник, но не знаем его имени и фамилии, для этого можно организовать группировку по месту работу, выбрав «Список» - «По местам работы», либо нажав «CTRL+F2». Для перехода обратно к группировке по алфавиту придется нажать «CTRL+F1», либо же «Список» - «По алфавиту». Кроме этого, для облегчения поиска нужного сотрудника имеется возможность поиска сотрудника по одному из фильтров: фамилии, имени или отчеству.
Чтобы еще немного упростить работу пользователя, можно выбирать порядок вывода сотрудников в список: по возрастанию или убыванию. Так же можно одним нажатием развернуть либо свернуть все дерево в независимости от того, в каком виде отображается список сотрудников. Для этих команд также реализованы горячие клавиши. Как видно на рисунках 3.7 и 3.8, при выборе одного из сотрудников, справа появляется наиболее востребованная информация о нем, а именно:
· ФИО, пол, возраст, фото;
· Актуальные контактные данные;
· Текущее место работы.
Для более детальной информации о сотруднике придется открыть личную карточку сотрудника, сделать это можно несколькими способами:
· нажав на панели инструментов «Личная карточка»;
· двойным кликом левой клавиши мыши в дереве по его имени сотрудника;
· воспользоваться сочетанием клавиш «CTRL+L».
На экране появится окно с детальной информацией
Личная карточка открывается в модальном режиме, поэтому работу с приложением можно будет продолжить только после его закрытия.
Как видно из рисунка 3.9, вся информация разбита по категориям. Здесь можно найти всю имеющуюся информацию на сотрудника. Так же можно заметить, что у окна имеются свои элементы управления, сделаны они для редактирования имеющейся информации о сотруднике.
Для редактирования достаточно нажать на кнопку «Редактировать», которая представлена в виде пиктограммы карандаша, в зависимости от отображаемой категории данных откроются дополнительные элементы управления, либо данные будут помещены в редактируемые поля, как это продемонстрированно на рисунке 3.10.
Для сохранения или отмены редактирования информации организованны соответствующие элементы управления «Сохранить» и «Отменить», которые представлены в виде пиктограмм птички и крестика соответственно. Они становятся доступны только после открытия информации на редактирование.
Если же информацию нельзя сразу поместить в элементы редактирования, то для них организованны дополнительные элементы управления и вспомогательные окна.
На окнах присутствуют дополнительные элементы, а именно кнопки «Добавить», с пиктограммой «Плюс», добавлены они для оперативного добавления информации в базу данных, если такой еще не имеется
Теперь мы можем просматривать информацию и редактировать ее, теперь надо иметь возможность добавлять новых сотрудников в нашу базу данных. Для этих целей организован пошаговый мастер, для вызова необходимо выбрать «Мастер», либо воспользоваться сочетанием клавиш CTRL+M.
Идя по мастеру, необходимо обязательно заполнять поля помеченные «*», остальные же поля заполняются по желанию пользователя. Во избежание непонимания того или иного поля для заполнения, мастер оборудован интерактивными подсказками. Для их отображения достаточно подвести указатель к непонятному полю, и в нижней части окна, появиться текст, описывающий это поле. Поле, где отображаются подсказки, расположено в нижней части окна на каждом шаге мастера.
После выполнения всех шагов мастера, предлагается еще раз посмотреть всю введенную информацию о сотруднике
На данном шаге добавления пользователь еще раз проверяет всю информацию о новом сотруднике, если, вдруг, найдены ошибки или недочеты, пользователь может вернуться обратно к мастеру, выполнив щелчок по кнопке «Вернуться к мастеру», и исправить ошибку. После чего опять отобразить окно со всей имеющейся информацией. Если все верно, то по нажатию на кнопку «Создать» произойдет создание нового сотрудника, со всей введенной информацией. По окончанию создания сотрудника, в зависимости от исхода выполнения процедуры добавления, появиться окно подтверждающее создание нового сотрудника, либо же уведомление об ошибке.
Далее рассмотрим удаление сотрудников из базы данных. Для этого необходимо найти на панели управления приложением кнопку «Удалить», либо воспользоваться горячей клавишей «DEL». После чего пользователь увидит предупредительное окно с подтверждением удаления записи. Как уже говорилось выше, вместе с записью сотрудника будет удалена вся ему присущая информация.
В базе данных хранятся не только текущие работники завода, но так же и бывшие - пенсионеры. Для их отображения надо воспользоваться кнопкой «Пенсионеры». На экране приложения появится окно схожее с тем, в котором отображаются сотрудники, только с небольшим исключением, а именно, в окне с более востребованной информацией теперь выводиться не текущее место работы, а последнее и отображается дата выхода на пенсию.
Для того, что бы отправить сотрудника на пенсию, необходимо в личной карточке сотрудника, перейти на вкладку «Работа», открыть информацию для редактирования, после нажать на кнопку «Выход на пенсию», указать дату выхода на пенсию, и причину.
После сохранения данной информации, в нижней части личной карточки, появиться надпись с информацией о выходе на пенсию
После сохранения этих данных у сотрудника будет обновлена информация о последнем месте работы, а именно дата окончания будет указана предыдущая дню выхода н пенсию, а так же добавлена информация в таблицу пенсионеров.
Имеются еще небольшие изменения в работе с записями пенсионеров, теперь в личной карточке нельзя будет изменять место работы. И для просмотра дерева пенсионеров доступна группировка лишь по алфавиту. В остальном работа с записями пенсионеров полностью идентична работе с записями сотрудников. Тут также доступен поиск по записям, выбор порядка вывода записей, управление деревом, удаление записей.
На этом рассмотрение вкладки «Отдел кадров» почти завершено, осталась пару команда, одна из них «Печать». Команда предназначена для печати информации о сотрудниках. Она реализована в виде выпадающего списка
При выборе того или иного отчета на печать, пользователю предлагается на выбор список действий:
· Предварительный просмотр отчета;
· Вывод сразу на принтер, без предварительного просмотра;
· Сохранение в файл.
Это все то, что касалось одного сотрудника, теперь перейдем к последней команде «Отчеты» на вкладке «Отдел кадров». Здесь собраны все отчеты, которые касаются всех сотрудников предприятия. Команда также организованна как выпадающий список.
Рассмотрим самый интересный из всех этих отчетов «Сотрудники (с параметрами)». Перед выполнением отчета, на экран выводится окно с предварительной настройкой фильтра. Здесь пользователь может настроить фильтры по своему желанию, после чего нажать на кнопку «Ок», и на экран выведется отчет с его фильтрами. Если отчет пользователя не удовлетворит, или пользователь точно не знает, какие ему нужны параметры, он может снять галочку с пункта «Закрыть окно после выполнения отчета». Если она стоит, после закрытия отчета окна тоже закроется, и всю введенную информацию придется вводить заново. Что может быть не совсем удобно, если точно не определенны параметры отчета.
Создадим отчет со следующими параметрами:
· Место работы - АСУП
· Возраст - 18-30
После чего запустим его на выполнение, и на экране появиться отчет
На этом рассмотрение вкладки «Отдел кадров» закончено, можно переходить к последней вкладке «Справочники», которая носит больше справочную информацию, чем информативную, хотя вносить изменения в базу данных также имеется возможность.
На этой вкладке можно просматривать всю справочную информацию в базе данных, для этого есть пункт с одноименным название «Справочники».
Но не все справочники удобно просматривать в виде списка, к примеру, справочник «Место работы», на рисунке 3.28 (справа), имеет ссылку сам на себя, такой справочник удобнее просматривать в виде дерева, что в приложении и организовано. В таком же виде, в виде дерева, организован справочник «Населенные пункты», на рисунке 3.28 (слева). Как видно из рисунка 3.26, на вкладке «Справочники» присутствует группа элементов «Управление», она содержит следующие команды:
· Переход на первую строку справочника;
· Переход на предыдущую строку;
· Переход на следующую строку;
· Переход на последнюю строку;
· Обновить справочник;
· Добавить новую строку;
· Удалить строку;
· Редактировать строку;
· Сохранить изменения;
· Отменить сделанные изменения.
Организованны они для управления справочниками, которые отображаются в виде простого списка. Для справочников же, которые отображаются в виде дерева, имеются свои элементы управления, которые расположены в том же окне, что и деревья с информацией.
На этом рассмотрение всех вкладок приложения окончено. Если пользователю будет не понятно назначение той ли иной команды, можно просто подвести указатель к команде, и через некоторое время на экране появиться подсказка по данной команде
Окнами можно управлять и через эти вкладки, для этого необходимо вызвать контекстное меню вкладки, которое содержит следующие пункты:
· Свернуть;
· Развернуть;
· Восстановить;
· Закрыть.
серверный персонал клиент кадр
Заключение
В данной работе разработано клиент-серверное приложение 'Отдел кадров'. Для разработки приложение использовалась интегрированная среда разработки Delphi XE, и СУБД Oracle 11g r2. Главным преимуществом данной среды является быстрота разработки программного обеспечения, благодаря наличию визуальных средств проектирования приложения, таких, как формы и набор визуальных и не визуальных компонентов, обладающих богатым функционалом. СУБД Oracle была взята за основу за свою надежность, функциональность и гибкость.
В результате получена информационная система, предоставляющая пользователям простой и удобный способ взаимодействия с базой данных. Информационная система легко модифицируема, при возникновении необходимости возможна дальнейшая ее доработка (как базы данных, так и клиентского приложения) для расширения круга решаемых задач. Полученная в результате проведенной работы информационная система в полной мере удовлетворяет поставленной задаче, что не исключает возможности расширения её функциональных возможностей в будущем. Клиентское приложение в совокупности с грамотно организованной базой данных позволяет облегчить работу сотрудников предприятия.
Данное клиент-серверное приложение можно внедрять и использовать на любом предприятии, на котором есть желание автоматизировать работу отдела кадров.
Список использованных источников
1) Генник, Жд. Oracle SQL*Plus. Карманный справочник. 2-е издание. - СПб.: Питер. - 2004. - 189 с., ил.
2) Нанда, А., Фейерштейн, С. Oracle PL/SQL для администраторов баз данных. - Пер. с англ. - СПб: Символ-Плюс, 2008. - 496 с., ил.
3) Р. Гринвальд, Р. Стаковьяк, Жд. Стерн. Oracle 11g. Основы, 4-е издание. - Пер. с англ. - СПб.: Символ-Плюс, 2009. - 464 с., ил.
4) Наместников, А.М. Построение баз дынных в среде Oracle. Практический курс: Учеб. пособие для вузов. Ульяновск: УлГТУ, 2008. 118 с.
5) Культин, Н. Б. Основы программирования в Delphi XE. - СПб.: БХВ-Петербург, 2011. - 416 с.: ил. + CD-ROM - (самоучитель)
6) Осипов, Д.Л. Базы данных и Delphi. Теория и практика - СПб.: БХВ-Петербург, 2011. - 752 с.: ил. + DVD - (Профессиональное программирование)
7) Хомоненко, А.Д., Гофман, В.Э. Работа с базами данных в Delphi. - 3-е изд., перераб. и доп. - СПб.: БХВ-Петербург, 2005. - 640 с.: ил
8) Русскоязычный форум по программированию [Электронный ресурс] // Русскоязычный форум по программированию - 2000. - Режим доступа - http://www.sql.ru. - Дата доступа: 08.04.2013.
Приложения
Приложение А. Описание таблиц базы данных
Таблица A.1 - Таблица DOLSHNOST
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
NAZVANIE |
Varchar2 |
Название должности |
Таблица A.2 - Таблица DOLSHNOST_PREFIX
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
NAZVANIE |
Varchar2 |
Название префикса должности |
Таблица A.3 - Таблица DOLSHNOST_SUFIX
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
NOMER |
Number |
Суффикс должности |
Таблица A.4 - Таблица INVALIDNOST
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
ID_TIP_INVALIDNOSTI |
Number |
Id типа инвалидности сотрудника |
|
ID_LICO |
Number |
Id сотрудника |
|
DATA_POLUCHENIA |
Date |
Дата получения инвалидности |
Таблица A.5 - Таблица KEM_VIDAN
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
NAZVANIE |
Varchar2 |
Название органа, который выдал паспорт |
|
ID_OBLAST |
Number |
Id области, в которой выдали паспорт |
Таблица A.6 - Таблица KONTAKTNIE_DANIE
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
ID_TIP_DANNIX |
Number |
Id типа контактных данных |
|
DANNIE |
Varchar2 |
Контактные данные |
|
ID_LICO |
Number |
Id сотрудника |
Таблица A.7 - Таблица MESTO_RABOTI
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
NAZVANIE |
Varchar2 |
Название места работы |
|
ID_PODRAZDELENIE |
Number |
Id места работы |
Таблица A.8 - Таблица LICO
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
FAMILIA |
Varchar2 |
Фамилия сотрудника |
|
IMIA |
Varchar2 |
Имя сотрудника |
|
OTCHESTVO |
Varchar2 |
Отчество сотрудника |
|
DATA_ROSHDENIA |
Date |
Дата рождения сотрудника |
|
ID_POL |
Number |
Id пола сотрудника |
|
ID_MESTO_ROSHDENIA |
Number |
Id места рождения сотрудника |
|
ID_SROCH_SLUSHBA |
Number |
Id срочной служба |
|
PHOTO |
Blob |
Фото сотрудника |
Таблица A.9 - Таблица MESTO_SHITELSTVA
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
ID_NAS_PUNKTA |
Number |
Id населенного пункта |
|
ID_ULICA |
Number |
Id улицы |
|
DOM |
Number |
Номер дома |
|
KVARTIRA |
Number |
Номер квартиры |
|
KORPUS |
Varchar2 |
Номер корпуса |
|
DATE_ZASELENIA |
Date |
Дата заселения |
|
DATE_VIPISKI |
Date |
Дата выписки |
|
ID_TIP_MESTA_SH |
Number |
Id типа места жительства |
|
ID_LICO |
Number |
Id сотрудника |
Таблица A.10 - Таблица NASELENI_PUNKT
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
NAZVANIE |
Varchar2 |
Название населенного пункта |
|
ID_TIP_NAS_PUNKTA |
Number |
Id типа населенного пункта |
|
ID_RAEN |
Number |
Id района, в котором расположен населенный пункт |
Таблица A.11 - Таблица OBLAST
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
NAZVANIE |
Название области |
||
ID_STRANI |
Number |
Id страны, в которой расположена область |
Таблица A.12 - Таблица POL
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
NAZVANIE |
Varchar2 |
Название пола |
Таблица A.13 - Таблица OBRAZOVANIE
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
ID_LICO |
Number |
Id сотрудника |
|
ID_UCH_ZAVEDENIA |
Number |
Id учебного заведения |
|
DATA_OKONCHANIA |
Date |
Дата окончания |
|
NOMER_DIPLOMA |
Varchar2 |
Номер полученного диплома |
|
ID_SPECIALNOST |
Number |
Id полученной специальности |
|
DATA_POSTUPLENIA |
Date |
Дата поступления |
Таблица A.14 - Таблица PASPORT
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
ID_LICO |
Number |
Id сотрудника |
|
ID_TIP_PASPORTA |
Number |
Id типа паспорта |
|
NOMER |
Number |
Номер паспорта |
|
SERIA |
Varchar2 |
Серия паспорта |
|
ID_KEM_VIDAN |
Number |
Id кем выдан паспорт |
|
DATA_VIDACHI |
Date |
Дата выдачи паспорта |
|
DATA_OKONCHANIA |
Date |
Дата окончания действия паспорта |
Таблица A.15 - Таблица PENSIONERI
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
ID_SOTR |
Number |
Id сотрудника |
|
DATA_VIXODA |
Date |
Дата выхода на пенсию |
|
ID_PRICHINA |
Number |
Id причина выхода на пенсию |
Таблица A.16 - Таблица PRICHINA_VIXODA_NA_PENSIE
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
NAZVANIE |
Varchar2 |
Причина выхода на пенсию |
Таблица A.17 - Таблица SROCHNAIA_SLUSHBA
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
ID_NAS_PUNKTA |
Number |
Id населенного пункта, где расположена часть |
|
CHAST |
Varchar2 |
Номер части |
|
ID_ZVANIE |
Number |
Id звания по окончанию службы |
|
DATA_NACHALA |
Date |
Дата начала служба |
|
DATA_OKONCHANIA |
Date |
Дата окончания службы |
Таблица A.18 - Таблица RABOTA
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
ID_DOLSHNOSTI |
Number |
Id должности |
|
ID_DOLSH_PREF |
Number |
Id префикса должности |
|
ID_DOLSH_SUF |
Number |
Id суффикса должности |
|
ID_MESTO_RAB |
Number |
Id места работы |
|
DATA_PRIEMA |
Date |
Дата приема на работу |
|
DATA_OKONCHANIA |
Date |
Дата окончания работы |
|
ID_SOTR |
Number |
Id сотрудника |
Таблица A.19 - Таблица RAEN
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
NAZVANIE |
Varchar2 |
Название района |
|
ID_OBL |
Number |
Id области, в которой находится район |
Таблица A.20 - Таблица SPECIALNOST
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
NAZVANIE |
Varchar2 |
Название специальности по окончанию учебы |
Таблица A.21 - Таблица STRANA
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
NAZVANIE |
Varchar2 |
Название страны |
Таблица A.22 - Таблица TIP_INVALIDNOSTI
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
NAZVANIE |
Varchar2 |
Название типа инвалидности |
Таблица A.23 - Таблица TIP_KONTAKT_DANNIX
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
NAZVANIE |
Varchar2 |
Название типа контактных данных |
Таблица A.24 - Таблица TIP_MESTA_SHITELSTVA
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
NAZVANIE |
Varchar2 |
Название типа места жительства |
Таблица A.25 - Таблица TIP_NAS_PUNKTA
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
NAZVANIE |
Varchar2 |
Название типа населенного пункта |
Таблица A.26 - Таблица TIP_PASPORTA
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
NAZVANIE |
Varchar2 |
Название типа паспорта |
Таблица A.27 - Таблица TIP_UCH_ZAVED
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
NAZVANIE |
Varchar2 |
Название типа учебного заведения |
Таблица A.28 - Таблица UCHEBNOE_ZAVEDENIE
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
NAZVANIE |
Varchar2 |
Название учебного заведения |
|
ID_NAS_PUNKT |
Number |
Id населенного пункта, где расположено учебное заведение |
|
ID_TIP_ZAVEDENIA |
Number |
Id типа учебного заведения |
Таблица A.29 - Таблица ULICA
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
NAZVANIE |
Varchar2 |
Название улицы |
Таблица A.30 - Таблица ZVANIE
Название столбца |
Тип столбца |
Описание |
|
ID |
Number |
Первичный ключ |
|
NAZVANIE |
Varchar2 |
Название звания по завершению срочной служба |
Приложение Б. Модуль приложения Main.pas
unit Main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Ribbon, ActnMenus, RibbonActnMenus, ImgList, ActnList, ActnMan,
ToolWin, ActnCtrls, RibbonLunaStyleActnCtrls, Tabs, Menus,
iniFiles, ScreenTips, StdActns, DBActns, DB, DBClient, SimpleDS, RpBase,
RpSystem, RpRave, RpDefine, RpCon, RpConDS, DBXOracle, SqlExpr,
RibbonSilverStyleActnCtrls, RibbonObsidianStyleActnCtrls, ComCtrls, FMTBcd;
type
TForm2 = class(TForm)
Ribbon1: TRibbon;
RibbonPage1: TRibbonPage;
ActionManager1: TActionManager;
ImageList_32_e: TImageList;
RibbonApplicationMenuBar1: TRibbonApplicationMenuBar;
RibbonQuickAccessToolbar1: TRibbonQuickAccessToolbar;
TabSet1: TTabSet;
AcConnect: TAction;
AcDisconnect: TAction;
AcSetting: TAction;
AcExit: TAction;
AcSotrudniki: TAction;
AcPol: TAction;
AcDolshnost: TAction;
RibbonGroup4: TRibbonGroup;
bla: TAction;
AcMasterAdd: TAction;
RibbonPage2: TRibbonPage;
RibbonGroup1: TRibbonGroup;
ImageList_16_e: TImageList;
ImageList_32_d: TImageList;
ImageList_16_d: TImageList;
RibbonGroup2: TRibbonGroup;
ScreenTipsManager1: TScreenTipsManager;
RibbonGroup3: TRibbonGroup;
WindowCascade1: TWindowCascade;
WindowTileHorizontal1: TWindowTileHorizontal;
WindowTileVertical1: TWindowTileVertical;
WindowMinimizeAll1: TWindowMinimizeAll;
WindowArrange1: TWindowArrange;
AcKartochka: TAction;
AcDelete: TAction;
RibbonGroup5: TRibbonGroup;
RibbonGroup6: TRibbonGroup;
AcPrint: TAction;
PopupMenu1: TPopupMenu;
N1: TMenuItem;
N2: TMenuItem;
N3: TMenuItem;
N4: TMenuItem;
N5: TMenuItem;
AcVsiaRabota: TAction;
RibbonPage3: TRibbonPage;
acAlfavit: TAction;
acMestoRaboti: TAction;
acRefresh: TAction;
acSearch: TAction;
acFullExpand: TAction;
acFullCollapse: TAction;
acSortAsc: TAction;
acSortDesc: TAction;
acOProgramme: TAction;
RibbonGroup7: TRibbonGroup;
acPensioneri: TAction;
RibbonGroup8: TRibbonGroup;
DataSetFirst1: TDataSetFirst;
DataSetPrior1: TDataSetPrior;
DataSetNext1: TDataSetNext;
DataSetLast1: TDataSetLast;
DataSetInsert1: TDataSetInsert;
DataSetDelete1: TDataSetDelete;
DataSetEdit1: TDataSetEdit;
DataSetPost1: TDataSetPost;
DataSetCancel1: TDataSetCancel;
DataSetRefresh1: TDataSetRefresh;
acNaselPunkti: TAction;
acVseSotrudniki: TAction;
acReport: TAction;
acVseSotrudnikiParam: TAction;
acVsePensioneri: TAction;
acVozrastnoi: TAction;
SQLQuery1: TSQLQuery;
acDolshnostPref: TAction;
acDolshnostSuf: TAction;
acInvaidnost: TAction;
acKemVidan: TAction;
acPrichinaNaPensiu: TAction;
acSpecialnost: TAction;
acTipKontaktDanix: TAction;
acTipMestaShitelstva: TAction;
acTipNasPunkta: TAction;
acTipPasporta: TAction;
acTipUcZaved: TAction;
acUchZaved: TAction;
acUloca: TAction;
acZvanie: TAction;
acMestoRab: TAction;
procedure AcConnectExecute(Sender: TObject);
procedure AcDisconnectExecute(Sender: TObject);
procedure N1Click(Sender: TObject);
procedure N2Click(Sender: TObject);
procedure N3Click(Sender: TObject);
procedure N5Click(Sender: TObject);
procedure PMTabSetPopup(Sender: TObject);
procedure TabSet1Change(Sender: TObject; NewTab: Integer; var AllowChange: Boolean);
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure AcSettingExecute(Sender: TObject);
procedure AcExitExecute(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure AcSotrudnikiExecute(Sender: TObject);
procedure AcPolExecute(Sender: TObject);
procedure AcDolshnostExecute(Sender: TObject);
procedure AcGalleryButtonExecute(Sender: TObject);
procedure blaExecute(Sender: TObject);
procedure AcMasterAddExecute(Sender: TObject);
function FindForm(Caption: string): Boolean;
procedure AcDeleteExecute(Sender: TObject);
procedure AcKartochkaExecute(Sender: TObject);
procedure AcPrintExecute(Sender: TObject);
procedure AcVsiaRabotaExecute(Sender: TObject);
procedure ScreenTipsManager1ShowScreenTip(Manager: TObject; Action: TBasicAction;
var ShowScreenTip: Boolean);
procedure WindowArrange1Execute(Sender: TObject);
procedure acAlfavitExecute(Sender: TObject);
procedure acMestoRabotiExecute(Sender: TObject);
procedure Action1Execute(Sender: TObject);
procedure acRefreshExecute(Sender: TObject);
procedure acSearchExecute(Sender: TObject);
procedure acFullCollapseExecute(Sender: TObject);
procedure acFullExpandExecute(Sender: TObject);
procedure acSortAscExecute(Sender: TObject);
procedure acSortDescExecute(Sender: TObject);
procedure acOProgrammeExecute(Sender: TObject);
procedure acPensioneriExecute(Sender: TObject);
procedure acNaselPunktiExecute(Sender: TObject);
procedure acVseSotrudnikiExecute(Sender: TObject);
procedure acReportExecute(Sender: TObject);
procedure acVsePensioneriExecute(Sender: TObject);
procedure acVozrastnoiExecute(Sender: TObject);
procedure acVseSotrudnikiParamExecute(Sender: TObject);
procedure acDolshnostPrefExecute(Sender: TObject);
procedure acDolshnostSufExecute(Sender: TObject);
procedure acInvaidnostExecute(Sender: TObject);
procedure acKemVidanExecute(Sender: TObject);
procedure acPrichinaNaPensiuExecute(Sender: TObject);
procedure acSpecialnostExecute(Sender: TObject);
procedure acTipKontaktDanixExecute(Sender: TObject);
procedure acTipMestaShitelstvaExecute(Sender: TObject);
procedure acTipNasPunktaExecute(Sender: TObject);
procedure acTipPasportaExecute(Sender: TObject);
procedure acTipUcZavedExecute(Sender: TObject);
procedure acUchZavedExecute(Sender: TObject);
procedure acUlocaExecute(Sender: TObject);
procedure acZvanieExecute(Sender: TObject);
procedure acMestoRabExecute(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
var
CommandText: string;
Spisok: Integer;
ActiveForm: Integer;
end;
var
Form2: TForm2;
ini: TIniFile;
const
Alfavit = 0;
MestoRaboti = 1;
Asceding = 'asc';
Desceding = 'desc';
Sotrudnik = 0;
Pensioner = 1;
implementation
Uses Login, DataModule, Lico, Setting, Sotrudniki, Spravochnik, MasterAdd,
DataModuleReports, OProgramme, Pensioneri, SpravochnikNaselPunkt, Report,
SpravochnikMestoRaboti;
{$R *.dfm}
procedure TForm2.acAlfavitExecute(Sender: TObject);
begin
if form5.Panel3.Visible then
begin
form5.Panel3.Visible := False;
end;
if Spisok <> Alfavit then
form5.showAlfavit(True, Asceding);
end;
procedure TForm2.AcConnectExecute(Sender: TObject);
begin
// Соединение с БД
if Form4.RadioButton2.Checked then
begin
if FileExists(ExtractFileDir(Application.ExeName) + 'Auth.ini') then
begin
ini := TIniFile.Create(ExtractFileDir(Application.ExeName) + 'Auth.ini');
DataModule1.Connect(ini.ReadString('Auth', 'DB', ''), ini.ReadString('Auth', 'user', ''),
ini.ReadString('Auth', 'pas', ''));
Exit;
end
else
MessageBox(0, pWideChar('Файл не найден!'), 'Не норм', MB_ICONWARNING + MB_OK);
end;
try
Form1 := TForm1.Create(Application);
Form1.ShowModal;
finally
Form1.Free;
end;
end;
// удалить сотрудниками, со всеми ему подчиненными данными
procedure TForm2.AcDeleteExecute(Sender: TObject);
var
id: Integer;
begin
case ActiveForm of
Sotrudnik:
id := Sotrudniki.id;
Pensioner:
id := Pensioneri.id;
end;
if MessageBox(handle,
pWideChar(
'Вы действительно хотитет удалить сотрудника?'#10#13'Вместе с сотрудником будут удаленны всего его данные!'),
'Удаление записи', MB_ICONQUESTION + MB_OKCANCEL) = mrOk then
begin
with SQLQuery1 do
begin
SchemaName := DataModule1.Login;
Close;
SQL.Clear;
SQL.Add('delete from lico where id = :id');
ParamByName('id').AsInteger := id;
ExecSQL();
end;
if ActiveForm = Sotrudnik then
if Spisok = Alfavit then
form5.showAlfavit(True, Asceding)
else
form5.ShowMestoRaboti(True, Asceding)
else
form14.ShowPensioneri(True, Asceding);
end;
end;
procedure TForm2.AcDisconnectExecute(Sender: TObject);
begin
// Разрыв соединения с БД
DataModule1.Disconnect;
end;
function TForm2.FindForm(Caption: string): Boolean;
var
i: Integer;
begin
Result := False;
if TabSet1.Tabs.IndexOf(Caption) > -1 then
begin
for i := 0 to Form2.MDIChildCount - 1 do
if MDIChildren[i].Caption = Caption then
MDIChildren[i].Show;
Result := True;
end;
end;
procedure TForm2.AcDolshnostExecute(Sender: TObject);
begin
if not FindForm('Справочник - Должность') then
begin
CommandText := 'DOLSHNOST';
Form6 := TForm6.Create(Form2);
Form6.Caption := 'Справочник - Должность';
TabSet1.Tabs.AddObject(Form6.Caption, TObject(Form6));
TabSet1.TabIndex := TabSet1.Tabs.Count - 1;
end;
end;
procedure TForm2.acDolshnostPrefExecute(Sender: TObject);
begin
if not FindForm('Справочник - Должность преффикс') then
begin
CommandText := 'DOLSHNOST_PREFIX';
Form6 := TForm6.Create(Form2);
Form6.Caption := 'Справочник - Должность преффикс';
TabSet1.Tabs.AddObject(Form6.Caption, TObject(Form6));
TabSet1.TabIndex := TabSet1.Tabs.Count - 1;
end;
end;
procedure TForm2.acDolshnostSufExecute(Sender: TObject);
begin
if not FindForm('Справочник - Должность суффикс') then
begin
CommandText := 'DOLSHOST_SUFIX';
Form6 := TForm6.Create(Form2);
Form6.Caption := 'Справочник - Должность суффикс';
TabSet1.Tabs.AddObject(Form6.Caption, TObject(Form6));
TabSet1.TabIndex := TabSet1.Tabs.Count - 1;
end;
end;
procedure TForm2.AcExitExecute(Sender: TObject);
begin
Close;
end;
procedure TForm2.acFullCollapseExecute(Sender: TObject);
begin
case ActiveForm of
Sotrudnik:
form5.TreeView1.FullCollapse;
Pensioner:
form14.TreeView1.FullCollapse;
end;
end;
procedure TForm2.acFullExpandExecute(Sender: TObject);
begin
case ActiveForm of
Sotrudnik:
form5.TreeView1.FullExpand;
Pensioner:
form14.TreeView1.FullExpand;
end;
end;
procedure TForm2.AcGalleryButtonExecute(Sender: TObject);
begin
//
end;
procedure TForm2.acInvaidnostExecute(Sender: TObject);
begin
if not FindForm('Справочник - Тип инвалидности') then
begin
CommandText := 'TIP_INVALIDNOSTI';
Form6 := TForm6.Create(Form2);
Form6.Caption := 'Справочник - Тип инвалидности';
TabSet1.Tabs.AddObject(Form6.Caption, TObject(Form6));
TabSet1.TabIndex := TabSet1.Tabs.Count - 1;
end;
end;
procedure TForm2.AcKartochkaExecute(Sender: TObject);
begin
case ActiveForm of
Sotrudnik:
if form5.TreeView1.Selected.getFirstChild = nil then
try
Form3 := TForm3.Create(form5);
Form3.ShowModal;
finally
FreeAndNil(Form3);
end;
Pensioner:
if form14.TreeView1.Selected.getFirstChild = nil then
try
Form3 := TForm3.Create(form14);
Form3.ShowModal;
finally
FreeAndNil(Form3);
end;
end;
end;
procedure TForm2.acKemVidanExecute(Sender: TObject);
begin
if not FindForm('Справочник - Кем выдан паспорт') then
begin
CommandText := 'KEM_VIDAN';
Form6 := TForm6.Create(Form2);
Form6.Caption := 'Справочник - Кем выдан паспорт';
TabSet1.Tabs.AddObject(Form6.Caption, TObject(Form6));
TabSet1.TabIndex := TabSet1.Tabs.Count - 1;
end;
end;
procedure TForm2.AcMasterAddExecute(Sender: TObject);
begin
try
Form7 := TForm7.Create(nil);
Form7.ShowModal;
finally
FreeAndNil(Form7);
end;
end;
procedure TForm2.acMestoRabExecute(Sender: TObject);
begin
if form19 = nil then
begin
form19 := TForm19.Create(Application);
TabSet1.Tabs.AddObject(form19.Caption, TObject(form19));
TabSet1.TabIndex := TabSet1.Tabs.Count - 1;
end
else
form19.Show;
end;
procedure TForm2.acMestoRabotiExecute(Sender: TObject);
begin
if form5.Panel3.Visible then
begin
form5.Panel3.Visible := False;
end;
if Spisok <> MestoRaboti then
form5.ShowMestoRaboti(True, Asceding);
end;
procedure TForm2.acNaselPunktiExecute(Sender: TObject);
begin
if form17 = nil then
begin
form17 := TForm17.Create(Application);
TabSet1.Tabs.AddObject(form17.Caption, TObject(form17));
TabSet1.TabIndex := TabSet1.Tabs.Count - 1;
end
else
form17.Show;
end;
procedure TForm2.acOProgrammeExecute(Sender: TObject);
begin
try
Form12 := TForm12.Create(Form2);
Form12.ShowModal;
finally
FreeAndNil(Form12);
end;
end;
procedure TForm2.acPensioneriExecute(Sender: TObject);
begin
if form14 = nil then
begin
form14 := TForm14.Create(Application);
TabSet1.Tabs.AddObject(form14.Caption, TObject(form14));
TabSet1.TabIndex := TabSet1.Tabs.Count - 1;
end
else
form14.Show;
end;
procedure TForm2.AcPolExecute(Sender: TObject);
begin
if not FindForm('Справочник - Пол') then
begin
CommandText := 'POL';
Form6 := TForm6.Create(Form2);
Form6.Caption := 'Справочник - Пол';
TabSet1.Tabs.AddObject(Form6.Caption, TObject(Form6));
TabSet1.TabIndex := TabSet1.Tabs.Count - 1;
end;
end;
procedure TForm2.acPrichinaNaPensiuExecute(Sender: TObject);
begin
if not FindForm('Справочник - На пенсию') then
begin
CommandText := 'PRICHINA_VIXODA_NA_PENSIE';
Form6 := TForm6.Create(Form2);
Form6.Caption := 'Справочник - На пенсию';
TabSet1.Tabs.AddObject(Form6.Caption, TObject(Form6));
TabSet1.TabIndex := TabSet1.Tabs.Count - 1;
end;
end;
procedure TForm2.AcPrintExecute(Sender: TObject);
var
id: Integer;
begin
case ActiveForm of
Sotrudnik:
id := Sotrudniki.id;
Pensioner:
id := Pensioneri.id;
end;
with DataModule2 do
begin
SimpleDataSet_report.Close;
SimpleDataSet_report.DataSet.Close;
SimpleDataSet_report.Connection := DataModule1.SQLConnection1;
SimpleDataSet_report.DataSet.SchemaName := DataModule1.Login;
SimpleDataSet_report.DataSet.CommandText := 'select * from VW_REPORT where id = :id';
SimpleDataSet_report.DataSet.ParamByName('id').AsInteger := id;
SimpleDataSet_report.DataSet.Open;
SimpleDataSet_report.Open;
SimpleDataSet_report_2.Close;
SimpleDataSet_report_2.DataSet.Close;
SimpleDataSet_report_2.Connection := DataModule1.SQLConnection1;
SimpleDataSet_report_2.DataSet.SchemaName := DataModule1.Login;
SimpleDataSet_report_2.DataSet.CommandText :=
'select * from VW_KONTAKTI_SOTR where ID_LICO = :id';
SimpleDataSet_report_2.DataSet.ParamByName('id').AsInteger := id;
SimpleDataSet_report_2.DataSet.Open;
SimpleDataSet_report_2.Open;
SimpleDataSet_report_3.Close;
SimpleDataSet_report_3.DataSet.Close;
SimpleDataSet_report_3.Connection := DataModule1.SQLConnection1;
SimpleDataSet_report_3.DataSet.SchemaName := DataModule1.Login;
SimpleDataSet_report_3.DataSet.CommandText :=
'select ID_LICO, UCH_ZAVED, SPECIAL, DATA_POSTUPLENIA, DATA_OKONCHANIA, NOMER_DIPLOMA from VW_OBRAZOVANIE where id_lico = :id';
SimpleDataSet_report_3.DataSet.ParamByName('id').AsInteger := id;
SimpleDataSet_report_3.DataSet.Open;
SimpleDataSet_report_3.Open;
SimpleDataSet_report_4.Close;
SimpleDataSet_report_4.DataSet.Close;
SimpleDataSet_report_4.Connection := DataModule1.SQLConnection1;
SimpleDataSet_report_4.DataSet.SchemaName := DataModule1.Login;
SimpleDataSet_report_4.DataSet.CommandText :=
'select NAS_PUNKT, TIP_MESTA_SH, ULICA, KVARTIRA, KORPUS, DOM from VW_MESTO_SHITELSTVA where ID_LICO = :id and DATE_VIPISKI is null';
SimpleDataSet_report_4.DataSet.ParamByName('id').AsInteger := id;
SimpleDataSet_report_4.DataSet.Open;
SimpleDataSet_report_4.Open;
RvProject1.Close;
if FileExists(ExtractFileDir(Application.ExeName) + 'ReportKartochka.rav') then
begin
RvProject1.ProjectFile := ExtractFileDir(Application.ExeName) + 'ReportKartochka.rav';
RvProject1.Execute;
end
else
MessageBox(handle, pWideChar('Файл отчета не найден!'), 'Файл не найден',
MB_ICONWARNING + MB_OK);
end;
end;
procedure TForm2.acRefreshExecute(Sender: TObject);
begin
if Spisok = MestoRaboti then
form5.ShowMestoRaboti(True, Asceding)
else
form5.showAlfavit(True, Asceding);
end;
procedure TForm2.acReportExecute(Sender: TObject);
begin
//
end;
procedure TForm2.acSearchExecute(Sender: TObject);
begin
case ActiveForm of
Sotrudnik:
if not form5.Panel3.Visible then
begin
form5.Edit1.Clear;
form5.ComboBox1.ItemIndex := 0;
form5.Panel3.Visible := True;
form5.Edit1.SetFocus;
end;
Pensioner:
if not form14.Panel3.Visible then
begin
form14.Edit1.Clear;
form14.ComboBox1.ItemIndex := 0;
form14.Panel3.Visible := True;
form14.Edit1.SetFocus;
end;
end;
end;
procedure TForm2.AcSettingExecute(Sender: TObject);
begin
Form4.ShowModal;
end;
procedure TForm2.acSortAscExecute(Sender: TObject);
begin
case ActiveForm of
Sotrudnik:
if Spisok = Alfavit then
form5.showAlfavit(True, Asceding)
else
form5.ShowMestoRaboti(True, Asceding);
Pensioner:
form14.ShowPensioneri(True, Asceding);
end;
end;
procedure TForm2.acSortDescExecute(Sender: TObject);
begin
case ActiveForm of
Sotrudnik:
if Spisok = Alfavit then
form5.showAlfavit(True, Desceding)
else
form5.ShowMestoRaboti(True, Desceding);
Pensioner:
form14.ShowPensioneri(True, Desceding);
end;
end;
procedure TForm2.AcSotrudnikiExecute(Sender: TObject);
begin
if form5 = nil then
begin
form5 := TForm5.Create(Application);
TabSet1.Tabs.AddObject(form5.Caption, TObject(form5));
TabSet1.TabIndex := TabSet1.Tabs.Count - 1;
end
else
form5.Show;
end;
procedure TForm2.acSpecialnostExecute(Sender: TObject);
begin
if not FindForm('Справочник - Специальность') then
begin
CommandText := 'SPECIALNOST';
Form6 := TForm6.Create(Form2);
Form6.Caption := 'Справочник - Специальность';
TabSet1.Tabs.AddObject(Form6.Caption, TObject(Form6));
TabSet1.TabIndex := TabSet1.Tabs.Count - 1;
end;
end;
procedure TForm2.Action1Execute(Sender: TObject);
begin
ShowMessage(IntToStr(form5.TreeView1.Items.Item[0].Level));
end;
procedure TForm2.acTipKontaktDanixExecute(Sender: TObject);
begin
if not FindForm('Справочник - Тип контактных данных') then
begin
CommandText := 'TIP_KONTAKT_DANNIX';
Form6 := TForm6.Create(Form2);
Form6.Caption := 'Справочник - Тип контактных данных';
TabSet1.Tabs.AddObject(Form6.Caption, TObject(Form6));
TabSet1.TabIndex := TabSet1.Tabs.Count - 1;
end;
end;
procedure TForm2.acTipMestaShitelstvaExecute(Sender: TObject);
begin
if not FindForm('Справочник - Тип места жительства') then
begin
CommandText := 'TIP_MESTA_SHITELSTVA';
Form6 := TForm6.Create(Form2);
Form6.Caption := 'Справочник - Тип места жительства';
TabSet1.Tabs.AddObject(Form6.Caption, TObject(Form6));
TabSet1.TabIndex := TabSet1.Tabs.Count - 1;
end;
end;
procedure TForm2.acTipNasPunktaExecute(Sender: TObject);
begin
if not FindForm('Справочник - Тип населенного пункта') then
begin
CommandText := 'TIP_NAS_PUNKTA';
Form6 := TForm6.Create(Form2);
Form6.Caption := 'Справочник - Тип населенного пункта';
TabSet1.Tabs.AddObject(Form6.Caption, TObject(Form6));
TabSet1.TabIndex := TabSet1.Tabs.Count - 1;
end;
end;
procedure TForm2.acTipPasportaExecute(Sender: TObject);
begin
if not FindForm('Справочник - Тип паспорта') then
begin
CommandText := 'TIP_PASPORTA';
Form6 := TForm6.Create(Form2);
Form6.Caption := 'Справочник - Тип паспорта';
TabSet1.Tabs.AddObject(Form6.Caption, TObject(Form6));
TabSet1.TabIndex := TabSet1.Tabs.Count - 1;
end;
end;
procedure TForm2.acTipUcZavedExecute(Sender: TObject);
begin
if not FindForm('Справочник - Тип учебного заведения') then
begin
CommandText := 'TIP_UCH_ZAVEDENIA';
Form6 := TForm6.Create(Form2);
Form6.Caption := 'Справочник - Тип учебного заведения';
TabSet1.Tabs.AddObject(Form6.Caption, TObject(Form6));
TabSet1.TabIndex := TabSet1.Tabs.Count - 1;
end;
end;
procedure TForm2.acUchZavedExecute(Sender: TObject);
begin
if not FindForm('Справочник - Учебное заведение') then
begin
CommandText := 'UCHEBNOE_ZAVEDENIE';
Form6 := TForm6.Create(Form2);
Form6.Caption := 'Справочник - Учебное заведение';
TabSet1.Tabs.AddObject(Form6.Caption, TObject(Form6));
TabSet1.TabIndex := TabSet1.Tabs.Count - 1;
end;
end;
procedure TForm2.acUlocaExecute(Sender: TObject);
begin
if not FindForm('Справочник - Улицы') then
begin
CommandText := 'ULICA';
Form6 := TForm6.Create(Form2);
Form6.Caption := 'Справочник - Улицы';
TabSet1.Tabs.AddObject(Form6.Caption, TObject(Form6));
TabSet1.TabIndex := TabSet1.Tabs.Count - 1;
end;
end;
procedure TForm2.acVozrastnoiExecute(Sender: TObject);
begin
if not FileExists(ExtractFileDir(Application.ExeName) + 'ReportStatistika.rav') then
begin
MessageBox(handle, 'Файл отчета не найден!', 'Ошибка', MB_ICONWARNING + MB_OK);
Exit;
end;
with DataModule2 do
begin
SimpleDataSet_report.Close;
SimpleDataSet_report.DataSet.Close;
SimpleDataSet_report.Connection := DataModule1.SQLConnection1;
SimpleDataSet_report.DataSet.SchemaName := DataModule1.Login;
SimpleDataSet_report.DataSet.CommandText := 'select * from VW_STASTIKA';
SimpleDataSet_report.DataSet.Open;
SimpleDataSet_report.Open;
RvProject1.Close;
RvProject1.ProjectFile := ExtractFileDir(Application.ExeName) + 'ReportStatistika.rav';
RvProject1.Execute;
end;
end;
procedure TForm2.acVsePensioneriExecute(Sender: TObject);
begin
if not FileExists(ExtractFileDir(Application.ExeName) + 'ReportPensioneri.rav') then
begin
MessageBox(handle, 'Файл отчета не найден!', 'Ошибка', MB_ICONWARNING + MB_OK);
Exit;
end;
with DataModule2 do
begin
SimpleDataSet_report.Close;
SimpleDataSet_report.DataSet.Close;
SimpleDataSet_report.Connection := DataModule1.SQLConnection1;
SimpleDataSet_report.DataSet.SchemaName := DataModule1.Login;
SimpleDataSet_report.DataSet.CommandText := 'select ROWNUM, A.* from (' +
'Select FAMILIA, IMIA, OTCHESTVO from VW_PENSIONERI order by FAMILIA) A';
SimpleDataSet_report.DataSet.Open;
SimpleDataSet_report.Open;
RvProject1.Close;
RvProject1.ProjectFile := ExtractFileDir(Application.ExeName) + 'ReportPensioneri.rav';
RvProject1.Execute;
end;
end;
procedure TForm2.acVseSotrudnikiExecute(Sender: TObject);
begin
if not FileExists(ExtractFileDir(Application.ExeName) + 'ReportSotrudniki.rav') then
begin
MessageBox(handle, 'Файл отчета не найден!', 'Ошибка', MB_ICONWARNING + MB_OK);
Exit;
end;
with DataModule2 do
begin
SimpleDataSet_report.Close;
SimpleDataSet_report.DataSet.Close;
SimpleDataSet_report.Connection := DataModule1.SQLConnection1;
SimpleDataSet_report.DataSet.SchemaName := DataModule1.Login;
SimpleDataSet_report.DataSet.CommandText := 'select ROWNUM, A.* from (' +
'Select FAMILIA, IMIA, OTCHESTVO from VW_SOTRUDNIKI order by FAMILIA) A';
SimpleDataSet_report.DataSet.Open;
SimpleDataSet_report.Open;
RvProject1.Close;
RvProject1.ProjectFile := ExtractFileDir(Application.ExeName) + 'ReportSotrudniki.rav';
RvProject1.Execute;
end;
end;
procedure TForm2.acVseSotrudnikiParamExecute(Sender: TObject);
begin
try
Form18 := TForm18.Create(Form2);
Form18.ShowModal;
finally
FreeAndNil(Form18);
end;
end;
procedure TForm2.AcVsiaRabotaExecute(Sender: TObject);
begin
with DataModule2 do
begin
SimpleDataSet_report.Close;
SimpleDataSet_report.DataSet.Close;
SimpleDataSet_report.Connection := DataModule1.SQLConnection1;
SimpleDataSet_report.DataSet.SchemaName := DataModule1.Login;
SimpleDataSet_report.DataSet.CommandText :=
'select DATA_PRIEMA, DATA_OKONCHANIA, PREF, DOLSHNOST, SUF, MESTO_RAB ' +
' from VW_FULL_RABOTA' + ' where ID_SOTR = :id and DATA_OKONCHANIA is not null' +
' order by DATA_PRIEMA';
SimpleDataSet_report.DataSet.ParamByName('id').AsInteger := Sotrudniki.id;
SimpleDataSet_report.DataSet.Open;
SimpleDataSet_report.Open;
SimpleDataSet_report_2.Close;
SimpleDataSet_report_2.DataSet.Close;
SimpleDataSet_report_2.Connection := DataModule1.SQLConnection1;
SimpleDataSet_report_2.DataSet.SchemaName := DataModule1.Login;
SimpleDataSet_report_2.DataSet.CommandText := 'select * from VW_REPORT where id = :id';
SimpleDataSet_report_2.DataSet.ParamByName('id').AsInteger := Sotrudniki.id;
SimpleDataSet_report_2.DataSet.Open;
SimpleDataSet_report_2.Open;
RvProject1.Close;
if FileExists(ExtractFileDir(Application.ExeName) + 'ReportSpisok.rav') then
begin
RvProject1.ProjectFile := ExtractFileDir(Application.ExeName) + 'ReportSpisok.rav';
RvProject1.Execute;
end;
end;
end;
procedure TForm2.acZvanieExecute(Sender: TObject);
begin
if not FindForm('Справочник - Звания') then
begin
CommandText := 'ZVANIE';
Form6 := TForm6.Create(Form2);
Form6.Caption := 'Справочник - Звания';
TabSet1.Tabs.AddObject(Form6.Caption, TObject(Form6));
TabSet1.TabIndex := TabSet1.Tabs.Count - 1;
end;
end;
procedure TForm2.blaExecute(Sender: TObject);
begin
//
end;
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
// Сохранение размера и положения окна при закрытии
ini := TIniFile.Create(ExtractFileDir(Application.ExeName) + 'Options.ini');
try
if WindowState = wsNormal then
begin
ini.WriteInteger('Form', 'Top', Top);
ini.WriteInteger('Form', 'Left', Left);
ini.WriteInteger('Form', 'Height', Height);
ini.WriteInteger('Form', 'Width', Width);
end;
ini.WriteBool('Form', 'WindowState', WindowState = wsMaximized);
finally
ini.Free;
end;
end;
procedure TForm2.FormCreate(Sender: TObject);
// var
// Item: TRibbonTabItem;
// Group: TCustomRibbonGroup;
begin
// Настройки положения окна
ini := TIniFile.Create(ExtractFileDir(Application.ExeName) + 'Options.ini');
try
Top := ini.ReadInteger('Form', 'Top', 200);
Left := ini.ReadInteger('Form', 'Left', 200);
Height := ini.ReadInteger('Form', 'Height', 370);
Width := ini.ReadInteger('Form', 'Width', 620);
if ini.ReadBool('Form', 'WindowState', False) then
WindowState := wsMaximized
else
WindowState := wsNormal;
finally
ini.Free;
end;
// настройка ribbon панели
RibbonPage2.Groups[1].Visible := False;
RibbonPage2.Groups[2].Visible := False;
RibbonPage2.Groups[3].Visible := False;
// Item := Ribbon1.Tabs.Add;
// Item.Caption := 'Сотрудники';
end;
procedure TForm2.FormShow(Sender: TObject);
begin
// Настройки аутентификации
ini := TIniFile.Create(ExtractFileDir(Application.ExeName) + 'Options.ini');
try
if ini.ReadBool('Conn DB', 'SaveAuth', False) then
Form4.RadioButton2.Checked := True
else
Form4.RadioButton1.Checked := True;
finally
ini.Free;
end;
if Form4.RadioButton2.Checked then
begin
ini := TIniFile.Create(ExtractFileDir(Application.ExeName) + 'Auth.ini');
try
Form4.LabeledEdit3.Text := ini.ReadString('Auth', 'DB', 'Opa');
Form4.LabeledEdit1.Text := ini.ReadString('Auth', 'user', 'Opa');
Form4.LabeledEdit2.Text := ini.ReadString('Auth', 'pas', 'Opa');
finally
ini.Free;
end;
end;
end;
procedure TForm2.N1Click(Sender: TObject);
begin
TForm(TabSet1.Tabs.Objects[TabSet1.TabIndex]).WindowState := wsMinimized;
end;
procedure TForm2.N2Click(Sender: TObject);
begin
TForm(TabSet1.Tabs.Objects[TabSet1.TabIndex]).WindowState := wsMaximized;
end;
procedure TForm2.N3Click(Sender: TObject);
begin
TForm(TabSet1.Tabs.Objects[TabSet1.TabIndex]).WindowState := wsNormal;
end;
procedure TForm2.N5Click(Sender: TObject);
begin
TForm(TabSet1.Tabs.Objects[TabSet1.TabIndex]).Close;
end;
procedure TForm2.PMTabSetPopup(Sender: TObject);
procedure EnabledPopupMenu(Enabled: Boolean);
begin
N1.Enabled := Enabled;
N2.Enabled := Enabled;
N3.Enabled := Enabled;
N5.Enabled := Enabled;
end;
begin
if TabSet1.Tabs.Count = 0 then
EnabledPopupMenu(False)
else
EnabledPopupMenu(True);
end;
procedure TForm2.ScreenTipsManager1ShowScreenTip(Manager: TObject; Action: TBasicAction;
var ShowScreenTip: Boolean);
begin
// ряд 1 из 3
if (Action = WindowCascade1) or (Action = WindowTileHorizontal1) or
(Action = WindowTileVertical1) then
ScreenTipsManager1.DisplayOffset.Y := 69
// ряд 2 из 3
else if Action = WindowMinimizeAll1 then
ScreenTipsManager1.DisplayOffset.Y := 47
// ряд 1 из 2
else if (Action = AcMasterAdd) or (Action = acFullExpand) or (Action = acFullCollapse) or
(Action = DataSetFirst1) or (Action = DataSetPrior1) or (Action = DataSetNext1) or
(Action = DataSetLast1) or (Action = DataSetRefresh1) then
ScreenTipsManager1.DisplayOffset.Y := 61
// ряд 2 из 2
else if (Action = acSortAsc) or (Action = acSortDesc) or (Action = acReport) then
ScreenTipsManager1.DisplayOffset.Y := 30
ScreenTipsManager1.DisplayOffset.Y := 25;
end;
procedure TForm2.TabSet1Change(Sender: TObject; NewTab: Integer; var AllowChange: Boolean);
var
i: Integer;
begin
if (TForm(TabSet1.Tabs.Objects[NewTab]) is TForm6) then
begin
for i := 0 to MDIChildCount - 1 do
if MDIChildren[i].Caption = TabSet1.Tabs[NewTab] then
MDIChildren[i].Show;
end
else
TForm(TabSet1.Tabs.Objects[NewTab]).Show;
end;
procedure TForm2.WindowArrange1Execute(Sender: TObject);
begin
if MessageBox(handle, pWideChar('Вы действительно хотете закрыть все окна приложения?'),
'Закрыть все', MB_ICONQUESTION + MB_YESNO) = mrYes then
while Form2.MDIChildCount > 0 do
Form2.MDIChildren[Form2.MDIChildCount - 1].Close;
end;
Приложение В. Модуль приложения Sotrudniki.pas
unit Sotrudniki;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ToolWin, ComCtrls, ExtCtrls, StdCtrls, FMTBcd, DB, SqlExpr, DBClient,
SimpleDS, ImgList, Menus, Ribbon, ActnList, ActnMan, Buttons;
type
TForm5 = class(TForm)
Panel1: TPanel;
Splitter1: TSplitter;
Panel2: TPanel;
TreeView1: TTreeView;
ImageList_16: TImageList;
ScrollBox1: TScrollBox;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
StaticText1: TStaticText;
StaticText2: TStaticText;
StaticText3: TStaticText;
SQLQuery2: TSQLQuery;
Label5: TLabel;
Label6: TLabel;
Label7: TLabel;
StaticText4: TStaticText;
StaticText5: TStaticText;
StaticText6: TStaticText;
Image1: TImage;
Label8: TLabel;
Label9: TLabel;
Label10: TLabel;
Label11: TLabel;
Label12: TLabel;
StaticText7: TStaticText;
StaticText8: TStaticText;
StaticText9: TStaticText;
StaticText10: TStaticText;
Label13: TLabel;
Label14: TLabel;
Label15: TLabel;
Label16: TLabel;
StaticText11: TStaticText;
StaticText12: TStaticText;
StaticText13: TStaticText;
Panel3: TPanel;
Edit1: TEdit;
SimpleDataSet1: TSimpleDataSet;
ComboBox1: TComboBox;
PopupMenu1: TPopupMenu;
N1: TMenuItem;
N2: TMenuItem;
N3: TMenuItem;
N6: TMenuItem;
SimpleDataSet2: TSimpleDataSet;
N4: TMenuItem;
SpeedButton1: TSpeedButton;
ToolBar1: TToolBar;
Bevel1: TBevel;
procedure FormActivate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure ClearTree;
procedure TreeView1Change(Sender: TObject; Node: TTreeNode);
procedure FormCreate(Sender: TObject);
procedure Edit1Change(Sender: TObject);
procedure Edit1KeyPress(Sender: TObject; var Key: Char);
procedure ComboBox1Change(Sender: TObject);
procedure N1Click(Sender: TObject);
procedure N2Click(Sender: TObject);
procedure PopupMenu1Popup(Sender: TObject);
procedure N4Click(Sender: TObject);
procedure TreeView1DblClick(Sender: TObject);
procedure SpeedButton1Click(Sender: TObject);
procedure N6Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure showAlfavit(Active: boolean; Sort: string);
procedure ShowMestoRaboti(Active: boolean; Sort: string);
end;
var
Form5: TForm5;
mas_StaticText: array [1 .. 4] of TStaticText;
id: integer;
implementation
Uses Main, DataModule, Lico, Pensioneri;
{$R *.dfm}
// Отображение дерева сотрудников по алфавиту
procedure TForm5.showAlfavit(Active: boolean; Sort: string);
// Поиск родителя
function FindNode(c: Char): TTreeNode;
var
i: integer;
begin
Result := nil;
for i := 0 to TreeView1.Items.Count - 1 do
if TreeView1.Items.Item[i].Text = c then
begin
Result := TreeView1.Items.Item[i];
break;
end;
end;
var
obj: ^integer;
ferst: Char;
Node: TTreeNode;
begin
// если Active = True, перечитываю данные с БД,
// если False работаю с тем же набором данных
if Active then
begin
with SimpleDataSet1 do
begin
Close;
DataSet.Close;
DataSet.SchemaName := DataModule1.Login;
DataSet.CommandText := 'select ID, FAMILIA, IMIA, OTCHESTVO from VW_SOTRUDNIKI';
DataSet.SortFieldNames := 'FAMILIA ' + Sort;
DataSet.Open;
Open;
end;
end;
ClearTree;
with TreeView1.Items do
begin
BeginUpdate;
with SimpleDataSet1 do
begin
First;
while not Eof do
begin
New(obj);
ferst := FieldByName('FAMILIA').AsString[1];
obj^ := FieldByName('ID').AsInteger;
Node := FindNode(ferst);
if Node = nil then
begin
TreeView1.Items.Add(nil, ferst);
Node := FindNode(ferst);
end;
TreeView1.Items.AddChildObject(Node, FieldByName('FAMILIA').AsString + ' ' +
FieldByName('IMIA').AsString + FieldByName('OTCHESTVO').AsString, obj);
Next;
end;
EndUpdate;
end;
end;
form2.Spisok := Alfavit;
end;
// Отображение дерева сотрудников по месту работы
procedure TForm5.ShowMestoRaboti(Active: boolean; Sort: string);
// Поиск родителя
function FindNode(c: integer): TTreeNode;
var
i: integer;
begin
Result := nil;
for i := 0 to TreeView1.Items.Count - 1 do
if integer(TreeView1.Items.Item[i].Data^) = c then
begin
Result := TreeView1.Items.Item[i];
break;
end;
end;
var
obj: ^integer;
Node: TTreeNode;
begin
// если Active = True, перечитываю данные с БД,
// если False работаю с тем же набором данных
if Active then
begin
with SimpleDataSet2 do
begin
Close;
DataSet.Close;
DataSet.SchemaName := DataModule1.Login;
DataSet.CommandText := 'Select * from MESTO_RABOTI ' + 'where id_podrazdelenie is not null';
DataSet.Open;
Open;
end;
with SimpleDataSet1 do
begin
Close;
DataSet.Close;
DataSet.CommandText :=
'select lico.id, FAMILIA, IMIA, OTCHESTVO, id_mesto_rab, MESTO_RABOTI.nazvanie ' +
'from lico, rabota, MESTO_RABOTI ' + 'where lico.id = rabota.id_sotr ' +
'and rabota.id_mesto_rab = mesto_raboti.id and rabota.data_okonchania is null';
DataSet.SortFieldNames := 'FAMILIA ' + Sort;
DataSet.Open;
Open;
end;
end;
ClearTree;
with TreeView1.Items do
begin
BeginUpdate;
with SimpleDataSet2 do
begin
First;
while not Eof do
begin
New(obj);
obj^ := FieldByName('ID').AsInteger;
Node := FindNode(FieldByName('ID_PODRAZDELENIE').AsInteger);
AddChildObject(Node, FieldByName('NAZVANIE').AsString, obj);
Next;
end;
end;
with SimpleDataSet1 do
begin
First;
while not Eof do
begin
New(obj);
obj^ := FieldByName('id').AsInteger;
Node := FindNode(FieldByName('id_mesto_rab').AsInteger);
AddChildObject(Node, FieldByName('FAMILIA').AsString + ' ' + FieldByName('IMIA').AsString +
' ' + FieldByName('OTCHESTVO').AsString, obj);
Next;
end;
end;
EndUpdate;
end;
form2.Spisok := MestoRaboti;
end;
procedure TForm5.SpeedButton1Click(Sender: TObject);
begin
Panel3.Visible := False;
SimpleDataSet1.Filtered := False;
if form2.Spisok = Alfavit then
showAlfavit(False, Asceding)
else
ShowMestoRaboti(False, Asceding);
TreeView1.SetFocus;
end;
procedure TForm5.FormActivate(Sender: TObject);
begin
if form2.TabSet1.Tabs.IndexOf(Form5.Caption) <> -1 then
begin
form2.TabSet1.TabIndex := form2.TabSet1.Tabs.IndexOf(Form5.Caption);
// TreeView1Change(TreeView1, TreeView1.Selected);
end;
form2.RibbonPage2.Groups[1].Items[form2.RibbonPage1.Groups[1].Items.Count - 1].Visible := True;
form2.RibbonPage2.Groups[1].Items[form2.RibbonPage1.Groups[1].Items.Count - 2].Visible := True;
// form2.acAlfavit.Enabled := True;
form2.ActiveForm := Sotrudnik;
end;
procedure TForm5.FormClose(Sender: TObject; var Action: TCloseAction);
begin
ClearTree;
form2.TabSet1.Tabs.Delete(form2.TabSet1.Tabs.IndexOf(Form5.Caption));
if form14 = nil then
begin
form2.RibbonPage2.Groups[1].Visible := False;
form2.RibbonPage2.Groups[2].Visible := False;
form2.RibbonPage2.Groups[3].Visible := False;
end;
Free;
Form5 := nil;
end;
procedure TForm5.FormCreate(Sender: TObject);
var
i: integer;
begin
// очишаю все staticText
for i := 0 to ComponentCount - 1 do
if (Components[i] is TStaticText) then
(Components[i] as TStaticText).Caption := '';
mas_StaticText[1] := StaticText7;
mas_StaticText[2] := StaticText8;
mas_StaticText[3] := StaticText9;
mas_StaticText[4] := StaticText10;
// настраиваем sqlquery и simpleDataset
SQLQuery2.SchemaName := DataModule1.Login;
SimpleDataSet1.DataSet.SchemaName := DataModule1.Login;
SimpleDataSet2.DataSet.SchemaName := DataModule1.Login;
// Строим дерево по алфавиту
showAlfavit(True, Asceding);
form2.RibbonPage2.Groups[1].Visible := True;
form2.RibbonPage2.Groups[2].Visible := True;
form2.RibbonPage2.Groups[3].Visible := True;
// form2.RibbonPage2.Groups[1].Items[form2.RibbonPage1.Groups[1].Items.Count - 1].Visible := False;
// form2.RibbonPage2.Groups[1].Items[form2.RibbonPage1.Groups[1].Items.Count - 2].Visible := False;
end;
// свернуть все дерево
procedure TForm5.N1Click(Sender: TObject);
begin
TreeView1.FullCollapse;
end;
// развернуть все дерево
procedure TForm5.N2Click(Sender: TObject);
begin
TreeView1.FullExpand;
end;
// показать личную карточку
procedure TForm5.N4Click(Sender: TObject);
begin
form2.AcKartochkaExecute(form2.AcKartochka);
end;
// удалить сотрудеика
procedure TForm5.N6Click(Sender: TObject);
begin
form2.AcDeleteExecute(form2.AcDelete);
end;
// настройка контекстноо меню при выборе элемента дерева
procedure TForm5.PopupMenu1Popup(Sender: TObject);
procedure EnablePopupMenu(Enabled: boolean);
begin
N4.Enabled := Enabled;
N6.Enabled := Enabled;
end;
begin
if TreeView1.Selected.getFirstChild = nil then
EnablePopupMenu(True)
else
EnablePopupMenu(False);
end;
// очистка дерева
procedure TForm5.ClearTree;
var
i: integer;
begin
for i := 0 to TreeView1.Items.Count - 1 do
if TreeView1.Items.Item[i].Data <> nil then
Dispose(TreeView1.Items.Item[i].Data);
TreeView1.Items.Clear;
end;
// изменение поля поиска по дереву
procedure TForm5.ComboBox1Change(Sender: TObject);
begin
Edit1.Clear;
Edit1.SetFocus;
end;
// поля для ввода фильтра записей в наборе данных
procedure TForm5.Edit1Change(Sender: TObject);
var
str: string;
i: integer;
begin
// если ничего не введено
if Length(Trim(Edit1.Text)) = 0 then
begin
SimpleDataSet1.Filtered := False;
if form2.Spisok = Alfavit then
showAlfavit(False, Asceding)
else
ShowMestoRaboti(False, Asceding);
end
else
begin
// настройка фильтра
case ComboBox1.ItemIndex of
0:
str := 'FAMILIA ';
1:
str := 'IMIA ';
2:
str := 'OTCHESTVO ';
end;
SimpleDataSet1.Filter := str + ' LIKE ' + QuotedStr(Edit1.Text + '%');
SimpleDataSet1.Filtered := True;
// перестроение списка
if form2.Spisok = Alfavit then
showAlfavit(False, Asceding)
else
ShowMestoRaboti(False, Asceding);
i := TreeView1.Items.Count - 1;
if form2.Spisok = MestoRaboti then
if TreeView1.Items.Count > 0 then
while i >= 0 do
begin
if (TreeView1.Items.Item[i].getFirstChild = nil) and
(TreeView1.Items.Item[i].Level < 2) then
TreeView1.Items.Delete(TreeView1.Items.Item[i]);
Dec(i);
end;
// развернуть все дерево
TreeView1.FullExpand;
end;
end;
// запрет ввода цифр, преобразование первого символа в загланую букву
procedure TForm5.Edit1KeyPress(Sender: TObject; var Key: Char);
var
s: string;
begin
if Key = #27 then
begin
SpeedButton1Click(SpeedButton1);
exit;
end;
if Key in ['1' .. '9'] then
Key := #0;
if Edit1.SelStart = 0 then
s := AnsiUpperCase(Key)
else
s := AnsiLowerCase(Key);
Key := s[1];
end;
// отображение информации о выбраном сотрулнике в дереве
procedure TForm5.TreeView1Change(Sender: TObject; Node: TTreeNode);
var
i: integer;
M: TMemoryStream;
begin
if Node.getFirstChild <> nil then
begin
form2.AcKartochka.Enabled := False;
form2.AcDelete.Enabled := False;
form2.AcPrint.Enabled := False;
end
else
begin
form2.AcKartochka.Enabled := True;
form2.AcDelete.Enabled := True;
form2.AcPrint.Enabled := True;
end;
if Node.getFirstChild = nil then
begin
id := integer(Node.Data^);
with SQLQuery2 do
begin
// Общая инфа
Close;
SQL.Clear;
SQL.Add('select * from vw_FULL_SOTRUDNIKI where id = :id');
ParamByName('id').AsInteger := id;
Open;
StaticText1.Caption := FieldByName('familia').AsString;
StaticText2.Caption := FieldByName('imia').AsString;
StaticText3.Caption := FieldByName('Otchestvo').AsString;
StaticText4.Caption := FieldByName('Pol').AsString;
StaticText5.Caption := FieldByName('vozrast').AsString;
StaticText6.Caption := FormatDateTime('DD MMM, YYYY', FieldByName('data_roshdenia')
.Value) + ' г.';
// загрузка картинки, если есть
if (FieldByName('photo') as TBlobField).IsNull = False then
begin
M := TMemoryStream.Create;
(FieldByName('photo') as TBlobField).SaveToStream(M);
M.Position := 0;
Image1.Picture.Bitmap.LoadFromStream(M);
M.Free;
end
else
Image1.Picture := nil;
Close;
// контактные данние
for i := 1 to 4 do
mas_StaticText[i].Caption := '-';
SQL.Clear;
SQL.Add('select * from vw_kontakti_sotr where id_lico = :id');
ParamByName('id').AsInteger := id;
Open;
while not Eof do
begin
if FieldByName('NAZVANIE').AsString = 'Домашний' then
StaticText7.Caption := FieldByName('DANNIE').AsString
else if FieldByName('NAZVANIE').AsString = 'Мобильный' then
StaticText8.Caption := FieldByName('DANNIE').AsString
else if FieldByName('NAZVANIE').AsString = 'Рабочий' then
StaticText9.Caption := FieldByName('DANNIE').AsString
else
StaticText10.Caption := FieldByName('DANNIE').AsString;
Next;
end;
Close;
// Место работы
SQL.Clear;
SQL.Add('Select * from vw_rabota where id_sotr = :id');
ParamByName('id').AsInteger := id;
Open;
StaticText11.Caption := FieldByName('MESTO_RABOTI').AsString;
StaticText12.Caption := FieldByName('DOLSHNOST').AsString;
StaticText13.Caption := FieldByName('DATA_PRIEMA').AsString;
Close;
end;
// вызов личной карточки сотрудника
procedure TForm5.TreeView1DblClick(Sender: TObject);
begin
form2.AcKartochkaExecute(Self);
end.