個人情報管理です。各項目は、仮の項目でご自由にカスタマイズ可能です。詳細は、仕様の変更・削除・機能追加・修正・デザイン変更・目的変更等も制限がありません。コードを公開しますので、参考になればご自由に使用してください。

仕様
1.ID(10桁指定) 氏名 職業(選択方式) 郵便番号(基本フォーマット) 電話番号(12桁) 住所(最大100文字) 備考(最大100文字)
2.全ての入力完了後に登録ボタン可
3.データの個別削除
4.全データの削除
5.IDの降順ソート
6.職業種別の検索機能
7.データ管理 サーバー(CSV)
ご使用について
本プログラムは、動作確認を行っておりますが、ソースの参考やコピー&ペースト等による完成後の不具合が有りましても、管理者は責任の回避ができるものとします。
また、デザインやソースコードをすべて使用した場合は、どこか片隅に小さくMOMOPLANと書いて頂ければ嬉しく思います。
ファイルの構成(参考)
jyunbanmati/date/date.csv
├── index.html
├── main.js
├── public_data.php
├── style.css
MAIN.JSへジャンプ public_data.phpへジャンプ styles.cssへジャンプ CSVへジャンプ
HTML(index.html)
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="styles.css">
    <title>データ管理フォーム</title>

</head>
<body>
    <center><font color="#5511c2"><h1>データ管理フォーム</h1></font></center>
    <form id="dataForm">
        <label>ID (10桁): <input type="text" id="id" maxlength="10" placeholder="例: 10桁を入力" required></label>
        <label>氏名 (16文字以内): <input type="text" id="name" maxlength="16" required></label>
        <label>職業: 
            <select id="job">
                <option value="A">A</option>
                <option value="B">B</option>
                <option value="C">C</option>
                <option value="D">D</option>
                <option value="E">E</option>
                <option value="F">F</option>
            </select>
        </label>
        <label>郵便番号 (000-0000): <input type="text" id="zip" pattern="^[0-9]{3}-[0-9]{4}$" placeholder="例: (000-0000)" required></label>
        <label>電話番号 (12桁以内): <input type="text" id="phone" maxlength="12" required></label>
        <label>住所 (最大100文字): <input type="text" id="address" maxlength="100"></label>
        <label>備考 (最大100文字): <input type="text" id="note" maxlength="100"></label>
        <button type="submit">登録</button>
    </form>

    <table id="dataTable">
        <thead>
            <tr>
                <th>ID</th>
                <th>氏名</th>
                <th>職業</th>
                <th>郵便番号</th>
                <th>電話番号</th>
                <th>住所</th>
                <th>備考</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody></tbody>
    </table>

    <button id="clearAll">全削除</button>
    <button id="sortDesc">降順ソート</button>
    <button id="search">検索</button>
    <button id="resetView" style="display: none;">戻る</button>
    <script src="main.js"></script>
</body>
</html>
JS(main.js)
document.addEventListener('DOMContentLoaded', function() {
    const registerBtn = document.querySelector('button[type="submit"]');
    const inputFields = Array.from(document.querySelectorAll('#dataForm input, #dataForm select, #dataForm textarea'));

    // **初期状態で登録ボタンを無効化**
    registerBtn.disabled = true;

    // **入力欄の変更を監視し、全て入力されたらボタンを有効化**
    inputFields.forEach(field => {
        field.addEventListener('input', validateForm);
        field.addEventListener('blur', validateForm); // フォーカスが外れたらチェック
    });

    function validateForm() {
        const allFilled = inputFields.every(field => field.value.trim() !== '');
        registerBtn.disabled = !allFilled;
    }
});

