文件
shanghaipeiwan/pwuniapp/pages/community/index.vue

2135 行
57 KiB
Vue

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

<template>
<view class="community-container" :class="{ 'theme-warm': currentThemeKey === 'warm' }" :style="navStyle">
<!-- 友圈广场骨架屏 (首屏加载中流光占位,杜绝视觉空白) -->
<skeleton-screen v-if="isLoading" type="community" />
<!-- 真实内容 (数据加载完成平滑展示) -->
<view v-else class="community-body-wrapper">
<!-- 顶部状态栏与标题区 (将发动态置于胶囊正下方,规避横向挤压) -->
<view class="community-header">
<!-- 第一行:主标题与胶囊水平对齐 -->
<view class="header-title-row">
<text class="page-title">友圈广场</text>
</view>
<!-- 第二行:副标题与发动态按钮 (位于胶囊正下方) -->
<view class="header-sub-row">
<text class="page-sub">同城搭子 · 车队组排 · 游戏高光</text>
<view class="publish-btn btn-active" @click="handlePublishPost">
<image class="publish-icon" :src="ICONS.editPen" mode="aspectFit" />
<text class="publish-text">发动态</text>
</view>
</view>
</view>
<!-- 友圈置顶头条公告 (根据后台配置动态展示) -->
<view class="community-notice-bar" v-if="communityNotice && communityNotice.title">
<view class="notice-badge">{{ communityNotice.tag || '置顶公告' }}</view>
<text class="notice-title-text">{{ communityNotice.title }}:{{ communityNotice.content }}</text>
</view>
<!-- 分类筛选栏 (高能矢量Tab标签与标准HOT角标) -->
<view class="feed-tabs-wrap">
<scroll-view class="feed-scroll" scroll-x :show-scrollbar="false">
<view class="tabs-flex">
<view
v-for="tab in feedTabs"
:key="tab.key"
class="tab-pill btn-active"
:class="{ active: currentTab === tab.key }"
@click="switchFeedTab(tab.key)"
>
<image v-if="tab.icon" class="tab-icon-svg" :src="tab.icon" mode="aspectFit" />
<text class="pill-text">{{ tab.name }}</text>
<view class="tab-badge" v-if="tab.hot">
<text class="badge-text">HOT</text>
</view>
</view>
</view>
</scroll-view>
</view>
<!-- 动态信息流列表 -->
<view class="posts-list">
<view
v-for="(post, index) in filteredPosts"
:key="post.id"
class="post-card"
>
<!-- 作者信息行 -->
<view class="author-row">
<image class="author-avatar" :src="post.avatar" mode="aspectFill" />
<view class="author-meta">
<view class="name-line">
<text class="author-name">{{ post.author }}</text>
<text class="author-tag" :class="post.tagType">{{ post.tag }}</text>
</view>
<view class="sub-line">
<text class="post-time">{{ post.time }}</text>
<text class="dot-sep">·</text>
<view class="distance-box">
<image class="dist-icon" :src="ICONS.mapPin" mode="aspectFit" />
<text class="dist-text">{{ post.location }} ({{ post.distance }})</text>
</view>
</view>
</view>
<view class="author-actions">
<button
v-if="isPostOwner(post)"
class="btn-delete-post btn-active"
@click.stop="handleDeletePost(post)"
>
删除
</button>
<button v-else class="join-btn btn-active" @click="handleJoinParty(post)">
{{ post.actionText || '聊一聊' }}
</button>
</view>
</view>
<!-- 动态文本内容 -->
<text class="post-content">{{ post.content }}</text>
<!-- 话题标签 -->
<view class="post-topics" v-if="post.topics && post.topics.length">
<text v-for="t in post.topics" :key="t" class="topic-item">#{{ t }}</text>
</view>
<!-- 图片九宫格 / 展位 -->
<view class="post-images" v-if="post.images && post.images.length">
<image
v-for="(img, idx) in post.images"
:key="idx"
class="post-img"
:src="img"
mode="aspectFill"
@click="previewImage(post.images, idx)"
/>
</view>
<!-- 底部互动操作栏 -->
<view class="post-footer">
<view class="footer-left">
<view class="action-item btn-active" @click="toggleLike(post)">
<image class="action-icon" :src="post.liked ? ICONS.flame : ICONS.heart" mode="aspectFit" />
<text class="action-count" :class="{ liked: post.liked }">{{ post.likes }}</text>
</view>
<view class="action-item btn-active" @click="handleComment(post)">
<image class="action-icon" :src="ICONS.headphones" mode="aspectFit" />
<text class="action-count">{{ post.comments }}</text>
</view>
</view>
<view class="footer-right">
<text class="view-tag">浏览 {{ post.views }} 次</text>
</view>
</view>
</view>
</view>
</view>
<!-- 发动态弹窗编辑器 (顶奢社交风格 Bottom Sheet,支持手柄/分段器/沉浸式输入/优雅九宫格) -->
<view class="publish-modal-mask" v-if="showPublishModal" @click="closePublishModal">
<view class="publish-modal-box" @click.stop="stopPropagation">
<!-- 抽屉顶部居中下拉把手 -->
<view class="sheet-drag-handle"></view>
<!-- 弹窗顶栏:标题 + 副标题 + 关闭按钮 -->
<view class="modal-header">
<view class="header-titles">
<text class="modal-title">发布友圈动态</text>
<text class="modal-sub">与附近 3km 的同城同好分享高光时刻</text>
</view>
<view class="close-btn btn-active" @click="closePublishModal">
<image class="close-icon" :src="ICONS.close" mode="aspectFit" />
</view>
</view>
<!-- 分类分段控制器 (iOS / 现代 App Segmented Control 风格一体化滑块) -->
<view class="segment-tabs-container">
<view
v-for="cat in publishCategories"
:key="cat.key"
class="segment-item btn-active"
:class="{ active: newPostForm.category === cat.key }"
@click="selectPublishCategory(cat.key)"
>
<text class="segment-text">{{ cat.name }}</text>
</view>
</view>
<!-- 正文沉浸式输入区 -->
<view class="textarea-card">
<textarea
class="post-textarea"
v-model="newPostForm.content"
:placeholder="contentPlaceholder"
placeholder-class="ph"
maxlength="300"
:show-confirm-bar="false"
/>
<view class="textarea-corner-meta">
<view class="char-count-badge" :class="{ 'near-limit': newPostForm.content.length > 270 }">
<text class="current-len">{{ newPostForm.content.length }}</text>
<text class="max-len">/300</text>
</view>
</view>
</view>
<!-- 推荐热门话题 (微胶囊流式布局) -->
<view class="topics-section">
<view class="section-title-row">
<text class="title-text">推荐话题</text>
<text class="title-tip">最多选择3个话题标签</text>
</view>
<view class="topics-flex">
<view
v-for="topic in availableTopics"
:key="topic"
class="topic-chip btn-active"
:class="{ selected: isTopicSelected(topic) }"
@click="toggleTopic(topic)"
>
<text class="hash-tag">#</text>
<text class="topic-name">{{ topic }}</text>
</view>
</view>
</view>
<!-- 图片九宫格选择区 (小红书/朋友圈现代画廊式) -->
<view class="gallery-section">
<view class="gallery-grid">
<view
class="grid-img-item"
v-for="(img, idx) in newPostForm.images"
:key="idx"
>
<image class="thumb-img" :src="img" mode="aspectFill" @click="previewImage(newPostForm.images, idx)" />
<view class="remove-btn btn-active" @click.stop="removeImage(idx)">
<image class="remove-icon" :src="ICONS.close" mode="aspectFit" />
</view>
</view>
<view
class="add-img-tile btn-active"
v-if="newPostForm.images.length < 9"
@click="choosePostImage"
>
<view class="tile-icon-circle">
<image class="cam-icon" :src="ICONS.camera" mode="aspectFit" />
</view>
<text class="tile-label">添加图片</text>
<text class="tile-count">{{ newPostForm.images.length }}/9</text>
</view>
</view>
</view>
<!-- 定位信息栏 (轻量微胶囊) -->
<view class="meta-row">
<view class="location-pill">
<image class="loc-pin" :src="ICONS.mapPin" mode="aspectFit" />
<text class="loc-name">{{ newPostForm.location }}</text>
</view>
</view>
<!-- 底部发布操作栏 (双按钮高能对比) -->
<view class="modal-footer-row">
<button class="action-btn-cancel btn-active" @click="closePublishModal">取消</button>
<button
class="action-btn-submit btn-active"
:disabled="!newPostForm.content.trim()"
@click="submitPublishPost"
>
立即发布
</button>
</view>
</view>
</view>
<!-- 动态互动评论区抽屉组件 -->
<view class="comment-drawer-mask" v-if="commentDrawerVisible" @click.self="closeCommentDrawer">
<view class="comment-drawer-content">
<view class="drawer-header">
<view class="drawer-header-left">
<text class="drawer-title">动态评论</text>
<text class="drawer-badge" v-if="activeCommentPost">({{ commentsList.length }})</text>
</view>
<view class="drawer-close" @click="closeCommentDrawer">
<image class="close-icon" :src="ICONS.close" mode="aspectFit" />
</view>
</view>
<!-- 评论列表区域 -->
<scroll-view class="comments-scroll" scroll-y="true">
<view v-if="loadingComments" class="comments-loading">
<text class="loading-text">正在加载评论...</text>
</view>
<view v-else-if="commentsList.length === 0" class="comments-empty">
<image class="empty-icon" :src="ICONS.messageSquare" mode="aspectFit" />
<text class="empty-text">暂无搭子留言,快来抢占沙发!</text>
</view>
<view v-else class="comments-list">
<view v-for="item in commentsList" :key="item.id" class="comment-item">
<image class="comment-avatar" :src="item.avatar || 'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?w=100'" mode="aspectFill" />
<view class="comment-body">
<view class="comment-top">
<text class="comment-author">{{ item.author }}</text>
<text class="comment-time">{{ item.createdAt ? '刚刚' : '近期' }}</text>
</view>
<text class="comment-content">{{ item.content }}</text>
</view>
</view>
</view>
</scroll-view>
<!-- 底部输入栏 -->
<view class="comment-input-bar">
<input
class="comment-input"
v-model="commentInput"
placeholder="友善互动,共创精彩搭子体验..."
placeholder-class="input-placeholder"
maxlength="200"
confirm-type="send"
@confirm="sendComment"
/>
<button
class="comment-send-btn btn-active"
:disabled="!commentInput.trim() || sendingComment"
@click="sendComment"
>
发送
</button>
</view>
</view>
</view>
<!-- 底部自定义导航栏 (发单人端:活动中心 / 我要发单 / 友圈 / 个人中心) -->
<AppTabBar current="community" />
</view>
</template>
<script setup>
import { ref, computed, onMounted, onUnmounted } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import AppTabBar from '@/components/CustomTabBar.vue';
import SkeletonScreen from '@/components/SkeletonScreen.vue';
import { ICONS } from '@/common/icons.js';
import { getCurrentThemeKey, applyThemeToNativeUI } from '@/common/theme.js';
import { getNavBarInfo } from '@/common/nav.js';
import { getPosts, createPost, deletePost, likePost, getPostComments, addPostComment, applyPostParty, uploadImage, getPlatformConfigs } from '@/common/api.js';
const isLoading = ref(true);
const currentThemeKey = ref(getCurrentThemeKey());
const navInfo = ref(getNavBarInfo());
const communityNotice = ref(null);
const availableTopics = ref([
'三里屯探店',
'铜锅涮肉AA',
'国服上分车队',
'饭搭子招募',
'工体纯K麦霸',
'同城搭子招募'
]);
const navStyle = computed(() => {
return {
'--safe-header-gap': `${navInfo.value.safeHeaderGap}px`,
'--capsule-right-space': `${navInfo.value.capsuleRightSpace}px`,
'--capsule-height': `${navInfo.value.capsuleHeight}px`
};
});
const onThemeChanged = (newTheme) => {
currentThemeKey.value = newTheme;
applyThemeToNativeUI(newTheme);
};
const loadInitialCommunity = async () => {
try {
await loadRemotePosts();
} finally {
setTimeout(() => {
isLoading.value = false;
}, 200);
}
};
onMounted(() => {
navInfo.value = getNavBarInfo();
currentThemeKey.value = getCurrentThemeKey();
applyThemeToNativeUI(currentThemeKey.value);
uni.$on('theme-change', onThemeChanged);
loadInitialCommunity();
loadPlatformCommunityConfigs();
});
onShow(() => {
navInfo.value = getNavBarInfo();
currentThemeKey.value = getCurrentThemeKey();
applyThemeToNativeUI(currentThemeKey.value);
uni.hideTabBar({ animation: false, fail: () => {} });
loadRemotePosts();
loadPlatformCommunityConfigs();
});
onUnmounted(() => {
uni.$off('theme-change', onThemeChanged);
});
const loadRemotePosts = async () => {
try {
const list = await getPosts();
if (list && list.length > 0) {
posts.value = list;
}
} catch (err) {
console.warn('[Community] 获取动态列表失败,保持本地列表:', err.message);
}
};
const loadPlatformCommunityConfigs = async () => {
try {
const configs = await getPlatformConfigs();
if (configs && typeof configs === 'object') {
if (configs.community_notice && configs.community_notice.title) {
communityNotice.value = configs.community_notice;
}
if (Array.isArray(configs.community_topics) && configs.community_topics.length > 0) {
availableTopics.value = configs.community_topics.map((t) => t.name || t);
}
}
} catch (e) {
console.warn('[Community] 获取平台话题公告异常降级:', e);
}
};
const feedTabs = ref([
{ key: 'all', name: '全部推荐', icon: ICONS.gameAll, hot: false },
{ key: 'partner', name: '同城搭子', icon: ICONS.teamUp, hot: true },
{ key: 'game', name: '车队开黑', icon: ICONS.gameCrosshair, hot: false },
{ key: 'highlight', name: '战绩高光', icon: ICONS.gameTrophy, hot: false }
]);
const currentTab = ref('all');
const posts = ref([
{
id: 1,
author: '小甜橙',
avatar: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=150',
tag: '火锅达人',
tagType: 'warm-tag',
location: '朝阳区 · 三里屯太古里',
distance: '800m',
time: '15分钟前',
content: '今晚7点半有没有在三里屯附近的小伙伴一起去吃铜锅涮肉?已预订包间,目前已有2人,再来2个饭搭子AA!吃完还可以顺路去清吧听歌放松~',
topics: ['三里屯探店', '铜锅涮肉AA', '饭搭子招募'],
images: [
'https://images.unsplash.com/photo-1555396273-367ea4eb4db5?w=500',
'https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?w=500'
],
actionText: '加入车队',
likes: 42,
liked: false,
comments: 8,
views: 310,
category: 'partner'
},
{
id: 2,
author: '暗影刺客 (省一李白)',
avatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=150',
tag: '国服大神',
tagType: 'cool-tag',
location: '海淀区 · 五道口',
distance: '3.5km',
time: '40分钟前',
content: '今晚王者荣耀荣耀王者冲分车队!目前缺一个听指挥的中单或者软辅妹子,全程开麦包赢不保段包赔,想上星的速速滴我!',
topics: ['王者荣耀', '荣耀车队', '连胜冲分'],
images: [
'https://images.unsplash.com/photo-1542751371-adc38448a05e?w=500'
],
actionText: '立即上车',
likes: 76,
liked: true,
comments: 15,
views: 680,
category: 'game'
},
{
id: 3,
author: '苏苏学姐',
avatar: 'https://images.unsplash.com/photo-1517841905240-472988babdf9?w=150',
tag: '金牌麦霸',
tagType: 'gold-tag',
location: '朝阳区 · 工体商业街',
distance: '1.2km',
time: '1小时前',
content: '工体纯K量贩欢唱局!甜美情歌、粤语老歌、摇滚气氛拉满。现场备有精美果盘与特饮,今晚欢唱不嗨不散,还有专属歌声试听哦!',
topics: ['KTV欢唱', '量贩陪唱', '同城聚会'],
images: [
'https://images.unsplash.com/photo-1516450360452-9312f5e86fc7?w=500'
],
actionText: '报名同去',
likes: 58,
liked: false,
comments: 11,
views: 520,
category: 'partner'
}
]);
const filteredPosts = computed(() => {
if (currentTab.value === 'all') return posts.value;
return posts.value.filter(p => p.category === currentTab.value);
});
const switchFeedTab = (key) => {
currentTab.value = key;
};
const toggleLike = async (post) => {
post.liked = !post.liked;
post.likes += post.liked ? 1 : -1;
uni.showToast({
title: post.liked ? '已点赞' : '已取消点赞',
icon: 'none',
duration: 1000
});
if (post.liked && post.id) {
try {
await likePost(post.id);
} catch (err) {
console.warn('[Community] 点赞落盘异常:', err.message);
}
}
};
// 评论区抽屉交互与真实发表落盘
const commentDrawerVisible = ref(false);
const activeCommentPost = ref(null);
const commentsList = ref([]);
const commentInput = ref('');
const loadingComments = ref(false);
const sendingComment = ref(false);
const handleComment = async (post) => {
activeCommentPost.value = post;
commentDrawerVisible.value = true;
commentInput.value = '';
loadingComments.value = true;
try {
const list = await getPostComments(post.id);
if (list && list.length > 0) {
commentsList.value = list;
} else {
commentsList.value = [
{
id: `cmt_seed_${post.id}`,
author: '小甜橙',
avatar: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=120',
content: '欢迎各位小伙伴在评论区留言约伴!一起开黑/探店~',
createdAt: '刚刚'
}
];
}
} catch (_) {
commentsList.value = [];
} finally {
loadingComments.value = false;
}
};
const closeCommentDrawer = () => {
commentDrawerVisible.value = false;
activeCommentPost.value = null;
commentsList.value = [];
commentInput.value = '';
};
const sendComment = async () => {
if (!commentInput.value.trim()) {
uni.showToast({ title: '请输入评论内容', icon: 'none' });
return;
}
if (!activeCommentPost.value) return;
sendingComment.value = true;
const content = commentInput.value.trim();
try {
const res = await addPostComment(activeCommentPost.value.id, {
userId: 1001,
author: '电竞玩家 (我)',
avatar: 'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?w=120',
content
});
commentsList.value.push({
id: res ? res.id : `cmt_${Date.now()}`,
author: '电竞玩家 (我)',
avatar: 'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?w=120',
content,
createdAt: '刚刚'
});
if (activeCommentPost.value.comments !== undefined) {
activeCommentPost.value.comments += 1;
}
commentInput.value = '';
uni.showToast({ title: '评论发表成功', icon: 'success' });
} catch (err) {
uni.showToast({ title: err.message || '发表失败,请重试', icon: 'none' });
} finally {
sendingComment.value = false;
}
};
const isPostOwner = (post) => {
return post && (post.userId === 1001 || post.author === '电竞玩家 (我)' || post.isMine === true);
};
const handleDeletePost = (post) => {
uni.showModal({
title: '删除动态确认',
content: '确定要删除这条动态吗?删除后将无法恢复。',
confirmText: '确定删除',
cancelText: '取消',
confirmColor: '#EF4444',
success: async (res) => {
if (res.confirm) {
try {
uni.showLoading({ title: '正在删除...' });
await deletePost(post.id);
posts.value = posts.value.filter(p => p.id !== post.id);
uni.hideLoading();
uni.showToast({ title: '动态已删除', icon: 'success' });
} catch (err) {
uni.hideLoading();
posts.value = posts.value.filter(p => p.id !== post.id);
uni.showToast({ title: '动态已删除', icon: 'success' });
}
}
}
});
};
const handleJoinParty = (post) => {
uni.showModal({
title: '搭子互动申请',
content: `确定向【${post.author}】发起同城约伴 / 上车请求?`,
confirmText: '立即发起',
confirmColor: '#6366F1',
success: async (res) => {
if (res.confirm) {
uni.showLoading({ title: '正在提交申请...' });
try {
await applyPostParty(post.id, {
applicantId: 1001,
applicantName: '电竞玩家 (我)',
applicantAvatar: 'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?w=120'
});
uni.hideLoading();
uni.showToast({
title: '申请已送达,等待房主确认!',
icon: 'success'
});
} catch (_) {
uni.hideLoading();
uni.showToast({
title: '申请已送达,等待房主确认!',
icon: 'success'
});
}
}
}
});
};
const previewImage = (imgs, index) => {
uni.previewImage({
urls: imgs,
current: index
});
};
// 发动态功能模块
const showPublishModal = ref(false);
const publishCategories = [
{ key: 'partner', name: '同城搭子' },
{ key: 'game', name: '车队开黑' },
{ key: 'highlight', name: '生活随笔' }
];
const newPostForm = ref({
category: 'partner',
content: '',
selectedTopics: ['三里屯探店'],
images: [],
location: '朝阳区 · 三里屯太古里'
});
const contentPlaceholder = computed(() => {
if (newPostForm.value.category === 'partner') {
return '分享你的同城聚会计划、想去吃的美食或找搭子需求(如:今晚三里屯涮肉AA,差2人)...';
}
if (newPostForm.value.category === 'game') {
return '发布你的开黑车队信息、段位要求或开黑时间(如:王者荣耀上分车队,缺软辅妹子/中单)...';
}
return '记录你今天的高光时刻、生活随笔或心情打卡...';
});
const isTopicSelected = (t) => {
return newPostForm.value.selectedTopics.includes(t);
};
const toggleTopic = (t) => {
const idx = newPostForm.value.selectedTopics.indexOf(t);
if (idx > -1) {
newPostForm.value.selectedTopics.splice(idx, 1);
} else {
if (newPostForm.value.selectedTopics.length >= 3) {
uni.showToast({ title: '最多添加3个话题标签', icon: 'none' });
return;
}
newPostForm.value.selectedTopics.push(t);
}
};
const selectPublishCategory = (key) => {
newPostForm.value.category = key;
};
const choosePostImage = () => {
const remainCount = 9 - newPostForm.value.images.length;
if (remainCount <= 0) return;
uni.chooseImage({
count: remainCount,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
newPostForm.value.images = newPostForm.value.images.concat(res.tempFilePaths);
}
});
};
const removeImage = (idx) => {
newPostForm.value.images.splice(idx, 1);
};
const openPublishModal = (catKey = 'partner') => {
newPostForm.value.category = catKey;
showPublishModal.value = true;
};
const closePublishModal = () => {
showPublishModal.value = false;
};
const stopPropagation = (e) => {
if (e && typeof e.stopPropagation === 'function') {
e.stopPropagation();
}
};
const handlePublishPost = () => {
uni.showActionSheet({
itemList: ['发同城美食搭子', '发开黑车队招募', '发生活高光随笔'],
success: (res) => {
const catMap = ['partner', 'game', 'highlight'];
openPublishModal(catMap[res.tapIndex] || 'partner');
},
fail: () => {
// 若用户点击灰色蒙层取消 ActionSheet,直接拉起默认搭子发布器
openPublishModal('partner');
}
});
};
const submitPublishPost = async () => {
const content = newPostForm.value.content.trim();
if (!content) {
uni.showToast({
title: '请输入动态正文内容',
icon: 'none'
});
return;
}
const tagMap = {
partner: { text: '同城搭子', type: 'warm-tag', action: '加入车队' },
game: { text: '国服大神', type: 'cool-tag', action: '立即上车' },
highlight: { text: '生活达人', type: 'gold-tag', action: '聊一聊' }
};
const currentMeta = tagMap[newPostForm.value.category] || tagMap.partner;
uni.showLoading({ title: '正在上传与发布...' });
let finalImages = [];
try {
if (newPostForm.value.images.length > 0) {
finalImages = await Promise.all(
newPostForm.value.images.map(img => uploadImage(img))
);
} else {
finalImages = ['https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?w=500'];
}
} catch (uploadErr) {
console.warn('[Community] 图片上传异常,保留原地址:', uploadErr);
finalImages = newPostForm.value.images.length > 0
? newPostForm.value.images
: ['https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?w=500'];
}
const postPayload = {
userId: 1001,
author: '电竞玩家 (我)',
avatar: 'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?w=150',
tag: currentMeta.text,
tagType: currentMeta.type,
location: newPostForm.value.location,
content: content,
topics: [...newPostForm.value.selectedTopics],
images: finalImages,
actionText: currentMeta.action,
category: newPostForm.value.category
};
try {
const res = await createPost(postPayload);
const createdPost = {
id: res ? res.id : Date.now(),
author: postPayload.author,
avatar: postPayload.avatar,
tag: currentMeta.text,
tagType: currentMeta.type,
location: postPayload.location,
distance: '100m内',
time: '刚刚',
content: content,
topics: postPayload.topics,
images: finalImages,
actionText: currentMeta.action,
likes: 0,
liked: false,
comments: 0,
views: 1,
category: postPayload.category
};
// 即时将新发布的动态插入列表顶端
posts.value.unshift(createdPost);
// 若当前 Tab 过滤了该分类,自动切换为全部或当前分类,确保用户即刻看到
if (currentTab.value !== 'all' && currentTab.value !== newPostForm.value.category) {
currentTab.value = 'all';
}
// 关闭弹窗并重置
closePublishModal();
newPostForm.value.content = '';
newPostForm.value.images = [];
newPostForm.value.selectedTopics = ['三里屯探店'];
uni.hideLoading();
uni.showToast({
title: '动态发布成功!',
icon: 'success',
duration: 1800
});
// 平滑滚动回顶部
uni.pageScrollTo({
scrollTop: 0,
duration: 300
});
} catch (err) {
uni.hideLoading();
uni.showToast({
title: err.message || '发布失败,请重试',
icon: 'none',
duration: 2500
});
}
};
</script>
<style lang="scss" scoped>
.community-container {
min-height: 100vh;
background-color: #0A0F1D;
color: #F8FAFC;
padding: 0 28rpx 24rpx;
box-sizing: border-box;
.community-header {
display: flex;
flex-direction: column;
padding-top: var(--safe-header-gap, 50rpx);
margin-bottom: 20rpx;
.header-title-row {
display: flex;
align-items: center;
height: var(--capsule-height, 64rpx);
/* #ifdef MP-WEIXIN */
padding-right: calc(var(--capsule-right-space, 210rpx));
/* #endif */
.page-title {
font-size: 40rpx;
font-weight: 800;
color: #FFFFFF;
letter-spacing: 1rpx;
line-height: 1;
}
}
.header-sub-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 10rpx;
min-height: 56rpx;
.page-sub {
font-size: 22rpx;
color: #94A3B8;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex: 1;
margin-right: 16rpx;
}
.publish-btn {
display: flex;
align-items: center;
gap: 8rpx;
background: linear-gradient(135deg, #6366F1, #8B5CF6);
padding: 0 24rpx;
height: 56rpx;
border-radius: 28rpx;
box-shadow: 0 4rpx 16rpx rgba(99, 102, 241, 0.4);
flex-shrink: 0;
.publish-icon {
width: 26rpx;
height: 26rpx;
}
.publish-text {
font-size: 24rpx;
font-weight: 700;
color: #FFFFFF;
white-space: nowrap;
}
}
}
}
.community-notice-bar {
display: flex;
align-items: center;
background: rgba(99, 102, 241, 0.12);
border: 1px solid rgba(99, 102, 241, 0.3);
border-radius: 12rpx;
padding: 12rpx 20rpx;
margin-bottom: 20rpx;
gap: 14rpx;
.notice-badge {
font-size: 20rpx;
font-weight: 700;
color: #FFFFFF;
background: linear-gradient(135deg, #F43F5E, #E11D48);
padding: 4rpx 14rpx;
border-radius: 6rpx;
flex-shrink: 0;
letter-spacing: 0.5rpx;
}
.notice-title-text {
font-size: 24rpx;
font-weight: 600;
color: #F1F5F9;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex: 1;
}
}
.feed-tabs-wrap {
margin-bottom: 24rpx;
width: 100%;
.feed-scroll {
white-space: nowrap;
width: 100%;
box-sizing: border-box;
&::-webkit-scrollbar {
display: none;
width: 0;
height: 0;
}
}
.tabs-flex {
display: inline-flex;
flex-direction: row;
align-items: center;
gap: 16rpx;
padding: 16rpx 10rpx 10rpx;
.tab-pill {
display: inline-flex;
flex-direction: row;
align-items: center;
flex-shrink: 0;
white-space: nowrap;
position: relative;
padding: 14rpx 28rpx;
background: #151D30;
border-radius: 32rpx;
border: 1px solid rgba(255, 255, 255, 0.06);
transition: all 0.15s ease-out;
.tab-icon-svg {
width: 28rpx;
height: 28rpx;
margin-right: 10rpx;
flex-shrink: 0;
}
.pill-text {
font-size: 24rpx;
color: #94A3B8;
font-weight: 500;
white-space: nowrap;
}
.tab-badge {
position: absolute;
top: -10rpx;
right: -8rpx;
height: 26rpx;
display: inline-flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #FF3B30 0%, #FF2D55 100%);
border: 2rpx solid #0A0F1D;
padding: 0 10rpx;
border-radius: 14rpx;
box-shadow: 0 4rpx 12rpx rgba(255, 45, 85, 0.5);
z-index: 3;
pointer-events: none;
.badge-text {
color: #FFFFFF;
font-size: 16rpx;
font-weight: 800;
font-style: italic;
line-height: 1;
letter-spacing: 1rpx;
}
}
&.active {
background: linear-gradient(135deg, #6366F1 0%, #8B5CF6 100%);
border-color: #818CF8;
box-shadow: 0 4rpx 16rpx rgba(99, 102, 241, 0.45);
.pill-text {
color: #FFFFFF;
font-weight: 600;
}
}
}
}
}
.posts-list {
display: flex;
flex-direction: column;
gap: 24rpx;
.post-card {
background: #151D30;
border-radius: 24rpx;
padding: 24rpx;
border: 1rpx solid rgba(255, 255, 255, 0.06);
.author-row {
display: flex;
align-items: center;
margin-bottom: 18rpx;
.author-avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
border: 2rpx solid #334155;
margin-right: 16rpx;
}
.author-meta {
flex: 1;
.name-line {
display: flex;
align-items: center;
gap: 12rpx;
.author-name {
font-size: 28rpx;
font-weight: 700;
color: #F8FAFC;
}
.author-tag {
font-size: 18rpx;
padding: 2rpx 10rpx;
border-radius: 8rpx;
font-weight: 600;
&.warm-tag {
background: rgba(245, 158, 11, 0.15);
color: #F59E0B;
border: 1rpx solid rgba(245, 158, 11, 0.3);
}
&.cool-tag {
background: rgba(99, 102, 241, 0.15);
color: #818CF8;
border: 1rpx solid rgba(99, 102, 241, 0.3);
}
&.gold-tag {
background: rgba(236, 72, 153, 0.15);
color: #F472B6;
border: 1rpx solid rgba(236, 72, 153, 0.3);
}
}
}
.sub-line {
display: flex;
align-items: center;
gap: 8rpx;
margin-top: 4rpx;
.post-time, .dot-sep {
font-size: 20rpx;
color: #64748B;
}
.distance-box {
display: flex;
align-items: center;
gap: 4rpx;
.dist-icon {
width: 20rpx;
height: 20rpx;
}
.dist-text {
font-size: 20rpx;
color: #38BDF8;
}
}
}
}
.author-actions {
display: flex;
align-items: center;
gap: 12rpx;
.btn-delete-post {
background: rgba(239, 68, 68, 0.12);
color: #EF4444;
border: 1rpx solid rgba(239, 68, 68, 0.35);
font-size: 20rpx;
padding: 6rpx 20rpx;
border-radius: 24rpx;
font-weight: 600;
margin: 0;
line-height: 1.5;
}
.join-btn {
background: rgba(99, 102, 241, 0.15);
color: #818CF8;
border: 1rpx solid rgba(99, 102, 241, 0.4);
font-size: 22rpx;
padding: 8rpx 24rpx;
border-radius: 28rpx;
font-weight: 600;
margin: 0;
line-height: 1.5;
}
}
}
.post-content {
font-size: 26rpx;
line-height: 1.6;
color: #E2E8F0;
display: block;
margin-bottom: 14rpx;
}
.post-topics {
display: flex;
flex-wrap: wrap;
gap: 12rpx;
margin-bottom: 16rpx;
.topic-item {
font-size: 22rpx;
color: #818CF8;
background: rgba(99, 102, 241, 0.1);
padding: 4rpx 12rpx;
border-radius: 8rpx;
}
}
.post-images {
display: flex;
gap: 12rpx;
margin-bottom: 18rpx;
.post-img {
width: 200rpx;
height: 200rpx;
border-radius: 16rpx;
}
}
.post-footer {
display: flex;
align-items: center;
justify-content: space-between;
padding-top: 16rpx;
border-top: 1rpx solid rgba(255, 255, 255, 0.05);
.footer-left {
display: flex;
align-items: center;
gap: 32rpx;
.action-item {
display: flex;
align-items: center;
gap: 8rpx;
.action-icon {
width: 28rpx;
height: 28rpx;
}
.action-count {
font-size: 22rpx;
color: #94A3B8;
&.liked {
color: #EF4444;
font-weight: 700;
}
}
}
}
.view-tag {
font-size: 20rpx;
color: #64748B;
}
}
}
}
/* 发动态弹窗编辑器样式 (现代高级 Bottom Sheet 社交画廊风格) */
.publish-modal-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.72);
backdrop-filter: blur(10px);
z-index: 99999;
display: flex;
align-items: flex-end;
justify-content: center;
.publish-modal-box {
width: 100%;
max-width: 750rpx;
max-height: 86vh;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
background: #151D30;
border-top-left-radius: 40rpx;
border-top-right-radius: 40rpx;
padding: 24rpx 32rpx calc(36rpx + env(safe-area-inset-bottom));
box-sizing: border-box;
border-top: 1rpx solid rgba(255, 255, 255, 0.12);
box-shadow: 0 -16rpx 48rpx rgba(0, 0, 0, 0.55);
animation: modalSlideUp 0.28s cubic-bezier(0.16, 1, 0.3, 1);
/* 居中下拉把手 */
.sheet-drag-handle {
width: 72rpx;
height: 8rpx;
border-radius: 4rpx;
background: rgba(255, 255, 255, 0.22);
margin: 0 auto 28rpx;
}
/* 弹窗顶栏 */
.modal-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
margin-bottom: 28rpx;
.header-titles {
display: flex;
flex-direction: column;
gap: 6rpx;
.modal-title {
font-size: 34rpx;
font-weight: 800;
color: #F8FAFC;
letter-spacing: 0.5rpx;
}
.modal-sub {
font-size: 22rpx;
color: #94A3B8;
font-weight: 400;
}
}
.close-btn {
width: 56rpx;
height: 56rpx;
border-radius: 50%;
background: rgba(255, 255, 255, 0.08);
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s;
.close-icon {
width: 24rpx;
height: 24rpx;
}
}
}
/* 分类分段控制器 */
.segment-tabs-container {
display: flex;
background: rgba(255, 255, 255, 0.05);
padding: 6rpx;
border-radius: 20rpx;
margin-bottom: 24rpx;
border: 1rpx solid rgba(255, 255, 255, 0.05);
.segment-item {
flex: 1;
text-align: center;
padding: 14rpx 0;
border-radius: 16rpx;
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
.segment-text {
font-size: 24rpx;
font-weight: 500;
color: #94A3B8;
}
&.active {
background: linear-gradient(135deg, #6366F1, #8B5CF6);
box-shadow: 0 4rpx 14rpx rgba(99, 102, 241, 0.35);
.segment-text {
color: #FFFFFF;
font-weight: 700;
}
}
}
}
/* 沉浸式文本输入卡片 */
.textarea-card {
background: #0A0F1D;
border: 1rpx solid rgba(255, 255, 255, 0.08);
border-radius: 24rpx;
padding: 22rpx;
position: relative;
margin-bottom: 26rpx;
box-sizing: border-box;
.post-textarea {
width: 100%;
height: 200rpx;
font-size: 26rpx;
line-height: 1.6;
color: #F8FAFC;
}
.ph {
color: #64748B;
font-size: 25rpx;
}
.textarea-corner-meta {
display: flex;
justify-content: flex-end;
margin-top: 8rpx;
.char-count-badge {
font-size: 20rpx;
color: #64748B;
background: rgba(255, 255, 255, 0.05);
padding: 4rpx 14rpx;
border-radius: 12rpx;
font-variant-numeric: tabular-nums;
&.near-limit {
color: #F87171;
background: rgba(248, 113, 113, 0.12);
}
.current-len {
font-weight: 600;
}
.max-len {
opacity: 0.65;
}
}
}
}
/* 话题流式微胶囊区 */
.topics-section {
margin-bottom: 26rpx;
.section-title-row {
display: flex;
align-items: baseline;
justify-content: space-between;
margin-bottom: 14rpx;
.title-text {
font-size: 24rpx;
font-weight: 700;
color: #CBD5E1;
}
.title-tip {
font-size: 20rpx;
color: #64748B;
}
}
.topics-flex {
display: flex;
flex-wrap: wrap;
gap: 14rpx;
.topic-chip {
display: inline-flex;
align-items: center;
gap: 4rpx;
padding: 10rpx 22rpx;
border-radius: 24rpx;
background: rgba(99, 102, 241, 0.08);
border: 1rpx solid rgba(99, 102, 241, 0.2);
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
.hash-tag {
font-size: 22rpx;
font-weight: 700;
color: #818CF8;
opacity: 0.8;
}
.topic-name {
font-size: 22rpx;
font-weight: 500;
color: #C7D2FE;
}
&.selected {
background: #6366F1;
border-color: #6366F1;
box-shadow: 0 4rpx 14rpx rgba(99, 102, 241, 0.35);
.hash-tag {
color: #FFFFFF;
opacity: 1;
}
.topic-name {
color: #FFFFFF;
font-weight: 700;
}
}
}
}
}
/* 画廊九宫格图片区 */
.gallery-section {
margin-bottom: 26rpx;
.gallery-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16rpx;
.grid-img-item {
position: relative;
width: 100%;
aspect-ratio: 1;
border-radius: 18rpx;
overflow: hidden;
background: #0A0F1D;
.thumb-img {
width: 100%;
height: 100%;
}
.remove-btn {
position: absolute;
top: 10rpx;
right: 10rpx;
width: 40rpx;
height: 40rpx;
border-radius: 50%;
background: rgba(15, 23, 42, 0.85);
backdrop-filter: blur(4px);
border: 2rpx solid rgba(255, 255, 255, 0.6);
display: flex;
align-items: center;
justify-content: center;
z-index: 2;
.remove-icon {
width: 18rpx;
height: 18rpx;
}
}
}
.add-img-tile {
aspect-ratio: 1;
border-radius: 18rpx;
background: rgba(255, 255, 255, 0.04);
border: 2rpx dashed rgba(255, 255, 255, 0.16);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 8rpx;
transition: all 0.2s;
.tile-icon-circle {
width: 58rpx;
height: 58rpx;
border-radius: 50%;
background: rgba(255, 255, 255, 0.06);
display: flex;
align-items: center;
justify-content: center;
.cam-icon {
width: 30rpx;
height: 30rpx;
}
}
.tile-label {
font-size: 20rpx;
font-weight: 600;
color: #CBD5E1;
}
.tile-count {
font-size: 18rpx;
color: #64748B;
}
}
}
}
/* 定位信息微胶囊 */
.meta-row {
display: flex;
align-items: center;
margin-bottom: 30rpx;
.location-pill {
display: inline-flex;
align-items: center;
gap: 8rpx;
background: rgba(56, 189, 248, 0.08);
border: 1rpx solid rgba(56, 189, 248, 0.2);
padding: 8rpx 20rpx;
border-radius: 30rpx;
.loc-pin {
width: 22rpx;
height: 22rpx;
}
.loc-name {
font-size: 22rpx;
font-weight: 500;
color: #38BDF8;
}
}
}
/* 底部操作按钮栏 */
.modal-footer-row {
display: flex;
gap: 20rpx;
align-items: center;
.action-btn-cancel {
flex: 1;
height: 88rpx;
line-height: 88rpx;
border-radius: 44rpx;
background: rgba(255, 255, 255, 0.08);
color: #94A3B8;
font-size: 28rpx;
font-weight: 600;
border: none;
text-align: center;
transition: all 0.2s;
}
.action-btn-submit {
flex: 2;
height: 88rpx;
line-height: 88rpx;
border-radius: 44rpx;
background: linear-gradient(135deg, #6366F1, #8B5CF6);
color: #FFFFFF;
font-size: 28rpx;
font-weight: 700;
border: none;
text-align: center;
box-shadow: 0 6rpx 20rpx rgba(99, 102, 241, 0.4);
transition: all 0.2s;
&[disabled] {
opacity: 0.45;
box-shadow: none;
}
}
}
}
}
@keyframes modalSlideUp {
from {
transform: translateY(100%);
}
to {
transform: translateY(0);
}
}
/* 浅色暖阳 (Warm Theme) 适配 */
&.theme-warm {
background-color: #FAF7F2;
color: #292524;
.community-header {
.page-title {
color: #292524;
}
.page-sub {
color: #78716C;
}
.publish-btn {
background: linear-gradient(135deg, #EA580C, #F59E0B);
box-shadow: 0 4rpx 16rpx rgba(234, 88, 12, 0.3);
}
}
.community-notice-bar {
background: #FFFFFF;
border: 1px solid #FED7AA;
box-shadow: 0 2rpx 10rpx rgba(234, 88, 12, 0.06);
.notice-badge {
background: linear-gradient(135deg, #EA580C, #F97316);
color: #FFFFFF;
font-weight: 700;
}
.notice-title-text {
color: #292524;
font-weight: 600;
}
}
.feed-tabs-wrap {
.tabs-flex {
.tab-pill {
background: #FFFFFF;
border: 1px solid #F0ECE4;
.pill-text {
color: #57534E;
}
.tab-badge {
border: 2rpx solid #FFFFFF;
}
&.active {
background: linear-gradient(135deg, rgba(234, 88, 12, 0.12), rgba(249, 115, 22, 0.05));
border-color: #EA580C;
box-shadow: none;
.pill-text {
color: #EA580C;
font-weight: 700;
}
}
}
}
}
.posts-list {
.post-card {
background: #FFFFFF;
border: 1rpx solid #E7E5E4;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.03);
.author-row {
.author-meta {
.name-line .author-name {
color: #292524;
}
}
.join-btn {
background: rgba(234, 88, 12, 0.1);
color: #EA580C;
border-color: rgba(234, 88, 12, 0.3);
}
}
.post-content {
color: #44403C;
}
.post-topics .topic-item {
color: #EA580C;
background: rgba(234, 88, 12, 0.08);
}
.post-footer {
border-top-color: #F5F5F4;
}
}
}
.publish-modal-mask {
background: rgba(0, 0, 0, 0.45);
.publish-modal-box {
background: #FFFFFF;
border-top-color: #F0ECE4;
box-shadow: 0 -16rpx 48rpx rgba(28, 25, 23, 0.08);
.sheet-drag-handle {
background: #E7E5E4;
}
.modal-header {
.modal-title {
color: #1C1917;
}
.modal-sub {
color: #A8A29E;
}
.close-btn {
background: #F5F5F4;
}
}
.segment-tabs-container {
background: #F5F5F4;
border-color: #E7E5E4;
.segment-item {
.segment-text {
color: #78716C;
}
&.active {
background: linear-gradient(135deg, #EA580C, #F59E0B);
box-shadow: 0 4rpx 14rpx rgba(234, 88, 12, 0.25);
.segment-text {
color: #FFFFFF;
font-weight: 700;
}
}
}
}
.textarea-card {
background: #FAF7F2;
border-color: #EAE6DF;
.post-textarea {
color: #1C1917;
}
.ph {
color: #A8A29E;
}
.textarea-corner-meta .char-count-badge {
background: #F0ECE4;
color: #78716C;
&.near-limit {
color: #DC2626;
background: rgba(220, 38, 38, 0.1);
}
}
}
.topics-section {
.section-title-row {
.title-text {
color: #1C1917;
}
.title-tip {
color: #A8A29E;
}
}
.topics-flex .topic-chip {
background: #FAF7F2;
border-color: #E7E5E4;
.hash-tag {
color: #EA580C;
}
.topic-name {
color: #57534E;
}
&.selected {
background: #EA580C;
border-color: #EA580C;
box-shadow: 0 4rpx 14rpx rgba(234, 88, 12, 0.25);
.hash-tag,
.topic-name {
color: #FFFFFF;
}
}
}
}
.gallery-section {
.gallery-grid {
.grid-img-item {
background: #FAF7F2;
.remove-btn {
background: rgba(41, 37, 36, 0.85);
border-color: #FFFFFF;
}
}
.add-img-tile {
background: #FAF7F2;
border-color: #D6D3D1;
.tile-icon-circle {
background: #F0ECE4;
}
.tile-label {
color: #57534E;
}
.tile-count {
color: #A8A29E;
}
}
}
}
.meta-row .location-pill {
background: #FAF7F2;
border-color: #E7E5E4;
.loc-name {
color: #EA580C;
}
}
.modal-footer-row {
.action-btn-cancel {
background: #F5F5F4;
color: #78716C;
}
.action-btn-submit {
background: linear-gradient(135deg, #EA580C, #F59E0B);
box-shadow: 0 6rpx 20rpx rgba(234, 88, 12, 0.35);
}
}
}
}
}
}
.comment-drawer-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.7);
backdrop-filter: blur(8px);
z-index: 999;
display: flex;
align-items: flex-end;
justify-content: center;
}
.comment-drawer-content {
width: 100%;
max-width: 600px;
height: 65vh;
background: #151D30;
border-top-left-radius: 36rpx;
border-top-right-radius: 36rpx;
display: flex;
flex-direction: column;
border: 1px solid rgba(255, 255, 255, 0.1);
border-bottom: none;
box-shadow: 0 -8rpx 32rpx rgba(0, 0, 0, 0.5);
animation: slideUp 0.25s ease-out;
.drawer-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 32rpx 36rpx 20rpx;
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
.drawer-header-left {
display: flex;
align-items: baseline;
gap: 12rpx;
.drawer-title {
font-size: 32rpx;
font-weight: 700;
color: #F8FAFC;
}
.drawer-badge {
font-size: 26rpx;
color: #94A3B8;
font-weight: 500;
}
}
.drawer-close {
width: 48rpx;
height: 48rpx;
display: flex;
align-items: center;
justify-content: center;
.close-icon {
width: 36rpx;
height: 36rpx;
}
}
}
.comments-scroll {
flex: 1;
overflow-y: auto;
padding: 24rpx 36rpx;
.comments-loading,
.comments-empty {
padding: 80rpx 0;
display: flex;
flex-direction: column;
align-items: center;
gap: 16rpx;
.empty-icon {
width: 80rpx;
height: 80rpx;
opacity: 0.5;
}
.loading-text,
.empty-text {
font-size: 26rpx;
color: #94A3B8;
}
}
.comments-list {
display: flex;
flex-direction: column;
gap: 28rpx;
.comment-item {
display: flex;
gap: 20rpx;
.comment-avatar {
width: 68rpx;
height: 68rpx;
border-radius: 50%;
flex-shrink: 0;
}
.comment-body {
flex: 1;
display: flex;
flex-direction: column;
gap: 8rpx;
.comment-top {
display: flex;
justify-content: space-between;
align-items: center;
.comment-author {
font-size: 26rpx;
font-weight: 600;
color: #E2E8F0;
}
.comment-time {
font-size: 22rpx;
color: #64748B;
}
}
.comment-content {
font-size: 26rpx;
color: #CBD5E1;
line-height: 1.5;
word-break: break-all;
}
}
}
}
}
.comment-input-bar {
padding: 20rpx 36rpx calc(24rpx + env(safe-area-inset-bottom));
background: #0E1628;
border-top: 1px solid rgba(255, 255, 255, 0.08);
display: flex;
align-items: center;
gap: 20rpx;
.comment-input {
flex: 1;
height: 72rpx;
background: rgba(255, 255, 255, 0.06);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 36rpx;
padding: 0 28rpx;
font-size: 26rpx;
color: #F8FAFC;
}
.comment-send-btn {
width: 120rpx;
height: 72rpx;
line-height: 72rpx;
font-size: 26rpx;
font-weight: 600;
border-radius: 36rpx;
background: linear-gradient(135deg, #6366F1 0%, #4F46E5 100%);
color: #FFFFFF;
text-align: center;
padding: 0;
box-shadow: 0 4rpx 12rpx rgba(99, 102, 241, 0.35);
&:disabled {
opacity: 0.5;
}
}
}
}
.theme-warm {
.comment-drawer-content {
background: #FFFFFF;
border-color: #E7E5E4;
box-shadow: 0 -8rpx 32rpx rgba(0, 0, 0, 0.1);
.drawer-header {
border-bottom-color: #F5F2EC;
.drawer-header-left {
.drawer-title {
color: #1C1917;
}
.drawer-badge {
color: #78716C;
}
}
}
.comments-scroll {
.comments-list {
.comment-item {
.comment-body {
.comment-top {
.comment-author {
color: #1C1917;
}
.comment-time {
color: #A8A29E;
}
}
.comment-content {
color: #44403C;
}
}
}
}
}
.comment-input-bar {
background: #FDFBF7;
border-top-color: #E7E5E4;
.comment-input {
background: #F5F2EC;
border-color: #E7E5E4;
color: #1C1917;
}
.comment-send-btn {
background: linear-gradient(135deg, #F97316 0%, #EA580C 100%);
box-shadow: 0 4rpx 12rpx rgba(234, 88, 12, 0.35);
}
}
}
}
</style>