Почему данные не попадают в таблицу после отправки через API?

index.vue

<template>
  <div class="flex flex-col gap-2">
    <h1 class="text-2xl font-bold mb-4">{{ $t('system_users') }}</h1>
    <div
      class="flex flex-col gap-4 bg-white border border-gray-200 shadow-sm rounded-xl p-4 h-[calc(100vh-200px)]"
    >
      <div class="flex justify-between">
        <custom-button
          @click="isAddModalVisible = true"
          type="button"
          :text="$t('add_user')"
          mode="py-2 px-4 rounded-xl bg-[#009FC2] hover:bg-[#009ec2cf] focus:ring-[#009ec2cf] shadow-sm text-white"
        >
          <template #icon>
            <icon-add class="w-5 h-5 text-white" />
          </template>
        </custom-button>
        <div class="flex justify-end gap-2">
          <custom-search type="text" class="w-[20rem]"></custom-search>
          <custom-button
            type="button"
            :text="$t('download_excel')"
            mode="py-2 px-4 border border-gray-300 rounded-xl bg-white hover:bg-gray-100 shadow-sm"
          >
            <template #icon>
              <icon-download class="w-5 h-5" :fontControlled="false" />
            </template>
          </custom-button>
        </div>
      </div>

      <custom-data-table :columns="columns" :data="user" :loading="isLoading">
        <template #cell-fullName="{ row }">
          {{ row.fullName }}
        </template>
        <template #cell-email="{ row }">
          {{ row.email }}
        </template>
        <template #cell-creationDate="{ row }">
          {{ row.creationDate }}
        </template>
        <template #cell-roles="{ row }">
          <div v-for="role in row.roles" :key="role.name">
            {{ role.name }} ({{ role.value }})
          </div>
        </template>
      </custom-data-table>

      <custom-modal
        v-model="isAddModalVisible"
        :title="$t('add_user')"
        :confirm-text="$t('add')"
        :show-cancel="true"
        @confirm="addUser"
        mode="w-[880px]"
      >
        <template #default>
          <p class="text-red-500 text-sm font-medium mb-3">
            {{ $t('requirement_about_form_components') }}
          </p>

          <div class="grid grid-cols-2 gap-4">
            <custom-input
              v-model="userData.fullName"
              :label="$t('user_fullname')"
              name="fullName"
              required
              mode="border border-[#dfdfdf] rounded-[12px] px-3 py-2 w-[416px] h-[40px]"
            />

            <custom-input
              v-model="userData.email"
              :label="$t('user_email')"
              name="email"
              required
              mode="border border-[#dfdfdf] rounded-[12px] px-3 py-2 w-[416px] h-[40px]"
            />

            <div>
              <label for="role" class="block text-sm font-medium text-gray-700 mb-1">
                {{ $t('user_role') }}
              </label>
              <custom-select
                v-model="userData.role"
                :id="'role'"
                :name="'role'"
                :data="roles"
                :required="true"
                :valueExpr="'name'"
                :displayExpr="'name'"
                :placeholder="$t('select')"
                mode="border border-[#dfdfdf] rounded-[12px] px-3 py-2 w-[416px] h-[40px]"
              />
            </div>

            <div class="relative">
              <custom-input
                v-model="userData.password"
                :type="isPasswordVisible ? 'text' : 'password'"
                :label="$t('password')"
                name="password"
                required
                mode="border border-[#dfdfdf] rounded-[12px] px-3 py-2 w-[416px] h-[40px]"
              />
              <component
                :is="isPasswordVisible ? 'icon-eye-open' : 'icon-eye-close'"
                @click="togglePasswordVisibility"
                class="text-[#767676] absolute right-4 top-9 cursor-pointer w-[1.5rem] h-[1rem]"
                :fontControlled="false"
              />
            </div>

            <div class="relative">
              <custom-input
                v-model="userData.confirmPassword"
                :type="isConfirmPasswordVisible ? 'text' : 'password'"
                :label="$t('confirm_password')"
                name="confirmPassword"
                required
                mode="border border-[#dfdfdf] rounded-[12px] px-3 py-2 w-[416px] h-[40px]"
              />
              <component
                :is="isConfirmPasswordVisible ? 'icon-eye-open' : 'icon-eye-close'"
                @click="toggleConfirmPasswordVisibility"
                class="text-[#767676] absolute right-4 top-9 cursor-pointer w-[1.5rem] h-[1rem]"
                :fontControlled="false"
              />
            </div>
          </div>
        </template>
      </custom-modal>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { useApi } from '@/composables/useApi';
