見出し画像

AIと生きる~Cursorでアプリ開発 #12~

開発の続き

前回、新規登録ページを追加して、知識が増えたので他のページも修正してみると書きました。
結果、大幅に改良しました。
当初、「こういう挙動になってほしいな~」と考えていたことに近づけました。


indexページ

  • 「Bootstrap」

    • ナビゲーションバー ⇒ そのまま

    • 「Card」 ⇒ 「Accordion-flush」

システム起動時の画面
「お客様情報とメンテナンス情報の両方を新規登録するのはこちら」をクリックした際の表示

顧客管理ページ

  • 新規登録 ⇒ 新規登録ページからのみ

  • 編集・更新のみ実行する仕様に変更

顧客管理のTOPページで顧客検索を行う
検索すると、検索文字で登録されている顧客情報を一覧表示
一覧表示された顧客から編集したい顧客の行をクリックして選択する
一覧表示から選択したら顧客フォームに表示する
この画面で編集し、更新ボタンで該当レコードを更新する

FHメンテナンス管理ページ

今アプリのメインとなるページになります。

  • 顧客情報とメンテナンス情報を同時に新規登録する場合 ⇒ 新規登録ページから実行

  • 既存顧客に新規メンテナンス情報を登録する場合 ⇒ 【新規登録】ボタンをクリック

  • 登録されているメンテナンス情報に変更があった場合 ⇒ 【既存メンテナンス情報の更新】ボタンをクリック

FHメンテナンス管理とTOPページ
「新規登録」か「既存メンテナンス情報の更新」を選択する
  • FHメンテナンス管理/新規登録

顧客検索をする
顧客検索結果の一覧表示
メンテナンス情報を登録したい顧客を選択する
顧客選択後の表示
選択された顧客情報を顧客フォームに表示(左側)
メンテナンスフォームを表示(右側)し入力と新規登録をする
新規登録ボタンがクリックされたら、結果に応じてアラートメッセージを表示する
  • FHメンテナンス管理/既存メンテナンス情報の更新

顧客検索するか、
登録されているメンテナンス情報一覧から編集・更新したいものを選択する
顧客検索をした際の表示
編集・更新したい顧客を選択する
顧客検索⇒一覧表示⇒顧客選択後の表示
顧客情報に紐づくメンテナンス情報が一覧表示される
この中から編集・更新するものを選択
編集・更新したいメンテナンス情報を選択後の表示
この画面で編集・更新を実行する
更新ボタンがクリックされた後、結果に応じてアラートメッセージを表示する

従業員管理ページ

  • 従業員の新規登録

  • 登録されている従業員一覧から、削除する従業員を選択して削除する

従業員管理TOP
従業員一覧から削除する従業員を選択した際にアラート表示する
削除をOKにすると、表示されるアラート
メンテナンス情報に登録されている従業員の削除はできない

今回のまとめ

  • pythonとhtmlに関しては、エラーがあっても、自力で修正できる

  • Script部分で、勝手にハマったと勘違いしていた

    • JavaScriptの知識が浅いまま開発を行ったので、「Cursor」が出力したコードの確認に手間取った

  • 「Fkask」公式ドキュメントを一読したあとは、エラーや処理実行への対処が早くなった

現在もJavaScriptを理解しているわけではありませんが、それでも、生成AIにサポートしてもらいながら、ここまで修正することができました。
今回のアプリ開発で、今後の開発にいい経験を積むことができました。
「Cursor」でのアプリ開発は、これで完了しました。
今回の開発は、色々な気付きと自身の成長を感じられる、有意義な時間でした。

手こずったscriptコード

メインページとなる、メンテナンス管理ページのscript部分は下記のように作成しました。
他のページは、このページから流用しているので、今回作成したJavaScriptコードがすべて含まれています。
これも、CursorのAI機能に指示(プロンプト)を伝えて作成してもらいました。

