اذهب إلى المحتوى

السؤال

نشر (معدل)

السلام عليكم جمعة مباركة إن شاء الله
مشكلتي في صفحة الاختبارات، عند الانتقال من سؤال لآخر في اختبار الاستماع، يتم تحديث الرابط ولكن الصوت لا يتغير. وأعتقد أن المشكلة تكمن في ذاكرة التخزين المؤقت (Cache). هل يمكنكم المساعدة في حل هذه المشكلة؟

علما أنني أستخدم إطار عمل laravel مع livewire 
 

            @elseif($questions[$currentQuestionIndex]->type == 'record_voice')
                <audio id="question-audio" controls>
                    <source
                       src="{{ asset('audio/'.$questions[$currentQuestionIndex]->question_text) }}?v={{ $questions[$currentQuestionIndex]->updated_at->timestamp }}"
                       // src="{{ $audioSource }}"
                        type="audio/mpeg">
                    Your browser does not support the audio element.
                </audio>



            @endif


يتم اختيار سؤال الحالي عن طريق الكورنت اندكس الذي يستخرجه من مصفوفه الاسئله  المشكله تكون فقط اذا كان اكثر من سؤال فيه ملف صوتي بحيث بقيه الاسئله تاخذ نفس المقطع الصوتي السابق رغم اني طبعت الرابط ولاحظت ان الرابط يتغير كل مره لكن الملف الصوتي يظل هو هو جربت كم من طريقه لم تفلح معي انتم تعرفون ان الصفحه لا يتم تحديثها في اللايف وير ربما هذه هي المشكله

$questions[$currentQuestionIndex]

 يتم تغيير الاندكس الخاص بالسؤال الحالي في متحكم لايف وير في حال إنتقل المستخدم من سؤال لآخر سواء ذهابا أم إيابا و إذا كان آخر سؤال يتم إرسال الأجوبة أو إذا إنتهى الوقت سأرفق لكم الشيفة الخاصة بالمتحكم وصفحة العرض لايفوير 

صفحة العرض :
 

