小さな管理機能を作ってみよう 第35話
初心者向け、PHPプログラム構築講座です。
初心者といっても、PHPの勉強を少し行い、LAMP環境が自分で構築でき、少しアプリケーションを作成しているレベルを対象とします。
まったくの初心者の場合は、わからない部分が出てくると思います。
できるだけ細かく説明は入れていきますが、説明がわからない場合は、PHPやMySQLの初心者講座をご覧ください。
対象のスキルレベル
- LAMP環境の構築
- PHP言語が読める
- HTML, CSS, Javascriptが少しわかる
- Bootstrapのドキュメントをみて、HTMLが書ける
- Ajax(非同期通信)を利用したことがある
- SESSIONを利用したことがある
構築環境
- Windows10
- XAMPP(PHP7.3.2, MariaDB 10.1.38)
小さな管理機能を作ってみようの巻 最終話
小さな管理機能をつくってみようの巻が最終回となります。
機能実装は前回で終了していますので、正しく実装していれば機能するはずです。
PHPに関しては抜粋ではなく、全ソースが載っている場所がありますが、HTMLはこれまで全ソースを載せていませんでした。
答え合わせもかねて、HTMLのみ全ソースを公開しようと思います。
ちゃんと実装されていて、挙動がおかしくないようでしたら、特に問題はありませんが、動かない又は挙動がおかしい方は、まずはこちらを参考にHTMLを修正してください。
login.html
login.html
<!doctype html> <html lang="ja" > <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="process"> <meta name="method"> <title>LOGIN | tech.pjin.jp</title> <!-- Bootstrap CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous"> <!-- Font Awesome CSS --> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous"> <!-- Animate.css CSS --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" /> <!-- Sawarabi Gothic --> <link href="https://fonts.googleapis.com/css?family=Sawarabi+Gothic" rel="stylesheet"> <link rel="stylesheet" href="assets/css/style.css" /> </head> <body class="text-center login"> <main class="form-signin shadow bg-white rounded needs-validation" novalidate> <form> <h1 class="mb-5"><i class="fas fa-paste"></i> BACK<span class="bland-red">OFFICE</span></h1> <div class="error"></div> <div class="form-floating"> <input type="email" id="mail" name="mail" class="form-control" placeholder="メールアドレス" required="" autofocus=""> <label for="mail">メールアドレス</label> </div> <div class="form-floating"> <input type="password" id="passwd" name="passwd" class="form-control" placeholder="パスワード" required=""> <label for="passwd">パスワード</label> </div> <div class="checkbox mb-3"> <label> <input type="checkbox" id="remember-me"> 記憶する </label> </div> <button class="w-100 btn btn-lg btn-success signin" type="submit"><i class="fas fa-sign-in-alt"></i> ログイン</button> <p class="mt-5 mb-3 text-muted">© 2021 SIE</p> </form> </main> <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script> <script src="assets/js/script.js"></script> <script> $(function(){ $process('Auth'); logout(); $('.signin').on('click', function(){ $method('login'); $xhr($('form:first'), function(json, status, xhr){ if($('#remember-me').is(':checked')){ localStorage.setItem('hash', $('#mail').val()); } location.href = 'index.html'; }); return false; }); }); </script> </body> </html>
index.html
index.html
<!doctype html> <html lang="ja" > <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="process"> <meta name="method"> <title>DASHBOARD | tech.pjin.jp</title> <!-- Bootstrap CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous"> <!-- Font Awesome CSS --> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous"> <!-- Animate.css CSS --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" /> <!-- Sawarabi Gothic --> <link href="https://fonts.googleapis.com/css?family=Sawarabi+Gothic" rel="stylesheet"> <link rel="stylesheet" href="assets/css/style.css" /> <style> .contents { overflow: hidden; } .scale-in .card { position:relative; } .scale-in .card::before { position:absolute; top:0; left:0; display:block; box-sizing:border-box; border:3px solid #ccc; border-radius: .25rem; width:100%; height:100%; content:""; opacity:0; transform:scale(1.2); transition:transform 0.3s, opacity 0.3s; } .scale-in .card:hover::before { opacity:1; transform:scale(1); } </style> </head> <body> <section class="loading d-flex justify-content-center align-items-center bg-light"> <div class="spinner shadow rounded d-flex justify-content-center align-items-center"> <p class="h4 text-secondary"><i class="fas fa-spinner fa-spin"></i> Loading...</p> </div> </section> <header> <nav class="navbar navbar-expand-lg navbar-light shadow bg-white fixed-top"> <div class="container-fluid"> <a class="navbar-brand" href="index.html"><i class="fas fa-paste"></i> BACK<span class="bland-red">OFFICE</span></a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarNavDropdown"> <ul class="navbar-nav header-menu"> <li class="nav-item active"> <a class="nav-link active" href="index.html"><i class="fas fa-tachometer-alt"></i> DASHBOARD</a> </li> <li class="nav-item"> <a class="nav-link" href="users.html"><i class="fas fa-id-card-alt"></i> ユーザ管理</a> </li> <li class="nav-item"> <a class="nav-link" href="depts.html"><i class="far fa-building"></i> 部署管理</a> </li> </ul> <ul class="navbar-nav ms-auto me-3"> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle username" href="#" id="navbarDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false"> 管理者 </a> <ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> <li><a class="dropdown-item" href="login.html"><i class="fas fa-sign-out-alt"></i> ログアウト</a></li> </ul> </li> </ul> </div> </div> </nav> </header> <nav class="left-nav shadow d-none d-lg-block"> <div class="list-group list-group-flush"> <a href="index.html" class="list-group-item list-group-item-action active"><i class="fas fa-tachometer-alt"></i> DASHBOARD</a> <a href="users.html" class="list-group-item list-group-item-action"><i class="fas fa-id-card-alt"></i> ユーザ管理</a> <a href="depts.html" class="list-group-item list-group-item-action"><i class="far fa-building"></i> 部署管理</a> </div> </nav> <main class="contents"> <section class="container-fluid"> <header> <h1><i class="fas fa-tachometer-alt"></i> DASHBOARD</h1> </header> <div class="row"> <div class="col-lg mb-3 scale-in"> <div class="card shadow-sm"> <div class="card-body text-center"> <h3>ユーザ登録数</h3> <p class="display-3 userEntry">0</p> </div> </div> </div> <div class="col-lg mb-3 scale-in"> <div class="card shadow-sm"> <div class="card-body text-center"> <h3>部署登録数</h3> <p class="display-3 deptEntry">0</p> </div> </div> </div> </div> <div class="row"> <div class="col-lg mb-3"> <div class="card shadow-sm"> <div class="card-body"> <div id="users"></div> </div> </div> </div> <div class="col-lg mb-3"> <div class="card shadow-sm"> <div class="card-body"> <div id="depts"></div> </div> </div> </div> </div> </section> </main> <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/apexcharts"></script> <script src="assets/js/script.js"></script> <script> $(function(){ /* ログインチェック */ isSignin(); /* processはDashbord */ $process('Dashboard'); /* methodはDashboard.php#getUserEntry */ $method('getUsersEntry'); /* validationなしの非同期通信実行 */ $xhrNoValidate([], function(data, status, xhr){ /* 戻り値は、dataにjsonが入るため、list.rsをキーに取得します。 */ var rs = data.list.rs; /* カウントアップの要素、数、時間(ミリ秒)を渡して実行します。 */ countUp($('.userEntry'), rs.count, 2500); }); /* methodはDashboard.php#getDeptEntry */ $method('getDeptsEntry'); $xhrNoValidate([], function(data, status, xhr){ /* 戻り値は、dataにjsonが入るため、list.rsをキーに取得します。 */ var rs = data.list.rs; /* カウントアップの要素、数、時間(ミリ秒)を渡して実行します。 */ countUp($('.deptEntry'), rs.count, 2500); }); /* グラフの描画設定 */ var options = { series: [], noData: { /* データ取得中の表示文字 */ text: 'Loading...' }, chart: { height: 450, type: 'line', zoom: { enabled: false } }, dataLabels: { enabled: false }, stroke: { curve: 'straight' }, title: { text: 'ユーザ登録推移', align: 'left' }, grid: { row: { colors: ['#efefef', 'transparent'], opacity: 0.05 }, }, xaxis: { categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], } }; /* グラフを描画する要素を取得し、グラフを描画 */ var uchart = new ApexCharts(document.querySelector('#users'), options); uchart.render(); /* methodはDashboard.php#getUsersTransitionなので、getUsersTransitionを設定 */ $method('getUsersTransition'); /* 非同期通信を実行 */ $xhrNoValidate([], function(data, status, xhr){ /* データの配列はlist.rsに格納されている */ var rs = data.list.rs; /* updateSeriesを実行すると、そのままデータが反映され描画されます */ uchart.updateSeries([{ name: "ユーザ登録数", data: rs }]) }); /* グラフの描画設定 */ var options = { series: [], noData: { text: 'Loading...' }, chart: { height: 450, type: 'line', zoom: { enabled: false } }, dataLabels: { enabled: false }, stroke: { curve: 'straight' }, title: { text: '部署登録推移', align: 'left' }, grid: { row: { colors: ['#efefef', 'transparent'], // takes an array which will be repeated on columns opacity: 0.05 }, }, xaxis: { categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], } }; /* グラフを描画する要素を取得し、グラフを描画 */ var dchart = new ApexCharts(document.querySelector('#depts'), options); dchart.render(); /* methodはDashboard.php#getDeptsTransitionなので、getDeptsTransitionを設定 */ $method('getDeptsTransition'); /* 非同期通信を実行 */ $xhrNoValidate([], function(data, status, xhr){ /* データの配列はlist.rsに格納されている */ var rs = data.list.rs; /* updateSeriesを実行すると、そのままデータが反映され描画されます */ dchart.updateSeries([{ name: "部署登録数", data: rs }]) }); }); </script> </body> </html>
depts.html
depts.html
<!doctype html> <html lang="ja" > <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="process"> <meta name="method"> <title>部署管理 | tech.pjin.jp</title> <!-- Bootstrap CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous"> <!-- Font Awesome CSS --> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous"> <!-- Animate.css CSS --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" /> <!-- Sawarabi Gothic --> <link href="https://fonts.googleapis.com/css?family=Sawarabi+Gothic" rel="stylesheet"> <!-- DataTables 1.10.24 --> <link rel="stylesheet" href="https://cdn.datatables.net/1.10.24/css/dataTables.bootstrap4.min.css"> <link rel="stylesheet" href="https://cdn.datatables.net/buttons/1.7.0/css/buttons.bootstrap4.min.css"> <link rel="stylesheet" href="https://cdn.datatables.net/responsive/2.2.7/css/responsive.dataTables.min.css"> <link rel="stylesheet" href="https://cdn.datatables.net/responsive/2.2.7/css/responsive.bootstrap4.min.css"> <link rel="stylesheet" href="assets/css/style.css" /> </head> <body> <section class="loading d-flex justify-content-center align-items-center bg-light"> <div class="spinner shadow rounded d-flex justify-content-center align-items-center"> <p class="h4 text-secondary"><i class="fas fa-spinner fa-spin"></i> Loading...</p> </div> </section> <header> <nav class="navbar navbar-expand-lg navbar-light shadow bg-white fixed-top"> <div class="container-fluid"> <a class="navbar-brand" href="index.html"><i class="fas fa-paste"></i> BACK<span class="bland-red">OFFICE</span></a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarNavDropdown"> <ul class="navbar-nav header-menu"> <li class="nav-item active"> <a class="nav-link" href="index.html"><i class="fas fa-tachometer-alt"></i> DASHBOARD</a> </li> <li class="nav-item"> <a class="nav-link" href="users.html"><i class="fas fa-id-card-alt"></i> ユーザ管理</a> </li> <li class="nav-item"> <a class="nav-link active" href="depts.html"><i class="far fa-building"></i> 部署管理</a> </li> </ul> <ul class="navbar-nav ms-auto me-3"> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle username" href="#" id="navbarDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false"> 管理者 </a> <ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> <li><a class="dropdown-item" href="login.html"><i class="fas fa-sign-out-alt"></i> ログアウト</a></li> </ul> </li> </ul> </div> </div> </nav> </header> <nav class="left-nav shadow d-none d-lg-block"> <div class="list-group list-group-flush"> <a href="index.html" class="list-group-item list-group-item-action"><i class="fas fa-tachometer-alt"></i> DASHBOARD</a> <a href="users.html" class="list-group-item list-group-item-action"><i class="fas fa-id-card-alt"></i> ユーザ管理</a> <a href="depts.html" class="list-group-item list-group-item-action active"><i class="far fa-building"></i> 部署管理</a> </div> </nav> <main class="contents"> <section class="container-fluid"> <header> <h1><i class="far fa-building"></i> 部署管理</h1> </header> <div class="row"> <div class="col buttons"> </div> <div class="col d-flex justify-content-end"> <button class="btn btn-success"><i class="fas fa-plus-square"></i> 新規登録</button> </div> </div> <table id="depts" class="table dt-responsive nowrap" style="width:100%"> <thead> <tr> <th>#</th> <th>部署名</th> <th>電話番号</th> <th>操作</th> </tr> </thead> </table> </section> </main> <div class="modal fade" tabindex="-1" role="dialog" id="deleteModal"> <div class="modal-dialog modal-dialog-centered"> <div class="modal-content"> <div class="modal-header bg-danger text-white"> <h5 class="modal-title"><i class="fas fa-exclamation-triangle"></i> 削除確認</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <p>削除致します。よろしいでしょうか。</p> </div> <div class="modal-footer"> <button type="button" class="btn btn-danger act-exec-delete"><i class="far fa-trash-alt"></i> 削除</button> </div> </div> </div> </div> <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script> <!-- DataTables 1.10.24 --> <script src="https://cdn.datatables.net/1.10.24/js/jquery.dataTables.min.js"></script> <script src="https://cdn.datatables.net/1.10.24/js/dataTables.bootstrap4.min.js"></script> <script src="https://cdn.datatables.net/buttons/1.7.0/js/dataTables.buttons.min.js"></script> <script src="https://cdn.datatables.net/buttons/1.7.0/js/buttons.bootstrap4.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.3/jszip.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/pdfmake.min.js"></script> <script src="./assets/js/vfs_fonts.js"></script> <script src="https://cdn.datatables.net/buttons/1.7.0/js/buttons.html5.min.js"></script> <script src="https://cdn.datatables.net/responsive/2.2.7/js/dataTables.responsive.min.js"></script> <script src="https://cdn.datatables.net/responsive/2.2.7/js/responsive.bootstrap4.min.js"></script> <script src="assets/js/script.js"></script> <script> $(function(){ /* ログインチェック */ isSignin(); $process('Depts'); /* 新規作成 */ $('.btn-primary,.btn-success').on('click', function(){ location.href = 'deptsEdit.html'; }); /* 連携用ID削除 */ localStorage.removeItem('dept_id'); /* 削除実行 */ $('.act-exec-delete').on('click', function(e){ $method('delete'); $xhrNoValidate([{name: 'dept_id', value: $('.act-exec-delete').data('id')}], function(data, status, xhr){ location.href = 'depts.html'; }); return false; }); /* テーブル定義 */ var table = $('#depts').DataTable({ /* 非同期通信の設定 */ ajax: { url: './api/', type: 'POST', /* processとmethodを定義します */ data: {'process': 'Depts', 'method': 'list'}, /* 戻ってきたjsonの利用するキーを指定します */ dataSrc: 'list.rs' }, /* カラムの設定でボタンは特殊なので、別定義します */ columnDefs: [{ targets : 3, data: null, defaultContent: [ '<button class="btn btn-primary btn-sm me-3 act-update"><i class="fas fa-edit"></i> 編集</button>', '<button class="btn btn-outline-danger btn-sm act-delete" data-bs-toggle="modal" data-bs-target="#deleteModal"><i class="far fa-trash-alt"></i> 削除</button>' ].join('') }], /* 項目とjsonの名前を紐づけます */ columns: [ {data: "dept_id"}, {data: "name"}, {data: "tel"} ], /* B:Buttons, t:Table!, p:Pagination control */ dom: 'Btp', buttons: [ { extend: 'copy', text: '<i class="fas fa-clipboard"></i> Copy' }, { extend: 'csv', text: '<i class="fas fa-file-alt"></i> Csc' }, { extend: 'excel', text: '<i class="fas fa-file-excel"></i> Excel' }, { extend: 'pdfHtml5', text: '<i class="fas fa-file-pdf"></i> PDF', customize: function(doc){ doc.defaultStyle.font= 'GenShin'; } } ] }); table.buttons().container().appendTo('.buttons'); table.on('draw', function(){ /* 更新 */ $('.act-update').on('click', function(e){ var tr = $(this).closest('tr'); /* 編集画面へ渡す用のIDを、localStorageにセットします */ localStorage.setItem('dept_id', $('td:first', tr).text()); /* 編集画面へ遷移します */ location.href = 'deptsEdit.html'; }); /* 削除確認 */ $('.act-delete').on('click', function(e){ var tr = $(this).closest('tr'); /* 削除ボタン押下時に開くモーダルに削除用IDをセットします */ $('.act-exec-delete').data('id', $('td:first', tr).text()); }); }); }); </script> </body> </html>
deptsEdit.html
deptsEdit.html
<!doctype html> <html lang="ja" > <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="process"> <meta name="method"> <title>部署管理 | tech.pjin.jp</title> <!-- Bootstrap CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous"> <!-- Font Awesome CSS --> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous"> <!-- Animate.css CSS --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" /> <!-- Sawarabi Gothic --> <link href="https://fonts.googleapis.com/css?family=Sawarabi+Gothic" rel="stylesheet"> <link rel="stylesheet" href="assets/css/style.css" /> </head> <body> <section class="loading d-flex justify-content-center align-items-center bg-light"> <div class="spinner shadow rounded d-flex justify-content-center align-items-center"> <p class="h4 text-secondary"><i class="fas fa-spinner fa-spin"></i> Loading...</p> </div> </section> <header> <nav class="navbar navbar-expand-lg navbar-light shadow bg-white fixed-top"> <div class="container-fluid"> <a class="navbar-brand" href="index.html"><i class="fas fa-paste"></i> BACK<span class="bland-red">OFFICE</span></a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarNavDropdown"> <ul class="navbar-nav header-menu"> <li class="nav-item active"> <a class="nav-link" href="index.html"><i class="fas fa-tachometer-alt"></i> DASHBOARD</a> </li> <li class="nav-item"> <a class="nav-link" href="users.html"><i class="fas fa-id-card-alt"></i> ユーザ管理</a> </li> <li class="nav-item"> <a class="nav-link active" href="depts.html"><i class="far fa-building"></i> 部署管理</a> </li> </ul> <ul class="navbar-nav ms-auto me-3"> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle username" href="#" id="navbarDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false"> 管理者 </a> <ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> <li><a class="dropdown-item" href="login.html"><i class="fas fa-sign-out-alt"></i> ログアウト</a></li> </ul> </li> </ul> </div> </div> </nav> </header> <nav class="left-nav shadow d-none d-lg-block"> <div class="list-group list-group-flush"> <a href="index.html" class="list-group-item list-group-item-action"><i class="fas fa-tachometer-alt"></i> DASHBOARD</a> <a href="users.html" class="list-group-item list-group-item-action"><i class="fas fa-id-card-alt"></i> ユーザ管理</a> <a href="depts.html" class="list-group-item list-group-item-action active"><i class="far fa-building"></i> 部署管理</a> </div> </nav> <main class="contents"> <section class="container-fluid"> <header> <h1><i class="far fa-building"></i> 部署管理</h1> </header> <form class="needs-validation" novalidate> <input type="hidden" name="dept_id" value=""> <div class="row"> <div class="col-lg mb-3"> <div class="form-floating"> <input type="text" class="form-control" id="name" name="name" placeholder="部署名を入力してください。" pattern=".{2,}" required> <label for="name">部署名</label> <div class="valid-feedback">正しい入力です</div> <div class="invalid-feedback">正しく入力してください</div> </div> </div> <div class="col-lg mb-3"> <div class="form-floating"> <input type="tel" class="form-control" id="tel" name="tel" placeholder="電話番号を入力してください。" pattern="\d{2,4}-?\d{3,4}-?\d{3,4}" required> <label for="tel">電話番号</label> <div class="valid-feedback">正しい入力です</div> <div class="invalid-feedback">正しく入力してください</div> </div> </div> </div> <div class="row"> <div class="col-lg mb-3"> <button class="btn btn-success"><i class="far fa-check-circle"></i> 登録</button> </div> </div> </form> </section> </main> <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script> <script src="assets/js/script.js"></script> <script> $(function(){ /* ログインチェック */ isSignin(); $process('Depts'); var isNew = true; if(localStorage.getItem('dept_id') != null){ isNew = false; $method('get'); $xhrNoValidate([{name: 'dept_id', value: localStorage.getItem('dept_id')}], function(data, status, xhr){ var rs = data.list.rs; $.each(rs, function(key, value){ if($('[name='+key+']').get(0)){ $('[name='+key+']').val(value); } }); }); } $('.btn-success').on('click', function(){ isNew ? $method('insert') : $method('update'); $xhr($('form:first'), function(data, status, xhr){ location.href = 'depts.html'; }); return false; }); }); </script> </body> </html>
users.html
users.html
<!doctype html> <html lang="ja" > <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="process"> <meta name="method"> <title>ユーザ管理 | tech.pjin.jp</title> <!-- Bootstrap CSS --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous"> <!-- Font Awesome CSS --> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous"> <!-- Animate.css CSS --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" /> <!-- Sawarabi Gothic --> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Sawarabi+Gothic"> <!-- DataTables 1.10.24 --> <link rel="stylesheet" href="https://cdn.datatables.net/1.10.24/css/dataTables.bootstrap4.min.css"> <link rel="stylesheet" href="https://cdn.datatables.net/buttons/1.7.0/css/buttons.bootstrap4.min.css"> <link rel="stylesheet" href="https://cdn.datatables.net/responsive/2.2.7/css/responsive.dataTables.min.css"> <link rel="stylesheet" href="https://cdn.datatables.net/responsive/2.2.7/css/responsive.bootstrap4.min.css"> <link rel="stylesheet" href="assets/css/style.css" /> </head> <body> <section class="loading d-flex justify-content-center align-items-center bg-light"> <div class="spinner shadow rounded d-flex justify-content-center align-items-center"> <p class="h4 text-secondary"><i class="fas fa-spinner fa-spin"></i> Loading...</p> </div> </section> <header> <nav class="navbar navbar-expand-lg navbar-light shadow bg-white fixed-top"> <div class="container-fluid"> <a class="navbar-brand" href="index.html"><i class="fas fa-paste"></i> BACK<span class="bland-red">OFFICE</span></a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarNavDropdown"> <ul class="navbar-nav header-menu"> <li class="nav-item active"> <a class="nav-link" href="index.html"><i class="fas fa-tachometer-alt"></i> DASHBOARD</a> </li> <li class="nav-item"> <a class="nav-link active" href="users.html"><i class="fas fa-id-card-alt"></i> ユーザ管理</a> </li> <li class="nav-item"> <a class="nav-link" href="depts.html"><i class="far fa-building"></i> 部署管理</a> </li> </ul> <ul class="navbar-nav ms-auto me-3"> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle username" href="#" id="navbarDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false"> 管理者 </a> <ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> <li><a class="dropdown-item" href="login.html"><i class="fas fa-sign-out-alt"></i> ログアウト</a></li> </ul> </li> </ul> </div> </div> </nav> </header> <nav class="left-nav shadow d-none d-lg-block"> <div class="list-group list-group-flush"> <a href="index.html" class="list-group-item list-group-item-action"><i class="fas fa-tachometer-alt"></i> DASHBOARD</a> <a href="users.html" class="list-group-item list-group-item-action active"><i class="fas fa-id-card-alt"></i> ユーザ管理</a> <a href="depts.html" class="list-group-item list-group-item-action"><i class="far fa-building"></i> 部署管理</a> </div> </nav> <main class="contents"> <section class="container-fluid"> <header> <h1><i class="fas fa-id-card-alt"></i> ユーザ管理</h1> </header> <div class="row"> <div class="col buttons"> </div> <div class="col d-flex justify-content-end"> <button class="btn btn-success"><i class="fas fa-plus-square"></i> 新規登録</button> </div> </div> <div class="mt-3"></div> <table id="users" class="table dt-responsive nowrap" style="width:100%"> <thead> <tr> <th>#</th> <th>名前</th> <th>メールアドレス</th> <th>電話番号</th> <th>所属部署</th> <th>操作</th> </tr> </thead> </table> </section> </main> <div class="modal fade" tabindex="-1" role="dialog" id="deleteModal"> <div class="modal-dialog modal-dialog-centered" role="document"> <div class="modal-content"> <div class="modal-header bg-danger text-white"> <h5 class="modal-title"><i class="fas fa-exclamation-triangle"></i> 削除確認</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <p>削除致します。よろしいでしょうか。</p> </div> <div class="modal-footer"> <button type="button" class="btn btn-danger act-exec-delete"><i class="far fa-trash-alt"></i> 削除</button> </div> </div> </div> </div> <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script> <!-- DataTables 1.10.24 --> <script src="https://cdn.datatables.net/1.10.24/js/jquery.dataTables.min.js"></script> <script src="https://cdn.datatables.net/1.10.24/js/dataTables.bootstrap4.min.js"></script> <script src="https://cdn.datatables.net/buttons/1.7.0/js/dataTables.buttons.min.js"></script> <script src="https://cdn.datatables.net/buttons/1.7.0/js/buttons.bootstrap4.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.3/jszip.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/pdfmake.min.js"></script> <script src="./assets/js/vfs_fonts.js"></script> <script src="https://cdn.datatables.net/buttons/1.7.0/js/buttons.html5.min.js"></script> <script src="https://cdn.datatables.net/responsive/2.2.7/js/dataTables.responsive.min.js"></script> <script src="https://cdn.datatables.net/responsive/2.2.7/js/responsive.bootstrap4.min.js"></script> <script src="assets/js/script.js"></script> <script> $(function(){ /* ログインチェック */ isSignin(); /* 連携用ID削除 */ localStorage.removeItem('user_id'); /* Users.phpを実行するためにprocessにはUsersを指定します */ $process('Users'); /* 新規作成 */ $('.btn-success').on('click', function(){ /* そのまま編集画面へ遷移します */ location.href = 'usersEdit.html'; }); /* 削除実行 */ $('.act-exec-delete').on('click', function(e){ /* Users.php#deleteを呼び出します */ $method('delete'); /* Validationチェックは行わないで、非同期通信します */ $xhrNoValidate([{name: 'user_id', value: $('.act-exec-delete').data('id')}], function(data, status, xhr){ location.href = 'users.html'; }); /* ボタン押下時のイベントを通知しない為、falseを返します */ return false; }); var table = $('#users').DataTable({ ajax: { url: './api/', type: 'POST', data: {'process': 'Users', 'method': 'list'}, dataSrc: 'list.rs' }, columnDefs: [{ targets : 5, data: null, defaultContent: [ '<button class="btn btn-primary btn-sm me-3 act-update"><i class="fas fa-edit"></i> 編集</button>', '<button class="btn btn-outline-danger btn-sm act-delete" data-bs-toggle="modal" data-bs-target="#deleteModal"><i class="far fa-trash-alt"></i> 削除</button>' ].join('') }], columns: [ {data: "user_id"}, {data: "name"}, {data: "mail"}, {data: "tel"}, {data: "dept_name"} ], dom: 'Btp', buttons: [ { extend: 'copy', text: '<i class="fas fa-clipboard"></i> Copy' }, { extend: 'csv', text: '<i class="fas fa-file-alt"></i> Csv' }, { extend: 'excel', text: '<i class="fas fa-file-excel"></i> Excel' }, { extend: 'pdfHtml5', text: '<i class="fas fa-file-pdf"></i> PDF', customize: function(doc){ doc.defaultStyle.font= 'GenShin'; } } ] }); /* ダウンロードなどのボタンを描画します */ table.buttons().container().appendTo('.buttons'); /* Datatablesのデータ部分の描画終了時に、コールバックされます */ table.on('draw', function(){ /* 更新 */ $('.act-update').on('click', function(e){ var tr = $(this).closest('tr'); /* localStorageにuser_idをセットします */ localStorage.setItem('user_id', $('td:first', tr).text()); /* 編集画面へ遷移 */ location.href = 'usersEdit.html'; }); /* 削除確認 */ $('.act-delete').on('click', function(e){ var tr = $(this).closest('tr'); /* モーダルを表示する際に削除するidをモーダル側へ設定します */ $('.act-exec-delete').data('id', $('td:first', tr).text()); }); }); }); </script> </body> </html>
usersEdit.html
usersEdit.html
<!doctype html> <html lang="ja" > <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="process"> <meta name="method"> <title>ユーザ管理 | tech.pjin.jp</title> <!-- Bootstrap CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous"> <!-- Font Awesome CSS --> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous"> <!-- Animate.css CSS --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" /> <!-- Sawarabi Gothic --> <link href="https://fonts.googleapis.com/css?family=Sawarabi+Gothic" rel="stylesheet"> <link rel="stylesheet" href="assets/css/style.css" /> </head> <body> <section class="loading d-flex justify-content-center align-items-center bg-light"> <div class="spinner shadow rounded d-flex justify-content-center align-items-center"> <p class="h4 text-secondary"><i class="fas fa-spinner fa-spin"></i> Loading...</p> </div> </section> <header> <nav class="navbar navbar-expand-lg navbar-light shadow bg-white fixed-top"> <div class="container-fluid"> <a class="navbar-brand" href="index.html"><i class="fas fa-paste"></i> BACK<span class="bland-red">OFFICE</span></a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarNavDropdown"> <ul class="navbar-nav header-menu"> <li class="nav-item active"> <a class="nav-link" href="index.html"><i class="fas fa-tachometer-alt"></i> DASHBOARD</a> </li> <li class="nav-item"> <a class="nav-link active" href="users.html"><i class="fas fa-id-card-alt"></i> ユーザ管理</a> </li> <li class="nav-item"> <a class="nav-link" href="depts.html"><i class="far fa-building"></i> 部署管理</a> </li> </ul> <ul class="navbar-nav ms-auto me-3"> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle username" href="#" id="navbarDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false"> 管理者 </a> <ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> <li><a class="dropdown-item" href="login.html"><i class="fas fa-sign-out-alt"></i> ログアウト</a></li> </ul> </li> </ul> </div> </div> </nav> </header> <nav class="left-nav shadow d-none d-lg-block"> <div class="list-group list-group-flush"> <a href="index.html" class="list-group-item list-group-item-action"><i class="fas fa-tachometer-alt"></i> DASHBOARD</a> <a href="users.html" class="list-group-item list-group-item-action active"><i class="fas fa-id-card-alt"></i> ユーザ管理</a> <a href="depts.html" class="list-group-item list-group-item-action"><i class="far fa-building"></i> 部署管理</a> </div> </nav> <main class="contents"> <section class="container-fluid"> <header> <h1><i class="fas fa-id-card-alt"></i> ユーザ管理</h1> </header> <form class="needs-validation"> <input type="hidden" name="user_id" value=""> <div class="row"> <div class="col-lg mb-3"> <div class="form-floating"> <input type="text" class="form-control" id="name" name="name" placeholder="名前を入力してください。" pattern=".{2,}" required> <label for="name">名前</label> <div class="valid-feedback">正しい入力です</div> <div class="invalid-feedback">正しく入力してください</div> </div> </div> </div> <div class="row"> <div class="col-lg mb-3"> <div class="form-floating"> <input type="email" class="form-control" id="mail" name="mail" placeholder="メールアドレスを入力してください。" required> <label for="mail">メールアドレス</label> <div class="valid-feedback">正しい入力です</div> <div class="invalid-feedback">正しく入力してください</div> </div> </div> <div class="col-lg mb-3"> <div class="form-floating"> <input type="password" class="form-control" id="passwd" name="passwd" placeholder="パスワードを入力してください。" pattern="(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\d)[a-zA-Z\d]{6,}" required> <label for="passwd">パスワード</label> <div class="valid-feedback">正しい入力です</div> <div class="invalid-feedback">正しく入力してください(英数大文字・小文字、半角数字いずれも含む6文字以上)</div> </div> </div> </div> <div class="row"> <div class="col-lg mb-3"> <div class="form-floating"> <input type="tel" class="form-control" id="tel" name="tel" placeholder="電話番号を入力してください。" pattern="\d{2,4}-?\d{3,4}-?\d{3,4}" required> <label for="tel">電話番号</label> <div class="valid-feedback">正しい入力です</div> <div class="invalid-feedback">正しく入力してください</div> </div> </div> <div class="col-lg mb-3"> <div class="form-floating"> <select class="form-select" id="dept_id" name="dept_id" required></select> <label for="dept_id">所属部署</label> <div class="valid-feedback">正しい入力です</div> <div class="invalid-feedback">正しく入力してください</div> </div> </div> </div> <div class="row"> <div class="col-lg mb-3"> <div class="form-floating"> <input type="text" class="form-control" id="addr" name="addr" placeholder="住所を入力してください。" pattern=".{5,}" required> <label for="addr">住所</label> <div class="valid-feedback">正しい入力です</div> <div class="invalid-feedback">正しく入力してください</div> </div> </div> </div> <div class="row"> <div class="col-lg mb-3"> <button class="btn btn-success"><i class="far fa-check-circle"></i> 登録</button> </div> </div> </form> </section> </main> <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script> <script src="assets/js/script.js"></script> <script> $(function(){ /* ログインチェック */ isSignin(); /* 部署プルダウン作成 */ $process('Depts'); $method('list'); $('#dept_id').append($('<option>').text('選択してください').val('')); $xhrNoValidate([], function(data, status, xhr){ var rs = data.list.rs; $.each(rs, function(idx, el){ $('#dept_id').append($('<option>').text(el.name).val(el.dept_id)); }); }); /* processをUsersに設定します。(/api/Users.phpを読み込むため) */ $process('Users'); /* 新規or更新処理を実施するための処理分岐用フラグ */ var isNew = true; if(localStorage.getItem('user_id') != null){ /* localStorageのuser_idがセットされていれば、更新処理 */ isNew = false; /* methodをgetに変更し、user_idよりデータを取得 */ $method('get'); /* validationを実行せずにデータを取得(非同期処理) */ $xhrNoValidate([{name: 'user_id', value: localStorage.getItem('user_id')}], function(data, status, xhr){ /* 取得したデータをセット */ var rs = data.list.rs; /* 選択セレクターにて項目名が指定されている要素に値を設定します */ $.each(rs, function(key, value){ if($('[name='+key+']').get(0)){ $('[name='+key+']').val(value); } }); /* パスワードハッシュは未入力とします */ $('[name=passwd]').val(''); }); } /* class="btn-success" を指定してある要素をクリックしたら */ $('.btn-success').on('click', function(){ /* 登録処理を実行(insertを実行します) */ isNew ? $method('insert') : $method('update'); /* 非同期通信を呼び出し、成功したらusers.htmlへ遷移します */ $xhr($('form:first'), function(data, status, xhr){ location.href = 'users.html'; }); /* ボタンを押下した際の戻り値にfalseを返すと、submitしません */ return false; }); }); </script> </body> </html>