Files
jurong_circle_frontdesk/src/views/Orders.vue

1238 lines
27 KiB
Vue
Raw Normal View History

2025-07-26 15:35:53 +08:00
<template>
<div class="orders-page">
<!-- 导航栏 -->
<nav class="navbar">
<div class="nav-center">
<h1 class="nav-title">我的订单</h1>
</div>
<div class="nav-right">
<el-button
type="text"
@click="$router.push('/shop')"
class="shop-btn"
>
<el-icon><ShoppingBag /></el-icon>
商城
</el-button>
</div>
</nav>
<!-- 订单状态筛选 -->
<div class="filter-tabs">
<div class="tabs-container">
<div
v-for="tab in statusTabs"
:key="tab.value"
:class="['tab-item', { active: selectedStatus === tab.value }]"
@click="selectStatus(tab.value)"
>
<span>{{ tab.label }}</span>
<el-badge
v-if="tab.count > 0"
:value="tab.count"
class="tab-badge"
/>
</div>
</div>
</div>
<!-- 订单列表 -->
<div class="orders-content">
<div v-loading="loading" class="orders-list">
<div v-if="filteredOrders.length === 0" class="empty-state">
<el-icon size="60"><Box /></el-icon>
<p>{{ getEmptyText() }}</p>
<el-button type="primary" @click="$router.push('/shop')">
去购物
</el-button>
</div>
2025-09-01 13:39:34 +08:00
<div v-else class="orders-container">
2025-07-26 15:35:53 +08:00
<div v-for="order in filteredOrders" :key="order.id" class="order-card">
<!-- 订单头部 -->
<div class="order-header">
<div class="order-info">
<span class="order-number">订单号{{ order.orderNumber }}</span>
<span class="order-date">{{ formatDate(order.createdAt) }}</span>
</div>
<div class="order-status">
<el-tag :type="getStatusType(order.status)">{{ getStatusText(order.status) }}</el-tag>
</div>
</div>
<!-- 订单商品 -->
<div class="order-items">
<div
v-for="item in order.items"
:key="item.id"
class="order-item"
@click="goToProduct(item.productId)"
>
<img :src="item.product.image" :alt="item.product.name" class="item-image" />
<div class="item-info">
<h4 class="item-name">{{ item.product.name }}</h4>
<p class="item-desc">{{ truncateText(item.product.description, 40) }}</p>
<div class="item-price">
2025-09-02 11:41:20 +08:00
<div class="item-price-container">
<div class="item-main-price">
2025-09-03 11:00:08 +08:00
<img src='/imgs/profile/rongdou.png' alt="融豆" class="item-rongdou-icon" />
2025-09-02 11:41:20 +08:00
<span class="item-rongdou-price">{{ item.rongdouPrice }}</span>
</div>
<div class="item-sub-price">
<el-icon class="item-points-icon"><Coin /></el-icon>
<span class="item-points-price">{{ item.points }}</span>
</div>
2025-08-29 16:58:00 +08:00
</div>
2025-07-26 15:35:53 +08:00
<span class="quantity">x{{ item.quantity }}</span>
</div>
</div>
</div>
</div>
<!-- 订单总计 -->
<div class="order-total">
<div class="total-info">
2025-08-29 16:58:00 +08:00
<span>{{ order.totalQuantity }}件商品</span>
<div class="total-price">
<span>总计</span>
<div class="total-price-group">
2025-09-02 11:41:20 +08:00
<span class="total-rongdou">
2025-09-03 11:00:08 +08:00
<img src='/imgs/profile/rongdou.png' alt="融豆" class="total-rongdou-icon" />
2025-09-02 11:41:20 +08:00
{{ order.totalRongdou }}
2025-08-29 16:58:00 +08:00
</span>
</div>
2025-07-26 15:35:53 +08:00
</div>
</div>
2025-08-29 16:58:00 +08:00
</div>
2025-07-26 15:35:53 +08:00
<!-- 订单操作 -->
<div class="order-actions">
2025-09-01 13:39:34 +08:00
<el-button
2025-09-01 17:42:19 +08:00
v-if="order.status === 'pre_order'"
2025-09-01 13:39:34 +08:00
type="primary"
size="small"
@click="goToPay(order.id)"
>
立即支付
</el-button>
2025-09-05 11:40:34 +08:00
<el-button
v-if="order.status === 'pre_order'"
size="small"
@click="cancelOrder(order.id)"
>
取消订单
</el-button>
2025-07-26 15:35:53 +08:00
<el-button
v-if="order.status === 'pending'"
size="small"
@click="cancelOrder(order.id)"
>
取消订单
</el-button>
<el-button
v-if="order.status === 'shipped'"
type="primary"
size="small"
@click="confirmReceive(order.id)"
>
确认收货
</el-button>
<el-button
v-if="order.status === 'completed'"
size="small"
@click="showReviewDialog(order)"
>
评价
</el-button>
<el-button
size="small"
@click="viewOrderDetail(order.id)"
>
查看详情
</el-button>
</div>
</div>
</div>
</div>
<!-- 加载更多 -->
<div v-if="hasMore" class="load-more">
<el-button @click="loadMore" :loading="loadingMore">
加载更多
</el-button>
</div>
</div>
<!-- 评价对话框 -->
<el-dialog
v-model="showReview"
title="商品评价"
width="90%"
:before-close="handleReviewClose"
>
<div v-if="reviewOrder" class="review-form">
<div v-for="item in reviewOrder.items" :key="item.id" class="review-item">
<div class="review-product">
<img :src="item.product.image" :alt="item.product.name" class="product-image" />
<div class="product-info">
<h4>{{ item.product.name }}</h4>
<p>{{ item.product.description }}</p>
</div>
</div>
<div class="review-rating">
<span class="rating-label">评分</span>
<el-rate v-model="item.rating" size="large" />
</div>
<div class="review-content">
<el-input
v-model="item.reviewContent"
type="textarea"
:rows="3"
placeholder="请分享您的使用体验..."
maxlength="200"
show-word-limit
/>
</div>
<div class="review-images">
<el-upload
v-model:file-list="item.reviewImages"
action="#"
list-type="picture-card"
:auto-upload="false"
:limit="3"
>
<el-icon><Plus /></el-icon>
</el-upload>
</div>
</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="showReview = false">取消</el-button>
<el-button type="primary" @click="submitReview" :loading="submittingReview">
提交评价
</el-button>
</span>
</template>
</el-dialog>
<!-- 订单详情对话框 -->
<el-dialog
v-model="showOrderDetail"
title="订单详情"
width="90%"
>
<div v-if="orderDetail" class="order-detail">
<div class="detail-section">
<h4>订单信息</h4>
<div class="detail-item">
<span class="label">订单号</span>
<span class="value">{{ orderDetail.orderNumber }}</span>
</div>
2025-08-29 16:58:00 +08:00
<div class="detail-item">
<span class="label">用户名</span>
<span class="value">{{ orderDetail.username || '未知用户' }}</span>
</div>
2025-07-26 15:35:53 +08:00
<div class="detail-item">
<span class="label">下单时间</span>
<span class="value">{{ formatDateTime(orderDetail.createdAt) }}</span>
</div>
2025-08-29 16:58:00 +08:00
<div class="detail-item">
<span class="label">更新时间</span>
<span class="value">{{ formatDateTime(orderDetail.updatedAt) }}</span>
</div>
2025-07-26 15:35:53 +08:00
<div class="detail-item">
<span class="label">订单状态</span>
<span class="value">
<el-tag :type="getStatusType(orderDetail.status)">
{{ getStatusText(orderDetail.status) }}
</el-tag>
</span>
</div>
</div>
<div class="detail-section">
<h4>商品信息</h4>
<div v-for="item in orderDetail.items" :key="item.id" class="detail-product">
<img :src="item.product.image" :alt="item.product.name" />
<div class="product-info">
<h5>{{ item.product.name }}</h5>
<p>{{ item.product.description }}</p>
2025-08-29 16:58:00 +08:00
<p v-if="item.specInfo" class="spec-info">规格{{ item.specInfo }}</p>
2025-07-26 15:35:53 +08:00
<div class="product-price">
2025-09-02 11:41:20 +08:00
<div class="detail-item-price-container">
<div class="detail-item-main-price">
2025-09-03 11:00:08 +08:00
<img src='/imgs/profile/rongdou.png' alt="融豆" class="detail-rongdou-icon" />
2025-09-02 11:41:20 +08:00
<span class="detail-rongdou-price">{{ item.rongdouPrice }}</span>
</div>
<div class="detail-item-sub-price">
<el-icon class="detail-points-icon"><Coin /></el-icon>
<span class="detail-points-price">{{ item.points }}</span>
</div>
2025-08-29 16:58:00 +08:00
</div>
<span class="quantity-text">x {{ item.quantity }}</span>
2025-07-26 15:35:53 +08:00
</div>
</div>
</div>
</div>
<div class="detail-section">
<h4>配送信息</h4>
<div class="detail-item">
<span class="label">物流信息</span>
<span class="value">{{ orderDetail.trackingNumber || '暂无' }}</span>
</div>
</div>
<div class="detail-section">
<h4>费用明细</h4>
<div class="detail-item">
<span class="label">商品总计</span>
2025-08-29 16:58:00 +08:00
<div class="value">
<span class="detail-price-group">
2025-09-03 11:00:08 +08:00
<img src='/imgs/profile/rongdou.png' alt="融豆" class="cost-rongdou-icon" />
2025-09-02 11:41:20 +08:00
<span>{{ orderDetail.totalRongdou }}</span>
2025-08-29 16:58:00 +08:00
</span>
</div>
2025-07-26 15:35:53 +08:00
</div>
<div class="detail-item total">
2025-08-29 16:58:00 +08:00
<span class="label">实付</span>
<div class="value">
<span class="detail-price-group">
2025-09-03 11:00:08 +08:00
<img src='/imgs/profile/rongdou.png' alt="融豆" class="cost-rongdou-icon" />
2025-09-02 11:41:20 +08:00
<span>{{ orderDetail.totalRongdou }}</span>
2025-08-29 16:58:00 +08:00
</span>
</div>
2025-07-26 15:35:53 +08:00
</div>
</div>
</div>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { useUserStore } from '@/stores/user'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
ArrowLeft,
ShoppingBag,
Box,
Coin,
Plus
} from '@element-plus/icons-vue'
import api from '@/utils/api'
2025-09-02 17:05:49 +08:00
import { getImageUrl } from '@/config'
2025-07-26 15:35:53 +08:00
const router = useRouter()
const userStore = useUserStore()
// 响应式数据
const loading = ref(false)
const loadingMore = ref(false)
const selectedStatus = ref('all')
const orders = ref([])
const page = ref(1)
const hasMore = ref(true)
const showReview = ref(false)
const showOrderDetail = ref(false)
const reviewOrder = ref(null)
const orderDetail = ref(null)
const submittingReview = ref(false)
// 状态标签
const statusTabs = ref([
{ label: '全部', value: 'all', count: 0 },
2025-09-02 13:56:09 +08:00
{ label: '待发货', value: 'pending', count: 0 },
{ label: '待支付', value: 'pre_order', count: 0 },
2025-07-26 15:35:53 +08:00
{ label: '已发货', value: 'shipped', count: 0 },
{ label: '已完成', value: 'completed', count: 0 },
{ label: '已取消', value: 'cancelled', count: 0 }
])
// 计算属性
const filteredOrders = computed(() => {
if (selectedStatus.value === 'all') {
return orders.value
}
return orders.value.filter(order => order.status === selectedStatus.value)
})
// 方法
const selectStatus = (status) => {
selectedStatus.value = status
}
const getEmptyText = () => {
const textMap = {
all: '暂无订单',
2025-09-01 17:42:19 +08:00
pending: '暂无待发货订单',
pre_order: '暂无待支付订单',
2025-07-26 15:35:53 +08:00
shipped: '暂无已发货订单',
completed: '暂无已完成订单',
cancelled: '暂无已取消订单'
}
return textMap[selectedStatus.value]
}
const getStatusType = (status) => {
const typeMap = {
pending: 'warning',
2025-09-01 17:42:19 +08:00
pre_order: 'warning',
2025-07-26 15:35:53 +08:00
shipped: 'primary',
completed: 'success',
cancelled: 'danger'
}
return typeMap[status] || 'info'
}
2025-08-29 16:58:00 +08:00
const mapOrderStatus = (backendStatus) => {
const statusMap = {
2025-09-01 17:42:19 +08:00
'pre_order': 'pre_order',
2025-08-29 16:58:00 +08:00
'pending': 'pending',
'shipped': 'shipped',
'completed': 'completed',
'cancelled': 'cancelled'
}
return statusMap[backendStatus] || 'pending'
}
2025-07-26 15:35:53 +08:00
const getStatusText = (status) => {
const textMap = {
2025-09-01 17:42:19 +08:00
pending: '待发货',
pre_order: '待支付',
2025-07-26 15:35:53 +08:00
shipped: '已发货',
completed: '已完成',
cancelled: '已取消'
}
return textMap[status] || '未知状态'
}
const formatDate = (date) => {
return new Date(date).toLocaleDateString('zh-CN')
}
const formatDateTime = (date) => {
return new Date(date).toLocaleString('zh-CN')
}
const truncateText = (text, maxLength) => {
if (text.length <= maxLength) return text
return text.substring(0, maxLength) + '...'
}
const goToProduct = (productId) => {
router.push(`/product/${productId}`)
}
2025-09-01 13:39:34 +08:00
const goToPay = (orderId) => {
router.push(`/pay/${orderId}`)
}
2025-07-26 15:35:53 +08:00
const cancelOrder = async (orderId) => {
try {
await ElMessageBox.confirm('确定要取消这个订单吗?', '确认取消', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
await api.put(`/orders/${orderId}/cancel`)
// 更新订单状态
const order = orders.value.find(o => o.id === orderId)
if (order) {
order.status = 'cancelled'
}
updateStatusCounts()
ElMessage.success('订单已取消')
} catch (error) {
if (error !== 'cancel') {
ElMessage.error('取消订单失败')
}
}
}
const confirmReceive = async (orderId) => {
try {
await ElMessageBox.confirm('确认已收到商品吗?', '确认收货', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'info'
})
2025-09-01 17:42:19 +08:00
await api.put(`/orders/${orderId}/confirm`)
2025-07-26 15:35:53 +08:00
// 更新订单状态
const order = orders.value.find(o => o.id === orderId)
if (order) {
order.status = 'completed'
}
updateStatusCounts()
ElMessage.success('确认收货成功')
} catch (error) {
if (error !== 'cancel') {
ElMessage.error('确认收货失败')
}
}
}
const showReviewDialog = (order) => {
reviewOrder.value = {
...order,
items: order.items.map(item => ({
...item,
rating: 5,
reviewContent: '',
reviewImages: []
}))
}
showReview.value = true
}
const handleReviewClose = () => {
reviewOrder.value = null
showReview.value = false
}
const submitReview = async () => {
try {
submittingReview.value = true
const reviewData = {
orderId: reviewOrder.value.id,
reviews: reviewOrder.value.items.map(item => ({
productId: item.productId,
rating: item.rating,
content: item.reviewContent,
images: item.reviewImages.map(img => img.url)
}))
}
await api.post('/reviews', reviewData)
showReview.value = false
ElMessage.success('评价提交成功')
} catch (error) {
ElMessage.error('评价提交失败')
} finally {
submittingReview.value = false
}
}
2025-08-29 16:58:00 +08:00
const viewOrderDetail = (orderId) => {
2025-07-26 15:35:53 +08:00
try {
2025-08-29 16:58:00 +08:00
console.log('正在查找订单详情订单ID:', orderId)
// 从已加载的订单列表中查找对应订单
const order = orders.value.find(o => o.id === orderId)
console.log('找到的订单数据:', order)
if (!order) {
ElMessage.error('未找到订单信息')
return
}
// 直接使用已映射的订单数据
orderDetail.value = {
id: order.id,
orderNumber: order.orderNumber,
createdAt: order.createdAt,
updatedAt: order.updatedAt || order.createdAt,
username: order.username || '未知用户',
status: order.status,
totalPoints: order.totalPoints,
totalRongdou: order.totalRongdou,
totalQuantity: order.totalQuantity,
items: order.items || [],
shippingAddress: order.shippingAddress || null,
trackingNumber: order.trackingNumber || null
}
console.log('设置的订单详情数据:', orderDetail.value)
2025-07-26 15:35:53 +08:00
showOrderDetail.value = true
} catch (error) {
2025-08-29 16:58:00 +08:00
console.error('查看订单详情失败:', error)
ElMessage.error(`查看订单详情失败: ${error.message || '未知错误'}`)
2025-07-26 15:35:53 +08:00
}
}
const getOrders = async (isLoadMore = false) => {
try {
if (!isLoadMore) {
loading.value = true
page.value = 1
} else {
loadingMore.value = true
}
2025-08-01 09:33:46 +08:00
const {data} = await api.get('/orders', {
2025-07-26 15:35:53 +08:00
params: {
page: page.value,
limit: 10
}
})
2025-08-01 09:33:46 +08:00
console.log(data,'response');
2025-07-26 15:35:53 +08:00
2025-08-29 16:58:00 +08:00
// 映射后端数据结构到前端需要的格式
const mappedOrders = data.data.orders.map(order => ({
id: order.id,
orderNumber: order.order_no,
createdAt: order.created_at,
updatedAt: order.updated_at,
username: order.username,
status: mapOrderStatus(order.status),
totalPoints: order.total_points,
totalRongdou: order.total_rongdou,
totalQuantity: order.items?.reduce((sum, item) => sum + item.quantity, 0) || 0,
items: order.items?.map(item => ({
id: item.id,
productId: item.product_id,
quantity: item.quantity,
points: item.points_price,
rongdouPrice: item.rongdou_price,
specInfo: item.spec_info,
product: {
name: item.product_name || '商品名称',
description: item.description || '商品描述',
image: item.image_url || '/imgs/loading.png'
}
})) || [],
shippingAddress: order.address || null,
trackingNumber: null
}))
2025-07-26 15:35:53 +08:00
if (isLoadMore) {
2025-08-29 16:58:00 +08:00
orders.value.push(...mappedOrders)
2025-07-26 15:35:53 +08:00
} else {
2025-08-29 16:58:00 +08:00
orders.value = mappedOrders
2025-07-26 15:35:53 +08:00
}
2025-08-29 16:58:00 +08:00
hasMore.value = data.data.pagination.page < data.data.pagination.pages
2025-07-26 15:35:53 +08:00
page.value++
updateStatusCounts()
} catch (error) {
ElMessage.error('获取订单列表失败')
} finally {
loading.value = false
loadingMore.value = false
}
}
const loadMore = () => {
getOrders(true)
}
const updateStatusCounts = () => {
const counts = {
all: orders.value.length,
pending: 0,
shipped: 0,
completed: 0,
cancelled: 0
}
orders.value.forEach(order => {
counts[order.status]++
})
statusTabs.value.forEach(tab => {
tab.count = counts[tab.value]
})
}
// 生命周期
onMounted(() => {
getOrders()
})
</script>
<style scoped>
.orders-page {
min-height: 100vh;
background-color: #f5f5f5;
}
.navbar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 16px;
height: 56px;
background: white;
border-bottom: 1px solid #eee;
position: sticky;
top: 0;
z-index: 100;
}
.nav-left,
.nav-right {
flex: 1;
}
.nav-right {
display: flex;
justify-content: flex-end;
}
.back-btn,
.shop-btn {
color: #409eff;
font-size: 14px;
}
.nav-title {
margin: 0;
font-size: 18px;
font-weight: 500;
color: #333;
}
.filter-tabs {
background: white;
border-bottom: 1px solid #eee;
padding: 0 16px;
}
.tabs-container {
display: flex;
overflow-x: auto;
}
.tab-item {
position: relative;
padding: 16px 20px;
color: #666;
font-size: 14px;
cursor: pointer;
white-space: nowrap;
border-bottom: 2px solid transparent;
transition: all 0.3s;
}
.tab-item.active {
color: #409eff;
border-bottom-color: #409eff;
}
.tab-badge {
position: absolute;
top: 8px;
right: 8px;
}
.orders-content {
padding: 16px;
}
.empty-state {
text-align: center;
padding: 60px 20px;
color: #999;
}
.orders-list {
display: flex;
flex-direction: column;
2025-09-01 13:39:34 +08:00
}
.orders-container {
display: flex;
flex-direction: column;
gap: 10px;
2025-07-26 15:35:53 +08:00
}
.order-card {
background: white;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.order-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px;
border-bottom: 1px solid #f5f5f5;
}
.order-info {
display: flex;
flex-direction: column;
gap: 4px;
}
.order-number {
font-size: 14px;
color: #333;
font-weight: 500;
}
.order-date {
font-size: 12px;
color: #999;
}
.order-items {
padding: 16px;
}
.order-item {
display: flex;
gap: 12px;
padding: 8px 0;
cursor: pointer;
transition: all 0.3s;
}
.order-item:hover {
background: #f8f9fa;
border-radius: 8px;
padding: 8px;
margin: 0 -8px;
}
.item-image {
width: 60px;
height: 60px;
border-radius: 8px;
object-fit: cover;
flex-shrink: 0;
}
.item-info {
flex: 1;
display: flex;
flex-direction: column;
gap: 4px;
}
.item-name {
margin: 0;
font-size: 14px;
color: #333;
font-weight: 500;
line-height: 1.4;
}
.item-desc {
margin: 0;
font-size: 12px;
color: #666;
line-height: 1.4;
}
.item-price {
display: flex;
justify-content: space-between;
align-items: center;
}
2025-08-29 16:58:00 +08:00
.price-group {
display: flex;
align-items: center;
gap: 4px;
}
2025-07-26 15:35:53 +08:00
.price {
display: flex;
align-items: center;
gap: 2px;
color: #ff6b35;
font-weight: 600;
font-size: 14px;
}
2025-08-29 16:58:00 +08:00
.plus-sign {
color: #999;
font-size: 12px;
margin: 0 2px;
}
.rongdou-icon {
width: 14px;
height: 14px;
object-fit: contain;
}
.detail-price-group {
display: flex;
align-items: center;
gap: 4px;
}
.detail-item-price-group {
display: flex;
align-items: center;
gap: 4px;
}
2025-07-26 15:35:53 +08:00
.quantity {
color: #999;
font-size: 12px;
}
.order-total {
padding: 16px;
border-top: 1px solid #f5f5f5;
border-bottom: 1px solid #f5f5f5;
}
.total-info {
display: flex;
justify-content: space-between;
align-items: center;
}
2025-08-29 16:58:00 +08:00
.total-price {
display: flex;
align-items: center;
gap: 8px;
}
.total-price-group {
display: flex;
align-items: center;
gap: 4px;
}
.total-points,
.total-rongdou {
2025-07-26 15:35:53 +08:00
display: flex;
align-items: center;
gap: 4px;
color: #ff6b35;
font-weight: 600;
font-size: 16px;
}
.order-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
padding: 16px;
}
.load-more {
text-align: center;
padding: 20px;
}
.review-form {
display: flex;
flex-direction: column;
gap: 24px;
}
.review-item {
border: 1px solid #eee;
border-radius: 8px;
padding: 16px;
}
.review-product {
display: flex;
gap: 12px;
margin-bottom: 16px;
}
.review-product .product-image {
width: 60px;
height: 60px;
border-radius: 8px;
object-fit: cover;
}
.review-product .product-info h4 {
margin: 0 0 4px 0;
font-size: 14px;
color: #333;
}
.review-product .product-info p {
margin: 0;
font-size: 12px;
color: #666;
}
.review-rating {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 16px;
}
.rating-label {
font-size: 14px;
color: #333;
}
.review-content {
margin-bottom: 16px;
}
.review-images {
margin-bottom: 16px;
}
.order-detail {
display: flex;
flex-direction: column;
gap: 24px;
}
.detail-section h4 {
margin: 0 0 16px 0;
font-size: 16px;
color: #333;
border-bottom: 1px solid #eee;
padding-bottom: 8px;
}
.detail-item {
display: flex;
justify-content: space-between;
padding: 8px 0;
border-bottom: 1px solid #f5f5f5;
}
.detail-item.total {
font-weight: 600;
color: #ff6b35;
border-bottom: none;
padding-top: 16px;
border-top: 1px solid #eee;
}
.detail-item .label {
color: #666;
font-size: 14px;
}
.detail-item .value {
color: #333;
font-size: 14px;
display: flex;
align-items: center;
gap: 4px;
}
.detail-product {
display: flex;
gap: 12px;
padding: 12px;
background: #f8f9fa;
border-radius: 8px;
margin-bottom: 8px;
}
.detail-product img {
width: 60px;
height: 60px;
border-radius: 8px;
object-fit: cover;
}
.detail-product .product-info h5 {
margin: 0 0 4px 0;
font-size: 14px;
color: #333;
}
.detail-product .product-info p {
margin: 0 0 8px 0;
font-size: 12px;
color: #666;
}
.detail-product .product-price {
2025-08-29 16:58:00 +08:00
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.detail-item-price-group {
2025-07-26 15:35:53 +08:00
display: flex;
align-items: center;
gap: 4px;
color: #ff6b35;
font-weight: 600;
font-size: 14px;
}
2025-09-02 11:41:20 +08:00
.detail-item-price-group img {
width: 12px !important;
height: 12px !important;
}
2025-08-29 16:58:00 +08:00
.quantity-text {
color: #999;
font-size: 12px;
}
.detail-price-group {
display: flex;
align-items: center;
gap: 4px;
color: #ff6b35;
font-weight: 600;
}
2025-09-02 11:41:20 +08:00
.detail-price-group img {
width: 14px !important;
height: 14px !important;
}
2025-08-29 16:58:00 +08:00
.spec-info {
font-size: 12px;
color: #666;
margin: 4px 0;
background: #f5f5f5;
padding: 2px 8px;
border-radius: 4px;
display: inline-block;
}
2025-09-02 11:41:20 +08:00
/* 商品价格显示样式 */
.item-price-container {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 2px;
margin-bottom: 4px;
}
.item-main-price {
display: flex;
align-items: center;
gap: 2px;
}
.item-rongdou-icon {
width: 12px;
height: 12px;
}
.item-rongdou-price {
font-size: 12px;
font-weight: 500;
color: #333;
}
.item-sub-price {
display: flex;
align-items: center;
gap: 2px;
}
.item-points-icon {
font-size: 10px;
color: #ffae00;
}
.item-points-price {
font-size: 10px;
color: #666;
}
/* 订单总计融豆图标样式 */
.total-rongdou-icon {
width: 14px;
height: 14px;
margin-right: 2px;
}
/* 订单详情商品价格样式 */
.detail-item-price-container {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 2px;
}
.detail-item-main-price {
display: flex;
align-items: center;
gap: 2px;
}
.detail-rongdou-icon {
width: 12px !important;
height: 12px !important;
}
.detail-item-price-container .detail-rongdou-icon {
width: 12px !important;
height: 12px !important;
}
.detail-rongdou-price {
font-size: 12px;
font-weight: 500;
color: #333;
}
.detail-item-sub-price {
display: flex;
align-items: center;
gap: 2px;
}
.detail-points-icon {
font-size: 10px;
color: #ffae00;
}
.detail-points-price {
font-size: 10px;
color: #666;
}
/* 费用明细融豆图标样式 */
.cost-rongdou-icon {
width: 14px !important;
height: 14px !important;
margin-right: 2px;
}
.detail-price-group .cost-rongdou-icon {
width: 14px !important;
height: 14px !important;
}
2025-07-26 15:35:53 +08:00
/* 响应式设计 */
@media (max-width: 480px) {
.order-header {
flex-direction: column;
align-items: flex-start;
gap: 8px;
}
.order-actions {
2025-09-05 11:40:34 +08:00
display: flex;
justify-content: flex-end;
gap: 6px;
padding: 12px 16px;
flex-wrap: nowrap;
}
.order-actions .el-button {
flex: 0 0 auto;
min-width: 70px;
font-size: 12px;
padding: 6px 12px;
2025-07-26 15:35:53 +08:00
}
.detail-item {
flex-direction: column;
gap: 4px;
}
}
</style>