<div class="page-body dark:bg-black dark:text-white bg-gray-200 mb-12 px-8 border h-full grid grid-cols-4 gap-2 p-20">

    {{-- 1 --}}
    <img src="{{ asset('storage/online2.png') }}" alt="" class="flex m-auto col-span-1">

    <div class="sec-question col-span-3 px-16">
        <div class="border-4 border-white dark:border-2 p-4 rounded-lg">
            {{-- Step and Exam information --}}
            <div class="space-x-32 relative px-1 m-auto">
                <!-- Display the current queepion number and the total number of questions -->
                <div class="total-number text-2xl text-red-400 font-bold absolute left-5">
                    {{ $currentQuestionIndex + 1 }}/{{ $questions->count() }}</div>
                <!-- Display the name of the exam -->
                <div class="exam-number font-bold right-5 absolute">{{ $exam->name }}</div>
            </div>

            {{-- Divider --}}

            <hr class="w-[94%] h-1 my-10 border-white text-white m-auto flex">

            {{-- Question and Time --}}
            <div class="justify-between text-clip flex">
                <div class="question-part font-bold px-7 mr-16 text-2xl overflow-wrap-anywhere">
                    {{ $questions[$currentQuestionIndex]->question }}</div>

                <div class="time-down font-bold text-lg">
                    <div id="taim" class="taim  flex gap-x-2 ">
                        <div class="circle relative w-28 h-28 justify-center flex items-center">
                            <div
                                class="dots hours   absolute w-full h-full rounded-[50%] flex justify-center items-start  z-[1000]   before:w-3 before:h-3 before:absolute before:top-[02px]  before:bg-amber-600 before:rounded-[50%] before:shadow-[0_0_20px_rgb(202_138_4)_,_0_0_60px_rgb(202_138_4)]   ">
                            </div>
                            <svg class="relative w-28 h-28 rotate-[270deg] ">
                                <circle
                                    class="w-full h-full fill-transparent stroke-[8] stroke-stone-900 translate-x-1 translate-y-1"
                                    cx="50" cy="50" r="50"></circle>
                                <circle stroke-dashoffset="440" stroke-dasharray="440"
                                    class="  w-full h-full fill-transparent stroke-[8] stroke-amber-600 translate-x-1 translate-y-1"
                                    cx="50" cy="50" r="50" id="hh"></circle>
                            </svg>
                            <div class="absolute text-center font-[500] text-[1.5rem] text-gray-800" id="hours">
                                00<br> <span
                                    class="uppercase text-gray-900 absolute translate-x-[-50%] translate-y-[-10px] text-[0.65rem] font-[500] tracking-[0.1rem]">hours</span>
                            </div>

                        </div>
                        <div class="circle  relative w-28 h-28 justify-center flex items-center ">
                            <div
                                class="dots minutes  absolute w-full h-full rounded-[50%] flex justify-center items-start  z-[1000]   before:w-3 before:h-3 before:absolute before:top-[02px]  before:bg-green-600 before:rounded-[50%] before:shadow-[0_0_20px_rgb(22_163_74)_,_0_0_60px_rgb(22_163_74)]  ">
                            </div>
                            <svg class="relative w-28 h-28 rotate-[270deg] ">
                                <circle
                                    class="w-full h-full fill-transparent stroke-[8] stroke-stone-900 translate-x-1 translate-y-1"
                                    cx="50" cy="50" r="50"></circle>
                                <circle stroke-dashoffset="300" stroke-dasharray="612"
                                    class="  w-full h-full fill-transparent stroke-[8] stroke-green-600 translate-x-1 translate-y-1"
                                    cx="50" cy="50" r="50" id="mm"></circle>
                            </svg>
                            <div class="absolute text-center font-[500] text-[1.5rem]  text-gray-800" id="minutes">
                                00<br> <span
                                    class="uppercase text-gray-900 absolute translate-x-[-50%] translate-y-[-10px] text-[0.65rem] font-[500] tracking-[0.1rem]">minutes</span>
                            </div>

                        </div>
                        <div class="circle   relative w-28 h-28 justify-center flex items-center ">
                            <div
                                class="dots seconds  absolute w-full h-full rounded-[50%] flex justify-center items-start  z-[1000]    before:w-3 before:h-3 before:absolute before:top-[02px]   before:bg-purple-500 before:rounded-[50%] before:shadow-[0_0_20px_rgb(168_85_247)_,_0_0_60px_rgb(168_85_247)]    ">
                            </div>
                            <svg class="relative w-28 h-28 rotate-[270deg] ">
                                <circle
                                    class="w-full h-full fill-transparent stroke-[8] stroke-stone-900 translate-x-1 translate-y-1"
                                    cx="50" cy="50" r="50"></circle>
                                <circle stroke-dashoffset="300" stroke-dasharray="612"
                                    class="  w-full h-full fill-transparent stroke-[8] stroke-purple-500 translate-x-1 translate-y-1"
                                    cx="50" cy="50" r="50" id="ss"></circle>
                            </svg>
                            <div class="absolute text-center font-[500] text-[1.5rem]  text-gray-800" id="seconds">00
                            </div>

                        </div>
                    </div>
                </div>

                <script>
                    var remainingTime = localStorage.getItem('remainingTime') || {{ $remainingTime }};
                    var initialTime = {{ $remainingTime }};

                    // Define a function to update the remaining time
                    function updateRemainingTime() {
                        // Check if the exam time has expired
                        if (remainingTime <= 0) {
                            // If so, submit the answers
                            // Livewire.emit('sendAnswersToServer');
                            console.log('exam finish');
                            @this.call('sendAnswersToServer');
                            localStorage.removeItem('remainingTime');
                        } else {
                            // Otherwise, decrement the remaining time by 1 second
                            remainingTime = remainingTime - 1;
                            // @this.call('updatePivotTable', remainingTime);

                            // Update the remaining time displayed on the page

                            var minutes = Math.floor(remainingTime / 60);
                            var seconds = remainingTime % 60;
                            document.getElementById('minutes').innerHTML = minutes +
                                '<br> <span class="uppercase text-gray-900 absolute translate-x-[-50%] translate-y-[-10px] text-[0.65rem] font-[500] tracking-[0.1rem]">menutes</span>';
                            document.getElementById('seconds').innerHTML = (seconds < 10 ? "0" : "") + seconds +
                                '<br> <span class="uppercase text-gray-900 absolute translate-x-[-50%] translate-y-[-10px] text-[0.65rem] font-[500] tracking-[0.1rem]">seconds</span>';

                            // retrieve the circle element by its id
                            var myHCircle = document.getElementById('hh');
                            var myMCircle = document.getElementById('mm');
                            var mySCircle = document.getElementById('ss');

                            // set the new stroke-dashoffset value
                            // mySCircle.setAttribute('stroke-dashoffset', 440 - (440 * minutes) / 60);
                            myMCircle.setAttribute('stroke-dasharray', 312 + (300 * minutes) / (initialTime / 60));
                            mySCircle.setAttribute('stroke-dasharray', 312 + (300 * seconds) / 60);


                            // formatTime(remainingTime);
                            // document.getElementById('remainingTime').innerHTML = 

                            // Store the remaining time in local storage
                            localStorage.setItem('remainingTime', remainingTime);

                            // Call the updateRemainingTime function again after 1 second
                            setTimeout(updateRemainingTime, 1000);
                        }
                    }

                    // Use setTimeout to update the remaining time after the exam has started

                    document.addEventListener('livewire:load', function() {
                        console.log('Livewire loaded');
                        setTimeout(updateRemainingTime, 1000);
                    });
                </script>





            </div>


            @if ($questions[$currentQuestionIndex]->type == 'fill')


                <div class="mt-8 font-bold px-10">
                    @php
                        $listItems = $questions[$currentQuestionIndex]->blanks;
                        $text = $questions[$currentQuestionIndex]->question_text;
                        $fillQuestion = '';
                        
                        for ($i = 1; $i < count($listItems) + 1; $i++) {
                            if (strpos($text, '[__]')) {
                                $fillQuestion = '<input type="text" class="m-1 text-center space-x-5 bg-inherit shadow border-none h-8 focus:ring-0 p-4 w-fit" placeholder="_ _ _ _ _ _ _ _ _" name="' . $i . '__blank"  wire:model.lazy="fill_answers.' . $currentQuestionIndex . '.' . $i . '">';
                                $text = substr_replace($text, $fillQuestion, strpos($text, '[__]'), 4);
                            }
                        }
                        echo $text;
                        
                    @endphp

                    {{-- <button type="submit" wire:click="saveInputs">submit</button> --}}
                    @foreach ($fill_answers as $key => $items)
                        {{ $key . ':' }}
                        @foreach ($items as $item)
                            {{ $item }}
                        @endforeach
                    @endforeach


                </div>
            @elseif($questions[$currentQuestionIndex]->type == 'Multiple_choice')
                {{-- Answers --}}
                <div class="answers mt-8">
                    <ul class="px-8">
                        {{-- Previous answer --}}
                        @if (isset($currentAnswers[$questions[$currentQuestionIndex]->id]))
                            @if (array_key_exists($questions[$currentQuestionIndex]->id, $currentAnswers))
                                <h1>Your previous answer</h1>
                                @php
                                    $answer = $all_answers->where('id', $currentAnswers[$questions[$currentQuestionIndex]->id])->first();
                                @endphp
                                <li
                                    class="my-2 w-full p-4 font-bold text-lg border rounded-lg dark:text-white/60 dark:font-semibold text-[#523b92] dark:border-white hover:text-white bg-red-400">
                                    {{ $answer->answer }}
                                </li>
                                <hr class="h-2 bg-slate-400">
                            @endif
                        @endif


                        {{-- Shuffled answers --}}
                        @php
                            $shuffledAnswers = collect($all_answers->where('question_id', $questions[$currentQuestionIndex]->id))->shuffle();
                            
                        @endphp
                        @foreach ($shuffledAnswers as $key => $item)
                            <li class="my-2 cursor-pointer w-full p-4 font-bold text-lg border rounded-lg dark:text-white/60 dark:font-semibold text-[#523b92] dark:border-white border-[#523b92] hover:text-white hover:bg-[#523b92]"
                                wire:click="submitAnswer('{{ $item->id }}')">
                                {{ $item->answer }}
                            </li>
                        @endforeach


                    </ul>
                </div>
            @elseif($questions[$currentQuestionIndex]->type == 'record_voice')
                <audio id="question-audio" controls>
                    <source
                        src="{{ $audioSource }}"
                        type="audio/mpeg">
                    Your browser does not support the audio element.
                </audio>



            @endif

            {{-- Navigation buttons --}}
            <div class="inline-flex justify-around mt-6 w-full">
                <button wire:click="preAnswer()" onclick="stopAudio()"
                    class="bg-orange-500 hover:bg-orange-400 text-white font-bold py-2 px-4 rounded-l">
                    <span class="material-symbols-outlined">Undo Prev</span>
                </button>

                @if ($questions->count() == $currentQuestionIndex + 1)
                    <button wire:click="submitAnswer()"
                        class="bg-orange-500 hover:bg-orange-400 text-white font-bold py-2 px-4 rounded-r">
                        Finish Exam
                    </button>
                @else
                    <button wire:click="goToNextQuestionIfPossible()" onclick="stopAudio()"
                        class="bg-orange-500 hover:bg-orange-400 text-white font-bold py-2 px-4 rounded-r">
                        <span class="material-symbols-outlined">Redo Next</span>
                    </button>
                @endif
            </div>

            <script>
                function stopAudio() {
                    var audio = document.getElementById("question-audio");
                    audio.pause();
                    audio.currentTime = 0;
                }
            </script>



        </div>
    </div>
