Files
akmon/pages/mall/merchant/index.uvue
2026-01-20 08:04:15 +08:00

678 lines
14 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- 商家端首页 - UTS Android 兼容 -->
<template>
<view class="merchant-container">
<!-- 头部导航 -->
<view class="header">
<view class="header-content">
<view class="shop-info">
<image :src="shopInfo.shop_logo || '/static/default-shop.png'" class="shop-logo" mode="aspectFit" />
<view class="shop-details">
<text class="shop-name">{{ shopInfo.shop_name }}</text>
<view class="shop-stats">
<text class="stat-item">评分: {{ shopInfo.rating }}</text>
<text class="stat-item">销量: {{ shopInfo.total_sales }}</text>
</view>
</view>
</view>
<view class="header-actions">
<text class="action-btn" @click="goToMessages">消息</text>
<text class="action-btn" @click="goToSettings">设置</text>
</view>
</view>
</view>
<!-- 数据概览 -->
<view class="overview-section">
<text class="section-title">今日数据</text>
<view class="overview-grid">
<view class="overview-item">
<text class="overview-value">{{ todayStats.orders }}</text>
<text class="overview-label">订单数</text>
</view>
<view class="overview-item">
<text class="overview-value">¥{{ todayStats.sales }}</text>
<text class="overview-label">销售额</text>
</view>
<view class="overview-item">
<text class="overview-value">{{ todayStats.visitors }}</text>
<text class="overview-label">访客数</text>
</view>
<view class="overview-item">
<text class="overview-value">{{ todayStats.conversion }}</text>
<text class="overview-label">转化率</text>
</view>
</view>
</view>
<!-- 待处理事项 -->
<view class="pending-section">
<text class="section-title">待处理</text>
<view class="pending-list">
<view class="pending-item" @click="goToOrders('pending')">
<text class="pending-icon">📦</text>
<text class="pending-text">待发货订单</text>
<text class="pending-count">{{ pendingCounts.pending_shipment }}</text>
</view>
<view class="pending-item" @click="goToOrders('refund')">
<text class="pending-icon">↩️</text>
<text class="pending-text">退款处理</text>
<text class="pending-count">{{ pendingCounts.refund_requests }}</text>
</view>
<view class="pending-item" @click="goToProducts('low_stock')">
<text class="pending-icon">⚠️</text>
<text class="pending-text">库存预警</text>
<text class="pending-count">{{ pendingCounts.low_stock }}</text>
</view>
<view class="pending-item" @click="goToReviews">
<text class="pending-icon">💬</text>
<text class="pending-text">待回复评价</text>
<text class="pending-count">{{ pendingCounts.pending_reviews }}</text>
</view>
</view>
</view>
<!-- 快捷功能 -->
<view class="shortcuts-section">
<text class="section-title">快捷功能</text>
<view class="shortcuts-grid">
<view class="shortcut-item" @click="goToProducts('add')">
<text class="shortcut-icon"></text>
<text class="shortcut-text">添加商品</text>
</view>
<view class="shortcut-item" @click="goToOrders('all')">
<text class="shortcut-icon">📋</text>
<text class="shortcut-text">订单管理</text>
</view>
<view class="shortcut-item" @click="goToProducts('manage')">
<text class="shortcut-icon">📦</text>
<text class="shortcut-text">商品管理</text>
</view>
<view class="shortcut-item" @click="goToPromotions">
<text class="shortcut-icon">🎯</text>
<text class="shortcut-text">营销活动</text>
</view>
<view class="shortcut-item" @click="goToStatistics">
<text class="shortcut-icon">📊</text>
<text class="shortcut-text">数据统计</text>
</view>
<view class="shortcut-item" @click="goToFinance">
<text class="shortcut-icon">💰</text>
<text class="shortcut-text">财务结算</text>
</view>
</view>
</view>
<!-- 最新订单 -->
<view class="recent-orders-section">
<view class="section-header">
<text class="section-title">最新订单</text>
<text class="section-more" @click="goToOrders('all')">查看全部</text>
</view>
<view class="orders-list">
<view v-for="order in recentOrders" :key="order.id" class="order-item" @click="goToOrderDetail(order.id)">
<view class="order-header">
<text class="order-no">{{ order.order_no }}</text>
<text class="order-status" :class="getOrderStatusClass(order.status)">{{ getOrderStatusText(order.status) }}</text>
</view>
<view class="order-products">
<view v-for="item in order.items" :key="item.id" class="product-item">
<image :src="item.product_image || '/static/default-product.png'" class="product-image" mode="aspectFit" />
<view class="product-info">
<text class="product-name">{{ item.product_name }}</text>
<text class="product-spec">{{ item.sku_specifications || '' }}</text>
<text class="product-price">¥{{ item.price }} × {{ item.quantity }}</text>
</view>
</view>
</view>
<view class="order-footer">
<text class="order-amount">合计: ¥{{ order.actual_amount }}</text>
<text class="order-time">{{ formatTime(order.created_at) }}</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script lang="uts">
import type {
MerchantType,
OrderType,
OrderItemType,
ProductType
} from '@/types/mall-types.uts'
type TodayStatsType = {
orders: number
sales: string
visitors: number
conversion: string
}
type PendingCountsType = {
pending_shipment: number
refund_requests: number
low_stock: number
pending_reviews: number
}
type RecentOrderType = {
id: string
order_no: string
status: number
actual_amount: number
created_at: string
items: Array<OrderItemType & { product_image: string }>
}
export default {
data() {
return {
shopInfo: {
id: '',
user_id: '',
shop_name: '我的店铺',
shop_logo: '',
shop_banner: '',
shop_description: '',
contact_name: '',
contact_phone: '',
shop_status: 1,
rating: 5.0,
total_sales: 0,
created_at: ''
} as MerchantType,
todayStats: {
orders: 0,
sales: '0.00',
visitors: 0,
conversion: '0.00%'
} as TodayStatsType,
pendingCounts: {
pending_shipment: 0,
refund_requests: 0,
low_stock: 0,
pending_reviews: 0
} as PendingCountsType,
recentOrders: [] as Array<RecentOrderType>
}
},
onLoad() {
this.loadMerchantData()
this.loadTodayStats()
this.loadPendingCounts()
this.loadRecentOrders()
},
methods: {
// 加载商家信息
loadMerchantData() {
// TODO: 调用API获取商家信息
console.log('Loading merchant data...')
},
// 加载今日统计
loadTodayStats() {
// TODO: 调用API获取今日统计数据
this.todayStats = {
orders: 25,
sales: '8,350.00',
visitors: 156,
conversion: '16.03%'
}
},
// 加载待处理数量
loadPendingCounts() {
// TODO: 调用API获取待处理数量
this.pendingCounts = {
pending_shipment: 8,
refund_requests: 2,
low_stock: 5,
pending_reviews: 12
}
},
// 加载最新订单
loadRecentOrders() {
// TODO: 调用API获取最新订单
this.recentOrders = [
{
id: '1',
order_no: 'M202501081234',
status: 2,
actual_amount: 299.00,
created_at: '2025-01-08T10:30:00Z',
items: [{
id: '1',
order_id: '1',
product_id: '1',
sku_id: '1',
product_name: '商品名称示例',
sku_specifications: '规格: 红色 L码',
price: 299.00,
quantity: 1,
total_amount: 299.00,
created_at: '2025-01-08T10:30:00Z',
product_image: '/static/product1.jpg'
}]
}
]
},
// 获取订单状态样式
getOrderStatusClass(status: number): string {
switch (status) {
case 1: return 'status-pending'
case 2: return 'status-paid'
case 3: return 'status-shipped'
case 4: return 'status-delivered'
case 5: return 'status-completed'
default: return 'status-default'
}
},
// 获取订单状态文本
getOrderStatusText(status: number): string {
switch (status) {
case 1: return '待付款'
case 2: return '待发货'
case 3: return '已发货'
case 4: return '已收货'
case 5: return '已完成'
default: return '未知状态'
}
},
// 格式化时间
formatTime(timeStr: string): string {
const date = new Date(timeStr)
const now = new Date()
const diff = now.getTime() - date.getTime()
const minutes = Math.floor(diff / (1000 * 60))
if (minutes < 60) {
return `${minutes}分钟前`
} else if (minutes < 1440) {
return `${Math.floor(minutes / 60)}小时前`
} else {
return `${Math.floor(minutes / 1440)}天前`
}
},
// 导航方法
goToMessages() {
uni.navigateTo({
url: '/pages/mall/merchant/messages'
})
},
goToSettings() {
uni.navigateTo({
url: '/pages/mall/merchant/settings'
})
},
goToOrders(type: string) {
uni.navigateTo({
url: `/pages/mall/merchant/orders?type=${type}`
})
},
goToProducts(type: string) {
uni.navigateTo({
url: `/pages/mall/merchant/products?type=${type}`
})
},
goToPromotions() {
uni.navigateTo({
url: '/pages/mall/merchant/promotions'
})
},
goToStatistics() {
uni.navigateTo({
url: '/pages/mall/merchant/statistics'
})
},
goToFinance() {
uni.navigateTo({
url: '/pages/mall/merchant/finance'
})
},
goToReviews() {
uni.navigateTo({
url: '/pages/mall/merchant/reviews'
})
},
goToOrderDetail(orderId: string) {
uni.navigateTo({
url: `/pages/mall/merchant/order-detail?id=${orderId}`
})
}
}
}
</script>
<style>
.merchant-container {
background-color: #f5f5f5;
min-height: 100vh;
}
.header {
background-color: #fff;
padding: 20rpx 30rpx;
border-bottom: 1rpx solid #e5e5e5;
}
.header-content {
display: flex;
justify-content: space-between;
align-items: center;
}
.shop-info {
display: flex;
align-items: center;
}
.shop-logo {
width: 80rpx;
height: 80rpx;
border-radius: 40rpx;
margin-right: 20rpx;
}
.shop-details {
display: flex;
flex-direction: column;
}
.shop-name {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 10rpx;
}
.shop-stats {
display: flex;
}
.stat-item {
font-size: 24rpx;
color: #666;
margin-right: 20rpx;
}
.header-actions {
display: flex;
}
.action-btn {
font-size: 28rpx;
color: #007AFF;
margin-left: 30rpx;
}
.overview-section {
background-color: #fff;
margin: 20rpx;
padding: 30rpx;
border-radius: 16rpx;
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 30rpx;
}
.overview-grid {
display: flex;
justify-content: space-between;
}
.overview-item {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
}
.overview-value {
font-size: 36rpx;
font-weight: bold;
color: #FF6B35;
margin-bottom: 10rpx;
}
.overview-label {
font-size: 24rpx;
color: #666;
}
.pending-section {
background-color: #fff;
margin: 20rpx;
padding: 30rpx;
border-radius: 16rpx;
}
.pending-list {
display: flex;
flex-direction: column;
}
.pending-item {
display: flex;
align-items: center;
padding: 20rpx 0;
border-bottom: 1rpx solid #f0f0f0;
}
.pending-item:last-child {
border-bottom: none;
}
.pending-icon {
font-size: 32rpx;
margin-right: 20rpx;
width: 40rpx;
}
.pending-text {
font-size: 28rpx;
color: #333;
flex: 1;
}
.pending-count {
font-size: 28rpx;
color: #FF6B35;
font-weight: bold;
}
.shortcuts-section {
background-color: #fff;
margin: 20rpx;
padding: 30rpx;
border-radius: 16rpx;
}
.shortcuts-grid {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.shortcut-item {
display: flex;
flex-direction: column;
align-items: center;
width: 30%;
margin-bottom: 30rpx;
}
.shortcut-icon {
font-size: 48rpx;
margin-bottom: 15rpx;
}
.shortcut-text {
font-size: 24rpx;
color: #333;
text-align: center;
}
.recent-orders-section {
background-color: #fff;
margin: 20rpx;
padding: 30rpx;
border-radius: 16rpx;
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30rpx;
}
.section-more {
font-size: 24rpx;
color: #007AFF;
}
.orders-list {
display: flex;
flex-direction: column;
}
.order-item {
border: 1rpx solid #e5e5e5;
border-radius: 12rpx;
padding: 20rpx;
margin-bottom: 20rpx;
}
.order-item:last-child {
margin-bottom: 0;
}
.order-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15rpx;
}
.order-no {
font-size: 28rpx;
color: #333;
font-weight: bold;
}
.order-status {
font-size: 24rpx;
padding: 8rpx 16rpx;
border-radius: 20rpx;
}
.status-pending {
background-color: #FFF3CD;
color: #856404;
}
.status-paid {
background-color: #D4EDDA;
color: #155724;
}
.status-shipped {
background-color: #CCE5FF;
color: #004085;
}
.status-delivered {
background-color: #E2E3E5;
color: #383D41;
}
.status-completed {
background-color: #D1ECF1;
color: #0C5460;
}
.order-products {
margin-bottom: 15rpx;
}
.product-item {
display: flex;
align-items: center;
margin-bottom: 10rpx;
}
.product-item:last-child {
margin-bottom: 0;
}
.product-image {
width: 80rpx;
height: 80rpx;
border-radius: 8rpx;
margin-right: 15rpx;
}
.product-info {
display: flex;
flex-direction: column;
flex: 1;
}
.product-name {
font-size: 26rpx;
color: #333;
margin-bottom: 5rpx;
}
.product-spec {
font-size: 22rpx;
color: #999;
margin-bottom: 5rpx;
}
.product-price {
font-size: 24rpx;
color: #666;
}
.order-footer {
display: flex;
justify-content: space-between;
align-items: center;
}
.order-amount {
font-size: 28rpx;
color: #FF6B35;
font-weight: bold;
}
.order-time {
font-size: 22rpx;
color: #999;
}
</style>