feat: 新增疯言疯语功能并优化UI样式

- 添加疯言疯语服务及页面,支持随机字符颜色变化效果
- 引入汉仪唐韵字体并优化全局字体设置
- 重构日期工具函数,优化时间显示格式
- 改进左侧模块布局,添加文章/分类/标签统计
- 优化浮动按钮组件,增加动态过渡效果
- 调整多个页面的背景透明度,提升视觉一致性
- 完善文章保存页面样式和交互逻辑
- 更新关于页面内容,增加个人介绍和技术栈展示
- 修复路由状态管理问题,优化页面跳转逻辑
This commit is contained in:
qingfeng1121
2025-11-05 16:11:46 +08:00
parent a927ad5a4d
commit ad893b3e5c
19 changed files with 1226 additions and 600 deletions

View File

@@ -34,13 +34,35 @@
</div>
</div>
<div id="bot" :class="{ 'botrelative': scrollY }">
<el-tabs v-model="activeName" class="demo-tabs">
<el-tabs v-model="activeName" stretch="true" class="demo-tabs">
<el-tab-pane label="个人简介" name="first">
<div class="mylogo">
<el-avatar :src="state.circleUrl" />
<el-avatar class="mylogo_avatar" :src="state.circleUrl" />
</div>
<a href="#">
<h6 class="mylogo_name logo-text">清疯不颠</h6>
</a>
<h6 class="mylogo_description">重度精神失常患者</h6>
<div class="stat-container">
<div>
<a href="#" class="stat-link">
<span class="site-state-item-count">{{ articleCount }}</span>
<span class="site-state-item-name">文章</span>
</a>
</div>
<div>
<a href="#" class="stat-link">
<span class="site-state-item-count">{{ categoryCount }}</span>
<span class="site-state-item-name">分类</span>
</a>
</div>
<div>
<a href="#" class="stat-link">
<span class="site-state-item-count">{{ AttributeCount }}</span>
<span class="site-state-item-name">标签</span>
</a>
</div>
</div>
<p>清疯不颠</p>
<p>重度精神失常患者</p>
</el-tab-pane>
<el-tab-pane label="功能" name="second">
</el-tab-pane>
@@ -52,6 +74,7 @@
<script lang="ts" setup>
import { reactive, ref, onMounted, onUnmounted } from 'vue'
import { useRouter } from 'vue-router'
import { articleService, categoryService, categoryAttributeService } from "@/services";
// 当前激活菜单
const activeIndex = ref('/:type')
@@ -74,6 +97,52 @@ router.beforeEach((to) => {
activeIndex.value = to.path
})
// 文章数量状态
const articleCount = ref(0)
// 分类数量状态
const categoryCount = ref(0)
// 标签数量状态
const AttributeCount = ref(0)
// 获取文章数量
const fetchArticleCount = async () => {
try {
const response = await articleService.getAllArticles();
articleCount.value = response.data?.length || 0
// 这里应该调用API获取实际的文章数量
// 暂时设置为模拟数据
} catch (error) {
console.error('获取文章数量失败:', error)
articleCount.value = 0
}
}
// 获取分类数量
const fetchCategoryCount = async () => {
try {
const response = await categoryService.getAllCategories();
categoryCount.value = response.data?.length || 0
// 这里应该调用API获取实际的分类数量
// 暂时设置为模拟数据
} catch (error) {
console.error('获取分类数量失败:', error)
categoryCount.value = 0
}
}
// 获取标签数量
const fetchAttributeCount = async () => {
try {
const response = await categoryAttributeService.getAllAttributes();
AttributeCount.value = response.data?.length || 0
// 这里应该调用API获取实际的标签数量
// 暂时设置为模拟数据
} catch (error) {
console.error('获取标签数量失败:', error)
AttributeCount.value = 0
}
}
// 控制底部模块吸顶效果
const scrollY = ref(false)
const handleScroll = () => {
@@ -83,6 +152,9 @@ const handleScroll = () => {
// 生命周期管理事件监听,防止内存泄漏
onMounted(() => {
window.addEventListener('scroll', handleScroll)
fetchArticleCount() // 组件挂载时获取文章数量
fetchCategoryCount() // 组件挂载时获取分类数量
fetchAttributeCount() // 组件挂载时获取标签数量
})
onUnmounted(() => {
@@ -100,17 +172,18 @@ onUnmounted(() => {
#top {
height: 100px;
border-radius: 10px;
background-color: rgba(102, 161, 216, 0.9); /* 蓝色半透明背景 */
background-color: rgba(102, 161, 216, 0.9);
/* 蓝色半透明背景 */
}
#alld #top .top1 {
#alld #top .top1 {
padding-top: 20px;
margin-bottom: 0;
text-align: center;
color: white;
}
#alld #top .top2 {
#alld #top .top2 {
text-align: center;
color: white;
}
@@ -118,13 +191,15 @@ onUnmounted(() => {
/* 内容区域样式 */
#cont {
border-radius: 10px;
background-color: rgba(255, 255, 255, 0.9); /* 白色半透明背景 */
background-color: rgba(255, 255, 255, 0.9);
/* 白色半透明背景 */
}
.cont1 {
text-align: center;
padding: 25px 10px 25px 10px ;
background-color: rgba(102, 161, 216, 0.9); /* 蓝色半透明背景 */
padding: 25px 10px 25px 10px;
background-color: rgba(102, 161, 216, 0.9);
/* 蓝色半透明背景 */
border-radius: 10px 10px 0 0;
}
@@ -141,21 +216,27 @@ onUnmounted(() => {
.cont2 {
margin-top: 20px;
}
.cont2 .el-menu-vertical-demo{
.cont2 .el-menu-vertical-demo {
display: block;
background-color: rgba(0, 0, 0,0 ); /* 白色半透明背景 */
}
.cont2 .el-menu-vertical-demo .el-menu-item:nth-child(3){
border-radius: 0 0 10px 10px;
}
.cont2 .el-menu-vertical-demo .el-menu-item:hover{
background-color: rgba(64, 158, 255, 0.9);
}
.cont2 .el-menu-vertical-demo .el-menu-item.is-active:hover{
color: black; /* 蓝色半透明背景 */
background-color: rgba(0, 0, 0, 0);
/* 白色半透明背景 */
}
.cont2 .el-menu-vertical-demo .el-menu-item.is-active{
.cont2 .el-menu-vertical-demo .el-menu-item:nth-child(3) {
border-radius: 0 0 10px 10px;
}
.cont2 .el-menu-vertical-demo .el-menu-item:hover {
background-color: rgba(64, 158, 255, 0.9);
}
.cont2 .el-menu-vertical-demo .el-menu-item.is-active:hover {
color: black;
/* 蓝色半透明背景 */
}
.cont2 .el-menu-vertical-demo .el-menu-item.is-active {
color: var(--nav-is-active);
}
@@ -212,22 +293,68 @@ onUnmounted(() => {
/* 底部标签页样式 */
#bot {
border-radius: 10px;
background-color: rgba(255, 255, 255, 0.9); /* 白色半透明背景 */
padding: 15px;
background-color: rgba(255, 255, 255, 0.9);
/* 白色半透明背景 */
padding: 10px;
}
.el-tabs__nav-scroll .el-tabs__nav .el-tabs__item{
.site-state-item-count {
display: block;
text-align: center;
color: #32325d;
font-weight: bold;
}
.demo-tabs {
transition: all 0.3s ease-in-out;
}
.el-tabs__nav-scroll .el-tabs__nav .el-tabs__item {
margin-left: 100px;
padding: 10px 20px;
}
/* 头像样式 */
.mylogo {
text-align: center;
margin-bottom: 10px;
.mylogo_name {
font-size: 13px;
}
.mylogo_description {
font-size: 13px;
opacity: 0.8;
color: #c21f30;
margin: 10px 0;
}
.el-avatar {
width: 80px;
height: 80px;
.stat-container {
display: flex;
gap: 10px;
justify-content: center;
font-size: 10px;
}
.stat-container div:not(:first-child) {
border-left: 1px solid #ccc;
padding-left: 10px;
}
/* 头像样式 */
#pane-first .mylogo {
text-align: center;
padding: 6px;
margin-bottom: 0px;
}
.mylogo_avatar {
height: 60px;
width: 60px;
}
/* 直接应用到el-avatar组件上的悬浮效果 */
.el-avatar.mylogo_avatar {
transition: transform 0.3s ease;
}
.el-avatar.mylogo_avatar:hover {
transform: scale(1.2);
}
/* 吸顶效果 */
@@ -243,6 +370,7 @@ onUnmounted(() => {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);