916 lines
20 KiB
Plaintext
916 lines
20 KiB
Plaintext
<!-- 专题详情页面 - 专题内容展示和管理 -->
|
|
<template>
|
|
<scroll-view direction="vertical" class="topic-detail" :scroll-y="true" :enable-back-to-top="true">
|
|
<!-- 专题头部 -->
|
|
<view class="topic-header" v-if="topicData !== null">
|
|
<view class="header-cover" :style="{ backgroundImage: `url(${topicData.cover_image})` }">
|
|
<view class="header-overlay">
|
|
<view class="back-btn" @click="goBack">
|
|
<text class="back-icon">←</text>
|
|
</view>
|
|
<view class="topic-badges">
|
|
<view class="type-badge" :style="{ backgroundColor: getTopicStatusColor(topicData.status) }">
|
|
<text class="badge-text">{{ $t('mt.topic.type.' + topicData.topic_type) }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view class="header-info">
|
|
<text class="topic-title">{{ topicData.title }}</text>
|
|
<text class="topic-description">{{ topicData.description }}</text>
|
|
<view class="topic-meta">
|
|
<view class="meta-stats">
|
|
<text class="stat-item">📄 {{ topicData.content_count }}{{ $t('mt.topic.contentCountUnit') }}</text>
|
|
<text class="stat-item">👁 {{ topicData.view_count }}{{ $t('mt.topic.viewCountUnit') }}</text>
|
|
<text class="stat-item">📅 {{ formatRelativeTimeKey(topicData.updated_at) }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 专题内容区域 -->
|
|
<view class="topic-content">
|
|
<!-- 内容筛选 -->
|
|
<view class="content-filters">
|
|
<view class="filter-tabs">
|
|
<view
|
|
class="filter-tab"
|
|
:class="{ active: currentViewMode === 'timeline' }"
|
|
@click="setViewMode('timeline')">
|
|
<text class="filter-text">{{ $t('mt.topic.filter.timeline') }}</text>
|
|
</view>
|
|
<view
|
|
class="filter-tab"
|
|
:class="{ active: currentViewMode === 'category' }"
|
|
@click="setViewMode('category')">
|
|
<text class="filter-text">{{ $t('mt.topic.filter.category') }}</text>
|
|
</view>
|
|
<view
|
|
class="filter-tab"
|
|
:class="{ active: currentViewMode === 'quality' }"
|
|
@click="setViewMode('quality')">
|
|
<text class="filter-text">{{ $t('mt.topic.filter.quality') }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 加载状态 -->
|
|
<view class="loading-section" v-if="contentState.loading">
|
|
<text class="loading-text">{{ $t('loading') }}</text>
|
|
</view>
|
|
|
|
<!-- 错误状态 -->
|
|
<view class="error-section" v-if="contentState.error !== null">
|
|
<text class="error-text">{{ contentState.error }}</text>
|
|
<view class="retry-btn" @click="retryLoadContent">
|
|
<text class="retry-text">{{ $t('mt.common.retry') }}</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 时间轴视图 -->
|
|
<view class="timeline-view" v-if="currentViewMode === 'timeline' && topicContentsList.length > 0">
|
|
<view
|
|
v-for="(content, index) in topicContentsList"
|
|
:key="content.id"
|
|
class="timeline-item">
|
|
<view class="timeline-dot"></view>
|
|
<view class="timeline-content" @click="navigateToContent(content)">
|
|
<view class="timeline-header">
|
|
<text class="timeline-title">{{ content.title }}</text>
|
|
<text class="timeline-time">{{ formatRelativeTimeKey(content.published_at) }}</text>
|
|
</view>
|
|
<text class="timeline-summary">{{ content.summary }}</text>
|
|
<view class="timeline-meta">
|
|
<text class="meta-author">{{ content.author }}</text>
|
|
<view class="quality-badge" :style="{ backgroundColor: getQualityScoreColor(content.quality_score) }">
|
|
<text class="quality-text">{{ getQualityScoreText(content.quality_score) }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 分类视图 -->
|
|
<view class="category-view" v-if="currentViewMode === 'category' && topicContentsList.length > 0">
|
|
<view
|
|
v-for="(content, index) in topicContentsList"
|
|
:key="content.id"
|
|
class="category-item"
|
|
@click="navigateToContent(content)">
|
|
<view class="category-header">
|
|
<text class="category-title">{{ content.title }}</text>
|
|
<view class="category-badge">
|
|
<text class="category-text">{{ content.category_id }}</text>
|
|
</view>
|
|
</view>
|
|
<text class="category-summary">{{ content.summary }}</text>
|
|
<view class="category-footer">
|
|
<view class="category-stats">
|
|
<text class="stat-text">👁 {{ content.view_count }}</text>
|
|
<text class="stat-text">👍 {{ content.like_count }}</text>
|
|
</view>
|
|
<text class="category-time">{{ formatRelativeTimeKey(content.published_at) }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 精选视图 -->
|
|
<view class="quality-view" v-if="currentViewMode === 'quality' && topicContentsList.length > 0">
|
|
<view
|
|
v-for="(content, index) in qualityContentsList"
|
|
:key="content.id"
|
|
class="quality-item"
|
|
@click="navigateToContent(content)">
|
|
<view class="quality-header">
|
|
<text class="quality-title">{{ content.title }}</text>
|
|
<view class="quality-score" :style="{ backgroundColor: getQualityScoreColor(content.quality_score) }">
|
|
<text class="score-text">{{ getQualityScoreText(content.quality_score) }}</text>
|
|
</view>
|
|
</view>
|
|
<text class="quality-summary">{{ content.summary }}</text>
|
|
<view class="quality-footer">
|
|
<text class="quality-author">{{ content.author }}</text>
|
|
<view class="quality-stats">
|
|
<text class="stat-text">👁 {{ content.view_count }}</text>
|
|
<text class="stat-text">👍 {{ content.like_count }}</text>
|
|
<text class="stat-text">📤 {{ content.share_count }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 空状态 -->
|
|
<view class="empty-section" v-if="topicContentsList.length === 0 && !contentState.loading && contentState.error === null">
|
|
<text class="empty-text">{{ $t('mt.common.empty') }}</text>
|
|
<view class="refresh-btn" @click="refreshContent">
|
|
<text class="refresh-text">{{ $t('mt.common.refresh') }}</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 加载更多 -->
|
|
<view class="load-more-section" v-if="topicContentsList.length > 0 && hasMoreContent">
|
|
<view class="load-more-btn" @click="loadMoreContent" v-if="!loadingMoreContent">
|
|
<text class="load-more-text">{{ $t('mt.common.loadMore') }}</text>
|
|
</view>
|
|
<view class="loading-more" v-if="loadingMoreContent">
|
|
<text class="loading-more-text">{{ $t('mt.common.loadingMore') }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 相关专题推荐 -->
|
|
<view class="related-topics" v-if="relatedTopicsList.length > 0">
|
|
<view class="section-header">
|
|
<text class="section-title">{{ $t('mt.topic.related') }}</text>
|
|
</view>
|
|
<scroll-view direction="horizontal" class="related-scroll" :scroll-x="true">
|
|
<view class="related-list">
|
|
<view
|
|
v-for="(topic, index) in relatedTopicsList"
|
|
:key="topic.id"
|
|
class="related-item"
|
|
@click="navigateToTopic(topic)">
|
|
<text class="related-title">{{ topic.title }}</text>
|
|
<text class="related-desc">{{ topic.description }}</text>
|
|
<view class="related-stats">
|
|
<text class="related-stat">{{ topic.content_count }}{{ $t('mt.topic.contentCountUnit') }}</text>
|
|
<text class="related-stat">{{ topic.view_count }}{{ $t('mt.topic.viewCountUnit') }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
|
|
<!-- 评论区域 -->
|
|
<view class="comments-section" v-if="topicData !== null">
|
|
<Comments
|
|
:targetType="'topic'"
|
|
:targetId="topicData.id"
|
|
:userId="currentUserId"
|
|
:userName="currentUserName">
|
|
</Comments>
|
|
</view>
|
|
|
|
<!-- 底部操作栏 -->
|
|
<view class="bottom-actions">
|
|
<view class="action-item" @click="shareTopic">
|
|
<text class="action-icon">📤</text>
|
|
<text class="action-text">{{ $t('mt.topic.action.share') }}</text>
|
|
</view>
|
|
<view class="action-item" @click="subscribeTopic">
|
|
<text class="action-icon">🔔</text>
|
|
<text class="action-text">{{ $t('mt.topic.action.subscribe') }}</text>
|
|
</view>
|
|
<view class="action-item" @click="openChat">
|
|
<text class="action-icon">💬</text>
|
|
<text class="action-text">{{ $t('mt.topic.action.aiAssistant') }}</text>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
</template>
|
|
|
|
<script setup lang="uts">
|
|
import Comments from './comments.uvue'
|
|
import {
|
|
Topic,
|
|
InfoContent,
|
|
PageState,
|
|
formatRelativeTimeKey,
|
|
getTopicStatusColor,
|
|
getQualityScoreText,
|
|
getQualityScoreColor
|
|
} from './types.uts'
|
|
import supa from '@/components/supadb/aksupainstance.uts'
|
|
import { tt } from '@/utils/i18nfun.uts'
|
|
import i18n from '@/i18n/index.uts' // 保留用于语言切换
|
|
|
|
// 页面参数
|
|
const topicId = ref<string>('')
|
|
|
|
// 专题数据
|
|
const topicData = ref<Topic | null>(null)
|
|
|
|
// 内容状态
|
|
const contentState = ref<PageState>({
|
|
loading: false,
|
|
error: null,
|
|
currentPage: 1,
|
|
pageSize: 20,
|
|
total: 0
|
|
})
|
|
|
|
// UI状态
|
|
const currentViewMode = ref<string>('timeline')
|
|
const hasMoreContent = ref<boolean>(true)
|
|
const loadingMoreContent = ref<boolean>(false)
|
|
const contentPageSize = ref<number>(20)
|
|
|
|
// 用户信息 - 评论功能需要
|
|
const currentUserId = ref<string>('user-demo-001')
|
|
const currentUserName = ref<string>('演示用户')
|
|
|
|
// 数据列表
|
|
const topicContentsList = ref<Array<InfoContent>>([])
|
|
const relatedTopicsList = ref<Array<Topic>>([])
|
|
|
|
// 计算属性
|
|
const qualityContentsList = computed((): Array<InfoContent> => {
|
|
return topicContentsList.value.filter(c => c.quality_score >= 0.8)
|
|
})
|
|
|
|
const topicContentFilter = computed((): string => {
|
|
let filter = `topic_id=eq.${topicId.value}`
|
|
|
|
// 根据视图模式调整排序
|
|
if (currentViewMode.value === 'timeline') {
|
|
filter += "&order=display_order.asc"
|
|
} else if (currentViewMode.value === 'category') {
|
|
filter += "&order=category_id.asc,display_order.asc"
|
|
} else if (currentViewMode.value === 'quality') {
|
|
filter += "&order=quality_score.desc,display_order.asc"
|
|
}
|
|
|
|
return filter
|
|
})
|
|
|
|
// 生命周期
|
|
onLoad((options: OnLoadOptions) => {
|
|
if (options.id !== undefined) {
|
|
topicId.value = options.id as string
|
|
}
|
|
|
|
if (topicId.value !== '') {
|
|
loadTopicData()
|
|
loadTopicContents()
|
|
loadRelatedTopics()
|
|
}
|
|
})
|
|
|
|
// 加载专题数据
|
|
const loadTopicData = async () => {
|
|
try {
|
|
const result = await supa.from('ak_topics')
|
|
.select('*')
|
|
.eq('id', topicId.value)
|
|
.single()
|
|
.executeAs<Topic>()
|
|
if (result.error !== null) {
|
|
console.error('Topic data loading error:', result.error)
|
|
return
|
|
}
|
|
const data = result.data
|
|
if (data !== null) {
|
|
topicData.value = data
|
|
}
|
|
} catch (e: any) {
|
|
console.error('Topic data loading error:', e)
|
|
}
|
|
}
|
|
|
|
// 加载专题内容
|
|
const loadTopicContents = async () => {
|
|
contentState.value.loading = true
|
|
contentState.value.error = null
|
|
try {
|
|
// TODO: 替换为实际接口调用
|
|
// 这里模拟异步加载
|
|
await new Promise(resolve => setTimeout(resolve, 500))
|
|
// 假设返回模拟数据
|
|
const mockContents: Array<InfoContent> = [
|
|
{
|
|
id: 'content-1',
|
|
title: 'AI赋能医疗行业',
|
|
summary: '人工智能正在深刻改变医疗行业的诊断和服务模式。',
|
|
content: '',
|
|
author: '张三',
|
|
published_at: '2025-07-01T10:00:00Z',
|
|
quality_score: 92,
|
|
view_count: 1200,
|
|
like_count: 88,
|
|
share_count: 12,
|
|
category_id: 'health',
|
|
original_language: 'zh-CN',
|
|
source_url: '',
|
|
tags: ['AI', '医疗'],
|
|
created_at: '2025-07-01T09:00:00Z',
|
|
updated_at: '2025-07-01T10:00:00Z'
|
|
}
|
|
]
|
|
topicContentsList.value = mockContents
|
|
// 可根据分页逻辑设置 hasMoreContent
|
|
hasMoreContent.value = false
|
|
} catch (e) {
|
|
contentState.value.error = '加载失败,请稍后重试'
|
|
} finally {
|
|
contentState.value.loading = false
|
|
}
|
|
}
|
|
|
|
// 处理专题内容数据
|
|
const handleTopicContentsData = (data: any) => {
|
|
contentState.value.loading = false
|
|
contentState.value.error = null
|
|
if (data !== null && Array.isArray(data)) {
|
|
const newContents = data as Array<InfoContent>
|
|
if (contentState.value.currentPage === 1) {
|
|
topicContentsList.value = newContents
|
|
} else {
|
|
topicContentsList.value = topicContentsList.value.concat(newContents)
|
|
}
|
|
hasMoreContent.value = newContents.length === contentPageSize.value
|
|
}
|
|
}
|
|
|
|
// 加载相关专题
|
|
const loadRelatedTopics = () => {
|
|
// 模拟相关专题数据
|
|
const relatedTopic: Topic = {
|
|
id: 'topic-related-1',
|
|
title: '机器学习算法详解',
|
|
description: '深入解析机器学习核心算法原理和应用',
|
|
created_by: '',
|
|
is_active: true,
|
|
content_count: 12,
|
|
created_at: '',
|
|
updated_at: '',
|
|
view_count: 15600
|
|
}
|
|
relatedTopicsList.value = [relatedTopic]
|
|
}
|
|
|
|
// 错误处理
|
|
const handleContentError = (error: any) => {
|
|
contentState.value.loading = false
|
|
contentState.value.error = '加载失败,请稍后重试'
|
|
console.error('Topic contents loading error:', error)
|
|
}
|
|
|
|
// 视图模式切换
|
|
const setViewMode = (mode: string) => {
|
|
currentViewMode.value = mode
|
|
contentState.value.currentPage = 1
|
|
loadTopicContents()
|
|
}
|
|
|
|
// 加载更多内容
|
|
const loadMoreContent = () => {
|
|
if (loadingMoreContent.value || !hasMoreContent.value) return
|
|
|
|
loadingMoreContent.value = true
|
|
contentState.value.currentPage += 1
|
|
|
|
setTimeout(() => {
|
|
loadTopicContents()
|
|
loadingMoreContent.value = false
|
|
}, 500)
|
|
}
|
|
|
|
// 刷新内容
|
|
const refreshContent = () => {
|
|
contentState.value.currentPage = 1
|
|
loadTopicContents()
|
|
}
|
|
|
|
// 重试加载内容
|
|
const retryLoadContent = () => {
|
|
contentState.value.error = null
|
|
loadTopicContents()
|
|
}
|
|
|
|
// 导航函数
|
|
const goBack = () => {
|
|
uni.navigateBack()
|
|
}
|
|
|
|
const navigateToContent = (content: InfoContent) => {
|
|
const contentId = content.id
|
|
uni.navigateTo({
|
|
url: `/pages/info/detail?id=${contentId}&from=topic`
|
|
})
|
|
}
|
|
|
|
const navigateToTopic = (topic: Topic) => {
|
|
const relatedTopicId = topic.id
|
|
uni.navigateTo({
|
|
url: `/pages/info/topic-detail?id=${relatedTopicId}`
|
|
})
|
|
}
|
|
|
|
// 操作函数
|
|
const shareTopic = () => {
|
|
// 分享专题
|
|
uni.showToast({
|
|
title: '分享功能开发中',
|
|
icon: 'none'
|
|
})
|
|
}
|
|
|
|
const subscribeTopic = () => {
|
|
// 订阅专题
|
|
uni.showToast({
|
|
title: '订阅功能开发中',
|
|
icon: 'none'
|
|
})
|
|
}
|
|
|
|
const openChat = () => {
|
|
// 打开AI助手
|
|
uni.navigateTo({
|
|
url: `/pages/info/chat?context=topic&id=${topicId.value}`
|
|
})
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.topic-detail {
|
|
flex: 1;
|
|
background-color: #f8fafc;
|
|
}
|
|
|
|
.topic-header {
|
|
background-color: #ffffff;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.header-cover {
|
|
height: 200px;
|
|
background-color: #8b5cf6;
|
|
background-size: cover;
|
|
background-position: center;
|
|
position: relative;
|
|
}
|
|
|
|
.header-overlay {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background-color: rgba(0, 0, 0, 0.3);
|
|
padding: 16px;
|
|
flex-direction: row;
|
|
justify-content: space-between;
|
|
align-items: flex-start;
|
|
}
|
|
|
|
.back-btn {
|
|
background-color: rgba(255, 255, 255, 0.9);
|
|
border-radius: 20px;
|
|
width: 40px;
|
|
height: 40px;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.back-icon {
|
|
font-size: 18px;
|
|
color: #1f2937;
|
|
}
|
|
|
|
.topic-badges {
|
|
flex-direction: row;
|
|
}
|
|
|
|
.type-badge {
|
|
background-color: #8b5cf6;
|
|
border-radius: 12px;
|
|
padding: 4px 8px;
|
|
}
|
|
|
|
.badge-text {
|
|
font-size: 12px;
|
|
color: #ffffff;
|
|
}
|
|
|
|
.header-info {
|
|
padding: 20px;
|
|
}
|
|
|
|
.topic-title {
|
|
font-size: 24px;
|
|
font-weight: bold;
|
|
color: #1f2937;
|
|
line-height: 32px;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.topic-description {
|
|
font-size: 16px;
|
|
color: #64748b;
|
|
line-height: 24px;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.topic-meta {
|
|
flex-direction: row;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.meta-stats {
|
|
flex-direction: row;
|
|
align-items: center;
|
|
}
|
|
|
|
.stat-item {
|
|
font-size: 14px;
|
|
color: #94a3b8;
|
|
margin-right: 16px;
|
|
}
|
|
|
|
.topic-content {
|
|
background-color: #ffffff;
|
|
padding: 16px 0;
|
|
}
|
|
|
|
.content-filters {
|
|
padding: 0 16px 16px 16px;
|
|
border-bottom-width: 1px;
|
|
border-bottom-color: #e2e8f0;
|
|
}
|
|
|
|
.filter-tabs {
|
|
flex-direction: row;
|
|
background-color: #f1f5f9;
|
|
border-radius: 24px;
|
|
padding: 4px;
|
|
}
|
|
|
|
.filter-tab {
|
|
flex: 1;
|
|
padding: 8px 16px;
|
|
align-items: center;
|
|
border-radius: 20px;
|
|
}
|
|
|
|
.filter-tab.active {
|
|
background-color: #8b5cf6;
|
|
}
|
|
|
|
.filter-text {
|
|
font-size: 14px;
|
|
color: #64748b;
|
|
}
|
|
|
|
.filter-tab.active .filter-text {
|
|
color: #ffffff;
|
|
}
|
|
|
|
.timeline-view {
|
|
padding: 16px;
|
|
}
|
|
|
|
.timeline-item {
|
|
flex-direction: row;
|
|
margin-bottom: 24px;
|
|
position: relative;
|
|
}
|
|
|
|
.timeline-dot {
|
|
width: 12px;
|
|
height: 12px;
|
|
border-radius: 6px;
|
|
background-color: #8b5cf6;
|
|
margin-top: 6px;
|
|
margin-right: 16px;
|
|
}
|
|
|
|
.timeline-content {
|
|
flex: 1;
|
|
background-color: #f8fafc;
|
|
border-radius: 12px;
|
|
padding: 16px;
|
|
border-width: 1px;
|
|
border-color: #e2e8f0;
|
|
}
|
|
|
|
.timeline-header {
|
|
flex-direction: row;
|
|
justify-content: space-between;
|
|
align-items: flex-start;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.timeline-title {
|
|
flex: 1;
|
|
font-size: 16px;
|
|
font-weight: bold;
|
|
color: #1f2937;
|
|
line-height: 22px;
|
|
margin-right: 12px;
|
|
}
|
|
|
|
.timeline-time {
|
|
font-size: 12px;
|
|
color: #94a3b8;
|
|
}
|
|
|
|
.timeline-summary {
|
|
font-size: 14px;
|
|
color: #64748b;
|
|
line-height: 20px;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.timeline-meta {
|
|
flex-direction: row;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.meta-author {
|
|
font-size: 12px;
|
|
color: #94a3b8;
|
|
}
|
|
|
|
.quality-badge {
|
|
background-color: #10b981;
|
|
border-radius: 10px;
|
|
padding: 2px 6px;
|
|
}
|
|
|
|
.quality-text {
|
|
font-size: 11px;
|
|
color: #ffffff;
|
|
}
|
|
|
|
.category-view, .quality-view {
|
|
padding: 16px;
|
|
}
|
|
|
|
.category-item, .quality-item {
|
|
background-color: #f8fafc;
|
|
border-radius: 12px;
|
|
padding: 16px;
|
|
margin-bottom: 12px;
|
|
border-width: 1px;
|
|
border-color: #e2e8f0;
|
|
}
|
|
|
|
.category-header, .quality-header {
|
|
flex-direction: row;
|
|
justify-content: space-between;
|
|
align-items: flex-start;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.category-title, .quality-title {
|
|
flex: 1;
|
|
font-size: 16px;
|
|
font-weight: bold;
|
|
color: #1f2937;
|
|
line-height: 22px;
|
|
margin-right: 12px;
|
|
}
|
|
|
|
.category-badge {
|
|
background-color: #3b82f6;
|
|
border-radius: 10px;
|
|
padding: 2px 8px;
|
|
}
|
|
|
|
.category-text {
|
|
font-size: 12px;
|
|
color: #ffffff;
|
|
}
|
|
|
|
.quality-score {
|
|
background-color: #10b981;
|
|
border-radius: 10px;
|
|
padding: 2px 8px;
|
|
}
|
|
|
|
.score-text {
|
|
font-size: 12px;
|
|
color: #ffffff;
|
|
}
|
|
|
|
.category-summary, .quality-summary {
|
|
font-size: 14px;
|
|
color: #64748b;
|
|
line-height: 20px;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.category-footer, .quality-footer {
|
|
flex-direction: row;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.category-stats, .quality-stats {
|
|
flex-direction: row;
|
|
align-items: center;
|
|
}
|
|
|
|
.stat-text {
|
|
font-size: 12px;
|
|
color: #94a3b8;
|
|
margin-right: 12px;
|
|
}
|
|
|
|
.category-time, .quality-author {
|
|
font-size: 12px;
|
|
color: #94a3b8;
|
|
}
|
|
|
|
.loading-section, .error-section {
|
|
padding: 40px 16px;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.loading-text {
|
|
font-size: 14px;
|
|
color: #94a3b8;
|
|
}
|
|
|
|
.error-text {
|
|
font-size: 14px;
|
|
color: #ef4444;
|
|
margin-bottom: 16px;
|
|
text-align: center;
|
|
}
|
|
|
|
.retry-btn, .refresh-btn {
|
|
background-color: #8b5cf6;
|
|
border-radius: 20px;
|
|
padding: 8px 24px;
|
|
}
|
|
|
|
.retry-text, .refresh-text {
|
|
font-size: 14px;
|
|
color: #ffffff;
|
|
}
|
|
|
|
.empty-section {
|
|
padding: 60px 16px;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.empty-text {
|
|
font-size: 16px;
|
|
color: #94a3b8;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.load-more-section {
|
|
padding: 20px 16px;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.load-more-btn {
|
|
background-color: #f1f5f9;
|
|
border-radius: 20px;
|
|
padding: 10px 24px;
|
|
border-width: 1px;
|
|
border-color: #e2e8f0;
|
|
}
|
|
|
|
.load-more-text {
|
|
font-size: 14px;
|
|
color: #475569;
|
|
}
|
|
|
|
.loading-more {
|
|
padding: 10px 24px;
|
|
}
|
|
|
|
.loading-more-text {
|
|
font-size: 14px;
|
|
color: #94a3b8;
|
|
}
|
|
|
|
.related-topics {
|
|
background-color: #ffffff;
|
|
margin-top: 8px;
|
|
padding: 16px 0;
|
|
}
|
|
|
|
.section-header {
|
|
padding: 0 16px 12px 16px;
|
|
}
|
|
|
|
.section-title {
|
|
font-size: 18px;
|
|
font-weight: bold;
|
|
color: #1f2937;
|
|
}
|
|
|
|
.related-scroll {
|
|
height: 120px;
|
|
}
|
|
|
|
.related-list {
|
|
flex-direction: row;
|
|
padding-left: 16px;
|
|
padding-right: 16px;
|
|
}
|
|
|
|
.related-item {
|
|
width: 200px;
|
|
background-color: #f8fafc;
|
|
border-radius: 12px;
|
|
padding: 12px;
|
|
margin-right: 12px;
|
|
border-width: 1px;
|
|
border-color: #e2e8f0;
|
|
}
|
|
|
|
.related-title {
|
|
font-size: 14px;
|
|
font-weight: bold;
|
|
color: #1f2937;
|
|
line-height: 20px;
|
|
margin-bottom: 4px;
|
|
}
|
|
|
|
.related-desc {
|
|
font-size: 12px;
|
|
color: #64748b;
|
|
line-height: 16px;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.related-stats {
|
|
flex-direction: row;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.related-stat {
|
|
font-size: 11px;
|
|
color: #94a3b8;
|
|
}
|
|
|
|
.comments-section {
|
|
background-color: #ffffff;
|
|
margin-top: 8px;
|
|
}
|
|
|
|
.bottom-actions {
|
|
background-color: #ffffff;
|
|
flex-direction: row;
|
|
padding: 16px;
|
|
border-top-width: 1px;
|
|
border-top-color: #e2e8f0;
|
|
}
|
|
|
|
.action-item {
|
|
flex: 1;
|
|
align-items: center;
|
|
padding: 12px;
|
|
}
|
|
|
|
.action-icon {
|
|
font-size: 20px;
|
|
margin-bottom: 4px;
|
|
}
|
|
|
|
.action-text {
|
|
font-size: 12px;
|
|
color: #64748b;
|
|
}
|
|
</style>
|