feat: 优化前端布局和代理配置

refactor: 移除调试日志并优化代码结构
style: 调整响应式设计和UI细节
fix: 修复路由和导航相关的问题
This commit is contained in:
qingfeng1121
2025-12-12 17:14:04 +08:00
parent 07ce8409e1
commit ede67faafd
14 changed files with 296 additions and 128 deletions

View File

@@ -34,12 +34,12 @@
</div>
</div>
<div id="bot" :class="{ 'botrelative': scrollY }">
<el-tabs v-model="activeName" stretch="true" class="demo-tabs">
<el-tabs v-model="activeName" :stretch="true" class="demo-tabs">
<el-tab-pane label="个人简介" name="first">
<div class="mylogo">
<el-avatar class="mylogo_avatar" :src="state.circleUrl" />
</div>
<a href="#">
<a href="http://www.qf1121.top/">
<h6 class="mylogo_name logo-text">清疯不颠</h6>
</a>
<h6 class="mylogo_description">重度精神失常患者</h6>
@@ -128,7 +128,7 @@ const activeIndex = ref('/:type')
const router = useRouter()
const activeName = ref('first')
const state = reactive({
circleUrl: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png',
circleUrl: '/blogicon.jpg',
squareUrl: 'https://cube.elemecdn.com/9/c2/f0ee8a3c7c9638a54940382568c9dpng.png',
sizeList: ['small', '', 'large'] as const,
})

View File

