打分评价
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
.comment-message-card {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border-radius: 24rpx;
|
||||
padding: 40rpx;
|
||||
color: #fff;
|
||||
box-shadow: 0 8rpx 24rpx rgba(102, 126, 234, 0.3);
|
||||
max-width: 600rpx;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.comment-header {
|
||||
margin-bottom: 32rpx;
|
||||
text-align: center;
|
||||
|
||||
.comment-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.comment-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 32rpx;
|
||||
|
||||
.star-rating {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 16rpx;
|
||||
|
||||
.star-item {
|
||||
transition: transform 0.2s ease;
|
||||
|
||||
&:active:not(.is-disabled) {
|
||||
transform: scale(1.15);
|
||||
}
|
||||
|
||||
&.is-disabled {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.star-icon {
|
||||
font-size: 56rpx;
|
||||
line-height: 1;
|
||||
|
||||
&.star-filled {
|
||||
color: #FFD700;
|
||||
}
|
||||
|
||||
&.star-empty {
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rating-desc {
|
||||
.rating-desc-text {
|
||||
font-size: 28rpx;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.submitted-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16rpx 32rpx;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 40rpx;
|
||||
|
||||
.submitted-text {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.no-permission {
|
||||
padding: 16rpx 32rpx;
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
border-radius: 40rpx;
|
||||
|
||||
.no-permission-text {
|
||||
font-size: 26rpx;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
padding: 20rpx 56rpx;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border: 2rpx solid rgba(255, 255, 255, 0.4);
|
||||
border-radius: 48rpx;
|
||||
color: #fff;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
|
||||
&.is-active {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-color: transparent;
|
||||
|
||||
.submit-btn-text {
|
||||
color: #667eea;
|
||||
}
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.submit-btn-text {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<view class="comment-message-card">
|
||||
<view class="comment-header">
|
||||
<text class="comment-title">{{ title }}</text>
|
||||
</view>
|
||||
|
||||
<view class="comment-body">
|
||||
<!-- 星级评分 -->
|
||||
<view class="star-rating">
|
||||
<view
|
||||
v-for="star in 5"
|
||||
:key="star"
|
||||
class="star-item"
|
||||
:class="{
|
||||
'is-active': star <= currentRating,
|
||||
'is-disabled': !canComment || isSubmitted
|
||||
}"
|
||||
@tap="handleStarClick(star)"
|
||||
>
|
||||
<text class="star-icon" :class="star <= currentRating ? 'star-filled' : 'star-empty'">★</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 评分描述 -->
|
||||
<view v-if="currentRating > 0" class="rating-desc">
|
||||
<text class="rating-desc-text">{{ getRatingDesc(currentRating) }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 不可评价提示 -->
|
||||
<view v-if="!canComment && !isSubmitted" class="no-permission">
|
||||
<text class="no-permission-text">仅访客可评价</text>
|
||||
</view>
|
||||
|
||||
<!-- 已评分状态 -->
|
||||
<view v-else-if="isSubmitted" class="submitted-status">
|
||||
<text class="submitted-text">✓ 已评分</text>
|
||||
</view>
|
||||
|
||||
<!-- 提交按钮 -->
|
||||
<button
|
||||
v-else-if="canComment"
|
||||
class="submit-btn"
|
||||
:class="{ 'is-active': currentRating > 0 }"
|
||||
:disabled="currentRating === 0 || submitting"
|
||||
@tap="handleSubmit"
|
||||
>
|
||||
<text class="submit-btn-text">{{ submitting ? '提交中...' : '提交评分' }}</text>
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
interface Props {
|
||||
roomId: string
|
||||
initialRating?: number
|
||||
canComment?: boolean // 是否可以评价(当前用户是否为guestId)
|
||||
title?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
initialRating: 0,
|
||||
canComment: false,
|
||||
title: '请为本次服务评分'
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
submit: [rating: number]
|
||||
}>()
|
||||
|
||||
const currentRating = ref(props.initialRating)
|
||||
const submitting = ref(false)
|
||||
const isSubmitted = ref(props.initialRating > 0)
|
||||
|
||||
// 监听 initialRating 变化
|
||||
watch(() => props.initialRating, (newVal) => {
|
||||
currentRating.value = newVal
|
||||
isSubmitted.value = newVal > 0
|
||||
})
|
||||
|
||||
// 星级描述映射
|
||||
const ratingDescriptions = {
|
||||
1: '非常不满意',
|
||||
2: '不满意',
|
||||
3: '一般',
|
||||
4: '满意',
|
||||
5: '非常满意'
|
||||
}
|
||||
|
||||
const getRatingDesc = (rating: number): string => {
|
||||
return ratingDescriptions[rating as keyof typeof ratingDescriptions] || ''
|
||||
}
|
||||
|
||||
const handleStarClick = (star: number) => {
|
||||
if (!props.canComment || isSubmitted.value) return
|
||||
currentRating.value = star
|
||||
}
|
||||
|
||||
const handleSubmit = () => {
|
||||
if (currentRating.value === 0 || !props.canComment || isSubmitted.value) return
|
||||
|
||||
submitting.value = true
|
||||
try {
|
||||
emit('submit', currentRating.value)
|
||||
isSubmitted.value = true
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import './CommentMessageCard.scss';
|
||||
</style>
|
||||
@@ -461,4 +461,26 @@
|
||||
.send-icon {
|
||||
font-size: 36rpx;
|
||||
color: #4b87ff;
|
||||
}
|
||||
}
|
||||
// ==================== 系统消息样式 ====================
|
||||
.system-row {
|
||||
justify-content: center;
|
||||
margin-bottom: 48rpx;
|
||||
}
|
||||
|
||||
.system-message-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
max-width: 80%;
|
||||
}
|
||||
|
||||
.system-message-text {
|
||||
padding: 16rpx 32rpx;
|
||||
background: rgba(148, 163, 184, 0.15);
|
||||
border-radius: 32rpx;
|
||||
font-size: 26rpx;
|
||||
color: #64748b;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -54,8 +54,31 @@
|
||||
<text class="loading-more-text">没有更多消息了</text>
|
||||
</view>
|
||||
<view class="message-list">
|
||||
<view class="message-item" v-for="msg in messages" :key="msg.messageId"
|
||||
:class="msg.senderType === 'guest' ? 'self' : 'other'">
|
||||
<view class="message-item" v-for="msg in messages" :key="msg.messageId">
|
||||
<!-- 系统消息(居中显示) -->
|
||||
<view class="message-row system-row" v-if="msg.senderType === 'system'">
|
||||
<view class="system-message-container">
|
||||
<!-- 评分消息卡片 -->
|
||||
<template v-if="msg.messageType === 'comment'">
|
||||
<CommentMessageCard
|
||||
:room-id="roomId"
|
||||
:can-comment="getCanComment()"
|
||||
:initial-rating="commentLevel"
|
||||
@submit="handleCommentSubmit"
|
||||
/>
|
||||
</template>
|
||||
<!-- 其他系统消息 -->
|
||||
<template v-else>
|
||||
<view class="system-message-text">
|
||||
<text>{{ msg.content }}</text>
|
||||
</view>
|
||||
</template>
|
||||
<text class="message-time">{{ formatTime(msg.sendTime) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 普通用户/客服消息 -->
|
||||
<view v-else :class="msg.senderType === 'guest' ? 'self' : 'other'">
|
||||
<!-- 对方消息(左侧) -->
|
||||
<view class="message-row other-row" v-if="msg.senderType !== 'guest'">
|
||||
<view>
|
||||
@@ -95,6 +118,7 @@
|
||||
<text class="avatar-text">我</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
@@ -120,6 +144,7 @@
|
||||
import { ref, reactive, computed, nextTick, onMounted, onUnmounted, watch } from 'vue'
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
import MeetingCard from '../../meeting/meetingCard/MeetingCard.uvue'
|
||||
import CommentMessageCard from './CommentMessageCard/CommentMessageCard.uvue'
|
||||
import type { ChatRoomMessageVO, CustomerVO, ChatMemberVO, TbChatRoomMessageDTO, VideoMeetingVO } from '@/types/workcase'
|
||||
import { workcaseChatAPI } from '@/api/workcase'
|
||||
import { wsClient } from '@/utils/websocket'
|
||||
@@ -130,6 +155,8 @@ const headerTotalHeight = ref<number>(88)
|
||||
const roomId = ref<string>('')
|
||||
const workcaseId = ref<string>('')
|
||||
const roomName = ref<string>('聊天室')
|
||||
const guestId = ref<string>('') // 聊天室访客ID
|
||||
const commentLevel = ref<number>(0) // 已有评分
|
||||
const inputText = ref<string>('')
|
||||
const scrollTop = ref<number>(0)
|
||||
const loading = ref<boolean>(false)
|
||||
@@ -211,6 +238,9 @@ const totalMembers = computed<MemberDisplay[]>(() => {
|
||||
return Array.from(memberMap.values())
|
||||
})
|
||||
|
||||
function getCanComment(): boolean {
|
||||
return currentUserId.value === guestId.value
|
||||
}
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
const windowInfo = uni.getWindowInfo()
|
||||
@@ -280,6 +310,8 @@ async function refreshChatRoomInfo() {
|
||||
if (roomRes.success && roomRes.data) {
|
||||
roomName.value = roomRes.data.roomName || '聊天室'
|
||||
workcaseId.value = roomRes.data.workcaseId || ''
|
||||
guestId.value = roomRes.data.guestId || ''
|
||||
commentLevel.value = roomRes.data.commentLevel || 0
|
||||
messageTotal.value = roomRes.data.messageCount || 0
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -311,7 +343,9 @@ async function loadChatRoom() {
|
||||
if (roomRes.success && roomRes.data) {
|
||||
roomName.value = roomRes.data.roomName || '聊天室'
|
||||
workcaseId.value = roomRes.data.workcaseId || ''
|
||||
guestId.value = roomRes.data.guestId || ''
|
||||
messageTotal.value = roomRes.data.messageCount || 0
|
||||
commentLevel.value = roomRes.data.commentLevel!
|
||||
}
|
||||
// 后端是降序查询,page1是最新消息
|
||||
currentPage.value = 1
|
||||
@@ -644,6 +678,31 @@ async function handleJoinMeeting(meetingId: string) {
|
||||
}
|
||||
}
|
||||
|
||||
// 处理评分提交
|
||||
async function handleCommentSubmit(rating: number) {
|
||||
console.log('[handleCommentSubmit] 提交评分:', rating)
|
||||
try {
|
||||
const result = await workcaseChatAPI.submitComment(roomId.value, rating)
|
||||
if (result.success) {
|
||||
uni.showToast({
|
||||
title: '感谢您的评分!',
|
||||
icon: 'success'
|
||||
})
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: result.message || '评分提交失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[handleCommentSubmit] 评分提交失败:', error)
|
||||
uni.showToast({
|
||||
title: '评分提交失败,请稍后重试',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 返回上一页
|
||||
function goBack() {
|
||||
uni.navigateBack()
|
||||
|
||||
Reference in New Issue
Block a user