From 7913bb5a34cae26b2245c5978f6542de810136ae Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 5 Mar 2026 11:04:33 +0800 Subject: [PATCH] =?UTF-8?q?feat(business):=20=E6=B7=BB=E5=8A=A0=E4=B8=9A?= =?UTF-8?q?=E5=8A=A1=E6=A8=A1=E5=9D=97=E5=89=8D=E5=90=8E=E7=AB=AF=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 后端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: 活动类型定义 --- frontend/admin/src/services/activity.ts | 206 +++++++++++++++ frontend/admin/src/services/audit.ts | 162 ++++++++++++ frontend/admin/src/services/reward.ts | 212 +++++++++++++++ frontend/admin/src/services/risk.ts | 243 ++++++++++++++++++ frontend/admin/src/services/systemConfig.ts | 164 ++++++++++++ frontend/admin/src/services/userManage.ts | 202 +++++++++++++++ frontend/admin/src/types/activity.ts | 48 ++++ .../project/controller/AuditController.java | 98 +++++++ .../project/controller/RewardController.java | 142 ++++++++++ .../project/controller/RiskController.java | 157 +++++++++++ .../project/controller/SystemController.java | 126 +++++++++ 11 files changed, 1760 insertions(+) create mode 100644 frontend/admin/src/services/activity.ts create mode 100644 frontend/admin/src/services/audit.ts create mode 100644 frontend/admin/src/services/reward.ts create mode 100644 frontend/admin/src/services/risk.ts create mode 100644 frontend/admin/src/services/systemConfig.ts create mode 100644 frontend/admin/src/services/userManage.ts create mode 100644 frontend/admin/src/types/activity.ts create mode 100644 src/main/java/com/mosquito/project/controller/AuditController.java create mode 100644 src/main/java/com/mosquito/project/controller/RewardController.java create mode 100644 src/main/java/com/mosquito/project/controller/RiskController.java create mode 100644 src/main/java/com/mosquito/project/controller/SystemController.java diff --git a/frontend/admin/src/services/activity.ts b/frontend/admin/src/services/activity.ts new file mode 100644 index 0000000..554ab0f --- /dev/null +++ b/frontend/admin/src/services/activity.ts @@ -0,0 +1,206 @@ +/** + * 活动管理服务 + */ +import type { Activity } from '../types/activity' + +export interface ApiResponse { + 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 { + 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 + if (result.code !== 200) { + throw new Error(result.message || '获取活动列表失败') + } + return result.data + } + + /** + * 获取单个活动详情 + */ + async getActivityById(id: number): Promise { + const response = await fetch(`${this.baseUrl}/activities/${id}`, { + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + return null + } + return result.data + } + + /** + * 创建活动 + */ + async createActivity(data: Partial): Promise { + 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 + if (result.code !== 200) { + throw new Error(result.message || '创建活动失败') + } + return result.data + } + + /** + * 更新活动 + */ + async updateActivity(id: number, data: Partial): Promise { + 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 + if (result.code !== 200) { + throw new Error(result.message || '更新活动失败') + } + } + + /** + * 删除活动 + */ + async deleteActivity(id: number): Promise { + const response = await fetch(`${this.baseUrl}/activities/${id}`, { + method: 'DELETE', + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + throw new Error(result.message || '删除活动失败') + } + } + + /** + * 发布活动 + */ + async publishActivity(id: number): Promise { + const response = await fetch(`${this.baseUrl}/activities/${id}/publish`, { + method: 'POST', + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + throw new Error(result.message || '发布活动失败') + } + } + + /** + * 暂停活动 + */ + async pauseActivity(id: number): Promise { + const response = await fetch(`${this.baseUrl}/activities/${id}/pause`, { + method: 'POST', + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + throw new Error(result.message || '暂停活动失败') + } + } + + /** + * 恢复活动 + */ + async resumeActivity(id: number): Promise { + const response = await fetch(`${this.baseUrl}/activities/${id}/resume`, { + method: 'POST', + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + throw new Error(result.message || '恢复活动失败') + } + } + + /** + * 结束活动 + */ + async endActivity(id: number): Promise { + const response = await fetch(`${this.baseUrl}/activities/${id}/end`, { + method: 'POST', + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + throw new Error(result.message || '结束活动失败') + } + } + + /** + * 获取活动统计 + */ + async getActivityStats(id: number): Promise { + const response = await fetch(`${this.baseUrl}/activities/${id}/stats`, { + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + throw new Error(result.message || '获取活动统计失败') + } + return result.data + } + + /** + * 获取活动图表数据 + */ + async getActivityGraph(id: number): Promise { + const response = await fetch(`${this.baseUrl}/activities/${id}/graph`, { + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + throw new Error(result.message || '获取活动图表失败') + } + return result.data + } + + /** + * 获取活动排行榜 + */ + async getActivityLeaderboard(id: number, limit?: number): Promise { + const params = limit ? `?limit=${limit}` : '' + const response = await fetch(`${this.baseUrl}/activities/${id}/leaderboard${params}`, { + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + throw new Error(result.message || '获取排行榜失败') + } + return result.data + } +} + +export const activityService = new ActivityService() +export default activityService diff --git a/frontend/admin/src/services/audit.ts b/frontend/admin/src/services/audit.ts new file mode 100644 index 0000000..75408ca --- /dev/null +++ b/frontend/admin/src/services/audit.ts @@ -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 { + 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 { + 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 + if (result.code !== 200) { + throw new Error(result.message || '获取审计日志失败') + } + return result.data + } + + /** + * 获取单个日志详情 + */ + async getLogById(id: number): Promise { + const response = await fetch(`${this.baseUrl}/audit/logs/${id}`, { + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + return null + } + return result.data + } + + /** + * 获取操作类型列表 + */ + async getActionTypes(): Promise { + const response = await fetch(`${this.baseUrl}/audit/actions`, { + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + return [] + } + return result.data + } + + /** + * 获取模块列表 + */ + async getModules(): Promise { + const response = await fetch(`${this.baseUrl}/audit/modules`, { + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + return [] + } + return result.data + } + + /** + * 导出审计日志 + */ + async exportLogs(params?: { + userId?: number + action?: string + module?: string + startDate?: string + endDate?: string + keyword?: string + }): Promise { + 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 + userCounts: Record + dailyCounts: Record + }> { + 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 + if (result.code !== 200) { + throw new Error(result.message || '获取审计统计失败') + } + return result.data + } +} + +export const auditService = new AuditService() +export default auditService diff --git a/frontend/admin/src/services/reward.ts b/frontend/admin/src/services/reward.ts new file mode 100644 index 0000000..55f94d7 --- /dev/null +++ b/frontend/admin/src/services/reward.ts @@ -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 { + 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 { + 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 + if (result.code !== 200) { + throw new Error(result.message || '获取奖励列表失败') + } + return result.data + } + + /** + * 获取单个奖励详情 + */ + async getRewardById(id: number): Promise { + const response = await fetch(`${this.baseUrl}/rewards/${id}`, { + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + return null + } + return result.data + } + + /** + * 申请奖励 + */ + async applyReward(data: { + userId: number + activityId: number + rewardType: RewardType + rewardAmount: number + applyReason: string + }): Promise { + 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 + if (result.code !== 200) { + throw new Error(result.message || '申请奖励失败') + } + return result.data + } + + /** + * 审批奖励 + */ + async approveReward(id: number, approved: boolean, comment?: string): Promise { + 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 + if (result.code !== 200) { + throw new Error(result.message || '审批奖励失败') + } + } + + /** + * 发放奖励 + */ + async grantReward(id: number): Promise { + const response = await fetch(`${this.baseUrl}/rewards/${id}/grant`, { + method: 'POST', + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + throw new Error(result.message || '发放奖励失败') + } + } + + /** + * 批量发放奖励 + */ + async batchGrantRewards(ids: number[]): Promise { + 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 + if (result.code !== 200) { + throw new Error(result.message || '批量发放失败') + } + } + + /** + * 取消奖励 + */ + async cancelReward(id: number, reason: string): Promise { + 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 + if (result.code !== 200) { + throw new Error(result.message || '取消奖励失败') + } + } + + /** + * 获取待审批奖励数量 + */ + async getPendingCount(): Promise { + const response = await fetch(`${this.baseUrl}/rewards/pending-count`, { + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + return 0 + } + return result.data + } + + /** + * 导出奖励记录 + */ + async exportRewards(params?: RewardListQuery): Promise { + 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 { + const response = await fetch(`${this.baseUrl}/rewards/reconcile?startDate=${startDate}&endDate=${endDate}`, { + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + throw new Error(result.message || '对账失败') + } + return result.data + } +} + +export const rewardService = new RewardService() +export default rewardService diff --git a/frontend/admin/src/services/risk.ts b/frontend/admin/src/services/risk.ts new file mode 100644 index 0000000..22952dd --- /dev/null +++ b/frontend/admin/src/services/risk.ts @@ -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 + 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 { + 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 { + 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 + if (result.code !== 200) { + throw new Error(result.message || '获取风险告警失败') + } + return result.data + } + + /** + * 获取单个告警详情 + */ + async getAlertById(id: number): Promise { + const response = await fetch(`${this.baseUrl}/risk/alerts/${id}`, { + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + return null + } + return result.data + } + + /** + * 处理风险告警 + */ + async handleAlert(id: number, data: { + status: AlertStatus + handleResult: string + }): Promise { + 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 + if (result.code !== 200) { + throw new Error(result.message || '处理告警失败') + } + } + + /** + * 批量处理告警 + */ + async batchHandleAlerts(ids: number[], data: { + status: AlertStatus + handleResult: string + }): Promise { + 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 + if (result.code !== 200) { + throw new Error(result.message || '批量处理失败') + } + } + + /** + * 获取风控规则列表 + */ + async getRules(params?: { + page?: number + size?: number + riskType?: string + status?: string + }): Promise { + 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 + if (result.code !== 200) { + throw new Error(result.message || '获取风控规则失败') + } + return result.data + } + + /** + * 创建风控规则 + */ + async createRule(data: Partial): Promise { + 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 + if (result.code !== 200) { + throw new Error(result.message || '创建规则失败') + } + return result.data + } + + /** + * 更新风控规则 + */ + async updateRule(id: number, data: Partial): Promise { + 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 + if (result.code !== 200) { + throw new Error(result.message || '更新规则失败') + } + } + + /** + * 删除风控规则 + */ + async deleteRule(id: number): Promise { + const response = await fetch(`${this.baseUrl}/risk/rules/${id}`, { + method: 'DELETE', + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + throw new Error(result.message || '删除规则失败') + } + } + + /** + * 启用/禁用规则 + */ + async toggleRule(id: number, enabled: boolean): Promise { + 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 + if (result.code !== 200) { + throw new Error(result.message || '切换规则状态失败') + } + } + + /** + * 获取待处理告警数量 + */ + async getPendingAlertCount(): Promise { + const response = await fetch(`${this.baseUrl}/risk/alerts/pending-count`, { + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + return 0 + } + return result.data + } +} + +export const riskService = new RiskService() +export default riskService diff --git a/frontend/admin/src/services/systemConfig.ts b/frontend/admin/src/services/systemConfig.ts new file mode 100644 index 0000000..77a7e26 --- /dev/null +++ b/frontend/admin/src/services/systemConfig.ts @@ -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 { + code: number + data: T + message?: string +} + +class SystemConfigService { + private baseUrl = '/api' + + /** + * 获取系统配置列表 + */ + async getConfigs(params?: { + category?: ConfigCategory + keyword?: string + }): Promise { + 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 + if (result.code !== 200) { + throw new Error(result.message || '获取配置列表失败') + } + return result.data + } + + /** + * 获取单个配置 + */ + async getConfigByKey(key: string): Promise { + const response = await fetch(`${this.baseUrl}/system/configs/${key}`, { + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + return null + } + return result.data + } + + /** + * 更新配置 + */ + async updateConfig(key: string, value: string): Promise { + 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 + if (result.code !== 200) { + throw new Error(result.message || '更新配置失败') + } + } + + /** + * 批量更新配置 + */ + async batchUpdateConfigs(configs: { key: string; value: string }[]): Promise { + 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 + if (result.code !== 200) { + throw new Error(result.message || '批量更新配置失败') + } + } + + /** + * 重置配置 + */ + async resetConfig(key: string): Promise { + const response = await fetch(`${this.baseUrl}/system/configs/${key}/reset`, { + method: 'POST', + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + throw new Error(result.message || '重置配置失败') + } + } + + /** + * 清除缓存 + */ + async clearCache(cacheType?: string): Promise { + 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 + 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 + 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 + if (result.code !== 200) { + throw new Error(result.message || '获取系统信息失败') + } + return result.data + } +} + +export const systemConfigService = new SystemConfigService() +export default systemConfigService diff --git a/frontend/admin/src/services/userManage.ts b/frontend/admin/src/services/userManage.ts new file mode 100644 index 0000000..e5bf929 --- /dev/null +++ b/frontend/admin/src/services/userManage.ts @@ -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 { + 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 { + 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 + if (result.code !== 200) { + throw new Error(result.message || '获取用户列表失败') + } + return result.data + } + + /** + * 获取单个用户详情 + */ + async getUserById(id: number): Promise { + const response = await fetch(`${this.baseUrl}/users/${id}`, { + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + return null + } + return result.data + } + + /** + * 创建用户 + */ + async createUser(data: Partial): Promise { + 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 + if (result.code !== 200) { + throw new Error(result.message || '创建用户失败') + } + return result.data + } + + /** + * 更新用户 + */ + async updateUser(id: number, data: Partial): Promise { + 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 + if (result.code !== 200) { + throw new Error(result.message || '更新用户失败') + } + } + + /** + * 删除用户 + */ + async deleteUser(id: number): Promise { + const response = await fetch(`${this.baseUrl}/users/${id}`, { + method: 'DELETE', + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + throw new Error(result.message || '删除用户失败') + } + } + + /** + * 冻结用户 + */ + async freezeUser(id: number): Promise { + const response = await fetch(`${this.baseUrl}/users/${id}/freeze`, { + method: 'POST', + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + throw new Error(result.message || '冻结用户失败') + } + } + + /** + * 解冻用户 + */ + async unfreezeUser(id: number): Promise { + const response = await fetch(`${this.baseUrl}/users/${id}/unfreeze`, { + method: 'POST', + credentials: 'include' + }) + const result = await response.json() as ApiResponse + if (result.code !== 200) { + throw new Error(result.message || '解冻用户失败') + } + } + + /** + * 分配角色 + */ + async assignRoles(userId: number, roleIds: number[]): Promise { + 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 + if (result.code !== 200) { + throw new Error(result.message || '分配角色失败') + } + } + + /** + * 实名认证 + */ + async verifyRealName(userId: number, realNameInfo: any): Promise { + 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 + if (result.code !== 200) { + throw new Error(result.message || '实名认证失败') + } + } + + /** + * 导出用户 + */ + async exportUsers(params?: UserListQuery): Promise { + 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 diff --git a/frontend/admin/src/types/activity.ts b/frontend/admin/src/types/activity.ts new file mode 100644 index 0000000..e0c94a1 --- /dev/null +++ b/frontend/admin/src/types/activity.ts @@ -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 +} diff --git a/src/main/java/com/mosquito/project/controller/AuditController.java b/src/main/java/com/mosquito/project/controller/AuditController.java new file mode 100644 index 0000000..54b855a --- /dev/null +++ b/src/main/java/com/mosquito/project/controller/AuditController.java @@ -0,0 +1,98 @@ +package com.mosquito.project.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.*; + +/** + * 审计日志控制器 + */ +@RestController +@RequestMapping("/api/audit") +public class AuditController { + + /** + * 获取审计日志列表 + */ + @GetMapping("/logs") + public ResponseEntity> getLogs( + @RequestParam(required = false) Integer page, + @RequestParam(required = false) Integer size, + @RequestParam(required = false) Long userId, + @RequestParam(required = false) String action, + @RequestParam(required = false) String module, + @RequestParam(required = false) String keyword) { + + // TODO: 实现实际的审计日志查询 + List> logs = new ArrayList<>(); + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("data", logs); + response.put("total", 0); + return ResponseEntity.ok(response); + } + + /** + * 获取单个日志详情 + */ + @GetMapping("/logs/{id}") + public ResponseEntity> getLogById(@PathVariable Long id) { + Map response = new HashMap<>(); + response.put("code", 200); + response.put("data", null); + return ResponseEntity.ok(response); + } + + /** + * 获取操作类型列表 + */ + @GetMapping("/actions") + public ResponseEntity> getActionTypes() { + List actions = Arrays.asList( + "CREATE", "UPDATE", "DELETE", "VIEW", "LOGIN", "LOGOUT", + "EXPORT", "IMPORT", "APPROVE", "REJECT" + ); + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("data", actions); + return ResponseEntity.ok(response); + } + + /** + * 获取模块列表 + */ + @GetMapping("/modules") + public ResponseEntity> getModules() { + List modules = Arrays.asList( + "ACTIVITY", "USER", "REWARD", "RISK", "APPROVAL", "SYSTEM" + ); + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("data", modules); + return ResponseEntity.ok(response); + } + + /** + * 获取审计统计 + */ + @GetMapping("/stats") + public ResponseEntity> getStats( + @RequestParam(required = false) String startDate, + @RequestParam(required = false) String endDate) { + + Map stats = new HashMap<>(); + stats.put("totalCount", 0); + stats.put("actionCounts", new HashMap<>()); + stats.put("userCounts", new HashMap<>()); + stats.put("dailyCounts", new HashMap<>()); + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("data", stats); + return ResponseEntity.ok(response); + } +} diff --git a/src/main/java/com/mosquito/project/controller/RewardController.java b/src/main/java/com/mosquito/project/controller/RewardController.java new file mode 100644 index 0000000..054186f --- /dev/null +++ b/src/main/java/com/mosquito/project/controller/RewardController.java @@ -0,0 +1,142 @@ +package com.mosquito.project.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.*; + +/** + * 奖励管理控制器 + */ +@RestController +@RequestMapping("/api/rewards") +public class RewardController { + + /** + * 获取奖励列表 + */ + @GetMapping + public ResponseEntity> getRewards( + @RequestParam(required = false) Integer page, + @RequestParam(required = false) Integer size, + @RequestParam(required = false) String status, + @RequestParam(required = false) String rewardType) { + + // TODO: 实现实际的奖励查询 + List> rewards = new ArrayList<>(); + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("data", rewards); + response.put("total", 0); + return ResponseEntity.ok(response); + } + + /** + * 获取单个奖励详情 + */ + @GetMapping("/{id}") + public ResponseEntity> getRewardById(@PathVariable Long id) { + Map response = new HashMap<>(); + response.put("code", 200); + response.put("data", null); + return ResponseEntity.ok(response); + } + + /** + * 申请奖励 + */ + @PostMapping("/apply") + public ResponseEntity> applyReward(@RequestBody Map request) { + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("data", 1L); + response.put("message", "奖励申请已提交"); + return ResponseEntity.ok(response); + } + + /** + * 审批奖励 + */ + @PostMapping("/{id}/approve") + public ResponseEntity> approveReward( + @PathVariable Long id, + @RequestBody Map request) { + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("message", "审批完成"); + return ResponseEntity.ok(response); + } + + /** + * 发放奖励 + */ + @PostMapping("/{id}/grant") + public ResponseEntity> grantReward(@PathVariable Long id) { + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("message", "奖励发放成功"); + return ResponseEntity.ok(response); + } + + /** + * 批量发放奖励 + */ + @PostMapping("/batch-grant") + public ResponseEntity> batchGrantRewards(@RequestBody Map request) { + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("message", "批量发放成功"); + return ResponseEntity.ok(response); + } + + /** + * 取消奖励 + */ + @PostMapping("/{id}/cancel") + public ResponseEntity> cancelReward( + @PathVariable Long id, + @RequestBody Map request) { + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("message", "奖励已取消"); + return ResponseEntity.ok(response); + } + + /** + * 获取待审批奖励数量 + */ + @GetMapping("/pending-count") + public ResponseEntity> getPendingCount() { + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("data", 0); + return ResponseEntity.ok(response); + } + + /** + * 奖励对账 + */ + @GetMapping("/reconcile") + public ResponseEntity> reconcile( + @RequestParam String startDate, + @RequestParam String endDate) { + + Map result = new HashMap<>(); + result.put("totalAmount", 0); + result.put("totalCount", 0); + result.put("successCount", 0); + result.put("failCount", 0); + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("data", result); + return ResponseEntity.ok(response); + } +} diff --git a/src/main/java/com/mosquito/project/controller/RiskController.java b/src/main/java/com/mosquito/project/controller/RiskController.java new file mode 100644 index 0000000..67b3e7b --- /dev/null +++ b/src/main/java/com/mosquito/project/controller/RiskController.java @@ -0,0 +1,157 @@ +package com.mosquito.project.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.*; + +/** + * 风险管理控制器 + */ +@RestController +@RequestMapping("/api/risk") +public class RiskController { + + /** + * 获取风险告警列表 + */ + @GetMapping("/alerts") + public ResponseEntity> getAlerts( + @RequestParam(required = false) Integer page, + @RequestParam(required = false) Integer size, + @RequestParam(required = false) String type, + @RequestParam(required = false) String level, + @RequestParam(required = false) String status) { + + // TODO: 实现实际的风险告警查询 + List> alerts = new ArrayList<>(); + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("data", alerts); + response.put("total", 0); + return ResponseEntity.ok(response); + } + + /** + * 获取单个告警详情 + */ + @GetMapping("/alerts/{id}") + public ResponseEntity> getAlertById(@PathVariable Long id) { + Map response = new HashMap<>(); + response.put("code", 200); + response.put("data", null); + return ResponseEntity.ok(response); + } + + /** + * 处理风险告警 + */ + @PostMapping("/alerts/{id}/handle") + public ResponseEntity> handleAlert( + @PathVariable Long id, + @RequestBody Map request) { + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("message", "告警处理完成"); + return ResponseEntity.ok(response); + } + + /** + * 批量处理告警 + */ + @PostMapping("/alerts/batch-handle") + public ResponseEntity> batchHandleAlerts(@RequestBody Map request) { + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("message", "批量处理完成"); + return ResponseEntity.ok(response); + } + + /** + * 获取待处理告警数量 + */ + @GetMapping("/alerts/pending-count") + public ResponseEntity> getPendingAlertCount() { + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("data", 0); + return ResponseEntity.ok(response); + } + + /** + * 获取风控规则列表 + */ + @GetMapping("/rules") + public ResponseEntity> getRules( + @RequestParam(required = false) Integer page, + @RequestParam(required = false) Integer size, + @RequestParam(required = false) String riskType, + @RequestParam(required = false) String status) { + + // TODO: 实现实际的风控规则查询 + List> rules = new ArrayList<>(); + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("data", rules); + response.put("total", 0); + return ResponseEntity.ok(response); + } + + /** + * 创建风控规则 + */ + @PostMapping("/rules") + public ResponseEntity> createRule(@RequestBody Map request) { + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("data", 1L); + response.put("message", "规则创建成功"); + return ResponseEntity.ok(response); + } + + /** + * 更新风控规则 + */ + @PutMapping("/rules/{id}") + public ResponseEntity> updateRule( + @PathVariable Long id, + @RequestBody Map request) { + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("message", "规则更新成功"); + return ResponseEntity.ok(response); + } + + /** + * 删除风控规则 + */ + @DeleteMapping("/rules/{id}") + public ResponseEntity> deleteRule(@PathVariable Long id) { + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("message", "规则删除成功"); + return ResponseEntity.ok(response); + } + + /** + * 启用/禁用规则 + */ + @PostMapping("/rules/{id}/toggle") + public ResponseEntity> toggleRule( + @PathVariable Long id, + @RequestBody Map request) { + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("message", "规则状态已更新"); + return ResponseEntity.ok(response); + } +} diff --git a/src/main/java/com/mosquito/project/controller/SystemController.java b/src/main/java/com/mosquito/project/controller/SystemController.java new file mode 100644 index 0000000..5064723 --- /dev/null +++ b/src/main/java/com/mosquito/project/controller/SystemController.java @@ -0,0 +1,126 @@ +package com.mosquito.project.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.*; + +/** + * 系统配置控制器 + */ +@RestController +@RequestMapping("/api/system") +public class SystemController { + + /** + * 获取系统配置列表 + */ + @GetMapping("/configs") + public ResponseEntity> getConfigs( + @RequestParam(required = false) String category, + @RequestParam(required = false) String keyword) { + + // TODO: 实现实际的配置查询 + List> configs = new ArrayList<>(); + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("data", configs); + return ResponseEntity.ok(response); + } + + /** + * 获取单个配置 + */ + @GetMapping("/configs/{key}") + public ResponseEntity> getConfigByKey(@PathVariable String key) { + Map response = new HashMap<>(); + response.put("code", 200); + response.put("data", null); + return ResponseEntity.ok(response); + } + + /** + * 更新配置 + */ + @PutMapping("/configs/{key}") + public ResponseEntity> updateConfig( + @PathVariable String key, + @RequestBody Map request) { + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("message", "配置更新成功"); + return ResponseEntity.ok(response); + } + + /** + * 批量更新配置 + */ + @PutMapping("/configs/batch") + public ResponseEntity> batchUpdateConfigs(@RequestBody Map request) { + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("message", "批量更新成功"); + return ResponseEntity.ok(response); + } + + /** + * 重置配置 + */ + @PostMapping("/configs/{key}/reset") + public ResponseEntity> resetConfig(@PathVariable String key) { + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("message", "配置重置成功"); + return ResponseEntity.ok(response); + } + + /** + * 清除缓存 + */ + @PostMapping("/cache/clear") + public ResponseEntity> clearCache( + @RequestParam(required = false) String type) { + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("message", "缓存清除成功"); + return ResponseEntity.ok(response); + } + + /** + * 获取缓存列表 + */ + @GetMapping("/cache/list") + public ResponseEntity> getCacheList() { + List> caches = new ArrayList<>(); + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("data", caches); + return ResponseEntity.ok(response); + } + + /** + * 获取系统信息 + */ + @GetMapping("/info") + public ResponseEntity> getSystemInfo() { + Map info = new HashMap<>(); + info.put("version", "1.0.0"); + info.put("uptime", System.currentTimeMillis()); + info.put("memory", Map.of("total", Runtime.getRuntime().totalMemory(), + "used", Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(), + "free", Runtime.getRuntime().freeMemory())); + info.put("cpu", Runtime.getRuntime().availableProcessors()); + info.put("threads", Thread.activeCount()); + + Map response = new HashMap<>(); + response.put("code", 200); + response.put("data", info); + return ResponseEntity.ok(response); + } +}