feat(business): 添加业务模块前后端服务
后端Controllers: - AuditController: 审计日志API - SystemController: 系统配置API - RewardController: 奖励管理API - RiskController: 风险管理API 前端Services: - activity.ts: 活动管理服务 - user管理服务 -Manage.ts: 用户 reward.ts: 奖励管理服务 - risk.ts: 风险管理服务 - audit.ts: 审计日志服务 - systemConfig.ts: 系统配置服务 - activity.ts: 活动类型定义
This commit is contained in:
206
frontend/admin/src/services/activity.ts
Normal file
206
frontend/admin/src/services/activity.ts
Normal file
@@ -0,0 +1,206 @@
|
||||
/**
|
||||
* 活动管理服务
|
||||
*/
|
||||
import type { Activity } from '../types/activity'
|
||||
|
||||
export interface ApiResponse<T> {
|
||||
code: number
|
||||
data: T
|
||||
message?: string
|
||||
}
|
||||
|
||||
export interface ActivityListQuery {
|
||||
page?: number
|
||||
size?: number
|
||||
status?: string
|
||||
keyword?: string
|
||||
startDate?: string
|
||||
endDate?: string
|
||||
}
|
||||
|
||||
class ActivityService {
|
||||
private baseUrl = '/api'
|
||||
|
||||
/**
|
||||
* 获取活动列表
|
||||
*/
|
||||
async getActivities(params?: ActivityListQuery): Promise<Activity[]> {
|
||||
const searchParams = new URLSearchParams()
|
||||
if (params?.page) searchParams.set('page', String(params.page))
|
||||
if (params?.size) searchParams.set('size', String(params.size))
|
||||
if (params?.status) searchParams.set('status', params.status)
|
||||
if (params?.keyword) searchParams.set('keyword', params.keyword)
|
||||
|
||||
const response = await fetch(`${this.baseUrl}/activities?${searchParams}`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<Activity[]>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '获取活动列表失败')
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单个活动详情
|
||||
*/
|
||||
async getActivityById(id: number): Promise<Activity | null> {
|
||||
const response = await fetch(`${this.baseUrl}/activities/${id}`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<Activity>
|
||||
if (result.code !== 200) {
|
||||
return null
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建活动
|
||||
*/
|
||||
async createActivity(data: Partial<Activity>): Promise<number> {
|
||||
const response = await fetch(`${this.baseUrl}/activities`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
const result = await response.json() as ApiResponse<number>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '创建活动失败')
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新活动
|
||||
*/
|
||||
async updateActivity(id: number, data: Partial<Activity>): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/activities/${id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '更新活动失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除活动
|
||||
*/
|
||||
async deleteActivity(id: number): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/activities/${id}`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '删除活动失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发布活动
|
||||
*/
|
||||
async publishActivity(id: number): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/activities/${id}/publish`, {
|
||||
method: 'POST',
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '发布活动失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停活动
|
||||
*/
|
||||
async pauseActivity(id: number): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/activities/${id}/pause`, {
|
||||
method: 'POST',
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '暂停活动失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复活动
|
||||
*/
|
||||
async resumeActivity(id: number): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/activities/${id}/resume`, {
|
||||
method: 'POST',
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '恢复活动失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束活动
|
||||
*/
|
||||
async endActivity(id: number): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/activities/${id}/end`, {
|
||||
method: 'POST',
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '结束活动失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取活动统计
|
||||
*/
|
||||
async getActivityStats(id: number): Promise<any> {
|
||||
const response = await fetch(`${this.baseUrl}/activities/${id}/stats`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<any>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '获取活动统计失败')
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取活动图表数据
|
||||
*/
|
||||
async getActivityGraph(id: number): Promise<any> {
|
||||
const response = await fetch(`${this.baseUrl}/activities/${id}/graph`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<any>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '获取活动图表失败')
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取活动排行榜
|
||||
*/
|
||||
async getActivityLeaderboard(id: number, limit?: number): Promise<any[]> {
|
||||
const params = limit ? `?limit=${limit}` : ''
|
||||
const response = await fetch(`${this.baseUrl}/activities/${id}/leaderboard${params}`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<any[]>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '获取排行榜失败')
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
}
|
||||
|
||||
export const activityService = new ActivityService()
|
||||
export default activityService
|
||||
162
frontend/admin/src/services/audit.ts
Normal file
162
frontend/admin/src/services/audit.ts
Normal file
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* 审计日志服务
|
||||
*/
|
||||
|
||||
export interface AuditLog {
|
||||
id: number
|
||||
userId: number
|
||||
userName?: string
|
||||
action: string
|
||||
module: string
|
||||
resource?: string
|
||||
method?: string
|
||||
requestUri?: string
|
||||
requestMethod?: string
|
||||
requestParams?: string
|
||||
requestBody?: string
|
||||
responseStatus?: number
|
||||
responseBody?: string
|
||||
ipAddress?: string
|
||||
userAgent?: string
|
||||
duration?: number
|
||||
errorMessage?: string
|
||||
createdAt: string
|
||||
}
|
||||
|
||||
export interface ApiResponse<T> {
|
||||
code: number
|
||||
data: T
|
||||
message?: string
|
||||
}
|
||||
|
||||
class AuditService {
|
||||
private baseUrl = '/api'
|
||||
|
||||
/**
|
||||
* 获取审计日志列表
|
||||
*/
|
||||
async getLogs(params?: {
|
||||
page?: number
|
||||
size?: number
|
||||
userId?: number
|
||||
action?: string
|
||||
module?: string
|
||||
startDate?: string
|
||||
endDate?: string
|
||||
keyword?: string
|
||||
}): Promise<AuditLog[]> {
|
||||
const searchParams = new URLSearchParams()
|
||||
if (params?.page) searchParams.set('page', String(params.page))
|
||||
if (params?.size) searchParams.set('size', String(params.size))
|
||||
if (params?.userId) searchParams.set('userId', String(params.userId))
|
||||
if (params?.action) searchParams.set('action', params.action)
|
||||
if (params?.module) searchParams.set('module', params.module)
|
||||
if (params?.keyword) searchParams.set('keyword', params.keyword)
|
||||
|
||||
const response = await fetch(`${this.baseUrl}/audit/logs?${searchParams}`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<AuditLog[]>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '获取审计日志失败')
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单个日志详情
|
||||
*/
|
||||
async getLogById(id: number): Promise<AuditLog | null> {
|
||||
const response = await fetch(`${this.baseUrl}/audit/logs/${id}`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<AuditLog>
|
||||
if (result.code !== 200) {
|
||||
return null
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取操作类型列表
|
||||
*/
|
||||
async getActionTypes(): Promise<string[]> {
|
||||
const response = await fetch(`${this.baseUrl}/audit/actions`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<string[]>
|
||||
if (result.code !== 200) {
|
||||
return []
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模块列表
|
||||
*/
|
||||
async getModules(): Promise<string[]> {
|
||||
const response = await fetch(`${this.baseUrl}/audit/modules`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<string[]>
|
||||
if (result.code !== 200) {
|
||||
return []
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出审计日志
|
||||
*/
|
||||
async exportLogs(params?: {
|
||||
userId?: number
|
||||
action?: string
|
||||
module?: string
|
||||
startDate?: string
|
||||
endDate?: string
|
||||
keyword?: string
|
||||
}): Promise<Blob> {
|
||||
const searchParams = new URLSearchParams()
|
||||
if (params?.userId) searchParams.set('userId', String(params.userId))
|
||||
if (params?.action) searchParams.set('action', params.action)
|
||||
if (params?.module) searchParams.set('module', params.module)
|
||||
if (params?.keyword) searchParams.set('keyword', params.keyword)
|
||||
|
||||
const response = await fetch(`${this.baseUrl}/audit/logs/export?${searchParams}`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
if (!response.ok) {
|
||||
throw new Error('导出审计日志失败')
|
||||
}
|
||||
return response.blob()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取审计统计
|
||||
*/
|
||||
async getStats(params?: {
|
||||
startDate?: string
|
||||
endDate?: string
|
||||
}): Promise<{
|
||||
totalCount: number
|
||||
actionCounts: Record<string, number>
|
||||
userCounts: Record<string, number>
|
||||
dailyCounts: Record<string, number>
|
||||
}> {
|
||||
const searchParams = new URLSearchParams()
|
||||
if (params?.startDate) searchParams.set('startDate', params.startDate)
|
||||
if (params?.endDate) searchParams.set('endDate', params.endDate)
|
||||
|
||||
const response = await fetch(`${this.baseUrl}/audit/stats?${searchParams}`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<any>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '获取审计统计失败')
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
}
|
||||
|
||||
export const auditService = new AuditService()
|
||||
export default auditService
|
||||
212
frontend/admin/src/services/reward.ts
Normal file
212
frontend/admin/src/services/reward.ts
Normal file
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
* 奖励管理服务
|
||||
*/
|
||||
|
||||
export interface Reward {
|
||||
id?: number
|
||||
userId: number
|
||||
userName?: string
|
||||
activityId?: number
|
||||
activityName?: string
|
||||
rewardType: RewardType
|
||||
rewardAmount: number
|
||||
status: RewardStatus
|
||||
applyReason?: string
|
||||
applyTime?: string
|
||||
approveTime?: string
|
||||
grantTime?: string
|
||||
createdAt?: string
|
||||
updatedAt?: string
|
||||
}
|
||||
|
||||
export type RewardType = 'COUPON' | 'POINTS' | 'CASH' | 'GIFT'
|
||||
|
||||
export type RewardStatus = 'PENDING' | 'APPROVED' | 'REJECTED' | 'GRANTED' | 'CANCELLED'
|
||||
|
||||
export interface ApiResponse<T> {
|
||||
code: number
|
||||
data: T
|
||||
message?: string
|
||||
}
|
||||
|
||||
export interface RewardListQuery {
|
||||
page?: number
|
||||
size?: number
|
||||
status?: string
|
||||
rewardType?: string
|
||||
userId?: number
|
||||
activityId?: number
|
||||
startDate?: string
|
||||
endDate?: string
|
||||
}
|
||||
|
||||
class RewardService {
|
||||
private baseUrl = '/api'
|
||||
|
||||
/**
|
||||
* 获取奖励列表
|
||||
*/
|
||||
async getRewards(params?: RewardListQuery): Promise<Reward[]> {
|
||||
const searchParams = new URLSearchParams()
|
||||
if (params?.page) searchParams.set('page', String(params.page))
|
||||
if (params?.size) searchParams.set('size', String(params.size))
|
||||
if (params?.status) searchParams.set('status', params.status)
|
||||
if (params?.rewardType) searchParams.set('rewardType', params.rewardType)
|
||||
|
||||
const response = await fetch(`${this.baseUrl}/rewards?${searchParams}`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<Reward[]>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '获取奖励列表失败')
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单个奖励详情
|
||||
*/
|
||||
async getRewardById(id: number): Promise<Reward | null> {
|
||||
const response = await fetch(`${this.baseUrl}/rewards/${id}`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<Reward>
|
||||
if (result.code !== 200) {
|
||||
return null
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 申请奖励
|
||||
*/
|
||||
async applyReward(data: {
|
||||
userId: number
|
||||
activityId: number
|
||||
rewardType: RewardType
|
||||
rewardAmount: number
|
||||
applyReason: string
|
||||
}): Promise<number> {
|
||||
const response = await fetch(`${this.baseUrl}/rewards/apply`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
const result = await response.json() as ApiResponse<number>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '申请奖励失败')
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 审批奖励
|
||||
*/
|
||||
async approveReward(id: number, approved: boolean, comment?: string): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/rewards/${id}/approve`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({ approved, comment })
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '审批奖励失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发放奖励
|
||||
*/
|
||||
async grantReward(id: number): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/rewards/${id}/grant`, {
|
||||
method: 'POST',
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '发放奖励失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量发放奖励
|
||||
*/
|
||||
async batchGrantRewards(ids: number[]): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/rewards/batch-grant`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({ ids })
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '批量发放失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消奖励
|
||||
*/
|
||||
async cancelReward(id: number, reason: string): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/rewards/${id}/cancel`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({ reason })
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '取消奖励失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取待审批奖励数量
|
||||
*/
|
||||
async getPendingCount(): Promise<number> {
|
||||
const response = await fetch(`${this.baseUrl}/rewards/pending-count`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<number>
|
||||
if (result.code !== 200) {
|
||||
return 0
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出奖励记录
|
||||
*/
|
||||
async exportRewards(params?: RewardListQuery): Promise<Blob> {
|
||||
const searchParams = new URLSearchParams()
|
||||
if (params?.status) searchParams.set('status', params.status)
|
||||
if (params?.rewardType) searchParams.set('rewardType', params.rewardType)
|
||||
|
||||
const response = await fetch(`${this.baseUrl}/rewards/export?${searchParams}`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
if (!response.ok) {
|
||||
throw new Error('导出奖励记录失败')
|
||||
}
|
||||
return response.blob()
|
||||
}
|
||||
|
||||
/**
|
||||
* 奖励对账
|
||||
*/
|
||||
async reconcile(startDate: string, endDate: string): Promise<any> {
|
||||
const response = await fetch(`${this.baseUrl}/rewards/reconcile?startDate=${startDate}&endDate=${endDate}`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<any>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '对账失败')
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
}
|
||||
|
||||
export const rewardService = new RewardService()
|
||||
export default rewardService
|
||||
243
frontend/admin/src/services/risk.ts
Normal file
243
frontend/admin/src/services/risk.ts
Normal file
@@ -0,0 +1,243 @@
|
||||
/**
|
||||
* 风险管理服务
|
||||
*/
|
||||
|
||||
export interface RiskAlert {
|
||||
id: number
|
||||
type: RiskType
|
||||
level: RiskLevel
|
||||
title: string
|
||||
description: string
|
||||
userId?: number
|
||||
userName?: string
|
||||
activityId?: number
|
||||
activityName?: string
|
||||
data?: Record<string, any>
|
||||
status: AlertStatus
|
||||
handleResult?: string
|
||||
handledBy?: number
|
||||
handledAt?: string
|
||||
createdAt: string
|
||||
updatedAt?: string
|
||||
}
|
||||
|
||||
export type RiskType = 'CHEAT' | 'ABNORMAL' | 'VIOLATION' | 'SYSTEM'
|
||||
|
||||
export type RiskLevel = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL'
|
||||
|
||||
export type AlertStatus = 'PENDING' | 'HANDLED' | 'IGNORED' | 'WHITELISTED'
|
||||
|
||||
export interface RiskRule {
|
||||
id: number
|
||||
name: string
|
||||
code: string
|
||||
description?: string
|
||||
riskType: RiskType
|
||||
condition: string
|
||||
action: RiskAction
|
||||
status: RuleStatus
|
||||
priority: number
|
||||
createdBy?: number
|
||||
createdAt?: string
|
||||
updatedAt?: string
|
||||
}
|
||||
|
||||
export type RiskAction = 'BLOCK' | 'WARN' | 'LOG' | 'CAPTCHA'
|
||||
|
||||
export type RuleStatus = 'ENABLED' | 'DISABLED'
|
||||
|
||||
export interface ApiResponse<T> {
|
||||
code: number
|
||||
data: T
|
||||
message?: string
|
||||
}
|
||||
|
||||
class RiskService {
|
||||
private baseUrl = '/api'
|
||||
|
||||
/**
|
||||
* 获取风险告警列表
|
||||
*/
|
||||
async getAlerts(params?: {
|
||||
page?: number
|
||||
size?: number
|
||||
type?: string
|
||||
level?: string
|
||||
status?: string
|
||||
startDate?: string
|
||||
endDate?: string
|
||||
}): Promise<RiskAlert[]> {
|
||||
const searchParams = new URLSearchParams()
|
||||
if (params?.page) searchParams.set('page', String(params.page))
|
||||
if (params?.size) searchParams.set('size', String(params.size))
|
||||
if (params?.type) searchParams.set('type', params.type)
|
||||
if (params?.level) searchParams.set('level', params.level)
|
||||
if (params?.status) searchParams.set('status', params.status)
|
||||
|
||||
const response = await fetch(`${this.baseUrl}/risk/alerts?${searchParams}`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<RiskAlert[]>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '获取风险告警失败')
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单个告警详情
|
||||
*/
|
||||
async getAlertById(id: number): Promise<RiskAlert | null> {
|
||||
const response = await fetch(`${this.baseUrl}/risk/alerts/${id}`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<RiskAlert>
|
||||
if (result.code !== 200) {
|
||||
return null
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理风险告警
|
||||
*/
|
||||
async handleAlert(id: number, data: {
|
||||
status: AlertStatus
|
||||
handleResult: string
|
||||
}): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/risk/alerts/${id}/handle`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '处理告警失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量处理告警
|
||||
*/
|
||||
async batchHandleAlerts(ids: number[], data: {
|
||||
status: AlertStatus
|
||||
handleResult: string
|
||||
}): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/risk/alerts/batch-handle`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({ ids, ...data })
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '批量处理失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取风控规则列表
|
||||
*/
|
||||
async getRules(params?: {
|
||||
page?: number
|
||||
size?: number
|
||||
riskType?: string
|
||||
status?: string
|
||||
}): Promise<RiskRule[]> {
|
||||
const searchParams = new URLSearchParams()
|
||||
if (params?.page) searchParams.set('page', String(params.page))
|
||||
if (params?.size) searchParams.set('size', String(params.size))
|
||||
if (params?.riskType) searchParams.set('riskType', params.riskType)
|
||||
if (params?.status) searchParams.set('status', params.status)
|
||||
|
||||
const response = await fetch(`${this.baseUrl}/risk/rules?${searchParams}`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<RiskRule[]>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '获取风控规则失败')
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建风控规则
|
||||
*/
|
||||
async createRule(data: Partial<RiskRule>): Promise<number> {
|
||||
const response = await fetch(`${this.baseUrl}/risk/rules`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
const result = await response.json() as ApiResponse<number>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '创建规则失败')
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新风控规则
|
||||
*/
|
||||
async updateRule(id: number, data: Partial<RiskRule>): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/risk/rules/${id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '更新规则失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除风控规则
|
||||
*/
|
||||
async deleteRule(id: number): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/risk/rules/${id}`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '删除规则失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用/禁用规则
|
||||
*/
|
||||
async toggleRule(id: number, enabled: boolean): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/risk/rules/${id}/toggle`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({ enabled })
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '切换规则状态失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取待处理告警数量
|
||||
*/
|
||||
async getPendingAlertCount(): Promise<number> {
|
||||
const response = await fetch(`${this.baseUrl}/risk/alerts/pending-count`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<number>
|
||||
if (result.code !== 200) {
|
||||
return 0
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
}
|
||||
|
||||
export const riskService = new RiskService()
|
||||
export default riskService
|
||||
164
frontend/admin/src/services/systemConfig.ts
Normal file
164
frontend/admin/src/services/systemConfig.ts
Normal file
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
* 系统配置服务
|
||||
*/
|
||||
|
||||
export interface SystemConfig {
|
||||
id: number
|
||||
configKey: string
|
||||
configValue: string
|
||||
valueType: ValueType
|
||||
description?: string
|
||||
category: ConfigCategory
|
||||
isSystem: boolean
|
||||
createdAt?: string
|
||||
updatedAt?: string
|
||||
}
|
||||
|
||||
export type ValueType = 'STRING' | 'NUMBER' | 'BOOLEAN' | 'JSON'
|
||||
|
||||
export type ConfigCategory = 'SYSTEM' | 'ACTIVITY' | 'REWARD' | 'NOTIFICATION' | 'SECURITY'
|
||||
|
||||
export interface ApiResponse<T> {
|
||||
code: number
|
||||
data: T
|
||||
message?: string
|
||||
}
|
||||
|
||||
class SystemConfigService {
|
||||
private baseUrl = '/api'
|
||||
|
||||
/**
|
||||
* 获取系统配置列表
|
||||
*/
|
||||
async getConfigs(params?: {
|
||||
category?: ConfigCategory
|
||||
keyword?: string
|
||||
}): Promise<SystemConfig[]> {
|
||||
const searchParams = new URLSearchParams()
|
||||
if (params?.category) searchParams.set('category', params.category)
|
||||
if (params?.keyword) searchParams.set('keyword', params.keyword)
|
||||
|
||||
const response = await fetch(`${this.baseUrl}/system/configs?${searchParams}`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<SystemConfig[]>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '获取配置列表失败')
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单个配置
|
||||
*/
|
||||
async getConfigByKey(key: string): Promise<SystemConfig | null> {
|
||||
const response = await fetch(`${this.baseUrl}/system/configs/${key}`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<SystemConfig>
|
||||
if (result.code !== 200) {
|
||||
return null
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新配置
|
||||
*/
|
||||
async updateConfig(key: string, value: string): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/system/configs/${key}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({ configValue: value })
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '更新配置失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新配置
|
||||
*/
|
||||
async batchUpdateConfigs(configs: { key: string; value: string }[]): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/system/configs/batch`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({ configs })
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '批量更新配置失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置配置
|
||||
*/
|
||||
async resetConfig(key: string): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/system/configs/${key}/reset`, {
|
||||
method: 'POST',
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '重置配置失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
*/
|
||||
async clearCache(cacheType?: string): Promise<void> {
|
||||
const url = cacheType
|
||||
? `${this.baseUrl}/system/cache/clear?type=${cacheType}`
|
||||
: `${this.baseUrl}/system/cache/clear`
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '清除缓存失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存列表
|
||||
*/
|
||||
async getCacheList(): Promise<{ name: string; size: number }[]> {
|
||||
const response = await fetch(`${this.baseUrl}/system/cache/list`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<any[]>
|
||||
if (result.code !== 200) {
|
||||
return []
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统信息
|
||||
*/
|
||||
async getSystemInfo(): Promise<{
|
||||
version: string
|
||||
uptime: number
|
||||
memory: { total: number; used: number; free: number }
|
||||
cpu: number
|
||||
threads: number
|
||||
}> {
|
||||
const response = await fetch(`${this.baseUrl}/system/info`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<any>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '获取系统信息失败')
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
}
|
||||
|
||||
export const systemConfigService = new SystemConfigService()
|
||||
export default systemConfigService
|
||||
202
frontend/admin/src/services/userManage.ts
Normal file
202
frontend/admin/src/services/userManage.ts
Normal file
@@ -0,0 +1,202 @@
|
||||
/**
|
||||
* 用户管理服务
|
||||
*/
|
||||
|
||||
export interface User {
|
||||
id: number
|
||||
username: string
|
||||
email?: string
|
||||
phone?: string
|
||||
nickname?: string
|
||||
avatar?: string
|
||||
status: UserStatus
|
||||
roles?: string[]
|
||||
departmentId?: number
|
||||
departmentName?: string
|
||||
realNameVerified?: boolean
|
||||
createdAt?: string
|
||||
updatedAt?: string
|
||||
}
|
||||
|
||||
export type UserStatus = 'ACTIVE' | 'FROZEN' | 'DISABLED'
|
||||
|
||||
export interface ApiResponse<T> {
|
||||
code: number
|
||||
data: T
|
||||
message?: string
|
||||
}
|
||||
|
||||
export interface UserListQuery {
|
||||
page?: number
|
||||
size?: number
|
||||
keyword?: string
|
||||
status?: string
|
||||
departmentId?: number
|
||||
startDate?: string
|
||||
endDate?: string
|
||||
}
|
||||
|
||||
class UserService {
|
||||
private baseUrl = '/api'
|
||||
|
||||
/**
|
||||
* 获取用户列表
|
||||
*/
|
||||
async getUsers(params?: UserListQuery): Promise<User[]> {
|
||||
const searchParams = new URLSearchParams()
|
||||
if (params?.page) searchParams.set('page', String(params.page))
|
||||
if (params?.size) searchParams.set('size', String(params.size))
|
||||
if (params?.keyword) searchParams.set('keyword', params.keyword)
|
||||
if (params?.status) searchParams.set('status', params.status)
|
||||
|
||||
const response = await fetch(`${this.baseUrl}/users?${searchParams}`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<User[]>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '获取用户列表失败')
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单个用户详情
|
||||
*/
|
||||
async getUserById(id: number): Promise<User | null> {
|
||||
const response = await fetch(`${this.baseUrl}/users/${id}`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<User>
|
||||
if (result.code !== 200) {
|
||||
return null
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建用户
|
||||
*/
|
||||
async createUser(data: Partial<User>): Promise<number> {
|
||||
const response = await fetch(`${this.baseUrl}/users`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
const result = await response.json() as ApiResponse<number>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '创建用户失败')
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户
|
||||
*/
|
||||
async updateUser(id: number, data: Partial<User>): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/users/${id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '更新用户失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
*/
|
||||
async deleteUser(id: number): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/users/${id}`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '删除用户失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 冻结用户
|
||||
*/
|
||||
async freezeUser(id: number): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/users/${id}/freeze`, {
|
||||
method: 'POST',
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '冻结用户失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解冻用户
|
||||
*/
|
||||
async unfreezeUser(id: number): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/users/${id}/unfreeze`, {
|
||||
method: 'POST',
|
||||
credentials: 'include'
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '解冻用户失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 分配角色
|
||||
*/
|
||||
async assignRoles(userId: number, roleIds: number[]): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/users/${userId}/roles`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({ roleIds })
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '分配角色失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 实名认证
|
||||
*/
|
||||
async verifyRealName(userId: number, realNameInfo: any): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/users/${userId}/verify`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(realNameInfo)
|
||||
})
|
||||
const result = await response.json() as ApiResponse<void>
|
||||
if (result.code !== 200) {
|
||||
throw new Error(result.message || '实名认证失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出用户
|
||||
*/
|
||||
async exportUsers(params?: UserListQuery): Promise<Blob> {
|
||||
const searchParams = new URLSearchParams()
|
||||
if (params?.keyword) searchParams.set('keyword', params.keyword)
|
||||
if (params?.status) searchParams.set('status', params.status)
|
||||
|
||||
const response = await fetch(`${this.baseUrl}/users/export?${searchParams}`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
if (!response.ok) {
|
||||
throw new Error('导出用户失败')
|
||||
}
|
||||
return response.blob()
|
||||
}
|
||||
}
|
||||
|
||||
export const userService = new UserService()
|
||||
export default userService
|
||||
48
frontend/admin/src/types/activity.ts
Normal file
48
frontend/admin/src/types/activity.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* 活动类型定义
|
||||
*/
|
||||
|
||||
export interface Activity {
|
||||
id?: number
|
||||
name: string
|
||||
description?: string
|
||||
shortLinkPrefix?: string
|
||||
startTime: string
|
||||
endTime: string
|
||||
status: ActivityStatus
|
||||
rewardType?: RewardType
|
||||
rewardAmount?: number
|
||||
rewardDesc?: string
|
||||
posterUrl?: string
|
||||
callbackUrl?: string
|
||||
createdAt?: string
|
||||
updatedAt?: string
|
||||
}
|
||||
|
||||
export type ActivityStatus = 'DRAFT' | 'PUBLISHED' | 'PAUSED' | 'ENDED'
|
||||
|
||||
export type RewardType = 'COUPON' | 'POINTS' | 'CASH' | 'GIFT'
|
||||
|
||||
export interface ActivityStats {
|
||||
views: number
|
||||
shares: number
|
||||
clicks: number
|
||||
conversions: number
|
||||
rewardIssued: number
|
||||
}
|
||||
|
||||
export interface ActivityGraphData {
|
||||
dates: string[]
|
||||
views: number[]
|
||||
shares: number[]
|
||||
clicks: number[]
|
||||
}
|
||||
|
||||
export interface LeaderboardEntry {
|
||||
rank: number
|
||||
userId: string
|
||||
userName: string
|
||||
shares: number
|
||||
clicks: number
|
||||
rewards: number
|
||||
}
|
||||
Reference in New Issue
Block a user