@@ -3,7 +3,7 @@
<el-row justify="center">
<el-col :span="6" v-if="windowwidth">
<div class="grid-content ep-bg-purple-dark">
<div class="logo-text"> <a href="/">清疯不颠</a></div>
<div class="logo-text"> <a href="http://www.qf1121.top/">清疯不颠</a></div>
</div>
</el-col>
<el-col :span="14" justify="center">
@@ -48,12 +48,13 @@
</div>
<!-- Hero 区域 -->
<div class="hero" :class="{ 'newhero': classhero }" v-if="windowwidth">
<div class="hero" :class="{ 'small-hero': classsmallhero }" v-if="windowwidth"
:style="{ marginTop: heroMarginTop, marginBottom: heroMarginBottom, transform: heroTransform, transition: 'all 0.3s ease' }">
<h1 class="typewriter">{{ heroText }}</h1>
</div>
<!-- 提示区域 -->
<div id="content-section" :class="{ 'visible': isconts }">
<!-- 内容区域 -->
<div id="content-section" :class="{ 'visible': iscontentvisible }">
<div class="nonsensetitle" v-if="classnonsenset">
<div class="nonsensetitleconst">
<h1>{{ Cardtitle }}</h1>
@@ -100,12 +101,23 @@ const Login = computed(() => globalStore.Login);
const Cardtitle = ref('');
const classmoduleorrouter = ref(false);
const classnonsenset = ref(false);
const classhero = ref(false);
const classsmallhero = ref(false);
const elrowtop = ref('transparent');
// hero区域的margin值用于实现滚动时动态变化
const heroMarginTop = ref('45%');
const heroMarginBottom = ref('45%');
// hero区域的初始margin值从CSS变量获取
const initialHeroMargin = 45;
// hero是否开始向上移动
const heroIsMoving = ref(false);
// hero的transform值用于实现向上移动和吸附效果
const heroTransform = ref('translateY(0)');
// hero的位置状态static(静态)、moving(移动中)、sticky(吸附顶部)
const heroPosition = ref('static');
// 布局相关状态
const isleftmodluecontainer = ref(true);
const isconts = ref(false);
const iscontentvisible = ref(false);
const isScrollingleftmodlue = ref(false);
const windowwidth = ref(true);
@@ -131,7 +143,7 @@ let heroTimer: number | undefined;
* 初始化并启动打字机效果
* @param {string} text - 要显示的完整文本
*/
const startTypewriter = () => {
const startTypewriter = (text: string) => {
// 重置状态
heroText.value = '';
heroIndex = 0;
@@ -143,8 +155,8 @@ const startTypewriter = () => {
// 设置新的定时器,逐字显示文本
heroTimer = window.setInterval(() => {
if (heroIndex < fullHeroText.length) {
heroText.value += fullHeroText[heroIndex];
if (heroIndex < text.length) {
heroText.value += text[heroIndex];
heroIndex++;
} else {
// 文本显示完毕,清除定时器
@@ -161,8 +173,13 @@ const stopTypewriter = () => {
if (heroTimer) {
clearInterval(heroTimer);
}
// 直接显示完整文本
heroText.value = fullHeroText;
// 非首页时清空hero内容
if (rpsliturl[1] !== localhome) {
heroText.value = '';
} else {
// 首页直接显示完整文本
heroText.value = fullHeroText;
}
};
// ========== 导航和路由处理模块 ==========
@@ -199,8 +216,7 @@ const setActiveIndex = (path: string) => {
*/
const updatePageState = () => {
// 根据是否为主页根路径设置hero区域状态
classhero.value = !(rpsliturl[1] == localhome && rpsliturl[2] == undefined);
classsmallhero.value = !(rpsliturl[1] == localhome && rpsliturl[2] == undefined);
// 控制左侧模块容器的显示/隐藏
isleftmodluecontainer.value = rpsliturl[1] !== "articlesave";
};
@@ -230,8 +246,8 @@ const updateArticleTitle = () => {
const shouldHideTitle =
// 特殊页面不需要显示标题
(rpsliturl[1] === 'article-list' ||
rpsliturl[1] === 'message' ||
rpsliturl[1] === 'about') ||
rpsliturl[1] === 'message' ||
rpsliturl[1] === 'about') ||
// 在主页且无标题数据时,不显示标题
(rpsliturl[1] === localhome && !articledata);
@@ -316,7 +332,7 @@ const handleResize = () => {
// 首页特殊处理:小屏幕下默认显示内容区
if (rpsliturl[1] === localhome) {
isconts.value = window.innerWidth <= 768;
iscontentvisible.value = window.innerWidth <= 768;
}
};
@@ -336,10 +352,50 @@ const handleScroll = () => {
// 仅在首页根路径应用滚动动画
if (rpsliturl[1] === localhome && rpsliturl[2] == undefined) {
// 控制内容区和左侧模块的滚动状态
isconts.value = window.scrollY > 200;
isScrollingleftmodlue.value = window.scrollY > 600;
const scrollY = window.scrollY;
const windowHeight = window.innerHeight;
// 计算滚动距离与窗口高度的比例,用于内容渐显
const contentScrollRatio = Math.min(scrollY / windowHeight, 1);
// 计算新的底部margin值从初始值45%逐渐减少到25%
const newMarginBottom = Math.max(initialHeroMargin - (initialHeroMargin * contentScrollRatio), 0);
// 更新hero的底部margin值
heroMarginBottom.value = `${newMarginBottom}%`;
// 顶部margin保持不变
heroMarginTop.value = `${initialHeroMargin}%`;
// 内容区域随滚动逐渐显现
// 当滚动超过50px时开始显示滚动到一屏高度时完全显示
iscontentvisible.value = scrollY > 50;
// 计算hero的移动阶段
if (scrollY >= 555) {
// 滚动超过555px标题开始向上移动
heroIsMoving.value = true;
heroPosition.value = 'moving';
// 计算移动距离从0到初始marginTop值(45%)
// 使用滚动距离减去起始位置(555px),除以移动范围(500px),得到移动比例
const moveScrollRatio = Math.min((scrollY - 555) / 500, 1);
const moveDistance = initialHeroMargin * moveScrollRatio;
heroTransform.value = `translateY(-${moveDistance*10}%)`;
// 当移动距离达到初始marginTop值时吸附到顶部
if (moveScrollRatio >= 1) {
heroPosition.value = 'sticky';
heroTransform.value = `translateY(-${initialHeroMargin*10}%)`;
}
} else {
// 滚动未超过555px标题保持静态
heroIsMoving.value = false;
heroPosition.value = 'static';
heroTransform.value = 'translateY(0)';
}
// 控制左侧模块的滚动状态
isScrollingleftmodlue.value = scrollY > 600;
}
};
/**
@@ -376,12 +432,26 @@ const handleRouteChange = () => {
// 根据是否为首页决定是否启动打字机效果
if (rpsliturl[1] === localhome && rpsliturl[2] == undefined) {
// 首页启动打字机效果
startTypewriter();
startTypewriter(fullHeroText);
// 重置hero的margin值为初始值
heroMarginBottom.value = `${initialHeroMargin}%`;
heroMarginTop.value = `${initialHeroMargin}%`;
// 重置hero的移动状态
heroIsMoving.value = false;
heroPosition.value = 'static';
heroTransform.value = 'translateY(0)';
// 移动端首页默认显示内容区,桌面端初始隐藏
iscontentvisible.value = window.innerWidth <= 768;
} else {
// 非首页直接显示完整文本
isconts.value = true;
iscontentvisible.value = true;
stopTypewriter();
}
// 不在首页时hero的margin为0
if (rpsliturl[1] !== localhome) {
heroMarginBottom.value = '0%';
heroMarginTop.value = '0%';
}
};
/**
@@ -392,7 +462,20 @@ const initializePage = () => {
handleResize();
// 启动打字机效果(如果是首页)
if (rpsliturl[1] === localhome && rpsliturl[2] == undefined) {
startTypewriter();
// 首页启动打字机效果
startTypewriter(fullHeroText);
// 重置hero的margin值为初始值
heroMarginBottom.value = `${initialHeroMargin}%`;
heroMarginTop.value = `${initialHeroMargin}%`;
// 重置hero的移动状态
heroIsMoving.value = false;
heroPosition.value = 'static';
heroTransform.value = 'translateY(0)';
// 移动端首页默认显示内容区,桌面端初始隐藏
iscontentvisible.value = window.innerWidth <= 768;
} else {
// 非首页清空hero内容
heroText.value = '';
}
};
@@ -514,9 +597,11 @@ watch(
.close-btn:hover {
color: #409eff;
}
.footer-container {
margin-top: 20px;
}
/* 防止搜索框在小屏幕上重叠 */
@media screen and (max-width: 1200px) {
.search-box-container.open {

View File

@@ -1,41 +1,43 @@
<template>
<div class="establish-container">
<!-- 弹出的按钮容器 -->
<!-- <div class="expanded-buttons" :class="{ 'show': isExpanded }"> -->
<button v-for="(btn, index) in isbuttonsave()" :class="['action-button', { 'show': isExpanded }]"
:style="getButtonStyle(index)" :key="btn.id" @click="handleButtonClick(btn)">
<!-- <i :class="btn.icon"></i> -->
<span>{{ btn.label }}</span>
</button>
<!-- </div> -->
<div class="establish-component-root">
<div class="establish-container">
<!-- 弹出的按钮容器 -->
<!-- <div class="expanded-buttons" :class="{ 'show': isExpanded }"> -->
<button v-for="(btn, index) in isbuttonsave()" :class="['action-button', { 'show': isExpanded }]"
:style="getButtonStyle(index)" :key="btn.id" @click="handleButtonClick(btn)">
<!-- <i :class="btn.icon"></i> -->
<span>{{ btn.label }}</span>
</button>
<!-- </div> -->
<!-- 主圆形按钮 -->
<button class="main-button" :class="{ 'active': isExpanded }" @click="toggleExpand">
<i class="icon">+</i>
</button>
</div>
<!-- 标签蒙板组件 -->
<Transition name="modal">
<div v-if="showAttributeModal" class="category-modal" @click.self="closeAttributeModal">
<div class="category-modal-content">
<div class="category-modal-header">
<h3>新建标签</h3>
<button class="category-modal-close" @click="closeAttributeModal">×</button>
</div>
<div class="category-modal-body">
<!-- 主圆形按钮 -->
<button class="main-button" :class="{ 'active': isExpanded }" @click="toggleExpand">
<i class="icon">+</i>
</button>
</div>
<!-- 标签蒙板组件 -->
<Transition name="modal">
<div v-if="showAttributeModal" class="category-modal" @click.self="closeAttributeModal">
<div class="category-modal-content">
<div class="category-modal-header">
<h3>新建标签</h3>
<button class="category-modal-close" @click="closeAttributeModal">×</button>
</div>
<div class="category-modal-body">
<el-select v-model="CategoryAttributeDto.categoryid" placeholder="请选择">
<el-option v-for="item in categories" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
<el-select v-model="CategoryAttributeDto.categoryid" placeholder="请选择">
<el-option v-for="item in categories" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
<el-input v-model="CategoryAttributeDto.name" placeholder="输入新标签" />
<el-button type="primary"
@click="saveAttribute(CategoryAttributeDto)">保存</el-button>
<el-input v-model="CategoryAttributeDto.name" placeholder="输入新标签" />
<el-button type="primary"
@click="saveAttribute(CategoryAttributeDto)">保存</el-button>
</div>
</div>
</div>
</div>
</Transition>
</Transition>
</div>
</template>
<script setup>
@@ -335,14 +337,14 @@ const createCategory = () => {
* @param {string} typename - 分类名称
*/
const saveCategory = (typename) => {
console.log('保存分类')
// console.log('保存分类')
categoryService.createCategory({
typename: typename
}).then(response => {
if (response.code === 200) {
ElMessage.success('分类创建成功');
// 刷新页面
router.push({ path: `/aericlelist`});
router.push({ path: `/articlelist`});
} else {
ElMessage.error(response.message || '创建分类失败');
}
@@ -365,7 +367,7 @@ const createAttribute = async () => {
} catch (error) {
handleErrorResponse(error, '获取分类失败');
} finally {
console.log(categories.value)
// console.log(categories.value)
}
};
@@ -387,7 +389,7 @@ const saveAttribute = (dto) => {
closeAttributeModal()
ElMessage.success('标签创建成功');
// 刷新页面
router.push({ path: `/aericlelist`});
router.push({ path: `/articlelist`});
} else {
ElMessage.error(response.message || '创建标签失败');
}
@@ -488,7 +490,7 @@ const reloadPage = () => {
* @param {{id: string, label: string, icon: string}} button - 按钮对象
*/
const handleButtonClick = (button) => {
console.log('点击了按钮:', button.id, button.label)
// console.log('点击了按钮:', button.id, button.label)
// 使用按钮ID进行处理更可靠且易于维护
switch (button.id) {

View File

@@ -4,7 +4,7 @@ import { ElMessage } from 'element-plus'
// 创建axios实例
const api = axios.create({
baseURL: 'http://www.qf1121.top/api', // API基础URL
baseURL: '/api', // API基础URL使用相对路径通过Vite代理转发
timeout: 10000, // 请求超时时间
withCredentials: true // 允许跨域请求携带凭证如cookies
})

View File

@@ -17,12 +17,14 @@
/* 内容区圆角 */
/* 首页 hero 区域高度和间距 */
--hero-height: 768px;
--hero-height: 100px;
/* hero 默认高度 */
--hero-height-small: 100px;
/* hero 收缩后高度 */
/* --hero-margin-top: 2%; */
/* hero 顶部外边距 */
--hero-margin: 45% 0;
/* hero 顶边距 */
--hero-min-margin-top: 45%;
/* hero 最小顶边距 */
/* 标题样式 */
--title-font-size: 3.5rem;
@@ -368,18 +370,21 @@ p {
/* 首页 hero 区域样式 */
.hero {
height: var(--hero-height);
margin: var(--hero-margin);
display: flex;
justify-content: center;
align-items: center;
text-align: center;
color: white;
transition: height 0.3s ease;
transition: all 0.3s ease;
position: sticky;
top: 0;
z-index: 999;
}
/* hero 收缩状态 */
.hero.newhero {
.hero.small-hero {
height: var(--hero-height-small);
margin-top: 10%;
}
/* 打字机效果 */
@@ -387,6 +392,10 @@ p {
white-space: pre;
min-height: 2.5em;
font-size: var(--title-font-size, 2rem);
/* 水平居中 */
display: flex;
justify-content: center;
align-items: center;
}
@keyframes blink {
@@ -445,8 +454,7 @@ p {
--nonsense-title-margin-bottom: 15px;
--nav-padding-small: 0 8px;
--nonsenset-margin-top: 10px;
--body-background-img: url();
/* 移动端不显示背景图片 */
--body-background-img: url(../img/bg.jpg);
}
.elrow-top {
@@ -506,3 +514,23 @@ p {
font-size: 1rem;
}
}
/* 移动端适配屏幕宽度小于820px时生效 */
@media (max-width: 820px) {
:root {
--nav-padding: 0;
--hero-height:300px;
}
.RouterViewpage {
height: auto;
}
.hero {
margin-top: 50%;
}
.el-col-14 {
flex: 0 0 0;
max-width: 100%;
}
.elrow-top {
}
}

View File

@@ -3,7 +3,7 @@
<div class="about-content-wrapper">
<!-- 页面头部 -->
<div class="about-page-header">
<h1 class="about-page-title">关于</h1>
<h3 class="about-page-title">关于</h3>
</div>
<!-- 关于内容 -->
@@ -281,14 +281,19 @@ const goToMessageBoard = () => {
.about-page-container {
padding: 20px 0;
}
.about-page-header{
margin-bottom: 0;
padding-bottom: 0;
border-bottom: none;
}
.about-content-wrapper {
width: 100%;
padding: 20px;
margin: 0 15px;
margin: 0 5%;
}
.about-page-title {
font-size: 1.8rem;
font-size: 1.2rem;
}
.about-page-subtitle {
@@ -306,7 +311,6 @@ const goToMessageBoard = () => {
.contact-options {
flex-direction: column;
}
.skills-display-list {
gap: 8px;
}

View File

@@ -99,7 +99,7 @@ const fetchCategories = async () => {
);
}
categories.value = processedCategories;
console.log('获取分类列表成功:', categories.value);
// console.log('获取分类列表成功:', categories.value);
} catch (err) {
console.error('获取分类列表失败:', err);
ElMessage.error('获取分类列表失败,请稍后重试');
@@ -118,7 +118,7 @@ const handleCategoryClick = (attribute: any) => {
id: attribute.attributeid,
name: attribute.typename
})
console.log(attribute)
// console.log(attribute)
router.push({
path: '/home/aericletype',
@@ -385,6 +385,7 @@ onMounted(() => {
.article-content {
padding: 15px;
height: 600px;
}
.category-group-container {

View File

@@ -154,8 +154,8 @@ const loadCategories = async () => {
}
}
console.log('分类选项:', optionsData);
console.log('选中的值:', selectedValues.value);
// console.log('分类选项:', optionsData);
// console.log('选中的值:', selectedValues.value);
}
} catch (error) {
console.error('加载分类失败:', error);
@@ -196,8 +196,8 @@ const handleSave = (markdown) => {
markdownscontent: Articleform.value.markdownscontent
};
console.log('发送文章数据:', articleData);
console.log('当前认证token是否存在:', !!localStorage.getItem('token'));
// console.log('发送文章数据:', articleData);
// console.log('当前认证token是否存在:', !!localStorage.getItem('token'));
// 根据articleid决定调用创建还是更新接口
const savePromise = Articleform.value.articleid === 0
@@ -205,7 +205,7 @@ const handleSave = (markdown) => {
: articleService.updateArticle(Articleform.value.articleid, articleData);
savePromise
.then(res => {
console.log('API响应:', res);
// console.log('API响应:', res);
if (res.code === 200) {
ElMessage.success(Articleform.value.articleid === 0 ? '文章创建成功' : '文章更新成功');
// 清除全局存储中的article

View File

@@ -28,7 +28,7 @@
</div>
</div>
<!-- 分页区域 -->
<PaginationComponent class="pagination-container" :list="articleList" :pageSize="10" @changePage="handleCurrentDataUpdate" />
<PaginationComponent class="pagination-container" :list="articleList" :pageSize="10" @changePage="handleCurrentDataUpdate" :key="'pagination'" />
</transition-group>
<!-- 空状态 -->
<div v-if="!loading && articleList.length === 0" class="empty-state-container">
@@ -69,7 +69,7 @@ const loading = ref(false)
*/
const handleCurrentDataUpdate = (data) => {
displayedArticles.value = data
console.log('更新后的当前页数据:', data)
// console.log('更新后的当前页数据:', data)
}
// ========== 文章数据获取模块 ==========
@@ -81,7 +81,7 @@ const handleCurrentDataUpdate = (data) => {
const getArticlesByRoute = async () => {
// 检查URL参数确定获取文章的方式
const pathSegment = route.path.split('/')[2]
console.log('当前路由分段:', pathSegment)
// console.log('当前路由分段:', pathSegment)
switch (pathSegment) {
case 'aericletype':
@@ -98,7 +98,7 @@ const getArticlesByRoute = async () => {
return await articleService.getArticlesByStatus(statusData?.status)
default:
// 默认获取所有文章
console.log('获取所有文章列表')
// console.log('获取所有文章列表')
return await articleService.getAllArticles()
}
}
@@ -189,7 +189,7 @@ const fetchArticles = async () => {
console.error('获取文章列表失败:', error)
ElMessage.error('获取文章列表失败,请稍后重试')
} finally {
console.log('最终文章列表数据:', articleList.value)
// console.log('最终文章列表数据:', articleList.value)
loading.value = false
}
}
@@ -230,7 +230,7 @@ const handleArticleClick = (article) => {
*/
const handleRouteChange = () => {
fetchArticles()
console.log('路由变化,重新获取文章列表')
// console.log('路由变化,重新获取文章列表')
}
/**
@@ -414,7 +414,6 @@ watch(
/* 响应式设计 - 平板和手机 */
@media (max-width: 768px) {
.article-list-container {
padding: 0 10px;
}
.article-card {

View File

@@ -105,7 +105,7 @@ const togglePassword = () => {
// 验证单个字段
const validateField = (field) => {
console.log('validateField', field)
// console.log('validateField', field)
errors.value = {}
if (field === 'username' && !loginForm.username) {
@@ -150,7 +150,7 @@ const handleLogin = async () => {
ElMessage.error('登录失败,请检查用户名和密码')
return
}
console.log('登录成功', user)
// console.log('登录成功', user)
// 这里应该是实际的登录API调用
// console.log('登录请求数据:', loginForm)
@@ -162,7 +162,7 @@ const handleLogin = async () => {
globalStore.setValue('loginhomestatus', {
status: 1 // 2:删除 1:已发布 0:发布登录
})
console.log('globalStore.Login', globalStore.Login)
// console.log('globalStore.Login', globalStore.Login)
// 保存登录状态token
if (user.token) {
localStorage.setItem('token', user.token)

View File

@@ -27,7 +27,7 @@
</div>
<div class="comment-content-text" v-html="comment.content"></div>
<div class="comment-actions-bar">
<span class="like-button" @click="handleLike(comment)">
<span class="like-button" v-if="false" @click="handleLike(comment)">
<span v-if="comment.likes && comment.likes > 0" class="like-count">{{ comment.likes
}}</span>
👍
@@ -55,7 +55,8 @@
</div>
<div class="reply-content-text">{{ reply.content }}</div>
<div class="reply-actions-bar">
<span class="like-button" @click="handleLike(reply)">
<span class="like-button" v-if="false" @click="handleLike(reply)">
<span v-if="reply.likes && reply.likes > 0" class="like-count">{{ reply.likes
}}</span>
👍
@@ -111,8 +112,8 @@
</el-form-item>
</div>
<div class="form-input-row">
<el-form-item>
<el-button type="primary" @click="onSubmit" :loading="submitting"
<el-form-item class="submit-button-container">
<el-button type="primary" @click="onSubmit" class="form-submit-button" :loading="submitting"
:disabled="!form.content || !form.nickname">
发送
</el-button>
@@ -600,7 +601,7 @@ const onSubmit = async () => {
try {
// 表单验证
await validateForm()
console.log('提交留言表单:', form)
// console.log('提交留言表单:', form)
submitting.value = true
@@ -902,16 +903,24 @@ onMounted(() => {
/**
* 内联表单输入行样式
* 用于将表单输入项与标签或其他元素对齐
* 用于将表单输入项水平均匀分布
*/
.form-input-row--inline {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
}
.form-input-row--inline div:nth-child(2) {
margin-left: 9%;
margin-right: 9%;
.form-input-row--inline .el-form-item {
flex: 1;
margin-right: 0;
margin-left: 0;
width: calc(33.33% - 10px);
}
.form-input-row--inline .el-input {
width: 100%;
}
/* 回复项容器 */
@@ -1055,18 +1064,20 @@ onMounted(() => {
.comment-form-section {
padding: 16px;
}
.el-form-item {
width: 100%;
}
.form-input-row {
flex-direction: column;
gap: 8px;
}
.comment-header-info,
.reply-header-info {
flex-direction: column;
align-items: flex-start;
}
.form-submit-button {
width: 100%;
}
.user-avatar {
margin-right: 0;
margin-bottom: 8px;

View File

@@ -1,6 +1,19 @@
<template>
<div class="nonsense-container">
<div class="nonsense-list">
<!-- 加载状态 -->
<div v-if="loading" class="loading-state-container">
<el-skeleton :count="5" />
</div>
<!-- 错误状态 -->
<div v-if="error" class="error-state-container">
<div>加载失败请稍后重试</div>
<el-button type="primary" @click="handleRetry">重试</el-button>
</div>
<!-- 空状态 -->
<div v-if="displayedNonsenseList.length === 0" class="empty-state-container">
<div>暂无吐槽内容</div>
</div>
<div class="nonsense-item" v-for="item in displayedNonsenseList" :key="item.id">
<div class="nonsense-meta-info">
<span class="nonsense-time">{{ formatRelativeTime(item.time) }}</span>
@@ -44,10 +57,21 @@ const charRefs = ref(new Map())
const charStyles = ref(new Map())
// 显示的吐槽内容列表
const displayedNonsenseList = ref([])
// 加载状态
const loading = ref(false)
// 错误状态
const error = ref(false)
// 处理分页数据更新
const handleCurrentDataUpdate = (data) => {
displayedNonsenseList.value = data
console.log(data)
// console.log(data)
}
// 重试加载
const handleRetry = () => {
error.value = false
loadNonsenseList()
}
// 定时器引用
@@ -57,17 +81,24 @@ let colorChangeTimer = null
* 加载所有吐槽内容
*/
const loadNonsenseList = async () => {
// 设置加载状态
loading.value = true
error.value = false
try {
const response = await nonsenseService.getNonsenseByStatus(1)
if (response.code === 200) {
nonsenseList.value = response.data
} else {
ElMessage.error('加载吐槽内容失败')
error.value = true
}
} catch (error) {
console.error('加载吐槽内容失败:', error)
} catch (err) {
console.error('加载吐槽内容失败:', err)
error.value = true
} finally {
console.log('加载吐槽内容完成')
// 结束加载状态
loading.value = false
// console.log('加载吐槽内容完成')
}
}
// 编辑吐槽内容
@@ -357,8 +388,7 @@ onBeforeUnmount(() => {
/* 响应式设计 */
@media (max-width: 768px) {
.nonsense-container {
padding: 14px 4px 10px 4px;
margin: 0 8px;
margin: 0;
}
.nonsense-header h1 {
@@ -370,9 +400,9 @@ onBeforeUnmount(() => {
line-height: 1.6;
}
.nonsense-list {
/* .nonsense-list {
gap: 12px;
}
} */
.nonsense-item {
padding: 14px 16px 10px 16px;

View File

@@ -50,7 +50,7 @@ const totalPages = computed(() => {
if (!props.list || props.list.length === 0) return 0
// 如果列表长度小于pageSize不进行分组返回0表示不分页
if (props.list.length <= props.pageSize) return 0
console.log(props.list.length, props.pageSize)
// console.log(props.list.length, props.pageSize)
// 列表长度小于等于pageSize时正常计算页数
// 如果能整除,直接返回商

View File

@@ -26,7 +26,15 @@ export default defineConfig({
},
},
server: {
host: '0.0.0.0'
host: '0.0.0.0',
proxy: {
// 配置API代理
'/api': {
target: 'http://localhost:7071',
changeOrigin: true,
rewrite: (path) => path
}
}
},
})