修改订单页面,1.tab改为全部订单2.添加三个筛选项3。对接接口展示列表以及详情页面

master
zhaoxiaodong 2026-03-30 22:09:14 +08:00
parent 15ffbb22ed
commit fda0800205
4 changed files with 390 additions and 184 deletions

50
api/back.js Normal file
View File

@ -0,0 +1,50 @@
import request8081 from '@/api/product'
import apiUrl from '@/utils/api'
import { getToken } from '@/utils/auth'
// 专门用于8081端口的请求复用 product.js 中的 request8081 逻辑)
const request = config => {
config.header = config.header || {}
const token = getToken()
if (token) {
config.header['Authorization'] = 'Bearer ' + token
}
const requestUrl = apiUrl + config.url
return new Promise((resolve, reject) => {
uni.request({
method: config.method || 'GET',
timeout: 10000,
url: requestUrl,
data: config.data,
header: {
'Content-Type': 'application/json;charset=UTF-8',
...config.header
},
dataType: 'json'
}).then(response => {
let [error, res] = response
if (error) {
reject(new Error('后端接口连接异常'))
return
}
if (res.statusCode !== 200) {
reject(new Error(`HTTP异常: ${res.statusCode}`))
return
}
resolve(res.data)
}).catch(err => {
reject(err)
})
})
}
// 获取订单列表
export function getOrderList(data) {
return request({
url: '/mall/order/list',
method: 'POST',
data: data
})
}

View File