// 初期データ読み込み(CSVから取得してテーブルに表示)
window.addEventListener('load', function() {
    fetch('public_data.php')
        .then(response => response.json())
        .then(data => {
            const tableBody = document.querySelector('#dataTable tbody');
            tableBody.innerHTML = ''; // 既存データをクリア

            data.data.forEach(row => {
                const newRow = `<tr>
                    <td>${row[0]}</td>
                    <td>${row[1]}</td>
                    <td>${row[2]}</td>
                    <td>${row[3]}</td>
                    <td>${row[4]}</td>
                    <td>${row[5]}</td>
                    <td>${row[6]}</td>
                    <td><button class="deleteBtn">削除</button></td>
                </tr>`;
                tableBody.insertAdjacentHTML('beforeend', newRow);
            });
        })
        .catch(error => console.error("データ取得エラー:", error));
});

// フォーム送信(登録)
document.getElementById('dataForm').addEventListener('submit', function(event) {
    event.preventDefault();

    const id = document.getElementById('id').value.trim();
    const name = document.getElementById('name').value.trim();
    const job = document.getElementById('job').value;
    const zip = document.getElementById('zip').value.trim();
    const phone = document.getElementById('phone').value.trim();
    const address = document.getElementById('address').value.trim();
    const note = document.getElementById('note').value.trim();

    const row = `<tr>
        <td>${id}</td>
        <td>${name}</td>
        <td>${job}</td>
        <td>${zip}</td>
        <td>${phone}</td>
        <td>${address}</td>
        <td>${note}</td>
        <td><button class="deleteBtn">削除</button></td>
    </tr>`;

    document.querySelector('#dataTable tbody').insertAdjacentHTML('beforeend', row);
    document.getElementById('dataForm').reset();

    saveData();
});

// 各レコードの削除
document.addEventListener('click', function(event) {
    if (event.target.classList.contains('deleteBtn')) {
        const row = event.target.closest('tr'); // 削除対象の行を明確に取得
        if (row) {
            row.remove(); // 行を削除
            saveData(); // CSVに変更を反映
        } else {
            console.error("削除対象の行が見つかりません");
        }
    }
});


// **全削除(テーブル&CSV連動)**
document.getElementById('clearAll').addEventListener('click', function() {
    document.querySelector('#dataTable tbody').innerHTML = ''; // テーブルをクリア

    // **CSVのデータも完全クリア**
    fetch('public_data.php', {
        method: 'POST',
        body: JSON.stringify({clear: true}),
        headers: { 'Content-Type': 'application/json' }
    })
    .then(response => response.json())
    .then(data => console.log(data.message))
    .catch(error => console.error("全削除エラー:", error));
});


// CSVファイルへデータ保存
function saveData() {
    const tableData = [];
    document.querySelectorAll('#dataTable tbody tr').forEach(row => {
        const rowData = Array.from(row.children).slice(0, 7).map(td => td.textContent.trim());
        tableData.push(rowData.join(','));
    });

    fetch('public_data.php', {
        method: 'POST',
        body: JSON.stringify({data: tableData}),
        headers: { 'Content-Type': 'application/json' }
    })
    .then(response => response.json())
    .then(data => console.log(data.message))
    .catch(error => console.error("データ保存エラー:", error));
}

document.getElementById('sortDesc').addEventListener('click', function() {
    console.log("ソートボタンがクリックされました"); // デバッグログ

    const tableBody = document.querySelector('#dataTable tbody');
    const rows = Array.from(tableBody.querySelectorAll('tr'));

    console.log("取得した行:", rows); // デバッグログ

    // **IDを数値として扱うために修正**
    rows.sort((a, b) => {
        const idA = parseInt(a.cells[0].textContent.trim(), 10); // 数値へ変換
        const idB = parseInt(b.cells[0].textContent.trim(), 10);
        
        console.log(`比較: ${idA} vs ${idB}`); // 比較のログ
        
        return idB - idA; // 数値比較
    });

    console.log("ソート後のデータ:", rows); // ソート結果のログ

    // **ソートした行をテーブルに反映**
    tableBody.innerHTML = ''; // クリア
    rows.forEach(row => tableBody.appendChild(row));
});

