Интерфейс приложения
Рисунок 2. Главная форма
Рисунок 3. Форма отчёта
Заключение
В результате выполнения курсовой работы было разработано приложение для учёта оргтехники в среде C++ Builder. Было реализовано: чтение и сохранение данных в файлы, добавление новых записей об оборудовании, редактирование и удаление строк, сортировку, поиск элементов, а также визуализацию расположения техники на плане помещения.
Также была реализована функциональность для расчёта амортизации оборудования и проверки гарантийных сроков. Реализованы эффективные алгоритмы обработки данных, включая быструю сортировку и линейный поиск.
Список использованных источников
1. А. В. Шевченко “Программирование и основы алгоритмизации: учеб. метод. пособие. Изд-во СПбГЭТУ «ЛЭТИ», 2011” // URL: https://vec.etu.ru/moodle/pluginfile.php/601203/mod_resource/content/0/Учебное%20пособие.%20Программирование%20и%20основы%20алгоритмизации.pdf (Дaта обращения: 09.09.2025)
2. Руководство по языку программирования Си. // URL: https://metanit.com/c/tutorial/ (Дата обращения: 25.09.2025)
3. Герберт Шилдт “С++ базовый курс” // URL: https://www.bsuir.by/m/12_100229_1_98220.pdf/ (Дата обращения: 30.10.2025)
4. Microsoft - “Справочник по языку C” // URL: https://learn.microsoft.com/ru-ru/cpp/c-language/c-language-reference?view=msvc-170 (дата обращения: 10.11.2025)
5. “C Programming Language Tutorial” // URL: https://www.geeksforgeeks.org/c-programming-language/?ysclid=mb7432j49u687387975 (дата обращения: 20.05.2025)
6. “Язык программирования С++” // URL: http://cppstudio.com/cat/274/ (дата обращения: 28.11.2025)
Приложение
ControlListTech.cpp
#include <vcl.h>
#include <windows.h>
#pragma comment(lib, "user32.lib")
// ПРАВИЛЬНАЯ ФУНКЦИЯ ДЛЯ #pragma startup
void SetRussianLocale()
{
SetConsoleOutputCP(1251);
SetConsoleCP(1251);
}
#pragma startup SetRussianLocale
#include <stdio.h>
#include <string.h>
#include <cctype>
#pragma hdrstop
#include "ControlListTech.h"
#include "class.h"
#include "TanksGame.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TFormControlListTech *FormControlListTech;
//---------------------------------------------------------------------------
__fastcall TFormControlListTech::TFormControlListTech(TComponent* Owner)
: TForm(Owner), deviceCount(0), supplyCount(0), repairCount(0)
{
// Настройка поля поиска
SearchEdit->Visible = false;
SearchEdit->TextHint = "Введите текст для поиска...";
ListView1->OnDblClick = ListView1DblClick;
ListView1->OnMouseDown = ListView1MouseDown;
PageControl1->OnChange = PageControl1Change;
BtnAdd->OnClick = BtnAddClickClick;
ButtonAddSupplier->OnClick = ButtonAddSupplierClick;
if (CheckListBox2) {
CheckListBox2->OnClick = CheckListBox2Click;
}
if (CheckListBox1) {
CheckListBox1->Items->Clear();
CheckListBox1->Items->Add("Сканеры");
CheckListBox1->Items->Add("Принтеры");
CheckListBox1->Items->Add("Компьютеры");
CheckListBox1->Items->Add("Факсы");
CheckListBox1->Items->Add("Мониторы");
// По умолчанию все отмечены
for (int i = 0; i < CheckListBox1->Items->Count; i++) {
CheckListBox1->Checked[i] = true;
}
}
if (CheckListBox1) {
CheckListBox1->OnClick = CheckListBox1ClickReport;
}
UpdateMainListView(); // Обновляем таблицу (будет пустая)
ShowMessage("Программа запущена. Для работы с данными загрузите файл через кнопку 'Загрузить'.");
}
//---------------------------------------------------------------------------
// МЕТОД ДЛЯ ЗАПУСКА ПАСХАЛКИ - ТЕПЕРЬ ЗАПУСКАЕМ РЕАЛЬНУЮ ИГРУ
void TFormControlListTech::LaunchEasterEgg()
{
ShowMessage("🎮 Активирована пасхалка! Запускаем Танчики...");
ShowTanksGame();
}
// МЕТОД ДЛЯ ФИЛЬТРАЦИИ НА char[]
void TFormControlListTech::UpdateMainListViewWithFilter(const char* filterText)
{
ListView1->Items->Clear();
char filterUpper[256];
strcpy(filterUpper, filterText);
// Переводим в верхний регистр для поиска
for(int i = 0; filterUpper[i]; i++) {
filterUpper[i] = toupper(filterUpper[i]);
}
int foundCount = 0;
for(int i = 0; i < deviceCount; i++) {
char modelUpper[100];
char categoryUpper[50];
char additionalInfoUpper[200];
// Копируем и переводим в верхний регистр
strcpy(modelUpper, devices[i].model);
strcpy(categoryUpper, devices[i].category);
strcpy(additionalInfoUpper, devices[i].additionalInfo);
for(int j = 0; modelUpper[j]; j++) modelUpper[j] = toupper(modelUpper[j]);
for(int j = 0; categoryUpper[j]; j++) categoryUpper[j] = toupper(categoryUpper[j]);
for(int j = 0; additionalInfoUpper[j]; j++) additionalInfoUpper[j] = toupper(additionalInfoUpper[j]);
// Проверяем совпадение
bool matches = (strlen(filterText) == 0) ||
(strstr(modelUpper, filterUpper) != NULL) ||
(strstr(categoryUpper, filterUpper) != NULL) ||
(strstr(additionalInfoUpper, filterUpper) != NULL);
if (matches) {
TListItem *item = ListView1->Items->Add();
item->Caption = IntToStr(devices[i].id);
item->SubItems->Add(devices[i].category);
item->SubItems->Add(devices[i].model);
item->SubItems->Add(devices[i].purchaseDate);
item->SubItems->Add(IntToStr(devices[i].warrantyMonths));
item->SubItems->Add(FloatToStrF(devices[i].price, ffFixed, 8, 2));
item->SubItems->Add(devices[i].additionalInfo);
item->SubItems->Add(devices[i].IsWarrantyValid() ? "Действует" : "Истекла");
item->SubItems->Add(FloatToStrF(devices[i].CurrentValue(), ffFixed, 8, 2));
item->SubItems->Add(IntToStr(devices[i].coordX) + "," + IntToStr(devices[i].coordY));
foundCount++;
}
}
// Сообщение если ничего не найдено
if (strlen(filterText) > 0 && foundCount == 0) {
char message[300];
sprintf(message, "По запросу '%s' ничего не найдено.", filterText);
ShowMessage(message);
}
}
// МЕТОД ДЛЯ ВЫПОЛНЕНИЯ ПОИСКА
void TFormControlListTech::PerformSearch(const char* searchText)
{
if(deviceCount == 0) {
return;
}
UpdateMainListViewWithFilter(searchText);
}
void TFormControlListTech::AddDevice()
{
if(deviceCount < 50) {
// Добавляем тестовое устройство
devices[deviceCount].id = deviceCount + 1;
// Используем AnsiString для корректного преобразования
AnsiString category = "Категория";
AnsiString model = "Модель " + IntToStr(deviceCount + 1);
AnsiString purchaseDate = "01.01.1970";
AnsiString additionalInfo = "Тестовое оборудование";
strcpy(devices[deviceCount].category, category.c_str());
strcpy(devices[deviceCount].model, model.c_str());
strcpy(devices[deviceCount].purchaseDate, purchaseDate.c_str());
devices[deviceCount].warrantyMonths = 12;
devices[deviceCount].price = 10000.0f;
strcpy(devices[deviceCount].additionalInfo, additionalInfo.c_str());
devices[deviceCount].SetCoordinates(50 + deviceCount * 20, 50 + deviceCount * 20);
deviceCount++;
SaveToFile(); // Сохраняем
UpdateMainListView(); // Обновляем таблицу
sample_pb->Repaint(); // Обновляем план
ShowMessage("Оборудование добавлено! ID: " + IntToStr(deviceCount));
} else {
ShowMessage("Достигнут лимит оборудования!");
}
}
void TFormControlListTech::EditDevice()
{
if(deviceCount == 0) {
ShowMessage("Нет данных для редактирования. Загрузите файл сначала.");
return;
}
if(ListView1->ItemIndex >= 0 && deviceCount > 0) {
int selectedIndex = ListView1->ItemIndex;
// Просто меняем статус для демонстрации
AnsiString newInfo = "Отредактировано";
strcpy(devices[selectedIndex].additionalInfo, newInfo.c_str());
SaveToFile(); // Сохраняем
UpdateMainListView(); // Обновляем таблицу
ShowMessage("Оборудование отредактировано: " + String(devices[selectedIndex].model));
} else {
ShowMessage("Выберите оборудование для редактирования!");
}
}
void TFormControlListTech::DeleteDevice()
{
if(deviceCount == 0) {
ShowMessage("Нет данных для удаления. Загрузите файл сначала.");
return;
}
if(ListView1->ItemIndex >= 0 && ListView1->ItemIndex < deviceCount) {
int selectedIndex = ListView1->ItemIndex;
int deviceIdToDelete = devices[selectedIndex].id; // Запоминаем ID удаляемого устройства
// Подтверждение удаления
if (MessageDlg("Удалить оборудование: " + String(devices[selectedIndex].model) + "?",
mtConfirmation, TMsgDlgButtons() << mbYes << mbNo, 0) == mrYes) {
String deletedModel = devices[selectedIndex].model;
// === УДАЛЯЕМ ОБОРУДОВАНИЕ ===
for(int i = selectedIndex; i < deviceCount - 1; i++) {
devices[i] = devices[i + 1];
}
deviceCount--;
// === УДАЛЯЕМ СВЯЗАННЫЕ РЕМОНТЫ ===
for(int i = 0; i < repairCount; i++) {
if (repairs[i].deviceId == deviceIdToDelete) {
// Сдвигаем ремонты
for(int j = i; j < repairCount - 1; j++) {
repairs[j] = repairs[j + 1];
}
repairCount--;
i--; // Проверяем текущую позицию снова
}
}
// === ПЕРЕНОМЕРУЕМ ID УСТРОЙСТВ ===
for(int i = 0; i < deviceCount; i++) {
devices[i].id = i + 1;
}
// === ОБНОВЛЯЕМ ID В РЕМОНТАХ ===
for(int i = 0; i < repairCount; i++) {
if (repairs[i].deviceId > deviceIdToDelete) {
repairs[i].deviceId--;
}
}
SaveToFile();
UpdateMainListView();
UpdateRepairsListView(); // ОБНОВЛЯЕМ ТАБЛИЦУ РЕМОНТОВ
sample_pb->Repaint();
ShowMessage("Оборудование удалено: " + deletedModel +
"\nУдалены связанные записи о ремонтах.");
}
} else {
ShowMessage("Выберите оборудование для удаления!");
}
}
// МЕТОДЫ ДЛЯ РАБОТЫ С ФАЙЛАМИ
void TFormControlListTech::SaveToFile()
{
if(deviceCount == 0 && supplyCount == 0 && repairCount == 0) {
ShowMessage("Нет данных для сохранения.");
return;
}
FILE *file = _wfopen(L"equipment.dat", L"w");
if(file) {
// Сохраняем оборудование
fprintf(file, "%d\n", deviceCount);
for(int i = 0; i < deviceCount; i++) {
devices[i].SaveToFile(file);
}
// Сохраняем поставки
fprintf(file, "%d\n", supplyCount);
for(int i = 0; i < supplyCount; i++) {
supplies[i].SaveToFile(file);
}
// Сохраняем ремонты
fprintf(file, "%d\n", repairCount);
for(int i = 0; i < repairCount; i++) {
repairs[i].SaveToFile(file);
}
// === СОХРАНЯЕМ ПОСТАВЩИКОВ ===
fprintf(file, "%d\n", supplierCount);
for(int i = 0; i < supplierCount; i++) {
fprintf(file, "%s\n", suppliers[i]);
}
fclose(file);
}
}
void TFormControlListTech::LoadFromFile()
{
FILE *file = _wfopen(L"equipment.dat", L"r");
if(file) {
// Загружаем оборудование
fscanf(file, "%d\n", &deviceCount);
for(int i = 0; i < deviceCount; i++) {
devices[i].LoadFromFile(file);
}
// Загружаем поставки
fscanf(file, "%d\n", &supplyCount);
for(int i = 0; i < supplyCount; i++) {
supplies[i].LoadFromFile(file);
}
// Загружаем ремонты
fscanf(file, "%d\n", &repairCount);
for(int i = 0; i < repairCount; i++) {
repairs[i].LoadFromFile(file);
}
// === ЗАГРУЖАЕМ ПОСТАВЩИКОВ ===
// Сначала считываем количество
int savedSupplierCount = 0;
fscanf(file, "%d\n", &savedSupplierCount);
// Загружаем поставщиков (но не больше чем вмещается)
supplierCount = 0;
for(int i = 0; i < savedSupplierCount && i < 50; i++) {
char supplier[100];
fgets(supplier, 100, file);
supplier[strcspn(supplier, "\n")] = 0; // Убираем перевод строки
// Проверяем на дубликаты (на всякий случай)
bool exists = false;
for(int j = 0; j < supplierCount; j++) {
if(strcmp(suppliers[j], supplier) == 0) {
exists = true;
break;
}
}
if(!exists) {
strcpy(suppliers[supplierCount], supplier);
supplierCount++;
}
}
fclose(file);
// Инициализируем фильтры
for (int i = 0; i < supplierCount; i++) {
supplierFilter[i] = true;
}
// Обновляем интерфейс
UpdateMainListView();
UpdateSupplierCheckboxes();
UpdateSuppliesListView();
UpdateRepairsListView();
sample_pb->Repaint();
}
}
void TFormControlListTech::SaveToFileWithDialog()
{
if(deviceCount == 0 && supplyCount == 0 && repairCount == 0) {
ShowMessage("Нет данных для сохранения. Сначала добавьте данные.");
return;
}
TSaveDialog *saveDialog = new TSaveDialog(this);
saveDialog->Filter = "Data files (*.dat)|*.dat|All files (*.*)|*.*";
saveDialog->DefaultExt = "dat";
saveDialog->FileName = "equipment.dat";
if (saveDialog->Execute()) {
AnsiString fileName = saveDialog->FileName;
FILE *file = fopen(fileName.c_str(), "w");
if(file) {
// Сохраняем оборудование
fprintf(file, "%d\n", deviceCount);
for(int i = 0; i < deviceCount; i++) {
devices[i].SaveToFile(file);
}
// Сохраняем поставки
fprintf(file, "%d\n", supplyCount);
for(int i = 0; i < supplyCount; i++) {
supplies[i].SaveToFile(file);
}
// Сохраняем ремонты
fprintf(file, "%d\n", repairCount);
for(int i = 0; i < repairCount; i++) {
repairs[i].SaveToFile(file);
}
fprintf(file, "%d\n", supplierCount);
for(int i = 0; i < supplierCount; i++) {
fprintf(file, "%s\n", suppliers[i]);
}
fclose(file);
ShowMessage("Данные успешно сохранены в файл: " + saveDialog->FileName +
"\nОборудование: " + IntToStr(deviceCount) +
"\nПоставки: " + IntToStr(supplyCount) +
"\nРемонты: " + IntToStr(repairCount) +
"\nПоставщики: " + IntToStr(supplierCount));
} else {
ShowMessage("Ошибка при сохранении файла!");
}
}
delete saveDialog;
}
void TFormControlListTech::LoadFromFileWithDialog()
{
TOpenDialog *openDialog = new TOpenDialog(this);
openDialog->Filter = "Data files (*.dat)|*.dat|All files (*.*)|*.*";
openDialog->DefaultExt = "dat";
openDialog->FileName = "equipment.dat";
if (openDialog->Execute()) {
AnsiString fileName = openDialog->FileName;
FILE *file = fopen(fileName.c_str(), "r");
if(file) {
// Загружаем оборудование
fscanf(file, "%d\n", &deviceCount);
for(int i = 0; i < deviceCount; i++) {
devices[i].LoadFromFile(file);
}
// Загружаем поставки
fscanf(file, "%d\n", &supplyCount);
for(int i = 0; i < supplyCount; i++) {
supplies[i].LoadFromFile(file);
}
// Загружаем ремонты
fscanf(file, "%d\n", &repairCount);
for(int i = 0; i < repairCount; i++) {
repairs[i].LoadFromFile(file);
}
// === ДОБАВЬ ЭТО: ЗАГРУЖАЕМ ПОСТАВЩИКОВ ===
supplierCount = 0;
// Проверяем есть ли ещё данные в файле
if (!feof(file)) {
int savedSupplierCount = 0;
if (fscanf(file, "%d\n", &savedSupplierCount) == 1) {
for(int i = 0; i < savedSupplierCount && i < 50; i++) {
char supplier[100];
if (fgets(supplier, 100, file)) {
supplier[strcspn(supplier, "\n")] = 0;
strcpy(suppliers[supplierCount], supplier);
supplierCount++;
}
}
}
}
// Если в файле не было поставщиков - собираем из данных
if (supplierCount == 0 && supplyCount > 0) {
for (int i = 0; i < supplyCount; i++) {
bool exists = false;
for (int j = 0; j < supplierCount; j++) {
if (strcmp(suppliers[j], supplies[i].supplier) == 0) {
exists = true;
break;
}
}
if (!exists && supplierCount < 50) {
strcpy(suppliers[supplierCount], supplies[i].supplier);
supplierCount++;
}
}
}
fclose(file);
// Инициализируем фильтры
for (int i = 0; i < supplierCount; i++) {
supplierFilter[i] = true;
}
// Обновляем интерфейс
UpdateMainListView();
UpdateSupplierCheckboxes();
UpdateSuppliesListView();
UpdateRepairsListView();
sample_pb->Repaint();
ShowMessage("Данные успешно загружены из файла: " + openDialog->FileName +
"\nОборудование: " + IntToStr(deviceCount) +
"\nПоставки: " + IntToStr(supplyCount) +
"\nРемонты: " + IntToStr(repairCount) +
"\nПоставщики: " + IntToStr(supplierCount));
} else {
ShowMessage("Ошибка при загрузке файла!");
}
}
delete openDialog;
}
void TFormControlListTech::UpdateRepairsListView()
{
if (!ListView2) return;
ListView2->Items->Clear();
for(int i = 0; i < repairCount; i++) {
TListItem *item = ListView2->Items->Add();
item->Caption = IntToStr(repairs[i].deviceId);
item->SubItems->Add(repairs[i].category);
item->SubItems->Add(repairs[i].model);
item->SubItems->Add(repairs[i].repairStartDate);
item->SubItems->Add(repairs[i].condition);
}
}
// ОБРАБОТЧИКИ СОБЫТИЙ
void __fastcall TFormControlListTech::BtnAddClickClick(TObject *Sender)
{
AddDevice();
}
//---------------------------------------------------------------------------
void __fastcall TFormControlListTech::BtnEditClickClick(TObject *Sender)
{
EditDevice();
}
//---------------------------------------------------------------------------
void __fastcall TFormControlListTech::BtnDeleteClickClick(TObject *Sender)
{
DeleteDevice();
}
//---------------------------------------------------------------------------
void __fastcall TFormControlListTech::BtnSearchClickClick(TObject *Sender)
{
SearchSort();
}
//---------------------------------------------------------------------------
void __fastcall TFormControlListTech::BtnSave(TObject *Sender)
{
SaveToFileWithDialog();
}
//---------------------------------------------------------------------------
void __fastcall TFormControlListTech::BtnLoad(TObject *Sender)
{
LoadFromFileWithDialog();
}
//---------------------------------------------------------------------------
void __fastcall TFormControlListTech::PaintPlanTech(TObject *Sender)
{
TCanvas *cs = sample_pb->Canvas;
// Очищаем область
cs->Brush->Color = clWhite;
cs->FillRect(Rect(0, 0, sample_pb->Width, sample_pb->Height));
// Если данных нет, показываем сообщение
if(deviceCount == 0) {
cs->Font->Size = 12;
cs->Font->Color = clGray;
cs->TextOut(50, 50, "Нет данных. Загрузите файл с оборудованием.");
return;
}
// Отрисовываем все устройства из массива
for(int i = 0; i < deviceCount; i++) {
DisplayDeviceOnPlan(devices[i]);
}
}
//---------------------------------------------------------------------------
void __fastcall TFormControlListTech::SearchEditChange(TObject *Sender)
{
AnsiString searchText = SearchEdit->Text;
AnsiString searchUpper = searchText.UpperCase();
if (searchUpper == "B" ||
searchUpper == "BY" ||
searchUpper == "BYD" ||
searchUpper == "BYDA" ||
searchUpper == "BYDAR" ||
searchUpper == "BYDARK" ||
searchUpper == "BYDARKS" ||
searchUpper == "BYDARKSNA" ||
searchUpper == "BYDARKSNAP" ||
searchUpper == "BYDARKSNAPE" ||
searchUpper == "BYDARKSNAPER") {
if (searchUpper == "BYDARKSNAPER") {
SearchEdit->Text = "";
SearchEdit->Visible = false;
LaunchEasterEgg();
UpdateMainListView();
}
return; // Выходим, не выполняя обычный поиск
}
// Обычный поиск только для других запросов
if(!searchText.IsEmpty()) {
PerformSearch(searchText.c_str());
} else {
UpdateMainListView();
}
}
void __fastcall TFormControlListTech::BtnSearchClick(TObject *Sender)
{
// Переключаем видимость поля поиска
SearchEdit->Visible = !SearchEdit->Visible;
if (SearchEdit->Visible) {
// Если показали поле поиска
SearchEdit->Text = "";
SearchEdit->SetFocus(); // Ставим фокус на ввод
SearchEdit->TextHint = "Введите текст для поиска...";
} else {
// Если скрыли поле поиска
SearchEdit->Text = "";
UpdateMainListView(); // Показываем полный список
}
}
//---------------------------------------------------------------------------
void TFormControlListTech::AddSampleData()
{
// Этот метод теперь не используется при запуске
}
// ДОБАВЛЯЕМ ЭТИ МЕТОДЫ В КОНЕЦ ФАЙЛА
void TFormControlListTech::UpdateMainListView()
{
ListView1->Items->Clear();
for(int i = 0; i < deviceCount; i++) {
TListItem *item = ListView1->Items->Add();
item->Caption = IntToStr(devices[i].id);
item->SubItems->Add(devices[i].category);
item->SubItems->Add(devices[i].model);
item->SubItems->Add(devices[i].purchaseDate);
item->SubItems->Add(IntToStr(devices[i].warrantyMonths));
item->SubItems->Add(FloatToStrF(devices[i].price, ffFixed, 8, 2));
item->SubItems->Add(devices[i].additionalInfo);
item->SubItems->Add(devices[i].IsWarrantyValid() ? "Действует" : "Истекла");
item->SubItems->Add(FloatToStrF(devices[i].CurrentValue(), ffFixed, 8, 2));
item->SubItems->Add(IntToStr(devices[i].coordX) + "," + IntToStr(devices[i].coordY));
}
}
void TFormControlListTech::DisplayDeviceOnPlan(OrgTechnic &device)
{
TCanvas *cs = sample_pb->Canvas;
int x = device.coordX;
int y = device.coordY;
// ЦВЕТ НА ОСНОВЕ ХЕША КАТЕГОРИИ
TColor colors[] = {clBlue, clGreen, clRed, clPurple, clTeal, clOlive, clNavy, clMaroon};
// Простой хеш для категории
int hash = 0;
for(int i = 0; device.category[i] != '\0'; i++) {
hash += device.category[i];
}
TColor deviceColor = colors[hash % 8];
// Если гарантия истекла - делаем цвет бледнее
if (!device.IsWarrantyValid()) {
deviceColor = TColor(RGB(
GetRValue(deviceColor) + 100,
GetGValue(deviceColor) + 100,
GetBValue(deviceColor) + 100
));
}
// Рисуем устройство
cs->Pen->Color = clBlack;
cs->Brush->Color = deviceColor;
cs->Rectangle(x, y, x + 120, y + 60);
// Подпись
String info = device.model;
cs->Font->Size = 7;
cs->Font->Color = clWhite;
cs->TextOut(x + 5, y + 5, info);
}
void TFormControlListTech::ManageDevices()
{
if(deviceCount == 0) {
ShowMessage("Нет данных об оборудовании. Загрузите файл сначала.");
return;
}
ShowMessage("Просмотр оборудования. Всего: " + IntToStr(deviceCount));
}
void TFormControlListTech::SearchSort()
{
if(deviceCount == 0) {
ShowMessage("Нет данных для поиска. Загрузите файл сначала.");
return;
}
// Теперь этот метод просто показывает поле ввода
BtnSearchClick(NULL);
}
void TFormControlListTech::HideSearchInput()
{
SearchEdit->Visible = false;
SearchEdit->Text = "";
UpdateMainListView();
}
// ОБРАБОТЧИК ДВОЙНОГО КЛИКА ДЛЯ РЕДАКТИРОВАНИЯ
void __fastcall TFormControlListTech::ListView1DblClick(TObject *Sender)
{
if(ListView1->ItemIndex >= 0 && deviceCount > 0) {
int selectedIndex = ListView1->ItemIndex;
ShowEditDialog(selectedIndex);
}
}
// ОБРАБОТЧИК ПРАВОЙ КНОПКИ МЫШИ ДЛЯ УДАЛЕНИЯ
void __fastcall TFormControlListTech::ListView1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
{
if (Button == mbRight) {
TListItem* item = ListView1->GetItemAt(X, Y);
if (item != NULL) {
ListView1->ItemIndex = item->Index;
DeleteDevice();
}
}
}
void TFormControlListTech::ShowEditDialog(int deviceIndex)
{
int deviceId = devices[deviceIndex].id;
char oldModel[100], oldCategory[50];
strcpy(oldModel, devices[deviceIndex].model);
strcpy(oldCategory, devices[deviceIndex].category);
TForm* editForm = new TForm(this);
editForm->Caption = "Редактирование оборудования";
editForm->Width = 650;
editForm->Height = 550;
editForm->Position = poScreenCenter;
TLabel* lblCategory = new TLabel(editForm);
lblCategory->Parent = editForm;
lblCategory->Left = 20;
lblCategory->Top = 20;
lblCategory->Caption = "Категория:";
TEdit* edtCategory = new TEdit(editForm);
edtCategory->Parent = editForm;
edtCategory->Left = 140;
edtCategory->Top = 20;
edtCategory->Width = 400;
edtCategory->Text = devices[deviceIndex].category;
TLabel* lblModel = new TLabel(editForm);
lblModel->Parent = editForm;
lblModel->Left = 20;
lblModel->Top = 60;
lblModel->Caption = "Модель:";
TEdit* edtModel = new TEdit(editForm);
edtModel->Parent = editForm;
edtModel->Left = 140;
edtModel->Top = 60;
edtModel->Width = 400;
edtModel->Text = devices[deviceIndex].model;
TLabel* lblDate = new TLabel(editForm);
lblDate->Parent = editForm;
lblDate->Left = 20;
lblDate->Top = 100;
lblDate->Caption = "Закупка:";
TEdit* edtDate = new TEdit(editForm);
edtDate->Parent = editForm;
edtDate->Left = 140;
edtDate->Top = 100;
edtDate->Width = 400;
edtDate->Text = devices[deviceIndex].purchaseDate;
TLabel* lblWarranty = new TLabel(editForm);
lblWarranty->Parent = editForm;
lblWarranty->Left = 20;
lblWarranty->Top = 140;
lblWarranty->Caption = "Гарантия:";
TEdit* edtWarranty = new TEdit(editForm);
edtWarranty->Parent = editForm;
edtWarranty->Left = 140;
edtWarranty->Top = 140;
edtWarranty->Width = 400;
edtWarranty->Text = IntToStr(devices[deviceIndex].warrantyMonths);
TLabel* lblPrice = new TLabel(editForm);
lblPrice->Parent = editForm;
lblPrice->Left = 20;
lblPrice->Top = 180;
lblPrice->Caption = "Цена:";
TEdit* edtPrice = new TEdit(editForm);
edtPrice->Parent = editForm;
edtPrice->Left = 140;
edtPrice->Top = 180;
edtPrice->Width = 400;
edtPrice->Text = FloatToStr(devices[deviceIndex].price);
TLabel* lblInfo = new TLabel(editForm);
lblInfo->Parent = editForm;
lblInfo->Left = 20;
lblInfo->Top = 220;
lblInfo->Caption = "Доп. информация:";
TMemo* memInfo = new TMemo(editForm);
memInfo->Parent = editForm;
memInfo->Left = 20;
memInfo->Top = 260;
memInfo->Width = 550;
memInfo->Height = 100;
memInfo->Text = devices[deviceIndex].additionalInfo;
TButton* btnOk = new TButton(editForm);
btnOk->Parent = editForm;
btnOk->Left = 150;
btnOk->Top = 370;
btnOk->Width = 150;
btnOk->Height = 50;
btnOk->Caption = "Сохранить";
btnOk->ModalResult = mrOk;
TButton* btnCancel = new TButton(editForm);
btnCancel->Parent = editForm;
btnCancel->Left = 310;
btnCancel->Top = 370;
btnCancel->Width = 150;
btnCancel->Height = 50;
btnCancel->Caption = "Отмена";
btnCancel->ModalResult = mrCancel;
if (editForm->ShowModal() == mrOk) {
AnsiString category = edtCategory->Text;
AnsiString model = edtModel->Text;
AnsiString date = edtDate->Text;
AnsiString info = memInfo->Text;
strcpy(devices[deviceIndex].category, category.c_str());
strcpy(devices[deviceIndex].model, model.c_str());
strcpy(devices[deviceIndex].purchaseDate, date.c_str());
devices[deviceIndex].warrantyMonths = StrToInt(edtWarranty->Text);
devices[deviceIndex].price = StrToFloat(edtPrice->Text);
strcpy(devices[deviceIndex].additionalInfo, info.c_str());
int updatedRepairs = 0;
for(int i = 0; i < repairCount; i++) {
if (repairs[i].deviceId == deviceId) {
strcpy(repairs[i].category, category.c_str());
strcpy(repairs[i].model, model.c_str());
updatedRepairs++;
}
}
int updatedSupplies = 0;
for(int i = 0; i < supplyCount; i++) {
if (strcmp(supplies[i].model, oldModel) == 0 && strcmp(supplies[i].category, oldCategory) == 0) {
strcpy(supplies[i].category, category.c_str());
strcpy(supplies[i].model, model.c_str());
updatedSupplies++;
}
}
SaveToFile();
UpdateMainListView();
UpdateRepairsListView();
UpdateSuppliesListView();
sample_pb->Repaint();
String message = "Оборудование обновлено: " + String(devices[deviceIndex].model);
if (updatedRepairs > 0) {
message += "\nОбновлено записей о ремонтах: " + IntToStr(updatedRepairs);
}
if (updatedSupplies > 0) {
message += "\nОбновлено записей о поставках: " + IntToStr(updatedSupplies);
}
ShowMessage(message);
}
delete editForm;
}
void TFormControlListTech::UpdateReportTab()
{
if(deviceCount == 0) {
Label3->Caption = " Нет данных для отчета.\nСначала загрузите файл!";
return;
}
// Подготавливаем данные для фильтра
bool categoryFilter[5] = {true, true, true, true, true}; // Все выбраны по умолчанию
char* categories[5] = {"Scanner", "Printer", "Computer", "Fax", "Monitor"};
// Если CheckListBox1 существует - получаем состояние чекбоксов
if (CheckListBox1) {
for (int i = 0; i < CheckListBox1->Items->Count && i < 5; i++) {
categoryFilter[i] = CheckListBox1->Checked[i];
}
}
// Используем конструктор с фильтром
ReportCalculator calculator(devices, deviceCount, categoryFilter, categories, 5);
// Формируем отчет
String reportText;
reportText = "ОТЧЕТ ПО СТОИМОСТИ ОБОРУДОВАНИЯ\n\n";
reportText += "Выбранные категории: ";
reportText += "\n\n";
reportText += "Количество оборудования: " + IntToStr(calculator.GetTotalDevicesCount()) + "\n";
reportText += "• С действующей гарантией: " + IntToStr(calculator.CountDevicesWithWarranty()) + "\n";
reportText += "• Без гарантии: " + IntToStr(calculator.CountDevicesWithoutWarranty()) + "\n\n";
reportText += "ФИНАНСОВЫЕ ПОКАЗАТЕЛИ:\n";
reportText += "• Первоначальная стоимость: " + FloatToStrF(calculator.CalculateTotalOriginalValue(), ffFixed, 12, 2) + " руб.\n";
reportText += "• Текущая стоимость: " + FloatToStrF(calculator.CalculateTotalCurrentValue(), ffFixed, 12, 2) + " руб.\n";
reportText += "• Общая амортизация: " + FloatToStrF(calculator.CalculateTotalDepreciation(), ffFixed, 12, 2) + " руб.\n";
reportText += "• Процент амортизации: " + FloatToStrF(calculator.CalculateDepreciationPercentage(), ffFixed, 5, 1) + "%\n\n";
reportText += "Отчет обновлен: " + FormatDateTime("dd.mm.yyyy hh:nn:ss", Now());
// Выводим на форму
Label3->Caption = reportText;
}
void __fastcall TFormControlListTech::CheckListBox1ClickReport(TObject *Sender)
{
UpdateReportTab(); // Обновляем отчет при изменении чекбоксов
}
// ОБРАБОТЧИК СМЕНЫ ВКЛАДКИ
void __fastcall TFormControlListTech::PageControl1Change(TObject *Sender)
{
// Если переключились на вкладку отчета (TabSheet3)
if (PageControl1->ActivePage == TabSheet3) {
UpdateReportTab(); // Обновляем отчет
}
}
// ========== ВСПОМОГАТЕЛЬНЫЙ МЕТОД ДЛЯ ОБМЕНА ==========
void TFormControlListTech::SwapDevices(int i, int j)
{
if (i == j || i < 0 || j < 0 || i >= deviceCount || j >= deviceCount) {
return;
}
OrgTechnic temp = devices[i];
devices[i] = devices[j];
devices[j] = temp;
}
// ========== РАЗБИЕНИЕ ДЛЯ СОРТИРОВКИ ПО ЦЕНЕ ==========
int TFormControlListTech::PartitionByPrice(int left, int right, bool ascending)
{
float pivot = devices[right].price;
int i = left - 1;
for (int j = left; j <= right - 1; j++) {
if (ascending) {
// По возрастанию
if (devices[j].price <= pivot) {
i++;
SwapDevices(i, j);
}
} else {
// По убыванию
if (devices[j].price >= pivot) {
i++;
SwapDevices(i, j);
}
}
}
SwapDevices(i + 1, right);
return i + 1;
}
void TFormControlListTech::QuickSortByPrice(int left, int right, bool ascending)
{
if (left < right) {
int pi = PartitionByPrice(left, right, ascending);
QuickSortByPrice(left, pi - 1, ascending);
QuickSortByPrice(pi + 1, right, ascending);
}
}
// ========== РАЗБИЕНИЕ ДЛЯ СОРТИРОВКИ ПО ДАТЕ ==========
// Вспомогательная функция для сравнения дат
int CompareDates(const char* date1, const char* date2)
{
// Дата в формате DD.MM.YYYY
int day1, month1, year1;
int day2, month2, year2;
sscanf(date1, "%d.%d.%d", &day1, &month1, &year1);
sscanf(date2, "%d.%d.%d", &day2, &month2, &year2);
if (year1 != year2) return year1 - year2;
if (month1 != month2) return month1 - month2;
return day1 - day2;
}
int TFormControlListTech::PartitionByDate(int left, int right, bool ascending)
{
char* pivot = devices[right].purchaseDate;
int i = left - 1;
for (int j = left; j <= right - 1; j++) {
int compareResult = CompareDates(devices[j].purchaseDate, pivot);
if (ascending) {
// По возрастанию (старые -> новые)
if (compareResult <= 0) {
i++;
SwapDevices(i, j);
}
} else {
// По убыванию (новые -> старые)
if (compareResult >= 0) {
i++;
SwapDevices(i, j);
}
}
}
SwapDevices(i + 1, right);
return i + 1;
}
void TFormControlListTech::QuickSortByDate(int left, int right, bool ascending)
{
if (left < right) {
int pi = PartitionByDate(left, right, ascending);
QuickSortByDate(left, pi - 1, ascending);
QuickSortByDate(pi + 1, right, ascending);
}
}
// ========== МЕТОДЫ ДЛЯ ВЫЗОВА СОРТИРОВКИ ==========
void TFormControlListTech::SortByPrice(bool ascending)
{
if (deviceCount == 0) {
ShowMessage("Нет данных для сортировки. Загрузите файл сначала.");
return;
}
DWORD startTime = GetTickCount();
QuickSortByPrice(0, deviceCount - 1, ascending);
DWORD endTime = GetTickCount();
UpdateMainListView();
String order = ascending ? "по возрастанию" : "по убыванию";
ShowMessage("Сортировка по стоимости " + order + " выполнена!\n" +
"Время: " + IntToStr((int)(endTime - startTime)) + " мс\n" +
"Элементов: " + IntToStr((int)deviceCount));
}
void TFormControlListTech::SortByDate(bool ascending)
{
if (deviceCount == 0) {
ShowMessage("Нет данных для сортировки. Загрузите файл сначала.");
return;
}
DWORD startTime = GetTickCount();
QuickSortByDate(0, deviceCount - 1, ascending);
DWORD endTime = GetTickCount();
UpdateMainListView();
String order = ascending ? "по возрастанию (старые->новые)" : "по убыванию (новые->старые)";
ShowMessage("Сортировка по дате закупки " + order + " выполнена!\n" +
"Время: " + IntToStr((int)(endTime - startTime)) + " мс\n" +
"Элементов: " + IntToStr((int)deviceCount));
}
// ========== ОБРАБОТЧИКИ КНОПОК СОРТИРОВКИ ==========
void __fastcall TFormControlListTech::BtnSortPriceAscClick(TObject *Sender)
{
SortByPrice(true); // По цене по возрастанию
}
void __fastcall TFormControlListTech::BtnSortPriceDescClick(TObject *Sender)
{
SortByPrice(false); // По цене по убыванию
}
void __fastcall TFormControlListTech::BtnSortDateAscClick(TObject *Sender)
{
SortByDate(true); // По дате по возрастанию
}
void __fastcall TFormControlListTech::BtnSortDateDescClick(TObject *Sender)
{
SortByDate(false); // По дате по убыванию
}
void __fastcall TFormControlListTech::BtnSortClick(TObject *Sender)
{
TPopupMenu* sortMenu = new TPopupMenu(this);
// Создаем пункты меню
TMenuItem* item1 = new TMenuItem(sortMenu);
item1->Caption = "По стоимости (возрастание)";
item1->OnClick = BtnSortPriceAscClick;
sortMenu->Items->Add(item1);
TMenuItem* item2 = new TMenuItem(sortMenu);
item2->Caption = "По стоимости (убывание)";
item2->OnClick = BtnSortPriceDescClick;
sortMenu->Items->Add(item2);
TMenuItem* item3 = new TMenuItem(sortMenu);
item3->Caption = "По дате закупки (старые->новые)";
item3->OnClick = BtnSortDateAscClick;
sortMenu->Items->Add(item3);
TMenuItem* item4 = new TMenuItem(sortMenu);
item4->Caption = "По дате закупки (новые->старые)";
item4->OnClick = BtnSortDateDescClick;
sortMenu->Items->Add(item4);
// Показываем меню рядом с кнопкой
TPoint p = ((TButton*)Sender)->ClientToScreen(Point(0, ((TButton*)Sender)->Height));
sortMenu->Popup(p.X, p.Y);
// Меню удалится автоматически после использования
}
//---------------------------------------------------------------------------
// ========== РАБОТА С ПОСТАВЩИКАМИ ==========
// ДОБАВЛЕНИЕ НОВОГО ПОСТАВЩИКА
void TFormControlListTech::AddSupplier()
{
// Используем InputBox для ввода названия поставщика
String supplierName = InputBox("Добавление поставщика",
"Введите название поставщика:",
"");
if (!supplierName.IsEmpty() && supplierCount < 50) {
// Преобразуем в AnsiString и копируем
AnsiString supplierAnsi = supplierName;
strcpy(suppliers[supplierCount], supplierAnsi.c_str());
supplierCount++;
// Обновляем список чекбоксов
UpdateSupplierCheckboxes();
ShowMessage("Поставщик добавлен: " + supplierName);
}
}
// ОБНОВЛЕНИЕ СПИСКА ЧЕКБОКСОВ
void TFormControlListTech::UpdateSupplierCheckboxes()
{
// Очищаем списки
CheckListBox2->Items->Clear();
// Заполняем чекбоксы поставщиками
for (int i = 0; i < supplierCount; i++) {
CheckListBox2->Items->Add(suppliers[i]);
}
// По умолчанию все выбраны
for (int i = 0; i < supplierCount; i++) {
CheckListBox2->Checked[i] = true;
supplierFilter[i] = true;
}
}
// ФИЛЬТРАЦИЯ ПО ВЫБРАННЫМ ПОСТАВЩИКАМ
void TFormControlListTech::FilterBySuppliers()
{
// Обновляем фильтр из CheckListBox1
for (int i = 0; i < supplierCount; i++) {
if (i < CheckListBox1->Items->Count) {
supplierFilter[i] = CheckListBox1->Checked[i];
}
}
// Применяем фильтр
UpdateSuppliesListViewWithFilter();
}
// ОБНОВЛЕНИЕ ТАБЛИЦЫ ПОСТАВОК С ФИЛЬТРОМ
void TFormControlListTech::UpdateSuppliesListViewWithFilter()
{
if (!Post) return;
Post->Items->Clear();
for (int i = 0; i < supplyCount; i++) {
// Проверяем, проходит ли поставка через фильтр
bool showSupply = true;
if (supplierCount > 0) {
// Ищем поставщика в фильтре
int supplierIndex = -1;
for (int j = 0; j < supplierCount; j++) {
if (strcmp(supplies[i].supplier, suppliers[j]) == 0) {
supplierIndex = j;
break;
}
}
// Если поставщик найден и не выбран в фильтре - скрываем
if (supplierIndex != -1 && !supplierFilter[supplierIndex]) {
showSupply = false;
}
}
// Если нужно показать - добавляем в таблицу
if (showSupply) {
TListItem *item = Post->Items->Add();
item->Caption = supplies[i].supplier;
item->SubItems->Add(supplies[i].category);
item->SubItems->Add(supplies[i].model);
item->SubItems->Add(supplies[i].supplyDate);
}
}
}
// ОБНОВЛЕННЫЙ МЕТОД ДЛЯ ТАБЛИЦЫ ПОСТАВОК (без фильтра)
void TFormControlListTech::UpdateSuppliesListView()
{
if (!Post) return;
Post->Items->Clear();
for (int i = 0; i < supplyCount; i++) {
// Проверяем, проходит ли поставка через фильтр
bool showSupply = true;
if (supplierCount > 0 && CheckListBox2) {
// Ищем поставщика в чекбоксах
int supplierIndex = -1;
for (int j = 0; j < CheckListBox2->Items->Count; j++) {
AnsiString cbSupplier = CheckListBox2->Items->Strings[j];
if (strcmp(supplies[i].supplier, cbSupplier.c_str()) == 0) {
supplierIndex = j;
break;
}
}
// Если поставщик найден и не выбран - скрываем
if (supplierIndex != -1 && !CheckListBox2->Checked[supplierIndex]) {
showSupply = false;
}
}
// Если нужно показать - добавляем в таблицу
if (showSupply) {
TListItem *item = Post->Items->Add();
item->Caption = supplies[i].supplier;
item->SubItems->Add(supplies[i].category);
item->SubItems->Add(supplies[i].model);
item->SubItems->Add(supplies[i].supplyDate);
}
}
}
// ОБРАБОТЧИК ИЗМЕНЕНИЯ ЧЕКБОКСОВ
void __fastcall TFormControlListTech::CheckListBox1Click(TObject *Sender)
{
FilterBySuppliers(); // Применяем фильтр при клике
}
void __fastcall TFormControlListTech::ButtonAddSupplierClick(TObject *Sender)
{
AddSupplier();
}
void __fastcall TFormControlListTech::CheckListBox2Click(TObject *Sender)
{
// Обновляем фильтр
UpdateSuppliesListView();
}
ControlListTech.h
#ifndef ControlListTechH
#define ControlListTechH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <System.ImageList.hpp>
#include <Vcl.ImgList.hpp>
#include <Vcl.ComCtrls.hpp>
#include <Vcl.CheckLst.hpp>
#include <Vcl.ExtCtrls.hpp>
//---------------------------------------------------------------------------
#include <class.h>
class TFormControlListTech : public TForm
{
__published:
TImageList *ImageList1;
TButton *Button1;
TButton *Button2;
TPageControl *PageControl1;
TTabSheet *TablePage;
TTabSheet *PlanPage;
TListView *ListView1;
TButton *Button3;
TButton *BtnSort;
TButton *BtnSearch;
TTabSheet *Deliveries;
TTabSheet *TabSheet2;
TTabSheet *TabSheet3;
TPanel *Panel1;
TListView *Post;
TListView *ListView2;
TLabel *Label1;
TLabel *Label2;
TPanel *Panel2;
TLabel *Label3;
TCheckListBox *CheckListBox1;
TButton *BtnGenerateReport;
TCheckListBox *CheckListBox2;
TButton *ButtonAddSupplier;
TPanel *Panel3;
TPaintBox *sample_pb;
TEdit *SearchEdit;
TButton *BtnAdd;
void __fastcall BtnAddClickClick(TObject *Sender);
void __fastcall BtnEditClickClick(TObject *Sender);
void __fastcall BtnDeleteClickClick(TObject *Sender);
void __fastcall BtnSearchClickClick(TObject *Sender);
void __fastcall PaintPlanTech(TObject *Sender);
void __fastcall BtnSave(TObject *Sender);
void __fastcall BtnLoad(TObject *Sender);
void __fastcall BtnSearchClick(TObject *Sender);
void __fastcall SearchEditChange(TObject *Sender);
void __fastcall BtnSortClick(TObject *Sender);
private:
OrgTechnic devices[50]; // Основное оборудование
Supply supplies[50]; // Поставки
Repair repairs[50]; // Ремонты
int deviceCount;
int supplyCount;
int repairCount;
// Для работы с поставщиками
char suppliers[50][100]; // Массив поставщиков
int supplierCount; // Количество поставщиков
bool supplierFilter[50]; // Флаги выбранных поставщиков для фильтрации
void ManageDevices();
void AddDevice();
void EditDevice();
void DeleteDevice();
void SearchSort();
void DisplayDeviceOnPlan(OrgTechnic &device); // Отрисовка на плане
void UpdateMainListView(); // Обновление основной таблицы
void UpdateSuppliesListView(); // Обновление поставок
void AddSupplier();
void __fastcall ButtonAddSupplierClick(TObject *Sender);
void __fastcall ButtonResetFiltersClick(TObject *Sender);
void __fastcall ButtonAddSupplyClick(TObject *Sender);
void __fastcall CheckListBox1Click(TObject *Sender);
void UpdateSupplierCheckboxes();
void FilterBySuppliers();
void UpdateSuppliesListViewWithFilter();
void UpdateRepairsListView(); // Обновление ремонтов
void AddSampleData(); // Заполнение тестовыми данными
void SaveToFileWithDialog();
void LoadFromFileWithDialog();
void SaveToFile();
void LoadFromFile();
void LaunchEasterEgg(); // Запуск пасхалки
void PerformSearch(const char* searchText);
void UpdateMainListViewWithFilter(const char* filterText);
void HideSearchInput();
void __fastcall ListView1DblClick(TObject *Sender);
void __fastcall ListView1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y);
void ShowEditDialog(int deviceIndex);
void CalculateTotalValue(); //стоимость
void UpdateReportTab();
void __fastcall PageControl1Change(TObject *Sender); // Обработчик смены вкладки
// ОБРАБОТЧИКИ СОРТИРОВКИ
void __fastcall BtnSortPriceAscClick(TObject *Sender);
void __fastcall BtnSortPriceDescClick(TObject *Sender);
void __fastcall BtnSortDateAscClick(TObject *Sender);
void __fastcall BtnSortDateDescClick(TObject *Sender);
//void __fastcall BtnSortClick(TObject *Sender); // Для меню
// МЕТОДЫ ДЛЯ БЫСТРОЙ СОРТИРОВКИ
void QuickSortByPrice(int left, int right, bool ascending = true);
void QuickSortByDate(int left, int right, bool ascending = true);
int PartitionByPrice(int left, int right, bool ascending);
int PartitionByDate(int left, int right, bool ascending);
void SwapDevices(int i, int j);
// МЕТОДЫ ДЛЯ ВЫЗОВА СОРТИРОВКИ
void SortByPrice(bool ascending);
void SortByDate(bool ascending);
void __fastcall CheckListBox2Click(TObject *Sender);
void __fastcall CheckListBox1ClickReport(TObject *Sender);
public:
__fastcall TFormControlListTech(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TFormControlListTech *FormControlListTech;
//---------------------------------------------------------------------------
#endif
class.cpp
#include "class.h"
#include <string.h>
#include <cmath>
#include <ctime>
bool OrgTechnic::IsWarrantyValid()
{
return MonthsInUse() <= warrantyMonths;
}
float OrgTechnic::CurrentValue()
{
int monthsUsed = MonthsInUse();
if(monthsUsed <= warrantyMonths) {
return price * (1.0f - (monthsUsed * 0.005f));
} else {
int monthsAfterWarranty = monthsUsed - warrantyMonths;
float depreciation = (warrantyMonths * 0.005f) + (monthsAfterWarranty * 0.02f);
float value = price * (1.0f - depreciation);
return (value > price * 0.1f) ? value : price * 0.1f;
}
}
int OrgTechnic::MonthsInUse()
{
int day, month, year;
sscanf(purchaseDate, "%d.%d.%d", &day, &month, &year);
time_t t = time(NULL);
struct tm *currentTime = localtime(&t);
int currentYear = currentTime->tm_year + 1900;
int currentMonth = currentTime->tm_mon + 1;
return (currentYear - year) * 12 + (currentMonth - month);
}
void OrgTechnic::SetCoordinates(int x, int y)
{
coordX = x;
coordY = y;
}
void OrgTechnic::SaveToFile(FILE *file)
{
fprintf(file, "%d|%s|%s|%s|%d|%f|%s|%d|%d\n",
id, category, model, purchaseDate, warrantyMonths,
price, additionalInfo, coordX, coordY);
}
void OrgTechnic::LoadFromFile(FILE *file)
{
fscanf(file, "%d|%[^|]|%[^|]|%[^|]|%d|%f|%[^|]|%d|%d\n",
&id, category, model, purchaseDate, &warrantyMonths,
&price, additionalInfo, &coordX, &coordY);
}
void Supply::SaveToFile(FILE *file)
{
fprintf(file, "%s|%s|%s|%s\n",
supplier, category, model, supplyDate);
}
void Supply::LoadFromFile(FILE *file)
{
char line[300];
if (fgets(line, sizeof(line), file)) {
char* token = strtok(line, "|\n");
if (token) strcpy(supplier, token);
token = strtok(NULL, "|\n");
if (token) strcpy(category, token);
token = strtok(NULL, "|\n");
if (token) strcpy(model, token);
token = strtok(NULL, "|\n");
if (token) strcpy(supplyDate, token);
}
}
void Repair::SaveToFile(FILE *file)
{
fprintf(file, "%d|%s|%s|%s|%s\n",
deviceId, category, model, repairStartDate, condition);
}
void Repair::LoadFromFile(FILE *file)
{
char line[300];
if (fgets(line, sizeof(line), file)) {
char* token = strtok(line, "|\n");
if (token) deviceId = atoi(token);
token = strtok(NULL, "|\n");
if (token) strcpy(category, token);
token = strtok(NULL, "|\n");
if (token) strcpy(model, token);
token = strtok(NULL, "|\n");
if (token) strcpy(repairStartDate, token);
token = strtok(NULL, "|\n");
if (token) strcpy(condition, token);
}
}
// Конструктор
ReportCalculator::ReportCalculator(OrgTechnic* devArray, int count, bool* filter, char** cats, int catCount)
{
devices = devArray;
deviceCount = count;
categoryFilter = filter;
categories = cats;
categoryCount = catCount;
}
// Проверка проходит ли устройство через фильтр категорий
bool ReportCalculator::DevicePassesFilter(int index)
{
// Если фильтр не установлен - пропускаем все устройства
if (categoryFilter == NULL || categories == NULL || categoryCount == 0) {
return true;
}
// Ищем категорию устройства в фильтре
for (int i = 0; i < categoryCount; i++) {
if (strcmp(devices[index].category, categories[i]) == 0) {
// Нашли категорию - проверяем выбран ли её чекбокс
return categoryFilter[i];
}
}
// Категория не найдена в фильтре - не показываем
return false;
}
// Общая первоначальная стоимость (с фильтром)
float ReportCalculator::CalculateTotalOriginalValue()
{
float total = 0.0f;
for(int i = 0; i < deviceCount; i++) {
if (DevicePassesFilter(i)) {
total += devices[i].price;
}
}
return total;
}
// Общая текущая стоимость (с фильтром)
float ReportCalculator::CalculateTotalCurrentValue()
{
float total = 0.0f;
for(int i = 0; i < deviceCount; i++) {
if (DevicePassesFilter(i)) {
total += devices[i].CurrentValue();
}
}
return total;
}
// Общая амортизация (с фильтром)
float ReportCalculator::CalculateTotalDepreciation()
{
return CalculateTotalOriginalValue() - CalculateTotalCurrentValue();
}
// Процент амортизации (с фильтром)
float ReportCalculator::CalculateDepreciationPercentage()
{
float original = CalculateTotalOriginalValue();
if(original == 0) return 0.0f;
return (CalculateTotalDepreciation() / original) * 100.0f;
}
// Количество устройств с гарантией (с фильтром)
int ReportCalculator::CountDevicesWithWarranty()
{
int count = 0;
for(int i = 0; i < deviceCount; i++) {
if (DevicePassesFilter(i) && devices[i].IsWarrantyValid()) {
count++;
}
}
return count;
}
// Количество устройств без гарантии (с фильтром)
int ReportCalculator::CountDevicesWithoutWarranty()
{
int count = 0;
for(int i = 0; i < deviceCount; i++) {
if (DevicePassesFilter(i) && !devices[i].IsWarrantyValid()) {
count++;
}
}
return count;
}
// Общее количество устройств (с фильтром)
int ReportCalculator::GetTotalDevicesCount()
{
int count = 0;
for(int i = 0; i < deviceCount; i++) {
if (DevicePassesFilter(i)) {
count++;
}
}
return count;
}
class.h
#ifndef ORGTECHCLASS_H
#define ORGTECHCLASS_H
class OrgTechnic
{
public:
int id;
char category[50];
char model[100];
char purchaseDate[20];
int warrantyMonths;
float price;
char additionalInfo[200];
int coordX;
int coordY;
// Методы
bool IsWarrantyValid();
float CurrentValue();
int MonthsInUse();
void SetCoordinates(int x, int y);
// Методы для работы с файлами
void SaveToFile(FILE *file);
void LoadFromFile(FILE *file);
};
class Supply
{
public:
char supplier[100];
char category[50];
char model[100];
char supplyDate[20];
void SaveToFile(FILE *file);
void LoadFromFile(FILE *file);
};
class Repair
{
public:
int deviceId;
char category[50];
char model[100];
char repairStartDate[20];
char condition[100];
void SaveToFile(FILE *file);
void LoadFromFile(FILE *file);
};
class ReportCalculator
{
private:
OrgTechnic* devices;
int deviceCount;
bool* categoryFilter; // Фильтр по категориям
char** categories; // Список категорий
int categoryCount; // Количество категорий
public:
// Конструктор
ReportCalculator(OrgTechnic* devArray, int count);
// Новый конструктор с фильтром
ReportCalculator(OrgTechnic* devArray, int count, bool* filter, char** cats, int catCount);
// Методы для расчетов
float CalculateTotalOriginalValue();
float CalculateTotalCurrentValue();
float CalculateTotalDepreciation();
float CalculateDepreciationPercentage();
int CountDevicesWithWarranty();
int CountDevicesWithoutWarranty();
int GetTotalDevicesCount();
// Метод для проверки проходит ли устройство через фильтр
bool DevicePassesFilter(int index);
};
#endif
