功能:增加订单搜索与状态筛选
This commit is contained in:
@@ -89,9 +89,9 @@ func (h *MerchantHandler) UpdateProductStatus(c *gin.Context) {
|
|||||||
func (h *MerchantHandler) ListOrders(c *gin.Context) {
|
func (h *MerchantHandler) ListOrders(c *gin.Context) {
|
||||||
page, size := pageParams(c)
|
page, size := pageParams(c)
|
||||||
orderSource := strings.TrimSpace(c.Query("order_source"))
|
orderSource := strings.TrimSpace(c.Query("order_source"))
|
||||||
list, total, err := h.fulfillmentSvc.ListOrders(middleware.GetMerchantID(c), page, size, c.Query("order_status"), orderSource)
|
list, total, err := h.fulfillmentSvc.ListOrders(middleware.GetMerchantID(c), page, size, c.Query("order_status"), orderSource, c.Query("keyword"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if orderSource != "" && err.Error() == "无效的订单来源" {
|
if err.Error() == "无效的订单来源" || err.Error() == "无效的订单状态" {
|
||||||
response.BadRequest(c, err.Error())
|
response.BadRequest(c, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"affiliate_dash/internal/model"
|
"affiliate_dash/internal/model"
|
||||||
@@ -23,10 +24,15 @@ func (s *FulfillmentService) GetOrder(merchantID uint, orderNo string) (*model.F
|
|||||||
return &order, nil
|
return &order, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *FulfillmentService) ListOrders(merchantID uint, page, size int, orderStatus, orderSource string) ([]model.FulfillmentOrder, int64, error) {
|
func (s *FulfillmentService) ListOrders(merchantID uint, page, size int, orderStatus, orderSource, keyword string) ([]model.FulfillmentOrder, int64, error) {
|
||||||
page, size = normalizePage(page, size)
|
page, size = normalizePage(page, size)
|
||||||
tx := s.db.Model(&model.FulfillmentOrder{}).Where("merchant_id = ?", merchantID)
|
tx := s.db.Model(&model.FulfillmentOrder{}).Where("merchant_id = ?", merchantID)
|
||||||
if orderStatus != "" {
|
if orderStatus != "" {
|
||||||
|
switch orderStatus {
|
||||||
|
case model.OrderStatusPaid, model.OrderStatusDelivering, model.OrderStatusDelivered, model.OrderStatusShipFailed, model.OrderStatusCancelled:
|
||||||
|
default:
|
||||||
|
return nil, 0, errors.New("无效的订单状态")
|
||||||
|
}
|
||||||
tx = tx.Where("order_status = ?", orderStatus)
|
tx = tx.Where("order_status = ?", orderStatus)
|
||||||
}
|
}
|
||||||
if orderSource != "" {
|
if orderSource != "" {
|
||||||
@@ -37,6 +43,10 @@ func (s *FulfillmentService) ListOrders(merchantID uint, page, size int, orderSt
|
|||||||
return nil, 0, errors.New("无效的订单来源")
|
return nil, 0, errors.New("无效的订单来源")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if keyword = strings.TrimSpace(keyword); keyword != "" {
|
||||||
|
like := "%" + keyword + "%"
|
||||||
|
tx = tx.Where("order_no LIKE ? OR client_order_no LIKE ?", like, like)
|
||||||
|
}
|
||||||
var total int64
|
var total int64
|
||||||
if err := tx.Count(&total).Error; err != nil {
|
if err := tx.Count(&total).Error; err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ export default function MerchantCenter({ fixedTab, title = '商户中心' }: Mer
|
|||||||
const [products, setProducts] = useState<PageResult<MerchantProduct>>({ list: [], total: 0, page: 1, size: 10 })
|
const [products, setProducts] = useState<PageResult<MerchantProduct>>({ list: [], total: 0, page: 1, size: 10 })
|
||||||
const [orders, setOrders] = useState<PageResult<FulfillmentOrder>>({ list: [], total: 0, page: 1, size: 10 })
|
const [orders, setOrders] = useState<PageResult<FulfillmentOrder>>({ list: [], total: 0, page: 1, size: 10 })
|
||||||
const [orderSource, setOrderSource] = useState<'api' | 'manual'>('api')
|
const [orderSource, setOrderSource] = useState<'api' | 'manual'>('api')
|
||||||
|
const [orderFilters, setOrderFilters] = useState<{ keyword: string; order_status: string }>({ keyword: '', order_status: '' })
|
||||||
const [ledger, setLedger] = useState<PageResult<WalletLedgerEntry>>({ list: [], total: 0, page: 1, size: 10 })
|
const [ledger, setLedger] = useState<PageResult<WalletLedgerEntry>>({ list: [], total: 0, page: 1, size: 10 })
|
||||||
const [wallet, setWallet] = useState<WalletAccount | null>(null)
|
const [wallet, setWallet] = useState<WalletAccount | null>(null)
|
||||||
const [apiClients, setApiClients] = useState<ApiClient[]>([])
|
const [apiClients, setApiClients] = useState<ApiClient[]>([])
|
||||||
@@ -163,10 +164,15 @@ export default function MerchantCenter({ fixedTab, title = '商户中心' }: Mer
|
|||||||
setProducts(data)
|
setProducts(data)
|
||||||
}, [products.page, products.size])
|
}, [products.page, products.size])
|
||||||
|
|
||||||
const loadOrders = useCallback(async (page = orders.page, size = orders.size, source = orderSource) => {
|
const loadOrders = useCallback(async (
|
||||||
const data = await merchantApi.orders({ page, size, order_source: source })
|
page = orders.page,
|
||||||
|
size = orders.size,
|
||||||
|
source = orderSource,
|
||||||
|
filters = orderFilters,
|
||||||
|
) => {
|
||||||
|
const data = await merchantApi.orders({ page, size, order_source: source, ...filters })
|
||||||
setOrders(data)
|
setOrders(data)
|
||||||
}, [orderSource, orders.page, orders.size])
|
}, [orderFilters, orderSource, orders.page, orders.size])
|
||||||
|
|
||||||
const loadWallet = useCallback(async (
|
const loadWallet = useCallback(async (
|
||||||
page = ledger.page,
|
page = ledger.page,
|
||||||
@@ -341,7 +347,12 @@ export default function MerchantCenter({ fixedTab, title = '商户中心' }: Mer
|
|||||||
|
|
||||||
const changeOrderSource = (source: 'api' | 'manual') => {
|
const changeOrderSource = (source: 'api' | 'manual') => {
|
||||||
setOrderSource(source)
|
setOrderSource(source)
|
||||||
loadOrders(1, orders.size, source).catch((e) => message.error(e instanceof Error ? e.message : '订单加载失败'))
|
loadOrders(1, orders.size, source, orderFilters).catch((e) => message.error(e instanceof Error ? e.message : '订单加载失败'))
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeOrderFilters = (filters: { keyword: string; order_status: string }) => {
|
||||||
|
setOrderFilters(filters)
|
||||||
|
loadOrders(1, orders.size, orderSource, filters).catch((e) => message.error(e instanceof Error ? e.message : '订单加载失败'))
|
||||||
}
|
}
|
||||||
|
|
||||||
const submitAPIClient = async () => {
|
const submitAPIClient = async () => {
|
||||||
@@ -499,7 +510,7 @@ export default function MerchantCenter({ fixedTab, title = '商户中心' }: Mer
|
|||||||
<ProductsTab loading={loading} products={products} canManage={canManage} onToggleProduct={openProductToggle} onLoadProducts={loadProducts} />
|
<ProductsTab loading={loading} products={products} canManage={canManage} onToggleProduct={openProductToggle} onLoadProducts={loadProducts} />
|
||||||
) },
|
) },
|
||||||
{ key: 'orders', label: '发货订单', disabled: !hasFeature('orders'), children: (
|
{ key: 'orders', label: '发货订单', disabled: !hasFeature('orders'), children: (
|
||||||
<OrdersTab loading={loading} orders={orders} orderSource={orderSource} canManage={canOrderManage} onCreateManualOrder={openManualOrderCreate} onOrderSourceChange={changeOrderSource} onLoadOrders={loadOrders} onCopyLink={copyDeliveryLink} onOpenLink={openDeliveryLink} onRevokeLink={revokeDeliveryLink} onRestoreLink={restoreDeliveryLink} />
|
<OrdersTab loading={loading} orders={orders} orderSource={orderSource} filters={orderFilters} canManage={canOrderManage} onCreateManualOrder={openManualOrderCreate} onOrderSourceChange={changeOrderSource} onFilterChange={changeOrderFilters} onLoadOrders={loadOrders} onCopyLink={copyDeliveryLink} onOpenLink={openDeliveryLink} onRevokeLink={revokeDeliveryLink} onRestoreLink={restoreDeliveryLink} />
|
||||||
) },
|
) },
|
||||||
{ key: 'wallet', label: '钱包', disabled: !hasFeature('wallet'), children: (
|
{ key: 'wallet', label: '钱包', disabled: !hasFeature('wallet'), children: (
|
||||||
<WalletTab loading={loading} wallet={wallet} canFinance={canFinance} ledger={ledger} form={walletFilterForm} onFilter={handleWalletFilter} onResetFilter={handleWalletFilterReset} onLoadLedger={handleLoadLedger} />
|
<WalletTab loading={loading} wallet={wallet} canFinance={canFinance} ledger={ledger} form={walletFilterForm} onFilter={handleWalletFilter} onResetFilter={handleWalletFilterReset} onLoadLedger={handleLoadLedger} />
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { useEffect, useState } from 'react'
|
||||||
import { Button, Card, Col, Form, Input, Popconfirm, Row, Select, Space, Table, Tabs, Tag, Typography, message } from 'antd'
|
import { Button, Card, Col, Form, Input, Popconfirm, Row, Select, Space, Table, Tabs, Tag, Typography, message } from 'antd'
|
||||||
import type { FormInstance } from 'antd'
|
import type { FormInstance } from 'antd'
|
||||||
import {
|
import {
|
||||||
@@ -30,6 +31,7 @@ import {
|
|||||||
defaultCallbackFormValues,
|
defaultCallbackFormValues,
|
||||||
eventOptions,
|
eventOptions,
|
||||||
money,
|
money,
|
||||||
|
orderStatusOptions,
|
||||||
orderStatusMap,
|
orderStatusMap,
|
||||||
pageConfig,
|
pageConfig,
|
||||||
rolePermissionText,
|
rolePermissionText,
|
||||||
@@ -171,9 +173,11 @@ export function OrdersTab({
|
|||||||
loading,
|
loading,
|
||||||
orders,
|
orders,
|
||||||
orderSource,
|
orderSource,
|
||||||
|
filters,
|
||||||
canManage,
|
canManage,
|
||||||
onCreateManualOrder,
|
onCreateManualOrder,
|
||||||
onOrderSourceChange,
|
onOrderSourceChange,
|
||||||
|
onFilterChange,
|
||||||
onLoadOrders,
|
onLoadOrders,
|
||||||
onCopyLink,
|
onCopyLink,
|
||||||
onOpenLink,
|
onOpenLink,
|
||||||
@@ -183,15 +187,25 @@ export function OrdersTab({
|
|||||||
loading: boolean
|
loading: boolean
|
||||||
orders: PageResult<FulfillmentOrder>
|
orders: PageResult<FulfillmentOrder>
|
||||||
orderSource: 'api' | 'manual'
|
orderSource: 'api' | 'manual'
|
||||||
|
filters: { keyword: string; order_status: string }
|
||||||
canManage: boolean
|
canManage: boolean
|
||||||
onCreateManualOrder: () => void
|
onCreateManualOrder: () => void
|
||||||
onOrderSourceChange: (source: 'api' | 'manual') => void
|
onOrderSourceChange: (source: 'api' | 'manual') => void
|
||||||
|
onFilterChange: (filters: { keyword: string; order_status: string }) => void
|
||||||
onLoadOrders: (page?: number, size?: number) => void
|
onLoadOrders: (page?: number, size?: number) => void
|
||||||
onCopyLink: (orderNo: string) => void
|
onCopyLink: (orderNo: string) => void
|
||||||
onOpenLink: (orderNo: string) => void
|
onOpenLink: (orderNo: string) => void
|
||||||
onRevokeLink: (orderNo: string) => void
|
onRevokeLink: (orderNo: string) => void
|
||||||
onRestoreLink: (orderNo: string) => void
|
onRestoreLink: (orderNo: string) => void
|
||||||
}) {
|
}) {
|
||||||
|
const [keyword, setKeyword] = useState(filters.keyword)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setKeyword(filters.keyword)
|
||||||
|
}, [filters.keyword])
|
||||||
|
|
||||||
|
const submitKeyword = () => onFilterChange({ ...filters, keyword: keyword.trim() })
|
||||||
|
|
||||||
const orderColumns: ColumnsType<FulfillmentOrder> = [
|
const orderColumns: ColumnsType<FulfillmentOrder> = [
|
||||||
{
|
{
|
||||||
title: '平台订单号',
|
title: '平台订单号',
|
||||||
@@ -253,6 +267,33 @@ export function OrdersTab({
|
|||||||
</Space>
|
</Space>
|
||||||
)}
|
)}
|
||||||
</Space>
|
</Space>
|
||||||
|
<Card size="small" style={{ borderRadius: 8 }}>
|
||||||
|
<Space direction="vertical" size="middle" style={{ width: '100%' }}>
|
||||||
|
<Space wrap>
|
||||||
|
<Input.Search
|
||||||
|
value={keyword}
|
||||||
|
onChange={(event) => setKeyword(event.target.value)}
|
||||||
|
onSearch={submitKeyword}
|
||||||
|
placeholder="搜索平台订单号或商户单号"
|
||||||
|
allowClear
|
||||||
|
onClear={() => onFilterChange({ ...filters, keyword: '' })}
|
||||||
|
style={{ width: 300, maxWidth: '100%' }}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
<Space wrap size={[8, 8]}>
|
||||||
|
{orderStatusOptions.map((option) => (
|
||||||
|
<Button
|
||||||
|
key={option.value || 'all'}
|
||||||
|
type={filters.order_status === option.value ? 'primary' : 'text'}
|
||||||
|
onClick={() => onFilterChange({ ...filters, order_status: option.value })}
|
||||||
|
style={{ minWidth: 76 }}
|
||||||
|
>
|
||||||
|
{option.label}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</Space>
|
||||||
|
</Space>
|
||||||
|
</Card>
|
||||||
<Table
|
<Table
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
|||||||
@@ -8,6 +8,15 @@ export const orderStatusMap: Record<string, { color: string; text: string }> = {
|
|||||||
cancelled: { color: 'default', text: '已取消' },
|
cancelled: { color: 'default', text: '已取消' },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const orderStatusOptions = [
|
||||||
|
{ value: '', label: '全部' },
|
||||||
|
{ value: 'paid', label: '待发货' },
|
||||||
|
{ value: 'delivering', label: '发货中' },
|
||||||
|
{ value: 'delivered', label: '已交付' },
|
||||||
|
{ value: 'ship_failed', label: '发货失败' },
|
||||||
|
{ value: 'cancelled', label: '已取消' },
|
||||||
|
]
|
||||||
|
|
||||||
export const memberRoleOptions = [
|
export const memberRoleOptions = [
|
||||||
{ value: 'owner', label: '负责人' },
|
{ value: 'owner', label: '负责人' },
|
||||||
{ value: 'operator', label: '运营' },
|
{ value: 'operator', label: '运营' },
|
||||||
|
|||||||
Reference in New Issue
Block a user