Laravel создает панель администратора Vue с нуля — часть 4

Мы создали наш первый Vue CRUD в последних двух частях. Мы почти завершили CRUD разрешений, за исключением сортировки и авторизации столбцов. В этой части мы реализуем функциональность сортировки.

Следующие шаги необходимы для создания сортировки столбцов для нашей панели администрирования Laravel Vue.

  • 1. Добавить заказПо
  • 2. Создайте компонент сортировки
  • 3. Включите компонент сортировки в компонент индекса.

1. Добавить заказПо

Мы собираемся добавить параметр строки запроса sort в URL-адрес. Основываясь на приведенном ниже значении сортировки, мы делаем порядок.

sort=name для порядка ASC

sort=-name для заказа DESC

Откройте функцию индекса в контроллере разрешений и добавьте функцию замены индекса с помощью приведенного ниже кода.

app/Http/Controllers/Admin/PermissionController.php

public function index()
{
    $permissions = (new Permission)->newQuery();
    if (request()->has('search')) {
        $permissions->where('name', 'Like', '%'.request()->input('search').'%');
    }
    if (request()->query('sort')) {
        $attribute = request()->query('sort');
        $sort_order = 'ASC';
        if (strncmp($attribute, '-', 1) === 0) {
            $sort_order = 'DESC';
            $attribute = substr($attribute, 1);
        }
        $permissions->orderBy($attribute, $sort_order);
    } else {
        $permissions->latest();
    }
    $permissions = $permissions->paginate(5)->onEachSide(2)->appends(request()->query());
    return Inertia::render('Admin/Permission/Index', [
        'permissions' => $permissions,
        'filters' => request()->all('search'),
    ]);
}

Не забудьте добавить request()->query() к ссылкам на страницы.

$permissions->paginate(5)->onEachSide(2)->appends(request()->query());

Теперь перейдите на страницу разрешений в браузере с sort=name параметром запроса. Он показывает результаты заказа ASC. Также проверьте порядок DESC с помощью sort=-name.

2. Создайте компонент сортировки

Создайте новый компонент сортировки для отображения имени столбца со ссылками сортировки и значками сортировки. Скопируйте приведенный ниже код и создайте компонент сортировки в папке Component/Admin.

resources/js/Components/Admin/Sort.vue

<script setup>
import { ref, computed } from "vue";
import { Link } from "@inertiajs/inertia-vue3";
const props = defineProps({
  label: {
    type: String,
    default: "",
  },
  attribute: {
    type: String,
    default: "",
  },
});
const downFill = ref("lightgray");
const upFill = ref("lightgray");
const sortLink = computed(() => {
  let url = new URL(document.location);
  let sortValue = url.searchParams.get("sort");
  if (sortValue == props.attribute) {
    url.searchParams.set("sort", "-" + props.attribute);
    upFill.value = "black";
  } else if (sortValue === "-" + props.attribute) {
    url.searchParams.set("sort", props.attribute);
    downFill.value = "black";
  } else {
    url.searchParams.set("sort", props.attribute);
  }
  return url.href;
});
</script>
<template>
  <div class="flex items-center gap-4">
    <Link
      :href="sortLink"
      class="no-underline hover:underline text-cyan-600 dark:text-cyan-400"
      >{{ label }}</Link
    >
    <div class="flex flex-col">
      <svg
        class="inline-block"
        xmlns="http://www.w3.org/2000/svg"
        width="15px"
        height="15px"
        viewBox="0 0 15 15"
        fill="none"
      >
        <path d="M7.5 3L15 11H0L7.5 3Z" :fill="upFill" />
      </svg>
      <svg
        class="inline-block"
        xmlns="http://www.w3.org/2000/svg"
        width="15px"
        height="15px"
        viewBox="0 0 15 15"
        fill="none"
      >
        <path
          d="M7.49988 12L-0.00012207 4L14.9999 4L7.49988 12Z"
          :fill="downFill"
        />
      </svg>
    </div>
  </div>
</template>

Компонент сортировки имеет свойства метки и атрибута. Кроме того, в компоненте мы использовали реактивную ref() Vue для заливки цветом для сортировки значка SVG.

3. Включите компонент сортировки в компонент индекса.

на последнем шаге мы импортируем компонент сортировки в Index.vue и включим компонент сортировки в столбец заголовка таблицы.

<Sort label="Name" attribute="name" />

Откройте компонент Index.vue и замените приведенным ниже кодом.

resources/js/Pages/Admin/Permission/Index.vue

<script setup>
import BreezeAuthenticatedLayout from "@/Layouts/Authenticated.vue";
import { Head, Link, useForm } from "@inertiajs/inertia-vue3";
import BreezeButton from "@/Components/Button.vue";
import Pagination from "@/Components/Admin/Pagination.vue";
import Sort from "@/Components/Admin/Sort.vue";
const props = defineProps({
  permissions: {
    type: Object,
    default: () => ({}),
  },
  filters: {
    type: Object,
    default: () => ({}),
  },
});
const form = useForm({
  search: props.filters.search,
});
const formDelete = useForm({});
function destroy(id) {
  if (confirm("Are you sure you want to delete?")) {
    formDelete.delete(route("permission.destroy", id));
  }
}
</script>
<template>
  <Head title="Permissions" />
