From ac44fda08b66b04ba100ac0c0b89f6203350c2e2 Mon Sep 17 00:00:00 2001 From: yml2213 Date: Thu, 13 Aug 2026 12:58:06 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=9A=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E8=AE=A2=E5=8D=95=E6=90=9C=E7=B4=A2=E4=B8=8E=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E7=AD=9B=E9=80=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/internal/handler/merchant.go | 4 +- backend/internal/service/fulfillment_query.go | 12 +++++- frontend/src/pages/MerchantCenter.tsx | 21 +++++++--- frontend/src/pages/merchantCenterTabs.tsx | 41 +++++++++++++++++++ frontend/src/pages/merchantCenterUtils.ts | 9 ++++ 5 files changed, 79 insertions(+), 8 deletions(-) diff --git a/backend/internal/handler/merchant.go b/backend/internal/handler/merchant.go index e6c0f9d..57e72dd 100644 --- a/backend/internal/handler/merchant.go +++ b/backend/internal/handler/merchant.go @@ -89,9 +89,9 @@ func (h *MerchantHandler) UpdateProductStatus(c *gin.Context) { func (h *MerchantHandler) ListOrders(c *gin.Context) { page, size := pageParams(c) 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 orderSource != "" && err.Error() == "无效的订单来源" { + if err.Error() == "无效的订单来源" || err.Error() == "无效的订单状态" { response.BadRequest(c, err.Error()) return } diff --git a/backend/internal/service/fulfillment_query.go b/backend/internal/service/fulfillment_query.go index 74576db..31fb4ca 100644 --- a/backend/internal/service/fulfillment_query.go +++ b/backend/internal/service/fulfillment_query.go @@ -2,6 +2,7 @@ package service import ( "errors" + "strings" "time" "affiliate_dash/internal/model" @@ -23,10 +24,15 @@ func (s *FulfillmentService) GetOrder(merchantID uint, orderNo string) (*model.F 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) tx := s.db.Model(&model.FulfillmentOrder{}).Where("merchant_id = ?", merchantID) 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) } if orderSource != "" { @@ -37,6 +43,10 @@ func (s *FulfillmentService) ListOrders(merchantID uint, page, size int, orderSt 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 if err := tx.Count(&total).Error; err != nil { return nil, 0, err diff --git a/frontend/src/pages/MerchantCenter.tsx b/frontend/src/pages/MerchantCenter.tsx index bc47941..4963df4 100644 --- a/frontend/src/pages/MerchantCenter.tsx +++ b/frontend/src/pages/MerchantCenter.tsx @@ -65,6 +65,7 @@ export default function MerchantCenter({ fixedTab, title = '商户中心' }: Mer const [products, setProducts] = useState>({ list: [], total: 0, page: 1, size: 10 }) const [orders, setOrders] = useState>({ list: [], total: 0, page: 1, size: 10 }) const [orderSource, setOrderSource] = useState<'api' | 'manual'>('api') + const [orderFilters, setOrderFilters] = useState<{ keyword: string; order_status: string }>({ keyword: '', order_status: '' }) const [ledger, setLedger] = useState>({ list: [], total: 0, page: 1, size: 10 }) const [wallet, setWallet] = useState(null) const [apiClients, setApiClients] = useState([]) @@ -163,10 +164,15 @@ export default function MerchantCenter({ fixedTab, title = '商户中心' }: Mer setProducts(data) }, [products.page, products.size]) - const loadOrders = useCallback(async (page = orders.page, size = orders.size, source = orderSource) => { - const data = await merchantApi.orders({ page, size, order_source: source }) + const loadOrders = useCallback(async ( + page = orders.page, + size = orders.size, + source = orderSource, + filters = orderFilters, + ) => { + const data = await merchantApi.orders({ page, size, order_source: source, ...filters }) setOrders(data) - }, [orderSource, orders.page, orders.size]) + }, [orderFilters, orderSource, orders.page, orders.size]) const loadWallet = useCallback(async ( page = ledger.page, @@ -341,7 +347,12 @@ export default function MerchantCenter({ fixedTab, title = '商户中心' }: Mer const changeOrderSource = (source: 'api' | 'manual') => { 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 () => { @@ -499,7 +510,7 @@ export default function MerchantCenter({ fixedTab, title = '商户中心' }: Mer ) }, { key: 'orders', label: '发货订单', disabled: !hasFeature('orders'), children: ( - + ) }, { key: 'wallet', label: '钱包', disabled: !hasFeature('wallet'), children: ( diff --git a/frontend/src/pages/merchantCenterTabs.tsx b/frontend/src/pages/merchantCenterTabs.tsx index 62fbc73..0a31672 100644 --- a/frontend/src/pages/merchantCenterTabs.tsx +++ b/frontend/src/pages/merchantCenterTabs.tsx @@ -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 type { FormInstance } from 'antd' import { @@ -30,6 +31,7 @@ import { defaultCallbackFormValues, eventOptions, money, + orderStatusOptions, orderStatusMap, pageConfig, rolePermissionText, @@ -171,9 +173,11 @@ export function OrdersTab({ loading, orders, orderSource, + filters, canManage, onCreateManualOrder, onOrderSourceChange, + onFilterChange, onLoadOrders, onCopyLink, onOpenLink, @@ -183,15 +187,25 @@ export function OrdersTab({ loading: boolean orders: PageResult orderSource: 'api' | 'manual' + filters: { keyword: string; order_status: string } canManage: boolean onCreateManualOrder: () => void onOrderSourceChange: (source: 'api' | 'manual') => void + onFilterChange: (filters: { keyword: string; order_status: string }) => void onLoadOrders: (page?: number, size?: number) => void onCopyLink: (orderNo: string) => void onOpenLink: (orderNo: string) => void onRevokeLink: (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 = [ { title: '平台订单号', @@ -253,6 +267,33 @@ export function OrdersTab({ )} + + + + setKeyword(event.target.value)} + onSearch={submitKeyword} + placeholder="搜索平台订单号或商户单号" + allowClear + onClear={() => onFilterChange({ ...filters, keyword: '' })} + style={{ width: 300, maxWidth: '100%' }} + /> + + + {orderStatusOptions.map((option) => ( + + ))} + + + = { 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 = [ { value: 'owner', label: '负责人' }, { value: 'operator', label: '运营' },