forked from gxwebsoft/mp-10550
feat(store): 添加门店管理功能和订单配送功能
- 在app.config.ts中添加门店相关路由配置 - 在config/app.ts中添加租户名称常量 - 在Header.tsx中实现门店选择功能,包括定位、距离计算和门店切换 - 更新ShopOrder模型,添加门店ID、门店名称、配送员ID和仓库ID字段 - 新增ShopStore相关API和服务,支持门店的增删改查 - 新增ShopStoreRider相关API和服务,支持配送员管理 - 新增ShopStoreUser相关API和服务,支持店员管理 - 新增ShopWarehouse相关API和服务,支持仓库管理 - 添加配送订单页面,支持订单状态管理和送达确认功能 - 优化经销商页面的样式布局
This commit is contained in:
@@ -89,6 +89,12 @@ interface OrderListProps {
|
||||
searchParams?: ShopOrderParam;
|
||||
showSearch?: boolean;
|
||||
onSearchParamsChange?: (params: ShopOrderParam) => void; // 新增:通知父组件参数变化
|
||||
// 订单视图模式:用户/门店/骑手
|
||||
mode?: 'user' | 'store' | 'rider';
|
||||
// 固定过滤条件(例如 storeId / riderId),会合并到每次请求里
|
||||
baseParams?: ShopOrderParam;
|
||||
// 只读模式:隐藏“支付/取消/确认收货/退款”等用户操作按钮
|
||||
readOnly?: boolean;
|
||||
}
|
||||
|
||||
function OrderList(props: OrderListProps) {
|
||||
@@ -115,6 +121,7 @@ function OrderList(props: OrderListProps) {
|
||||
const [orderToCancel, setOrderToCancel] = useState<ShopOrder | null>(null)
|
||||
const [confirmReceiveDialogVisible, setConfirmReceiveDialogVisible] = useState(false)
|
||||
const [orderToConfirmReceive, setOrderToConfirmReceive] = useState<ShopOrder | null>(null)
|
||||
const isReadOnly = props.readOnly || props.mode === 'store' || props.mode === 'rider'
|
||||
|
||||
// 获取订单状态文本
|
||||
const getOrderStatusText = (order: ShopOrder) => {
|
||||
@@ -131,8 +138,14 @@ function OrderList(props: OrderListProps) {
|
||||
|
||||
// 已付款后检查发货状态
|
||||
if (order.deliveryStatus === 10) return '待发货';
|
||||
if (order.deliveryStatus === 20) return '待收货';
|
||||
if (order.deliveryStatus === 30) return '已完成';
|
||||
if (order.deliveryStatus === 20) {
|
||||
// 若订单没有配送员,沿用原“待收货”语义
|
||||
if (!order.riderId) return '待收货';
|
||||
// 配送员确认送达后(sendEndTime有值),才进入“待确认收货”
|
||||
if (order.sendEndTime && order.orderStatus !== 1) return '待确认收货';
|
||||
return '配送中';
|
||||
}
|
||||
if (order.deliveryStatus === 30) return '部分发货';
|
||||
|
||||
// 最后检查订单完成状态
|
||||
if (order.orderStatus === 1) return '已完成';
|
||||
@@ -155,8 +168,12 @@ function OrderList(props: OrderListProps) {
|
||||
|
||||
// 已付款后检查发货状态
|
||||
if (order.deliveryStatus === 10) return 'text-blue-500'; // 待发货
|
||||
if (order.deliveryStatus === 20) return 'text-purple-500'; // 待收货
|
||||
if (order.deliveryStatus === 30) return 'text-green-500'; // 已收货
|
||||
if (order.deliveryStatus === 20) {
|
||||
if (!order.riderId) return 'text-purple-500'; // 待收货
|
||||
if (order.sendEndTime && order.orderStatus !== 1) return 'text-purple-500'; // 待确认收货
|
||||
return 'text-blue-500'; // 配送中
|
||||
}
|
||||
if (order.deliveryStatus === 30) return 'text-blue-500'; // 部分发货
|
||||
|
||||
// 最后检查订单完成状态
|
||||
if (order.orderStatus === 1) return 'text-green-600'; // 已完成
|
||||
@@ -167,9 +184,13 @@ function OrderList(props: OrderListProps) {
|
||||
|
||||
// 使用后端统一的 statusFilter 进行筛选
|
||||
const getOrderStatusParams = (index: string | number) => {
|
||||
let params: ShopOrderParam = {};
|
||||
// 添加用户ID过滤
|
||||
params.userId = Taro.getStorageSync('UserId');
|
||||
let params: ShopOrderParam = {
|
||||
...(props.baseParams || {})
|
||||
};
|
||||
// 默认是用户视图:添加 userId 过滤;门店/骑手视图由 baseParams 控制
|
||||
if (!props.mode || props.mode === 'user') {
|
||||
params.userId = Taro.getStorageSync('UserId');
|
||||
}
|
||||
|
||||
// 获取当前tab的statusFilter配置
|
||||
const currentTab = tabs.find(tab => tab.index === Number(index));
|
||||
@@ -190,7 +211,7 @@ function OrderList(props: OrderListProps) {
|
||||
// 合并搜索条件,tab的statusFilter优先级更高
|
||||
const searchConditions: any = {
|
||||
page: currentPage,
|
||||
userId: statusParams.userId, // 用户ID
|
||||
...statusParams,
|
||||
...props.searchParams, // 搜索关键词等其他条件
|
||||
};
|
||||
|
||||
@@ -285,7 +306,7 @@ function OrderList(props: OrderListProps) {
|
||||
|
||||
await updateShopOrder({
|
||||
...orderToConfirmReceive,
|
||||
deliveryStatus: 20, // 已收货
|
||||
deliveryStatus: orderToConfirmReceive.deliveryStatus, // 10未发货 20已发货 30部分发货(收货由orderStatus控制)
|
||||
orderStatus: 1 // 已完成
|
||||
});
|
||||
|
||||
@@ -764,6 +785,7 @@ function OrderList(props: OrderListProps) {
|
||||
<Text className={'w-full text-right'}>实付金额:¥{item.payPrice}</Text>
|
||||
|
||||
{/* 操作按钮 */}
|
||||
{!isReadOnly && (
|
||||
<Space className={'btn flex justify-end'}>
|
||||
{/* 待付款状态:显示取消订单和立即支付 */}
|
||||
{(!item.payStatus) && item.orderStatus !== 2 && (
|
||||
@@ -788,7 +810,7 @@ function OrderList(props: OrderListProps) {
|
||||
)}
|
||||
|
||||
{/* 待收货状态:显示查看物流和确认收货 */}
|
||||
{item.deliveryStatus === 20 && item.orderStatus !== 2 && (
|
||||
{item.deliveryStatus === 20 && (!item.riderId || !!item.sendEndTime) && item.orderStatus !== 2 && (
|
||||
<Space>
|
||||
<Button size={'small'} onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
@@ -837,6 +859,7 @@ function OrderList(props: OrderListProps) {
|
||||
}}>再次购买</Button>
|
||||
)}
|
||||
</Space>
|
||||
)}
|
||||
</Space>
|
||||
</Cell>
|
||||
)
|
||||
|
||||
4
src/user/store/orders/index.config.ts
Normal file
4
src/user/store/orders/index.config.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export default {
|
||||
navigationBarTitleText: '门店订单',
|
||||
navigationBarTextStyle: 'black'
|
||||
}
|
||||
73
src/user/store/orders/index.tsx
Normal file
73
src/user/store/orders/index.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import {useEffect, useMemo, useState} from 'react'
|
||||
import Taro from '@tarojs/taro'
|
||||
import {NavBar, Button} from '@nutui/nutui-react-taro'
|
||||
import {ArrowLeft} from '@nutui/icons-react-taro'
|
||||
import {View, Text} from '@tarojs/components'
|
||||
import OrderList from '@/user/order/components/OrderList'
|
||||
import {getSelectedStoreFromStorage} from '@/utils/storeSelection'
|
||||
import {listShopStoreUser} from '@/api/shop/shopStoreUser'
|
||||
|
||||
export default function StoreOrders() {
|
||||
const [statusBarHeight, setStatusBarHeight] = useState<number>(0)
|
||||
|
||||
const [boundStoreId, setBoundStoreId] = useState<number | undefined>(undefined)
|
||||
const store = useMemo(() => getSelectedStoreFromStorage(), [])
|
||||
const storeId = boundStoreId || store?.id
|
||||
|
||||
useEffect(() => {
|
||||
Taro.getSystemInfo({
|
||||
success: (res) => setStatusBarHeight(res.statusBarHeight ?? 0)
|
||||
})
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
// 优先按“店员绑定关系”确定门店归属:门店看到的是自己的订单
|
||||
const userId = Number(Taro.getStorageSync('UserId'))
|
||||
if (!Number.isFinite(userId) || userId <= 0) return
|
||||
listShopStoreUser({userId}).then(list => {
|
||||
const first = (list || []).find(i => i?.isDelete !== 1 && i?.storeId)
|
||||
if (first?.storeId) setBoundStoreId(first.storeId)
|
||||
}).catch(() => {
|
||||
// fallback to SelectedStore
|
||||
})
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<View className="bg-gray-50 min-h-screen">
|
||||
<View style={{height: `${statusBarHeight || 0}px`, backgroundColor: '#ffffff'}}></View>
|
||||
<NavBar
|
||||
fixed
|
||||
style={{marginTop: `${statusBarHeight || 0}px`, backgroundColor: '#ffffff'}}
|
||||
left={<ArrowLeft onClick={() => Taro.navigateBack()}/>}
|
||||
>
|
||||
<span>门店订单</span>
|
||||
</NavBar>
|
||||
|
||||
<View className="pt-14 px-3">
|
||||
<View className="bg-white rounded-lg p-3 mb-3">
|
||||
<Text className="text-sm text-gray-600">当前门店:</Text>
|
||||
<Text className="text-base font-medium">{store?.name || (boundStoreId ? `门店ID: ${boundStoreId}` : '未选择门店')}</Text>
|
||||
</View>
|
||||
|
||||
{!storeId ? (
|
||||
<View className="bg-white rounded-lg p-4">
|
||||
<Text className="text-sm text-gray-600">
|
||||
请先在首页左上角选择门店,再查看门店订单。
|
||||
</Text>
|
||||
<View className="mt-3">
|
||||
<Button
|
||||
type="primary"
|
||||
size="small"
|
||||
onClick={() => Taro.switchTab({url: '/pages/index/index'})}
|
||||
>
|
||||
去首页选择门店
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
) : (
|
||||
<OrderList mode="store" baseParams={{storeId}} readOnly />
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user