feat: initial backend codebase — EnCoach v3
Complete Odoo 19 backend with 25 custom addons: - encoach_core: user/entity/role management - encoach_api: REST API + JWT auth - encoach_ai: OpenAI integration, AI settings, generation - encoach_ai_course: AI-powered English & IELTS course generation - encoach_exam_template/session: exam creation, structures, sessions - encoach_scoring: AI auto-grading + manual approval - encoach_vector: pgvector RAG integration - encoach_adaptive: adaptive learning engine - encoach_placement: placement testing - encoach_taxonomy/resources: content taxonomy & resource management - Plus 14 more modules for courses, branding, portal, etc. Includes docs: user guide, generation report, developer workflow. Made-with: Cursor
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
|
||||
<template id="exam_session_page" name="Exam Session">
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>EnCoach Exam</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"/>
|
||||
<style>
|
||||
:root { --ec-primary: #4F46E5; --ec-bg: #F8FAFC; }
|
||||
body { background: var(--ec-bg); font-family: system-ui, -apple-system, sans-serif; margin:0; }
|
||||
.ec-topbar { background: var(--ec-primary); color:#fff; padding:12px 24px; display:flex; justify-content:space-between; align-items:center; }
|
||||
.ec-topbar h1 { font-size:1.1rem; margin:0; font-weight:600; }
|
||||
.ec-timer { font-size:1.25rem; font-weight:700; font-variant-numeric:tabular-nums; }
|
||||
.ec-timer.warning { color:#FCD34D; }
|
||||
.ec-timer.danger { color:#EF4444; animation:pulse 1s infinite; }
|
||||
@keyframes pulse { 50% { opacity:.5; } }
|
||||
.ec-sidebar { width:260px; background:#fff; border-right:1px solid #E2E8F0; padding:16px; overflow-y:auto; }
|
||||
.ec-sidebar .section-title { font-weight:600; color:var(--ec-primary); margin:16px 0 8px; font-size:.85rem; text-transform:uppercase; letter-spacing:.05em; }
|
||||
.ec-sidebar .q-btn { display:inline-flex; align-items:center; justify-content:center; width:40px; height:40px; border-radius:8px; border:2px solid #E2E8F0; background:#fff; cursor:pointer; font-weight:600; margin:3px; transition:.2s; }
|
||||
.ec-sidebar .q-btn:hover { border-color:var(--ec-primary); }
|
||||
.ec-sidebar .q-btn.active { background:var(--ec-primary); color:#fff; border-color:var(--ec-primary); }
|
||||
.ec-sidebar .q-btn.answered { background:#D1FAE5; border-color:#10B981; color:#065F46; }
|
||||
.ec-main { flex:1; padding:32px; overflow-y:auto; max-width:900px; margin:0 auto; }
|
||||
.ec-card { background:#fff; border-radius:12px; box-shadow:0 1px 3px rgba(0,0,0,.1); padding:28px; margin-bottom:24px; }
|
||||
.ec-question-stem { font-size:1.1rem; line-height:1.6; margin-bottom:20px; }
|
||||
.ec-option { display:flex; align-items:center; padding:14px 18px; border:2px solid #E2E8F0; border-radius:10px; margin-bottom:10px; cursor:pointer; transition:.15s; }
|
||||
.ec-option:hover { border-color:var(--ec-primary); background:#EEF2FF; }
|
||||
.ec-option.selected { border-color:var(--ec-primary); background:#EEF2FF; }
|
||||
.ec-option input { margin-right:12px; accent-color:var(--ec-primary); }
|
||||
.ec-option-key { font-weight:700; color:var(--ec-primary); margin-right:10px; min-width:24px; }
|
||||
.ec-nav { display:flex; justify-content:space-between; margin-top:24px; }
|
||||
.ec-layout { display:flex; height:calc(100vh - 56px); }
|
||||
.ec-progress-bar { height:4px; background:#E2E8F0; }
|
||||
.ec-progress-fill { height:100%; background:var(--ec-primary); transition:width .3s; }
|
||||
.ec-results { text-align:center; padding:48px; }
|
||||
.ec-band { font-size:4rem; font-weight:800; color:var(--ec-primary); }
|
||||
.ec-skill-row { display:flex; justify-content:space-between; padding:12px 0; border-bottom:1px solid #E2E8F0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="ec-topbar">
|
||||
<h1>EnCoach — <t t-out="attempt.exam_id.title"/></h1>
|
||||
<div class="ec-timer" id="timer">Loading…</div>
|
||||
</div>
|
||||
<div class="ec-progress-bar"><div class="ec-progress-fill" id="progressBar" style="width:0%"/></div>
|
||||
<div class="ec-layout">
|
||||
<div class="ec-sidebar" id="sidebar"/>
|
||||
<div class="ec-main" id="mainContent">
|
||||
<div class="ec-card" style="text-align:center; padding:48px;">
|
||||
<h2>Loading exam…</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="exam_session_app"
|
||||
t-att-data-attempt-id="attempt.id"
|
||||
t-att-data-exam-id="attempt.exam_id.id"
|
||||
t-att-data-session-token="session_token"
|
||||
style="display:none"/>
|
||||
|
||||
<script src="/encoach_exam_session/static/src/js/exam_delivery.js"/>
|
||||
</body>
|
||||
</html>
|
||||
</template>
|
||||
|
||||
<template id="placement_session_page" name="Placement Session">
|
||||
<t t-call="web.frontend_layout">
|
||||
<t t-set="no_header" t-value="True"/>
|
||||
<t t-set="no_footer" t-value="True"/>
|
||||
<div id="placement_session_app"
|
||||
t-att-data-session-id="cat_session.id"
|
||||
t-att-data-student-id="cat_session.student_id.id"
|
||||
class="ec-exam-fullscreen"/>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user