Team Ai
Apppublic

Suparak/integer-web-app-demo

sourceHugging Faceupdated 5mo agoView on Hugging Face
0likes
PisaChatBot.html599 linesDownload Raw Back to root
1<!DOCTYPE html>
2<html lang="th">
3
4<head>
5    <meta charset="UTF-8">
6    <meta name="viewport" content="width=device-width, initial-scale=1.0">
7    <title>แบบทดสอบวัดทักษะการคิดวิเคราะห์ (PISA Style)</title>
8    <link rel="preconnect" href="https://fonts.googleapis.com">
9    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10    <link href="https://fonts.googleapis.com/css2?family=Sarabun:wght@300;400;500;600;700&display=swap"
11        rel="stylesheet">
12
13    <style>
14        :root {
15            --primary-color: #10B981;
16            /* เปลี่ยนเป็นสีเขียว Emerald */
17            --primary-hover: #059669;
18            /* สีเขียวเข้มเมื่อโฮเวอร์ */
19            --bg-color: #F0FDF4;
20            /* พื้นหลังสีเขียวมิ้นต์อ่อนๆ */
21            --card-bg: #FFFFFF;
22            /* การ์ดสีขาว */
23            --text-main: #1F2937;
24            --text-muted: #4B5563;
25            --border-color: #A7F3D0;
26            /* ขอบสีเขียวอ่อน */
27
28            /* Domain Colors - ปรับให้เข้ากับโทนธรรมชาติ */
29            --tag-math: #E0F2FE;
30            --tag-math-text: #0369A1;
31            --tag-read: #FEF3C7;
32            --tag-read-text: #B45309;
33            --tag-sci: #F3E8FF;
34            --tag-sci-text: #7E22CE;
35            --tag-digital: #FFEDD5;
36            --tag-digital-text: #C2410C;
37        }
38
39        * {
40            box-sizing: border-box;
41            margin: 0;
42            padding: 0;
43        }
44
45        body {
46            font-family: 'Sarabun', sans-serif;
47            background-color: var(--bg-color);
48            color: var(--text-main);
49            display: flex;
50            justify-content: center;
51            align-items: center;
52            min-height: 100vh;
53            padding: 20px;
54        }
55
56        .app-container {
57            background-color: var(--card-bg);
58            width: 100%;
59            max-width: 600px;
60            border-radius: 16px;
61            box-shadow: 0 10px 25px rgba(0, 0, 0, 0.05);
62            overflow: hidden;
63            display: flex;
64            flex-direction: column;
65        }
66
67        /* Header & Progress */
68        .header {
69            padding: 24px 24px 0 24px;
70        }
71
72        .progress-info {
73            display: flex;
74            justify-content: space-between;
75            align-items: center;
76            margin-bottom: 12px;
77            font-weight: 600;
78            color: var(--text-muted);
79            font-size: 0.9rem;
80        }
81
82        .progress-bar-bg {
83            width: 100%;
84            height: 8px;
85            background-color: var(--border-color);
86            border-radius: 4px;
87            overflow: hidden;
88        }
89
90        .progress-bar-fill {
91            height: 100%;
92            background-color: var(--primary-color);
93            border-radius: 4px;
94            transition: width 0.4s ease;
95        }
96
97        /* Question Area */
98        .question-container {
99            padding: 24px;
100            flex-grow: 1;
101        }
102
103        .domain-tag {
104            display: inline-block;
105            padding: 6px 12px;
106            border-radius: 20px;
107            font-size: 0.85rem;
108            font-weight: 600;
109            margin-bottom: 16px;
110        }
111
112        .tag-math {
113            background-color: var(--tag-math);
114            color: var(--tag-math-text);
115        }
116
117        .tag-read {
118            background-color: var(--tag-read);
119            color: var(--tag-read-text);
120        }
121
122        .tag-sci {
123            background-color: var(--tag-sci);
124            color: var(--tag-sci-text);
125        }
126
127        .tag-digital {
128            background-color: var(--tag-digital);
129            color: var(--tag-digital-text);
130        }
131
132        .scenario-box {
133            background-color: #F8FAFC;
134            border-left: 4px solid var(--border-color);
135            padding: 16px;
136            border-radius: 4px 8px 8px 4px;
137            margin-bottom: 20px;
138            font-size: 1rem;
139            line-height: 1.6;
140            color: var(--text-main);
141        }
142
143        .question-text {
144            font-size: 1.15rem;
145            font-weight: 600;
146            margin-bottom: 20px;
147            line-height: 1.5;
148        }
149
150        /* Options */
151        .options-grid {
152            display: flex;
153            flex-direction: column;
154            gap: 12px;
155        }
156
157        .option-btn {
158            background-color: transparent;
159            border: 2px solid var(--border-color);
160            padding: 16px;
161            border-radius: 12px;
162            text-align: left;
163            font-family: inherit;
164            font-size: 1rem;
165            cursor: pointer;
166            transition: all 0.2s ease;
167            color: var(--text-main);
168            display: flex;
169            align-items: center;
170        }
171
172        .option-btn:hover {
173            border-color: #34D399;
174            /* กรอบเขียวเวลาเอาเมาส์ชี้ */
175            background-color: #ECFDF5;
176        }
177
178        .option-btn.selected {
179            border-color: var(--primary-color);
180            background-color: #D1FAE5;
181            /* พื้นหลังเขียวอ่อนตอนเลือก */
182            font-weight: 600;
183            box-shadow: 0 2px 4px rgba(16, 185, 129, 0.15);
184        }
185
186        .option-letter {
187            display: inline-flex;
188            justify-content: center;
189            align-items: center;
190            width: 28px;
191            height: 28px;
192            background-color: var(--border-color);
193            border-radius: 50%;
194            margin-right: 12px;
195            font-weight: bold;
196            font-size: 0.9rem;
197            transition: all 0.2s ease;
198        }
199
200        .option-btn.selected .option-letter {
201            background-color: var(--primary-color);
202            color: white;
203        }
204
205        /* Footer & Navigation */
206        .footer {
207            padding: 20px 24px;
208            border-top: 1px solid var(--border-color);
209            display: flex;
210            justify-content: space-between;
211            align-items: center;
212        }
213
214        .nav-btn {
215            padding: 10px 20px;
216            border: none;
217            border-radius: 8px;
218            font-family: inherit;
219            font-size: 1rem;
220            font-weight: 600;
221            cursor: pointer;
222            transition: background-color 0.2s ease;
223        }
224
225        .btn-prev {
226            background-color: white;
227            color: var(--text-muted);
228            border: 1px solid var(--border-color);
229        }
230
231        .btn-prev:hover:not(:disabled) {
232            background-color: var(--bg-color);
233            color: var(--text-main);
234        }
235
236        .btn-next {
237            background-color: var(--primary-color);
238            color: white;
239        }
240
241        .btn-next:hover:not(:disabled) {
242            background-color: var(--primary-hover);
243        }
244
245        .nav-btn:disabled {
246            opacity: 0.5;
247            cursor: not-allowed;
248        }
249
250        /* Result Screen */
251        .result-container {
252            padding: 40px 24px;
253            text-align: center;
254            display: none;
255        }
256
257        .score-circle {
258            width: 120px;
259            height: 120px;
260            border-radius: 50%;
261            background-color: #ECFDF5;
262            /* วงกลมพื้นหลังเขียวอ่อน */
263            border: 8px solid var(--primary-color);
264            display: flex;
265            justify-content: center;
266            align-items: center;
267            margin: 0 auto 24px auto;
268            font-size: 2.5rem;
269            font-weight: 700;
270            color: var(--primary-color);
271        }
272
273        .feedback-text {
274            font-size: 1.2rem;
275            margin-bottom: 12px;
276            font-weight: 600;
277        }
278
279        .feedback-desc {
280            color: var(--text-muted);
281            line-height: 1.6;
282            margin-bottom: 30px;
283        }
284
285        .btn-retry {
286            background-color: var(--primary-color);
287            color: white;
288            padding: 12px 24px;
289            border: none;
290            border-radius: 8px;
291            font-family: inherit;
292            font-size: 1rem;
293            font-weight: 600;
294            cursor: pointer;
295            width: 100%;
296        }
297
298        /* Responsive */
299        @media (max-width: 480px) {
300            .app-container {
301                min-height: 90vh;
302            }
303
304            .question-text {
305                font-size: 1.05rem;
306            }
307
308            .option-btn {
309                padding: 12px;
310            }
311
312            .footer {
313                padding: 16px;
314            }
315        }
316    </style>
317</head>
318
319<body>
320
321    <div class="app-container" id="app">
322        <!-- Header -->
323        <div class="header" id="header">
324            <div class="progress-info">
325                <span>📝 ข้อสอบ PISA Style 🌱</span>
326                <span id="progress-text">🎯 ข้อ 1 จาก 5</span>
327            </div>
328            <div class="progress-bar-bg">
329                <div class="progress-bar-fill" id="progress-fill" style="width: 20%;"></div>
330            </div>
331        </div>
332
333        <!-- Question View -->
334        <div class="question-container" id="question-view">
335            <div id="domain-tag" class="domain-tag tag-math">🔢 คณิตศาสตร์</div>
336            <div class="scenario-box" id="scenario-text">
337                โหลดเนื้อหาสถานการณ์...
338            </div>
339            <h2 class="question-text" id="question-text">
340                โหลดคำถาม...
341            </h2>
342            <div class="options-grid" id="options-container">
343                <!-- ตัวเลือกจะถูกสร้างด้วย JS -->
344            </div>
345        </div>
346
347        <!-- Footer Navigation -->
348        <div class="footer" id="footer">
349            <button class="nav-btn btn-prev" id="btn-prev" onclick="prevQuestion()" disabled>◀ 🍃 ข้อก่อนหน้า</button>
350            <button class="nav-btn btn-next" id="btn-next" onclick="nextQuestion()">ข้อถัดไป 🌿 ▶</button>
351        </div>
352
353        <!-- Result View -->
354        <div class="result-container" id="result-view">
355            <div class="score-circle">
356                <span id="final-score">0</span>/5
357            </div>
358            <h2 class="feedback-text" id="feedback-title">ประมวลผลคะแนน...</h2>
359            <p class="feedback-desc" id="feedback-desc">รายละเอียดคำแนะนำ</p>
360            <button class="btn-retry" onclick="resetQuiz()">ทำข้อสอบอีกครั้ง</button>
361        </div>
362    </div>
363
364    <!-- JavaScript สำหรับควบคุมระบบข้อสอบ -->
365    <script>
366        // โครงสร้างข้อมูลข้อสอบ
367        const quizData = [
368            {
369                id: 1,
370                domain: "🔢 คณิตศาสตร์",
371                tagClass: "tag-math",
372                scenario: "ป้ายโปรโมชันหน้าร้านกาแฟแห่งหนึ่งระบุว่า \"พิเศษ! ซื้อแก้วที่ 2 ลดทันที 50%\" โดยกาแฟแก้วแรกราคาปกติ 80 บาท และกาแฟแก้วที่สองราคาปกติ 80 บาทเท่ากัน",
373                question: "หากมานีต้องการซื้อกาแฟ 2 แก้วตามโปรโมชันนี้ เธอจะต้องจ่ายเงินทั้งหมดเท่าไร?",
374                options: ["80 บาท", "120 บาท", "140 บาท", "160 บาท"],
375                correctAnswer: 1 // ตัวเลือก B (index 1) : 80 + 40 = 120
376            },
377            {
378                id: 2,
379                domain: "📖 การอ่าน",
380                tagClass: "tag-read",
381                scenario: "ประกาศเทศบาลเมือง: \"เพื่อลดปัญหาขยะพลาสติกและรักษาสิ่งแวดล้อม ตั้งแต่วันที่ 1 เดือนหน้าเป็นต้นไป ห้างสรรพสินค้าและร้านสะดวกซื้อในเขตเทศบาล จะงดให้บริการถุงพลาสติกฟรี หากลูกค้าต้องการถุงพลาสติกจะต้องชำระเงินเพิ่มใบละ 2 บาท\"",
382                question: "จุดประสงค์หลักที่แท้จริงของประกาศฉบับนี้คือข้อใด?",
383                options: ["เพื่อเพิ่มรายได้พิเศษให้กับร้านสะดวกซื้อ", "เพื่อกระตุ้นให้ประชาชนพกถุงผ้ามาเอง", "เพื่อนำเงิน 2 บาทไปจัดตั้งกองทุนกำจัดขยะ", "เพื่อบังคับให้ทุกคนต้องซื้อถุงพลาสติก"],
384                correctAnswer: 1 // ตัวเลือก B (index 1) : เพื่อกระตุ้นพฤติกรรมลดการใช้พลาสติก
385            },
386            {
387                id: 3,
388                domain: "🔬 วิทยาศาสตร์",
389                tagClass: "tag-sci",
390                scenario: "นักเรียนทดลองต้มน้ำในบีกเกอร์และบันทึกอุณหภูมิทุกๆ 2 นาที ได้ผลดังนี้<br><br>นาทีที่ 0: 25°C<br>นาทีที่ 2: 45°C<br>นาทีที่ 4: 65°C<br>นาทีที่ 6: 85°C",
391                question: "หากทดลองต้มน้ำต่อไปเรื่อยๆ ที่ระดับความดันบรรยากาศปกติ (น้ำเดือดที่ 100°C) อุณหภูมิของน้ำในนาทีที่ 8 ควรจะเป็นเท่าไร?",
392                options: ["95°C", "100°C", "105°C", "125°C"],
393                correctAnswer: 1 // ตัวเลือก B (index 1) : 100°C เพราะน้ำไม่สามารถร้อนเกินจุดเดือดที่ความดันปกติได้ (PISA Trick)
394            },
395            {
396                id: 4,
397                domain: "📊 คณิตศาสตร์",
398                tagClass: "tag-math",
399                scenario: "พนักงานตรวจสอบคุณภาพสินค้าทำการสุ่มตรวจสินค้า 100 ชิ้นจากสายการผลิต พบว่ามีสินค้าไม่ได้มาตรฐานจำนวน 5 ชิ้น",
400                question: "หากในวันนั้นโรงงานผลิตสินค้าออกมาทั้งหมด 2,000 ชิ้น คาดว่าจะมีสินค้าที่ไม่ได้มาตรฐานประมาณกี่ชิ้น?",
401                options: ["50 ชิ้น", "100 ชิ้น", "150 ชิ้น", "200 ชิ้น"],
402                correctAnswer: 1 // ตัวเลือก B (index 1) : (5/100) * 2000 = 100
403            },
404            {
405                id: 5,
406                domain: "💻 Digital Literacy",
407                tagClass: "tag-digital",
408                scenario: "นักเรียนได้รับข้อความส่งต่อในแอปพลิเคชันแชทว่า \"ด่วน! ข่าวดีทางการแพทย์ ดื่มน้ำมะนาวอุ่นผสมโซดาทุกเช้า ช่วยฆ่าเซลล์มะเร็งได้ 100% แชร์ต่อให้คนที่คุณรักด่วน!\"",
409                question: "สิ่งแรกที่นักเรียนควรทำเพื่อประเมินความน่าเชื่อถือของข้อความนี้คือข้อใด?",
410                options: ["ส่งต่อให้เพื่อนในกลุ่มห้องเรียนเพื่อถามความคิดเห็น", "ทดลองดื่มด้วยตนเองเป็นเวลา 1 สัปดาห์เพื่อดูผลลัพธ์", "ค้นหาข้อมูลยืนยันจากเว็บไซต์ของกระทรวงสาธารณสุขหรือสถาบันมะเร็ง", "ตรวจสอบดูว่าคนที่ส่งข้อความมาให้นั้นเป็นคนรู้จักที่ไว้ใจได้หรือไม่"],
411                correctAnswer: 2 // ตัวเลือก C (index 2) : ตรวจสอบจากแหล่งข้อมูลที่น่าเชื่อถืออย่างเป็นทางการ
412            }
413        ];
414
415        // ตัวแปรสถานะที่สำคัญ (currentQuestion สามารถให้ Dify เข้าถึงได้)
416        let currentQuestion = 0;
417        let userAnswers = new Array(quizData.length).fill(null);
418
419        // อ้างอิง DOM Elements
420        const headerEl = document.getElementById('header');
421        const footerEl = document.getElementById('footer');
422        const questionView = document.getElementById('question-view');
423        const resultView = document.getElementById('result-view');
424        const progressText = document.getElementById('progress-text');
425        const progressFill = document.getElementById('progress-fill');
426
427        const domainTag = document.getElementById('domain-tag');
428        const scenarioText = document.getElementById('scenario-text');
429        const questionText = document.getElementById('question-text');
430        const optionsContainer = document.getElementById('options-container');
431
432        const btnPrev = document.getElementById('btn-prev');
433        const btnNext = document.getElementById('btn-next');
434
435        // ฟังก์ชันแสดงผลข้อสอบตาม Index ปัจจุบัน
436        function renderQuestion() {
437            const data = quizData[currentQuestion];
438
439            // อัปเดต Progress
440            progressText.innerText = `🎯 ข้อ ${currentQuestion + 1} จาก ${quizData.length}`;
441            progressFill.style.width = `${((currentQuestion + 1) / quizData.length) * 100}%`;
442
443            // อัปเดตเนื้อหา
444            domainTag.className = `domain-tag ${data.tagClass}`;
445            domainTag.innerText = data.domain;
446            scenarioText.innerHTML = data.scenario;
447            questionText.innerText = data.question;
448
449            // สร้างตัวเลือก
450            optionsContainer.innerHTML = '';
451            const labels = ['A', 'B', 'C', 'D'];
452
453            data.options.forEach((optText, index) => {
454                const btn = document.createElement('button');
455                btn.className = `option-btn ${userAnswers[currentQuestion] === index ? 'selected' : ''}`;
456                btn.onclick = () => selectOption(index);
457
458                btn.innerHTML = `
459                    <span class="option-letter">${labels[index]}</span>
460                    <span>${optText}</span>
461                `;
462                optionsContainer.appendChild(btn);
463            });
464
465            // จัดการปุ่มนำทาง
466            btnPrev.disabled = currentQuestion === 0;
467
468            if (currentQuestion === quizData.length - 1) {
469                btnNext.innerText = 'ส่งคำตอบ / ดูผลลัพธ์ ✨';
470                btnNext.style.backgroundColor = '#059669'; // Green for submit
471            } else {
472                btnNext.innerText = 'ข้อถัดไป 🌿 ▶';
473                btnNext.style.backgroundColor = 'var(--primary-color)';
474            }
475        }
476
477        // ฟังก์ชันเมื่อผู้ใช้คลิกเลือกคำตอบ
478        function selectOption(selectedIndex) {
479            userAnswers[currentQuestion] = selectedIndex;
480
481            // อัปเดต UI ทันที
482            const optionBtns = optionsContainer.children;
483            for (let i = 0; i < optionBtns.length; i++) {
484                if (i === selectedIndex) {
485                    optionBtns[i].classList.add('selected');
486                } else {
487                    optionBtns[i].classList.remove('selected');
488                }
489            }
490        }
491
492        // ไปข้อถัดไป หรือ แสดงผลลัพธ์
493        function nextQuestion() {
494            // ตรวจสอบว่าตอบคำถามหรือยัง
495            if (userAnswers[currentQuestion] === null) {
496                alert("กรุณาเลือกคำตอบอย่างน้อย 1 ตัวเลือกก่อนไปข้อถัดไป");
497                return;
498            }
499
500            if (currentQuestion < quizData.length - 1) {
501                currentQuestion++;
502                renderQuestion();
503            } else {
504                showResults();
505            }
506        }
507
508        // ย้อนกลับไปข้อก่อนหน้า
509        function prevQuestion() {
510            if (currentQuestion > 0) {
511                currentQuestion--;
512                renderQuestion();
513            }
514        }
515
516        // ฟังก์ชันคำนวณคะแนนและแสดงผลลัพธ์
517        function showResults() {
518            headerEl.style.display = 'none';
519            questionView.style.display = 'none';
520            footerEl.style.display = 'none';
521            resultView.style.display = 'block';
522
523            let score = 0;
524            userAnswers.forEach((ans, index) => {
525                if (ans === quizData[index].correctAnswer) {
526                    score++;
527                }
528            });
529
530            document.getElementById('final-score').innerText = score;
531
532            const feedbackTitle = document.getElementById('feedback-title');
533            const feedbackDesc = document.getElementById('feedback-desc');
534
535            if (score === 5) {
536                feedbackTitle.innerText = 'ยอดเยี่ยมมาก! 🏆🌟';
537                feedbackDesc.innerText = 'ทักษะการคิดวิเคราะห์ของคุณอยู่ในระดับสูงมาก! 🧠✨ คุณสามารถวิเคราะห์ข้อมูลจากหลากหลายสถานการณ์ได้อย่างแม่นยำ 🎯';
538            } else if (score >= 3) {
539                feedbackTitle.innerText = 'ทำได้ดี! 👍✨';
540                feedbackDesc.innerText = 'คุณมีความเข้าใจพื้นฐานและทักษะการวิเคราะห์ที่ดี 🌿 แต่อาจต้องฝึกฝนการสังเกตจุดเล็กๆ น้อยๆ ในข้อมูลที่ซับซ้อนขึ้นอีกนิดนะ 🔍';
541            } else {
542                feedbackTitle.innerText = 'พยายามได้ดี! 💪🌱';
543                feedbackDesc.innerText = 'ข้อสอบ PISA จะเน้นการนำความรู้ไปใช้ในสถานการณ์จริง 💡 แนะนำให้ฝึกอ่านและวิเคราะห์ข้อมูลจากข่าวสารรอบตัวให้มากขึ้นนะ สู้ๆ! ✌️';
544            }
545        }
546
547        // เริ่มทำข้อสอบใหม่
548        function resetQuiz() {
549            currentQuestion = 0;
550            userAnswers = new Array(quizData.length).fill(null);
551
552            headerEl.style.display = 'block';
553            questionView.style.display = 'block';
554            footerEl.style.display = 'flex';
555            resultView.style.display = 'none';
556
557            renderQuestion();
558        }
559
560        // เริ่มต้นแอป
561        renderQuestion();
562    </script>
563
564    <script>
565 window.difyChatbotConfig = {
566  token: 'APlBRFntPxGRUIOd',
567  inputs: {
568    // You can define the inputs from the Start node here
569    // key is the variable name
570    // e.g.
571    // name: "NAME"
572  },
573  systemVariables: {
574    // user_id: 'YOU CAN DEFINE USER ID HERE',
575    // conversation_id: 'YOU CAN DEFINE CONVERSATION ID HERE, IT MUST BE A VALID UUID',
576  },
577  userVariables: {
578    // avatar_url: 'YOU CAN DEFINE USER AVATAR URL HERE',
579    // name: 'YOU CAN DEFINE USER NAME HERE',
580  },
581 }
582</script>
583<script
584 src="https://udify.app/embed.min.js"
585 id="APlBRFntPxGRUIOd"
586 defer>
587</script>
588<style>
589  #dify-chatbot-bubble-button {
590    background-color: #1C64F2 !important;
591  }
592  #dify-chatbot-bubble-window {
593    width: 24rem !important;
594    height: 40rem !important;
595  }
596</style>
597</body>
598
599</html>