feat: 新增疯言疯语功能并优化UI样式
- 添加疯言疯语服务及页面,支持随机字符颜色变化效果 - 引入汉仪唐韵字体并优化全局字体设置 - 重构日期工具函数,优化时间显示格式 - 改进左侧模块布局,添加文章/分类/标签统计 - 优化浮动按钮组件,增加动态过渡效果 - 调整多个页面的背景透明度,提升视觉一致性 - 完善文章保存页面样式和交互逻辑 - 更新关于页面内容,增加个人介绍和技术栈展示 - 修复路由状态管理问题,优化页面跳转逻辑
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user