feat(store-orders): 增强订单页支持搜索及重构Tab
- 将订单列表底部时间显示格式由只含日期改为显示至分钟的完整时间 - 门店订单页新增搜索功能,支持订单号、手机号、昵称等多字段模糊匹配 - 实现单个搜索框叠加于当前Tab内,切Tab及搜索提交自动刷新订单列表 - 调整ScrollView高度以适配搜索栏新增布局 - 优化订单Tab结构,由“全部/已完成/已关闭”改为“待处理/已完成/已关闭” - 待处理Tab合并待付款、待发货、待核销、待收货多状态订单 - 去除原“全部”Tab,默认激活改为“待处理”Tab - 新订单角标由“全部”Tab迁移到“待处理”Tab显示 - 搜索无结果时显示“未找到与‘xxx’相关的订单”提示 - 确保后端筛选与前端Tab状态映射一致,提升用户体验
This commit is contained in:
@@ -20,3 +20,15 @@
|
||||
|
||||
`pages/order/list` 列表卡片(`OrderCard`)底部日期原为 `order.createTime?.slice(0, 10)`(仅显示 YYYY-MM-DD)。
|
||||
改为 `order.createTime?.replace('T', ' ').slice(0, 16)`,显示「下单时间: YYYY-MM-DD HH:mm」,`replace('T',' ')` 兼容后端 ISO(T 分隔)与空格分隔两种时间格式。
|
||||
|
||||
## 门店订单页增加搜索功能(pages/store/orders/index.tsx)
|
||||
|
||||
方案(已与用户确认):单个搜索框 + 在当前 Tab 内叠加筛选,无需改后端、无需改类型定义。
|
||||
|
||||
实现要点:
|
||||
- 新增 `searchInput`(受控输入)、`searchKeyword`(已提交搜索词)两个 state。
|
||||
- `loadOrders` 每个 `pageShopOrder` 请求附带 `keywords: searchKeyword || undefined`(后端 `keywords` 已支持订单号/订单ID/手机号/昵称/备注组合模糊搜索);`useCallback` 依赖加 `searchKeyword`,切 Tab/提交搜索自动重加载。
|
||||
- 触发:点「搜索」按钮 / 键盘回车(`onConfirm` + `confirmType='search'`)/ 点「×」清空。
|
||||
- 搜索无结果显示「未找到与"xxx"相关的订单」,否则「暂无订单」。
|
||||
- ScrollView 高度由 `calc(100vh - 50px)` 改为 `calc(100vh - 100px)`(为新增搜索栏留位)。
|
||||
- 注意:后端「全部」Tab 默认隐藏已关闭单(`statusFilter != 8` 加 `order_status != 2`),搜已关闭单需切到「已关闭」Tab。手机号在 keywords 里是精确匹配(`b.phone =`),订单号支持部分匹配。
|
||||
|
||||
@@ -50,5 +50,17 @@
|
||||
2. `sms-login.tsx`:`loginBySms` 后加 `syncFromStorage()` 同步状态
|
||||
3. 防御性措施:`cart.tsx`、`product-detail.tsx`、`index/index.tsx` 的 `useDidShow` 加 `syncFromStorage()` 确保页面显示时从 storage 同步用户状态
|
||||
|
||||
## 门店订单页 Tab 改造(src/pages/store/orders/index.tsx)
|
||||
- **需求**:原「全部 / 已完成 / 已关闭」Tab 改为「待处理 / 已完成 / 已关闭」
|
||||
- 待处理 = 待付款(0) + 待发货(1) + 待核销(2) + 待收货(3),按用户确认把待核销(2)也并入
|
||||
- 已完成 = statusFilter 5(不变);已关闭 = statusFilter 8(不变)
|
||||
- **TabKey 类型**:`'all' | 'pending' | 'completed'` → `'pending' | 'completed' | 'closed'`
|
||||
- **TABS 配置**:删除原「全部」无筛选 Tab;待处理用 params 数组 `[{statusFilter:0},{1},{2},{3}]` 并行请求合并去重(loadOrders 已支持)
|
||||
- **默认选中**:`useState<TabKey>('all')` → `'pending'`
|
||||
- **新订单角标**:`tab.key === 'all'` → `tab.key === 'pending'`(移到待处理 Tab)
|
||||
- **statusFilter 后端映射参考**(ShopOrderMapper.xml 第240-282行):0待支付=未付款、1待发货=pay1&delivery10&order0、2待核销=pay1&order0、3待收货=delivery20&order!=1、5已完成=order1、8已取消=order2
|
||||
- **验证**:tsc 仅剩预存 `@tarojs/taro` 类型缺失环境报错,本文件无新错误
|
||||
- ⚠️ 注意:原「全部」Tab 显示的「待评价(statusFilter=4)」订单在改版后无 Tab 承接(用户确认不含待评价),如需可见后续可并入待处理
|
||||
|
||||
### 验证
|
||||
- `npx taro build --type weapp` 构建成功
|
||||
|
||||
@@ -13,16 +13,16 @@ definePageConfig({
|
||||
navigationBarTitleText: '订单管理',
|
||||
})
|
||||
|
||||
// ─── Tab 配置(全部 + 待处理 + 已完成)──────────────────────────
|
||||
type TabKey = 'all' | 'pending' | 'completed'
|
||||
// ─── Tab 配置(待处理 + 已完成 + 已关闭)──────────────────────────
|
||||
type TabKey = 'pending' | 'completed' | 'closed'
|
||||
|
||||
const TABS: { key: TabKey; label: string; params: Partial<ShopOrderParam>[] }[] = [
|
||||
// 全部:不传 statusFilter
|
||||
{key: 'all', label: '全部', params: [{}]},
|
||||
// 待处理:合并 statusFilter=0(待付款)、1(待发货)、2(待核销)、3(待收货)
|
||||
{key: 'pending', label: '待处理', params: [{statusFilter: 0}, {statusFilter: 1}, {statusFilter: 2}, {statusFilter: 3}]},
|
||||
// 已完成:statusFilter=5(与后台管理一致)
|
||||
{key: 'completed', label: '已完成', params: [{statusFilter: 5}]},
|
||||
// 待处理:已关闭订单 statusFilter=8
|
||||
{key: 'pending', label: '已关闭', params: [{statusFilter: 8}]},
|
||||
// 已关闭:statusFilter=8
|
||||
{key: 'closed', label: '已关闭', params: [{statusFilter: 8}]},
|
||||
]
|
||||
|
||||
// ─── 操作类型 ─────────────────────────────────────────────────────
|
||||
@@ -140,7 +140,7 @@ function getOrderActions(order: ShopOrder): { label: string; type: OpType }[] {
|
||||
|
||||
// ─── 页面组件 ──────────────────────────────────────────────────────
|
||||
export default function StoreOrdersPage() {
|
||||
const [activeTab, setActiveTab] = useState<TabKey>('all')
|
||||
const [activeTab, setActiveTab] = useState<TabKey>('pending')
|
||||
|
||||
// 订单列表与分页
|
||||
const [orderList, setOrderList] = useState<ShopOrder[]>([])
|
||||
@@ -161,6 +161,10 @@ export default function StoreOrdersPage() {
|
||||
const [editPayPrice, setEditPayPrice] = useState('')
|
||||
const [editReason, setEditReason] = useState('')
|
||||
|
||||
// 搜索:searchInput 受控输入框,searchKeyword 为已提交的搜索词
|
||||
const [searchInput, setSearchInput] = useState('')
|
||||
const [searchKeyword, setSearchKeyword] = useState('')
|
||||
|
||||
const pageSize = 10
|
||||
const loadingRef = useRef(false)
|
||||
|
||||
@@ -214,7 +218,7 @@ export default function StoreOrdersPage() {
|
||||
|
||||
// 并行请求所有 params 组合,合并去重
|
||||
const allRequests = tabConfig.params.map(p =>
|
||||
pageShopOrder({...p, page: pageNo, limit: pageSize})
|
||||
pageShopOrder({...p, page: pageNo, limit: pageSize, keywords: searchKeyword || undefined})
|
||||
)
|
||||
const allResults = await Promise.all(allRequests)
|
||||
|
||||
@@ -248,7 +252,7 @@ export default function StoreOrdersPage() {
|
||||
loadingRef.current = false
|
||||
setLoading(false)
|
||||
}
|
||||
}, [])
|
||||
}, [searchKeyword])
|
||||
|
||||
// 切换 tab 时重新加载
|
||||
useEffect(() => {
|
||||
@@ -267,6 +271,17 @@ export default function StoreOrdersPage() {
|
||||
}
|
||||
}
|
||||
|
||||
/** 提交搜索(点击搜索按钮或键盘回车) */
|
||||
const handleSearch = () => {
|
||||
setSearchKeyword(searchInput.trim())
|
||||
}
|
||||
|
||||
/** 清空搜索 */
|
||||
const handleClearSearch = () => {
|
||||
setSearchInput('')
|
||||
setSearchKeyword('')
|
||||
}
|
||||
|
||||
/** 打开操作弹窗 */
|
||||
const openModal = (order: ShopOrder, type: OpType) => {
|
||||
setCurrentOrder(order)
|
||||
@@ -581,6 +596,31 @@ export default function StoreOrdersPage() {
|
||||
|
||||
return (
|
||||
<View className='min-h-full bg-gray-50'>
|
||||
{/* 搜索栏 */}
|
||||
<View className='bg-white px-3 py-2 flex items-center'>
|
||||
<View className='flex-1 flex items-center bg-gray-100 rounded-full px-3 h-9'>
|
||||
<Input
|
||||
className='flex-1 text-sm text-gray-800'
|
||||
value={searchInput}
|
||||
onInput={(e) => setSearchInput(e.detail.value)}
|
||||
onConfirm={handleSearch}
|
||||
placeholder='搜索订单号 / 手机号 / 昵称'
|
||||
confirmType='search'
|
||||
/>
|
||||
{searchInput ? (
|
||||
<View
|
||||
className='ml-2 w-5 h-5 flex items-center justify-center'
|
||||
onClick={handleClearSearch}
|
||||
>
|
||||
<Text className='text-gray-400 text-base leading-none'>×</Text>
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
<View className='ml-1 px-2 py-1' onClick={handleSearch}>
|
||||
<Text className='text-sm text-green-500 font-medium'>搜索</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Tab 栏 */}
|
||||
<View className='bg-white flex'>
|
||||
{TABS.map(tab => (
|
||||
@@ -598,8 +638,8 @@ export default function StoreOrdersPage() {
|
||||
className={`text-sm ${activeTab === tab.key ? 'text-green-500 font-medium' : 'text-gray-500'}`}>
|
||||
{tab.label}
|
||||
</Text>
|
||||
{/* 新订单角标:在"全部"Tab 上显示 */}
|
||||
{tab.key === 'all' && newOrderCount > 0 && (
|
||||
{/* 新订单角标:在"待处理"Tab 上显示 */}
|
||||
{tab.key === 'pending' && newOrderCount > 0 && (
|
||||
<View className='absolute -top-0.5 right-2 min-w-[18px] h-[18px] rounded-full bg-red-500 flex items-center justify-center px-1'>
|
||||
<Text className='text-white text-[10px] font-bold'>
|
||||
{newOrderCount > 99 ? '99+' : newOrderCount}
|
||||
@@ -613,7 +653,7 @@ export default function StoreOrdersPage() {
|
||||
{/* 订单列表 */}
|
||||
<ScrollView
|
||||
scrollY
|
||||
style={{height: 'calc(100vh - 50px)'}}
|
||||
style={{height: 'calc(100vh - 100px)'}}
|
||||
onScrollToLower={handleLoadMore}
|
||||
lowerThreshold={100}
|
||||
>
|
||||
@@ -623,7 +663,9 @@ export default function StoreOrdersPage() {
|
||||
</View>
|
||||
) : orderList.length === 0 ? (
|
||||
<View className='flex justify-center items-center py-20'>
|
||||
<Text className='text-gray-400'>暂无订单</Text>
|
||||
<Text className='text-gray-400'>
|
||||
{searchKeyword ? `未找到与“${searchKeyword}”相关的订单` : '暂无订单'}
|
||||
</Text>
|
||||
</View>
|
||||
) : (
|
||||
orderList.map(renderOrderCard)
|
||||
|
||||
Reference in New Issue
Block a user