создал систему календарного учебного графика
This commit is contained in:
@@ -20,13 +20,28 @@ INSERT INTO departments (name, code) VALUES
|
||||
CREATE TABLE IF NOT EXISTS specialties (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
specialty_code VARCHAR(255) NOT NULL
|
||||
specialty_code VARCHAR(255) UNIQUE NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO specialties (name, specialty_code) VALUES
|
||||
('Информационная безопасность', '10.03.01'),
|
||||
('Информатика и вычислительная техника', '09.03.01'),
|
||||
('Программная инженерия', '09.03.04');
|
||||
('Программная инженерия', '09.03.04')
|
||||
ON CONFLICT (specialty_code) DO NOTHING;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS specialty_profiles (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
specialty_id BIGINT NOT NULL REFERENCES specialties(id) ON DELETE CASCADE,
|
||||
name VARCHAR(500) NOT NULL,
|
||||
description TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT uq_specialty_profiles_name UNIQUE (specialty_id, name)
|
||||
);
|
||||
|
||||
INSERT INTO specialty_profiles (specialty_id, name)
|
||||
SELECT id, 'Без профиля'
|
||||
FROM specialties
|
||||
ON CONFLICT (specialty_id, name) DO NOTHING;
|
||||
|
||||
-- ==========================================
|
||||
-- Пользователи и роли
|
||||
@@ -70,20 +85,28 @@ ON CONFLICT (name) DO NOTHING;
|
||||
-- ==========================================
|
||||
CREATE TABLE IF NOT EXISTS student_groups (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
name VARCHAR(100) UNIQUE NOT NULL,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
group_size BIGINT NOT NULL,
|
||||
education_form_id BIGINT NOT NULL REFERENCES education_forms(id),
|
||||
department_id BIGINT NOT NULL REFERENCES departments(id),
|
||||
specialty_code INT NOT NULL REFERENCES specialties(id),
|
||||
specialty_id BIGINT NOT NULL REFERENCES specialties(id),
|
||||
specialty_profile_id BIGINT NOT NULL REFERENCES specialty_profiles(id),
|
||||
year_start_study BIGINT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Тестовая базовая группа для работы
|
||||
INSERT INTO student_groups (name, group_size, education_form_id, department_id, specialty_code, year_start_study)
|
||||
VALUES ('ИВТ-21-1', 25, 1, 1, 2, 2025),
|
||||
('ИБ-41м', 15, 2, 1, 1, 2024)
|
||||
ON CONFLICT (name) DO NOTHING;
|
||||
INSERT INTO student_groups (name, group_size, education_form_id, department_id, specialty_id, specialty_profile_id, year_start_study)
|
||||
SELECT data.name, data.group_size, ef.id, dept.id, specialty.id, profile.id, data.year_start_study
|
||||
FROM (VALUES
|
||||
('ИВТ-21-1', 25::BIGINT, 'Бакалавриат', 'Кафедра ИБ', '09.03.01', 2025::BIGINT),
|
||||
('ИБ-41м', 15::BIGINT, 'Магистратура', 'Кафедра ИБ', '10.03.01', 2024::BIGINT)
|
||||
) AS data(name, group_size, education_form_name, department_name, specialty_code, year_start_study)
|
||||
JOIN education_forms ef ON ef.name = data.education_form_name
|
||||
JOIN departments dept ON dept.name = data.department_name
|
||||
JOIN specialties specialty ON specialty.specialty_code = data.specialty_code
|
||||
JOIN specialty_profiles profile ON profile.specialty_id = specialty.id AND profile.name = 'Без профиля'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM student_groups existing WHERE existing.name = data.name);
|
||||
|
||||
-- ==========================================
|
||||
-- Подгруппы (например: "ИВТ-21-1 Подгруппа 1")
|
||||
@@ -272,45 +295,131 @@ ON CONFLICT (academic_year_id, semester_type) DO NOTHING;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_semesters_dates ON semesters(start_date, end_date);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS holidays (
|
||||
CREATE TABLE IF NOT EXISTS calendar_study_forms (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
date DATE NOT NULL,
|
||||
name VARCHAR(100) UNIQUE NOT NULL,
|
||||
description TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
INSERT INTO calendar_study_forms (name, description) VALUES
|
||||
('очная', 'Очная форма обучения')
|
||||
ON CONFLICT (name) DO NOTHING;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS academic_calendar_activity_types (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
code VARCHAR(10) UNIQUE NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
allow_schedule BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
color_code VARCHAR(7) NOT NULL DEFAULT '#64748b',
|
||||
display_order INT NOT NULL DEFAULT 100,
|
||||
description TEXT
|
||||
);
|
||||
|
||||
INSERT INTO academic_calendar_activity_types (code, name, allow_schedule, color_code, display_order, description) VALUES
|
||||
('Т', 'Теоретическое обучение', TRUE, '#10b981', 10, 'Обычные занятия динамического расписания разрешены'),
|
||||
('Э', 'Экзаменационная сессия', FALSE, '#f59e0b', 20, 'Обычные занятия не генерируются'),
|
||||
('К', 'Каникулы', FALSE, '#38bdf8', 30, 'Обычные занятия не генерируются'),
|
||||
('У', 'Учебная практика', FALSE, '#a78bfa', 40, 'Обычные занятия не генерируются'),
|
||||
('П', 'Производственная практика', FALSE, '#fb7185', 50, 'Обычные занятия не генерируются'),
|
||||
('Пд', 'Преддипломная практика', FALSE, '#f97316', 60, 'Обычные занятия не генерируются'),
|
||||
('Н', 'Научно-исследовательская работа', FALSE, '#22c55e', 70, 'Обычные занятия не генерируются'),
|
||||
('Г', 'Подготовка к сдаче и сдача государственного экзамена', FALSE, '#ef4444', 80, 'Обычные занятия не генерируются'),
|
||||
('Д', 'Подготовка к защите и защита выпускной квалификационной работы', FALSE, '#dc2626', 90, 'Обычные занятия не генерируются'),
|
||||
('ПА', 'Повторная промежуточная аттестация', FALSE, '#eab308', 100, 'Обычные занятия не генерируются'),
|
||||
('С', 'Симуляционный курс', FALSE, '#06b6d4', 110, 'Обычные занятия не генерируются'),
|
||||
('*', 'Нерабочий праздничный день', FALSE, '#64748b', 120, 'День исключается из генерации расписания'),
|
||||
('=', 'День вне учебного года', FALSE, '#475569', 130, 'День исключается из генерации расписания')
|
||||
ON CONFLICT (code) DO NOTHING;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS academic_calendars (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
title VARCHAR(255) NOT NULL,
|
||||
academic_year_id BIGINT NOT NULL REFERENCES academic_years(id) ON DELETE CASCADE,
|
||||
description VARCHAR(255),
|
||||
CONSTRAINT uq_holidays_year_date UNIQUE (academic_year_id, date)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_holidays_date ON holidays(date);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS academic_calendar_matrix (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
semester_id BIGINT NOT NULL REFERENCES semesters(id) ON DELETE CASCADE,
|
||||
course_number INT NOT NULL,
|
||||
specialty_id BIGINT NOT NULL REFERENCES specialties(id),
|
||||
week_number INT NOT NULL,
|
||||
activity_type VARCHAR(20) NOT NULL,
|
||||
CONSTRAINT chk_calendar_course_positive CHECK (course_number > 0),
|
||||
CONSTRAINT chk_calendar_week_positive CHECK (week_number > 0),
|
||||
CONSTRAINT chk_calendar_activity_type CHECK (activity_type IN ('THEORY', 'EXAM', 'VACATION', 'PRACTICE')),
|
||||
CONSTRAINT uq_calendar_matrix UNIQUE (semester_id, course_number, specialty_id, week_number)
|
||||
specialty_profile_id BIGINT NOT NULL REFERENCES specialty_profiles(id),
|
||||
study_form_id BIGINT NOT NULL REFERENCES calendar_study_forms(id),
|
||||
course_count INT NOT NULL DEFAULT 4,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_academic_calendars_course_count CHECK (course_count > 0),
|
||||
CONSTRAINT uq_academic_calendar_title UNIQUE (academic_year_id, specialty_profile_id, study_form_id, title)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_calendar_lookup
|
||||
ON academic_calendar_matrix(semester_id, course_number, specialty_id, week_number);
|
||||
CREATE INDEX IF NOT EXISTS idx_academic_calendars_context
|
||||
ON academic_calendars(academic_year_id, specialty_id, specialty_profile_id, study_form_id);
|
||||
|
||||
INSERT INTO academic_calendar_matrix (semester_id, course_number, specialty_id, week_number, activity_type)
|
||||
INSERT INTO academic_calendars (title, academic_year_id, specialty_id, specialty_profile_id, study_form_id, course_count)
|
||||
SELECT
|
||||
s.id,
|
||||
SPLIT_PART(ay.title, '-', 1)::INT - sg.year_start_study + 1 AS course_number,
|
||||
sg.specialty_code AS specialty_id,
|
||||
weeks.week_number,
|
||||
'THEORY'
|
||||
FROM semesters s
|
||||
JOIN academic_years ay ON ay.id = s.academic_year_id
|
||||
CROSS JOIN student_groups sg
|
||||
CROSS JOIN GENERATE_SERIES(1, 22) AS weeks(week_number)
|
||||
WHERE SPLIT_PART(ay.title, '-', 1)::INT - sg.year_start_study + 1 > 0
|
||||
ON CONFLICT (semester_id, course_number, specialty_id, week_number) DO NOTHING;
|
||||
specialty.specialty_code || ' ' || profile.name || ' ' || study_form.name || ' ' || ay.title,
|
||||
ay.id,
|
||||
specialty.id,
|
||||
profile.id,
|
||||
study_form.id,
|
||||
4
|
||||
FROM academic_years ay
|
||||
CROSS JOIN calendar_study_forms study_form
|
||||
JOIN specialties specialty ON specialty.specialty_code IN ('09.03.01', '10.03.01')
|
||||
JOIN specialty_profiles profile ON profile.specialty_id = specialty.id AND profile.name = 'Без профиля'
|
||||
WHERE ay.title = '2025-2026'
|
||||
ON CONFLICT (academic_year_id, specialty_profile_id, study_form_id, title) DO NOTHING;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS academic_calendar_days (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
calendar_id BIGINT NOT NULL REFERENCES academic_calendars(id) ON DELETE CASCADE,
|
||||
course_number INT NOT NULL,
|
||||
date DATE NOT NULL,
|
||||
week_number INT NOT NULL,
|
||||
day_of_week INT NOT NULL,
|
||||
activity_type_id BIGINT NOT NULL REFERENCES academic_calendar_activity_types(id),
|
||||
CONSTRAINT chk_calendar_days_course_positive CHECK (course_number > 0),
|
||||
CONSTRAINT chk_calendar_days_week_positive CHECK (week_number > 0),
|
||||
CONSTRAINT chk_calendar_days_day CHECK (day_of_week BETWEEN 1 AND 7),
|
||||
CONSTRAINT uq_calendar_days UNIQUE (calendar_id, course_number, date)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_calendar_days_lookup
|
||||
ON academic_calendar_days(calendar_id, course_number, date);
|
||||
|
||||
INSERT INTO academic_calendar_days (calendar_id, course_number, date, week_number, day_of_week, activity_type_id)
|
||||
SELECT
|
||||
calendar.id,
|
||||
course.course_number,
|
||||
days.date::DATE,
|
||||
((days.date::DATE - ay.start_date) / 7) + 1,
|
||||
EXTRACT(ISODOW FROM days.date::DATE)::INT,
|
||||
activity.id
|
||||
FROM academic_calendars calendar
|
||||
JOIN academic_years ay ON ay.id = calendar.academic_year_id
|
||||
JOIN academic_calendar_activity_types activity ON activity.code = 'Т'
|
||||
CROSS JOIN GENERATE_SERIES(1, calendar.course_count) AS course(course_number)
|
||||
CROSS JOIN GENERATE_SERIES(ay.start_date, ay.end_date, INTERVAL '1 day') AS days(date)
|
||||
ON CONFLICT (calendar_id, course_number, date) DO NOTHING;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS student_group_calendar_assignments (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
group_id BIGINT NOT NULL REFERENCES student_groups(id) ON DELETE CASCADE,
|
||||
academic_year_id BIGINT NOT NULL REFERENCES academic_years(id) ON DELETE CASCADE,
|
||||
calendar_id BIGINT NOT NULL REFERENCES academic_calendars(id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT uq_group_calendar_year UNIQUE (group_id, academic_year_id)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_group_calendar_assignments_lookup
|
||||
ON student_group_calendar_assignments(group_id, academic_year_id);
|
||||
|
||||
INSERT INTO student_group_calendar_assignments (group_id, academic_year_id, calendar_id)
|
||||
SELECT
|
||||
sg.id,
|
||||
ay.id,
|
||||
calendar.id
|
||||
FROM student_groups sg
|
||||
JOIN academic_years ay ON ay.title = '2025-2026'
|
||||
JOIN academic_calendars calendar
|
||||
ON calendar.academic_year_id = ay.id
|
||||
AND calendar.specialty_profile_id = sg.specialty_profile_id
|
||||
WHERE sg.name IN ('ИВТ-21-1', 'ИБ-41м')
|
||||
ON CONFLICT (group_id, academic_year_id) DO NOTHING;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS schedule_rules (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
@@ -445,17 +554,26 @@ CREATE TRIGGER update_users_updated_at
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
CREATE TRIGGER update_academic_calendars_updated_at
|
||||
BEFORE UPDATE ON academic_calendars
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
-- ==========================================
|
||||
-- Комментарии к таблицам и полям (для документации)
|
||||
-- ==========================================
|
||||
COMMENT ON TABLE users IS 'Пользователи системы (студенты, преподаватели, администраторы)';
|
||||
COMMENT ON TABLE departments IS 'Кафедры';
|
||||
COMMENT ON TABLE specialties IS 'Специальности';
|
||||
COMMENT ON TABLE specialty_profiles IS 'Профили обучения внутри специальности';
|
||||
COMMENT ON TABLE time_slots IS 'Настраиваемая сетка временных слотов занятий';
|
||||
COMMENT ON TABLE academic_years IS 'Учебные годы';
|
||||
COMMENT ON TABLE semesters IS 'Семестры учебного года';
|
||||
COMMENT ON TABLE holidays IS 'Праздники и неучебные даты';
|
||||
COMMENT ON TABLE academic_calendar_matrix IS 'Матрица учебного графика по курсу, специальности и неделе';
|
||||
COMMENT ON TABLE calendar_study_forms IS 'Формы обучения календарного учебного графика';
|
||||
COMMENT ON TABLE academic_calendar_activity_types IS 'Коды активностей календарного учебного графика';
|
||||
COMMENT ON TABLE academic_calendars IS 'Календарные учебные графики по профилю, форме обучения и учебному году';
|
||||
COMMENT ON TABLE academic_calendar_days IS 'Дневные ячейки календарного учебного графика';
|
||||
COMMENT ON TABLE student_group_calendar_assignments IS 'Назначения календарных графиков учебным группам по учебному году';
|
||||
COMMENT ON TABLE schedule_rules IS 'Правила динамической генерации расписания';
|
||||
COMMENT ON TABLE schedule_rule_groups IS 'Привязка правил расписания к учебным группам';
|
||||
COMMENT ON TABLE schedule_rule_slots IS 'Слоты проведения занятий внутри правила расписания';
|
||||
@@ -489,7 +607,8 @@ COMMENT ON COLUMN student_groups.name IS 'Название группы';
|
||||
COMMENT ON COLUMN student_groups.group_size IS 'Количество студентов';
|
||||
COMMENT ON COLUMN student_groups.education_form_id IS 'ID формы обучения, к которой относится группа';
|
||||
COMMENT ON COLUMN student_groups.department_id IS 'ID кафедры';
|
||||
COMMENT ON COLUMN student_groups.specialty_code IS 'ID специальности';
|
||||
COMMENT ON COLUMN student_groups.specialty_id IS 'ID специальности';
|
||||
COMMENT ON COLUMN student_groups.specialty_profile_id IS 'ID профиля обучения';
|
||||
COMMENT ON COLUMN student_groups.year_start_study IS 'Год начала обучения';
|
||||
COMMENT ON COLUMN student_groups.created_at IS 'Дата и время создания';
|
||||
|
||||
@@ -526,7 +645,7 @@ COMMENT ON COLUMN classrooms.created_at IS 'Дата и время создан
|
||||
|
||||
COMMENT ON COLUMN classroom_equipments.classroom_id IS 'ID аудитории';
|
||||
COMMENT ON COLUMN classroom_equipments.equipment_id IS 'ID оборудования';
|
||||
COMMENT ON COLUMN classroom_equipments.quantity IS 'Дата и время создания'; -- Так было в V2
|
||||
COMMENT ON COLUMN classroom_equipments.quantity IS 'Количество единиц оборудования';
|
||||
COMMENT ON COLUMN classroom_equipments.notes IS 'Примечания к записи';
|
||||
|
||||
COMMENT ON COLUMN teacher_subjects.user_id IS 'ID преподавателя';
|
||||
@@ -542,6 +661,37 @@ COMMENT ON COLUMN specialties.id IS 'ID специальности';
|
||||
COMMENT ON COLUMN specialties.name IS 'Название специальности';
|
||||
COMMENT ON COLUMN specialties.specialty_code IS 'Код специальности';
|
||||
|
||||
COMMENT ON COLUMN specialty_profiles.id IS 'ID профиля обучения';
|
||||
COMMENT ON COLUMN specialty_profiles.specialty_id IS 'ID специальности';
|
||||
COMMENT ON COLUMN specialty_profiles.name IS 'Название профиля обучения';
|
||||
COMMENT ON COLUMN specialty_profiles.description IS 'Описание профиля обучения';
|
||||
|
||||
COMMENT ON COLUMN calendar_study_forms.id IS 'ID формы обучения графика';
|
||||
COMMENT ON COLUMN calendar_study_forms.name IS 'Название формы обучения графика';
|
||||
COMMENT ON COLUMN calendar_study_forms.description IS 'Описание формы обучения графика';
|
||||
|
||||
COMMENT ON COLUMN academic_calendar_activity_types.code IS 'Код активности из календарного графика';
|
||||
COMMENT ON COLUMN academic_calendar_activity_types.name IS 'Название активности';
|
||||
COMMENT ON COLUMN academic_calendar_activity_types.allow_schedule IS 'Разрешает ли код генерацию обычного расписания';
|
||||
|
||||
COMMENT ON COLUMN academic_calendars.title IS 'Название календарного учебного графика';
|
||||
COMMENT ON COLUMN academic_calendars.academic_year_id IS 'ID учебного года';
|
||||
COMMENT ON COLUMN academic_calendars.specialty_id IS 'ID специальности';
|
||||
COMMENT ON COLUMN academic_calendars.specialty_profile_id IS 'ID профиля обучения';
|
||||
COMMENT ON COLUMN academic_calendars.study_form_id IS 'ID формы обучения графика';
|
||||
COMMENT ON COLUMN academic_calendars.course_count IS 'Количество курсов в графике';
|
||||
|
||||
COMMENT ON COLUMN academic_calendar_days.calendar_id IS 'ID календарного учебного графика';
|
||||
COMMENT ON COLUMN academic_calendar_days.course_number IS 'Номер курса';
|
||||
COMMENT ON COLUMN academic_calendar_days.date IS 'Дата';
|
||||
COMMENT ON COLUMN academic_calendar_days.week_number IS 'Номер недели в учебном году';
|
||||
COMMENT ON COLUMN academic_calendar_days.day_of_week IS 'День недели ISO';
|
||||
COMMENT ON COLUMN academic_calendar_days.activity_type_id IS 'ID кода активности';
|
||||
|
||||
COMMENT ON COLUMN student_group_calendar_assignments.group_id IS 'ID учебной группы';
|
||||
COMMENT ON COLUMN student_group_calendar_assignments.academic_year_id IS 'ID учебного года';
|
||||
COMMENT ON COLUMN student_group_calendar_assignments.calendar_id IS 'ID назначенного календарного графика';
|
||||
|
||||
COMMENT ON COLUMN teacher_lesson_types.user_id IS 'ID преподавателя';
|
||||
COMMENT ON COLUMN teacher_lesson_types.subject_id IS 'ID предмета';
|
||||
COMMENT ON COLUMN teacher_lesson_types.lesson_type_id IS 'ID типа занятия';
|
||||
|
||||
Reference in New Issue
Block a user