修正了一堆东西

This commit is contained in:
Jeffrey Hsu 2024-12-01 13:09:44 +08:00
parent 376b5964a1
commit 6e3f55480a
19 changed files with 246 additions and 110 deletions

View File

@ -1,8 +0,0 @@
import {request} from "~/composables/network";
export async function getBlogRecentPost(): Promise<IBlogResponse<IPostsData>> {
return request({
url: "/blog/index.php/api/posts",
method: "get"
})
}

View File

@ -1,16 +0,0 @@
import {request} from "~/composables/network";
const TOKEN: string = "fb8aec429ea7d0a36f7238dbffda9d2d66c7b045"
export async function getActivity(): Promise<IActivity[]> {
return request({
url: '/git/api/v1/users/cantyonion/activities/feeds',
method: 'get',
headers: {
Authorization: ` ${TOKEN}`,
},
params: {
limit: 10
}
})
}

View File

@ -16,8 +16,8 @@ emitter.on('startLoading', on => {
<div ref="loading" class="loading"></div> <div ref="loading" class="loading"></div>
<div class="relative flex min-h-screen flex-col overflow-hidden bg-blue-50"> <div class="relative flex min-h-screen flex-col overflow-hidden bg-blue-50">
<nav-bar/> <nav-bar/>
<NuxtPage/> <nuxt-page/>
<footer-main/> <footer-main/>
<alert-notification/>
</div> </div>
</template> </template>

View File

@ -0,0 +1,47 @@
<script lang="ts" setup>
const notifications = ref<INotification[]>([]);
const typeClasses = {
success: 'bg-green-100 text-green-800 border border-green-400',
error: 'bg-red-100 text-red-800 border border-red-400',
warning: 'bg-yellow-100 text-yellow-800 border border-yellow-400',
info: 'bg-blue-100 text-blue-800 border border-blue-400',
};
const addNotification = (notification: INotification) => {
notifications.value.push(notification);
//
setTimeout(() => {
notifications.value.shift();
}, 5000);
console.log(1)
};
emitter.on('eventBus', addNotification)
onBeforeUnmount(() => {
emitter.off('eventBus', addNotification);
});
</script>
<template>
<div class="fixed top-5 right-5 space-y-4 z-50">
<div
v-for="(notification, index) in notifications"
:key="index"
:class="[
'p-4 rounded-lg shadow-lg transition-all duration-300',
typeClasses[notification.level]
]"
>
<h3 class="font-bold text-lg">{{ notification.title }}</h3>
<p>{{ notification.message }}</p>
</div>
</div>
</template>
<style scoped>
</style>

View File

@ -30,7 +30,7 @@ const handleReload = () => {
</div> </div>
<div v-else> <div v-else>
<!-- 正式内容 --> <!-- 正式内容 -->
<span v-if="empty" class="text-2xl font-bold">最近没有动态</span> <span v-if="empty" class="text-center text-2xl font-bold">最近没有动态</span>
<slot v-else name="default"/> <slot v-else name="default"/>
</div> </div>
</div> </div>

View File

@ -7,6 +7,12 @@ type Widget = {
title: string title: string
} }
const props = defineProps({
navColor: {
default: false,
type: Boolean
}
})
// 使 ref // 使 ref
const scrolled = ref(false) const scrolled = ref(false)
const littleWidget: Widget[] = [ const littleWidget: Widget[] = [
@ -94,7 +100,7 @@ const handleScroll = () => {
const debouncedScroll = debounce(handleScroll, 10) const debouncedScroll = debounce(handleScroll, 10)
const alwaysBlueBackground = computed(() => route.name !== 'index') const alwaysBlueBackground = computed(() => route.name !== 'index' || props.navColor)
// //
onMounted(() => { onMounted(() => {

View File

@ -3,6 +3,7 @@ import mitt from 'mitt'
type Events = { type Events = {
openPost: IPost openPost: IPost
startLoading: boolean startLoading: boolean
eventBus: INotification
} }
const emitter = mitt<Events>() const emitter = mitt<Events>()

View File

@ -1,7 +1,9 @@
export const getAssetURL = (image: string) => { export const getAssetURL = (image: string) => {
// 参数一: 相对路径 // 参数一: 相对路径
// 参数二: 当前路径的URL // 参数二: 当前路径的URL
return new URL(`../assets/images/${image}`, import.meta.url).href if (import.meta.client)
return new URL(`../assets/images/${image}`, import.meta.url).href
return `/_nuxt/assets/images/${image}`
} }
export const debounce = (fn: Function, delay: number) => { export const debounce = (fn: Function, delay: number) => {

View File

@ -1,24 +1,53 @@
import axios from 'axios' import type { AsyncData, UseFetchOptions } from '#app'
import type {AxiosRequestConfig, AxiosError} from 'axios'
export async function request<T = unknown>(config: AxiosRequestConfig<any>): Promise<T> { export function requestCore<DataT>(url: string, options: UseFetchOptions<DataT>) {
const instance = axios.create({ // const config = useRuntimeConfig()
baseURL: import.meta.env.VITE_BASE_URL, return useFetch(url, {
timeout: 5000, baseURL: "https://cantyonion.site",
headers: {}, retry: false,
onRequest({ options }) {
let token: string = ""
if (import.meta.client) {
token = localStorage.getItem("token") || ""
}
if (!options.headers.get('Authorization'))
options.headers.set('Authorization', `Bearer ${token}`)
},
onResponse({ response }) {
// HTTP状态码2XX/3XX执行否则不执行
if (response.status < 200 || response.status >= 400) {
console.error(`HTTP 错误: ${response.status}`)
return
}
// 业务code状态码判断
// if (response._data.code !== 200) {
//
// }
},
onResponseError({ response }) {
emitter.emit('eventBus', {
level: 'error',
title: `HTTP错误${response.status}`,
message: response.statusText
})
},
...options
}) })
}
instance.interceptors.request.use(config => {
return config export function get<DataT, ErrorT>(url: string, options?: UseFetchOptions<DataT>): () => Promise<DataT> {
}, error => error) let result: AsyncData<DataT, ErrorT> | null = null
// bug fixed on csdn https://blog.csdn.net/qq_45325810/article/details/120704910 return async (): Promise<DataT> => {
instance.interceptors.response.use(resource => { if (result != null) {
if (resource.status === 200) return resource await result.refresh()
return Promise.reject(new Error(resource.data)) return result.data.value
}, (error: AxiosError) => { }
return Promise.reject(error.response ? error.response.data : error.code)
}) result = await requestCore(url, {
method: 'GET',
return instance.request<T>(config).then(res => res.data) ...options,
}) as AsyncData<DataT, ErrorT>
return result.data.value
}
} }

60
error.vue Normal file
View File

@ -0,0 +1,60 @@
<script setup lang="ts">
import type { NuxtError } from '#app'
const props = defineProps({
error: Object as () => NuxtError
})
const errorMessages: Record<string, { icon: string; title: string; message: string }> = {
'400': {
icon: '❓',
title: '哦豁!请求有点问题',
message: '请求似乎有点小问题,服务器君有点摸不着头脑呢!',
},
'403': {
icon: '🔒',
title: '哎呀!大门被锁住了',
message: '你没有权限访问这个角落,试试返回首页吧!',
},
'404': {
icon: '🌌',
title: '哎呀!你发现了超级基地的秘密角落',
message: '看起来你找的页面藏到了未知的时空层里!',
},
'500': {
icon: '🚀',
title: '糟糕!超级基地出了一点故障',
message: '服务器君正在努力解决问题,请稍等片刻!',
},
'502': {
icon: '👽',
title: '糟糕!基地信号被外星人拦截了',
message: '网络通道似乎遇到了问题,请稍后再试!',
},
default: {
icon: '⚠️',
title: '哦豁!此时遇到了点小麻烦',
message: '请求在穿越洋葱星球时迷路了,请返回首页重新探索!',
},
};
const errorContent = computed(() => errorMessages[props.error!.statusCode] || errorMessages['default']);
console.error(props.error)
onMounted(() => {
emitter.emit("startLoading", false)
})
</script>
<template>
<div class="relative flex min-h-screen flex-col overflow-hidden bg-blue-50">
<nav-bar :nav-color="true"/>
<alert :title="errorContent.title" :message="errorContent.message" :icon="errorContent.icon"/>
<footer-main/>
<alert-notification/>
</div>
</template>
<style scoped>
</style>

View File

@ -11,13 +11,13 @@ export default defineNuxtConfig({
head: { head: {
title: 'CANTYONION.SITE', title: 'CANTYONION.SITE',
meta: [ meta: [
{name: 'viewport', content: 'width=device-width, initial-scale=1'}, { name: 'viewport', content: 'width=device-width, initial-scale=1' },
{name: 'charset', content: 'utf-8'}, { name: 'charset', content: 'utf-8' },
{name: 'keywords', content: 'cantyonion, onion, 洋葱, 博客, 学习, 主页, index'}, { name: 'keywords', content: 'cantyonion, onion, 洋葱, 博客, 学习, 主页, index' },
{name: 'description', content: 'cantyonion的超级基地进来看看吧'}, { name: 'description', content: 'cantyonion的超级基地进来看看吧' },
], ],
link: [ link: [
{rel: 'icon', href: '/favicon.png'}, { rel: 'icon', href: '/favicon.png' },
] ]
} }
}, },
@ -43,14 +43,11 @@ export default defineNuxtConfig({
} }
} }
}, },
server: { },
proxy: { runtimeConfig: {
'/api': { public: {
target: 'https://cantyonion.site', gitApiKey: 'fb8aec429ea7d0a36f7238dbffda9d2d66c7b045',
changeOrigin: true, baseURL: 'https://cantyonion.site'
rewrite: (path) => path.replace(/^\/api/, '') }
}
}
},
} }
}) })