</div>

المتحكم :
 

<?php

// In your Questions component

namespace App\Http\Livewire;

use App\Models\Answer;
use App\Models\Exam;
use App\Models\Question;
use App\Models\UserAnswer;
use Illuminate\Contracts\Session\Session;
use Illuminate\Database\Eloquent\Collection;
use Livewire\Component;
use Illuminate\Session\SessionManager;
use Illuminate\Support\Facades\Auth;

class Questions extends Component
{
    public Exam $exam;

    public Collection $questions;
    public int $currentQuestionIndex = 0;
    public $all_answers;
    public $remainingTime;
    public $fill_answers = [];
    public $audioSource;





    //  /تحديث الوقت كل ثانية / إحضار جميع الإجابات
    public function mount()
    {
        $this->emit('examStarted');
        $this->getAnswers();
        $this->getUser();
        $this->remainingTime = $this->user->exams->find($this->exam->id)->pivot->time_of_exam * 60;
       
    }
    //  إحضار جميع الإجابات
    public function getAnswers()
    {
        $this->all_answers = Answer::all();
    }
    //   المستخد الحالي 
    public function getUser()
    {
        $this->user = auth()->user();
    }

    // Define a function to update the remaining time



    public function submitAnswer($choiceKey, SessionManager $session)
    {
        // Get ID for current question
        $questionId = $this->questions[$this->currentQuestionIndex]->id;

        // Get stored answers from session
        $storedAnswers = json_decode($session->get('answers', '{}'), true);

        // Check if an answer for this question already exists
        if (array_key_exists($questionId, $storedAnswers)) {
            // Remove existing answer
            unset($storedAnswers[$questionId]);
        }

        // Add new answer
        $storedAnswers[$questionId] = $choiceKey;

        // Save updated answers to session
        $session->put('answers', json_encode($storedAnswers));



        if ($this->isLastQuestion()) {
            // Send answers to server and redirect to exam result page
            $this->sendAnswersToServer();
            $session->forget('answers');
            // exam-result
            // return redirect()->route('types');
        }

        $this->goToNextQuestionIfPossible();
    }

