CourseReviewsPage.vue 4.48 KB
<!--
 * @Date: 2025-03-21 11:33:26
 * @LastEditors: hookehuyr hookehuyr@gmail.com
 * @LastEditTime: 2025-12-03 20:00:05
 * @FilePath: /mlaj/src/views/courses/CourseReviewsPage.vue
 * @Description: 文件描述
-->
<template>
  <AppLayout title="全部评价">
    <div class="px-4 py-3">
      <!-- Overall Rating -->
      <div class="flex items-center justify-between mb-4">
        <div class="flex items-center">
          <div class="text-2xl font-bold mr-2">{{ overallRating }}</div>
          <van-rate v-model="overallRating" readonly :size="20" color="#ffd21e" void-icon="star" void-color="#eee" />
        </div>
        <div class="text-gray-500 text-sm">{{ commentTotal }}条评论</div>
      </div>

      <!-- Reviews List -->
      <van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" @load="onLoad">
        <div v-for="(review, index) in reviews" :key="index" class="mb-4 pb-4 border-b border-gray-100 last:border-0">
          <div class="flex justify-between items-center mb-2">
            <div class="flex items-center flex-1 min-w-0 mr-2">
              <div class="flex-grow">
                <span class="font-medium text-sm block">{{ review.name || '匿名用户' }}</span>
              </div>
            </div>
            <van-rate v-model="review.score" readonly :size="20" color="#ffd21e" void-icon="star" void-color="#eee" />
          </div>
          <p class="text-gray-600 text-sm mb-2">{{ review.note }}</p>
          <div class="flex justify-between items-center">
            <div class="text-gray-400 text-xs">{{ formatDate(review.created_time) }}</div>
            <van-icon v-if="review.is_my" name="ellipsis" class="text-gray-400" @click="showActionSheet(review)" />
          </div>
        </div>
      </van-list>
    </div>

    <!-- Action Sheet -->
    <van-action-sheet v-model:show="showActions" :actions="actions" cancel-text="取消" close-on-click-action
      @select="onSelect" />

    <!-- Review Edit Popup -->
    <ReviewPopup v-model:show="showReviewPopup" title="编辑评价" :initial-score="currentReview?.score"
      :initial-note="currentReview?.note" @submit="handleReviewEdit" />
  </AppLayout>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import AppLayout from '@/components/layout/AppLayout.vue'
import { Rate, List, Icon, ActionSheet, showConfirmDialog, showToast } from 'vant'
import { formatDate } from '@/utils/tools'
import ReviewPopup from '@/components/courses/ReviewPopup.vue'

// 导入接口
import { getGroupCommentListAPI, editGroupCommentAPI, delGroupCommentAPI } from '@/api/course'

const route = useRoute()
const overallRating = ref(0)
const loading = ref(false)
const finished = ref(false)
const reviews = ref([])
const commentTotal = ref(0)
const limit = ref(5)
const page = ref(0)

// 动作面板相关
const showActions = ref(false)
const currentReview = ref(null)
const actions = [
  { name: '编辑', color: '#2563eb' },
  { name: '删除', color: '#ef4444' },
]

// 评论编辑相关
const showReviewPopup = ref(false)

const fetchComments = async () => {
  const { code, data } = await getGroupCommentListAPI({
    group_id: route.params.id,
    page: page.value,
    limit: limit.value
  })
  if (code) {
    if (page.value === 0) {
      reviews.value = data.comment_list
      overallRating.value = data.comment_score || 0
      commentTotal.value = data.comment_count || 0
    } else {
      reviews.value.push(...data.comment_list)
    }
    finished.value = data.comment_list.length < limit.value
    page.value += 1
  }
  loading.value = false
}

const onLoad = () => {
  fetchComments()
}

const showActionSheet = (review) => {
  currentReview.value = review
  showActions.value = true
}

const onSelect = (action) => {
  if (action.name === '编辑') {
    showReviewPopup.value = true
  } else if (action.name === '删除') {
    showConfirmDialog({
      title: '温馨提示',
      message: '确定要删除这条评论吗?',
    }).then(() => {
      handleReviewDelete()
    })
  }
}

const handleReviewEdit = async ({ score, note }) => {
  const { code } = await editGroupCommentAPI({
    i: currentReview.value.id,
    score,
    note
  })
  if (code) {
    showToast('评论修改成功')
    page.value = 0
    await fetchComments()
  }
}

const handleReviewDelete = async () => {
  const { code } = await delGroupCommentAPI({
    i: currentReview.value.id
  })
  if (code) {
    showToast('评论删除成功')
    page.value = 0
    await fetchComments()
  }
}
</script>