|
|
- <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="switchTab(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" />
- </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.pickupTime">
- <text class="info-label">取件时间:</text>
- <text class="info-value">{{ order.pickupTime }}</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">
- <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, // px
- tabBarHeight: 48, // px
- navBarHeight: 44, // 默认值,后续动态获取
- navBarRealHeight: 44, // 实际高度
- tabs: [
- { label: '全部', value: -1 },
- { label: '已预约', value: 0 },
- { label: '待质检', value: 1 },
- { label: '已结款', value: 2 },
- { label: '已驳回', value: 3 },
- { label: '已取消', value: 4 }
- ],
- currentTab: 0,
- orderList: [
- {
- id: 1,
- orderNo: 'RE82738127861524',
- userName: '周小艺',
- phone: '138****1234',
- appointTime: '周四 11:00~13:00',
- statusText: '已预约',
- statusClass: 'green',
- statusLabel: '已预约',
- actions: [],
- status: 0
- },
- {
- id: 2,
- orderNo: 'RE82738127861524',
- userName: '周小艺',
- phone: '138****1234',
- appointTime: '周四 11:00~13:00',
- statusText: '不包邮',
- statusClass: 'green',
- statusLabel: '已预约',
- actions: [],
- status: 0
- },
- {
- id: 3,
- orderNo: 'RE82738127861526',
- userName: '周小艺',
- phone: '138****1234',
- pickupTime: '2025-03-20 11:00',
- statusText: '待质检',
- statusClass: 'orange',
- statusLabel: '待质检',
- actions: [
- { icon: 'undo', text: '驳回' },
- { icon: 'person', text: '审批' }
- ],
- status: 1
- },
- {
- id: 4,
- orderNo: 'RE82738127861525',
- userName: '周小艺',
- phone: '138****1234',
- pickupTime: '2025-03-20 12:00',
- statusText: '已驳回',
- statusClass: 'red',
- statusLabel: '已驳回',
- actions: [],
- status: 3
- },
- {
- id: 5,
- orderNo: 'RE82738127861525',
- userName: '周小艺',
- phone: '138****1234',
- cancelTime: '2025-03-20 12:00',
- statusText: '已取消',
- statusClass: 'gray',
- statusLabel: '已取消',
- actions: [],
- status: 4
- },
- {
- id: 6,
- orderNo: 'RE82738127861526',
- userName: '周小艺',
- phone: '138****1234',
- qualityTime: '2025-03-20 12:00',
- statusText: '已结款',
- statusClass: 'blue',
- statusLabel: '已结款',
- actions: [],
- status: 2
- }
- ],
- searchMode: false,
- searchText: '',
- historyOrderMode: false,
- }
- },
- 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;
- }
- },
- 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;
- if (tabValue === -1) return this.orderList;
- return this.orderList.filter(order => order.status === tabValue);
- }
- },
- methods: {
- goBack() {
- uni.navigateBack()
- },
- switchTab(idx) {
- this.currentTab = idx
- },
- onSearchIconClick() {
- this.searchMode = true;
- this.$nextTick(() => {
- this.$refs.searchInput && this.$refs.searchInput.focus();
- });
- },
- onClearSearch() {
- this.searchText = '';
- },
- onCancelSearch() {
- this.searchText = '';
- this.searchMode = false;
- },
- goToOrderDetail(order) {
- // 根据订单状态动态设置订单详情页的显示内容
- const orderDetail = {
- status: order.status,
- statusText: order.statusText,
- statusLabel: order.statusLabel,
- statusClass: order.statusClass,
- estimate: '73.6~75.8',
- items: [
- { name: '羽绒服', desc: '允许脏破烂,160码以上', price: 8, count: 8, total: 64, img: '/static/coat1.png' },
- { name: '品牌羽绒服', desc: '允许脏破烂,160码以上', price: 10, count: 8, total: 8, img: '/static/coat2.png' }
- ]
- }
- // 跳转到订单详情页
- uni.navigateTo({
- url: '/pages/manager/order-detail',
- success: (res) => {
- res.eventChannel.emit('orderDetail', orderDetail)
- }
- })
- },
- refreshData() {
- // TODO: 实现订单列表刷新逻辑,如重新请求接口
- },
- async onRefresh() {
- await this.refreshData && this.refreshData()
- },
- },
- onPullDownRefresh() {
- this.refreshData && this.refreshData()
- uni.stopPullDownRefresh()
- }
- }
- </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>
|