    public function sendAnswersToServer()
    {
        // جلب عدد المحاولات المتبقية للامتحان الخاصة بالطالب
        $examPivot = $this->user->exams()->where('exam_id', $this->exam->id)->first()->pivot;
        $attempts = $examPivot->number_of_submission;
        if ($attempts > 0) {
            $attempts = $attempts - 1;
        }
        // Save the user's answers
        $answers = json_decode(request()->session()->get('answers', '{}'), true);
        $score = 0;
        $num_questions = count($answers);


        // اذا كانت الاجوبة اختيار من متعدد
        if ($num_questions > 0) {
            foreach ($answers as  $answerId) {
                // Get the question from the database
                $answer = Answer::find($answerId);

                // Check if the user's answer is correct
                if ($answer->is_correct == true) {
                    $score++;
                }
            }

            foreach ($answers as $question_id => $answer_key) {
                $answer = new UserAnswer();
                $answer->user_id = $this->user->id;
                $answer->question_id = $question_id;
                $answer->answer_id = $answer_key;
                $answer->save();
            }
        }

        // اذا كانت الاجوبة املئ الفراغ 
        if (count($this->fill_answers)) {
            $questionScore = 0;
            foreach ($this->fill_answers as $questionIndex => $fillAnswers) {
                $question = $this->questions[$questionIndex];

                foreach ($fillAnswers as $index => $answer) {
                    // Check if the answer is valid

                    $answer = strtolower(trim($answer));
                    foreach ($question->blanks as $validAnswer) {
                        // dd($validAnswer);
                        if (strtolower(trim($validAnswer['text'])) === $answer) {
                            // Add score for valid answer
                            $questionScore += 1 / count($question->blanks);
                        }
                    }
                }
            }
            $score += $questionScore;
        }



        // Update the exam_user pivot table
        $examPivot->update([
            'number_of_submission' => $attempts,
        ]);

        $this->user->exams()->updateExistingPivot($this->exam->id, [
            'score' => $score,
            'closed' => ($attempts == 0),
        ]);

        return redirect()->route('exam.result', $this->exam->id);
    }


