266 lines
11 KiB
Plaintext
266 lines
11 KiB
Plaintext
<!-- 外层容器:统一页面背景 -->
|
||
<view class="page-wrapper" bindtap="handleBlankTap">
|
||
<!-- 核心内容容器:包裹投票区+评论区,消除割裂感 -->
|
||
<view class="content-container">
|
||
<!-- 1. 投票区域:仅当有投票数据时显示 -->
|
||
<view class="voting-section" wx:if="{{cardReviewData}}">
|
||
<!-- 卡片头部:用户信息+投票状态 -->
|
||
<view class="card-header" bindtap="goToDetail" data-id="{{cardReviewData.article_id}}">
|
||
<view class="user-info">
|
||
<image
|
||
src="https://picsum.photos/id/100/200/200"
|
||
mode="widthFix"
|
||
class="avatar"
|
||
alt="用户头像"
|
||
></image>
|
||
<view class="user-details">
|
||
<text class="username">{{cardReviewData.publisher_id}}</text>
|
||
<text class="user-status">发起人 ({{cardReviewData.vote_type === 'single' ? '单选' : '多选'}})</text>
|
||
</view>
|
||
</view>
|
||
<!-- 投票状态:已投票/进行中/已结束 -->
|
||
<view class="vote-status {{cardReviewData.user_has_voted ? 'status-voted' : (cardReviewData.is_ended ? 'status-ended' : 'status-active')}}">
|
||
{{cardReviewData.user_has_voted ? '已投票' : (cardReviewData.is_ended ? '已结束' : '进行中')}}
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 分割线 -->
|
||
<view class="divider"></view>
|
||
|
||
<!-- 投票标题区域:含“您已投票”提示 -->
|
||
<view class="vote-title-section" bindtap="goToDetail" data-id="{{cardReviewData.article_id}}">
|
||
<text class="vote-title">
|
||
{{cardReviewData.article_title}}
|
||
<text class="voted-tip" wx:if="{{cardReviewData.user_has_voted}}">• 您已投票</text>
|
||
</text>
|
||
<text class="vote-desc">{{cardReviewData.article_desc || ''}}</text>
|
||
</view>
|
||
|
||
<!-- 投票选项列表 -->
|
||
<view class="options-container">
|
||
<block wx:for="{{cardReviewData.options}}" wx:for-item="option" wx:key="id">
|
||
<view
|
||
class="option-item {{(cardReviewData.user_has_voted && option.is_voted) ? 'selected voted-option' : (option.isSelected ? 'selected' : '')}} {{(cardReviewData.is_ended || cardReviewData.user_has_voted) ? 'disabled-option' : ''}}"
|
||
bindtap="{{(cardReviewData.is_ended || cardReviewData.user_has_voted) ? '' : 'selectOption'}}"
|
||
data-card-id="{{cardReviewData.article_id}}"
|
||
data-option-id="{{option.id}}"
|
||
>
|
||
<view class="option-info">
|
||
<!-- 选项图标:对勾/圆圈 -->
|
||
<view class="option-icon bg-gray">
|
||
<text class="iconfont">{{(cardReviewData.user_has_voted && option.is_voted) ? '✓' : (option.isSelected ? '✓' : '○')}}</text>
|
||
</view>
|
||
<!-- 选项内容 -->
|
||
<view class="option-details">
|
||
<text class="option-name">
|
||
{{option.name}}
|
||
<text class="your-selection" wx:if="{{cardReviewData.user_has_voted && option.is_voted}}">(您的选择)</text>
|
||
</text>
|
||
<text class="option-desc">{{option.desc || ''}}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- AI标识 -->
|
||
<view class="option-action-btn">AI</view>
|
||
|
||
<!-- 投票百分比 -->
|
||
<text class="option-percent">{{option.percentage || 0}}%</text>
|
||
|
||
<!-- 进度条 -->
|
||
<view class="progress-bar">
|
||
<view class="progress-value" style="width: {{(option.percentage || 0) + '%'}}"></view>
|
||
</view>
|
||
|
||
<!-- 选中指示器 -->
|
||
<view class="vote-indicator {{(cardReviewData.user_has_voted && option.is_voted) || option.isSelected ? 'show' : ''}}">
|
||
<text class="iconfont icon-check-circle"></text>
|
||
</view>
|
||
</view>
|
||
</block>
|
||
</view>
|
||
|
||
<!-- 投票统计信息 -->
|
||
<view class="vote-stats" bindtap="goToDetail" data-id="{{cardReviewData.article_id}}">
|
||
<text class="stats-text">已有 {{cardReviewData.total_voters || 0}} 人参与投票</text>
|
||
<text class="stats-text">
|
||
{{cardReviewData.is_ended ? '已结束' : '截止至 ' + (cardReviewData.end_time || '0天')}}
|
||
</text>
|
||
</view>
|
||
|
||
<!-- 投票按钮 -->
|
||
<view class="vote-btn-wrapper">
|
||
<button
|
||
class="vote-btn {{(cardReviewData.is_ended ? 'vote-btn-ended' : (cardReviewData.user_has_voted ? 'vote-btn-disabled' : ''))}}"
|
||
disabled="{{cardReviewData.is_ended || cardReviewData.user_has_voted}}"
|
||
bindtap="submitVote"
|
||
data-card-id="{{cardReviewData.article_id}}"
|
||
>
|
||
<text class="btn-text">
|
||
{{cardReviewData.user_has_voted ? '已提交投票' : (cardReviewData.is_ended ? '投票结束' : '投我一票')}}
|
||
</text>
|
||
</button>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 投票区状态提示:无数据/加载中/加载失败 -->
|
||
<view class="vote-status-tip" wx:if="{{!cardReviewData && !loading && !error}}">暂无投票数据</view>
|
||
<view class="vote-status-tip" wx:if="{{loading}}">投票数据加载中...</view>
|
||
<view class="vote-status-tip error" wx:if="{{error}}">加载失败:{{error}}</view>
|
||
|
||
<!-- 分割线:区分投票区和评论区 -->
|
||
<view class="section-divider"></view>
|
||
|
||
<!-- 2. 评论区域 -->
|
||
<view class="comment-section">
|
||
<!-- 评论列表:有评论时显示 -->
|
||
<view wx:if="{{comments.length > 0}}">
|
||
<text class="comment-count">共 {{totalCommentsCount}} 条评论</text>
|
||
<block wx:for="{{comments}}" wx:for-item="comment" wx:key="id">
|
||
<!-- 修复错误:将模板参数改为单行,移除注释 -->
|
||
<template is="commentItem" data="{{item: comment, onCommentTap: handleCommentTap, formatter: formatter}}" />
|
||
</block>
|
||
</view>
|
||
|
||
<!-- 评论状态提示:无评论/加载中/加载失败 -->
|
||
<view class="comment-status" wx:else>
|
||
<view wx:if="{{!loading && !error}}">快来发布第一条评论吧!</view>
|
||
<view wx:elif="{{loading}}">评论加载中...</view>
|
||
<view wx:elif="{{error}}">加载失败: {{error}}</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 3. 回复输入框:点击评论时弹出,fixed固定在底部 -->
|
||
<view class="reply-input-container" wx:if="{{showReplyInput}}">
|
||
<input
|
||
class="reply-input"
|
||
placeholder="请输入回复内容..."
|
||
value="{{replyContent}}"
|
||
bindinput="handleReplyInput"
|
||
bindblur="handleInputBlur"
|
||
/>
|
||
<button
|
||
class="reply-submit-btn"
|
||
bindtap="handleReplySubmit"
|
||
disabled="{{!replyContent.trim()}}"
|
||
>
|
||
发送
|
||
</button>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- WXS工具:时间格式化(评论时间显示用) -->
|
||
<wxs src="./utils.wxs" module="formatter" />
|
||
|
||
<!-- 评论项模板:主评论+子评论通用 -->
|
||
<template name="commentItem">
|
||
<view
|
||
class="comment-item {{item.parent_id ? 'reply-level' : 'top-level'}}"
|
||
bindtap="{{onCommentTap}}"
|
||
data-comment-id="{{item.id}}"
|
||
data-comment-type="{{item.parent_id ? 'sub' : 'main'}}"
|
||
>
|
||
<!-- 评论头部:用户头像+用户名 -->
|
||
<view class="comment-header">
|
||
<image
|
||
class="avatar"
|
||
src="{{item.avatar_url || 'https://picsum.photos/id/237/200/200'}}"
|
||
mode="widthFix"
|
||
alt="用户头像"
|
||
></image>
|
||
<view class="user-info">
|
||
<text class="username">{{item.username || '匿名用户'}}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 评论内容 -->
|
||
<view class="comment-content">
|
||
<text>{{item.content}}</text>
|
||
</view>
|
||
|
||
<!-- 评论底部:时间+点赞+点踩 -->
|
||
<view class="comment-footer">
|
||
<view class="footer-left">
|
||
{{formatter.formatIsoDateTime(item.created_at)}} <!-- 格式化评论时间 -->
|
||
</view>
|
||
<view class="footer-right">
|
||
<!-- 点赞按钮:用Vant Icon -->
|
||
<view class="like-icon-wrap" bindtap="handleLike" data-id="{{item.id}}">
|
||
<van-icon
|
||
class="like-icon {{item.is_liked ? 'liked' : ''}}"
|
||
name="{{item.is_liked ? 'good-job' : 'good-job-o'}}"
|
||
size="18"
|
||
/>
|
||
<text class="likes-count">{{item.likes_count || 0}}</text>
|
||
</view>
|
||
<!-- 点踩按钮:自定义图片 -->
|
||
<view class="dislike-icon-wrap" bindtap="handleDislike" data-id="{{item.id}}">
|
||
<image
|
||
class="dislike-icon {{item.is_disliked ? 'disliked' : ''}}"
|
||
src="/images/dislike.png"
|
||
mode="widthFix"
|
||
alt="点踩图标"
|
||
></image>
|
||
<text class="dislikes-count">{{item.dislikes_count || 0}}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 子评论容器:有子评论时显示 -->
|
||
<view class="replies-container" wx:if="{{item.replies && item.replies.length > 0}}">
|
||
<block wx:for="{{item.replies}}" wx:for-item="reply" wx:key="id">
|
||
<view
|
||
class="comment-item reply-level sub-comment"
|
||
bindtap="{{onCommentTap}}"
|
||
data-comment-id="{{reply.id}}"
|
||
data-comment-type="sub"
|
||
>
|
||
<view class="comment-header">
|
||
<image
|
||
class="avatar"
|
||
src="{{reply.avatar_url || 'https://picsum.photos/id/237/200/200'}}"
|
||
mode="widthFix"
|
||
alt="用户头像"
|
||
></image>
|
||
<view class="user-info">
|
||
<text class="username">{{reply.username || '匿名用户'}}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="comment-content">
|
||
<text>{{reply.content}}</text>
|
||
</view>
|
||
|
||
<view class="comment-footer">
|
||
<view class="footer-left">
|
||
{{formatter.formatIsoDateTime(reply.created_at)}}
|
||
</view>
|
||
<view class="footer-right">
|
||
<view class="like-icon-wrap" bindtap="handleLike" data-id="{{reply.id}}">
|
||
<van-icon
|
||
class="like-icon {{reply.is_liked ? 'liked' : ''}}"
|
||
name="{{reply.is_liked ? 'good-job' : 'good-job-o'}}"
|
||
size="18"
|
||
/>
|
||
<text class="likes-count">{{reply.likes_count || 0}}</text>
|
||
</view>
|
||
<view class="dislike-icon-wrap" bindtap="handleDislike" data-id="{{reply.id}}">
|
||
<image
|
||
class="dislike-icon {{reply.is_disliked ? 'disliked' : ''}}"
|
||
src="/images/dislike.png"
|
||
mode="widthFix"
|
||
alt="点踩图标"
|
||
></image>
|
||
<text class="dislikes-count">{{reply.dislikes_count || 0}}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</block>
|
||
</view>
|
||
|
||
<!-- 评论分割线 -->
|
||
<view class="comment-divider"></view>
|
||
</view>
|
||
</template>
|