|
|
@ -0,0 +1,824 @@ |
|
|
|
<template> |
|
|
|
<div class="customer-reviews"> |
|
|
|
<div class="reviews-header"> |
|
|
|
<h2><i class="fas fa-comments"></i> 客户评价</h2> |
|
|
|
<div class="separator"></div> |
|
|
|
<p class="subtitle">真实的客户反馈,见证我们的专业服务</p> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="reviews-container"> |
|
|
|
<!-- 评价卡片轮播 --> |
|
|
|
<div class="reviews-carousel" ref="carouselRef"> |
|
|
|
<div class="reviews-track" :style="{ transform: `translateX(-${currentIndex * cardWidth}px)` }"> |
|
|
|
<div |
|
|
|
v-for="(review, index) in reviews" |
|
|
|
:key="index" |
|
|
|
class="review-card" |
|
|
|
@click="openModal(review)" |
|
|
|
> |
|
|
|
<div class="review-header"> |
|
|
|
<div class="customer-info"> |
|
|
|
<div class="avatar"> |
|
|
|
<img :src="review.avatar" :alt="review.customerName" /> |
|
|
|
</div> |
|
|
|
<div class="customer-details"> |
|
|
|
<h4>{{ review.customerName }}</h4> |
|
|
|
<p class="company">{{ review.company }}</p> |
|
|
|
<div class="rating"> |
|
|
|
<i v-for="n in 5" :key="n" |
|
|
|
class="fas fa-star" |
|
|
|
:class="{ active: n <= review.rating }"> |
|
|
|
</i> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="review-date">{{ formatDate(review.date) }}</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="review-content"> |
|
|
|
<p class="review-text">{{ review.content }}</p> |
|
|
|
|
|
|
|
<!-- 聊天截图预览 --> |
|
|
|
<div v-if="review.chatScreenshots && review.chatScreenshots.length > 0" class="chat-preview"> |
|
|
|
<div class="screenshot-grid"> |
|
|
|
<div |
|
|
|
v-for="(screenshot, sIndex) in review.chatScreenshots.slice(0, 3)" |
|
|
|
:key="sIndex" |
|
|
|
class="screenshot-item" |
|
|
|
:class="{ 'more-indicator': sIndex === 2 && review.chatScreenshots.length > 3 }" |
|
|
|
> |
|
|
|
<img :src="screenshot.thumbnail || screenshot.url" :alt="`聊天截图 ${sIndex + 1}`" /> |
|
|
|
<div v-if="sIndex === 2 && review.chatScreenshots.length > 3" class="more-overlay"> |
|
|
|
<span>+{{ review.chatScreenshots.length - 3 }}</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="view-more"> |
|
|
|
<i class="fas fa-search-plus"></i> |
|
|
|
点击查看完整聊天记录 |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="review-tags"> |
|
|
|
<span v-for="tag in review.tags" :key="tag" class="tag">{{ tag }}</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 轮播控制 --> |
|
|
|
<div class="carousel-controls"> |
|
|
|
<button class="control-btn prev" @click="prevSlide" :disabled="currentIndex === 0"> |
|
|
|
<i class="fas fa-chevron-left"></i> |
|
|
|
</button> |
|
|
|
<div class="indicators"> |
|
|
|
<span |
|
|
|
v-for="(_, index) in totalSlides" |
|
|
|
:key="index" |
|
|
|
class="indicator" |
|
|
|
:class="{ active: index === currentIndex }" |
|
|
|
@click="goToSlide(index)" |
|
|
|
></span> |
|
|
|
</div> |
|
|
|
<button class="control-btn next" @click="nextSlide" :disabled="currentIndex >= totalSlides - 1"> |
|
|
|
<i class="fas fa-chevron-right"></i> |
|
|
|
</button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 详情弹窗 --> |
|
|
|
<div v-if="showModal" class="modal-overlay" @click="closeModal"> |
|
|
|
<div class="modal-content" @click.stop> |
|
|
|
<div class="modal-header"> |
|
|
|
<div class="customer-info"> |
|
|
|
<div class="avatar"> |
|
|
|
<img :src="selectedReview.avatar" :alt="selectedReview.customerName" /> |
|
|
|
</div> |
|
|
|
<div class="customer-details"> |
|
|
|
<h3>{{ selectedReview.customerName }}</h3> |
|
|
|
<p class="company">{{ selectedReview.company }}</p> |
|
|
|
<div class="rating"> |
|
|
|
<i v-for="n in 5" :key="n" |
|
|
|
class="fas fa-star" |
|
|
|
:class="{ active: n <= selectedReview.rating }"> |
|
|
|
</i> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<button class="close-btn" @click="closeModal"> |
|
|
|
<i class="fas fa-times"></i> |
|
|
|
</button> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="modal-body"> |
|
|
|
<div class="review-content"> |
|
|
|
<h4>客户评价</h4> |
|
|
|
<p>{{ selectedReview.content }}</p> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 完整聊天截图展示 --> |
|
|
|
<div v-if="selectedReview.chatScreenshots && selectedReview.chatScreenshots.length > 0" class="chat-screenshots"> |
|
|
|
<h4>聊天记录</h4> |
|
|
|
<div class="screenshots-grid"> |
|
|
|
<div |
|
|
|
v-for="(screenshot, index) in selectedReview.chatScreenshots" |
|
|
|
:key="index" |
|
|
|
class="screenshot-full" |
|
|
|
@click="openImageViewer(screenshot.url)" |
|
|
|
> |
|
|
|
<img :src="screenshot.url" :alt="`聊天截图 ${index + 1}`" /> |
|
|
|
<div class="screenshot-overlay"> |
|
|
|
<i class="fas fa-search-plus"></i> |
|
|
|
</div> |
|
|
|
<div v-if="screenshot.description" class="screenshot-desc"> |
|
|
|
{{ screenshot.description }} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="review-meta"> |
|
|
|
<div class="tags"> |
|
|
|
<span v-for="tag in selectedReview.tags" :key="tag" class="tag">{{ tag }}</span> |
|
|
|
</div> |
|
|
|
<div class="review-date">评价时间:{{ formatDate(selectedReview.date) }}</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 图片查看器 --> |
|
|
|
<div v-if="showImageViewer" class="image-viewer-overlay" @click="closeImageViewer"> |
|
|
|
<div class="image-viewer-content"> |
|
|
|
<img :src="currentImage" alt="聊天截图" /> |
|
|
|
<button class="close-btn" @click="closeImageViewer"> |
|
|
|
<i class="fas fa-times"></i> |
|
|
|
</button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
|
|
|
|
<script setup> |
|
|
|
import { ref, onMounted, onUnmounted, computed } from 'vue' |
|
|
|
|
|
|
|
// 响应式数据 |
|
|
|
const currentIndex = ref(0) |
|
|
|
const cardWidth = ref(400) |
|
|
|
const carouselRef = ref(null) |
|
|
|
const showModal = ref(false) |
|
|
|
const selectedReview = ref({}) |
|
|
|
const showImageViewer = ref(false) |
|
|
|
const currentImage = ref('') |
|
|
|
|
|
|
|
// 示例数据 |
|
|
|
const reviews = ref([ |
|
|
|
{ |
|
|
|
customerName: '张总', |
|
|
|
company: '科技有限公司', |
|
|
|
avatar: 'https://randomuser.me/api/portraits/men/32.jpg', |
|
|
|
rating: 5, |
|
|
|
date: '2024-01-15', |
|
|
|
content: '合作非常愉快!团队专业度很高,项目按时交付,质量超出预期。特别是在沟通过程中,响应速度很快,问题解决及时。', |
|
|
|
tags: ['专业', '高效', '优质服务'], |
|
|
|
chatScreenshots: [ |
|
|
|
{ |
|
|
|
url: 'https://via.placeholder.com/400x300/3498db/ffffff?text=项目需求讨论', |
|
|
|
thumbnail: 'https://via.placeholder.com/200x150/3498db/ffffff?text=讨论', |
|
|
|
description: '项目需求讨论' |
|
|
|
}, |
|
|
|
{ |
|
|
|
url: 'https://via.placeholder.com/400x300/2ecc71/ffffff?text=进度汇报', |
|
|
|
thumbnail: 'https://via.placeholder.com/200x150/2ecc71/ffffff?text=汇报', |
|
|
|
description: '进度汇报' |
|
|
|
}, |
|
|
|
{ |
|
|
|
url: 'https://via.placeholder.com/400x300/e74c3c/ffffff?text=最终确认', |
|
|
|
thumbnail: 'https://via.placeholder.com/200x150/e74c3c/ffffff?text=确认', |
|
|
|
description: '最终确认' |
|
|
|
} |
|
|
|
] |
|
|
|
}, |
|
|
|
{ |
|
|
|
customerName: '李经理', |
|
|
|
company: '贸易集团', |
|
|
|
avatar: 'https://randomuser.me/api/portraits/women/44.jpg', |
|
|
|
rating: 5, |
|
|
|
date: '2024-01-10', |
|
|
|
content: '服务态度很好,技术实力强,解决了我们很多技术难题。整个合作过程很顺畅,推荐!', |
|
|
|
tags: ['技术强', '服务好', '值得推荐'], |
|
|
|
chatScreenshots: [ |
|
|
|
{ |
|
|
|
url: 'https://via.placeholder.com/400x300/9b59b6/ffffff?text=技术方案讨论', |
|
|
|
thumbnail: 'https://via.placeholder.com/200x150/9b59b6/ffffff?text=方案', |
|
|
|
description: '技术方案讨论' |
|
|
|
}, |
|
|
|
{ |
|
|
|
url: 'https://via.placeholder.com/400x300/f39c12/ffffff?text=问题解决过程', |
|
|
|
thumbnail: 'https://via.placeholder.com/200x150/f39c12/ffffff?text=解决', |
|
|
|
description: '问题解决过程' |
|
|
|
} |
|
|
|
] |
|
|
|
}, |
|
|
|
{ |
|
|
|
customerName: '王总监', |
|
|
|
company: '制造企业', |
|
|
|
avatar: 'https://randomuser.me/api/portraits/men/67.jpg', |
|
|
|
rating: 4, |
|
|
|
date: '2024-01-05', |
|
|
|
content: '项目完成度很高,团队配合默契。在遇到突发问题时,能够快速响应并提供解决方案。', |
|
|
|
tags: ['高完成度', '快速响应', '团队协作'], |
|
|
|
chatScreenshots: [ |
|
|
|
{ |
|
|
|
url: 'https://via.placeholder.com/400x300/1abc9c/ffffff?text=紧急问题处理', |
|
|
|
thumbnail: 'https://via.placeholder.com/200x150/1abc9c/ffffff?text=紧急', |
|
|
|
description: '紧急问题处理' |
|
|
|
}, |
|
|
|
{ |
|
|
|
url: 'https://via.placeholder.com/400x300/34495e/ffffff?text=解决方案确认', |
|
|
|
thumbnail: 'https://via.placeholder.com/200x150/34495e/ffffff?text=方案', |
|
|
|
description: '解决方案确认' |
|
|
|
}, |
|
|
|
{ |
|
|
|
url: 'https://via.placeholder.com/400x300/e67e22/ffffff?text=客户满意度反馈', |
|
|
|
thumbnail: 'https://via.placeholder.com/200x150/e67e22/ffffff?text=反馈', |
|
|
|
description: '客户满意度反馈' |
|
|
|
}, |
|
|
|
{ |
|
|
|
url: 'https://via.placeholder.com/400x300/8e44ad/ffffff?text=后续合作讨论', |
|
|
|
thumbnail: 'https://via.placeholder.com/200x150/8e44ad/ffffff?text=合作', |
|
|
|
description: '后续合作讨论' |
|
|
|
} |
|
|
|
] |
|
|
|
} |
|
|
|
]) |
|
|
|
|
|
|
|
// 计算属性 |
|
|
|
const totalSlides = computed(() => { |
|
|
|
const cardsPerSlide = Math.floor(window.innerWidth / cardWidth.value) || 1 |
|
|
|
return Math.ceil(reviews.value.length / cardsPerSlide) |
|
|
|
}) |
|
|
|
|
|
|
|
// 方法 |
|
|
|
const formatDate = (dateStr) => { |
|
|
|
const date = new Date(dateStr) |
|
|
|
return date.toLocaleDateString('zh-CN') |
|
|
|
} |
|
|
|
|
|
|
|
const prevSlide = () => { |
|
|
|
if (currentIndex.value > 0) { |
|
|
|
currentIndex.value-- |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
const nextSlide = () => { |
|
|
|
if (currentIndex.value < totalSlides.value - 1) { |
|
|
|
currentIndex.value++ |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
const goToSlide = (index) => { |
|
|
|
currentIndex.value = index |
|
|
|
} |
|
|
|
|
|
|
|
const openModal = (review) => { |
|
|
|
selectedReview.value = review |
|
|
|
showModal.value = true |
|
|
|
document.body.style.overflow = 'hidden' |
|
|
|
} |
|
|
|
|
|
|
|
const closeModal = () => { |
|
|
|
showModal.value = false |
|
|
|
document.body.style.overflow = 'auto' |
|
|
|
} |
|
|
|
|
|
|
|
const openImageViewer = (imageUrl) => { |
|
|
|
currentImage.value = imageUrl |
|
|
|
showImageViewer.value = true |
|
|
|
} |
|
|
|
|
|
|
|
const closeImageViewer = () => { |
|
|
|
showImageViewer.value = false |
|
|
|
currentImage.value = '' |
|
|
|
} |
|
|
|
|
|
|
|
const updateCardWidth = () => { |
|
|
|
if (window.innerWidth >= 1200) { |
|
|
|
cardWidth.value = 400 |
|
|
|
} else if (window.innerWidth >= 768) { |
|
|
|
cardWidth.value = 350 |
|
|
|
} else { |
|
|
|
cardWidth.value = 300 |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 生命周期 |
|
|
|
onMounted(() => { |
|
|
|
updateCardWidth() |
|
|
|
window.addEventListener('resize', updateCardWidth) |
|
|
|
}) |
|
|
|
|
|
|
|
onUnmounted(() => { |
|
|
|
window.removeEventListener('resize', updateCardWidth) |
|
|
|
document.body.style.overflow = 'auto' |
|
|
|
}) |
|
|
|
</script> |
|
|
|
|
|
|
|
<style lang="scss" scoped> |
|
|
|
.customer-reviews { |
|
|
|
padding: 80px 0; |
|
|
|
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); |
|
|
|
} |
|
|
|
|
|
|
|
.reviews-header { |
|
|
|
text-align: center; |
|
|
|
margin-bottom: 60px; |
|
|
|
|
|
|
|
h2 { |
|
|
|
font-size: 2.5rem; |
|
|
|
color: #2c3e50; |
|
|
|
margin-bottom: 20px; |
|
|
|
font-weight: 700; |
|
|
|
|
|
|
|
i { |
|
|
|
color: #3498db; |
|
|
|
margin-right: 15px; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.separator { |
|
|
|
width: 80px; |
|
|
|
height: 4px; |
|
|
|
background: linear-gradient(90deg, #3498db, #2980b9); |
|
|
|
margin: 0 auto 20px; |
|
|
|
border-radius: 2px; |
|
|
|
} |
|
|
|
|
|
|
|
.subtitle { |
|
|
|
font-size: 1.1rem; |
|
|
|
color: #7f8c8d; |
|
|
|
max-width: 600px; |
|
|
|
margin: 0 auto; |
|
|
|
line-height: 1.6; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.reviews-container { |
|
|
|
max-width: 1400px; |
|
|
|
margin: 0 auto; |
|
|
|
padding: 0 20px; |
|
|
|
position: relative; |
|
|
|
} |
|
|
|
|
|
|
|
.reviews-carousel { |
|
|
|
overflow: hidden; |
|
|
|
margin-bottom: 40px; |
|
|
|
} |
|
|
|
|
|
|
|
.reviews-track { |
|
|
|
display: flex; |
|
|
|
transition: transform 0.5s ease; |
|
|
|
gap: 30px; |
|
|
|
} |
|
|
|
|
|
|
|
.review-card { |
|
|
|
flex: 0 0 400px; |
|
|
|
background: white; |
|
|
|
border-radius: 20px; |
|
|
|
padding: 30px; |
|
|
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); |
|
|
|
cursor: pointer; |
|
|
|
transition: all 0.3s ease; |
|
|
|
border: 1px solid #e9ecef; |
|
|
|
|
|
|
|
&:hover { |
|
|
|
transform: translateY(-10px); |
|
|
|
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15); |
|
|
|
} |
|
|
|
|
|
|
|
@media (max-width: 768px) { |
|
|
|
flex: 0 0 300px; |
|
|
|
padding: 20px; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.review-header { |
|
|
|
display: flex; |
|
|
|
justify-content: space-between; |
|
|
|
align-items: flex-start; |
|
|
|
margin-bottom: 20px; |
|
|
|
} |
|
|
|
|
|
|
|
.customer-info { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
gap: 15px; |
|
|
|
} |
|
|
|
|
|
|
|
.avatar { |
|
|
|
width: 60px; |
|
|
|
height: 60px; |
|
|
|
border-radius: 50%; |
|
|
|
overflow: hidden; |
|
|
|
border: 3px solid #3498db; |
|
|
|
|
|
|
|
img { |
|
|
|
width: 100%; |
|
|
|
height: 100%; |
|
|
|
object-fit: cover; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.customer-details { |
|
|
|
h4, h3 { |
|
|
|
margin: 0 0 5px 0; |
|
|
|
color: #2c3e50; |
|
|
|
font-weight: 600; |
|
|
|
} |
|
|
|
|
|
|
|
.company { |
|
|
|
color: #7f8c8d; |
|
|
|
font-size: 0.9rem; |
|
|
|
margin: 0 0 8px 0; |
|
|
|
} |
|
|
|
|
|
|
|
.rating { |
|
|
|
.fa-star { |
|
|
|
color: #ddd; |
|
|
|
font-size: 0.9rem; |
|
|
|
margin-right: 2px; |
|
|
|
|
|
|
|
&.active { |
|
|
|
color: #f39c12; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.review-date { |
|
|
|
color: #95a5a6; |
|
|
|
font-size: 0.85rem; |
|
|
|
} |
|
|
|
|
|
|
|
.review-content { |
|
|
|
margin-bottom: 20px; |
|
|
|
|
|
|
|
.review-text { |
|
|
|
color: #34495e; |
|
|
|
line-height: 1.6; |
|
|
|
margin-bottom: 20px; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.chat-preview { |
|
|
|
.screenshot-grid { |
|
|
|
display: grid; |
|
|
|
grid-template-columns: repeat(3, 1fr); |
|
|
|
gap: 10px; |
|
|
|
margin-bottom: 15px; |
|
|
|
} |
|
|
|
|
|
|
|
.screenshot-item { |
|
|
|
position: relative; |
|
|
|
aspect-ratio: 16/9; |
|
|
|
border-radius: 8px; |
|
|
|
overflow: hidden; |
|
|
|
border: 2px solid #e9ecef; |
|
|
|
|
|
|
|
img { |
|
|
|
width: 100%; |
|
|
|
height: 100%; |
|
|
|
object-fit: cover; |
|
|
|
transition: transform 0.3s ease; |
|
|
|
} |
|
|
|
|
|
|
|
&:hover img { |
|
|
|
transform: scale(1.05); |
|
|
|
} |
|
|
|
|
|
|
|
&.more-indicator .more-overlay { |
|
|
|
position: absolute; |
|
|
|
top: 0; |
|
|
|
left: 0; |
|
|
|
right: 0; |
|
|
|
bottom: 0; |
|
|
|
background: rgba(0, 0, 0, 0.7); |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
color: white; |
|
|
|
font-weight: bold; |
|
|
|
font-size: 1.2rem; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.view-more { |
|
|
|
text-align: center; |
|
|
|
color: #3498db; |
|
|
|
font-size: 0.9rem; |
|
|
|
font-weight: 500; |
|
|
|
|
|
|
|
i { |
|
|
|
margin-right: 5px; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.review-tags { |
|
|
|
display: flex; |
|
|
|
flex-wrap: wrap; |
|
|
|
gap: 8px; |
|
|
|
|
|
|
|
.tag { |
|
|
|
background: linear-gradient(135deg, #3498db, #2980b9); |
|
|
|
color: white; |
|
|
|
padding: 4px 12px; |
|
|
|
border-radius: 15px; |
|
|
|
font-size: 0.8rem; |
|
|
|
font-weight: 500; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.carousel-controls { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
gap: 20px; |
|
|
|
|
|
|
|
.control-btn { |
|
|
|
width: 50px; |
|
|
|
height: 50px; |
|
|
|
border: none; |
|
|
|
background: #3498db; |
|
|
|
color: white; |
|
|
|
border-radius: 50%; |
|
|
|
cursor: pointer; |
|
|
|
transition: all 0.3s ease; |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
|
|
|
|
&:hover:not(:disabled) { |
|
|
|
background: #2980b9; |
|
|
|
transform: scale(1.1); |
|
|
|
} |
|
|
|
|
|
|
|
&:disabled { |
|
|
|
background: #bdc3c7; |
|
|
|
cursor: not-allowed; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.indicators { |
|
|
|
display: flex; |
|
|
|
gap: 10px; |
|
|
|
|
|
|
|
.indicator { |
|
|
|
width: 12px; |
|
|
|
height: 12px; |
|
|
|
border-radius: 50%; |
|
|
|
background: #bdc3c7; |
|
|
|
cursor: pointer; |
|
|
|
transition: all 0.3s ease; |
|
|
|
|
|
|
|
&.active { |
|
|
|
background: #3498db; |
|
|
|
transform: scale(1.2); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 弹窗样式 |
|
|
|
.modal-overlay { |
|
|
|
position: fixed; |
|
|
|
top: 0; |
|
|
|
left: 0; |
|
|
|
right: 0; |
|
|
|
bottom: 0; |
|
|
|
background: rgba(0, 0, 0, 0.8); |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
z-index: 1000; |
|
|
|
padding: 20px; |
|
|
|
} |
|
|
|
|
|
|
|
.modal-content { |
|
|
|
background: white; |
|
|
|
border-radius: 20px; |
|
|
|
max-width: 800px; |
|
|
|
width: 100%; |
|
|
|
max-height: 90vh; |
|
|
|
overflow-y: auto; |
|
|
|
position: relative; |
|
|
|
} |
|
|
|
|
|
|
|
.modal-header { |
|
|
|
display: flex; |
|
|
|
justify-content: space-between; |
|
|
|
align-items: center; |
|
|
|
padding: 30px 30px 20px; |
|
|
|
border-bottom: 1px solid #e9ecef; |
|
|
|
|
|
|
|
.close-btn { |
|
|
|
width: 40px; |
|
|
|
height: 40px; |
|
|
|
border: none; |
|
|
|
background: #e74c3c; |
|
|
|
color: white; |
|
|
|
border-radius: 50%; |
|
|
|
cursor: pointer; |
|
|
|
transition: all 0.3s ease; |
|
|
|
|
|
|
|
&:hover { |
|
|
|
background: #c0392b; |
|
|
|
transform: scale(1.1); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.modal-body { |
|
|
|
padding: 30px; |
|
|
|
|
|
|
|
h4 { |
|
|
|
color: #2c3e50; |
|
|
|
margin-bottom: 15px; |
|
|
|
font-weight: 600; |
|
|
|
} |
|
|
|
|
|
|
|
.review-content p { |
|
|
|
color: #34495e; |
|
|
|
line-height: 1.6; |
|
|
|
margin-bottom: 30px; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.chat-screenshots { |
|
|
|
margin-bottom: 30px; |
|
|
|
|
|
|
|
.screenshots-grid { |
|
|
|
display: grid; |
|
|
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); |
|
|
|
gap: 20px; |
|
|
|
margin-top: 20px; |
|
|
|
} |
|
|
|
|
|
|
|
.screenshot-full { |
|
|
|
position: relative; |
|
|
|
border-radius: 12px; |
|
|
|
overflow: hidden; |
|
|
|
cursor: pointer; |
|
|
|
border: 2px solid #e9ecef; |
|
|
|
transition: all 0.3s ease; |
|
|
|
|
|
|
|
&:hover { |
|
|
|
transform: scale(1.02); |
|
|
|
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15); |
|
|
|
} |
|
|
|
|
|
|
|
img { |
|
|
|
width: 100%; |
|
|
|
height: auto; |
|
|
|
display: block; |
|
|
|
} |
|
|
|
|
|
|
|
.screenshot-overlay { |
|
|
|
position: absolute; |
|
|
|
top: 0; |
|
|
|
left: 0; |
|
|
|
right: 0; |
|
|
|
bottom: 0; |
|
|
|
background: rgba(0, 0, 0, 0.5); |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
opacity: 0; |
|
|
|
transition: opacity 0.3s ease; |
|
|
|
|
|
|
|
i { |
|
|
|
color: white; |
|
|
|
font-size: 1.5rem; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
&:hover .screenshot-overlay { |
|
|
|
opacity: 1; |
|
|
|
} |
|
|
|
|
|
|
|
.screenshot-desc { |
|
|
|
position: absolute; |
|
|
|
bottom: 0; |
|
|
|
left: 0; |
|
|
|
right: 0; |
|
|
|
background: linear-gradient(transparent, rgba(0, 0, 0, 0.8)); |
|
|
|
color: white; |
|
|
|
padding: 15px 10px 10px; |
|
|
|
font-size: 0.9rem; |
|
|
|
text-align: center; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.review-meta { |
|
|
|
display: flex; |
|
|
|
justify-content: space-between; |
|
|
|
align-items: center; |
|
|
|
padding-top: 20px; |
|
|
|
border-top: 1px solid #e9ecef; |
|
|
|
|
|
|
|
.tags { |
|
|
|
display: flex; |
|
|
|
flex-wrap: wrap; |
|
|
|
gap: 8px; |
|
|
|
} |
|
|
|
|
|
|
|
.review-date { |
|
|
|
color: #7f8c8d; |
|
|
|
font-size: 0.9rem; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 图片查看器 |
|
|
|
.image-viewer-overlay { |
|
|
|
position: fixed; |
|
|
|
top: 0; |
|
|
|
left: 0; |
|
|
|
right: 0; |
|
|
|
bottom: 0; |
|
|
|
background: rgba(0, 0, 0, 0.95); |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
z-index: 1100; |
|
|
|
padding: 20px; |
|
|
|
} |
|
|
|
|
|
|
|
.image-viewer-content { |
|
|
|
position: relative; |
|
|
|
max-width: 90vw; |
|
|
|
max-height: 90vh; |
|
|
|
|
|
|
|
img { |
|
|
|
max-width: 100%; |
|
|
|
max-height: 100%; |
|
|
|
object-fit: contain; |
|
|
|
border-radius: 8px; |
|
|
|
} |
|
|
|
|
|
|
|
.close-btn { |
|
|
|
position: absolute; |
|
|
|
top: -50px; |
|
|
|
right: 0; |
|
|
|
width: 40px; |
|
|
|
height: 40px; |
|
|
|
border: none; |
|
|
|
background: #e74c3c; |
|
|
|
color: white; |
|
|
|
border-radius: 50%; |
|
|
|
cursor: pointer; |
|
|
|
transition: all 0.3s ease; |
|
|
|
|
|
|
|
&:hover { |
|
|
|
background: #c0392b; |
|
|
|
transform: scale(1.1); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 响应式设计 |
|
|
|
@media (max-width: 768px) { |
|
|
|
.customer-reviews { |
|
|
|
padding: 40px 0; |
|
|
|
} |
|
|
|
|
|
|
|
.reviews-header h2 { |
|
|
|
font-size: 2rem; |
|
|
|
} |
|
|
|
|
|
|
|
.reviews-track { |
|
|
|
gap: 20px; |
|
|
|
} |
|
|
|
|
|
|
|
.modal-content { |
|
|
|
margin: 10px; |
|
|
|
border-radius: 15px; |
|
|
|
} |
|
|
|
|
|
|
|
.modal-header, |
|
|
|
.modal-body { |
|
|
|
padding: 20px; |
|
|
|
} |
|
|
|
|
|
|
|
.chat-screenshots .screenshots-grid { |
|
|
|
grid-template-columns: 1fr; |
|
|
|
} |
|
|
|
|
|
|
|
.review-meta { |
|
|
|
flex-direction: column; |
|
|
|
align-items: flex-start; |
|
|
|
gap: 15px; |
|
|
|
} |
|
|
|
} |
|
|
|
</style> |