blob: 28cdff245463fae02f717b35b901284e95535de8 [file] [log] [blame]
Xing Jinwenff16b1e2025-06-05 00:29:26 +08001<template>
2 <div class="forum-page">
Xing Jinwenebbccad2025-06-07 21:24:44 +08003 <Navbar />
Xing Jinwenff16b1e2025-06-05 00:29:26 +08004 <div class="page-container">
5 <!-- 论坛头部 -->
6 <div class="forum-header">
7 <div class="header-content">
8 <h1>社区论坛</h1>
9 <p class="header-description">与其他用户交流讨论,分享经验心得</p>
10 <div class="header-actions">
11 <el-button type="primary" :icon="Edit" @click="showNewTopicDialog = true">
12 发布新帖
13 </el-button>
14 </div>
15 </div>
16 </div>
17
18 <!-- 论坛统计 -->
19 <div class="forum-stats">
20 <div class="stats-grid">
21 <div class="stat-item">
22 <el-icon size="32" color="#409eff"><ChatDotRound /></el-icon>
23 <div class="stat-info">
24 <h3>{{ forumStats.totalTopics }}</h3>
25 <p>主题总数</p>
26 </div>
27 </div>
28 <div class="stat-item">
29 <el-icon size="32" color="#67c23a"><Comment /></el-icon>
30 <div class="stat-info">
31 <h3>{{ forumStats.totalReplies }}</h3>
32 <p>回复总数</p>
33 </div>
34 </div>
35 <div class="stat-item">
36 <el-icon size="32" color="#e6a23c"><User /></el-icon>
37 <div class="stat-info">
38 <h3>{{ forumStats.activeUsers }}</h3>
39 <p>活跃用户</p>
40 </div>
41 </div>
42 <div class="stat-item">
43 <el-icon size="32" color="#f56c6c"><View /></el-icon>
44 <div class="stat-info">
45 <h3>{{ forumStats.todayPosts }}</h3>
46 <p>今日发帖</p>
47 </div>
48 </div>
49 </div>
50 </div>
51
52 <!-- 版块列表 -->
53 <div class="forum-sections">
54 <h2 class="section-title">论坛版块</h2>
55 <div class="sections-list">
56 <div
57 v-for="section in forumSections"
58 :key="section.id"
59 class="section-card"
60 @click="navigateToSection(section.id)"
61 >
62 <div class="section-icon">
63 <el-icon size="48" :color="section.color">
64 <component :is="section.icon" />
65 </el-icon>
66 </div>
67 <div class="section-info">
68 <h3 class="section-name">{{ section.name }}</h3>
69 <p class="section-description">{{ section.description }}</p>
70 <div class="section-stats">
71 <span class="stat">{{ section.topics }} 主题</span>
72 <span class="stat">{{ section.replies }} 回复</span>
73 </div>
74 </div>
75 <div class="section-latest">
76 <div v-if="section.latestTopic" class="latest-topic">
77 <p class="topic-title">{{ section.latestTopic.title }}</p>
78 <div class="topic-meta">
79 <span class="author">{{ section.latestTopic.author }}</span>
80 <span class="time">{{ formatTime(section.latestTopic.time) }}</span>
81 </div>
82 </div>
83 </div>
84 </div>
85 </div>
86 </div>
87
88 <!-- 热门主题 -->
89 <div class="hot-topics">
90 <div class="section-header">
91 <h2 class="section-title">热门主题</h2>
92 <el-button type="primary" text @click="$router.push('/forum/topics')">
93 查看全部 <el-icon><ArrowRight /></el-icon>
94 </el-button>
95 </div>
96 <div class="topics-list">
97 <div
98 v-for="topic in hotTopics"
99 :key="topic.id"
100 class="topic-item"
101 @click="navigateToTopic(topic.id)"
102 >
103 <div class="topic-content">
104 <div class="topic-header">
105 <h4 class="topic-title">{{ topic.title }}</h4>
106 <div class="topic-tags">
107 <el-tag
108 v-for="tag in topic.tags"
109 :key="tag"
110 size="small"
111 type="info"
112 >
113 {{ tag }}
114 </el-tag>
115 </div>
116 </div>
117 <div class="topic-meta">
118 <div class="author-info">
119 <el-avatar :size="24">{{ topic.author.charAt(0) }}</el-avatar>
120 <span class="author-name">{{ topic.author }}</span>
121 </div>
122 <div class="topic-stats">
123 <span class="stat-item">
124 <el-icon><View /></el-icon>
125 {{ topic.views }}
126 </span>
127 <span class="stat-item">
128 <el-icon><Comment /></el-icon>
129 {{ topic.replies }}
130 </span>
131 <span class="time">{{ formatTime(topic.lastReply) }}</span>
132 </div>
133 </div>
134 </div>
135 <div class="topic-status">
136 <el-tag v-if="topic.pinned" type="warning" size="small">置顶</el-tag>
137 <el-tag v-if="topic.hot" type="danger" size="small">热门</el-tag>
138 </div>
139 </div>
140 </div>
141 </div>
142
143 <!-- 最新回复 -->
144 <div class="recent-replies">
145 <h2 class="section-title">最新回复</h2>
146 <div class="replies-list">
147 <div
148 v-for="reply in recentReplies"
149 :key="reply.id"
150 class="reply-item"
151 @click="navigateToTopic(reply.topicId)"
152 >
153 <div class="reply-avatar">
154 <el-avatar :size="40">{{ reply.author.charAt(0) }}</el-avatar>
155 </div>
156 <div class="reply-content">
157 <div class="reply-header">
158 <span class="reply-author">{{ reply.author }}</span>
159 <span class="reply-action">回复了主题</span>
160 <span class="topic-title">{{ reply.topicTitle }}</span>
161 </div>
162 <div class="reply-text">{{ reply.content }}</div>
163 <div class="reply-time">{{ formatTime(reply.time) }}</div>
164 </div>
165 </div>
166 </div>
167 </div>
168 </div>
169
170 <!-- 发布新帖对话框 -->
171 <el-dialog
172 v-model="showNewTopicDialog"
173 title="发布新主题"
174 width="600px"
175 :before-close="handleCloseDialog"
176 >
177 <el-form
178 ref="topicFormRef"
179 :model="newTopic"
180 :rules="topicRules"
181 label-width="80px"
182 >
183 <el-form-item label="版块" prop="sectionId">
184 <el-select v-model="newTopic.sectionId" placeholder="选择版块">
185 <el-option
186 v-for="section in forumSections"
187 :key="section.id"
188 :label="section.name"
189 :value="section.id"
190 />
191 </el-select>
192 </el-form-item>
193
194 <el-form-item label="标题" prop="title">
195 <el-input
196 v-model="newTopic.title"
197 placeholder="请输入主题标题"
198 maxlength="100"
199 show-word-limit
200 />
201 </el-form-item>
202
203 <el-form-item label="标签">
204 <div class="tags-input">
205 <el-tag
206 v-for="tag in newTopic.tags"
207 :key="tag"
208 closable
209 @close="removeTopicTag(tag)"
210 >
211 {{ tag }}
212 </el-tag>
213 <el-input
214 v-if="tagInputVisible"
215 ref="tagInputRef"
216 v-model="tagInputValue"
217 size="small"
218 @keyup.enter="addTopicTag"
219 @blur="addTopicTag"
220 style="width: 100px;"
221 />
222 <el-button
223 v-else
224 size="small"
225 @click="showTagInput"
226 >
227 + 添加标签
228 </el-button>
229 </div>
230 </el-form-item>
231
232 <el-form-item label="内容" prop="content">
233 <el-input
234 v-model="newTopic.content"
235 type="textarea"
236 :rows="8"
237 placeholder="请输入主题内容..."
238 maxlength="5000"
239 show-word-limit
240 />
241 </el-form-item>
242 </el-form>
243
244 <template #footer>
245 <el-button @click="handleCloseDialog">取消</el-button>
246 <el-button type="primary" @click="submitNewTopic" :loading="submitting">
247 发布主题
248 </el-button>
249 </template>
250 </el-dialog>
251 </div>
252</template>
253
254<script>
255import { ref, reactive, onMounted, nextTick } from 'vue'
256import { useRouter } from 'vue-router'
257import { ElMessage, ElMessageBox } from 'element-plus'
258import {
259 Edit,
260 ChatDotRound,
261 Comment,
262 User,
263 View,
264 ArrowRight,
265 Film,
266 Headphones,
267 Monitor,
268 GamePad,
269 ChatLineRound,
270 QuestionFilled,
271 Bell
272} from '@element-plus/icons-vue'
Xing Jinwenebbccad2025-06-07 21:24:44 +0800273import Navbar from '@/components/Navbar.vue'
Xing Jinwenff16b1e2025-06-05 00:29:26 +0800274
275export default {
276 name: 'ForumView',
Xing Jinwenebbccad2025-06-07 21:24:44 +0800277 components:{
278 Navbar
279 },
Xing Jinwenff16b1e2025-06-05 00:29:26 +0800280 setup() {
281 const router = useRouter()
282 const topicFormRef = ref(null)
283 const tagInputRef = ref(null)
284
285 const showNewTopicDialog = ref(false)
286 const submitting = ref(false)
287 const tagInputVisible = ref(false)
288 const tagInputValue = ref('')
289
290 const forumStats = reactive({
291 totalTopics: '15,268',
292 totalReplies: '89,456',
293 activeUsers: '2,341',
294 todayPosts: '156'
295 })
296
297 const newTopic = reactive({
298 sectionId: '',
299 title: '',
300 content: '',
301 tags: []
302 })
303
304 const topicRules = {
305 sectionId: [
306 { required: true, message: '请选择版块', trigger: 'change' }
307 ],
308 title: [
309 { required: true, message: '请输入标题', trigger: 'blur' },
310 { min: 5, max: 100, message: '标题长度在 5 到 100 个字符', trigger: 'blur' }
311 ],
312 content: [
313 { required: true, message: '请输入内容', trigger: 'blur' },
314 { min: 10, max: 5000, message: '内容长度在 10 到 5000 个字符', trigger: 'blur' }
315 ]
316 }
317
318 const forumSections = ref([
319 {
320 id: 1,
321 name: '电影讨论',
322 description: '分享和讨论电影资源,交流观影心得',
323 icon: 'Film',
324 color: '#409eff',
325 topics: 3256,
326 replies: 18934,
327 latestTopic: {
328 title: '2024年最佳科幻电影推荐',
329 author: 'MovieFan',
330 time: '2025-06-03T14:30:00'
331 }
332 },
333 {
334 id: 2,
335 name: '音乐分享',
336 description: '音乐资源分享,音乐制作技术交流',
337 icon: 'Headphones',
338 color: '#67c23a',
339 topics: 1892,
340 replies: 9567,
341 latestTopic: {
342 title: '无损音乐格式对比分析',
343 author: 'AudioExpert',
344 time: '2025-06-03T13:45:00'
345 }
346 },
347 {
348 id: 3,
349 name: '软件技术',
350 description: '软件资源分享,技术问题讨论',
351 icon: 'Monitor',
352 color: '#e6a23c',
353 topics: 2134,
354 replies: 12456,
355 latestTopic: {
356 title: 'Adobe 2025 新功能体验分享',
357 author: 'TechGuru',
358 time: '2025-06-03T12:20:00'
359 }
360 },
361 {
362 id: 4,
363 name: '游戏天地',
364 description: '游戏资源分享,游戏攻略讨论',
365 icon: 'GamePad',
366 color: '#f56c6c',
367 topics: 1567,
368 replies: 8234,
369 latestTopic: {
370 title: '年度游戏大作盘点',
371 author: 'GameMaster',
372 time: '2025-06-03T11:50:00'
373 }
374 },
375 {
376 id: 5,
377 name: '站务公告',
378 description: '网站公告,规则说明,意见建议',
379 icon: 'Bell',
380 color: '#909399',
381 topics: 234,
382 replies: 1567,
383 latestTopic: {
384 title: '网站维护通知',
385 author: 'Admin',
386 time: '2025-06-03T10:00:00'
387 }
388 },
389 {
390 id: 6,
391 name: '新手求助',
392 description: '新手问题解答,使用教程分享',
393 icon: 'QuestionFilled',
394 color: '#606266',
395 topics: 456,
396 replies: 2890,
397 latestTopic: {
398 title: '新手如何提高分享率?',
399 author: 'Newbie123',
400 time: '2025-06-03T09:30:00'
401 }
402 }
403 ])
404
405 const hotTopics = ref([
406 {
407 id: 1,
408 title: '2024年度最佳PT站点推荐与对比分析',
409 author: 'PTExpert',
410 views: 2856,
411 replies: 147,
412 lastReply: '2025-06-03T14:25:00',
413 tags: ['PT站点', '推荐', '对比'],
414 pinned: true,
415 hot: true
416 },
417 {
418 id: 2,
419 title: '如何安全高效地使用BT下载工具',
420 author: 'SafeDownloader',
421 views: 1932,
422 replies: 89,
423 lastReply: '2025-06-03T13:50:00',
424 tags: ['BT工具', '安全', '教程'],
425 hot: true
426 },
427 {
428 id: 3,
429 title: '分享率提升技巧与经验总结',
430 author: 'SeedMaster',
431 views: 1654,
432 replies: 76,
433 lastReply: '2025-06-03T12:40:00',
434 tags: ['分享率', '技巧', '经验']
435 }
436 ])
437
438 const recentReplies = ref([
439 {
440 id: 1,
441 author: 'MovieLover88',
442 topicId: 1,
443 topicTitle: '阿凡达2观影感受分享',
444 content: '画面效果确实震撼,特别是水下的场景...',
445 time: '2025-06-03T14:45:00'
446 },
447 {
448 id: 2,
449 author: 'TechEnthusiast',
450 topicId: 2,
451 topicTitle: '最新版Photoshop使用技巧',
452 content: '新的AI功能确实很强大,大大提高了工作效率...',
453 time: '2025-06-03T14:30:00'
454 },
455 {
456 id: 3,
457 author: 'GameFan2024',
458 topicId: 3,
459 topicTitle: '赛博朋克2077最新更新体验',
460 content: '修复了很多bug,现在游戏体验好多了...',
461 time: '2025-06-03T14:15:00'
462 }
463 ])
464
465 onMounted(() => {
466 // 初始化论坛数据
467 })
468
469 const formatTime = (timeString) => {
470 const date = new Date(timeString)
471 const now = new Date()
472 const diff = now - date
473 const hours = Math.floor(diff / (1000 * 60 * 60))
474
475 if (hours < 1) return '刚刚'
476 if (hours < 24) return `${hours}小时前`
477 const days = Math.floor(hours / 24)
478 return `${days}天前`
479 }
480
481 const navigateToSection = (sectionId) => {
482 router.push(`/forum/section/${sectionId}`)
483 }
484
485 const navigateToTopic = (topicId) => {
486 router.push(`/forum/topic/${topicId}`)
487 }
488
489 const showTagInput = () => {
490 tagInputVisible.value = true
491 nextTick(() => {
492 tagInputRef.value?.focus()
493 })
494 }
495
496 const addTopicTag = () => {
497 const tag = tagInputValue.value.trim()
498 if (tag && !newTopic.tags.includes(tag)) {
499 newTopic.tags.push(tag)
500 }
501 tagInputVisible.value = false
502 tagInputValue.value = ''
503 }
504
505 const removeTopicTag = (tag) => {
506 const index = newTopic.tags.indexOf(tag)
507 if (index > -1) {
508 newTopic.tags.splice(index, 1)
509 }
510 }
511
512 const handleCloseDialog = () => {
513 if (newTopic.title || newTopic.content) {
514 ElMessageBox.confirm(
515 '确定要关闭吗?未保存的内容将会丢失。',
516 '提示',
517 {
518 confirmButtonText: '确定',
519 cancelButtonText: '取消',
520 type: 'warning'
521 }
522 ).then(() => {
523 resetForm()
524 showNewTopicDialog.value = false
525 }).catch(() => {
526 // 用户取消
527 })
528 } else {
529 resetForm()
530 showNewTopicDialog.value = false
531 }
532 }
533
534 const submitNewTopic = async () => {
535 try {
536 await topicFormRef.value?.validate()
537
538 submitting.value = true
539
540 // 模拟提交过程
541 await new Promise(resolve => setTimeout(resolve, 1500))
542
543 ElMessage.success('主题发布成功!')
544 resetForm()
545 showNewTopicDialog.value = false
546
547 // 跳转到新创建的主题页面
548 router.push('/forum/topic/new')
549
550 } catch (error) {
551 console.error('表单验证失败:', error)
552 } finally {
553 submitting.value = false
554 }
555 }
556
557 const resetForm = () => {
558 topicFormRef.value?.resetFields()
559 newTopic.sectionId = ''
560 newTopic.title = ''
561 newTopic.content = ''
562 newTopic.tags = []
563 }
564
565 return {
566 showNewTopicDialog,
567 submitting,
568 tagInputVisible,
569 tagInputValue,
570 topicFormRef,
571 tagInputRef,
572 forumStats,
573 forumSections,
574 hotTopics,
575 recentReplies,
576 newTopic,
577 topicRules,
578 formatTime,
579 navigateToSection,
580 navigateToTopic,
581 showTagInput,
582 addTopicTag,
583 removeTopicTag,
584 handleCloseDialog,
585 submitNewTopic,
586 Edit,
587 ChatDotRound,
588 Comment,
589 User,
590 View,
591 ArrowRight,
592 Film,
593 Headphones,
594 Monitor,
595 GamePad,
596 Bell,
597 QuestionFilled
598 }
599 }
600}
601</script>
602
603<style lang="scss" scoped>
604.forum-page {
605 max-width: 1200px;
606 margin: 0 auto;
607 padding: 24px;
608 background: #f5f5f5;
609 min-height: 100vh;
610}
611
612.forum-header {
613 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
614 border-radius: 12px;
615 padding: 48px 32px;
616 margin-bottom: 24px;
617 color: white;
618 text-align: center;
619
620 h1 {
621 font-size: 36px;
622 font-weight: 600;
623 margin: 0 0 12px 0;
624 }
625
626 .header-description {
627 font-size: 18px;
628 margin: 0 0 24px 0;
629 opacity: 0.9;
630 }
631}
632
633.forum-stats {
634 background: #fff;
635 border-radius: 12px;
636 padding: 24px;
637 margin-bottom: 24px;
638 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
639
640 .stats-grid {
641 display: grid;
642 grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
643 gap: 24px;
644
645 .stat-item {
646 display: flex;
647 align-items: center;
648 gap: 16px;
649
650 .stat-info {
651 h3 {
652 font-size: 24px;
653 font-weight: 600;
654 color: #2c3e50;
655 margin: 0 0 4px 0;
656 }
657
658 p {
659 font-size: 14px;
660 color: #7f8c8d;
661 margin: 0;
662 }
663 }
664 }
665 }
666}
667
668.forum-sections {
669 background: #fff;
670 border-radius: 12px;
671 padding: 24px;
672 margin-bottom: 24px;
673 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
674
675 .section-title {
676 font-size: 20px;
677 font-weight: 600;
678 color: #2c3e50;
679 margin: 0 0 20px 0;
680 }
681
682 .sections-list {
683 .section-card {
684 display: flex;
685 align-items: center;
686 gap: 20px;
687 padding: 20px;
688 border: 1px solid #f0f0f0;
689 border-radius: 8px;
690 margin-bottom: 12px;
691 cursor: pointer;
692 transition: all 0.3s ease;
693
694 &:hover {
695 background: #f8f9fa;
696 border-color: #409eff;
697 transform: translateX(4px);
698 }
699
700 .section-info {
701 flex: 1;
702
703 .section-name {
704 font-size: 18px;
705 font-weight: 600;
706 color: #2c3e50;
707 margin: 0 0 8px 0;
708 }
709
710 .section-description {
711 font-size: 14px;
712 color: #7f8c8d;
713 margin: 0 0 12px 0;
714 }
715
716 .section-stats {
717 display: flex;
718 gap: 16px;
719
720 .stat {
721 font-size: 12px;
722 color: #909399;
723 }
724 }
725 }
726
727 .section-latest {
728 width: 200px;
729
730 .latest-topic {
731 .topic-title {
732 font-size: 14px;
733 color: #2c3e50;
734 margin: 0 0 8px 0;
735 overflow: hidden;
736 text-overflow: ellipsis;
737 display: -webkit-box;
738 -webkit-line-clamp: 2;
739 -webkit-box-orient: vertical;
740 }
741
742 .topic-meta {
743 font-size: 12px;
744 color: #909399;
745
746 .author {
747 margin-right: 8px;
748 }
749 }
750 }
751 }
752 }
753 }
754}
755
756.hot-topics {
757 background: #fff;
758 border-radius: 12px;
759 padding: 24px;
760 margin-bottom: 24px;
761 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
762
763 .section-header {
764 display: flex;
765 justify-content: space-between;
766 align-items: center;
767 margin-bottom: 20px;
768
769 .section-title {
770 font-size: 20px;
771 font-weight: 600;
772 color: #2c3e50;
773 margin: 0;
774 }
775 }
776
777 .topics-list {
778 .topic-item {
779 display: flex;
780 justify-content: space-between;
781 align-items: center;
782 padding: 16px;
783 border: 1px solid #f0f0f0;
784 border-radius: 8px;
785 margin-bottom: 12px;
786 cursor: pointer;
787 transition: all 0.3s ease;
788
789 &:hover {
790 background: #f8f9fa;
791 border-color: #409eff;
792 }
793
794 .topic-content {
795 flex: 1;
796
797 .topic-header {
798 display: flex;
799 align-items: center;
800 gap: 12px;
801 margin-bottom: 8px;
802
803 .topic-title {
804 font-size: 16px;
805 font-weight: 500;
806 color: #2c3e50;
807 margin: 0;
808 }
809
810 .topic-tags {
811 .el-tag {
812 margin-right: 4px;
813 }
814 }
815 }
816
817 .topic-meta {
818 display: flex;
819 justify-content: space-between;
820 align-items: center;
821
822 .author-info {
823 display: flex;
824 align-items: center;
825 gap: 8px;
826
827 .author-name {
828 font-size: 14px;
829 color: #7f8c8d;
830 }
831 }
832
833 .topic-stats {
834 display: flex;
835 align-items: center;
836 gap: 16px;
837 font-size: 12px;
838 color: #909399;
839
840 .stat-item {
841 display: flex;
842 align-items: center;
843 gap: 4px;
844 }
845 }
846 }
847 }
848
849 .topic-status {
850 .el-tag {
851 margin-left: 8px;
852 }
853 }
854 }
855 }
856}
857
858.recent-replies {
859 background: #fff;
860 border-radius: 12px;
861 padding: 24px;
862 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
863
864 .section-title {
865 font-size: 20px;
866 font-weight: 600;
867 color: #2c3e50;
868 margin: 0 0 20px 0;
869 }
870
871 .replies-list {
872 .reply-item {
873 display: flex;
874 flex-direction: column;
875 gap: 12px;
876 padding: 16px;
877 border: 1px solid #f0f0f0;
878 border-radius: 8px;
879 margin-bottom: 12px;
880 cursor: pointer;
881 transition: all 0.3s ease;
882
883 &:hover {
884 background: #f8f9fa;
885 border-color: #409eff;
886 }
887
888 .reply-content {
889 flex: 1;
890
891 .reply-header {
892 font-size: 14px;
893 margin-bottom: 8px;
894
895 .reply-author {
896 font-weight: 600;
897 color: #2c3e50;
898 }
899
900 .reply-action {
901 color: #7f8c8d;
902 margin: 0 4px;
903 }
904
905 .topic-title {
906 color: #409eff;
907 font-weight: 500;
908 }
909 }
910
911 .reply-text {
912 font-size: 14px;
913 color: #5a6c7d;
914 margin-bottom: 8px;
915 overflow: hidden;
916 text-overflow: ellipsis;
917 display: -webkit-box;
918 -webkit-line-clamp: 2;
919 -webkit-box-orient: vertical;
920 }
921
922 .reply-time {
923 font-size: 12px;
924 color: #909399;
925 }
926 }
927 }
928 }
929}
930</style>
931
932.tags-input {
933 display: flex;
934 flex-wrap: wrap;
935 gap: 8px;
936 align-items: center;
937
938 .el-tag {
939 margin: 0;
940 }
941}
942
943@media (max-width: 768px) {
944 .forum-page {
945 padding: 16px;
946 }
947
948 .forum-header {
949 padding: 32px 24px;
950
951 h1 {
952 font-size: 28px;
953 }
954
955 .header-description {
956 font-size: 16px;
957 }
958 }
959
960 .stats-grid {
961 grid-template-columns: repeat(2, 1fr);
962 }
963
964 .section-card {
965 flex-direction: column;
966 text-align: center;
967
968 .section-latest {
969 width: 100%;
970 margin-top: 16px;
971 }
972 }
973
974 .topic-item {
975 flex-direction: column;
976 align-items: flex-start;
977
978 .topic-status {
979 margin-top: 12px;
980 align-self: flex-end;
981 }
982 }
xingjinwend652cc62025-06-04 19:52:19 +0800983}