feat: promote seatmap and organization updates

This commit is contained in:
hyunho
2026-03-30 16:40:07 +09:00
parent 2e8c79bb43
commit f77be3f482
5 changed files with 250 additions and 71 deletions

View File

@@ -982,7 +982,7 @@ def parse_fixed_office_template(office_key: str = FIXED_OFFICE_SOURCE_KEY) -> di
raise HTTPException(status_code=500, detail=f"Fixed office viewer data not found: {office_key}")
html = re.sub(
r'<script\s+src="\./[^"]+payload[^"]*\.js"></script>',
r'<script\s+src="\./[^"]+payload[^"]*\.js(?:\?[^"]*)?"></script>',
f"<script>{payload_js}</script>",
html,
count=1,
@@ -1582,6 +1582,10 @@ def fetch_seat_layout(seat_map_id: int, as_of: datetime | None = None) -> dict[s
(as_of, as_of, seat_map_id, as_of, as_of),
)
placements = cur.fetchall()
cur.execute("SELECT name FROM member_retirements")
retired_names = {str(row["name"] or "").strip() for row in cur.fetchall() if str(row["name"] or "").strip()}
for member in members:
member["is_retired"] = str(member.get("name") or "").strip() in retired_names
viewer_data: dict[str, object] | None = None
office_key = str(seat_map.get("source_url") or FIXED_OFFICE_SOURCE_KEY)
fixed_office = FIXED_OFFICE_CONFIGS.get(office_key)
@@ -1807,6 +1811,8 @@ def build_center_chair_viewer_html(layout: dict[str, object]) -> str:
<script>
const seatAssignments = new Map();
let selectedChairKey = null;
let focusedChairKey = null;
let focusedChairPulseUntil = 0;
let viewerMode = "default";
const popup = document.createElement("div");
popup.className = "seat-popup";
@@ -1854,6 +1860,9 @@ def build_center_chair_viewer_html(layout: dict[str, object]) -> str:
function focusChair(chairKey, padding = 2200) {
const chair = chairGeometry.find((item) => String(item.key) === String(chairKey));
if (!chair) return;
selectedChairKey = String(chairKey);
focusedChairKey = String(chairKey);
focusedChairPulseUntil = Date.now() + 2600;
const rect = canvas.getBoundingClientRect();
const pad = 24;
const minX = chair.minX - padding;
@@ -1919,8 +1928,31 @@ def build_center_chair_viewer_html(layout: dict[str, object]) -> str:
const originalDraw = draw;
draw = function drawWithAssignments() {
originalDraw();
if (!seatAssignments.size) return;
const rect = canvas.getBoundingClientRect();
const now = Date.now();
const focusedChair = focusedChairKey
? chairGeometry.find((item) => String(item.key) === String(focusedChairKey))
: null;
if (focusedChair && now <= focusedChairPulseUntil) {
const pulse = (Math.sin(now / 180) + 1) / 2;
const center = worldToScreen((focusedChair.minX + focusedChair.maxX) / 2, (focusedChair.minY + focusedChair.maxY) / 2);
const width = Math.max(34, (focusedChair.maxX - focusedChair.minX) * camera.scale + 20 + pulse * 18);
const height = Math.max(34, (focusedChair.maxY - focusedChair.minY) * camera.scale + 20 + pulse * 18);
ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
ctx.save();
ctx.strokeStyle = `rgba(245, 158, 11, ${0.38 + pulse * 0.32})`;
ctx.lineWidth = 3 + pulse * 2;
ctx.shadowColor = "rgba(245, 158, 11, 0.35)";
ctx.shadowBlur = 16 + pulse * 10;
ctx.beginPath();
ctx.roundRect(center.x - width / 2, center.y - height / 2, width, height, 16);
ctx.stroke();
ctx.restore();
if (typeof requestDraw === "function") requestDraw();
} else if (focusedChair && now > focusedChairPulseUntil) {
focusedChairPulseUntil = 0;
}
if (!seatAssignments.size) return;
ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
ctx.textBaseline = "middle";
for (const chair of chairGeometry) {