    public function preAnswer()
    {
        $this->goToPreviousQuestionIfPossible();
    }



    public function isLastQuestion(): bool
    {
        return $this->currentQuestionIndex === $this->questions->count() - 1;
    }

    public function goToNextQuestionIfPossible()
    {
        if ($this->canGoToNextQuestion()) {
            
            $this->currentQuestionIndex++;
            $this->audioSource = asset('audio/' . $this->questions[$this->currentQuestionIndex]->question_text);
        }
    }

    public function goToPreviousQuestionIfPossible()
    {
        if ($this->canGoToPreviousQuestion()) {
            $this->currentQuestionIndex--;
        }
    }

    public function canGoToNextQuestion(): bool
    {
        
        return $this->currentQuestionIndex < $this->questions->count() - 1;
    }

    public function canGoToPreviousQuestion(): bool
    {
        return $this->currentQuestionIndex > 0;
    }
    // update time every secend 
    public function updatePivotTable($remainingTime)
    {
        $this->user->exams()->updateExistingPivot($this->exam->id, ['time_of_exam' => $this->remainingTime]);
    }



    public function render()
    {

        $answers = json_decode(request()->session()->get('answers', '{}'), true);
        return view('livewire.questions', [
            'currentAnswers' => $answers ?? null,
        ]);
        
    }
}

شكرا لكم واتمنى ان تقدموا لي نصائح  بشان تحسين الشفره او عن اي اخطاء موجوده فيها او ملاحظات 

تم التعديل في بواسطة Mustafa Suleiman
تنسيق النص

Recommended Posts

  • 0
نشر

السلام عليكم،

أود أن أشكر جميع المدربين في أكاديمية حسوب على محاولتهم في مساعدتي حل مشكلتي التي واجهتني في صفحة الاختبارات. كانت المشكلة تتمثل في عدم تحديث الصوت عند الانتقال من سؤال لآخر في اختبار الاستماع، وكنت أشتبه بأن المشكلة تكمن في ذاكرة التخزين المؤقت (Cache).

بعد البحث والتجربة، توصلت إلى الحل عن طريق استخدام خاصية emit() في Livewire. هذه الخاصية تسمح بإرسال بيانات من component إلى مكون آخر في الصفحة. في حالتي، قمت بإصدار emit() في component الخاص بالاختبارات لإرسال بيانات الصوت الجديدة إلى مكون audio element الموجود في صفحة الاختبارات.

وبعد إعداد الكود وتمرير الصوت باستخدام الأحداث ، تم حل مشكلة تحديث الصوت في اختبار الاستماع في صفحة الاختبارات بنجاح.

اليكم الكود النهائي للحل:
 

$this->emit('questionChanged', ['currentQuestionIndex' => $this->currentQuestionIndex]);
                document.addEventListener('livewire:load', function() {
                    Livewire.on('updated', (data) => {
            
                        // Get the current question index from the data
                        var currentQuestionIndex = data.currentQuestionIndex;
            
                        // Get the audio element
                        var audioElement = document.getElementById('question-audio');
            
                        // Update the audio source
                        var audioSource = '{{ asset('audio/') }}/' + data.question.question_text + '?v=' + data.question.updated_at.timestamp;
                        audioElement.src = audioSource;
            
                        // Play the audio
                        audioElement.play();
                    });
                });

أتمنى أن يساعد هذا الحل من يواجهون مشكلة مماثلة. شكراً لكم جميعاً على المحاولة في المساعدة.

  • 0
