feat(pre-planting): Admin Web 预种计划 Service 层

[2026-02-17] Admin Web 预种管理 API 服务 + React Query Hooks

新增文件:
- endpoints.ts: PRE_PLANTING 端点组(config/toggle/orders/positions/merges/stats)
- prePlantingService.ts: 预种管理服务(开关配置、订单/持仓/合并查询、统计汇总)
  - 完整 TypeScript 类型定义(Config, Stats, Order, Position, Merge)
  - 分页列表请求/响应类型
- usePrePlanting.ts: React Query hooks
  - Query key factory(层级化参数化)
  - usePrePlantingConfig/Stats/Orders/Positions/Merges
  - useTogglePrePlantingConfig(mutation + 自动刷新)
- hooks/index.ts: 导出新 hooks

所有端点走 admin-service 的 PrePlantingAdminModule
与现有认种管理完全独立

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-02-18 05:48:58 -08:00
parent 03f5c4af28
commit 63ae7662a4
4 changed files with 288 additions and 0 deletions

View File

@ -5,3 +5,5 @@ export * from './useUsers';
export * from './useUserDetailPage'; export * from './useUserDetailPage';
export * from './useAuthorizations'; export * from './useAuthorizations';
export * from './useSystemWithdrawal'; export * from './useSystemWithdrawal';
// [2026-02-17] 预种计划管理
export * from './usePrePlanting';

View File

@ -0,0 +1,107 @@
/**
* [2026-02-17] React Query Hooks
*
* admin-web hooks
* React Query
* - Query key factory
* - hook
* - useMutation
*
* === 使 ===
* import { usePrePlantingConfig, usePrePlantingStats, ... } from '@/hooks';
*/
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import {
prePlantingService,
type PrePlantingListParams,
} from '@/services/prePlantingService';
// ============================================
// Query Key Factory
// ============================================
export const prePlantingKeys = {
all: ['pre-planting'] as const,
config: () => [...prePlantingKeys.all, 'config'] as const,
stats: () => [...prePlantingKeys.all, 'stats'] as const,
orders: (params: PrePlantingListParams) =>
[...prePlantingKeys.all, 'orders', params] as const,
positions: (params: PrePlantingListParams) =>
[...prePlantingKeys.all, 'positions', params] as const,
merges: (params: PrePlantingListParams) =>
[...prePlantingKeys.all, 'merges', params] as const,
};
// ============================================
// Query Hooks
// ============================================
/** 获取预种开关配置 */
export function usePrePlantingConfig() {
return useQuery({
queryKey: prePlantingKeys.config(),
queryFn: () => prePlantingService.getConfig(),
staleTime: 30 * 1000,
gcTime: 5 * 60 * 1000,
});
}
/** 获取预种统计汇总 */
export function usePrePlantingStats() {
return useQuery({
queryKey: prePlantingKeys.stats(),
queryFn: () => prePlantingService.getStats(),
staleTime: 30 * 1000,
gcTime: 5 * 60 * 1000,
});
}
/** 获取预种订单列表 */
export function usePrePlantingOrders(params: PrePlantingListParams = {}) {
return useQuery({
queryKey: prePlantingKeys.orders(params),
queryFn: () => prePlantingService.getOrders(params),
staleTime: 30 * 1000,
gcTime: 5 * 60 * 1000,
});
}
/** 获取预种持仓列表 */
export function usePrePlantingPositions(params: PrePlantingListParams = {}) {
return useQuery({
queryKey: prePlantingKeys.positions(params),
queryFn: () => prePlantingService.getPositions(params),
staleTime: 30 * 1000,
gcTime: 5 * 60 * 1000,
});
}
/** 获取合并记录列表 */
export function usePrePlantingMerges(params: PrePlantingListParams = {}) {
return useQuery({
queryKey: prePlantingKeys.merges(params),
queryFn: () => prePlantingService.getMerges(params),
staleTime: 30 * 1000,
gcTime: 5 * 60 * 1000,
});
}
// ============================================
// Mutation Hooks
// ============================================
/** 切换预种开关 */
export function useTogglePrePlantingConfig() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (isActive: boolean) =>
prePlantingService.toggleConfig(isActive),
onSuccess: () => {
// 开关切换后刷新配置和统计
queryClient.invalidateQueries({ queryKey: prePlantingKeys.config() });
queryClient.invalidateQueries({ queryKey: prePlantingKeys.stats() });
},
});
}

View File

