爱简收旧衣按件回收前端代码仓库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

600 lines
16 KiB

<template>
<view class="order-manage-container">
<!-- 顶部导航栏 -->
<view
class="nav-bar"
:style="{
paddingTop: statusBarHeight + 'px',
height: (statusBarHeight + navBarContentHeight) + 'px'
}"
>
<uni-icons type="left" @tap="goBack" size="24" color="#222" />
<text class="nav-title">{{ historyOrderMode ? '历史订单' : '订单管理' }}</text>
</view>
<!-- Tab栏 -->
<scroll-view
v-if="!historyOrderMode"
class="order-tabs-scroll"
scroll-x
:style="{
top: navBarRealHeight + 'px',
height: tabBarHeight + 'px',
position: 'fixed',
left: 0,
width: '100%',
zIndex: 99
}"
>
<view
class="order-tabs"
:style="{width: (tabs.length * 20) + '%'}"
>
<view
v-for="(tab, idx) in tabs"
:key="tab.value"
:class="['tab-item', {active: currentTab === idx}]"
@tap="onTabChange(idx)"
>
{{ tab.label }}
</view>
</view>
</scroll-view>
<!-- 搜索与筛选 -->
<view
v-if="!historyOrderMode"
class="search-bar"
:style="{
position: 'fixed',
zIndex: 10,
top: (navBarRealHeight + tabBarHeight) + 'px',
left: 0,
width: '100vw',
height: '40px'
}"
>
<view class="search-bar-inner">
<template v-if="!searchMode">
<uni-icons class="search-icon" type="search" size="22" color="#999" @tap="onSearchIconClick" />
<uni-icons class="scan-icon" type="scan" size="22" color="#999" @tap="scanCode" />
</template>
<template v-else>
<view class="search-input-wrap">
<uni-icons type="search" size="22" color="#999" />
<input
ref="searchInput"
class="search-input"
v-model="searchText"
placeholder="请输入要查询的内容"
placeholder-style="color:#ccc"
/>
<uni-icons v-if="searchText" type="close" size="22" color="#ccc" @tap="onClearSearch" />
</view>
<text class="search-cancel" @tap="onCancelSearch">取消</text>
</template>
</view>
</view>
<!-- 订单卡片列表 -->
<view class="order-list"
:style="{paddingTop: (navBarRealHeight + (historyOrderMode ? 0 : (tabBarHeight + 16 + 40))) + 'px'}"
>
<view class="order-card" v-for="order in filteredOrders" :key="order.id" @tap="goToOrderDetail(order)">
<view class="order-card-header">
<text class="order-id">{{ order.orderNo }}</text>
<view v-if="order.statusText === '不包邮'" class="order-status-tag red">{{ order.statusText }}</view>
</view>
<view class="order-info-wrapper">
<view class="order-info">
<view>
<text class="info-label">用户名:</text>
<text class="info-value">{{ order.userName }}</text>
</view>
<view>
<text class="info-label">电话:</text>
<text class="info-value">{{ order.phone }}</text>
</view>
<view v-if="order.appointTime">
<text class="info-label">预约时间:</text>
<text class="info-value">{{ order.appointTime }}</text>
</view>
<view v-if="order.cancelTime">
<text class="info-label">取消时间:</text>
<text class="info-value">{{ order.cancelTime }}</text>
</view>
<view v-if="order.qualityTime">
<text class="info-label">质检时间:</text>
<text class="info-value">{{ order.qualityTime }}</text>
</view>
</view>
<view class="order-status-label-bar order-info-status" :class="order.statusClass">{{ order.statusLabel }}</view>
</view>
<view class="order-card-footer" v-if="order.actions && order.actions.length && !historyOrderMode">
<view class="order-actions-bar">
<view class="action-btn-bar" v-for="action in order.actions" :key="action.text" @tap="action.text === '审批' ? goToOrderDetail(order) : null">
<uni-icons :type="action.icon" size="28" color="#666" />
<text>{{ action.text }}</text>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import pullRefreshMixin from '../mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
statusBarHeight: 0,
navBarContentHeight: 44,
tabBarHeight: 48,
navBarHeight: 44,
navBarRealHeight: 44,
tabs: [
{ label: '全部', value: -1 },
{ label: '已预约', value: 0 },
{ label: '待质检', value: 1 },
{ label: '已结款', value: 2 },
{ label: '已驳回', value: 3 }
],
currentTab: 0,
orderList: [],
searchMode: false,
searchText: '',
historyOrderMode: false,
pageNum: 1,
pageSize: 10,
hasMore: true,
isLoading: false,
userId: ''
}
},
onLoad(options) {
const sys = uni.getSystemInfoSync();
this.statusBarHeight = sys.statusBarHeight;
this.$nextTick(() => {
uni.createSelectorQuery().select('.nav-bar').boundingClientRect(rect => {
if (rect) {
this.navBarRealHeight = rect.height;
}
}).exec();
});
if (options && options.historyOrder) {
this.historyOrderMode = true;
}
if (options && options.userId) {
this.userId = options.userId;
}
this.fetchOrderList()
},
computed: {
filteredOrders() {
if (this.searchText) {
const text = this.searchText.toLowerCase();
return this.orderList.filter(order =>
(order.orderNo && order.orderNo.toLowerCase().includes(text)) ||
(order.userName && order.userName.toLowerCase().includes(text)) ||
(order.phone && order.phone.toLowerCase().includes(text))
);
}
const tabValue = this.tabs[this.currentTab].value;
// console.log('当前tab:', tabValue, 'orderList:', this.orderList);
if (tabValue === -1) return this.orderList;
if (tabValue === 0) {
// 已预约:status == 1
// console.log(this.orderList.filter(order => order.status == 1),'this.orderList')
return this.orderList.filter(order => order.status == 1);
} else if (tabValue === 1) {
// 待质检:state == 1
return this.orderList.filter(order => order.status == 2);
} else if (tabValue === 2) {
// 已结款:status == 3
return this.orderList.filter(order => order.status == 3);
} else if (tabValue === 3) {
// 已驳回:status == 1 && state == 3
return this.orderList.filter(order => order.status == 4);
}
return this.orderList;
}
},
methods: {
goBack() {
uni.navigateBack()
},
onTabChange(idx) {
this.currentTab = idx
this.pageNum = 1
this.hasMore = true
this.orderList = []
this.fetchOrderList()
},
onSearchIconClick() {
this.searchMode = true;
this.$nextTick(() => {
this.$refs.searchInput && this.$refs.searchInput.focus();
});
},
onClearSearch() {
this.searchText = '';
},
onCancelSearch() {
this.searchText = '';
this.searchMode = false;
},
goToOrderDetail(order) {
uni.navigateTo({
url: '/pages/manager/order-detail?id=' + order.id
})
},
refreshData() {
// TODO: 实现订单列表刷新逻辑,如重新请求接口
},
async onRefresh() {
await this.refreshData && this.refreshData()
},
fetchOrderList(isLoadMore = false) {
if (this.isLoading || (!isLoadMore && !this.hasMore)) return
this.isLoading = true
const params = {
pageNum: this.pageNum,
pageSize: this.pageSize
}
if (this.userId) {
params.userId = this.userId;
}
this.$api && this.$api('getOrderList', params, res => {
if (res && res.code === 200 && res.result && res.result.records) {
const newOrders = res.result.records.map(order => {
const statusInfo = this.getOrderStatusInfo(order.status, order.state)
return {
id: order.id,
orderNo: order.ordeNo,
userName: order.name,
phone: order.phone,
appointTime: order.goTime,
cancelTime: order.state === 3 ? order.updateTime : '',
qualityTime: order.status === 2 && order.state === 1 ? order.updateTime : '',
statusText: order.isBy === 'Y' ? statusInfo.label : '不包邮',
statusClass: statusInfo.class,
statusLabel: statusInfo.label,
actions: this.getOrderActions(order.status, order.state),
status: this.getOrderStatus(order.status, order.state)
}
})
if (isLoadMore) {
this.orderList = [...this.orderList, ...newOrders]
} else {
this.orderList = newOrders
}
this.hasMore = newOrders.length === this.pageSize
this.pageNum = isLoadMore ? this.pageNum + 1 : 1
}
this.isLoading = false
})
},
getOrderStatusInfo(status, state) {
// if (state === 3) {
// return { label: '已取消', class: 'gray' }
// }
if (status === 1 ) {
return { label: '已预约', class: 'green' }
} else if (state === 1) {
return { label: '待质检', class: 'orange' }
} else if (status === 3) {
return { label: '已结款', class: 'blue' }
} else if (status === 1 && state === 3) {
return { label: '已驳回', class: 'red' }
}
return { label: '未知状态', class: 'gray' }
},
getOrderStatus(status, state) {
// // 已取消状态
// if (state === 3) return 4
// 已预约状态 - 快递上门
if (status === 1 ) return 1
// 待质检状态 - 已取件
if (state === 1) return 2
// 已结款状态 - 现金打款
if (status === 3 ) return 3
// 已驳回状态 - 快递上门终止
if (status === 1 && state === 3) return 4
return -1
},
getOrderActions(status, state) {
const actions = []
// 只有待质检状态显示操作按钮
if (status === 2 && state === 1) {
actions.push({ icon: 'undo', text: '驳回' })
actions.push({ icon: 'person', text: '审批' })
}
return actions
},
onLoadMore() {
if (this.hasMore && !this.isLoading) {
this.fetchOrderList(true)
}
},
scanCode() {
uni.scanCode({
scanType: ['qrCode'],
success: (res) => {
console.log('扫码结果:', res);
// 这里可以根据扫码结果进行相应处理
// 比如跳转到订单详情页
if(res.result) {
uni.navigateTo({
url: '/pages/manager/order-detail?id=' + res.result
})
}
},
fail: (err) => {
console.error('扫码失败:', err);
uni.showToast({
title: '扫码失败',
icon: 'none'
})
}
})
},
},
onPullDownRefresh() {
this.pageNum = 1;
this.hasMore = true;
this.orderList = [];
this.fetchOrderList();
uni.stopPullDownRefresh();
},
onReachBottom() {
this.onLoadMore()
}
}
</script>
<style lang="scss" scoped>
.order-manage-container {
background: #f8f8f8;
min-height: 100vh;
padding-bottom: 24px;
}
.nav-bar {
display: flex;
align-items: center;
justify-content: space-between;
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
background: #fff;
padding: 0 32rpx;
box-sizing: border-box;
.nav-title {
flex: 1;
text-align: center;
font-size: 36rpx;
font-weight: bold;
color: #222;
}
.nav-icons {
display: flex;
align-items: center;
gap: 32rpx;
}
}
.order-tabs-scroll {
position: fixed;
left: 0;
width: 100%;
z-index: 99;
background: #fff;
border-bottom: 1px solid #f0f0f0;
height: 96rpx;
overflow-x: auto;
white-space: nowrap;
-webkit-overflow-scrolling: touch;
&::-webkit-scrollbar {
display: none;
}
}
.order-tabs {
display: flex;
width: 100%;
}
.tab-item {
flex: 1 0 0%;
text-align: center;
font-size: 34rpx;
color: #bfbfbf;
height: 96rpx;
line-height: 96rpx;
position: relative;
font-weight: 500;
transition: color 0.2s;
letter-spacing: 0.5px;
}
.tab-item.active {
color: #ffb400;
font-weight: bold;
}
.tab-item.active::after {
content: '';
display: block;
margin: 0 auto;
margin-top: 2px;
width: 22px;
height: 3px;
border-radius: 2px;
background: #ffb400;
}
.search-bar {
width: 100vw;
height: 40px;
position: fixed;
z-index: 10;
left: 0;
top: 0;
display: flex;
align-items: center;
}
.search-bar-inner {
margin: 0 16px;
background: #fff;
border-radius: 20px;
height: 40px;
flex: 1;
display: flex;
align-items: center;
box-shadow: 0 2px 8px rgba(0,0,0,0.02);
padding: 0 12px;
justify-content: space-around;
.search-icon {
margin-right: 8px;
}
.scan-icon {
margin-left: 8px;
}
}
.search-input-wrap {
display: flex;
align-items: center;
flex: 1;
background: #f5f5f5;
border-radius: 20px;
height: 32px;
margin: 0 0;
padding: 0 8px;
.search-input {
flex: 1;
border: none;
outline: none;
background: transparent;
font-size: 15px;
color: #222;
margin-left: 8px;
}
}
.search-cancel {
margin-left: 8px;
color: #999;
font-size: 15px;
line-height: 40px;
}
.order-list {
margin: 0;
padding-top: calc(var(--status-bar-height, 0px) + 44px + 44px + 16px);
}
.order-card {
background: #fff;
border-radius: 20px;
margin: 0 16px 16px 16px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.04);
}
.order-card-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 12px;
.order-id {
font-size: 16px;
font-weight: bold;
color: #222;
}
.order-status-tag {
font-size: 14px;
border-radius: 12px;
padding: 2px 12px;
&.green { background: #e6f9e6; color: #1ecb1e; }
&.red { background: #ffeaea; color: #ff4d4f; }
&.orange { background: #fff7e6; color: #ffb400; }
&.blue { background: #e6f0ff; color: #409eff; }
&.gray { background: #f5f5f5; color: #999; }
}
}
.order-info-wrapper {
position: relative;
.order-info-status {
position: absolute;
right: 0;
bottom: 0;
font-size: 14px;
border-radius: 12px;
padding: 2px 12px;
&.green { background: #e6f9e6; color: #1ecb1e; }
&.red { background: #ffeaea; color: #ff4d4f; }
&.orange { background: #fff7e6; color: #ffb400; }
&.blue { background: #e6f0ff; color: #409eff; }
&.gray { background: #f5f5f5; color: #999; }
}
}
.order-info {
font-family: 'PingFang SC', 'Microsoft YaHei', Arial, sans-serif;
font-weight: 400;
font-size: 14px;
line-height: 1.4;
letter-spacing: 0;
vertical-align: middle;
color: #666;
margin-bottom: 12px;
view {
margin-bottom: 4px;
display: flex;
align-items: center;
}
.info-label {
color: #999;
font-family: 'PingFang SC', 'Microsoft YaHei', Arial, sans-serif;
font-weight: 400;
font-size: 14px;
line-height: 1.4;
margin-right: 4px;
}
.info-value {
color: #222;
font-family: 'PingFang SC', 'Microsoft YaHei', Arial, sans-serif;
font-weight: 400;
font-size: 14px;
line-height: 1.4;
}
}
.order-card-footer {
display: flex;
align-items: center;
justify-content: center;
margin: 0 -20px -20px -20px;
padding: 0 20px;
border-bottom-left-radius: 20px;
border-bottom-right-radius: 20px;
background: #fafbfc;
min-height: 60px;
position: relative;
.order-actions-bar {
display: flex;
flex: 1;
justify-content: center;
align-items: center;
gap: 48px;
.action-btn-bar {
display: flex;
flex-direction: column;
align-items: center;
font-size: 14px;
color: #666;
margin-top: 8px;
margin-bottom: 8px;
uni-icons {
margin-bottom: 2px;
}
}
}
}
</style>