import { type InternalUserResponse, type Role } from '@/types';
import { ref, onMounted, reactive } from 'vue';
import { useNuxtApp } from '#imports';

const { $toast } = useNuxtApp();
const api = useApi();

const user = ref<InternalUserResponse[]>([]); // Список пользователей
const isLoading = ref(true);

const isAddModalVisible = ref(false);
const isPasswordVisible = ref(false);
const isConfirmPasswordVisible = ref(false);

const userData = reactive<Omit<InternalUserResponse, 'roles'> & { role: string; confirmPassword: string }>({
  fullName: '',
  email: '',
  password: '',
  confirmPassword: '',
  role: '',
});

const roles = ref<Role[]>([
  { name: 'Admin', value: 1 }, // Роли пользователей
  { name: 'Fond əməkdaşı', value: 2 },
  { name: 'EN əməkdaşı', value: 3 },
]);

const togglePasswordVisibility = () => {
  isPasswordVisible.value = !isPasswordVisible.value;
};

const toggleConfirmPasswordVisibility = () => {
  isConfirmPasswordVisible.value = !isConfirmPasswordVisible.value;
};

// Подготовка данных о ролях для API
const prepareRoles = (role: string): Role[] => {
  const selectedRole = roles.value.find((r) => r.name === role);
  return selectedRole ? [{ name: selectedRole.name, value: selectedRole.value }] : []; 
};

// Добавление нового пользователя
const addUser = async () => {
  if (userData.password !== userData.confirmPassword) {
    $toast.error('Пароли не совпадают!');
    return;
  }

  try {
    const preparedData: InternalUserResponse = {
      fullName: userData.fullName,
      email: userData.email,
      password: userData.password,
      roles: prepareRoles(userData.role),
    };

    console.log('Отправляемые данные:', preparedData);

    const response = await api.post('/api/endpoint', preparedData);

    console.log('Ответ от сервера:', response);

    if (response.status >= 200 && response.status < 300) {
      $toast.success('Пользователь успешно создан!');
      isAddModalVisible.value = false;
      await loadUser();
      Object.keys(userData).forEach((key) => (userData[key] = ''));
    } else {
      console.error('Ошибка создания пользователя:', response.status, response.data);
      $toast.error('Не удалось создать пользователя. Ошибка API: ' + response.status);
    }
  } catch (error) {
    console.error('Ошибка создания пользователя:', error);
    $toast.error('Не удалось создать пользователя. ' + error.message);
    if (error.response) {
      console.error('Детали ошибки:', error.response.status, error.response.data);
    }
  }
};

// Загрузка данных о пользователях
onMounted(async () => {
  await loadUser();
});

const loadUser = async () => {
  try {
    isLoading.value = true;
    user.value = await api.get<InternalUserResponse[]>('/api/endpoint');
  } catch (error) {
    console.error('Ошибка загрузки пользователей:', error);
    $toast.error('Не удалось загрузить пользователей.');
  } finally {
    isLoading.value = false;
  }
};

// Колонки для таблицы
const columns = [
  { key: 'fullName', label: 'İstifadəçi adı və soyadı' },
  { key: 'email', label: 'İstifadəçi log-ini' },
  { key: 'creationDate', label: 'Yaradılma tarixi' },
  { key: 'roles', label: 'İstifadəçi rolu' },
];
</script>

index.ts


export interface InternalUserResponse {
  fullName: string;
  email: string;
  password?: string; 
  roles: Role[];
}

export interface Role {
  name: string;
  value: number;
}

POST API Request body

{
  "fullName": "string",
  "email": "string",
  "password": "string",
  "roles": [
    {
      "name": "string",
      "value": 0
    }
  ]
}

GET API Responses

[
  {
    "id": "string",
    "email": "string",
    "fullName": "string"
  }
]

Ответы (0 шт):