View File

@ -19,6 +19,7 @@
"@pinia-plugin-persistedstate/nuxt": "^1.2.1", "@pinia-plugin-persistedstate/nuxt": "^1.2.1",
"@pinia/nuxt": "^0.7.0", "@pinia/nuxt": "^0.7.0",
"axios": "^1.7.7", "axios": "^1.7.7",
"mathjax": "^3.2.2",
"mitt": "^3.0.1", "mitt": "^3.0.1",
"nuxt": "^3.14.159", "nuxt": "^3.14.159",
"vue": "latest", "vue": "latest",

11
pages/auth.vue Normal file
View File

@ -0,0 +1,11 @@
<script setup lang="ts">
</script>
<template>
</template>
<style scoped>
</style>

14
pages/blog/[cid].vue Normal file
View File

@ -0,0 +1,14 @@
<script setup lang="ts">
const route = useRoute()
const cid = route.params.cid as string
onMounted( () => {
})
</script>
<template>
</template>
<style scoped>
</style>

View File

@ -1,48 +1,18 @@
<script setup lang="ts"> <script setup lang="ts">
const route = useRoute() const route = useRoute()
const errorCode = route.params.code as string const errorCode = parseInt(route.params.code as string, 10)
const errorMessages: Record<string, { icon: string; title: string; message: string }> = {
'400': {
icon: '❓',
title: '哦豁!请求有点问题',
message: '请求似乎有点小问题,服务器君有点摸不着头脑呢!',
},
'403': {
icon: '🔒',
title: '哎呀!大门被锁住了',
message: '你没有权限访问这个角落,试试返回首页吧!',
},
'404': {
icon: '🌌',
title: '哎呀!你发现了超级基地的秘密角落',
message: '看起来你找的页面藏到了未知的时空层里!',
},
'500': {
icon: '🚀',
title: '糟糕!超级基地出了一点故障',
message: '服务器君正在努力解决问题,请稍等片刻!',
},
'502': {
icon: '👽',
title: '糟糕!基地信号被外星人拦截了',
message: '网络通道似乎遇到了问题,请稍后再试!',
},
default: {
icon: '⚠️',
title: '哦豁!此时遇到了点小麻烦',
message: '请求在穿越洋葱星球时迷路了,请返回首页重新探索!',
},
};
const errorContent = computed(() => errorMessages[errorCode] || errorMessages['default']); if (import.meta.server)
throw createError({
statusCode: errorCode,
})
else
showError({statusCode: errorCode})
onMounted(() => {
emitter.emit("startLoading", false)
})
</script> </script>
<template> <template>
<alert :title="errorContent.title" :message="errorContent.message" :icon="errorContent.icon"/>
</template> </template>
<style scoped> <style scoped>

