Files
pokopiawiki.tootaio.com/frontend/src/views/PokemonList.vue
2026-04-29 17:46:58 +08:00

106 lines
3.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { computed, onMounted, ref, watch } from 'vue';
import EntityChips from '../components/EntityChips.vue';
import { api, type Options, type Pokemon } from '../services/api';
const options = ref<Options | null>(null);
const pokemon = ref<Pokemon[]>([]);
const loading = ref(true);
const search = ref('');
const environmentId = ref('');
const skillIds = ref<string[]>([]);
const skillMode = ref<'any' | 'all'>('any');
const favoriteThingIds = ref<string[]>([]);
const favoriteThingMode = ref<'any' | 'all'>('any');
const query = computed(() => ({
search: search.value,
environmentId: environmentId.value,
skillIds: skillIds.value.join(','),
skillMode: skillMode.value,
favoriteThingIds: favoriteThingIds.value.join(','),
favoriteThingMode: favoriteThingMode.value
}));
async function loadPokemon() {
loading.value = true;
pokemon.value = await api.pokemon(query.value);
loading.value = false;
}
onMounted(async () => {
options.value = await api.options();
await loadPokemon();
});
watch(query, loadPokemon);
</script>
<template>
<section>
<div class="page-header">
<div>
<h1 class="page-title">Pokemon</h1>
<p class="page-subtitle">搜索宝可梦并按特长环境喜欢的东西筛选</p>
</div>
</div>
<div v-if="options" class="toolbar">
<div class="field">
<label for="pokemon-search">搜索</label>
<input id="pokemon-search" v-model="search" type="search" placeholder="名字" />
</div>
<div class="field">
<label for="environment">喜欢的环境</label>
<select id="environment" v-model="environmentId">
<option value="">全部</option>
<option v-for="item in options.environments" :key="item.id" :value="item.id">
{{ item.name }}
</option>
</select>
</div>
<div class="field">
<label for="skills">特长</label>
<select id="skills" v-model="skillIds" multiple>
<option v-for="item in options.skills" :key="item.id" :value="String(item.id)">
{{ item.name }}{{ item.subcategory ? ` · ${item.subcategory}` : '' }}
</option>
</select>
<div class="segmented" aria-label="特长匹配方式">
<button :class="{ active: skillMode === 'any' }" type="button" @click="skillMode = 'any'">任意</button>
<button :class="{ active: skillMode === 'all' }" type="button" @click="skillMode = 'all'">全部</button>
</div>
</div>
<div class="field">
<label for="favorite-things">喜欢的东西</label>
<select id="favorite-things" v-model="favoriteThingIds" multiple>
<option v-for="item in options.favoriteThings" :key="item.id" :value="String(item.id)">
{{ item.name }}
</option>
</select>
<div class="segmented" aria-label="喜欢的东西匹配方式">
<button :class="{ active: favoriteThingMode === 'any' }" type="button" @click="favoriteThingMode = 'any'">
任意
</button>
<button :class="{ active: favoriteThingMode === 'all' }" type="button" @click="favoriteThingMode = 'all'">
全部
</button>
</div>
</div>
</div>
<p v-if="loading" class="status">加载中</p>
<div v-else class="grid">
<RouterLink v-for="item in pokemon" :key="item.id" class="entity-card" :to="`/pokemon/${item.id}`">
<h2>#{{ item.id }} {{ item.name }}</h2>
<p class="meta-line">喜欢的环境{{ item.environment.name }}</p>
<EntityChips :items="item.skills" />
<EntityChips :items="item.favorite_things" />
</RouterLink>
</div>
</section>
</template>