rick-and-morty-vue3

Форк
0
195 строк · 5.2 Кб
1
<template>
2
  <!-- Общая информация о количестве персонажей, локаций и эпизодов -->
3
  <section class="info">
4
    <p>Персонажи: {{ info.countCharacters }}</p>
5
    <p>Локации: {{ info.countLocations }}</p>
6
    <p>Эпизоды: {{ info.countEpisodes }}</p>
7
  </section>
8

9
  <!-- Поля фильтрации по имени, статусу и полу -->
10
  <section class="filter">    
11
    <Input
12
      v-model="filters.name"
13
      placeholder="Искать по имени..."
14
      @keydown.enter="handleSearch"
15
    />
16
    <Select
17
      v-model="filters.status"
18
      :options="statuses"
19
      placeholder="Выбрать статус"
20
      @keydown.enter="handleSearch"
21
    />
22
    <Select
23
      v-model="filters.gender"
24
      :options="genders"
25
      placeholder="Выбрать пол"
26
      @keydown.enter="handleSearch"
27
    />
28
    <Button @click="handleSearch" :disabled="!isSearchEnabled">Поиск</Button>
29
  </section>
30

31
  <!-- Отображение списка карточек персонажей -->
32
  <section class="section">
33
    <div class="card-list">
34
      <Card
35
        v-for="character in paginatedCharacters"
36
        :key="character.id"
37
        :character="character"
38
      />
39
    </div>
40
    <Loader v-if="loading" />
41
  </section>
42

43
  <!-- Элемент выбора количества карточек на страницу -->
44
  <section class="section">
45
    <ItemsPerPage v-model="cardsPerPage" />
46
  </section>
47

48
  <!-- Пагинация -->
49
  <section class="section">
50
    <Pagination
51
      :currentPage="currentPage"
52
      :hasMoreCharacters="hasMoreCharacters"
53
      @prevPage="prevPage"
54
      @nextPage="nextPage"
55
    />
56
  </section>
57

58
  <!-- Кнопка "Вверх" -->
59
  <ScrollToTop />
60
</template>
61

62
<script setup>
63
import { onMounted, ref, computed } from "vue";
64
import { useCharacters } from "@/services/useCharacters";
65
import ItemsPerPage from "@/components/ItemsPerPage.vue";
66
import Pagination from "@/components/Pagination.vue";
67
import Input from "@/components/Input.vue";
68
import Select from "@/components/Select.vue";
69
import Button from "@/components/Button.vue";
70
import Card from "@/components/Card.vue";
71
import Loader from "@/components/Loader.vue";
72
import ScrollToTop from "@/components/ScrollToTop.vue";
73

74
// Варианты выбора фильтров на русском языке
75
const statusMap = {
76
  Alive: "Живой",
77
  Dead: "Мёртвый",
78
  Unknown: "Неизвестно",
79
};
80

81
const genderMap = {
82
  Male: "Мужской",
83
  Female: "Женский",
84
  Genderless: "Бесполый",
85
  Unknown: "Неизвестно",
86
};
87

88
// Опции Select, которые будут отображаться на русском
89
const statuses = Object.values(statusMap);
90
const genders = Object.values(genderMap);
91

92
// Фильтры для поиска
93
const filters = ref({
94
  name: "",
95
  status: "",
96
  gender: "",
97
});
98

99
// Параметры пагинации
100
const cardsPerPage = ref(10);
101
const currentPage = ref(1);
102

103
// Получение данных персонажей и информации
104
const { characters, loading, loadCharacters, resetCharacters, info, loadInfo } = useCharacters();
105

106
// Отображение карточек на текущей странице
107
const paginatedCharacters = computed(() => {
108
  const start = (currentPage.value - 1) * cardsPerPage.value;
109
  const end = start + cardsPerPage.value;
110
  return characters.value.slice(start, end);
111
});
112

113
const hasMoreCharacters = computed(() => {
114
  return characters.value.length > currentPage.value * cardsPerPage.value;
115
});
116

117
// Функция поиска персонажей по фильтрам
118
const handleSearch = () => {
119
  // Преобразование выбранных фильтров на русском обратно в английский для API
120
  const translatedFilters = {
121
    name: filters.value.name,
122
    status: Object.keys(statusMap).find(
123
      (key) => statusMap[key] === filters.value.status
124
    ),
125
    gender: Object.keys(genderMap).find(
126
      (key) => genderMap[key] === filters.value.gender
127
    ),
128
  };
129

130
  resetCharacters();
131
  loadCharacters(translatedFilters);
132
};
133

134
// Переход по страницам
135
const prevPage = () => {
136
  if (currentPage.value > 1) {
137
    currentPage.value--;
138
  }
139
};
140

141
const nextPage = () => {
142
  if (hasMoreCharacters.value) {
143
    currentPage.value++;
144
  }
145
};
146

147
// Проверка, включена ли кнопка поиска
148
const isSearchEnabled = computed(() => {
149
  return filters.value.name || filters.value.status || filters.value.gender;
150
});
151

152
// Начальная загрузка данных
153
onMounted(async () => {
154
  await loadCharacters(filters.value);
155
  await loadInfo();
156
});
157

158
</script>
159

160
<style lang="scss" scoped>
161
.section {
162
  display: flex;
163
  justify-content: center;
164
  margin: 0;
165
  padding: 1rem;
166
}
167

168
.card-list {
169
  display: flex;
170
  justify-content: center;
171
  flex-wrap: wrap;
172
  gap: 8px;
173
}
174

175
.filter {
176
  width: auto;
177
  display: flex;
178
  justify-content: center;
179
  padding: 5px 20px;
180
  gap: 1rem;
181

182
  @media (max-width: 480px) {
183
    flex-direction: column;
184
    padding: 0px 20px;
185
  }
186
}
187

188
.info {
189
  display: flex;
190
  justify-content: center;
191
  gap: 10px;
192
  text-align: center;
193
  color: rgb(158, 158, 158);
194
}
195
</style>
196

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.