<BreezeAuthenticatedLayout>
    <template #header>
      <h2 class="font-semibold text-xl text-gray-800 leading-tight">
        Permissions
      </h2>
    </template>
    <div class="py-12">
      <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
        <div
          v-if="$page.props.flash.message"
          class="
            p-4
            mb-4
            text-sm text-green-700
            bg-green-100
            rounded-lg
            dark:bg-green-200 dark:text-green-800
          "
          role="alert"
        >
          <span class="font-medium">
            {{ $page.props.flash.message }}
          </span>
        </div>
        <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
          <div class="p-6 bg-white border-b border-gray-200">
            <div class="flex flex-col mt-8">
              <div class="d-print-none with-border mb-8">
                <Link
                  :href="route('permission.create')"
                  class="
                    text-white
                    bg-blue-700
                    hover:bg-blue-800
                    focus:ring-4 focus:ring-blue-300
                    font-medium
                    rounded-lg
                    text-sm
                    px-5
                    py-2.5
                    text-center
                    mr-2
                    mb-2
                    dark:bg-blue-600
                    dark:hover:bg-blue-700
                    dark:focus:ring-blue-800
                  "
                  >Add Permission</Link
                >
              </div>
              <div class="py-2">
                <div
                  class="
                    min-w-full
                    border-b border-gray-200
                    shadow
                    overflow-x-auto
                  "
                >
                  <form @submit.prevent="form.get(route('permission.index'))">
                    <div class="py-2 flex">
                      <div class="flex pl-4">
                        <input
                          type="search"
                          v-model="form.search"
                          class="
                            rounded-md
                            shadow-sm
                            border-gray-300
                            focus:border-indigo-300
                            focus:ring
                            focus:ring-indigo-200
                            focus:ring-opacity-50
                          "
                          placeholder="Search"
                        />
                        <button
                          type="submit"
                          class="
                            ml-4
                            inline-flex
                            items-center
                            px-4
                            py-2
                            bg-gray-800
                            border border-transparent
                            rounded-md
                            font-semibold
                            text-xs text-white
                            uppercase
                            tracking-widest
                            hover:bg-gray-700
                            active:bg-gray-900
                            focus:outline-none focus:border-gray-900 focus:ring
                            ring-gray-300
                            disabled:opacity-25
                            transition
                            ease-in-out
                            duration-150
                          "
                        >
                          Search
                        </button>
                      </div>
                    </div>
                  </form>
                  <table class="border-collapse table-auto w-full text-sm">
                    <thead>
                      <tr>
                        <th
                          class="
                            py-2
                            px-4
                            bg-gray-50
                            font-bold
                            uppercase
                            text-sm text-grey-dark
                            border-b border-grey-light
                            text-left
                          "
                        >
                          <Sort label="Name" attribute="name" />
                        </th>
                        <th
                          class="
                            py-2
                            px-4
                            bg-gray-50
                            font-bold
                            uppercase
                            text-sm text-grey-dark
                            border-b border-grey-light
                            text-left
                          "
                        >
                          Actions
                        </th>
                      </tr>
                    </thead>
                    <tbody class="bg-white dark:bg-slate-800">
                      <tr
                        v-for="permission in permissions.data"
                        :key="permission.id"
                      >
                        <td
                          class="
                            border-b border-slate-100
                            dark:border-slate-700
                            p-4
                            pl-8
                            text-slate-500
                            dark:text-slate-400
                          "
                        >
                          <div class="text-sm text-gray-900">
                            <Link
                              :href="route('permission.show', permission.id)"
                              class="
                                no-underline
                                hover:underline
                                text-cyan-600
                                dark:text-cyan-400
                              "
                              >{{ permission.name }}</Link
                            >
                          </div>
                        </td>
                        <td
                          class="
                            border-b border-slate-100
                            dark:border-slate-700
                            p-4
                            pl-8
                            text-slate-500
                            dark:text-slate-400
                          "
                        >
                          <div class="flex">
                            <Link
                              :href="route('permission.edit', permission.id)"
                              class="
                                inline-flex
                                items-center
                                px-4
                                py-2
                                text-white
                                mr-4
                                bg-blue-600
                                border border-transparent
                                rounded-md
                                font-semibold
                                text-xs text-white
                                uppercase
                                tracking-widest
                                hover:bg-gray-700
                                active:bg-gray-900
                                focus:outline-none
                                focus:border-gray-900
                                focus:shadow-outline-gray
                                transition
                                ease-in-out
                                duration-150
                                px-4
                                py-2
                                text-white
                              "
                            >
                              Edit
                            </Link>
                            <BreezeButton
                              class="px-4 py-2 text-white bg-red-600"
                              @click="destroy(permission.id)"
                            >
                              Delete
                            </BreezeButton>
                          </div>
                        </td>
                      </tr>
                    </tbody>
                  </table>
                </div>
                <div class="py-8">
                  <Pagination class="mt-6" :data="permissions" />
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </BreezeAuthenticatedLayout>
</template>

Репозиторий GitHub

Панель администратора Laravel Vue доступна на https://github.com/balajidharma/laravel-vue-admin-panel. Установите панель администратора и поделитесь своим мнением.

Спасибо за чтение.

Оставайтесь с нами, чтобы узнать больше!

Подпишитесь на меня balajidharma.medium.com.

Предыдущая часть — Часть 3: Создание Laravel CRUD, создание и обновление страниц с использованием Inertia и Vue

Следующая часть — Часть 5: Авторизация Laravel CRUD с помощью Inertia и Vue — Контроль доступа с использованием роли и разрешения