@ -1,222 +1,232 @@
<template> <template>
<view class="page-container"> <view class="page-container">
<!-- 顶部状态栏模拟原生手机状态栏 -->
<!-- 导航栏 --> <!-- 导航栏 -->
<view class="navbar"> <view class="navbar">
<view class="nav-tabs"> <view class="nav-tabs">
<view class="tab-item active">全部事件</view> <view class="tab-item active">全部订单</view>
<view class="tab-item">只看订单</view> <!-- <view class="tab-item">只看订单</view> -->
</view> </view>
</view> </view>
<!-- 搜索与筛选区 --> <!-- 搜索与筛选区 -->
<view class="search-section"> <view class="search-section">
<view class="search-box"> <view class="search-box">
<text class="search-icon">🔍</text> <!-- <text class="search-icon">🔍</text> -->
<input class="search-input" placeholder="稽查单/事件/订单/商品名/用户" />
<text class="split-icon"></text> <!-- 选择订单号 -->
<block v-if="filterType === 'orderNo'">
<input class="search-input" v-model="queryParams.orderNo" placeholder="请输入订单号" @confirm="handleSearch" />
</block>
<!-- 选择条码 -->
<block v-else-if="filterType === 'barcode'">
<input class="search-input" v-model="queryParams.productBarCode" placeholder="请输入条码" @confirm="handleSearch" />
</block>
<!-- 选择支付状态 -->
<block v-else-if="filterType === 'payStatus'">
<picker class="search-input picker-input" mode="selector" :range="payStatusOptions" range-key="label" @change="onPayStatusChange">
<view class="picker-text">
{{ currentPayStatusLabel || '请选择支付状态' }}
</view>
</picker>
</block>
<!-- 重置 -->
<text class="reset-icon" @click="handleReset"></text>
<!-- 点击弹出下拉单选框选择类型 -->
<text class="split-icon" @click="showFilterTypeSelector"></text>
</view> </view>
<view class="filter-btn"> <view class="filter-btn" @click="handleSearch">
<text class="filter-icon">🔍</text> <!-- <text class="filter-icon">🔍</text> -->
<text class="filter-text">筛选</text> <text class="filter-text">搜索</text>
</view> </view>
</view> </view>
<!-- 内容区 --> <!-- 内容区 -->
<view class="content"> <scroll-view scroll-y class="content" @scrolltolower="loadMore">
<view class="empty-card"> <block v-if="orderList.length > 0">
<!-- 订单列表展示 订单号支付状态支付金额支付时间 -->
<view class="order-item" v-for="(item, index) in orderList" :key="item.id" @click="goToDetail(item)">
<view class="order-header">
<text class="order-no">订单号{{ item.orderNo || '--' }}</text>
<text :class="['pay-status', item.payStatus === 2 ? 'status-success' : item.payStatus === 3 ? 'status-error' : 'status-warning']">
{{ getPayStatusText(item.payStatus) }}
</text>
</view>
<view class="order-body">
<view class="info-row">
<text class="info-label">支付金额</text>
<text class="info-value amount">¥{{ item.payAmount || '0.00' }}</text>
</view>
<view class="info-row">
<text class="info-label">支付时间</text>
<text class="info-value">{{ item.payTime || '--' }}</text>
</view>
</view>
</view>
</block>
<!-- 暂无数据状态 -->
<view class="empty-card" v-else>
<view class="empty-icon-wrapper"> <view class="empty-icon-wrapper">
<view class="empty-icon">📄</view> <view class="empty-icon">📄</view>
</view> </view>
<text class="empty-text">暂无数据</text> <text class="empty-text">暂无数据</text>
</view> </view>
</view> </scroll-view>
</view> </view>
</template> </template>
<script> <script>
import { getOrderList } from '@/api/back';
export default { export default {
data() {
return {
// orderNo(), barcode(), payStatus()
filterType: 'orderNo',
currentPayStatusLabel: '',
payStatusOptions: [
{ label: '未支付', value: 0 },
{ label: '支付中', value: 1 },
{ label: '已支付', value: 2 },
{ label: '支付失败', value: 3 },
{ label: '已退款', value: 4 }
],
queryParams: {
storeId: '2', // id
orderNo: '',
productBarCode: '',
payStatus: ''
},
orderList: []
};
},
onLoad() {
this.fetchOrderList();
},
methods: { methods: {
goBack() { goBack() {
uni.navigateBack(); uni.navigateBack();
},
// split-icon
showFilterTypeSelector() {
const types = ['orderNo', 'barcode', 'payStatus'];
const labels = ['订单号', '条码', '支付状态'];
const itemList = labels.map((label, i) => (types[i] === this.filterType ? '✓ ' : '') + label);
uni.showActionSheet({
itemList,
success: (res) => {
this.filterType = types[res.tapIndex];
//
this.queryParams.orderNo = '';
this.queryParams.productBarCode = '';
this.queryParams.payStatus = '';
this.currentPayStatusLabel = '';
}
});
},
onPayStatusChange(e) {
const index = e.detail.value;
const selectedOption = this.payStatusOptions[index];
this.currentPayStatusLabel = selectedOption.label;
this.queryParams.payStatus = selectedOption.value;
},
handleSearch() {
this.fetchOrderList();
},
handleReset() {
this.filterType = 'orderNo';
this.currentPayStatusLabel = '';
this.queryParams.orderNo = '';
this.queryParams.productBarCode = '';
this.queryParams.payStatus = '';
this.fetchOrderList();
},
getPayStatusText(status) {
const map = { 0: '未支付', 1: '支付中', 2: '已支付', 3: '支付失败', 4: '已退款' };
return map[status] ?? '未知状态';
},
//
fetchOrderList() {
uni.showLoading({ title: '加载中...' });
const data = { storeId: this.queryParams.storeId };
if (this.queryParams.orderNo) data.orderNo = this.queryParams.orderNo;
if (this.queryParams.productBarCode) data.productBarCode = this.queryParams.productBarCode;
if (this.queryParams.payStatus !== '') data.payStatus = this.queryParams.payStatus;
getOrderList(data).then(res => {
if (res.code === 200) {
this.orderList = res.data || [];
} else {
uni.showToast({ title: res.msg || '获取失败', icon: 'none' });
}
}).catch(err => {
uni.showToast({ title: '网络请求失败', icon: 'none' });
}).finally(() => {
uni.hideLoading();
});
},
loadMore() {
},
goToDetail(orderObj) {
const itemsStr = encodeURIComponent(JSON.stringify(orderObj.orderItems || []));
uni.navigateTo({
url: `/package_a/back/backDetail?items=${itemsStr}`
});
} }
} }
}; };
</script> </script>
<style scoped> <style scoped>
/* 页面基础容器 */ .page-container { width: 100%; min-height: 100vh; background: #f5f5f5; display: flex; flex-direction: column; }
.page-container { .navbar { height: 48px; background: #e62318; color: white; display: flex; align-items: center; padding: 0 16px; position: relative; }
width: 100%; .nav-tabs { flex: 1; display: flex; justify-content: center; }
min-height: 100vh; .tab-item { font-size: 17px; padding: 0 8px; position: relative; font-weight: bold; }
background-color: #f5f5f5; .tab-item.active::after { content: ''; position: absolute; bottom: -8px; left: 0; right: 0; height: 3px; background: white; border-radius: 2px; }
display: flex;
flex-direction: column;
}
/* 状态栏 */ .search-section { background: white; padding: 12px 16px; display: flex; align-items: center; gap: 12px; }
.status-bar { .search-box { flex: 1; height: 36px; background: #f5f5f5; border-radius: 6px; border: 1px solid #e5e5e5; display: flex; align-items: center; padding: 0 12px; }
height: 44px; .search-icon { font-size: 16px; color: #999; margin-right: 8px; }
background-color: #e62318; .search-input { flex: 1; font-size: 15px; color: #333; background: transparent; border: none; height: 100%; }
color: white; .picker-input { display: flex; align-items: center; }
display: flex; .picker-text { line-height: 36px; color: #666; }
justify-content: space-between; .split-icon { font-size: 18px; color: #666; margin-left: 8px; padding: 4px; display: flex; align-items: center; }
align-items: center; .reset-icon { font-size: 20px; color: #999; margin-left: 4px; padding: 4px; display: flex; align-items: center; line-height: 1; }
padding: 0 16px; .filter-btn { height: 36px; background: #e62318; border-radius: 6px; padding: 0 16px; display: flex; align-items: center; gap: 4px; font-size: 15px; color: #fff; }
font-size: 17px; .reset-btn { height: 36px; background: #fff; border-radius: 6px; padding: 0 16px; display: flex; align-items: center; font-size: 15px; color: #666; border: 1px solid #ddd; }
font-weight: 500; .filter-icon { font-size: 14px; }
}
.status-icons { .content { flex: 1; padding: 12px; box-sizing: border-box; }
display: flex; .order-item { background: #fff; border-radius: 8px; padding: 16px; margin-bottom: 12px; box-shadow: 0 2px 6px rgba(0,0,0,0.04); }
gap: 8px; .order-header { display: flex; justify-content: space-between; border-bottom: 1px solid #f0f0f0; padding-bottom: 12px; margin-bottom: 12px; }
} .order-no { font-size: 14px; color: #333; font-weight: bold; }
.pay-status { font-size: 13px; }
.status-warning { color: #f29c1f; }
.status-success { color: #52c41a; }
.status-error { color: #e62318; }
.order-body { display: flex; flex-direction: column; gap: 8px; }
.info-row { display: flex; justify-content: space-between; align-items: center; }
.info-label { font-size: 13px; color: #666; }
.info-value { font-size: 13px; color: #333; }
.amount { color: #e62318; font-weight: bold; font-size: 16px; }
/* 导航栏 */ .empty-card { background: transparent; padding: 100px 0; display: flex; flex-direction: column; align-items: center; }
.navbar { .empty-icon-wrapper { width: 80px; height: 80px; background: #e8e8e8; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin-bottom: 16px; }
height: 48px; .empty-icon { font-size: 32px; color: #999; }
background-color: #e62318; .empty-text { font-size: 16px; color: #999; }
color: white;
display: flex;
align-items: center;
padding: 0 16px;
position: relative;
}
.nav-back {
width: 44px;
height: 44px;
display: flex;
align-items: center;
justify-content: center;
}
.back-icon {
font-size: 20px;
font-weight: 500;
}
.nav-tabs {
flex: 1;
display: flex;
justify-content: center;
gap: 40px;
}
.tab-item {
font-size: 17px;
padding: 0 8px;
position: relative;
}
.tab-item.active {
font-weight: bold;
}
.tab-item.active::after {
content: '';
position: absolute;
bottom: -8px;
left: 0;
right: 0;
height: 3px;
background-color: white;
border-radius: 2px;
}
/* 搜索与筛选区 */
.search-section {
background-color: white;
padding: 12px 16px;
display: flex;
align-items: center;
gap: 12px;
}
.search-box {
flex: 1;
height: 36px;
background-color: #f5f5f5;
border-radius: 6px;
border: 1px solid #e5e5e5;
display: flex;
align-items: center;
padding: 0 12px;
}
.search-icon {
font-size: 16px;
color: #999;
margin-right: 8px;
}
.search-input {
flex: 1;
font-size: 15px;
color: #333;
background: transparent;
border: none;
outline: none;
}
.split-icon {
font-size: 16px;
color: #999;
margin-left: 8px;
}
.filter-btn {
height: 36px;
background-color: #f5f5f5;
border-radius: 6px;
padding: 0 12px;
display: flex;
align-items: center;
gap: 4px;
font-size: 15px;
color: #333;
}
.filter-icon {
font-size: 16px;
}
/* 内容区 */
.content {
flex: 1;
padding: 24px 16px;
}
.empty-card {
background-color: white;
border-radius: 12px;
padding: 60px 0;
display: flex;
flex-direction: column;
align-items: center;
}
.empty-icon-wrapper {
width: 80px;
height: 80px;
background-color: #fff5f5;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 16px;
}
.empty-icon {
font-size: 32px;
color: #ffb3b3;
}
.empty-text {
font-size: 16px;
color: #666;
}
</style> </style>

View File

@ -0,0 +1,144 @@
<template>
<view class="detail-container">
<block v-if="orderItems && orderItems.length > 0">
<view class="product-item" v-for="item in orderItems" :key="item.id">
<!-- 商品图片点击放大 -->
<image class="product-img" :src="resolveImage(item.mainImage)" mode="aspectFill" @click="previewImage(item.mainImage)"></image>
<view class="product-info">
<!-- 商品名称 -->
<view class="product-name">{{ item.productName || '--' }}</view>
<!-- 商品条码 -->
<view class="product-code">条码{{ item.productBarCode || '--' }}</view>
<view class="price-row">
<!-- 商品价格 -->
<text class="price">¥{{ item.subtotal || item.unitPrice || '0.00' }}</text>
<!-- 商品件数 -->
<text class="quantity">x {{ item.quantity || 1 }}</text>
</view>
</view>
</view>
</block>
<view class="empty-status" v-else>
<text>暂无商品信息</text>
</view>
</view>
</template>
<script>
import config from '@/config';
export default {
data() {
return {
orderItems: []
};
},
onLoad(options) {
if (options.items) {
try {
this.orderItems = JSON.parse(decodeURIComponent(options.items));
} catch (e) {
console.error('商品数据解析失败', e);
}
}
},
methods: {
//
resolveImage(url) {
if (!url) return '/static/images/default.png';
if (url.startsWith('http')) return url;
return config.baseUrl + url;
},
//
previewImage(url) {
if (!url) return;
const fullUrl = this.resolveImage(url);
uni.previewImage({
urls: [fullUrl],
current: fullUrl
});
}
}
};
</script>
<style scoped>
.detail-container {
min-height: 100vh;
background-color: #f5f5f5;
padding: 12px;
box-sizing: border-box;
}
.product-item {
display: flex;
background-color: #fff;
border-radius: 8px;
padding: 12px;
margin-bottom: 12px;
box-shadow: 0 2px 6px rgba(0,0,0,0.04);
}
.product-img {
width: 80px;
height: 80px;
border-radius: 6px;
background-color: #f0f0f0;
margin-right: 12px;
flex-shrink: 0;
}
.product-info {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.product-name {
font-size: 15px;
color: #333;
font-weight: 500;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.product-code {
font-size: 12px;
color: #999;
margin-top: 4px;
}
.price-row {
display: flex;
justify-content: space-between;
align-items: flex-end;
margin-top: 8px;
}
.price {
font-size: 16px;
color: #e62318;
font-weight: bold;
}
.quantity {
font-size: 13px;
color: #666;
}
.empty-status {
padding: 60px 0;
text-align: center;
color: #999;
font-size: 15px;
}
</style>

View File

@ -46,6 +46,8 @@
{ "path": "import/import", "style": { "navigationBarTitleText": "" } }, { "path": "import/import", "style": { "navigationBarTitleText": "" } },
{ "path": "category/category", "style": { "navigationBarTitleText": "" } }, { "path": "category/category", "style": { "navigationBarTitleText": "" } },
{ "path": "back/back", "style": { "navigationBarTitleText": "" } }, { "path": "back/back", "style": { "navigationBarTitleText": "" } },
{ "path": "back/backDetail", "style": { "navigationBarTitleText": "订单详情" } },
{ "path": "mine/info/index", "style": { "navigationBarTitleText": "个人信息" } }, { "path": "mine/info/index", "style": { "navigationBarTitleText": "个人信息" } },
{ "path": "mine/info/edit", "style": { "navigationBarTitleText": "编辑资料" } }, { "path": "mine/info/edit", "style": { "navigationBarTitleText": "编辑资料" } },
{ "path": "mine/setting/index", "style": { "navigationBarTitleText": "应用设置" } }, { "path": "mine/setting/index", "style": { "navigationBarTitleText": "应用设置" } },