清除数据

This commit is contained in:
2026-05-06 23:30:54 +08:00
parent 17a5734d67
commit d16fc36264
149 changed files with 6691 additions and 5575 deletions

View File

@@ -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>