清除数据
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:model-value="visible"
|
||||
title="商品评价"
|
||||
width="640px"
|
||||
@update:model-value="$emit('update:visible', $event)"
|
||||
>
|
||||
<div v-if="checkLoading" class="text-center py-8">
|
||||
<el-icon :size="32" class="animate-spin">
|
||||
<Loading/>
|
||||
</el-icon>
|
||||
<p class="mt-2 text-gray-500">加载评价状态...</p>
|
||||
</div>
|
||||
|
||||
<div v-else class="space-y-6">
|
||||
<div v-if="reviewableItems.length === 0 && reviewedItems.length === 0" class="text-center py-8">
|
||||
<el-empty description="暂无可评价商品"/>
|
||||
</div>
|
||||
|
||||
<!-- 待评价商品 -->
|
||||
<div v-for="item in reviewableItems" :key="item.productId" class="border rounded-lg p-4">
|
||||
<div class="flex gap-4 mb-4">
|
||||
<SafeImage :alt="item.productName" :src="item.productImage" img-class="w-16 h-16 object-cover rounded"
|
||||
wrapper-class="w-16 h-16 rounded"/>
|
||||
<div class="flex-1">
|
||||
<h4 class="font-semibold">{{ item.productName }}</h4>
|
||||
<div class="text-sm text-gray-500">¥{{ item.price }} × {{ item.quantity }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="block text-sm text-gray-600 mb-1">评分</label>
|
||||
<el-rate v-model="item.rating" :texts="['很差', '较差', '一般', '满意', '非常满意']" show-text/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm text-gray-600 mb-1">评价内容</label>
|
||||
<el-input
|
||||
v-model="item.content"
|
||||
:rows="3"
|
||||
maxlength="500"
|
||||
placeholder="分享一下你的使用感受吧"
|
||||
show-word-limit
|
||||
type="textarea"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 已评价商品 -->
|
||||
<div v-for="item in reviewedItems" :key="'reviewed-' + item.productId" class="border rounded-lg p-4 bg-gray-50">
|
||||
<div class="flex gap-4">
|
||||
<SafeImage :alt="item.productName" :src="item.productImage" img-class="w-16 h-16 object-cover rounded"
|
||||
wrapper-class="w-16 h-16 rounded"/>
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<h4 class="font-semibold">{{ item.productName }}</h4>
|
||||
<el-tag size="small" type="success">已评价</el-tag>
|
||||
</div>
|
||||
<el-rate :model-value="item.existingReview!.rating" disabled/>
|
||||
<p class="text-sm text-gray-600 mt-1">{{ item.existingReview!.content }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="$emit('update:visible', false)">关闭</el-button>
|
||||
<el-button
|
||||
v-if="reviewableItems.length > 0"
|
||||
:disabled="!canSubmit"
|
||||
:loading="submitting"
|
||||
type="primary"
|
||||
@click="handleSubmit"
|
||||
>
|
||||
提交评价
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {ref, computed, watch} from 'vue'
|
||||
import {ElMessage} from 'element-plus'
|
||||
import {reviewApi} from '@/api/modules/review'
|
||||
import type {ReviewItem} from '@/api/modules/review'
|
||||
import type {OrderItem} from '@/types/api'
|
||||
import SafeImage from '@/components/common/SafeImage.vue'
|
||||
|
||||
interface ReviewableItem extends OrderItem {
|
||||
rating: number
|
||||
content: string
|
||||
reviewed: boolean
|
||||
existingReview?: ReviewItem
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
visible: boolean
|
||||
orderId: number
|
||||
orderItems: OrderItem[]
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:visible': [value: boolean]
|
||||
success: []
|
||||
}>()
|
||||
|
||||
const checkLoading = ref(false)
|
||||
const submitting = ref(false)
|
||||
const items = ref<ReviewableItem[]>([])
|
||||
|
||||
const reviewableItems = computed(() => items.value.filter(i => !i.reviewed))
|
||||
const reviewedItems = computed(() => items.value.filter(i => i.reviewed))
|
||||
const canSubmit = computed(() => reviewableItems.value.some(i => i.content.trim()))
|
||||
|
||||
const loadReviewStatus = async () => {
|
||||
if (!props.orderId || !props.orderItems.length) {
|
||||
items.value = []
|
||||
return
|
||||
}
|
||||
checkLoading.value = true
|
||||
try {
|
||||
const list: ReviewableItem[] = props.orderItems.map(item => ({
|
||||
...item,
|
||||
rating: 5,
|
||||
content: '',
|
||||
reviewed: false,
|
||||
existingReview: undefined,
|
||||
}))
|
||||
|
||||
const checks = await Promise.all(
|
||||
list.map(item => reviewApi.checkReview(props.orderId, item.productId).catch(() => null))
|
||||
)
|
||||
|
||||
checks.forEach((res, index) => {
|
||||
if (res?.success && res.data.reviewed) {
|
||||
list[index].reviewed = true
|
||||
list[index].existingReview = res.data.review
|
||||
}
|
||||
})
|
||||
|
||||
items.value = list
|
||||
} finally {
|
||||
checkLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleSubmit = async () => {
|
||||
const toSubmit = reviewableItems.value.filter(i => i.content.trim())
|
||||
if (toSubmit.length === 0) {
|
||||
ElMessage.warning('请至少填写一条评价内容')
|
||||
return
|
||||
}
|
||||
|
||||
submitting.value = true
|
||||
let successCount = 0
|
||||
try {
|
||||
for (const item of toSubmit) {
|
||||
try {
|
||||
await reviewApi.create({
|
||||
orderId: props.orderId,
|
||||
productId: item.productId,
|
||||
rating: item.rating,
|
||||
content: item.content.trim(),
|
||||
})
|
||||
item.reviewed = true
|
||||
item.existingReview = {rating: item.rating, content: item.content} as ReviewItem
|
||||
successCount++
|
||||
} catch (error: any) {
|
||||
const respData = error?.response?.data
|
||||
const msg = respData?.message || error?.message || '提交失败'
|
||||
ElMessage.error(`${item.productName}: ${msg}`)
|
||||
}
|
||||
}
|
||||
|
||||
if (successCount > 0) {
|
||||
ElMessage.success(`成功提交 ${successCount} 条评价`)
|
||||
emit('success')
|
||||
if (reviewableItems.value.length === 0) {
|
||||
emit('update:visible', false)
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
watch(() => props.visible, (val) => {
|
||||
if (val) loadReviewStatus()
|
||||
if (!val) items.value = []
|
||||
})
|
||||
|
||||
watch(
|
||||
() => [props.orderId, props.orderItems],
|
||||
() => {
|
||||
if (props.visible) loadReviewStatus()
|
||||
},
|
||||
{immediate: true}
|
||||
)
|
||||
</script>
|
||||
Reference in New Issue
Block a user