feat: 新增订单查询页面,按客户姓名查询
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Agent
2026-03-28 03:25:22 +00:00
parent 5d2e13df79
commit 848423faa3
3 changed files with 271 additions and 0 deletions

View File

@@ -48,6 +48,12 @@
"navigationBarTitleText": "订单列表" "navigationBarTitleText": "订单列表"
} }
}, },
{
"path": "pages/order/search",
"style": {
"navigationBarTitleText": "订单查询"
}
},
{ {
"path": "pages/stock/list", "path": "pages/stock/list",
"style": { "style": {

View File

@@ -70,6 +70,10 @@
<Icon name="order" :size="48" color="#fff" /> <Icon name="order" :size="48" color="#fff" />
<text class="menu-card-title">订单列表</text> <text class="menu-card-title">订单列表</text>
</view> </view>
<view class="menu-card" @click="goTo('/pages/order/search')">
<Icon name="search" :size="48" color="#fff" />
<text class="menu-card-title">订单查询</text>
</view>
<view class="menu-card" @click="goStock()"> <view class="menu-card" @click="goStock()">
<Icon name="stock" :size="48" color="#fff" /> <Icon name="stock" :size="48" color="#fff" />
<text class="menu-card-title">库存管理</text> <text class="menu-card-title">库存管理</text>

261
src/pages/order/search.vue Normal file
View File

@@ -0,0 +1,261 @@
<template>
<view class="page">
<!-- 搜索栏 -->
<view class="search-section">
<view class="search-bar">
<text class="search-icon">🔍</text>
<input
class="search-input"
v-model="customerName"
placeholder="请输入客户姓名"
placeholder-class="placeholder"
@confirm="searchOrders"
/>
</view>
<button class="search-btn" @click="searchOrders">查询</button>
</view>
<!-- 搜索结果 -->
<scroll-view scroll-y class="result-section">
<view v-if="loading" class="loading">加载中...</view>
<view v-else-if="orders.length === 0 && searched" class="empty">
<text class="empty-icon">📋</text>
<text class="empty-text">未找到相关订单</text>
</view>
<view v-else-if="orders.length > 0" class="order-list">
<view
v-for="order in orders"
:key="order.orderId"
class="order-card"
@click="viewDetail(order)"
>
<view class="card-header">
<text class="order-no">{{ order.orderNo }}</text>
<text class="order-status" :class="getStatusClass(order.status)">
{{ getStatusText(order.status) }}
</text>
</view>
<view class="card-body">
<text class="customer-name">👤 {{ order.customerName || '散客' }}</text>
<text class="order-amount">实付: ¥{{ order.actualAmount }}</text>
<text class="order-time">{{ formatTime(order.createdAt) }}</text>
</view>
</view>
</view>
<view v-else class="hint">
<text>请输入客户姓名进行查询</text>
</view>
</scroll-view>
</view>
</template>
<script>
import orderApi from '@/api/order'
export default {
data() {
return {
customerName: '',
orders: [],
loading: false,
searched: false
}
},
methods: {
async searchOrders() {
if (!this.customerName.trim()) {
uni.showToast({ title: '请输入客户姓名', icon: 'none' })
return
}
this.loading = true
this.searched = true
this.orders = []
try {
const res = await orderApi.getOrders({
customerName: this.customerName.trim(),
page: 1,
pageSize: 50
})
this.orders = res.records || []
} catch (e) {
uni.showToast({ title: '查询失败', icon: 'none' })
} finally {
this.loading = false
}
},
getStatusClass(status) {
const map = {
1: 'status-success',
2: 'status-cancel',
3: 'status-refunding',
4: 'status-refunded'
}
return map[status] || ''
},
getStatusText(status) {
const map = {
0: '未完成',
1: '已完成',
2: '已取消',
3: '退款中',
4: '已退款'
}
return map[status] || '未知'
},
formatTime(time) {
if (!time) return ''
return time.substring(0, 16).replace('T', ' ')
},
viewDetail(order) {
uni.showModal({
title: '订单详情',
content: `订单号: ${order.orderNo}\n客户: ${order.customerName || '散客'}\n原价: ¥${order.totalAmount}\n优惠: ¥${order.discountAmount}\n实付: ¥${order.actualAmount}\n状态: ${this.getStatusText(order.status)}`,
showCancel: false
})
}
}
}
</script>
<style>
.page {
min-height: 100vh;
background: #f8f9fa;
}
.search-section {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 30rpx;
display: flex;
align-items: center;
}
.search-bar {
flex: 1;
display: flex;
align-items: center;
background: rgba(255, 255, 255, 0.95);
border-radius: 50rpx;
padding: 0 30rpx;
height: 80rpx;
}
.search-icon {
font-size: 32rpx;
margin-right: 16rpx;
}
.search-input {
flex: 1;
font-size: 28rpx;
color: #333;
}
.placeholder {
color: #999;
}
.search-btn {
margin-left: 20rpx;
background: #fff;
color: #667eea;
font-size: 28rpx;
padding: 16rpx 32rpx;
border-radius: 40rpx;
border: none;
}
.result-section {
height: calc(100vh - 180rpx);
padding: 20rpx;
}
.loading, .hint {
text-align: center;
color: #999;
padding: 60rpx;
}
.empty {
display: flex;
flex-direction: column;
align-items: center;
padding: 100rpx;
}
.empty-icon {
font-size: 80rpx;
margin-bottom: 20rpx;
}
.empty-text {
color: #999;
font-size: 28rpx;
}
.order-list {
display: flex;
flex-direction: column;
}
.order-card {
background: #fff;
border-radius: 16rpx;
padding: 24rpx;
margin-bottom: 20rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.06);
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16rpx;
}
.order-no {
font-size: 28rpx;
font-weight: bold;
color: #333;
}
.order-status {
font-size: 24rpx;
padding: 4rpx 16rpx;
border-radius: 20rpx;
}
.status-success {
background: #e6f7e6;
color: #52c41a;
}
.status-cancel {
background: #fff1f0;
color: #ff4d4f;
}
.card-body {
display: flex;
flex-direction: column;
gap: 8rpx;
}
.customer-name {
font-size: 26rpx;
color: #666;
}
.order-amount {
font-size: 30rpx;
font-weight: bold;
color: #ff4d4f;
}
.order-time {
font-size: 24rpx;
color: #999;
}
</style>