StudyCommentsSection.vue 8.04 KB
<template>
    <div id="comment" class="py-4 px-4 space-y-4" :style="{ paddingBottom: bottomWrapperHeight }">
        <div class="flex justify-between items-center mb-4">
            <div class="text-gray-900 font-medium text-sm">评论 ({{ commentCount }})</div>
            <div class="text-gray-500 cursor-pointer text-sm" @click="show_comment_popup_model = true">查看更多</div>
        </div>
        <div v-for="comment in commentList" :key="comment.id" class="border-b border-gray-100 last:border-b-0 py-4">
            <div class="flex">
                <img :src="comment.avatar || 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg'"
                    class="w-10 h-10 rounded-full flex-shrink-0" style="margin-right: 0.5rem;" />
                <div class="flex-1 ml-3">
                    <div class="flex justify-between items-center mb-1">
                        <span class="font-medium text-gray-900">{{ comment.name || '匿名用户' }}</span>
                        <div class="flex items-center space-x-1">
                            <span class="text-sm text-gray-500">{{ comment.like_count }}</span> &nbsp;
                            <van-icon :name="comment.is_like ? 'like' : 'like-o'"
                                :class="{ 'text-red-500': comment.is_like, 'text-gray-400': !comment.is_like }"
                                @click="$emit('toggleLike', comment)" class="text-lg cursor-pointer" />
                        </div>
                    </div>
                    <p class="text-gray-700 text-sm mb-1">{{ comment.note }}</p>
                    <div class="flex items-center justify-between">
                        <div class="text-gray-400 text-xs">{{ formatDate(comment.updated_time) }}</div>
                        <van-icon v-if="comment.is_my" name="ellipsis" class="text-gray-400"
                            @click="show_action_sheet(comment)" />
                    </div>
                </div>
            </div>
        </div>
        <van-popup v-model:show="show_comment_popup_model" position="bottom" round closeable safe-area-inset-bottom
            style="height: 80%">
            <div class="flex flex-col h-full">
                <div class="flex-none px-4 py-3 border-b bg-white sticky top-0 z-10">
                    <div class="text-lg font-medium">全部评论 ({{ commentCount }})</div>
                </div>
                <div class="flex-1 overflow-y-auto">
                    <van-list v-model:loading="popup_loading_model" :finished="popupFinished" finished-text="没有更多评论了"
                        @load="$emit('popupLoad')" class="px-4 py-2 pb-16">
                        <div v-for="comment in popupCommentList" :key="comment.id"
                            class="border-b border-gray-100 last:border-b-0 py-4">
                            <div class="flex">
                                <img :src="comment.avatar || 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg'"
                                    class="w-10 h-10 rounded-full flex-shrink-0" style="margin-right: 0.5rem;" />
                                <div class="flex-1 ml-3">
                                    <div class="flex justify-between items-center mb-1">
                                        <span class="font-medium text-gray-900">{{ comment.name || '匿名用户' }}</span>
                                        <div class="flex items-center space-x-1">
                                            <span class="text-sm text-gray-500">{{ comment.like_count }}</span>
                                            &nbsp;
                                            <van-icon :name="comment.is_like ? 'like' : 'like-o'"
                                                :class="{ 'text-red-500': comment.is_like, 'text-gray-400': !comment.is_like }"
                                                @click="$emit('toggleLike', comment)" class="text-lg cursor-pointer" />
                                        </div>
                                    </div>
                                    <p class="text-gray-700 text-sm mb-1">{{ comment.note }}</p>
                                    <div class="flex items-center justify-between">
                                        <div class="text-gray-400 text-xs">{{ formatDate(comment.updated_time) }}</div>
                                        <van-icon v-if="comment.is_my" name="ellipsis" class="text-gray-400"
                                            @click="show_action_sheet(comment)" />
                                    </div>
                                </div>
                            </div>
                        </div>
                    </van-list>
                </div>
                <div class="flex-none border-t px-4 py-2 bg-white fixed bottom-0 left-0 right-0 z-10">
                    <div class="flex items-center space-x-2">
                        <van-field v-model="popup_comment_model" rows="1" autosize type="textarea" placeholder="请输入评论"
                            class="flex-1 bg-gray-100 rounded-lg" />
                        <van-button type="primary" size="small" @click="$emit('submitPopupComment')">发送</van-button>
                    </div>
                </div>
            </div>
        </van-popup>

        <van-action-sheet v-model:show="show_actions" :actions="actions" cancel-text="取消" close-on-click-action
            @select="on_select_action" />
    </div>
</template>

<script setup>
import { computed, ref } from 'vue';
import { showConfirmDialog, showToast } from 'vant'
import { formatDate } from '@/utils/tools'
import { delGroupCommentAPI } from '@/api/course'

const props = defineProps({
    commentCount: {
        type: Number,
        default: 0
    },
    commentList: {
        type: Array,
        default: () => []
    },
    showCommentPopup: {
        type: Boolean,
        default: false
    },
    popupCommentList: {
        type: Array,
        default: () => []
    },
    popupLoading: {
        type: Boolean,
        default: false
    },
    popupFinished: {
        type: Boolean,
        default: false
    },
    popupComment: {
        type: String,
        default: ''
    },
    bottomWrapperHeight: {
        type: String,
        default: '0px'
    }
});

const emit = defineEmits([
    'update:showCommentPopup',
    'update:popupLoading',
    'update:popupComment',
    'toggleLike',
    'popupLoad',
    'submitPopupComment',
    'commentDeleted'
]);

const show_comment_popup_model = computed({
    get: () => props.showCommentPopup,
    set: (val) => emit('update:showCommentPopup', val)
});

const popup_loading_model = computed({
    get: () => props.popupLoading,
    set: (val) => emit('update:popupLoading', val)
});

const popup_comment_model = computed({
    get: () => props.popupComment,
    set: (val) => emit('update:popupComment', val)
});

const show_actions = ref(false)
const current_comment = ref(null)
const actions = [
    { name: '删除', color: '#ef4444' },
]

/**
 * @function show_action_sheet
 * @description 打开评论操作面板(目前仅支持删除)
 * @param {Object} comment - 当前选中的评论对象
 * @returns {void}
 */
const show_action_sheet = (comment) => {
    current_comment.value = comment
    show_actions.value = true
}

/**
 * @function on_select_action
 * @description 处理评论操作面板选项点击
 * @param {Object} action - 选中的动作项
 * @returns {void}
 */
const on_select_action = (action) => {
    if (action?.name === '删除') {
        confirm_delete_comment()
    }
}

/**
 * @function confirm_delete_comment
 * @description 二次确认删除评论并调用接口
 * @returns {Promise<void>}
 */
const confirm_delete_comment = async () => {
    const comment_id = current_comment.value?.id
    if (!comment_id) return

    try {
        await showConfirmDialog({
            title: '温馨提示',
            message: '确定要删除这条评论吗?',
        })
    } catch (e) {
        return
    }

    const { code } = await delGroupCommentAPI({ i: comment_id })
    if (code === 1) {
        showToast('评论删除成功')
        emit('commentDeleted', comment_id)
    }
}
</script>