@ -288,4 +288,20 @@ export const API_ENDPOINTS = {
// 批量下载任务状态 // 批量下载任务状态
BATCH_DOWNLOAD_STATUS: (taskNo: string) => `/v1/admin/contracts/batch-download/${taskNo}`, BATCH_DOWNLOAD_STATUS: (taskNo: string) => `/v1/admin/contracts/batch-download/${taskNo}`,
}, },
// [2026-02-17] 新增:预种计划管理 (admin-service / PrePlantingAdminModule)
// 3171 USDT/份预种,累计 5 份合成 1 棵树
// 开关管理 + 预种订单/持仓/合并记录查询
PRE_PLANTING: {
// 预种开关配置
CONFIG: '/v1/admin/pre-planting/config',
TOGGLE: '/v1/admin/pre-planting/config/toggle',
// 预种订单列表(管理员视角,可按用户/状态过滤)
ORDERS: '/v1/admin/pre-planting/orders',
// 预种持仓列表(管理员视角)
POSITIONS: '/v1/admin/pre-planting/positions',
// 合并记录列表(管理员视角)
MERGES: '/v1/admin/pre-planting/merges',
// 预种统计汇总(总份数、总金额、合并树数等)
STATS: '/v1/admin/pre-planting/stats',
},
} as const; } as const;

View File

@ -0,0 +1,163 @@
/**
* [2026-02-17]
*
* API
* //
*
* === API ===
* admin-service PrePlantingAdminModule
* - GET /v1/admin/pre-planting/config
* - PUT /v1/admin/pre-planting/config/toggle
* - GET /v1/admin/pre-planting/orders
* - GET /v1/admin/pre-planting/positions
* - GET /v1/admin/pre-planting/merges
* - GET /v1/admin/pre-planting/stats
*
* === ===
* planting_orders CONTRACTS
*/
import apiClient from '@/infrastructure/api/client';
import { API_ENDPOINTS } from '@/infrastructure/api/endpoints';
// ============================================
// 类型定义
// ============================================
/** 预种开关配置 */
export interface PrePlantingConfig {
isActive: boolean;
activatedAt: string | null;
updatedAt: string;
updatedBy: string | null;
}
/** 预种统计汇总 */
export interface PrePlantingStats {
totalOrders: number; // 总订单数
totalPortions: number; // 总份数
totalAmount: number; // 总金额USDT
totalMerges: number; // 合并次数
totalTreesMerged: number; // 合成树数
totalUsers: number; // 参与用户数
pendingContracts: number; // 待签约合并数
}
/** 预种订单(管理员视角) */
export interface PrePlantingAdminOrder {
id: string;
orderNo: string;
userId: string;
accountSequence: string;
portionCount: number;
pricePerPortion: number;
totalAmount: number;
provinceCode: string;
cityCode: string;
status: 'CREATED' | 'PAID' | 'MERGED';
mergedToMergeId: string | null;
createdAt: string;
paidAt: string | null;
mergedAt: string | null;
}
/** 预种持仓(管理员视角) */
export interface PrePlantingAdminPosition {
id: string;
userId: string;
accountSequence: string;
totalPortions: number;
availablePortions: number;
mergedPortions: number;
totalTreesMerged: number;
provinceCode: string | null;
cityCode: string | null;
firstPurchaseAt: string | null;
updatedAt: string;
}
/** 预种合并记录(管理员视角) */
export interface PrePlantingAdminMerge {
id: string;
mergeNo: string;
userId: string;
accountSequence: string;
sourceOrderNos: string[];
treeCount: number;
contractStatus: 'PENDING' | 'SIGNED' | 'EXPIRED';
contractSignedAt: string | null;
miningEnabledAt: string | null;
selectedProvince: string | null;
selectedCity: string | null;
mergedAt: string;
}
/** 分页列表请求参数 */
export interface PrePlantingListParams {
page?: number;
pageSize?: number;
status?: string;
accountSequence?: string;
keyword?: string;
}
/** 分页列表响应 */
export interface PaginatedResponse<T> {
items: T[];
total: number;
page: number;
pageSize: number;
}
// ============================================
// 预种计划管理服务
// ============================================
export const prePlantingService = {
/**
*
*/
async getConfig(): Promise<PrePlantingConfig> {
return apiClient.get(API_ENDPOINTS.PRE_PLANTING.CONFIG);
},
/**
* /
*
* "能否发起新购买"
* 5
*/
async toggleConfig(isActive: boolean): Promise<PrePlantingConfig> {
return apiClient.put(API_ENDPOINTS.PRE_PLANTING.TOGGLE, { isActive });
},
/**
*
*/
async getStats(): Promise<PrePlantingStats> {
return apiClient.get(API_ENDPOINTS.PRE_PLANTING.STATS);
},
/**
*
*/
async getOrders(params: PrePlantingListParams = {}): Promise<PaginatedResponse<PrePlantingAdminOrder>> {
return apiClient.get(API_ENDPOINTS.PRE_PLANTING.ORDERS, { params });
},
/**
*
*/
async getPositions(params: PrePlantingListParams = {}): Promise<PaginatedResponse<PrePlantingAdminPosition>> {
return apiClient.get(API_ENDPOINTS.PRE_PLANTING.POSITIONS, { params });
},
/**
*
*/
async getMerges(params: PrePlantingListParams = {}): Promise<PaginatedResponse<PrePlantingAdminMerge>> {
return apiClient.get(API_ENDPOINTS.PRE_PLANTING.MERGES, { params });
},
};
export default prePlantingService;