Vue.js | ユーザー管理にCRUD機能を追加

Webアプリケーションで効率的な運用を支えるためには、管理機能の強化が欠かせません。今回、メールアカウント申請システムに「ユーザー管理」のCRUD機能(Create, Read, Update, Delete)を追加しました。この機能により、管理者はユーザー情報の作成・閲覧・編集・削除が可能になり、運用がスムーズになりました。


実装した機能の概要

以下の操作がユーザー管理画面で可能になりました:

  1. ユーザーの新規追加
    新しいユーザーを登録できます。名前やメールアドレス、権限を指定するシンプルなUIを提供します。
  2. ユーザー情報の閲覧
    ユーザー一覧を確認する「Read」機能で、登録済みのユーザーを一目で把握できます。
  3. ユーザー情報の編集
    名前やメールアドレスの変更だけでなく、権限の更新も可能です。
  4. ユーザーの削除
    必要に応じて登録済みのユーザーを削除する機能を提供します。

フロントエンドの実装

ユーザー管理画面は、Vue.jsを使用して構築しました。以下に主なコードを示します。

ユーザー管理画面のUI構築

管理者がユーザーを操作するためのインターフェースを用意しました。CRUD操作をモーダルウィンドウで行えるように設計し、直感的な操作が可能です。

メインのユーザー管理画面

export default {
  template: `
    <div class="max-w-4xl mx-auto bg-white shadow-lg rounded-lg p-6 mt-10">
      <h2 class="text-2xl font-bold mb-4 text-gray-800">ユーザー管理</h2>
      <button @click="openCreateModal" class="bg-blue-500 text-white px-4 py-2 rounded-lg hover:bg-blue-600 mb-4">
        新規ユーザー追加
      </button>
      <div v-if="loading" class="text-center">読み込み中...</div>
      <div v-else>
        <table class="table-auto w-full border-collapse border border-gray-300">
          <thead>
            <tr class="bg-gray-100">
              <th class="border border-gray-300 px-4 py-2">ユーザーID</th>
              <th class="border border-gray-300 px-4 py-2">名前</th>
              <th class="border border-gray-300 px-4 py-2">メールアドレス</th>
              <th class="border border-gray-300 px-4 py-2">権限</th>
              <th class="border border-gray-300 px-4 py-2">操作</th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="user in users" :key="user.id">
              <td class="border border-gray-300 px-4 py-2">{{ user.id }}</td>
              <td class="border border-gray-300 px-4 py-2">{{ user.name }}</td>
              <td class="border border-gray-300 px-4 py-2">{{ user.email }}</td>
              <td class="border border-gray-300 px-4 py-2">{{ translateRole(user.role) }}</td>
              <td class="border border-gray-300 px-4 py-2">
                <button @click="openEditModal(user)" class="bg-yellow-500 text-white px-2 py-1 rounded-lg hover:bg-yellow-600">編集</button>
                <button @click="deleteUser(user.id)" class="bg-red-500 text-white px-2 py-1 rounded-lg hover:bg-red-600 ml-2">削除</button>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
      <create-edit-modal v-if="showModal" :user="selectedUser" @close="closeModal" @refresh="fetchUsers"></create-edit-modal>
    </div>
  `,
  data() {
    return {
      users: [],
      loading: true,
      showModal: false,
      selectedUser: null,
    };
  },
  methods: {
    translateRole(role) {
      return role === 'admin' ? '管理者' : 'ユーザー';
    },
    async fetchUsers() {
      try {
        const response = await fetch('/api/admin/users');
        const data = await response.json();
        if (data.success) {
          this.users = data.users;
        } else {
          alert('ユーザー一覧の取得に失敗しました: ' + data.message);
        }
      } catch (error) {
        console.error('エラー:', error);
      } finally {
        this.loading = false;
      }
    },
    openCreateModal() {
      this.selectedUser = null;
      this.showModal = true;
    },
    openEditModal(user) {
      this.selectedUser = { ...user };
      this.showModal = true;
    },
    closeModal() {
      this.showModal = false;
    },
    async deleteUser(userId) {
      if (!confirm('本当に削除しますか?')) return;
      try {
        const response = await fetch('/api/admin/users/delete', {
          method: 'DELETE',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ user_id: userId }),
        });
        const data = await response.json();
        if (data.success) {
          alert('ユーザーを削除しました。');
          this.fetchUsers();
        } else {
          alert('削除に失敗しました: ' + data.message);
        }
      } catch (error) {
        console.error('削除エラー:', error);
      }
    },
  },
  async created() {
    this.fetchUsers();
  },
  components: {
    'create-edit-modal': {
      template: `
        <div class="fixed inset-0 bg-gray-800 bg-opacity-50 flex items-center justify-center">
          <div class="bg-white p-6 rounded shadow-lg">
            <h3 class="text-lg font-bold mb-4" v-if="user">ユーザー編集</h3>
            <h3 class="text-lg font-bold mb-4" v-else>新規ユーザー追加</h3>
            <form @submit.prevent="saveUser">
              <div class="mb-4">
                <label class="block text-gray-700 font-bold mb-2">名前</label>
                <input type="text" v-model="form.name" required class="w-full px-3 py-2 border rounded-lg">
              </div>
              <div class="mb-4">
                <label class="block text-gray-700 font-bold mb-2">メールアドレス</label>
                <input type="email" v-model="form.email" required class="w-full px-3 py-2 border rounded-lg">
              </div>
              <div class="mb-4">
                <label class="block text-gray-700 font-bold mb-2">パスワード</label>
                <input type="password" v-model="form.password" placeholder="変更時のみ入力" class="w-full px-3 py-2 border rounded-lg">
              </div>
              <div class="mb-4">
                <label class="block text-gray-700 font-bold mb-2">権限</label>
                <select v-model="form.role" required class="w-full px-3 py-2 border rounded-lg">
                  <option value="user">ユーザー</option>
                  <option value="admin">管理者</option>
                </select>
              </div>
              <div class="flex justify-end">
                <button type="submit" class="bg-blue-500 text-white px-4 py-2 rounded-lg hover:bg-blue-600">
                  保存
                </button>
                <button @click="$emit('close')" class="bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 ml-2">
                  キャンセル
                </button>
              </div>
            </form>
          </div>
        </div>
      `,
      props: ['user'],
      data() {
        return {
          form: {
            name: this.user ? this.user.name : '',
            email: this.user ? this.user.email : '',
            password: '',
            role: this.user ? this.user.role : 'user',
          },
        };
      },
      methods: {
        async saveUser() {
          try {
            const url = this.user ? '/api/admin/users/update' : '/api/admin/users/create';
            const method = this.user ? 'PUT' : 'POST';
            const response = await fetch(url, {
              method,
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify(this.form),
            });
            const data = await response.json();
            if (data.success) {
              alert(this.user ? 'ユーザーを更新しました。' : 'ユーザーを追加しました。');
              this.$emit('refresh');
              this.$emit('close');
            } else {
              alert('保存に失敗しました: ' + data.message);
            }
          } catch (error) {
            console.error('保存エラー:', error);
          }
        },
      },
    },
  },
};

最後に

今回の実装で、ユーザー管理機能にCRUD操作を加え、管理者がより快適に業務を行える環境を構築しました。この取り組みを通じて、システムの使いやすさと運用性が大幅に向上したと感じています。

次のステップでは、権限管理の強化や操作ログの記録機能の追加を検討し、さらに高度な管理機能を提供できるよう努めていきます。この記事が、同様の課題に取り組む方々の参考になれば幸いです!

コメント

タイトルとURLをコピーしました