feat(distribution): 分销站点增加用户数量统计与用户信息展示模块

- 数据模型与迁移: 新增 000082 迁移在 users 表追加 distribution_site_id 并建索引,用户首次在分销站点注册/短信登录时自动绑定站点归属
- 分销管理接口: 新增 GET /admin/distribution/users 接口,聚合本站注册用户与下单客户,返回完整11位手机号、累计消费金额、订单数及来源标签
- 统计与大盘扩展: GET /admin/distribution/sites/:id/analytics 补全今日注册、累计用户、成交客户指标,主站分销商列表追加用户体量展示
- 分销后台前端: 新增「客户与用户」页面 (Users.tsx) 支持一键复制手机号与订单穿透,大盘 (Dashboard.tsx) 增加用户规模核心卡片
- 自动化测试与门禁: 新增 TestListDistributionUsersAndAnalytics 单元测试,通过全量 Go 后端集成测试及前后端构建检查
This commit is contained in:
yml2213
2026-10-10 14:58:33 +08:00
parent 6d34f86765
commit 4ea08e355b
17 changed files with 956 additions and 60 deletions
+52
View File
@@ -138,6 +138,8 @@ export interface Site {
admin_username?: string
admin_nickname?: string
member_type?: string
user_count?: number
order_user_count?: number
created_at: string
}
@@ -820,6 +822,9 @@ export interface DistributionAnalytics {
today_profit_cent: number
month_profit_cent: number
available_balance_cent: number
today_user_count?: number
total_user_count?: number
total_order_user_count?: number
trend_days: {
date: string
received_count: number
@@ -834,6 +839,53 @@ export async function fetchDashboardAnalytics(siteID: number): Promise<Distribut
return extract(resp)
}
export interface DistributionUser {
id: number
phone: string
nickname: string
avatar_url: string
realname_status: string
status: string
source: 'register' | 'order' | 'both'
order_count: number
total_spent_cent: number
last_order_at?: string
created_at: string
last_login_at?: string
}
export interface DistributionUserPage {
items: DistributionUser[]
total: number
page: number
page_size: number
total_users: number
order_users: number
}
export interface ListDistributionUsersParams {
siteID?: number
keyword?: string
source?: 'all' | 'register' | 'order'
page?: number
pageSize?: number
}
export async function listDistributionUsers(
params: ListDistributionUsersParams = {}
): Promise<DistributionUserPage> {
const resp = await api.get<ApiResponse<DistributionUserPage>>('/admin/distribution/users', {
params: {
site_id: params.siteID,
keyword: params.keyword,
source: params.source,
page: params.page,
page_size: params.pageSize,
},
})
return extract(resp)
}
export interface SiteSMSConfig {
enabled: boolean
provider: string