نشر

وعليكم السلام،

من الواضح من الشيفرة التي قدمتها أنه يتم استخدام Cache Busting technique في الرابط الذي يحمل ملف الصوت، ولكن هذا لن يحل المشكلة بشكل كامل في حال كان لديك أكثر من سؤال يحتوي على ملف صوتي. يمكن حل هذه المشكلة بتغيير رابط ملف الصوت في كل مرة تنتقل فيها إلى سؤال جديد باستخدام JavaScript.

في الصفحة التي تحتوي على الاختبار، يمكنك إضافة JavaScript الذي يقوم بتغيير رابط ملف الصوت عند التبديل بين الأسئلة. يمكنك القيام بذلك عن طريق إضافة معرف فريد لعنصر الصوت وتحديث الخاصية src في كل مرة تنتقل فيها إلى سؤال جديد. يمكنك القيام بذلك باستخدام الشيفرة التالية:

// إنشاء متغير جديد للإشارة إلى عنصر الصوت
var audioElement = document.getElementById('question-audio');

// إنشاء دالة لتحديث مصدر الصوت في كل مرة تتغير فيها الأسئلة
function updateAudioSource() {
    // إستخراج رابط ملف الصوت الجديد من الأسئلة الحالية
    var audioSource = '{{ asset('audio/'.$questions[$currentQuestionIndex]->question_text) }}?v={{ $questions[$currentQuestionIndex]->updated_at->timestamp }}';

    // تحديث خاصية src في عنصر الصوت
    audioElement.src = audioSource;

    // تشغيل الصوت
    audioElement.play();
}

// استدعاء دالة updateAudioSource في كل مرة يتم فيها التبديل بين الأسئلة
updateAudioSource();

يمكنك وضع هذا الكود في ملف JavaScript منفصل وتضمينه في صفحة الاختبار. يجب تحديث قيمة $currentQuestionIndex عندما يتم التبديل بين الأسئلة في متحكم Laravel Livewire الخاص بك.

اذا استمرت المشكلة فيرجي مشاركة ملفات المشروع حتي يمكننا مساعدتك.

  • 0
نشر

يتم تحديث الملف الصوتي فقط عند الذهاب اما عند الايام والتنقل رجوعا الى السؤال السابق يظل نفس المقطع الصوتي 
سأشارك معك كل الصفحات  المسؤولة عن هذا الجزء من الموقع 
\project\app\Http\Livewire 1   Questions.php
\project\resources\views\livewire 2    questions.blade.php
 شكرا لكم

  • 0
نشر
بتاريخ 1 دقيقة مضت قال ابراهيم الخليل سماني:

يتم تحديث الملف الصوتي فقط عند الذهاب اما عند الايام والتنقل رجوعا الى السؤال السابق يظل نفس المقطع الصوتي 
سأشارك معك كل الصفحات  المسؤولة عن هذا الجزء من الموقع 
\project\app\Http\Livewire 1   Questions.php
\project\resources\views\livewire 2    questions.blade.php
 شكرا لكم

لحل هذه المشكلة، يمكنك استخدام نفس المنهجية التي استخدمتها للتحديث عند الانتقال إلى سؤال جديد، ولكن عليك القيام بذلك في الاتجاه المعاكس أيضًا (عند الرجوع إلى سؤال سابق). يمكنك تحقيق ذلك باستخدام نفس الكود JavaScript السابق، ولكن يجب أن تستخدم متغيرًا لتخزين رابط الملف الصوتي الحالي وتحديثه أيضًا في كل مرة تتغير فيها الأسئلة.

يمكنك استخدام مثل هذا الكود في متحكم Laravel Livewire الخاص بك:

// في متغير Livewire
protected $currentQuestionIndex = 0;
protected $currentAudioSource;

public function render()
{
$questions = Question::all();
// استخراج رابط ملف الصوت الحالي من الأسئلة الحالية
$this->currentAudioSource = asset('audio/'.$questions[$this->currentQuestionIndex]->question_text) . '?v=' . $questions[$this->currentQuestionIndex]->updated_at->timestamp;

return view('livewire.quiz', [
    'questions' => $questions,
]);
}