<script>
        // 新規登録ボタンがクリックされたときの処理
        $('#newRegistrationBtn').on('click', function() {
            // 顧客検索ボックス表示
            $('#searchCustomerBox').show();
            // newRegistrationBtnとupdateMaintenanceBtnを消す
            $('#newRegistrationBtn').hide();
            $('#updateMaintenanceBtn').hide();
        

            // 顧客検索ボタンがクリックされたときの処理
            $('#searchCustomerBtn').on('click', function() {
                // maintenanceTableテーブルを非表示にする
                $('#maintenanceTable').hide();
                var customerName = $('#customerName').val();
                // 顧客名で顧客を検索するためのAJAX呼び出し
                $.ajax({
                    url: '/search_customer',
                    type: 'POST', // FlaskエンドポイントがPOSTを受け付けるため
                    dataType: 'json', // JSON形式の応答を期待
                    data: { 'name': customerName }, // フォームデータとして顧客名を送信
                    success: function(response) {
                        if (response.error) {
                            alert('該当するお客様はおられません。新規登録ページから新規登録してください');
                            window.location.href = "registration";
                        } else {
                            // テーブルの内容をクリア
                            $('#searchResultsTable tbody').empty();
                            $('#searchResultsTable').show();
                            // JSONデータをテーブルに変換して表示
                            $.each(response.customers, function(index, customer) {
                                $('<tr>').data('id', customer.id).append( // 顧客IDをdata-id属性として追加
                                    $('<td>').text(customer.id),
                                    $('<td>').text(customer.name),
                                    $('<td>').text(customer.address),
                                    $('<td>').text(customer.telephone),
                                    $('<td>').text(customer.usage_number),
                                    // 他に表示したい列があればここに追加
                                ).appendTo('#searchResultsTable tbody');
                            });
                        }
                    }
                });
            });

            // 顧客検索結果テーブルの行をクリックしたときのイベント
            $('#searchResultsTable').on('click', 'tbody tr', function() {
                // 顧客検索結果テーブルを非表示にする
                $('#searchResultsTable').hide();
                // 検索ボックスを非表示にする
                $('#searchCustomerBox').hide();
                // customerFormを表示する
                $('#customerForm').show();
                $('#customer_id4').show();
                $('#customer_id5').hide();

                // maintenanceFormを表示する
                $('#maintenanceForm').show();
                // newbtnを表示する
                $('#new').show();

                // 選択された行の全カラムを取得して表示する
                var customerValues = $(this).children('td').map(function() {
                    return $(this).text();
                }).get();
                // 顧客フォームの該当箇所に表示する
                $('#customer_id2').prop('readonly', true).val(customerValues[0]);
                $('#customer_name').prop('readonly', true).val(customerValues[1]);
                $('#customer_address').prop('readonly', true).val(customerValues[2]);
                $('#customer_telephone').prop('readonly', true).val(customerValues[3]);
                $('#customer_usage_number').prop('readonly', true).val(customerValues[4]);
                // メンテナンスフォームの該当箇所に表示する
                $('#customer_id').prop('readonly', true).val(customerValues[0]);
            });
        });

        // 入力フォームに入力中にエンターキーが押された場合、入力情報を保持してそのままページに留まる
        $(document).on('keypress', 'input', function(e) {
        if (e.keyCode == 13) {
            e.preventDefault();
            return false;
        }
        });
        // 預り日数が変更されたときに、受付日に預り日数を加算して返却予定日を自動計算し、表示する
        $('#number_of_days_deposited').on('change', function() {
            var dateOfReceipt = new Date($('#date_of_receipt').val());
            var numberOfDaysDeposited = parseInt($('#number_of_days_deposited').val());
            if (!isNaN(dateOfReceipt.getTime()) && !isNaN(numberOfDaysDeposited)) {
                var returnDate = new Date(dateOfReceipt.getTime() + numberOfDaysDeposited * 24 * 60 * 60 * 1000);
                var formattedReturnDate = returnDate.getFullYear() + '-' + (returnDate.getMonth() + 1).toString().padStart(2, '0') + '-' + returnDate.getDate().toString().padStart(2, '0');
                $('#scheduled_return_date').val(formattedReturnDate);
            }
        });


        // 更新ボタンがクリックされたときの処理
        $('#updateMaintenanceBtn').on('click', function() {
            // 新規顧客とメンテナンス登録用のフォームを表示
            $('#searchCustomerBox').show();
            $('#maintenanceTable').show();            
            // newRegistrationBtnとupdateMaintenanceBtnを消す
            $('#newRegistrationBtn').hide();
            $('#updateMaintenanceBtn').hide();
        

            // 顧客検索ボタンがクリックされたときの処理
            $('#searchCustomerBtn').on('click', function() {
                // 顧客検索結果テーブルを非表示にする
                $('#searchResultsTable').hide();
                // 検索ボックスを非表示にする
                $('#searchCustomerBox').hide();
                $('#maintenanceTable').hide(); 

                var customerName = $('#customerName').val();
                // 顧客名で顧客を検索するためのAJAX呼び出し
                $.ajax({
                    url: '/search_customer',
                    type: 'POST', // FlaskエンドポイントがPOSTを受け付けるため
                    dataType: 'json', // JSON形式の応答を期待
                    data: { 'name': customerName }, // フォームデータとして顧客名を送信
                    success: function(response) {
                        if (response.error) {
                            $('#error-message').text('該当するお客様はおられません。顧客管理画面から新規登録してください');
                            $('#error-message').show();
                        } else {
                            // テーブルの内容をクリア
                            $('#searchResultsTable tbody').empty();
                            $('#searchResultsTable').show();
                            // JSONデータをテーブルに変換して表示
                            $.each(response.customers, function(index, customer) {
                                $('<tr>').data('id', customer.id).append( // 顧客IDをdata-id属性として追加
                                    $('<td>').text(customer.id),
                                    $('<td>').text(customer.name),
                                    $('<td>').text(customer.address),
                                    $('<td>').text(customer.telephone),
                                    $('<td>').text(customer.usage_number),
                                    // 他に表示したい列があればここに追加
                                ).appendTo('#searchResultsTable tbody');
                            });
                        }
                    }
                });
            });

            // 顧客検索結果テーブルの行をクリックしたときのイベント
            $('#searchResultsTable').on('click', 'tbody tr', function() {
                // テーブルを非表示にする
                $('#searchResultsTable').hide();
                // 検索ボックスを非表示にする
                $('#searchCustomerBox').hide();
                // customerFormを表示する
                $('#customerForm').show();
                $('#customer_id5').show();
                // 選択された行の全カラムを取得して表示する
                var customerValues = $(this).children('td').map(function() {
                    return $(this).text();
                }).get();
                // 顧客フォームの該当箇所に表示する
                $('#customer_id3').prop('readonly', true).val(customerValues[0]);
                $('#customer_name').prop('readonly', true).val(customerValues[1]);
                $('#customer_address').prop('readonly', true).val(customerValues[2]);
                $('#customer_telephone').prop('readonly', true).val(customerValues[3]);
                $('#customer_usage_number').prop('readonly', true).val(customerValues[4]);
                                
                // 顧客IDに紐づくメンテナンス情報を取得してテーブルに一覧表示する処理を追加する
                var customerId2 = customerValues[0];
                $.ajax({
                    url: '/search_maintenance',
                    type: 'POST',
                    data: { 'customer_id3': customerId2 },
                    success: function(response) {
                        if (response.error) {
                            $('#error-message2').text('該当するメンテナンス情報はありません。メンテナンス情報を新規登録してください');
                            $('#error-message2').show();
                        } else {
                            // テーブルの内容をクリア
                            $('#searchResultsTable2 tbody').empty();
                            $('#searchResultsTable2').show();
                            // JSONデータをテーブルに変換して表示
                            $.each(response.maintenances, function(index, maintenance) {
                                $('<tr>').data('id', maintenance.id).append( // メンテナンスIDをdata-id属性として追加
                                    $('<td>').text(maintenance.id),
                                    $('<td>').text(maintenance.customer_id),
                                    $('<td>').text(new Date(maintenance.date_of_receipt).toISOString().split('T')[0]),
                                    $('<td>').text(maintenance.recipient_id),
                                    $('<td>').text(maintenance.model_number),
                                    $('<td>').text(maintenance.maintenance_person_id),
                                    $('<td>').text(maintenance.paid_free),
                                    $('<td>').text(maintenance.number_of_days_deposited),
                                    $('<td>').text(new Date(maintenance.scheduled_return_date).toISOString().split('T')[0]),
                                    $('<td>').text(maintenance.return_processing_date ? new Date(maintenance.return_processing_date).toISOString().split('T')[0] : ''),
                                    $('<td>').text(maintenance.returned_unreturned),
                                    $('<td>').text(maintenance.remarks),
                                    // 他に表示したい列があればここに追加
                                ).appendTo('#searchResultsTable2 tbody');
                            });
                        }
                    }
                });

            });

            // メンテナンス検索結果テーブルの行をクリックしたときのイベント
            $('#searchResultsTable2').on('click', 'tbody tr', function() {
                // テーブルを非表示にする
                $('#searchResultsTable2').hide();
                // 検索ボックスを非表示にする
                $('#searchCustomerBox').hide();
                // customerFormを表示する
                $('#maintenanceForm').show();
                $('#maintenance_id2').show();
                $('#up').show();
                // 選択された行の全カラムを取得して表示する
                var maintenanceValues = $(this).children('td').map(function() {
                    return $(this).text();
                }).get();
                console.log(maintenanceValues);
                // メンテナンスフォームの該当箇所に表示する
                $('#maintenance_id').prop('readonly', true).val(maintenanceValues[0]);
                $('#customer_id').prop('readonly', true).val(maintenanceValues[1]);
                $('#date_of_receipt').prop('readonly', true).val(maintenanceValues[2]);
                $('#recipient_id').val(maintenanceValues[3]);
                $('#model_number').val(maintenanceValues[4]);
                $('#maintenance_person_id').val(maintenanceValues[5]);
                if (maintenanceValues[6] == '有償') {
                    $('#paid_free1').prop('checked', true);
                } else if (maintenanceValues[6] == '無償') {
                    $('#paid_free2').prop('checked', true);
                }
                $('#number_of_days_deposited').val(maintenanceValues[7]);
                $('#scheduled_return_date').val(maintenanceValues[8]);
                $('#return_processing_date').val(maintenanceValues[9]);
                if (maintenanceValues[10] == '返却済') {
                    $('#returned_unreturned1').prop('checked', true);
                } else if (maintenanceValues[10] == '未返却') {
                    $('#returned_unreturned2').prop('checked', true);
                }
            });
        });

        $('#new').click(function() {
            document.getElementById('maintenanceForm').addEventListener('submit', function(event) {
                event.preventDefault();
                let maintenancedata = new FormData(this);
                fetch('{{ url_for("register_maintenance") }}', {
                    method: 'POST',
                    body: maintenancedata,
                })
                .then(response => response.json())
                .then(maintenancedata => {
                    switch(maintenancedata.message) {
                        case '登録が完了しました':
                            $('#maintenanceForm').hide();
                            alert('メンテナンス情報の新規登録が完了しました。');
                            window.location.href = "/";
                            break;
                        case 'データベースエラーが発生しました。登録に失敗しました。':
                            alert('データベースエラーが発生しました。メンテナンス管理ページからメンテナンス情報を登録してください');
                            window.location.href = "maintenance_management";
                            break;
                        case 'フォームのバリデーションに失敗しました':
                            alert('入力内容に誤りがあります。メンテナンス管理ページからメンテナンス情報を登録してください');
                            window.location.href = "maintenance_management";
                            break;
                        default:
                            alert('未知のメッセージ: ' + data.message);
                    }
                });
            });
        });

        $('#up').click(function() {
            document.getElementById('maintenanceForm').addEventListener('submit', function(event) {
                    event.preventDefault();
                    let maintenancedata = new FormData(this);
                    fetch('{{ url_for("update_maintenance") }}', {
                        method: 'POST',
                        body: maintenancedata,
                    })
                    .then(response => response.json())
                    .then(maintenancedata => {
                        switch(maintenancedata.message) {
                            case '登録が完了しました':
                                $('#maintenanceForm2').hide();
                                alert('メンテナンス情報の更新が完了しました。');
                                window.location.href = "/";
                                break;
                            case 'データベースエラーが発生しました。登録に失敗しました。':
                                alert('データベースエラーが発生しました。メンテナンス管理ページからメンテナンス情報を登録しなおしてください');
                                window.location.href = "maintenance_management";
                                break;
                            case 'フォームのバリデーションに失敗しました':
                                alert('入力内容に誤りがあります。メンテナンス管理ページからメンテナンス情報を登録しなおしてください');
                                window.location.href = "maintenance_management";
                                break;
                            default:
                                alert('未知のメッセージ: ' + data.message);
                        }
                    });
            });
        });

        // 全メンテナンス情報テーブルの行をクリックしたときのイベント
        $('#maintenanceTable').on('click', 'tbody tr', function() {
                // テーブルを非表示にする
                $('#maintenanceTable').hide();
                // 検索ボックスを非表示にする
                $('#searchCustomerBox').hide();
                // customerFormを表示する
                $('#customerForm').show();
                $('#customer_id4').show();
                // maintenanceForm2を表示する
                $('#maintenanceForm').show();
                $('#up').show();
                
                // 選択された行の全カラムを取得して表示する
                var maintenanceValues = $(this).children('td').map(function() {
                    return $(this).text();
                }).get();
                console.log(maintenanceValues);
                // 顧客フォームの該当箇所に表示する
                $('#customer_id2').prop('readonly', true).val(maintenanceValues[1]);
                $('#customer_name').prop('readonly', true).val(maintenanceValues[2]);
                $('#customer_address').prop('readonly', true).val(maintenanceValues[3]);
                $('#customer_telephone').prop('readonly', true).val(maintenanceValues[4]);
                $('#customer_usage_number').prop('readonly', true).val(maintenanceValues[5]);
                // メンテナンスフォームの該当箇所に表示する
                $('#maintenance_id').prop('readonly', true).val(maintenanceValues[0]);
                $('#customer_id').prop('readonly', true).val(maintenanceValues[1]);
                $('#date_of_receipt').prop('readonly', true).val(maintenanceValues[6]);
                $('#recipient_id').val(maintenanceValues[7]);
                $('#model_number').val(maintenanceValues[9]);
                $('#maintenance_person_id').val(maintenanceValues[10]);
                if (maintenanceValues[12] == '有償') {
                    $('#paid_free1').prop('checked', true);
                } else if (maintenanceValues[12] == '無償') {
                    $('#paid_free2').prop('checked', true);
                }
                $('#number_of_days_deposited').val(maintenanceValues[13]);
                $('#scheduled_return_date').val(maintenanceValues[14]);
                $('#return_processing_date').val(maintenanceValues[15]);
                if (maintenanceValues[16] == '返却済') {
                    $('#returned_unreturned1').prop('checked', true);
                } else if (maintenanceValues[16] == '未返却') {
                    $('#returned_unreturned2').prop('checked', true);
                }

            });
    </script>

今の体調

少しマシにはなってきたものの、気候変動に影響されています。
作業を始めると、課題の過集中になってしまい、終了後の疲労感が大きくなってしまいます。

この記事が気に入ったらサポートをしてみませんか?