mirror of
https://github.com/nagisa77/OpenIsle.git
synced 2026-05-11 05:07:28 +08:00
feat(frontend_nuxt): fetch menu data server-side
This commit is contained in:
@@ -115,7 +115,7 @@
|
|||||||
import { themeState, cycleTheme, ThemeMode } from '~/utils/theme'
|
import { themeState, cycleTheme, ThemeMode } from '~/utils/theme'
|
||||||
import { authState } from '~/utils/auth'
|
import { authState } from '~/utils/auth'
|
||||||
import { fetchUnreadCount, notificationState } from '~/utils/notification'
|
import { fetchUnreadCount, notificationState } from '~/utils/notification'
|
||||||
import { watch } from 'vue'
|
import { ref, computed, watch, onMounted } from 'vue'
|
||||||
import { API_BASE_URL } from '~/main'
|
import { API_BASE_URL } from '~/main'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -126,18 +126,42 @@ export default {
|
|||||||
default: true
|
default: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
async setup(props, { emit }) {
|
||||||
return {
|
const categories = ref([])
|
||||||
categories: [],
|
const tags = ref([])
|
||||||
tags: [],
|
const categoryOpen = ref(true)
|
||||||
categoryOpen: true,
|
const tagOpen = ref(true)
|
||||||
tagOpen: true,
|
|
||||||
isLoadingCategory: false,
|
const { data: categoryData, pending: isLoadingCategory } = await useFetch(
|
||||||
isLoadingTag: false
|
`${API_BASE_URL}/api/categories`,
|
||||||
}
|
{ server: true }
|
||||||
},
|
)
|
||||||
computed: {
|
const { data: tagData, pending: isLoadingTag } = await useFetch(
|
||||||
iconClass() {
|
`${API_BASE_URL}/api/tags?limit=10`,
|
||||||
|
{ server: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
categoryData,
|
||||||
|
(val) => {
|
||||||
|
categories.value = (val || []).slice(0, 10)
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
)
|
||||||
|
watch(
|
||||||
|
tagData,
|
||||||
|
(val) => {
|
||||||
|
tags.value = val || []
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
localStorage.setItem('menu-categories', JSON.stringify(categories.value))
|
||||||
|
localStorage.setItem('menu-tags', JSON.stringify(tags.value))
|
||||||
|
})
|
||||||
|
|
||||||
|
const iconClass = computed(() => {
|
||||||
switch (themeState.mode) {
|
switch (themeState.mode) {
|
||||||
case ThemeMode.DARK:
|
case ThemeMode.DARK:
|
||||||
return 'fas fa-moon'
|
return 'fas fa-moon'
|
||||||
@@ -146,18 +170,14 @@ export default {
|
|||||||
default:
|
default:
|
||||||
return 'fas fa-desktop'
|
return 'fas fa-desktop'
|
||||||
}
|
}
|
||||||
},
|
})
|
||||||
unreadCount() {
|
|
||||||
return notificationState.unreadCount
|
const unreadCount = computed(() => notificationState.unreadCount)
|
||||||
},
|
const showUnreadCount = computed(() =>
|
||||||
showUnreadCount() {
|
unreadCount.value > 99 ? '99+' : unreadCount.value
|
||||||
return this.unreadCount > 99 ? '99+' : this.unreadCount
|
)
|
||||||
},
|
const shouldShowStats = computed(() => authState.role === 'ADMIN')
|
||||||
shouldShowStats() {
|
|
||||||
return authState.role === 'ADMIN'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async mounted() {
|
|
||||||
const updateCount = async () => {
|
const updateCount = async () => {
|
||||||
if (authState.loggedIn) {
|
if (authState.loggedIn) {
|
||||||
await fetchUnreadCount()
|
await fetchUnreadCount()
|
||||||
@@ -165,94 +185,58 @@ export default {
|
|||||||
notificationState.unreadCount = 0
|
notificationState.unreadCount = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(() => authState.loggedIn, async () => {
|
onMounted(async () => {
|
||||||
await updateCount()
|
await updateCount()
|
||||||
|
watch(() => authState.loggedIn, updateCount)
|
||||||
})
|
})
|
||||||
|
|
||||||
const CAT_CACHE_KEY = 'menu-categories'
|
const router = useRouter()
|
||||||
const TAG_CACHE_KEY = 'menu-tags'
|
|
||||||
|
|
||||||
const cachedCategories = localStorage.getItem(CAT_CACHE_KEY)
|
const handleHomeClick = () => {
|
||||||
if (cachedCategories) {
|
router.push('/').then(() => {
|
||||||
try {
|
|
||||||
this.categories = JSON.parse(cachedCategories)
|
|
||||||
} catch { /* ignore */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
const cachedTags = localStorage.getItem(TAG_CACHE_KEY)
|
|
||||||
if (cachedTags) {
|
|
||||||
try {
|
|
||||||
this.tags = JSON.parse(cachedTags)
|
|
||||||
} catch { /* ignore */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isLoadingCategory = !cachedCategories
|
|
||||||
this.isLoadingTag = !cachedTags
|
|
||||||
|
|
||||||
const fetchCategories = () => {
|
|
||||||
fetch(`${API_BASE_URL}/api/categories`).then(res => {
|
|
||||||
if (res.ok) {
|
|
||||||
res.json().then(data => {
|
|
||||||
this.categories = data.slice(0, 10)
|
|
||||||
localStorage.setItem(CAT_CACHE_KEY, JSON.stringify(this.categories))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.isLoadingCategory = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const fetchTags = () => {
|
|
||||||
fetch(`${API_BASE_URL}/api/tags?limit=10`).then(res => {
|
|
||||||
if (res.ok) {
|
|
||||||
res.json().then(data => {
|
|
||||||
this.tags = data
|
|
||||||
localStorage.setItem(TAG_CACHE_KEY, JSON.stringify(this.tags))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.isLoadingTag = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cachedCategories) {
|
|
||||||
setTimeout(fetchCategories, 1500)
|
|
||||||
} else {
|
|
||||||
fetchCategories()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cachedTags) {
|
|
||||||
setTimeout(fetchTags, 1500)
|
|
||||||
} else {
|
|
||||||
fetchTags()
|
|
||||||
}
|
|
||||||
|
|
||||||
await updateCount()
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
cycleTheme,
|
|
||||||
handleHomeClick() {
|
|
||||||
this.$router.push('/').then(() => {
|
|
||||||
window.location.reload()
|
window.location.reload()
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
handleItemClick() {
|
|
||||||
if (window.innerWidth <= 768) this.$emit('item-click')
|
const handleItemClick = () => {
|
||||||
},
|
if (window.innerWidth <= 768) emit('item-click')
|
||||||
isImageIcon(icon) {
|
}
|
||||||
|
|
||||||
|
const isImageIcon = (icon) => {
|
||||||
if (!icon) return false
|
if (!icon) return false
|
||||||
return /^https?:\/\//.test(icon) || icon.startsWith('/')
|
return /^https?:\/\//.test(icon) || icon.startsWith('/')
|
||||||
},
|
}
|
||||||
gotoCategory(c) {
|
|
||||||
|
const gotoCategory = (c) => {
|
||||||
const value = encodeURIComponent(c.id ?? c.name)
|
const value = encodeURIComponent(c.id ?? c.name)
|
||||||
this.$router
|
router.push({ path: '/', query: { category: value } })
|
||||||
.push({ path: '/', query: { category: value } })
|
handleItemClick()
|
||||||
this.handleItemClick()
|
}
|
||||||
},
|
|
||||||
gotoTag(t) {
|
const gotoTag = (t) => {
|
||||||
const value = encodeURIComponent(t.id ?? t.name)
|
const value = encodeURIComponent(t.id ?? t.name)
|
||||||
this.$router
|
router.push({ path: '/', query: { tags: value } })
|
||||||
.push({ path: '/', query: { tags: value } })
|
handleItemClick()
|
||||||
this.handleItemClick()
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
categories,
|
||||||
|
tags,
|
||||||
|
categoryOpen,
|
||||||
|
tagOpen,
|
||||||
|
isLoadingCategory,
|
||||||
|
isLoadingTag,
|
||||||
|
iconClass,
|
||||||
|
unreadCount,
|
||||||
|
showUnreadCount,
|
||||||
|
shouldShowStats,
|
||||||
|
cycleTheme,
|
||||||
|
handleHomeClick,
|
||||||
|
handleItemClick,
|
||||||
|
isImageIcon,
|
||||||
|
gotoCategory,
|
||||||
|
gotoTag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user