blob: 98c97805a6f8be83c7f14d5e5797b613197bb352 [file] [log] [blame]
Xing Jinwenff16b1e2025-06-05 00:29:26 +08001<template>
vulgar5201c4345b12025-06-09 18:48:06 +08002 <Navbar />
Xing Jinwenff16b1e2025-06-05 00:29:26 +08003 <div class="section-page">
208159515458d95702025-06-09 14:46:58 +08004 <Navbar />
Xing Jinwenff16b1e2025-06-05 00:29:26 +08005 <div class="page-container">
6 <!-- 面包屑导航 -->
7 <div class="breadcrumb">
8 <el-breadcrumb separator="/">
9 <el-breadcrumb-item :to="{ path: '/forum' }">论坛首页</el-breadcrumb-item>
10 <el-breadcrumb-item>{{ sectionInfo.name }}</el-breadcrumb-item>
11 </el-breadcrumb>
12 </div>
13
14 <!-- 版块信息 -->
15 <div class="section-header">
16 <div class="section-info">
17 <div class="section-icon">
18 <el-icon size="48" :color="sectionInfo.color">
19 <component :is="sectionInfo.icon" />
20 </el-icon>
21 </div>
22 <div class="section-details">
23 <h1 class="section-name">{{ sectionInfo.name }}</h1>
24 <p class="section-description">{{ sectionInfo.description }}</p>
25 <div class="section-stats">
26 <div class="stat-item">
27 <el-icon><ChatDotRound /></el-icon>
28 <span>{{ sectionInfo.topics }} 主题</span>
29 </div>
Xing Jinwenff16b1e2025-06-05 00:29:26 +080030 </div>
31 </div>
32 </div>
33
34 <div class="section-actions">
35 <el-button type="primary" :icon="Edit" @click="showNewTopicDialog = true">
36 发布新主题
37 </el-button>
38 </div>
39 </div>
40
41 <!-- 筛选和搜索 -->
42 <div class="filter-section">
43 <div class="filter-left">
44 <el-input
45 v-model="searchQuery"
46 placeholder="搜索主题..."
47 :prefix-icon="Search"
48 @keyup.enter="handleSearch"
49 clearable
50 style="width: 300px;"
51 />
52 <el-button type="primary" @click="handleSearch">搜索</el-button>
53 </div>
54
55 <div class="filter-right">
56 <el-select v-model="sortBy" placeholder="排序方式" @change="handleFilter">
57 <el-option label="最新回复" value="last_reply" />
58 <el-option label="发布时间" value="create_time" />
59 <el-option label="回复数量" value="replies" />
60 <el-option label="浏览次数" value="views" />
61 </el-select>
62
63 <el-select v-model="filterType" placeholder="主题类型" @change="handleFilter">
64 <el-option label="全部主题" value="" />
65 <el-option label="置顶主题" value="pinned" />
66 <el-option label="热门主题" value="hot" />
67 <el-option label="精华主题" value="featured" />
68 </el-select>
69 </div>
70 </div>
71
72 <!-- 置顶主题 -->
73 <div v-if="pinnedTopics.length > 0" class="pinned-topics">
74 <h3 class="section-title">置顶主题</h3>
75 <div class="topics-list">
76 <div
77 v-for="topic in pinnedTopics"
78 :key="topic.id"
79 class="topic-item pinned"
80 @click="navigateToTopic(topic.id)"
81 >
82 <div class="topic-status">
83 <el-icon class="pin-icon"><Top /></el-icon>
84 </div>
85
86 <div class="topic-content">
87 <div class="topic-header">
88 <h4 class="topic-title">{{ topic.title }}</h4>
89 <div class="topic-tags">
90 <el-tag type="warning" size="small">置顶</el-tag>
91 <el-tag v-if="topic.hot" type="danger" size="small">热门</el-tag>
92 <el-tag v-if="topic.featured" type="success" size="small">精华</el-tag>
93 </div>
94 </div>
95
96 <div class="topic-meta">
97 <div class="author-info">
208159515458d95702025-06-09 14:46:58 +080098 <el-avatar :size="24">{{ topic.user?.username ? topic.user.username.charAt(0) : 'A' }}</el-avatar>
99 <span class="author-name">{{ topic.user?.username || '匿名' }}</span>
Xing Jinwenff16b1e2025-06-05 00:29:26 +0800100 <span class="create-time">{{ formatTime(topic.createTime) }}</span>
101 </div>
102
103 <div class="topic-stats">
104 <span class="stat-item">
105 <el-icon><View /></el-icon>
106 {{ topic.views }}
107 </span>
108 <span class="stat-item">
109 <el-icon><Comment /></el-icon>
110 {{ topic.replies }}
111 </span>
112 </div>
113 </div>
114 </div>
115
116 <div class="last-reply">
117 <div v-if="topic.lastReply" class="reply-info">
118 <div class="reply-author">{{ topic.lastReply.author }}</div>
119 <div class="reply-time">{{ formatTime(topic.lastReply.time) }}</div>
120 </div>
121 </div>
122 </div>
123 </div>
124 </div>
125
126 <!-- 普通主题列表 -->
127 <div class="normal-topics">
128 <div class="section-header">
129 <h3 class="section-title">主题列表</h3>
130 <div class="results-info">
131 共 {{ totalTopics }} 个主题
132 </div>
133 </div>
134
135 <div class="topics-list" v-loading="loading">
136 <div
137 v-for="topic in topics"
138 :key="topic.id"
139 class="topic-item"
140 @click="navigateToTopic(topic.id)"
141 >
142 <div class="topic-status">
143 <el-icon v-if="topic.hasNewReplies" class="new-icon" color="#f56c6c">
144 <ChatDotRound />
145 </el-icon>
146 <el-icon v-else class="normal-icon" color="#909399">
147 <ChatLineRound />
148 </el-icon>
149 </div>
150
151 <div class="topic-content">
152 <div class="topic-header">
153 <h4 class="topic-title">{{ topic.title }}</h4>
154 <div class="topic-tags">
155 <el-tag v-if="topic.hot" type="danger" size="small">热门</el-tag>
156 <el-tag v-if="topic.featured" type="success" size="small">精华</el-tag>
157 <el-tag v-if="topic.closed" type="info" size="small">已关闭</el-tag>
158 </div>
159 </div>
160
161 <div class="topic-meta">
162 <div class="author-info">
208159515458d95702025-06-09 14:46:58 +0800163 <el-avatar :size="24">{{ topic.user?.username ? topic.user.username.charAt(0) : 'A' }}</el-avatar>
164 <span class="author-name">{{ topic.user?.username || '匿名' }}</span>
Xing Jinwenff16b1e2025-06-05 00:29:26 +0800165 <span class="create-time">{{ formatTime(topic.createTime) }}</span>
166 </div>
167
168 <div class="topic-stats">
169 <span class="stat-item">
170 <el-icon><View /></el-icon>
171 {{ topic.views }}
172 </span>
173 <span class="stat-item">
174 <el-icon><Comment /></el-icon>
175 {{ topic.replies }}
176 </span>
177 </div>
178 </div>
179 </div>
180
181 <div class="last-reply">
182 <div v-if="topic.lastReply" class="reply-info">
183 <div class="reply-author">{{ topic.lastReply.author }}</div>
184 <div class="reply-time">{{ formatTime(topic.lastReply.time) }}</div>
185 </div>
186 <div v-else class="no-reply">暂无回复</div>
187 </div>
188 </div>
189
190 <div v-if="topics.length === 0 && !loading" class="no-topics">
191 暂无主题,快来发布第一个主题吧!
192 </div>
193 </div>
194
195 <!-- 分页 -->
196 <div class="pagination-wrapper">
197 <el-pagination
208159515458d95702025-06-09 14:46:58 +0800198 v-model="currentPage"
199 :page-size="pageSize"
Xing Jinwenff16b1e2025-06-05 00:29:26 +0800200 :page-sizes="[20, 50, 100]"
201 :total="totalTopics"
202 layout="total, sizes, prev, pager, next, jumper"
203 @size-change="handleSizeChange"
204 @current-change="handleCurrentChange"
205 />
206 </div>
207 </div>
208 </div>
209
210 <!-- 发布新主题对话框 -->
211 <el-dialog
212 v-model="showNewTopicDialog"
213 title="发布新主题"
214 width="600px"
215 :before-close="handleCloseDialog"
216 >
217 <el-form
218 ref="topicFormRef"
219 :model="newTopic"
220 :rules="topicRules"
221 label-width="80px"
222 >
223 <el-form-item label="主题标题" prop="title">
224 <el-input
225 v-model="newTopic.title"
226 placeholder="请输入主题标题"
227 maxlength="100"
228 show-word-limit
229 />
230 </el-form-item>
231
232 <el-form-item label="主题标签">
233 <div class="tags-input">
234 <el-tag
235 v-for="tag in newTopic.tags"
236 :key="tag"
237 closable
238 @close="removeTopicTag(tag)"
239 >
240 {{ tag }}
241 </el-tag>
242 <el-input
243 v-if="tagInputVisible"
244 ref="tagInputRef"
245 v-model="tagInputValue"
246 size="small"
247 @keyup.enter="addTopicTag"
248 @blur="addTopicTag"
249 style="width: 100px;"
250 />
251 <el-button
252 v-else
253 size="small"
254 @click="showTagInput"
255 >
256 + 添加标签
257 </el-button>
258 </div>
259 </el-form-item>
260
261 <el-form-item label="主题内容" prop="content">
262 <el-input
263 v-model="newTopic.content"
264 type="textarea"
265 :rows="8"
266 placeholder="请输入主题内容..."
267 maxlength="5000"
268 show-word-limit
269 />
270 </el-form-item>
271
272 <el-form-item label="主题选项">
273 <el-checkbox-group v-model="newTopic.options">
274 <el-checkbox label="hot">申请热门</el-checkbox>
275 <el-checkbox label="featured">申请精华</el-checkbox>
276 </el-checkbox-group>
277 </el-form-item>
278 </el-form>
279
280 <template #footer>
281 <el-button @click="handleCloseDialog">取消</el-button>
282 <el-button type="primary" @click="submitNewTopic" :loading="submitting">
283 发布主题
284 </el-button>
285 </template>
286 </el-dialog>
287 </div>
288</template>
289
290<script>
291import { ref, reactive, onMounted, nextTick } from 'vue'
292import { useRoute, useRouter } from 'vue-router'
293import { ElMessage, ElMessageBox } from 'element-plus'
294import {
295 Edit,
296 Search,
297 ChatDotRound,
298 Comment,
299 User,
300 View,
301 Top,
302 ChatLineRound,
303 Film,
304 Headphones,
305 Monitor,
306 GamePad,
307 Bell,
308 QuestionFilled
309} from '@element-plus/icons-vue'
208159515458d95702025-06-09 14:46:58 +0800310import { getTopicsByForum, createTopic } from '@/api/topic'
311import Navbar from "@/components/Navbar.vue";
Xing Jinwenff16b1e2025-06-05 00:29:26 +0800312
313export default {
314 name: 'ForumSectionView',
208159515458d95702025-06-09 14:46:58 +0800315 components: {Navbar},
Xing Jinwenff16b1e2025-06-05 00:29:26 +0800316 setup() {
317 const route = useRoute()
318 const router = useRouter()
319 const topicFormRef = ref(null)
320 const tagInputRef = ref(null)
321
322 const loading = ref(false)
323 const showNewTopicDialog = ref(false)
324 const submitting = ref(false)
325 const tagInputVisible = ref(false)
326 const tagInputValue = ref('')
327
328 const searchQuery = ref('')
329 const sortBy = ref('last_reply')
330 const filterType = ref('')
331 const currentPage = ref(1)
332 const pageSize = ref(20)
333 const totalTopics = ref(0)
334
335 const sectionInfo = ref({
336 id: 1,
337 name: '电影讨论',
338 description: '分享和讨论电影资源,交流观影心得',
339 icon: 'Film',
340 color: '#409eff',
341 topics: 3256,
342 replies: 18934,
343 members: 1234
344 })
345
346 const newTopic = reactive({
347 title: '',
348 content: '',
349 tags: [],
350 options: []
351 })
352
353 const topicRules = {
354 title: [
355 { required: true, message: '请输入标题', trigger: 'blur' },
356 { min: 5, max: 100, message: '标题长度在 5 到 100 个字符', trigger: 'blur' }
357 ],
358 content: [
359 { required: true, message: '请输入内容', trigger: 'blur' },
360 { min: 10, max: 5000, message: '内容长度在 10 到 5000 个字符', trigger: 'blur' }
361 ]
362 }
363
364 const pinnedTopics = ref([
365 {
366 id: 1,
367 title: '【公告】本版块发帖规则和注意事项',
368 author: 'Admin',
369 createTime: '2025-05-01T10:00:00',
370 views: 5678,
371 replies: 23,
372 hot: false,
373 featured: true,
374 lastReply: {
375 author: 'User123',
376 time: '2025-06-02T15:30:00'
377 }
378 }
379 ])
380
208159515458d95702025-06-09 14:46:58 +0800381 const topics = ref([])
Xing Jinwenff16b1e2025-06-05 00:29:26 +0800382
383 onMounted(() => {
384 const sectionId = route.params.id
385 fetchSectionData(sectionId)
208159515458d95702025-06-09 14:46:58 +0800386 fetchTopics()
Xing Jinwenff16b1e2025-06-05 00:29:26 +0800387 })
388
389 const fetchSectionData = async (id) => {
390 loading.value = true
391 try {
392 // 模拟API调用
393 console.log('获取版块数据:', id)
394
395 // 根据版块ID设置不同的版块信息
396 const sections = {
397 1: { name: '电影讨论', description: '分享和讨论电影资源,交流观影心得', icon: 'Film', color: '#409eff' },
398 2: { name: '音乐分享', description: '音乐资源分享,音乐制作技术交流', icon: 'Headphones', color: '#67c23a' },
399 3: { name: '软件技术', description: '软件资源分享,技术问题讨论', icon: 'Monitor', color: '#e6a23c' },
400 4: { name: '游戏天地', description: '游戏资源分享,游戏攻略讨论', icon: 'GamePad', color: '#f56c6c' },
401 5: { name: '站务公告', description: '网站公告,规则说明,意见建议', icon: 'Bell', color: '#909399' },
402 6: { name: '新手求助', description: '新手问题解答,使用教程分享', icon: 'QuestionFilled', color: '#606266' }
403 }
404
405 const sectionData = sections[id] || sections[1]
406 sectionInfo.value = {
407 id: parseInt(id),
408 ...sectionData,
208159515458d95702025-06-09 14:46:58 +0800409 topics: 0 // 初始化为0,会在fetchTopics中更新为真实数量
Xing Jinwenff16b1e2025-06-05 00:29:26 +0800410 }
411
412 totalTopics.value = 156
413
414 } catch (error) {
415 ElMessage.error('获取版块数据失败')
416 } finally {
417 loading.value = false
418 }
419 }
420
421 const formatTime = (timeString) => {
422 const date = new Date(timeString)
423 const now = new Date()
424 const diff = now - date
425 const hours = Math.floor(diff / (1000 * 60 * 60))
426
427 if (hours < 1) return '刚刚'
428 if (hours < 24) return `${hours}小时前`
429 const days = Math.floor(hours / 24)
430 if (days < 7) return `${days}天前`
431
432 return date.toLocaleDateString('zh-CN', {
433 month: '2-digit',
434 day: '2-digit',
435 hour: '2-digit',
436 minute: '2-digit'
437 })
438 }
439
440 const navigateToTopic = (topicId) => {
441 router.push(`/forum/topic/${topicId}`)
442 }
443
444 const handleSearch = () => {
445 currentPage.value = 1
446 fetchTopics()
447 }
448
449 const handleFilter = () => {
450 currentPage.value = 1
451 fetchTopics()
452 }
453
454 const fetchTopics = async () => {
455 loading.value = true
456 try {
208159515458d95702025-06-09 14:46:58 +0800457 // 调用后端API获取主题列表
458 const res = await getTopicsByForum(sectionInfo.value.id)
459 topics.value = res.data || res // 兼容不同返回结构
460 totalTopics.value = topics.value.length
461 // 同时更新顶部显示的主题数量
462 sectionInfo.value.topics = topics.value.length
Xing Jinwenff16b1e2025-06-05 00:29:26 +0800463 } catch (error) {
464 ElMessage.error('获取主题列表失败')
465 } finally {
466 loading.value = false
467 }
468 }
469
470 const handleSizeChange = (size) => {
471 pageSize.value = size
472 currentPage.value = 1
473 fetchTopics()
474 }
475
476 const handleCurrentChange = (page) => {
477 currentPage.value = page
478 fetchTopics()
479 }
480
481 const showTagInput = () => {
482 tagInputVisible.value = true
483 nextTick(() => {
484 tagInputRef.value?.focus()
485 })
486 }
487
488 const addTopicTag = () => {
489 const tag = tagInputValue.value.trim()
490 if (tag && !newTopic.tags.includes(tag)) {
491 newTopic.tags.push(tag)
492 }
493 tagInputVisible.value = false
494 tagInputValue.value = ''
495 }
496
497 const removeTopicTag = (tag) => {
498 const index = newTopic.tags.indexOf(tag)
499 if (index > -1) {
500 newTopic.tags.splice(index, 1)
501 }
502 }
503
504 const handleCloseDialog = () => {
505 if (newTopic.title || newTopic.content) {
506 ElMessageBox.confirm(
507 '确定要关闭吗?未保存的内容将会丢失。',
508 '提示',
509 {
510 confirmButtonText: '确定',
511 cancelButtonText: '取消',
512 type: 'warning'
513 }
514 ).then(() => {
515 resetForm()
516 showNewTopicDialog.value = false
517 }).catch(() => {
518 // 用户取消
519 })
520 } else {
521 resetForm()
522 showNewTopicDialog.value = false
523 }
524 }
525
526 const submitNewTopic = async () => {
527 try {
528 await topicFormRef.value?.validate()
529
530 submitting.value = true
531
208159515458d95702025-06-09 14:46:58 +0800532 // 构建主题数据
533 const topicData = {
534 title: newTopic.title,
535 content: newTopic.content,
536 forumId: sectionInfo.value.id, // 使用当前版块ID
537 tags: newTopic.tags,
538 isPinned: newTopic.options.includes('hot'),
539 isLocked: false
540 }
541
542 console.log('提交主题数据:', topicData)
543
544 // 调用API创建主题
545 const response = await createTopic(topicData)
Xing Jinwenff16b1e2025-06-05 00:29:26 +0800546
547 ElMessage.success('主题发布成功!')
548 resetForm()
549 showNewTopicDialog.value = false
550
551 // 刷新主题列表
552 fetchTopics()
553
554 } catch (error) {
208159515458d95702025-06-09 14:46:58 +0800555 console.error('发布主题失败:', error)
556 ElMessage.error('发布主题失败,请重试')
Xing Jinwenff16b1e2025-06-05 00:29:26 +0800557 } finally {
558 submitting.value = false
559 }
560 }
561
562 const resetForm = () => {
563 topicFormRef.value?.resetFields()
564 newTopic.title = ''
565 newTopic.content = ''
566 newTopic.tags = []
567 newTopic.options = []
568 }
569
570 return {
571 loading,
572 showNewTopicDialog,
573 submitting,
574 tagInputVisible,
575 tagInputValue,
576 searchQuery,
577 sortBy,
578 filterType,
579 currentPage,
580 pageSize,
581 totalTopics,
582 sectionInfo,
583 pinnedTopics,
584 topics,
585 newTopic,
586 topicRules,
587 topicFormRef,
588 tagInputRef,
589 formatTime,
590 navigateToTopic,
591 handleSearch,
592 handleFilter,
593 handleSizeChange,
594 handleCurrentChange,
595 showTagInput,
596 addTopicTag,
597 removeTopicTag,
598 handleCloseDialog,
599 submitNewTopic,
600 Edit,
601 Search,
602 ChatDotRound,
603 Comment,
604 User,
605 View,
606 Top,
607 ChatLineRound,
608 Film,
609 Headphones,
610 Monitor,
611 GamePad,
612 Bell,
613 QuestionFilled
614 }
615 }
616}
617</script>
618
619<style lang="scss" scoped>
620.section-page {
621 max-width: 1200px;
622 margin: 0 auto;
623 padding: 24px;
624 background: #f5f5f5;
625 min-height: 100vh;
626}
627
628.breadcrumb {
629 margin-bottom: 16px;
630}
631
632.section-header {
633 background: #fff;
634 border-radius: 12px;
635 padding: 32px;
636 margin-bottom: 24px;
637 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
638
639 display: flex;
640 justify-content: space-between;
641 align-items: center;
642 gap: 24px;
643
644 .section-info {
645 display: flex;
646 align-items: center;
647 gap: 20px;
648 flex: 1;
649
650 .section-details {
651 .section-name {
652 font-size: 28px;
653 font-weight: 600;
654 color: #2c3e50;
655 margin: 0 0 8px 0;
656 }
657
658 .section-description {
659 font-size: 16px;
660 color: #7f8c8d;
661 margin: 0 0 16px 0;
662 }
663
664 .section-stats {
665 display: flex;
666 gap: 24px;
667
668 .stat-item {
669 display: flex;
670 align-items: center;
671 gap: 8px;
672 font-size: 14px;
673 color: #606266;
674 }
675 }
676 }
677 }
678
679 .section-actions {
680 flex-shrink: 0;
681 }
682}
683
684.filter-section {
685 background: #fff;
686 border-radius: 12px;
687 padding: 20px 24px;
688 margin-bottom: 24px;
689 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
690
691 display: flex;
692 justify-content: space-between;
693 align-items: center;
694 gap: 20px;
695
696 .filter-left {
697 display: flex;
698 align-items: center;
699 gap: 12px;
700 }
701
702 .filter-right {
703 display: flex;
704 align-items: center;
705 gap: 12px;
706
707 .el-select {
708 width: 120px;
709 }
710 }
711}
712
713.pinned-topics, .normal-topics {
714 background: #fff;
715 border-radius: 12px;
716 padding: 24px;
717 margin-bottom: 24px;
718 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
719
720 .section-header {
721 display: flex;
722 justify-content: space-between;
723 align-items: center;
724 margin-bottom: 20px;
725 background: none;
726 padding: 0;
727 box-shadow: none;
728
729 .section-title {
730 font-size: 18px;
731 font-weight: 600;
732 color: #2c3e50;
733 margin: 0;
734 }
735
736 .results-info {
737 font-size: 14px;
738 color: #909399;
739 }
740 }
741}
742
743.topics-list {
744 .topic-item {
745 display: flex;
746 align-items: center;
747 gap: 16px;
748 padding: 16px;
749 border: 1px solid #f0f0f0;
750 border-radius: 8px;
751 margin-bottom: 12px;
752 cursor: pointer;
753 transition: all 0.3s ease;
754
755 &:hover {
756 background: #f8f9fa;
757 border-color: #409eff;
758 transform: translateX(2px);
759 }
760
761 &.pinned {
762 background: linear-gradient(90deg, #fff7e6 0%, #fff 100%);
763 border-color: #e6a23c;
764 }
765
766 .topic-status {
767 width: 32px;
768 text-align: center;
769
770 .pin-icon {
771 color: #e6a23c;
772 }
773
774 .new-icon {
775 animation: pulse 2s infinite;
776 }
777 }
778
779 .topic-content {
780 flex: 1;
781
782 .topic-header {
783 display: flex;
784 align-items: center;
785 gap: 12px;
786 margin-bottom: 8px;
787
788 .topic-title {
789 font-size: 16px;
790 font-weight: 500;
791 color: #2c3e50;
792 margin: 0;
793 flex: 1;
794
795 &:hover {
796 color: #409eff;
797 }
798 }
799
800 .topic-tags {
801 .el-tag {
802 margin-left: 4px;
803 }
804 }
805 }
806
807 .topic-meta {
808 display: flex;
809 justify-content: space-between;
810 align-items: center;
811
812 .author-info {
813 display: flex;
814 align-items: center;
815 gap: 8px;
816
817 .author-name {
818 font-size: 14px;
819 font-weight: 500;
820 color: #606266;
821 }
822
823 .create-time {
824 font-size: 12px;
825 color: #909399;
826 }
827 }
828
829 .topic-stats {
830 display: flex;
831 gap: 16px;
832
833 .stat-item {
834 display: flex;
835 align-items: center;
836 gap: 4px;
837 font-size: 12px;
838 color: #909399;
839 }
840 }
841 }
842 }
843
844 .last-reply {
845 width: 150px;
846 text-align: right;
847
848 .reply-info {
849 .reply-author {
850 font-size: 14px;
851 font-weight: 500;
852 color: #606266;
853 margin-bottom: 4px;
854 }
855
856 .reply-time {
857 font-size: 12px;
858 color: #909399;
859 }
860 }
861
862 .no-reply {
863 font-size: 12px;
864 color: #c0c4cc;
865 }
866 }
867 }
868
869 .no-topics {
870 text-align: center;
871 color: #909399;
872 padding: 60px 0;
873 font-size: 16px;
874 }
875}
876
877.pagination-wrapper {
878 margin-top: 24px;
879 text-align: center;
880}
881
882.tags-input {
883 display: flex;
884 flex-wrap: wrap;
885 gap: 8px;
886 align-items: center;
887
888 .el-tag {
889 margin: 0;
890 }
891}
892
893@keyframes pulse {
894 0% {
895 transform: scale(1);
896 }
897 50% {
898 transform: scale(1.1);
899 }
900 100% {
901 transform: scale(1);
902 }
903}
904
905@media (max-width: 768px) {
906 .section-page {
907 padding: 16px;
908 }
909
910 .section-header {
911 flex-direction: column;
912 align-items: flex-start;
913 gap: 16px;
914
915 .section-info {
916 flex-direction: column;
917 text-align: center;
918
919 .section-stats {
920 justify-content: center;
921 }
922 }
923
924 .section-actions {
925 width: 100%;
926 text-align: center;
927 }
928 }
929
930 .filter-section {
931 flex-direction: column;
932 gap: 16px;
933
934 .filter-left, .filter-right {
935 width: 100%;
936 justify-content: center;
937 }
938
939 .filter-right {
940 .el-select {
941 width: 140px;
942 }
943 }
944 }
945
946 .topic-item {
947 flex-direction: column;
948 align-items: flex-start;
949 gap: 12px;
950
951 .topic-status {
952 align-self: flex-start;
953 }
954
955 .topic-content {
956 width: 100%;
957
958 .topic-meta {
959 flex-direction: column;
960 align-items: flex-start;
961 gap: 8px;
962 }
963 }
964
965 .last-reply {
966 width: 100%;
967 text-align: left;
968 }
969 }
970}
xingjinwend652cc62025-06-04 19:52:19 +0800971</style>