diff --git a/.gitignore b/.gitignore index 6195f51..7d113fa 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ backend/logs/ deploy/.data/ miniapp/miniprogram_npm/ miniapp/private.* +**/project.private.config.json diff --git a/admin-web/src/api/groupBuyApi.test.ts b/admin-web/src/api/groupBuyApi.test.ts index 3e1efa5..7e57c2b 100644 --- a/admin-web/src/api/groupBuyApi.test.ts +++ b/admin-web/src/api/groupBuyApi.test.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest' import { buildGroupBuyOrderActionPath, + buildGroupBuyOrderQuery, filterPendingDeliveryGroupBuyOrders, groupBuyOrderDispatchLabel } from './groupBuyApi' @@ -30,6 +31,18 @@ describe('group buy dispatch helpers', () => { expect(buildGroupBuyOrderActionPath(1, 'confirm')).toBe('/api/admin/group-buy-orders/1/confirm') expect(buildGroupBuyOrderActionPath(1, 'ready')).toBe('/api/admin/group-buy-orders/1/ready') }) + + it('builds group buy order page query params', () => { + expect(buildGroupBuyOrderQuery({ + status: 'PENDING_CONFIRM', + pageNo: 2, + pageSize: 10 + })).toEqual({ + status: 'PENDING_CONFIRM', + pageNo: 2, + pageSize: 10 + }) + }) }) function groupBuyOrder(overrides: Partial): GroupBuyOrder { diff --git a/admin-web/src/api/groupBuyApi.ts b/admin-web/src/api/groupBuyApi.ts index b6ecaad..ee55d03 100644 --- a/admin-web/src/api/groupBuyApi.ts +++ b/admin-web/src/api/groupBuyApi.ts @@ -1,4 +1,4 @@ -import type { GroupBuy, GroupBuyOrder } from '../types' +import type { GroupBuy, GroupBuyOrder, PageResponse } from '../types' import { apiGet, apiPost, apiPut } from './http' export function listGroupBuys() { @@ -9,6 +9,24 @@ export function listGroupBuyOrders(groupBuyId: number) { return apiGet(`/api/admin/group-buys/${groupBuyId}/orders`) } +export interface GroupBuyOrderQuery { + status?: string + pageNo?: number + pageSize?: number +} + +export function buildGroupBuyOrderQuery(query: GroupBuyOrderQuery = {}) { + const params: Record = {} + if (query.status) params.status = query.status + if (query.pageNo) params.pageNo = query.pageNo + if (query.pageSize) params.pageSize = query.pageSize + return params +} + +export function pageGroupBuyOrders(groupBuyId: number, query: GroupBuyOrderQuery = {}) { + return apiGet>(`/api/admin/group-buys/${groupBuyId}/orders/page`, buildGroupBuyOrderQuery(query)) +} + export function filterPendingDeliveryGroupBuyOrders(orders: GroupBuyOrder[]) { return orders.filter((order) => order.status === 'PENDING_DELIVERY') } diff --git a/admin-web/src/api/orderApi.test.ts b/admin-web/src/api/orderApi.test.ts index 4734466..cae55e1 100644 --- a/admin-web/src/api/orderApi.test.ts +++ b/admin-web/src/api/orderApi.test.ts @@ -6,11 +6,15 @@ describe('buildGoodsOrderQuery', () => { expect(buildGoodsOrderQuery({ status: 'PENDING_DELIVERY', startDate: '2026-07-01', - endDate: '2026-07-07' + endDate: '2026-07-07', + pageNo: 2, + pageSize: 20 })).toEqual({ status: 'PENDING_DELIVERY', startDate: '2026-07-01', - endDate: '2026-07-07' + endDate: '2026-07-07', + pageNo: 2, + pageSize: 20 }) }) }) diff --git a/admin-web/src/api/orderApi.ts b/admin-web/src/api/orderApi.ts index b47820e..2a4098a 100644 --- a/admin-web/src/api/orderApi.ts +++ b/admin-web/src/api/orderApi.ts @@ -1,17 +1,21 @@ -import type { ExpressOrder, GoodsOrder } from '../types' +import type { ExpressOrder, GoodsOrder, PageResponse } from '../types' import { apiGet, apiPut } from './http' export interface GoodsOrderQuery { status?: string startDate?: string endDate?: string + pageNo?: number + pageSize?: number } export function buildGoodsOrderQuery(query: GoodsOrderQuery) { - const params: Record = {} + const params: Record = {} if (query.status) params.status = query.status if (query.startDate) params.startDate = query.startDate if (query.endDate) params.endDate = query.endDate + if (query.pageNo) params.pageNo = query.pageNo + if (query.pageSize) params.pageSize = query.pageSize return params } @@ -19,6 +23,10 @@ export function listGoodsOrders(query: GoodsOrderQuery = {}) { return apiGet('/api/admin/goods-orders', buildGoodsOrderQuery(query)) } +export function pageGoodsOrders(query: GoodsOrderQuery = {}) { + return apiGet>('/api/admin/goods-orders/page', buildGoodsOrderQuery(query)) +} + export function confirmGoodsOrder(id: number) { return apiPut(`/api/admin/goods-orders/${id}/confirm`) } @@ -28,17 +36,35 @@ export function markGoodsOrderPrepared(id: number) { } export function cancelGoodsOrder(id: number) { - return apiPut(`/api/mini/goods-orders/${id}/cancel`) + return apiPut(`/api/admin/goods-orders/${id}/cancel`) } export function markGoodsOrderPaid(id: number) { return apiPut(`/api/admin/goods-orders/${id}/paid`) } +export interface ExpressOrderQuery { + status?: string + pageNo?: number + pageSize?: number +} + +export function buildExpressOrderQuery(query: ExpressOrderQuery = {}) { + const params: Record = {} + if (query.status) params.status = query.status + if (query.pageNo) params.pageNo = query.pageNo + if (query.pageSize) params.pageSize = query.pageSize + return params +} + export function listExpressOrders(status?: string) { return apiGet('/api/admin/express-orders', status ? { status } : undefined) } +export function pageExpressOrders(query: ExpressOrderQuery = {}) { + return apiGet>('/api/admin/express-orders/page', buildExpressOrderQuery(query)) +} + export function confirmExpressOrder(id: number) { return apiPut(`/api/admin/express-orders/${id}/confirm`) } diff --git a/admin-web/src/api/productApi.test.ts b/admin-web/src/api/productApi.test.ts new file mode 100644 index 0000000..3211a9a --- /dev/null +++ b/admin-web/src/api/productApi.test.ts @@ -0,0 +1,20 @@ +import { describe, expect, it } from 'vitest' +import { buildProductQuery } from './productApi' + +describe('buildProductQuery', () => { + it('keeps pagination and optional product filters stable', () => { + expect(buildProductQuery({ + keyword: '苹果', + categoryId: 2, + merchantId: 1, + pageNo: 3, + pageSize: 10 + })).toEqual({ + keyword: '苹果', + categoryId: 2, + merchantId: 1, + pageNo: 3, + pageSize: 10 + }) + }) +}) diff --git a/admin-web/src/api/productApi.ts b/admin-web/src/api/productApi.ts index ef453bf..b4f2044 100644 --- a/admin-web/src/api/productApi.ts +++ b/admin-web/src/api/productApi.ts @@ -1,8 +1,28 @@ -import type { Product, ProductCategory, ProductSku } from '../types' +import type { PageResponse, Product, ProductCategory, ProductSku } from '../types' import { apiGet, apiPost, apiPut } from './http' -export function listProducts() { - return apiGet('/api/admin/products') +export interface ProductQuery { + keyword?: string + categoryId?: number + merchantId?: number + pageNo?: number + pageSize?: number +} + +export function buildProductQuery(query: ProductQuery = {}) { + const params: Record = { + pageNo: query.pageNo || 1, + pageSize: query.pageSize || 20 + } + if (query.keyword) params.keyword = query.keyword + if (query.categoryId) params.categoryId = query.categoryId + if (query.merchantId) params.merchantId = query.merchantId + return params +} + +export async function listProducts(query: ProductQuery = {}) { + const page = await apiGet>('/api/admin/products/page', buildProductQuery(query)) + return page.records } export function createProduct(data: Partial) { diff --git a/admin-web/src/styles.css b/admin-web/src/styles.css index 41a8c8c..fae7628 100644 --- a/admin-web/src/styles.css +++ b/admin-web/src/styles.css @@ -140,3 +140,9 @@ body { display: inline-flex; gap: 8px; } + +.pagination-bar { + display: flex; + justify-content: flex-end; + padding-top: 14px; +} diff --git a/admin-web/src/types.ts b/admin-web/src/types.ts index d494be5..2b00679 100644 --- a/admin-web/src/types.ts +++ b/admin-web/src/types.ts @@ -6,6 +6,13 @@ export interface CurrentUser { roleCode: string } +export interface PageResponse { + total: number + pageNo: number + pageSize: number + records: T[] +} + export interface ProductSku { id: number productId: number diff --git a/admin-web/src/views/ExpressOrderListView.vue b/admin-web/src/views/ExpressOrderListView.vue index f24bd60..27554b6 100644 --- a/admin-web/src/views/ExpressOrderListView.vue +++ b/admin-web/src/views/ExpressOrderListView.vue @@ -6,7 +6,7 @@ import { adjustExpressFee, cancelExpressOrder, confirmExpressOrder, - listExpressOrders, + pageExpressOrders, updateExpressPayStatus } from '../api/orderApi' import type { ExpressOrder } from '../types' @@ -15,11 +15,18 @@ import { statusText, yuan } from '../utils/format' const loading = ref(false) const rows = ref([]) const filters = reactive({ status: '' }) +const pagination = reactive({ pageNo: 1, pageSize: 10, total: 0 }) async function load() { loading.value = true try { - rows.value = await listExpressOrders(filters.status || undefined) + const page = await pageExpressOrders({ + status: filters.status || undefined, + pageNo: pagination.pageNo, + pageSize: pagination.pageSize + }) + rows.value = page.records + pagination.total = page.total } catch (error) { ElMessage.error(error instanceof Error ? error.message : '加载失败') } finally { @@ -27,6 +34,17 @@ async function load() { } } +function search() { + pagination.pageNo = 1 + load() +} + +function changeSize(size: number) { + pagination.pageSize = size + pagination.pageNo = 1 + load() +} + async function run(action: () => Promise) { try { await action() @@ -63,7 +81,7 @@ onMounted(load) - 查询 + 查询 刷新 @@ -88,5 +106,16 @@ onMounted(load) +
+ +
diff --git a/admin-web/src/views/GoodsOrderListView.vue b/admin-web/src/views/GoodsOrderListView.vue index 7d28e8e..6232309 100644 --- a/admin-web/src/views/GoodsOrderListView.vue +++ b/admin-web/src/views/GoodsOrderListView.vue @@ -5,9 +5,9 @@ import { ElMessage } from 'element-plus' import { cancelGoodsOrder, confirmGoodsOrder, - listGoodsOrders, markGoodsOrderPaid, - markGoodsOrderPrepared + markGoodsOrderPrepared, + pageGoodsOrders } from '../api/orderApi' import type { GoodsOrder } from '../types' import { statusText, yuan } from '../utils/format' @@ -15,11 +15,18 @@ import { statusText, yuan } from '../utils/format' const loading = ref(false) const rows = ref([]) const filters = reactive({ status: '' }) +const pagination = reactive({ pageNo: 1, pageSize: 10, total: 0 }) async function load() { loading.value = true try { - rows.value = await listGoodsOrders({ status: filters.status || undefined }) + const page = await pageGoodsOrders({ + status: filters.status || undefined, + pageNo: pagination.pageNo, + pageSize: pagination.pageSize + }) + rows.value = page.records + pagination.total = page.total } catch (error) { ElMessage.error(error instanceof Error ? error.message : '加载失败') } finally { @@ -27,6 +34,17 @@ async function load() { } } +function search() { + pagination.pageNo = 1 + load() +} + +function changeSize(size: number) { + pagination.pageSize = size + pagination.pageNo = 1 + load() +} + async function run(action: () => Promise) { try { await action() @@ -51,7 +69,7 @@ onMounted(load) - 查询 + 查询 刷新 @@ -79,5 +97,16 @@ onMounted(load) +
+ +
diff --git a/admin-web/src/views/GroupBuyListView.vue b/admin-web/src/views/GroupBuyListView.vue index 5294255..637904b 100644 --- a/admin-web/src/views/GroupBuyListView.vue +++ b/admin-web/src/views/GroupBuyListView.vue @@ -7,9 +7,9 @@ import { completeGroupBuy, confirmGroupBuyOrder, createGroupBuy, - listGroupBuyOrders, listGroupBuys, markGroupBuyOrderReady, + pageGroupBuyOrders, startGroupBuy } from '../api/groupBuyApi' import type { GroupBuy, GroupBuyOrder } from '../types' @@ -22,6 +22,7 @@ const orders = ref([]) const activeGroupBuy = ref(null) const dialog = ref(false) const orderDialog = ref(false) +const orderPagination = reactive({ pageNo: 1, pageSize: 10, total: 0 }) const form = reactive({ title: '', coverUrl: '', @@ -46,6 +47,7 @@ async function load() { async function openOrders(row: GroupBuy) { activeGroupBuy.value = row + orderPagination.pageNo = 1 orderDialog.value = true await loadOrders(row.id) } @@ -54,7 +56,12 @@ async function loadOrders(groupBuyId = activeGroupBuy.value?.id) { if (!groupBuyId) return orderLoading.value = true try { - orders.value = await listGroupBuyOrders(groupBuyId) + const page = await pageGroupBuyOrders(groupBuyId, { + pageNo: orderPagination.pageNo, + pageSize: orderPagination.pageSize + }) + orders.value = page.records + orderPagination.total = page.total } catch (error) { ElMessage.error(error instanceof Error ? error.message : '加载失败') } finally { @@ -62,6 +69,12 @@ async function loadOrders(groupBuyId = activeGroupBuy.value?.id) { } } +function changeOrderSize(size: number) { + orderPagination.pageSize = size + orderPagination.pageNo = 1 + loadOrders() +} + async function save() { try { await createGroupBuy(form) @@ -153,6 +166,17 @@ onMounted(load) +
+ +
diff --git a/admin-web/src/views/ProductListView.vue b/admin-web/src/views/ProductListView.vue index 11c7bdf..9a198ed 100644 --- a/admin-web/src/views/ProductListView.vue +++ b/admin-web/src/views/ProductListView.vue @@ -1,6 +1,6 @@