View File

@ -1,7 +1,5 @@
<script lang="ts" setup> <script lang="ts" setup>
import {computed, onMounted, ref} from "vue"; import {computed, onMounted, ref} from "vue";
import {getBlogRecentPost} from "~/api/blog";
import {getActivity} from "~/api/git"
const recentPosts = ref<IPost[] | null>(null); const recentPosts = ref<IPost[] | null>(null);
const recentActivities = ref<IActivity[] | null>(null); const recentActivities = ref<IActivity[] | null>(null);
@ -14,6 +12,17 @@ const isError = ref({
git: false git: false
}); });
const config = useRuntimeConfig()
const getBlogRecentPost = get<IBlogResponse<IPostsData>, any>('/blog/index.php/api/posts')
const getActivity = get<IActivity[], any>('/git/api/v1/users/cantyonion/activities/feeds', {
headers: {
Authorization: ` ${config.public.gitApiKey}`
},
params: {
limit: 10,
}
})
const hasPosts = computed(() => (recentPosts.value ?? []).length > 0); const hasPosts = computed(() => (recentPosts.value ?? []).length > 0);
const hasActivities = computed(() => (recentActivities.value ?? []).length > 0); const hasActivities = computed(() => (recentActivities.value ?? []).length > 0);
const postsData = computed(() => { const postsData = computed(() => {
@ -41,30 +50,33 @@ const activitiesData = computed((): IActivity<IContent>[] => {
const reloadPosts = async () => { const reloadPosts = async () => {
try { try {
isLoading.value.blog = true isLoading.value.blog = true
const postData = await getBlogRecentPost(); const postData = await getBlogRecentPost()
recentPosts.value = postData.data.dataSet recentPosts.value = postData!.data.dataSet
isLoading.value.blog = false
} catch (e) { } catch (e) {
isLoading.value.blog = false
isError.value.blog = true isError.value.blog = true
} }
finally {
isLoading.value.blog = false
}
} }
const reloadActivities = async () => { const reloadActivities = async () => {
try { try {
isLoading.value.git = true isLoading.value.git = true
recentActivities.value = await getActivity() recentActivities.value = await getActivity()
isLoading.value.git = false
} catch (e) { } catch (e) {
isLoading.value.git = false
isError.value.git = true isError.value.git = true
console.log(e)
}
finally {
isLoading.value.git = false
} }
} }
onMounted(async () => { await reloadPosts()
await reloadPosts() await reloadActivities()
await reloadActivities()
onMounted(() => {
emitter.emit('startLoading', false) emitter.emit('startLoading', false)
}) })
</script> </script>

5
types/notification.ts Normal file
View File

@ -0,0 +1,5 @@
declare interface INotification {
level: 'warning' | 'error' | 'info' | 'success'
title: string
message: string
}

View File

@ -3319,6 +3319,11 @@ make-dir@^3.1.0:
dependencies: dependencies:
semver "^6.0.0" semver "^6.0.0"
mathjax@^3.2.2:
version "3.2.2"
resolved "https://registry.npmmirror.com/mathjax/-/mathjax-3.2.2.tgz#c754d7b46a679d7f3fa03543d6b8bf124ddf9f6b"
integrity sha512-Bt+SSVU8eBG27zChVewOicYs7Xsdt40qm4+UpHyX7k0/O9NliPc+x77k1/FEsPsjKPZGJvtRZM1vO+geW0OhGw==
mdn-data@2.0.28: mdn-data@2.0.28:
version "2.0.28" version "2.0.28"
resolved "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.0.28.tgz#5ec48e7bef120654539069e1ae4ddc81ca490eba" resolved "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.0.28.tgz#5ec48e7bef120654539069e1ae4ddc81ca490eba"