| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- <template>
- <Popup :title="t('评论')" isClose ref="popRef">
- <template #content>
- <List url="/discover/video/comments" :defaultParams="{ video_id: video_id }" @datas="getList" ref="listRef">
- <template #item="{ item }">
- <view class="comment-item">
- <image class="avatar" :src="item.avatar || '/static/tx.png'" mode="aspectFill"></image>
- <view class="content">
- <view class="username">{{ item.username }}</view>
- <view class="text">{{ item.content }}</view>
- <view class="footer">
- <text class="time">{{ fromTime(item.indate) }}</text>
- <view class="actions">
- <text class="reply" @click="reply(item)">{{ t('回复') }}</text>
- </view>
- </view>
- </view>
- </view>
- <view v-if="item.replay && item.replay.length" class="child-comments">
- <view class="comment-item" v-for="child in item.replay" :key="child.id">
- <image class="avatar" :src="child.avatar || '/static/tx.png'" mode="aspectFill"></image>
- <view class="content">
- <text class="username">{{ child.username }}</text>
- <view class="text">{{ child.content }}</view>
- <view class="footer">
- <text class="time">{{ fromTime(child.indate) }}</text>
- </view>
- </view>
- </view>
- </view>
- </template>
- </List>
- </template>
- <template #footer>
- <view class="comment-input">
- <Input class="input" :placeholder="replyTo ? t('回复') + '@' + replyTo.username : t('说点什么...')"
- @confirm="submitComment" :focus="showReplyInput" border="surround" v-model="commentText" />
- <view class="submit-btn" @click.stop="submitComment" :style="{ opacity: commentText ? 1 : .5 }">
- <trans _t="发送" />
- </view>
- </view>
- </template>
- </Popup>
- </template>
- <script setup>
- import { ref, nextTick } from 'vue'
- import Input from "./input";
- import { t } from "@/locale"
- import { DISCOVER_VIDEO_SUBCOMMENTS } from "@/api"
- import List from "@/components/list";
- import { Toast, fromTime } from "@/utils"
- import Popup from './popup.vue';
- const props = defineProps({
- video_id: {
- required: true
- }
- })
- const popRef = ref(null);
- const defaultParams = ref([])
- // 评论输入
- const commentText = ref('')
- const replyTo = ref(null)
- const listRef = ref(null)
- const showReplyInput = ref(false)
- const commentList = ref([])
- const getList = (list) => {
- commentList.value = list
- }
- const open = () => {
- clearInput()
- popRef.value && popRef.value.open()
- defaultParams.video_id = props.video_id
- nextTick(() => {
- listRef.value && listRef.value.handleRefresh();
- })
- }
- const close = () => {
- clearInput()
- popRef.value && popRef.value.close()
- }
- const submitComment = async () => {
- if (!commentText.value.trim()) return
- try {
- const result = await DISCOVER_VIDEO_SUBCOMMENTS({
- video_id: props.video_id,
- content: commentText.value,
- pid: replyTo.value ? replyTo.value.id : 0
- })
- // 只添加新评论而不刷新整个列表
- if (replyTo.value) {
- addReplyToCommentList(commentList.value, replyTo.value.id, result.data)
- } else {
- commentList.value.unshift(result.data)
- }
- listRef.value && listRef.value.setList(commentList.value);
- clearInput()
- } catch (error) {
- Toast(error.msg)
- }
- }
- // 辅助函数 - 添加回复到评论树
- function addReplyToCommentList(comments, parentId, newComment) {
- for (const comment of comments) {
- if (comment.id === parentId) {
- if (!comment.replay) comment.replay = []
- comment.replay.unshift(newComment)
- return true
- }
- if (comment.replay && addReplyToCommentList(comment.replay, parentId, newComment)) {
- return true
- }
- }
- return false
- }
- function clearInput() {
- commentText.value = ''
- replyTo.value = null
- showReplyInput.value = false
- }
- const reply = (comment) => {
- replyTo.value = comment
- showReplyInput.value = true
- }
- defineExpose({
- open,
- close
- })
- </script>
- <style lang="less" scoped>
- @import url('@/style.less');
- :deep(.u-list) {
- height: max-content !important;
- }
- .comment-item {
- display: flex;
- padding: 20rpx 0;
- // border-bottom: 1rpx solid var(--borderColor);
- .avatar {
- width: 80rpx;
- height: 80rpx;
- border-radius: 50%;
- margin-right: 20rpx;
- flex-shrink: 0;
- }
- .content {
- flex: 1;
- overflow: hidden;
- .username {
- .size(28rpx);
- color: var(--text);
- margin-right: 10rpx;
- }
- .text {
- .size(30rpx);
- margin: 10rpx 0;
- line-height: 1.5;
- color: var(--text);
- word-break: break-all;
- }
- .footer {
- display: flex;
- justify-content: space-between;
- margin-top: 10rpx;
- .time {
- font-size: 24rpx;
- color: var(--text);
- }
- .actions {
- display: flex;
- align-items: center;
- .like,
- .reply {
- font-size: 24rpx;
- color: var(--text);
- margin-left: 20rpx;
- display: flex;
- align-items: center;
- &:active {
- opacity: 0.7;
- }
- }
- }
- }
- }
- }
- .child-comments {
- margin-left: 80rpx;
- }
- .comment-input {
- .flex_center;
- background-color: var(--bg);
- .input {
- flex: 1;
- height: 70rpx;
- padding: 0 20rpx;
- background-color: var(--inputBg);
- border-radius: 35rpx;
- margin-right: 20rpx;
- font-size: 28rpx;
- color: var(--text);
- }
- .submit-btn {
- .size(28rpx);
- height: 70rpx;
- line-height: 70rpx;
- padding: 0 30rpx;
- background-color: var(--black);
- color: #fff;
- border-radius: 35rpx;
- border: none;
- &[disabled] {
- background-color: var(--text-02);
- }
- }
- }
- </style>
|