daShangDao_miniProgram/pages/warehouse/order-query.vue
2026-06-15 16:37:57 +08:00

1634 lines
39 KiB
Vue

<template>
<view class="container">
<!-- 筛选弹窗 -->
<view class="filter-mask" v-if="showFilterPopup" @click="closePopup">
<view class="filter-popup-wrapper" @click.stop>
<view class="filter-popup">
<view class="popup-header">
<view class="popup-title">筛选条件</view>
<view class="popup-actions">
<text class="reset-text" @click="handleReset">重置</text>
<text class="close-text" @click="closePopup">✕</text>
</view>
</view>
<scroll-view class="filter-scroll" scroll-y>
<view class="filter-content">
<view class="form-item">
<view class="label">订单编号</view>
<input v-model="tempParams.orderSn" class="input" placeholder="请输入订单编号" />
</view>
<view class="form-item">
<view class="label">店铺类型</view>
<picker mode="selector" :range="shopTypeOptions" range-key="label"
@change="onShopTypeChange">
<view class="picker-input">
<text :class="{'placeholder': !tempSelectedShopTypeLabel}">
{{ tempSelectedShopTypeLabel || '请选择店铺类型' }}
</text>
<u-icon name="arrow-down" size="14"></u-icon>
</view>
</picker>
</view>
<view class="form-item">
<view class="label">时间范围</view>
<picker mode="selector" :range="timeRangeOptions" range-key="label"
@change="onTimeRangeChange">
<view class="picker-input">
<text :class="{'placeholder': !tempSelectedTimeRangeLabel}">
{{ tempSelectedTimeRangeLabel || '请选择时间范围' }}
</text>
<u-icon name="arrow-down" size="14"></u-icon>
</view>
</picker>
</view>
<view class="form-item">
<view class="label">出库状态</view>
<picker mode="selector" :range="outboundStatusOptions" range-key="label"
@change="onOutboundStatusChange">
<view class="picker-input">
<text :class="{'placeholder': !tempSelectedOutboundStatusLabel}">
{{ tempSelectedOutboundStatusLabel || '请选择出库状态' }}
</text>
<u-icon name="arrow-down" size="14"></u-icon>
</view>
</picker>
</view>
<view class="form-item">
<view class="label">发货状态</view>
<picker mode="selector" :range="orderStatusOptions" range-key="label"
@change="onOrderStatusChange">
<view class="picker-input">
<text :class="{'placeholder': !tempSelectedOrderStatusLabel}">
{{ tempSelectedOrderStatusLabel || '请选择发货状态' }}
</text>
<u-icon name="arrow-down" size="14"></u-icon>
</view>
</picker>
</view>
<view class="form-item">
<view class="label">货号</view>
<input v-model="tempParams.artNo" class="input" placeholder="请输入货号" />
</view>
<view class="form-item">
<view class="label">原货号</view>
<input v-model="tempParams.originalArtNo" class="input" placeholder="请输入原货号" />
</view>
<view class="form-item">
<view class="label">ISBN</view>
<input v-model="tempParams.isbn" class="input" placeholder="请输入ISBN(可选)" />
</view>
<view class="form-item">
<view class="label">排序方式</view>
<picker mode="selector" :range="sortOrderOptions" range-key="label"
@change="onSortOrderChange">
<view class="picker-input">
<text :class="{'placeholder': !tempSelectedSortOrderLabel}">
{{ tempSelectedSortOrderLabel || '请选择排序方式' }}
</text>
<u-icon name="arrow-down" size="14"></u-icon>
</view>
</picker>
</view>
</view>
</scroll-view>
<view class="popup-footer">
<view class="footer-buttons">
<button class="cancel-btn" @click="closePopup">取消</button>
<button class="confirm-btn" @click="applyFilter">确认查询</button>
</view>
</view>
</view>
</view>
</view>
<!-- 统计信息 -->
<view class="statistics" v-if="total > 0">
<text class="total-text">共 {{ total }} 条记录</text>
</view>
<!-- 订单列表 -->
<view class="order-list" v-if="orderList.length > 0">
<view class="order-item" v-for="(item, index) in orderList" :key="index" @click="toggleSelect(item.id)">
<view class="order-content" :class="{'selection-mode-active': isSelectionMode}">
<!-- 选择模式下的复选框 -->
<view v-if="isSelectionMode" class="checkbox-wrapper" @click.stop="toggleSelect(item.id)">
<view class="checkbox" :class="{'checked': selectedIds.includes(item.id)}">
<u-icon v-if="selectedIds.includes(item.id)" name="checkbox-mark" size="14"
color="#fff"></u-icon>
</view>
</view>
<!-- 左侧图片 -->
<view class="order-left">
<view v-if="isWithin48Hours(item.createdAt)" class="time-tag"
:class="isWithin24Hours(item.createdAt) ? 'time-tag-24h' : 'time-tag-48h'">
<text class="time-tag-text">{{ isWithin24Hours(item.createdAt) ? '24h内' : '48h内' }}</text>
</view>
<image
v-if="parsedItemList(item) && parsedItemList(item).goodsImgs && parsedItemList(item).goodsImgs.length > 0"
:src="parsedItemList(item).goodsImgs[0]" class="goods-thumb" mode="aspectFill"
@click.stop="previewImage(parsedItemList(item).goodsImgs, 0)"></image>
<view v-else class="goods-thumb-placeholder">
<text class="placeholder-text">暂无图片</text>
</view>
<!-- 订单时间标签 -->
<view class="order-time-tag">
<text class="order-time-text">{{ getOrderTimeText(item.createdAt) }}</text>
</view>
</view>
<!-- 右侧信息 -->
<view class="order-right">
<view class="order-title">
{{ parsedItemList(item) ? (parsedItemList(item).goodsName || '-') : '-' }}
</view>
<view class="order-info-row">
<text class="info-label">新货号:</text>
<text class="info-value">{{ item.artNo || '-' }}</text>
</view>
<view class="order-info-row">
<text class="info-label">原货号:</text>
<text class="info-value">{{ item.originalArtNo || '-' }}</text>
</view>
<view class="order-info-row">
<text class="info-label">ISBN:</text>
<text class="info-value">{{ item.isbn || '-' }}</text>
</view>
<view class="order-info-row">
<text class="info-label">发货状态:</text>
<text class="info-value" :class="{
'status-pending-payment': item.orderStatus === 1,
'status-pending-ship': item.orderStatus === 2,
'status-shipped': item.orderStatus === 3,
'status-completed': item.orderStatus === 4,
'status-refunded': item.orderStatus === 5,
'status-closed': item.orderStatus === 6,
'status-after-sale': item.orderStatus === 7
}">
{{ item.orderStatus === 1 ? '到付款' : (item.orderStatus === 2 ? '待发货' : (item.orderStatus === 3 ? '已发货待签收' : (item.orderStatus === 4 ? '交易完成' : (item.orderStatus === 5 ? '已退款' : (item.orderStatus === 6 ? '交易关闭' : (item.orderStatus === 7 ? '售后处理中' : '-')))))) }}
</text>
</view>
<view class="order-info-row">
<text class="info-label">出库状态:</text>
<text class="info-value"
:class="{'status-out': item.whetherOutbound === 1, 'status-not-out': item.whetherOutbound === 0}">
{{ item.whetherOutbound === 1 ? '已出库' : (item.whetherOutbound === 0 ? '未出库' : '-') }}
</text>
</view>
</view>
</view>
</view>
</view>
<!-- 空状态 -->
<view class="empty-state" v-else-if="!loading">
<view class="empty-icon">📦</view>
<text class="empty-text">{{ emptyText }}</text>
</view>
<!-- 加载状态 -->
<view class="loading-state" v-if="loading">
<u-loading-icon mode="circle"></u-loading-icon>
<text class="loading-text">加载中...</text>
</view>
<!-- 批量操作按钮 - 固定在底部 -->
<view class="batch-actions-fixed">
<view class="actions-row">
<!-- 筛选按钮 -->
<view class="filter-section">
<button class="filter-btn-bottom" @click="openFilter">
<u-icon name="arrow-down" size="16" color="#fff"></u-icon>
<text>筛选</text>
</button>
<!-- <view v-if="hasActiveFilters" class="filter-info">
<text class="filter-count">{{ activeFilterCount }}</text>
<text class="filter-time" v-if="selectedTimeRangeLabel">{{ selectedTimeRangeLabel }}</text>
</view> -->
</view>
<!-- 批量出库按钮 -->
<view v-if="orderList.length > 0" class="batch-section">
<button v-if="!isSelectionMode" class="batch-btn" @click="startSelect">
<text>批量出库</text>
</button>
<view v-else class="selection-mode">
<view class="selected-count">已选 {{ selectedIds.length }}</view>
<button class="cancel-btn-small" @click="cancelSelect">取消</button>
<button class="confirm-btn-small" :class="{'disabled': selectedIds.length === 0}"
:disabled="selectedIds.length === 0" @click="confirmOutbound">确认</button>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
showFilterPopup: false,
queryParams: {
pageNum: 1,
pageSize: 1000,
createBy: '',
erpAfterSalesStatus: 0,
isQueryAllGoods: 1,
orderSn: '',
shopType: null,
startTime: null,
endTime: null,
whetherOutbound: null,
orderStatus: null,
artNo: '',
originalArtNo: '',
isbn: ''
},
tempParams: {
orderSn: '',
shopType: null,
startTime: null,
endTime: null,
whetherOutbound: null,
orderStatus: null,
artNo: '',
originalArtNo: '',
isbn: ''
},
shopTypeOptions: [{
label: '全部',
value: null
},
{
label: '拼多多',
value: 1
},
{
label: '孔夫子',
value: 2
},
{
label: '闲鱼',
value: 5
}
],
timeRangeOptions: [{
label: '全部',
value: null
},
{
label: '24小时内',
value: '24h'
},
{
label: '48小时内',
value: '48h'
},
{
label: '48小时外',
value: 'outside48h'
}
],
outboundStatusOptions: [{
label: '全部',
value: null
},
{
label: '未出库',
value: 0
},
{
label: '已出库',
value: 1
}
],
orderStatusOptions: [{
label: '全部',
value: null
},
{
label: '到付款',
value: 1
},
{
label: '待发货',
value: 2
},
{
label: '已发货待签收',
value: 3
},
{
label: '交易完成',
value: 4
},
{
label: '已退款',
value: 5
},
{
label: '交易关闭',
value: 6
},
{
label: '售后处理中',
value: 7
}
],
sortOrderOptions: [{
label: '时间排序',
value: 'time'
},
{
label: '货号排序',
value: 'artNo'
}
],
selectedShopTypeLabel: '',
selectedTimeRangeLabel: '',
selectedOutboundStatusLabel: '',
selectedOrderStatusLabel: '',
selectedSortOrderLabel: '时间排序',
tempSelectedShopTypeLabel: '',
tempSelectedTimeRangeLabel: '',
tempSelectedOutboundStatusLabel: '',
tempSelectedOrderStatusLabel: '',
tempSelectedSortOrderLabel: '时间排序',
orderList: [],
total: 0,
loading: false,
userId: '',
isSelectionMode: false,
selectedIds: [],
sortOrder: 'time', // time 或 artNo
tempSortOrder: 'time' // 临时排序方式
}
},
computed: {
hasActiveFilters() {
return this.activeFilterCount > 0;
},
activeFilterCount() {
let count = 0;
if (this.queryParams.orderSn) count++;
if (this.queryParams.shopType !== null) count++;
if (this.queryParams.startTime !== null) count++;
if (this.queryParams.whetherOutbound !== null) count++;
if (this.queryParams.orderStatus !== null) count++;
if (this.queryParams.artNo) count++;
if (this.queryParams.originalArtNo) count++;
if (this.queryParams.isbn) count++;
return count;
},
emptyText() {
// 如果有筛选条件,生成带筛选条件的提示文本
if (!this.hasActiveFilters) {
return '暂无订单数据';
}
let textParts = [];
// 按优先级添加筛选条件到提示文本
if (this.selectedTimeRangeLabel) {
textParts.push(this.selectedTimeRangeLabel);
}
if (this.selectedOutboundStatusLabel) {
textParts.push(this.selectedOutboundStatusLabel);
}
if (this.selectedOrderStatusLabel) {
textParts.push(this.selectedOrderStatusLabel);
}
if (this.selectedShopTypeLabel) {
textParts.push(this.selectedShopTypeLabel);
}
// 如果有具体条件,显示条件+暂无订单数据
if (textParts.length > 0) {
return `${textParts.join('、')}暂无订单数据`;
}
// 其他筛选条件(订单编号、货号等)
if (this.queryParams.orderSn) {
return '该订单编号暂无数据';
}
if (this.queryParams.artNo) {
return '该货号暂无数据';
}
if (this.queryParams.originalArtNo) {
return '该原货号暂无数据';
}
if (this.queryParams.isbn) {
return '该ISBN暂无数据';
}
return '暂无订单数据';
}
},
onLoad() {
// 从本地存储获取userId
this.userId = uni.getStorageSync('userId') || '';
this.queryParams.createBy = this.userId;
// 加载保存的筛选条件
this.loadSavedFilters();
},
onPullDownRefresh() {
// 下拉刷新时重新加载数据
this.handleSearch().then(() => {
// 停止下拉刷新动画
uni.stopPullDownRefresh();
}).catch((e) => {
// 即使失败也要停止刷新动画
console.error('下拉刷新失败:', e);
uni.stopPullDownRefresh();
});
},
onUnload() {
// 页面卸载时保存筛选条件
this.saveFilters();
},
methods: {
// 保存筛选条件到本地
saveFilters() {
const filterData = {
queryParams: this.queryParams,
selectedShopTypeLabel: this.selectedShopTypeLabel,
selectedTimeRangeLabel: this.selectedTimeRangeLabel,
selectedOutboundStatusLabel: this.selectedOutboundStatusLabel,
selectedOrderStatusLabel: this.selectedOrderStatusLabel,
selectedSortOrderLabel: this.selectedSortOrderLabel,
sortOrder: this.sortOrder
};
uni.setStorageSync('orderQueryFilters', JSON.stringify(filterData));
},
// 从本地加载筛选条件
loadSavedFilters() {
const savedFilters = uni.getStorageSync('orderQueryFilters');
if (savedFilters) {
try {
const filterData = JSON.parse(savedFilters);
// 恢复查询参数
this.queryParams = {
...this.queryParams,
...filterData.queryParams,
createBy: this.userId, // 始终使用当前userId
pageNum: 1, // 重置页码
pageSize: 1000
};
// 恢复显示标签
this.selectedShopTypeLabel = filterData.selectedShopTypeLabel || '';
this.selectedTimeRangeLabel = filterData.selectedTimeRangeLabel || '';
this.selectedOutboundStatusLabel = filterData.selectedOutboundStatusLabel || '';
this.selectedOrderStatusLabel = filterData.selectedOrderStatusLabel || '';
this.selectedSortOrderLabel = filterData.selectedSortOrderLabel || '时间排序';
this.sortOrder = filterData.sortOrder || 'time';
// 同步临时参数
this.tempParams = {
...this.queryParams
};
this.tempSelectedShopTypeLabel = this.selectedShopTypeLabel;
this.tempSelectedTimeRangeLabel = this.selectedTimeRangeLabel;
this.tempSelectedOutboundStatusLabel = this.selectedOutboundStatusLabel;
this.tempSelectedOrderStatusLabel = this.selectedOrderStatusLabel;
this.tempSelectedSortOrderLabel = this.selectedSortOrderLabel;
this.tempSortOrder = this.sortOrder;
// 执行查询
this.handleSearch();
} catch (e) {
console.error('加载筛选条件失败:', e);
// 加载失败时使用默认设置
this.loadDefaultFilters();
}
} else {
// 没有保存的筛选条件时使用默认设置
this.loadDefaultFilters();
}
},
// 加载默认筛选条件
loadDefaultFilters() {
// 设置默认筛选条件为48小时内
this.selectedTimeRangeLabel = '48小时内';
this.tempSelectedTimeRangeLabel = '48小时内';
const now = Date.now();
this.queryParams.endTime = now;
this.queryParams.startTime = now - 48 * 60 * 60 * 1000;
this.tempParams.endTime = now;
this.tempParams.startTime = now - 48 * 60 * 60 * 1000;
// 初始加载
this.handleSearch();
},
openFilter() {
this.showFilterPopup = true;
},
closePopup() {
this.showFilterPopup = false;
},
openPopup() {
this.showFilterPopup = true;
},
onShopTypeChange(e) {
const index = e.detail.value;
this.tempParams.shopType = this.shopTypeOptions[index].value;
this.tempSelectedShopTypeLabel = this.shopTypeOptions[index].label;
},
onTimeRangeChange(e) {
const index = e.detail.value;
const option = this.timeRangeOptions[index];
this.tempSelectedTimeRangeLabel = option.label;
if (option.value === '24h') {
// 24小时内
const now = Date.now();
this.tempParams.endTime = now;
this.tempParams.startTime = now - 24 * 60 * 60 * 1000;
} else if (option.value === '48h') {
// 48小时内
const now = Date.now();
this.tempParams.endTime = now;
this.tempParams.startTime = now - 48 * 60 * 60 * 1000;
} else if (option.value === 'outside48h') {
// 48小时外
const now = Date.now();
this.tempParams.endTime = now - 48 * 60 * 60 * 1000;
this.tempParams.startTime = 0;
} else {
// 全部
this.tempParams.startTime = null;
this.tempParams.endTime = null;
}
},
onOutboundStatusChange(e) {
const index = e.detail.value;
const option = this.outboundStatusOptions[index];
this.tempParams.whetherOutbound = option.value;
this.tempSelectedOutboundStatusLabel = option.label;
},
onOrderStatusChange(e) {
const index = e.detail.value;
const option = this.orderStatusOptions[index];
this.tempParams.orderStatus = option.value;
this.tempSelectedOrderStatusLabel = option.label;
},
onSortOrderChange(e) {
const index = e.detail.value;
const option = this.sortOrderOptions[index];
this.tempSortOrder = option.value;
this.tempSelectedSortOrderLabel = option.label;
},
applyFilter() {
// 将临时参数应用到正式参数
this.queryParams.orderSn = this.tempParams.orderSn;
this.queryParams.shopType = this.tempParams.shopType;
this.queryParams.startTime = this.tempParams.startTime;
this.queryParams.endTime = this.tempParams.endTime;
this.queryParams.whetherOutbound = this.tempParams.whetherOutbound;
this.queryParams.orderStatus = this.tempParams.orderStatus;
this.queryParams.artNo = this.tempParams.artNo;
this.queryParams.originalArtNo = this.tempParams.originalArtNo;
this.queryParams.isbn = this.tempParams.isbn;
// 同步显示标签
this.selectedShopTypeLabel = this.tempSelectedShopTypeLabel;
this.selectedTimeRangeLabel = this.tempSelectedTimeRangeLabel;
this.selectedOutboundStatusLabel = this.tempSelectedOutboundStatusLabel;
this.selectedOrderStatusLabel = this.tempSelectedOrderStatusLabel;
this.selectedSortOrderLabel = this.tempSelectedSortOrderLabel;
// 应用排序方式
this.sortOrder = this.tempSortOrder;
// 保存筛选条件到本地
this.saveFilters();
// 关闭弹窗并执行查询
this.showFilterPopup = false;
this.handleSearch();
},
async handleSearch() {
this.queryParams.pageNum = 1;
this.orderList = [];
await this.fetchOrders();
// 应用排序
if (this.sortOrder === 'artNo') {
this.sortOrderByArtNo();
}
},
handleReset() {
// 重置临时参数
this.tempParams = {
orderSn: '',
shopType: null,
startTime: null,
endTime: null,
whetherOutbound: null,
orderStatus: null,
artNo: '',
originalArtNo: '',
isbn: ''
};
this.tempSelectedShopTypeLabel = '';
this.tempSelectedTimeRangeLabel = '';
this.tempSelectedOutboundStatusLabel = '';
this.tempSelectedOrderStatusLabel = '';
this.tempSelectedSortOrderLabel = '时间排序';
this.tempSortOrder = 'time';
// 重置正式参数
this.queryParams = {
pageNum: 1,
pageSize: 1000,
createBy: this.userId,
erpAfterSalesStatus: 0,
isQueryAllGoods: 1,
orderSn: '',
shopType: null,
startTime: null,
endTime: null,
whetherOutbound: null,
orderStatus: null,
artNo: '',
originalArtNo: '',
isbn: ''
};
this.selectedShopTypeLabel = '';
this.selectedTimeRangeLabel = '';
this.selectedOutboundStatusLabel = '';
this.selectedOrderStatusLabel = '';
this.selectedSortOrderLabel = '时间排序';
this.sortOrder = 'time';
// 关闭弹窗并执行查询
this.showFilterPopup = false;
this.handleSearch();
},
async fetchOrders() {
if (this.loading) return;
this.loading = true;
try {
// 构建查询参数,过滤掉空值
const params = {};
for (const key in this.queryParams) {
if (this.queryParams[key] !== null && this.queryParams[key] !== undefined && this.queryParams[
key] !== '') {
params[key] = this.queryParams[key];
}
}
// 转换时间戳为数字
if (params.startTime) {
params.startTime = Number(params.startTime);
}
if (params.endTime) {
params.endTime = Number(params.endTime);
}
console.log("完整请求:", params);
const response = await this.$http({
url: 'https://api.buzhiyushu.cn/zhishu/orderExternalGoods/appList',
// url: 'http://localhost:8080/zhishu/orderExternalGoods/appList',
method: 'GET',
data: params,
loading: false
});
console.log("完整响应:", response);
console.log("状态码:", response.statusCode);
console.log("响应头:", response.header);
console.log("响应数据:", response.data);
if (response.code === 200) {
const newOrders = response.rows || [];
this.total = response.total || 0;
// 使用 $set 确保 Vue 能检测到数据变化
this.$set(this, 'orderList', newOrders);
// 强制更新视图
this.$forceUpdate();
} else {
uni.showToast({
title: response.msg || '查询失败',
icon: 'none'
});
}
} catch (error) {
console.error('查询订单失败:', error);
uni.showToast({
title: '查询失败,请稍后重试',
icon: 'none'
});
} finally {
this.loading = false;
}
},
previewImage(images, current) {
uni.previewImage({
urls: images,
current: current
});
},
// 判断是否在24小时内
isWithin24Hours(createdAt) {
if (!createdAt) return false;
const now = Date.now();
const timeDiff = now - createdAt;
const twentyFourHours = 24 * 60 * 60 * 1000;
return timeDiff <= twentyFourHours;
},
// 判断是否在48小时内
isWithin48Hours(createdAt) {
if (!createdAt) return false;
const now = Date.now();
const timeDiff = now - createdAt;
const fortyEightHours = 48 * 60 * 60 * 1000;
return timeDiff <= fortyEightHours;
},
parsedItemList(item) {
if (!item.itemList) {
return null;
}
try {
return typeof item.itemList === 'string' ? JSON.parse(item.itemList) : item.itemList;
} catch (e) {
console.error('解析itemList失败:', e);
return null;
}
},
// 获取订单时间文本
getOrderTimeText(createdAt) {
if (!createdAt) return '-';
const now = Date.now();
const timeDiff = now - createdAt;
const hours = Math.floor(timeDiff / (1000 * 60 * 60));
if (hours < 1) {
const minutes = Math.floor(timeDiff / (1000 * 60));
return `${minutes}分钟前`;
} else if (hours < 24) {
return `${hours}小时内`;
} else if (hours < 48) {
return '48小时内';
} else if (hours < 72) {
return '72小时内';
} else if (hours < 168) { // 7天
const days = Math.floor(hours / 24);
return `${days}天前`;
} else {
const days = Math.floor(hours / 24);
return `${days}天前`;
}
},
// 获取时间标签文本
getTimeTagText(createdAt) {
if (!createdAt) return '';
const now = Date.now();
const timeDiff = now - createdAt;
const twentyFourHours = 24 * 60 * 60 * 1000; // 24小时的毫秒数
const fortyEightHours = 48 * 60 * 60 * 1000; // 48小时的毫秒数
if (timeDiff <= twentyFourHours) {
return '24h内';
} else if (timeDiff <= fortyEightHours) {
return '48h内';
}
return '';
},
// 获取时间标签样式类
getTimeTagClass(createdAt) {
if (!createdAt) return '';
const now = Date.now();
const timeDiff = now - createdAt;
const twentyFourHours = 24 * 60 * 60 * 1000; // 24小时的毫秒数
const fortyEightHours = 48 * 60 * 60 * 1000; // 48小时的毫秒数
if (timeDiff <= twentyFourHours) {
return 'time-tag-24h';
} else if (timeDiff <= fortyEightHours) {
return 'time-tag-48h';
}
return 'time-tag-hidden';
},
// 获取订单状态文本
getOrderStatusText(status) {
const statusMap = {
1: '到付款',
2: '待发货',
3: '已发货待签收',
4: '交易完成',
5: '已退款',
6: '交易关闭',
7: '售后处理中'
};
return statusMap[status] || '-';
},
// 获取订单状态样式类
getOrderStatusClass(status) {
const classMap = {
1: 'status-pending-payment',
2: 'status-pending-ship',
3: 'status-shipped',
4: 'status-completed',
5: 'status-refunded',
6: 'status-closed',
7: 'status-after-sale'
};
return classMap[status] || '';
},
// 切换排序方式
changeSortOrder(order) {
if (this.sortOrder === order) return;
this.sortOrder = order;
if (order === 'artNo') {
// 按货号前五位ASCII排序
this.sortOrderByArtNo();
} else {
// 按时间排序(重新请求)
this.fetchOrders();
}
},
// 按货号排序
sortOrderByArtNo() {
const sortedList = [...this.orderList].sort((a, b) => {
const artNoA = (a.artNo || '').toString();
const artNoB = (b.artNo || '').toString();
// 获取前五位
const prefixA = artNoA.substring(0, 5);
const prefixB = artNoB.substring(0, 5);
// 如果前五位相同,比较完整货号
if (prefixA === prefixB) {
return artNoA.localeCompare(artNoB);
}
// 按ASCII排序
return prefixA.localeCompare(prefixB);
});
this.orderList = sortedList;
this.$forceUpdate();
},
// 开始选择模式
startSelect() {
this.isSelectionMode = true;
this.selectedIds = [];
},
// 取消选择模式
cancelSelect() {
this.isSelectionMode = false;
this.selectedIds = [];
},
// 切换选中状态
toggleSelect(id) {
if (!this.isSelectionMode) return;
const index = this.selectedIds.indexOf(id);
if (index > -1) {
this.selectedIds.splice(index, 1);
} else {
this.selectedIds.push(id);
}
},
// 确认出库
async confirmOutbound() {
if (this.selectedIds.length === 0) {
uni.showToast({
title: '请至少选择一项',
icon: 'none'
});
return;
}
try {
// 将选中的ID用逗号拼接
const ids = this.selectedIds.join(',');
// 打印出库参数
console.log('=== 批量出库参数 ===');
console.log('选中的ID列表:', this.selectedIds);
console.log('拼接后的ids参数:', ids);
console.log('请求URL:', 'http://192.168.101.127:8080/zhishu/orderExternalGoods/editWhetherOutbound');
console.log('请求方法:', 'POST');
console.log('请求数据:', {
ids: ids
});
console.log('==================');
// 调用接口 - 使用 $http 方法
const response = await this.$http({
url: 'https://api.buzhiyushu.cn/zhishu/orderExternalGoods/editWhetherOutbound',
method: 'POST',
data: `ids=${encodeURIComponent(ids)}`, // 直接传查询字符串
header: {
'Content-Type': 'application/x-www-form-urlencoded', // 关键
// 如果需要token
// 'Authorization': 'Bearer ' + uni.getStorageSync('token')
},
loading: true
});
console.log("出库状态", response)
if (response.code === 200) {
uni.showToast({
title: '出库成功',
icon: 'success'
});
// 退出选择模式并刷新列表
this.isSelectionMode = false;
this.selectedIds = [];
// 使用 handleSearch 刷新数据,确保应用当前筛选条件和排序
await this.handleSearch();
} else {
uni.showToast({
title: response.msg || '出库失败',
icon: 'none'
});
}
} catch (error) {
console.error('出库失败:', error);
uni.showToast({
title: '出库失败,请稍后重试',
icon: 'none'
});
}
}
}
}
</script>
<style scoped>
.container {
padding: 20rpx;
padding-bottom: 140rpx;
background-color: #f5f5f5;
min-height: 100vh;
position: relative;
}
/* 弹窗样式 */
.filter-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 999;
display: flex;
align-items: flex-end;
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.filter-popup-wrapper {
width: 100%;
height: 75vh;
display: flex;
flex-direction: column;
animation: slideUp 0.3s ease;
}
@keyframes slideUp {
from {
transform: translateY(100%);
}
to {
transform: translateY(0);
}
}
.filter-popup {
background-color: #fff;
border-radius: 20rpx 20rpx 0 0;
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
}
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-bottom: 1rpx solid #f0f0f0;
flex-shrink: 0;
}
.popup-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.popup-actions {
display: flex;
align-items: center;
gap: 30rpx;
}
.reset-text {
font-size: 28rpx;
color: #2b9939;
}
.close-text {
font-size: 36rpx;
color: #999;
width: 40rpx;
height: 40rpx;
display: flex;
align-items: center;
justify-content: center;
}
.filter-scroll {
flex: 1;
min-height: 0;
}
.filter-content {
padding: 30rpx;
}
.form-item {
margin-bottom: 30rpx;
}
.form-item:last-child {
margin-bottom: 0;
}
.label {
font-size: 28rpx;
color: #333;
margin-bottom: 16rpx;
font-weight: 500;
}
.input {
width: 100%;
height: 80rpx;
border: 1rpx solid #e0e0e0;
border-radius: 8rpx;
padding: 0 20rpx;
font-size: 28rpx;
box-sizing: border-box;
}
.picker-input {
display: flex;
justify-content: space-between;
align-items: center;
height: 80rpx;
border: 1rpx solid #e0e0e0;
border-radius: 8rpx;
padding: 0 20rpx;
font-size: 28rpx;
}
.placeholder {
color: #999;
}
.popup-footer {
padding: 0;
border-top: 1rpx solid #f0f0f0;
flex-shrink: 0;
background-color: #fff;
}
.footer-buttons {
padding: 20rpx 30rpx;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
display: flex;
gap: 20rpx;
}
.cancel-btn {
flex: 1;
height: 80rpx;
line-height: 80rpx;
background: #f5f5f5;
color: #666;
border: none;
border-radius: 40rpx;
font-size: 30rpx;
font-weight: 500;
}
.confirm-btn {
flex: 1;
height: 80rpx;
line-height: 80rpx;
background: linear-gradient(135deg, #6c757d 0%, #495057 100%);
color: #fff;
border: none;
border-radius: 40rpx;
font-size: 30rpx;
font-weight: bold;
}
/* 统计信息 */
.statistics {
padding: 20rpx;
display: flex;
align-items: center;
justify-content: space-between;
gap: 20rpx;
}
.total-text {
font-size: 26rpx;
color: #666;
flex-shrink: 0;
}
.sort-options {
display: flex;
gap: 10rpx;
flex-shrink: 0;
}
.sort-option {
padding: 8rpx 16rpx;
background: #f5f5f5;
border-radius: 20rpx;
transition: all 0.3s ease;
}
.sort-option.active {
background: linear-gradient(135deg, #2b9939 0%, #218838 100%);
}
.sort-option .sort-text {
font-size: 24rpx;
color: #666;
font-weight: 500;
}
.sort-option.active .sort-text {
color: #fff;
font-weight: bold;
}
.order-list {
margin-bottom: 20rpx;
}
.order-item {
background-color: #fff;
border-radius: 16rpx;
margin-bottom: 20rpx;
overflow: hidden;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
}
.order-content {
display: flex;
padding: 20rpx;
}
.order-left {
margin-right: 20rpx;
flex-shrink: 0;
position: relative;
}
.time-tag {
position: absolute;
top: -8rpx;
left: -8rpx;
color: #fff;
padding: 4rpx 12rpx;
border-radius: 12rpx;
font-size: 20rpx;
font-weight: bold;
z-index: 1;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.2);
}
.time-tag-24h {
background: linear-gradient(135deg, #ff1744 0%, #d50000 100%);
box-shadow: 0 2rpx 8rpx rgba(255, 23, 68, 0.5);
}
.time-tag-48h {
background: linear-gradient(135deg, #ff6b6b 0%, #ff5252 100%);
box-shadow: 0 2rpx 8rpx rgba(255, 107, 107, 0.4);
}
.time-tag-hidden {
display: none;
}
.time-tag-text {
font-size: 20rpx;
line-height: 1;
}
.goods-thumb {
width: 160rpx;
height: 160rpx;
border-radius: 12rpx;
background-color: #f5f5f5;
border: 1rpx solid #e0e0e0;
}
.goods-thumb-placeholder {
width: 160rpx;
height: 160rpx;
border-radius: 12rpx;
background-color: #f5f5f5;
border: 1rpx solid #e0e0e0;
display: flex;
align-items: center;
justify-content: center;
}
.placeholder-text {
font-size: 22rpx;
color: #999;
}
.order-time-tag {
margin-top: 8rpx;
text-align: center;
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
border-radius: 6rpx;
padding: 4rpx 8rpx;
}
.order-time-text {
font-size: 20rpx;
color: #666;
font-weight: 500;
}
.order-right {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.order-title {
font-size: 30rpx;
font-weight: bold;
color: #333;
margin-bottom: 16rpx;
line-height: 1.4;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
}
.order-info-row {
display: flex;
margin-bottom: 10rpx;
font-size: 26rpx;
}
.order-info-row:last-child {
margin-bottom: 0;
}
.info-label {
min-width: 140rpx;
color: #666;
font-weight: 500;
}
.info-value {
flex: 1;
color: #333;
font-weight: 500;
word-break: break-all;
}
.status-out {
color: #28a745;
font-weight: bold;
}
.status-not-out {
color: #dc3545;
font-weight: bold;
}
/* 订单状态样式 */
.status-pending-payment {
color: #ff9800;
font-weight: bold;
}
.status-pending-ship {
color: #2196f3;
font-weight: bold;
}
.status-shipped {
color: #9c27b0;
font-weight: bold;
}
.status-completed {
color: #4caf50;
font-weight: bold;
}
.status-refunded {
color: #f44336;
font-weight: bold;
}
.status-closed {
color: #9e9e9e;
font-weight: bold;
}
.status-after-sale {
color: #ff5722;
font-weight: bold;
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 120rpx 0;
}
.empty-icon {
font-size: 120rpx;
margin-bottom: 30rpx;
opacity: 0.5;
}
.empty-text {
font-size: 28rpx;
color: #999;
}
.loading-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 80rpx 0;
}
.loading-text {
font-size: 28rpx;
color: #666;
margin-top: 20rpx;
}
/* 批量操作样式 - 固定在底部 */
.batch-actions-fixed {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: #fff;
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1);
padding: 20rpx;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
z-index: 100;
}
.actions-row {
display: flex;
gap: 15rpx;
align-items: flex-start;
}
.filter-section {
flex: 0 0 auto;
display: flex;
flex-direction: column;
gap: 10rpx;
}
.batch-section {
flex: 1;
min-width: 0;
}
.filter-btn-bottom {
display: flex;
align-items: center;
justify-content: center;
gap: 8rpx;
background: linear-gradient(135deg, #6c757d 0%, #495057 100%);
color: #fff;
border: none;
border-radius: 8rpx;
padding: 24rpx 28rpx;
font-size: 28rpx;
font-weight: 500;
box-shadow: 0 4rpx 12rpx rgba(108, 117, 125, 0.3);
white-space: nowrap;
}
.filter-info {
display: flex;
align-items: center;
gap: 8rpx;
background: linear-gradient(135deg, #e8f7ed 0%, #f0f9f1 100%);
border-radius: 8rpx;
padding: 12rpx 16rpx;
border-left: 3rpx solid #2b9939;
}
.filter-info .filter-count {
background: #fff;
color: #2b9939;
font-size: 20rpx;
font-weight: bold;
padding: 4rpx 10rpx;
border-radius: 12rpx;
min-width: 32rpx;
text-align: center;
}
.filter-info .filter-time {
font-size: 22rpx;
color: #2b9939;
font-weight: 500;
}
.batch-btn {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
gap: 8rpx;
background: linear-gradient(135deg, #2b9939 0%, #218838 100%);
color: #fff;
border: none;
border-radius: 8rpx;
padding: 24rpx;
font-size: 30rpx;
font-weight: bold;
box-shadow: 0 4rpx 12rpx rgba(43, 153, 57, 0.3);
}
.selection-mode {
display: flex;
align-items: center;
gap: 15rpx;
}
.selected-count {
flex: 1;
font-size: 28rpx;
color: #333;
font-weight: 500;
text-align: center;
padding: 0 20rpx;
}
.cancel-btn-small {
flex: 1;
height: 70rpx;
line-height: 70rpx;
background: #f5f5f5;
color: #666;
border: none;
border-radius: 8rpx;
font-size: 28rpx;
font-weight: 500;
}
.confirm-btn-small {
flex: 1;
height: 70rpx;
line-height: 70rpx;
background: linear-gradient(135deg, #2b9939 0%, #218838 100%);
color: #fff;
border: none;
border-radius: 8rpx;
font-size: 28rpx;
font-weight: bold;
box-shadow: 0 4rpx 12rpx rgba(43, 153, 57, 0.3);
}
.confirm-btn-small.disabled {
opacity: 0.5;
background: #ccc;
box-shadow: none;
}
/* 选择模式下的样式 */
.selection-mode-active {
position: relative;
}
.checkbox-wrapper {
display: flex;
align-items: center;
justify-content: center;
margin-right: 15rpx;
flex-shrink: 0;
}
.checkbox {
width: 40rpx;
height: 40rpx;
border: 2rpx solid #d0d0d0;
border-radius: 50%;
background-color: #fff;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
}
.checkbox.checked {
background: linear-gradient(135deg, #2b9939 0%, #218838 100%);
border-color: #2b9939;
}
.order-item.selection-mode-active {
cursor: pointer;
}
.order-item.selection-mode-active:active {
background-color: #f8f8f8;
}
</style>