document.getElementById('search').addEventListener('click', function() {
    const searchTerm = prompt("検索する職業を入力してください(例: A, B, C, D, E, F):");
    console.log("検索ワード:", searchTerm); // デバッグログ
    if (!searchTerm) return; // キャンセルされた場合は何もしない

    const tableBody = document.querySelector('#dataTable tbody');
    const rows = Array.from(tableBody.querySelectorAll('tr'));

    // **検索前にすべての行を表示**
    rows.forEach(row => row.style.display = "");

    rows.forEach(row => {
        const job = row.cells[2]?.textContent.trim(); // 職業欄(3列目)
        console.log(`比較: ${searchTerm} vs ${job}`); // デバッグログ

        if (job !== searchTerm) {
            row.style.display = "none"; // 検索対象外を非表示
        }
    });

    // **「戻るボタン」を有効にする**
    document.getElementById('resetView').style.display = "block";
});

// **戻るボタンでデータを元に戻す**
document.getElementById('resetView').addEventListener('click', function() {
    const rows = Array.from(document.querySelectorAll('#dataTable tbody tr'));
    rows.forEach(row => row.style.display = ""); // すべての行を再表示

    // **戻るボタンを非表示に戻す**
    document.getElementById('resetView').style.display = "none";
});
PHP(public_data.php)
<?php
$file = 'date/date.csv';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $data = json_decode(file_get_contents('php://input'), true);

    if (isset($data['clear']) && $data['clear'] === true) {
        // **CSVファイルの内容を完全削除**
        $fp = fopen($file, 'w'); // 空のファイルを作成(上書き)
        fclose($fp);
        echo json_encode(["message" => "CSVクリア完了"]);
    } else if (!empty($data['data'])) {
        // **CSVデータの更新**
        $fp = fopen($file, 'w');
        foreach ($data['data'] as $row) {
            fputcsv($fp, explode(',', $row));
        }
        fclose($fp);
        echo json_encode(["message" => "データ保存完了"]);
    } else {
        echo json_encode(["message" => "エラー: データが空です"]);
    }
} else {
    // **CSVデータの読み込み**
    $csvData = [];
    if (file_exists($file) && ($fp = fopen($file, 'r')) !== false) {
        while (($row = fgetcsv($fp)) !== false) {
            $csvData[] = $row;
        }
        fclose($fp);
    }
    echo json_encode(["data" => $csvData]);
}
?>
CSS(styles.css)
body {
    font-family: Arial, sans-serif;
    background-image: url("s-brick008.gif");
}

/* テーブル全体のスタイル */
table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 20px;
}

/* ヘッダー部分(タイトル行)のスタイル */
thead {
    background-color: #78ff95; /* 視認性の高い青色 */
    color: rgb(24, 23, 23);
    font-weight: bold;
}

/* ヘッダーの各セルのスタイル */
th {
    padding: 10px;
    border: 2px solid #8abbf0;
    text-align: center;
}

/* データセル(本文)のスタイル */
td {
    padding: 8px;
    border: 1px solid #ddd;
    text-align: center;
}

/* 奇数行・偶数行の色を交互に変更して視認性UP */
tbody tr:nth-child(odd) {
    background-color: #f9f9f9;
}

tbody tr:nth-child(even) {
    background-color: #e9ecef;
}

/* 削除ボタン(赤) */
.deleteBtn {
    background-color: #dc3545;
    color: white;
    border: none;
    padding: 8px 12px;
    cursor: pointer;
    font-weight: bold;
    border-radius: 6px; /* 角を丸める */
}

.deleteBtn:hover {
    background-color: #c82333;
}

/* 登録ボタン(青) */
button[type="submit"] {
    background-color: #007BFF;
    color: white;
    border: none;
    padding: 6px 10px;
    cursor: pointer;
    font-weight: bold;
    border-radius: 6px; /* 角を丸める */
}

button[type="submit"]:hover {
    background-color: #0056b3;
}

button:disabled {
    background-color: #ccc;
    cursor: not-allowed;
}


CSV
0123456987,dddddd,D,123-1237,77777777,東京都大田区,ssssss
0123456987,dddddd,C,123-1234,0312456981,wwwwwww,rrrrrrrrrrr
0123456987,ああああ,D,123-1237,0312456981,東京都大田区,ssssss

以上です、失礼します。