Аудитории: фильтры по типу, вместимости и оснащению + режим «свободные на паре»
Бэкенд: - parse_rooms_info разбирает описание аудитории (формат «тип; оснащение; N мест») в атрибуты: type (фразой как в таблице), capacity (места, а для компьютерных классов — рабочие места; null, если данных нет), equipment (ПК, Проектор, Интерактивная панель, Телевизор, Маркер, Меловая доска) и available_days («402 четверг пятница»); «без проектора» трактуется как отсутствие; - /rooms-day и /rooms-free отдают атрибуты (room_payload); аудитории с ограничением по дням не предлагаются в /rooms-free в остальные дни. Фронтенд (вкладка «Аудитории»): - панель фильтров: тип (значения из данных таблицы), «мест не меньше», оснащение чекбоксами с выбором условия «все (И)» / «любое (ИЛИ)»; - счётчик «Показано N из M» и пояснения: сколько аудиторий скрыто из-за отсутствия данных о вместимости, сколько доступны только по отдельным дням; - переключатель «Занятость за день» / «Свободные на паре» (с выбором пары) — вместе с фильтрами это «свободная аудитория на 30 человек с проектором в 3-ю пару»; выбранные фильтры запоминаются в браузере; - в карточке аудитории видны разобранные атрибуты и пометки из таблицы. Тесты: разбор всех форматов описаний (включая отрицания и меловую доску), API атрибутов и учёта доступных дней. Всего 159.
This commit is contained in:
@@ -263,3 +263,31 @@ def test_cache_without_link():
|
||||
assert c.get("/groups").status_code == 502
|
||||
body = c.get("/status").json()
|
||||
assert "Ссылка" in body["error"]
|
||||
|
||||
|
||||
def test_rooms_day_and_free_include_attributes(monkeypatch):
|
||||
"""Аудитории отдаются с типом/вместимостью/оснащением и учётом доступных дней."""
|
||||
from fixtures import fixture_sheets
|
||||
from xlsx_builder import build_workbook
|
||||
|
||||
sheets = fixture_sheets()
|
||||
rooms = sheets["аудитории"]
|
||||
rooms.rows[0].append("402")
|
||||
rooms.rows[1].append("402 четверг пятница")
|
||||
|
||||
cache, _, _ = make_cache(monkeypatch, build_workbook(sheets))
|
||||
with TestClient(main.create_app(cache)) as client:
|
||||
day = client.get("/rooms-day", params={"day": "понедельник"}).json()
|
||||
by_label = {r["room"]: r for r in day["rooms"]}
|
||||
room215 = by_label["ауд. 215"]
|
||||
assert room215["type"] == "комп.класс"
|
||||
assert room215["capacity"] == 12
|
||||
assert room215["equipment"] == ["ПК"]
|
||||
assert by_label["ауд. 402"]["available_days"] == ["четверг", "пятница"]
|
||||
|
||||
free_monday = client.get("/rooms-free", params={"day": "понедельник", "period": 1}).json()
|
||||
assert not any(r["room"] == "ауд. 402" for r in free_monday)
|
||||
assert all("capacity" in r and "equipment" in r for r in free_monday)
|
||||
|
||||
free_thursday = client.get("/rooms-free", params={"day": "четверг", "period": 1}).json()
|
||||
assert any(r["room"] == "ауд. 402" for r in free_thursday)
|
||||
|
||||
@@ -176,11 +176,20 @@ def test_group_schedule_shape(data):
|
||||
|
||||
def test_rooms_info(sheets):
|
||||
info = parsing.parse_rooms_info(sheets)
|
||||
assert info == {
|
||||
"ауд. 215": {"room": "ауд. 215", "info": "комп.класс, 12 мест"},
|
||||
"ауд. 301": {"room": "ауд. 301", "info": "интерактивная панель, 24 места"},
|
||||
"ауд. 220": {"room": "ауд. 220", "info": "20 мест"},
|
||||
}
|
||||
assert set(info) == {"ауд. 215", "ауд. 301", "ауд. 220"}
|
||||
assert info["ауд. 215"]["info"] == "комп.класс, 12 мест"
|
||||
assert info["ауд. 215"]["type"] == "комп.класс"
|
||||
assert info["ауд. 215"]["capacity"] == 12
|
||||
assert info["ауд. 215"]["equipment"] == ["ПК"]
|
||||
|
||||
assert info["ауд. 301"]["info"] == "интерактивная панель, 24 места"
|
||||
assert info["ауд. 301"]["capacity"] == 24
|
||||
assert info["ауд. 301"]["equipment"] == ["Интерактивная панель"]
|
||||
|
||||
assert info["ауд. 220"]["info"] == "20 мест"
|
||||
assert info["ауд. 220"]["type"] == ""
|
||||
assert info["ауд. 220"]["capacity"] == 20
|
||||
assert info["ауд. 220"]["equipment"] == []
|
||||
|
||||
|
||||
def test_teachers_full(sheets):
|
||||
@@ -205,3 +214,64 @@ def test_build_room_schedule(data):
|
||||
assert set(out["days"]) == {"понедельник", "вторник"}
|
||||
assert out["days"]["понедельник"]["1"]["ч"][0]["subject"] == "Физика"
|
||||
assert parsing.build_room_schedule(rooms, "ауд. 999", times) is None
|
||||
|
||||
|
||||
def test_room_attributes_from_descriptions():
|
||||
"""Атрибуты аудиторий разбираются из описаний вида «тип; оснащение; N мест»."""
|
||||
from xlsx_builder import SheetSpec
|
||||
|
||||
descriptions = {
|
||||
"201": "комп.класс МО и СТ; без проектора; маркер; 12 мест",
|
||||
"203": "аудитория для практических; без проектора; меловая доска; 44 места",
|
||||
"210": "комп.класс; проектор; маркер; 28 мест",
|
||||
"305": "кабинет английского; телевизор; маркер; 24 места",
|
||||
"402": "402 четверг пятница",
|
||||
"405": "пк",
|
||||
"410": "",
|
||||
}
|
||||
spec = SheetSpec(rows=[
|
||||
[None] * 6 + list(descriptions.keys()),
|
||||
[None] * 6 + list(descriptions.values()),
|
||||
])
|
||||
info = parsing.parse_rooms_info(make_sheets({parsing.ROOMS_SHEET: spec}))
|
||||
|
||||
assert info["ауд. 201"]["type"] == "комп.класс"
|
||||
assert info["ауд. 201"]["capacity"] == 12
|
||||
# «без проектора» — проектора нет, хотя слово в тексте есть
|
||||
assert info["ауд. 201"]["equipment"] == ["ПК", "Маркер"]
|
||||
assert info["ауд. 201"]["available_days"] is None
|
||||
|
||||
assert info["ауд. 203"]["type"] == "аудитория для практических"
|
||||
assert info["ауд. 203"]["equipment"] == ["Меловая доска"]
|
||||
assert info["ауд. 203"]["capacity"] == 44
|
||||
|
||||
assert info["ауд. 210"]["equipment"] == ["ПК", "Проектор", "Маркер"]
|
||||
|
||||
assert info["ауд. 305"]["type"] == "кабинет английского"
|
||||
assert info["ауд. 305"]["equipment"] == ["Телевизор", "Маркер"]
|
||||
|
||||
assert info["ауд. 402"]["available_days"] == ["четверг", "пятница"]
|
||||
assert info["ауд. 402"]["capacity"] is None
|
||||
assert info["ауд. 402"]["type"] == ""
|
||||
|
||||
assert info["ауд. 405"]["equipment"] == ["ПК"]
|
||||
assert info["ауд. 410"]["info"] == ""
|
||||
assert info["ауд. 410"]["type"] == ""
|
||||
|
||||
|
||||
def test_room_payload_shape():
|
||||
payload = parsing.room_payload("ауд. 215", {
|
||||
"info": "лекционная; проектор; 96 мест",
|
||||
"type": "лекционная",
|
||||
"capacity": 96,
|
||||
"equipment": ["Проектор"],
|
||||
"available_days": None,
|
||||
})
|
||||
assert payload == {
|
||||
"room": "ауд. 215",
|
||||
"info": "лекционная; проектор; 96 мест",
|
||||
"type": "лекционная",
|
||||
"capacity": 96,
|
||||
"equipment": ["Проектор"],
|
||||
"available_days": None,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user