// دالة تحديث الملف الصوتي للأمام
public function updateAudioForward()
{
$this->currentQuestionIndex++;
// استخراج رابط ملف الصوت الجديد من الأسئلة الجديدة
$this->currentAudioSource = asset('audio/'.$this->questions[$this->currentQuestionIndex]->question_text) . '?v=' . $this->questions[$this->currentQuestionIndex]->updated_at->timestamp;

$this->emit('updateAudio');
}

// دالة تحديث الملف الصوتي للخلف
public function updateAudioBackward()
{
$this->currentQuestionIndex--;
// استخراج رابط ملف الصوت الجديد من الأسئلة الجديدة
$this->currentAudioSource = asset('audio/'.$this->questions[$this->currentQuestionIndex]->question_text) . '?v=' . $this->questions[$this->currentQuestionIndex]->updated_at->timestamp;

$this->emit('updateAudio');
}

ويمكنك استخدام الكود السابق في ملف JavaScript منفصل، وتضمينه في صفحة الاختبار. يمكنك ثم استخدام الشيفرة التالية للاستماع إلى حدث updateAudio وتحديث مصدر الصوت على الصفحة:

// استدعاء دالة updateAudioSource عند استقبال حدث update

  • 0
نشر

شكرا لك أخ مصطفى على مداخلتك, لكن يبدوا أنك لم تطلع بشكل جيد على المتحكم Question.php يوجد فيه كل الدوال الخاصة بالتنقل بين الأسئلة واما المنهجية التي إستخدمتها لتغيير الملف الصوتي عند الإنتقال للسؤال التالي لم اقصد بها ذلك و إنما وضعت جزء الجافاسكريبت في ملف العرض question.blade.php الخاص بlivewire ومن المفروض يتم تنفيذه كل ما تغيير السؤال لا ادري لماذا يتم تنفيذه فقط عند تحديث السؤال نحو الأمام 
 

<div>
  ...
  ...
  ...
              @elseif($questions[$currentQuestionIndex]->type == 'record_voice')
                <audio id="question-audio" controls>
                    <source
                        src="{{ asset('audio/' . $questions[$currentQuestionIndex]->question_text) }}?v={{ $questions[$currentQuestionIndex]->updated_at->timestamp }}"
                        type="audio/mpeg">
                    Your browser does not support the audio element.
                </audio>



            @endif


            {{-- Navigation buttons --}}
            <div class="inline-flex justify-around mt-6 w-full">
                <button wire:click="preAnswer()"
                    class="bg-orange-500 hover:bg-orange-400 text-white font-bold py-2 px-4 rounded-l">
                    <span class="material-symbols-outlined">Undo Prev</span>
                </button>

                @if ($questions->count() == $currentQuestionIndex + 1)
                    <button wire:click="submitAnswer()"
                        class="bg-orange-500 hover:bg-orange-400 text-white font-bold py-2 px-4 rounded-r">
                        Finish Exam
                    </button>
                @else
                    <button wire:click="goToNextQuestionIfPossible()"
                        class="bg-orange-500 hover:bg-orange-400 text-white font-bold py-2 px-4 rounded-r">
                        <span class="material-symbols-outlined">Redo Next</span>
                    </button>
                @endif
            </div>


            <script>
                // إنشاء متغير جديد للإشارة إلى عنصر الصوت
                var audioElement = document.getElementById('question-audio');

                // إنشاء دالة لتحديث مصدر الصوت في كل مرة تتغير فيها الأسئلة
                function updateAudioSource() {
                    // إستخراج رابط ملف الصوت الجديد من الأسئلة الحالية
                    var audioSource =
                        '{{ asset('audio/' . $questions[$currentQuestionIndex]->question_text) }}?v={{ $questions[$currentQuestionIndex]->updated_at->timestamp }}';

                    // تحديث خاصية src في عنصر الصوت
                    audioElement.src = audioSource;

                    // تشغيل الصوت
                    audioElement.play();
                }

                // استدعاء دالة updateAudioSource في كل مرة يتم فيها التبديل بين الأسئلة
                updateAudioSource();

                // استماع لحدث تغيير رقم السؤال واستدعاء الدالة المناسبة
                // Livewire.on('updated', function() {
                //     updateAudioSource();
                // });
            </script>



        </div>
    </div>
</div>

 

  • 0
نشر

