9 changed files with 604 additions and 286 deletions
-
474src/components/blogs/HomePage.vue
-
2src/components/blogs/LeftSiteInfo.vue
-
84src/components/blogs/StatisticCount.vue
-
26src/components/blogs/header/CarouselImg.vue
-
150src/components/blogs/header/NavigateMenu.vue
-
11src/router/blog.ts
-
28src/stores/index.ts
-
57src/views/blog/imagemanage/OtherImgView.vue
-
56src/views/blog/imagemanage/PersonSelfView.vue
@ -0,0 +1,84 @@ |
|||||
|
<template> |
||||
|
<a-card hoverable> |
||||
|
<div class="statistic"> |
||||
|
<a-row> |
||||
|
<a-col :span="8" v-for="statistic in statistics" :key="statistic.id"> |
||||
|
<a-statistic :title=statistic.title :value=statistic.counts /> |
||||
|
</a-col> |
||||
|
</a-row> |
||||
|
</div> |
||||
|
</a-card> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang='ts'> |
||||
|
import { reactive, ref, computed, onMounted } from 'vue'; |
||||
|
import { get } from '@/tools/request'; |
||||
|
const createData = new Date('2024-07-12'); |
||||
|
const currentDate = ref(new Date()); |
||||
|
const getDateOnly = (date: Date) => { |
||||
|
return new Date(date.getFullYear(), date.getMonth(), date.getDate()); |
||||
|
}; |
||||
|
|
||||
|
// 计算相差的天数 |
||||
|
const daysDifference = computed(() => { |
||||
|
const oneDay = 24 * 60 * 60 * 1000; // 一天的毫秒数 |
||||
|
const diffTime = Math.abs(getDateOnly(currentDate.value).getTime() - getDateOnly(createData).getTime()); |
||||
|
return Math.floor(diffTime / oneDay); // 使用Math.floor确保是整天数 |
||||
|
}); |
||||
|
const diaryTotal = ref(); |
||||
|
const blogTotal = ref(); |
||||
|
const diaryList = async () => { |
||||
|
try { |
||||
|
const response = await get('/diarys/list'); |
||||
|
diaryTotal.value = response.data.data.total; // 更新总数 |
||||
|
} catch (error) { |
||||
|
console.error('Failed to fetch data', error); |
||||
|
} |
||||
|
}; |
||||
|
const blogList = async () => { |
||||
|
try { |
||||
|
const response = await get("/blogs/list"); |
||||
|
if (response) { |
||||
|
blogTotal.value = response.data.data.total; |
||||
|
} else { |
||||
|
console.log("bloglist is not exits") |
||||
|
} |
||||
|
} catch (error) { |
||||
|
console.log("bloglist is error") |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
// 更新当前时间 |
||||
|
const updateCurrentDate = () => { |
||||
|
currentDate.value = new Date(); |
||||
|
}; |
||||
|
const statistics = reactive([ |
||||
|
{ |
||||
|
id: "1", |
||||
|
title: "DAYS", |
||||
|
counts: daysDifference |
||||
|
}, |
||||
|
{ |
||||
|
id: "2", |
||||
|
title: "DIARYS", |
||||
|
counts: diaryTotal |
||||
|
}, |
||||
|
{ |
||||
|
id: "3", |
||||
|
title: "BLOGS", |
||||
|
counts: blogTotal |
||||
|
}, |
||||
|
]) |
||||
|
onMounted(() => { |
||||
|
diaryList() |
||||
|
blogList() |
||||
|
setInterval(updateCurrentDate, 24 * 60 * 60 * 1000); |
||||
|
}) |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.statistic { |
||||
|
text-align: center; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,26 @@ |
|||||
|
<template> |
||||
|
<div class="carousel" v-if="show_carousel"> |
||||
|
<a-carousel autoplay> |
||||
|
<div class="img" v-for="imgdata in imgdatas"><img :src="imgdata" alt=""></div> |
||||
|
</a-carousel> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang='ts'> |
||||
|
import { homePageStore } from '@/stores'; |
||||
|
import { toRefs } from 'vue'; |
||||
|
const { idShow } = homePageStore() |
||||
|
const { show_carousel } = toRefs(idShow) |
||||
|
const imgdatas: string[] = [ |
||||
|
"/src/assets/images/nav1.png", |
||||
|
"/src/assets/images/nav10.png", |
||||
|
"/src/assets/images/nav13.png" |
||||
|
] |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.carousel img { |
||||
|
height: 100vh; |
||||
|
width: 100vw; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,150 @@ |
|||||
|
<template> |
||||
|
<div class="menu" v-if="show_menu"> |
||||
|
<a-menu v-model:selectedKeys="current" mode="horizontal" :items="items" style="border-bottom: none;" |
||||
|
@click="jumpMenu" /> |
||||
|
<a-input-search v-model:value="searchValue" placeholder="search" style="width: 200px" @search="onSearch" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang='ts'> |
||||
|
import { ref, h, toRefs,watch,onMounted } from 'vue'; |
||||
|
import { HomeOutlined, HighlightOutlined, ProfileOutlined, CameraOutlined, UsergroupDeleteOutlined } from '@ant-design/icons-vue'; |
||||
|
import type { MenuProps } from 'ant-design-vue'; |
||||
|
import router from '@/router'; |
||||
|
import { useRouter } from 'vue-router'; |
||||
|
const route=useRouter() |
||||
|
import { homePageStore } from '@/stores'; |
||||
|
const { idShow } = homePageStore() |
||||
|
const { show_menu } = toRefs(idShow) |
||||
|
const current = ref<string[]>(['home']); |
||||
|
const items = ref<MenuProps['items']>([ |
||||
|
{ |
||||
|
key: 'home', |
||||
|
icon: () => h(HomeOutlined), |
||||
|
label: '首页', |
||||
|
title: '首页', |
||||
|
|
||||
|
}, |
||||
|
{ |
||||
|
key: 'blog', |
||||
|
icon: () => h(HighlightOutlined), |
||||
|
label: '博客', |
||||
|
title: '博客', |
||||
|
}, |
||||
|
{ |
||||
|
key: 'diary', |
||||
|
icon: () => h(ProfileOutlined), |
||||
|
label: '日记', |
||||
|
title: '日记', |
||||
|
}, |
||||
|
{ |
||||
|
key: 'album', |
||||
|
icon: () => h(CameraOutlined), |
||||
|
label: '相册', |
||||
|
title: '相册', |
||||
|
children: [ |
||||
|
{ |
||||
|
label: '个人', |
||||
|
key: 'personself', |
||||
|
}, |
||||
|
{ |
||||
|
label: '其他', |
||||
|
key: 'otherimg', |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
{ |
||||
|
key: 'chart', |
||||
|
icon: () => h(UsergroupDeleteOutlined), |
||||
|
label: '收支图', |
||||
|
title: '收支图', |
||||
|
}, |
||||
|
{ |
||||
|
key: 'aboutme', |
||||
|
icon: () => h(UsergroupDeleteOutlined), |
||||
|
label: '关于sunfree', |
||||
|
title: '关于sunfree', |
||||
|
}, |
||||
|
]); |
||||
|
const searchValue = ref("") |
||||
|
const articleTitle = ref<string>(''); |
||||
|
const onSearch = (searchValue: string) => { |
||||
|
console.log('use value', searchValue); |
||||
|
console.log('or use this.value', articleTitle.value); |
||||
|
}; |
||||
|
const jumpMenu = ({ key }: { key: string }) => { |
||||
|
router.push(`/${key}`) |
||||
|
}; |
||||
|
const updateCarouselVisibility = (routeName: any) => { |
||||
|
handleScrollEnabled.value = false; |
||||
|
if (scrollbar.value) { |
||||
|
scrollbar.value.scrollTop = 0; |
||||
|
} |
||||
|
if (routeName === 'home') { |
||||
|
handleScrollEnabled.value = true; |
||||
|
show_carousel.value = true; |
||||
|
show_menu.value = false |
||||
|
} else { |
||||
|
show_menu.value = true; |
||||
|
show_author.value = false; |
||||
|
show_carousel.value = false; |
||||
|
show_anchornDown.value = false; |
||||
|
mainCss.marginTop = '48px'; |
||||
|
} |
||||
|
}; |
||||
|
router.beforeEach((to, _, next) => { |
||||
|
updateCarouselVisibility(to.name); |
||||
|
next(); |
||||
|
}); |
||||
|
watch( |
||||
|
() => route.name, |
||||
|
(newRouteName) => { |
||||
|
updateCarouselVisibility(newRouteName); |
||||
|
|
||||
|
if (newRouteName) { |
||||
|
// 尝试从菜单项中找到与当前路由名称匹配的项 |
||||
|
const menuItem = items.value?.find((item: any) => { |
||||
|
// 这里可以根据实际情况来匹配路由名称或路径 |
||||
|
// 例如,可以根据 route.name 或 route.path 来匹配 |
||||
|
if (newRouteName === 'blogdetail') { |
||||
|
return item.key === 'blog'; // 匹配博客详情页,选中博客菜单 |
||||
|
} else if (newRouteName === 'diarydetail') { |
||||
|
return item.key === 'diary'; // 匹配日记详情页,选中日记菜单 |
||||
|
} else { |
||||
|
return item.key === newRouteName; // 默认匹配路由名称 |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
if (menuItem) { |
||||
|
current.value = [menuItem.key as string]; |
||||
|
} else { |
||||
|
current.value = ['home']; // 找不到对应的菜单项,默认选中 'home' |
||||
|
} |
||||
|
} else { |
||||
|
current.value = ['home']; // 如果 route.name 不存在,默认选中 'home' |
||||
|
} |
||||
|
}, |
||||
|
{ immediate: true } |
||||
|
); |
||||
|
const scrollbar = ref<Element | null>(null); |
||||
|
onMounted(()=>{ |
||||
|
scrollbar.value = document.querySelector('.simplebar-content-wrapper'); |
||||
|
}) |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.menu { |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
width: 100%; |
||||
|
height: 48px; |
||||
|
border-bottom: 1px solid rgba(5, 5, 5, 0.06); |
||||
|
position: fixed; |
||||
|
background-color: white; |
||||
|
transform: translateX(-50%); |
||||
|
top: 0; |
||||
|
left: 50%; |
||||
|
z-index: 999; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,57 @@ |
|||||
|
<template> |
||||
|
<div class="otherimg"> |
||||
|
<a-card hoverable> |
||||
|
<a-image-preview-group> |
||||
|
<div class="img"> |
||||
|
<a-image :style="imageStyle" v-for="img in imgurl" :src="img" /> |
||||
|
</div> |
||||
|
</a-image-preview-group> |
||||
|
</a-card> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang='ts'> |
||||
|
import { get } from '@/tools/request'; |
||||
|
import { ref, computed, onMounted } from 'vue'; |
||||
|
const imageWidthPercentage = 45 / 3.5; // 45% divided by 2 = 22.5% |
||||
|
const imageStyle = computed(() => { |
||||
|
const width = `${imageWidthPercentage}vw`; |
||||
|
const height = `${(5 / 5) * imageWidthPercentage}vw`; |
||||
|
|
||||
|
return { |
||||
|
width, |
||||
|
height, |
||||
|
border: '2px solid #ddd', // Border style |
||||
|
boxShadow: '0 4px 8px rgba(0, 0, 0, 0.1)', // Shadow effect |
||||
|
transition: 'transform 0.3s ease, box-shadow 0.3s ease' |
||||
|
}; |
||||
|
}); |
||||
|
const imgurl = ref([]) |
||||
|
const baseurl = "http://www.wuruilin.cn" |
||||
|
const imgList = async () => { |
||||
|
await get("photos/listfiles", |
||||
|
{ album_key: "otherimg" } |
||||
|
|
||||
|
).then((response) => { |
||||
|
const imglist = response.data.files |
||||
|
imgurl.value = imglist.map((path: string) => `${baseurl}/${path}`); |
||||
|
}) |
||||
|
} |
||||
|
onMounted(() => { |
||||
|
imgList() |
||||
|
}) |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.otherimg { |
||||
|
width: 45%; |
||||
|
margin: 0 24px; |
||||
|
} |
||||
|
|
||||
|
.img { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
flex-wrap: wrap; |
||||
|
gap: 24px; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,56 @@ |
|||||
|
<template> |
||||
|
<div class="personself"> |
||||
|
<a-card hoverable> |
||||
|
<a-image-preview-group> |
||||
|
<div class="img"> |
||||
|
<a-image :style="imageStyle" v-for="img in imgurl" :src="img" /> |
||||
|
</div> |
||||
|
</a-image-preview-group> |
||||
|
</a-card> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang='ts'> |
||||
|
import { get } from '@/tools/request'; |
||||
|
import { ref, computed, onMounted } from 'vue'; |
||||
|
const imageWidthPercentage = 45 / 2.5; // 45% divided by 2 = 22.5% |
||||
|
const imageStyle = computed(() => { |
||||
|
const width = `${imageWidthPercentage}vw`; |
||||
|
const height = `${(3 / 5) * imageWidthPercentage}vw`; |
||||
|
return { |
||||
|
width, |
||||
|
height, |
||||
|
border: '2px solid #ddd', // Border style |
||||
|
boxShadow: '0 4px 8px rgba(0, 0, 0, 0.1)', // Shadow effect |
||||
|
transition: 'transform 0.3s ease, box-shadow 0.3s ease' |
||||
|
}; |
||||
|
}); |
||||
|
const imgurl = ref([]) |
||||
|
const baseurl = "http://www.wuruilin.cn" |
||||
|
const imgList = async () => { |
||||
|
await get("photos/listfiles", |
||||
|
{ album_key: "personself" } |
||||
|
|
||||
|
).then((response) => { |
||||
|
const imglist = response.data.files |
||||
|
imgurl.value = imglist.map((path: string) => `${baseurl}/${path}`); |
||||
|
}) |
||||
|
} |
||||
|
onMounted(() => { |
||||
|
imgList() |
||||
|
}) |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.personself { |
||||
|
width: 45%; |
||||
|
margin: 0 24px; |
||||
|
} |
||||
|
|
||||
|
.img { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
flex-wrap: wrap; |
||||
|
gap: 24px; |
||||
|
} |
||||
|
</style> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue