mirror of
https://github.com/nagisa77/OpenIsle.git
synced 2026-02-21 22:41:05 +08:00
Merge pull request #168 from nagisa77/2gqwih-codex
Fix filter dropdown preloading
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<Dropdown v-model="selected" :fetch-options="fetchCategories" placeholder="选择分类">
|
||||
<Dropdown v-model="selected" :fetch-options="fetchCategories" placeholder="选择分类" :initial-options="providedOptions">
|
||||
<template #option="{ option }">
|
||||
<div class="option-container">
|
||||
<div class="option-main">
|
||||
@@ -17,7 +17,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { computed } from 'vue'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { API_BASE_URL } from '../main'
|
||||
import Dropdown from './Dropdown.vue'
|
||||
|
||||
@@ -25,11 +25,24 @@ export default {
|
||||
name: 'CategorySelect',
|
||||
components: { Dropdown },
|
||||
props: {
|
||||
modelValue: { type: [String, Number], default: '' }
|
||||
modelValue: { type: [String, Number], default: '' },
|
||||
options: { type: Array, default: () => [] }
|
||||
},
|
||||
emits: ['update:modelValue'],
|
||||
setup(props, { emit }) {
|
||||
const providedOptions = ref(Array.isArray(props.options) ? [...props.options] : [])
|
||||
|
||||
watch(
|
||||
() => props.options,
|
||||
val => {
|
||||
providedOptions.value = Array.isArray(val) ? [...val] : []
|
||||
}
|
||||
)
|
||||
|
||||
const fetchCategories = async () => {
|
||||
if (providedOptions.value.length) {
|
||||
return [{ id: '', name: '无分类' }, ...providedOptions.value]
|
||||
}
|
||||
const res = await fetch(`${API_BASE_URL}/api/categories`)
|
||||
if (!res.ok) return []
|
||||
const data = await res.json()
|
||||
@@ -46,7 +59,7 @@ export default {
|
||||
set: v => emit('update:modelValue', v)
|
||||
})
|
||||
|
||||
return { fetchCategories, selected, isImageIcon }
|
||||
return { fetchCategories, selected, isImageIcon, providedOptions }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -71,7 +71,8 @@ export default {
|
||||
remote: { type: Boolean, default: false },
|
||||
menuClass: { type: String, default: '' },
|
||||
optionClass: { type: String, default: '' },
|
||||
showSearch: { type: Boolean, default: true }
|
||||
showSearch: { type: Boolean, default: true },
|
||||
initialOptions: { type: Array, default: () => [] }
|
||||
},
|
||||
emits: ['update:modelValue'],
|
||||
setup(props, { emit }) {
|
||||
@@ -80,7 +81,7 @@ export default {
|
||||
const setSearch = (val) => {
|
||||
search.value = val
|
||||
}
|
||||
const options = ref([])
|
||||
const options = ref(Array.isArray(props.initialOptions) ? [...props.initialOptions] : [])
|
||||
const loaded = ref(false)
|
||||
const loading = ref(false)
|
||||
const wrapper = ref(null)
|
||||
@@ -136,6 +137,15 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.initialOptions,
|
||||
val => {
|
||||
if (Array.isArray(val)) {
|
||||
options.value = [...val]
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
watch(open, async val => {
|
||||
if (val) {
|
||||
if (props.remote) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<Dropdown v-model="selected" :fetch-options="fetchTags" multiple placeholder="选择标签" remote>
|
||||
<Dropdown v-model="selected" :fetch-options="fetchTags" multiple placeholder="选择标签" remote :initial-options="mergedOptions">
|
||||
<template #option="{ option }">
|
||||
<div class="option-container">
|
||||
<div class="option-main">
|
||||
@@ -17,7 +17,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { API_BASE_URL, toast } from '../main'
|
||||
import Dropdown from './Dropdown.vue'
|
||||
|
||||
@@ -26,11 +26,25 @@ export default {
|
||||
components: { Dropdown },
|
||||
props: {
|
||||
modelValue: { type: Array, default: () => [] },
|
||||
creatable: { type: Boolean, default: false }
|
||||
creatable: { type: Boolean, default: false },
|
||||
options: { type: Array, default: () => [] }
|
||||
},
|
||||
emits: ['update:modelValue'],
|
||||
setup(props, { emit }) {
|
||||
const localTags = ref([])
|
||||
const providedTags = ref(Array.isArray(props.options) ? [...props.options] : [])
|
||||
|
||||
watch(
|
||||
() => props.options,
|
||||
val => {
|
||||
providedTags.value = Array.isArray(val) ? [...val] : []
|
||||
}
|
||||
)
|
||||
|
||||
const mergedOptions = computed(() => {
|
||||
const arr = [...providedTags.value, ...localTags.value]
|
||||
return arr.filter((v, i, a) => a.findIndex(t => t.id === v.id) === i)
|
||||
})
|
||||
|
||||
const isImageIcon = icon => {
|
||||
if (!icon) return false
|
||||
@@ -38,17 +52,21 @@ export default {
|
||||
}
|
||||
|
||||
const fetchTags = async (kw = '') => {
|
||||
const url = new URL(`${API_BASE_URL}/api/tags`)
|
||||
if (kw) url.searchParams.set('keyword', kw)
|
||||
url.searchParams.set('limit', '10')
|
||||
let data = []
|
||||
try {
|
||||
const res = await fetch(url.toString())
|
||||
if (res.ok) {
|
||||
data = await res.json()
|
||||
if (!kw && providedTags.value.length) {
|
||||
data = [...providedTags.value]
|
||||
} else {
|
||||
const url = new URL(`${API_BASE_URL}/api/tags`)
|
||||
if (kw) url.searchParams.set('keyword', kw)
|
||||
url.searchParams.set('limit', '10')
|
||||
try {
|
||||
const res = await fetch(url.toString())
|
||||
if (res.ok) {
|
||||
data = await res.json()
|
||||
}
|
||||
} catch {
|
||||
toast.error('获取标签失败')
|
||||
}
|
||||
} catch {
|
||||
toast.error('获取标签失败')
|
||||
}
|
||||
|
||||
let options = [...data, ...localTags.value]
|
||||
@@ -91,7 +109,7 @@ export default {
|
||||
}
|
||||
})
|
||||
|
||||
return { fetchTags, selected, isImageIcon }
|
||||
return { fetchTags, selected, isImageIcon, mergedOptions }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
>
|
||||
{{ topic }}
|
||||
</div>
|
||||
<CategorySelect v-model="selectedCategory" />
|
||||
<TagSelect v-model="selectedTags" />
|
||||
<CategorySelect v-model="selectedCategory" :options="categoryOptions" />
|
||||
<TagSelect v-model="selectedTags" :options="tagOptions" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -131,6 +131,8 @@ export default {
|
||||
.map(v => decodeURIComponent(v))
|
||||
.map(v => (isNaN(v) ? v : Number(v)))
|
||||
}
|
||||
const tagOptions = ref([])
|
||||
const categoryOptions = ref([])
|
||||
const isLoadingPosts = ref(false)
|
||||
const topics = ref(['最新', '排行榜' /*, '热门', '类别'*/])
|
||||
const selectedTopic = ref(route.query.view === 'ranking' ? '排行榜' : '最新')
|
||||
@@ -140,6 +142,30 @@ export default {
|
||||
const pageSize = 5
|
||||
const allLoaded = ref(false)
|
||||
|
||||
const loadOptions = async () => {
|
||||
if (selectedCategory.value && !isNaN(selectedCategory.value)) {
|
||||
try {
|
||||
const res = await fetch(`${API_BASE_URL}/api/categories/${selectedCategory.value}`)
|
||||
if (res.ok) {
|
||||
categoryOptions.value = [await res.json()]
|
||||
}
|
||||
} catch (e) { /* ignore */ }
|
||||
}
|
||||
|
||||
if (selectedTags.value.length) {
|
||||
const arr = []
|
||||
for (const t of selectedTags.value) {
|
||||
if (!isNaN(t)) {
|
||||
try {
|
||||
const r = await fetch(`${API_BASE_URL}/api/tags/${t}`)
|
||||
if (r.ok) arr.push(await r.json())
|
||||
} catch (e) { /* ignore */ }
|
||||
}
|
||||
}
|
||||
tagOptions.value = arr
|
||||
}
|
||||
}
|
||||
|
||||
const buildUrl = () => {
|
||||
let url = `${API_BASE_URL}/api/posts?page=${page.value}&pageSize=${pageSize}`
|
||||
if (selectedCategory.value) {
|
||||
@@ -249,7 +275,8 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
await loadOptions()
|
||||
if (selectedTopic.value === '排行榜') {
|
||||
fetchRanking()
|
||||
} else {
|
||||
@@ -275,7 +302,7 @@ export default {
|
||||
|
||||
const sanitizeDescription = (text) => stripMarkdown(text)
|
||||
|
||||
return { topics, selectedTopic, articles, sanitizeDescription, isLoadingPosts, handleScroll, selectedCategory, selectedTags }
|
||||
return { topics, selectedTopic, articles, sanitizeDescription, isLoadingPosts, handleScroll, selectedCategory, selectedTags, tagOptions, categoryOptions }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user