شكرا للتوضيح،  يمكنك تخزين رقم السؤال الحالي وتاريخ آخر تحديث للسؤال الحالي في ذاكرة التخزين المؤقت للمتصفح (Browser's Local Storage) باستخدام JavaScript. ثم يمكن استرداد هذه القيم من ذاكرة التخزين المؤقت وتحديث رابط ملف الصوت عند تحميل الصفحة. يمكنك القيام بذلك باستخدام الشيفرة التالية:

// إنشاء متغير جديد للإشارة إلى عنصر الصوت
const audioElement = document.getElementById('question-audio');

// إنشاء متغير جديد لتخزين رقم السؤال الحالي
const currentQuestionIndex = localStorage.getItem('currentQuestionIndex') || 0;

// إنشاء متغير جديد لتخزين تاريخ آخر تحديث للسؤال الحالي
const currentQuestionUpdatedAt = localStorage.getItem('currentQuestionUpdatedAt') || 0;

// إستخراج رابط ملف الصوت الجديد من الأسئلة الحالية والقيم المخزنة في ذاكرة التخزين المؤقت
const audioSource = '{{ asset('audio/'.$questions[$currentQuestionIndex]->question_text) }}?v={{ $questions[$currentQuestionIndex]->updated_at->timestamp }}';
if (currentQuestionIndex == {{ $currentQuestionIndex }} && currentQuestionUpdatedAt == '{{ $questions[$currentQuestionIndex]->updated_at }}') {
audioSource = localStorage.getItem('currentAudioSource');
} else {
localStorage.setItem('currentQuestionIndex', {{ $currentQuestionIndex }});
localStorage.setItem('currentQuestionUpdatedAt', '{{ $questions[$currentQuestionIndex]->updated_at }}');
localStorage.setItem('currentAudioSource', audioSource);
}

// تحديث خاصية src في عنصر الصوت
audioElement.src = audioSource;

// تشغيل الصوت
audioElement.play();

يمكنك وضع هذا الكود في ملف JavaScript منفصل وتضمينه في صفحة الاختبار. يتم تحديث قيمة $currentQuestionIndex عندما يتم التبديل بين الأسئلة في متحكم Laravel Livewire الخاص بك. ويتم استخدام localStorage لتخزين القيم الحالية للسؤال وتاريخ آخر تحديث للسؤال الحالي ورابط الملف الصوتي الحالي. أيضًا يتم استخدام هذه القيم لتحديث رابط الملف الصوتي الحالي.

وتستخدم هذه القيم لتحديث رابط الملف الصوتي في حالة العودة إلى السؤال السابق والتالي. ويمكن تحسين هذا الحل بتحميل جميع الملفات الصوتية في الصفحة الأولى وتبديلها باستخدام JavaScript عوضًا عن تحميل كل ملف صوتي منفردًا. ومع ذلك ، فإن الحل الحالي يبدو كافيًا لحل المشكلة المذكورة.

  • 0
نشر

السلام عليكم , 
اتعبتكم معي المعذرة رجاءا للأسف لم تحل المشكلة بعد’
المشكلة على ما أعتقد سببها أنه لا يتم تنفيد شيفرة جافاسكريبت إلا مرة واحدة فقط لأنه لا يتم تحديث صفحة  عرض <<Livewire>> 

فيديو صغير يوضح المشكلة

 

 


 

  • 0
نشر

السلام عليكم , 
لم أجد أي حل لتخزين الكاش هذه لهذا قررت أستخدم هذه الطريقة مؤقتا ... ولمن لديه أي حل أرجو ان يساعدني فيه وشكرا لكم 

            @elseif($questions[$currentQuestionIndex]->type == 'record_voice')
            {{-- قمت بهذا لأتخلص من مشكلة تخزين الكاش بحيث كان يتغيير الرابط ولا يتغيير الملف الصوتي --}}
                @foreach ($questions as $key => $question)
                @if ($question->type == 'record_voice'  )
             
                        <audio {{$key !== $currentQuestionIndex ? 'hidden' : ''}} --plyr-badge-background id="question-audio" controls>
                        <source
                            src="{{ asset('audio/' . $question->question_text) }}?v={{ $question->updated_at->timestamp }}"
                            type="audio/mpeg">
                        Your browser does not support the audio element.
                    </audio> 
                @endif
               
                @endforeach

            @endif

 

انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أجب على هذا السؤال...

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.

  • إعلانات

  • تابعنا على



×
×
  • أضف...