返回 AiToEarn
task.controller.ts
根目录 / project / aitoearn-electron / server / src / modules / task / task.controller.ts
1 /*
2 * @Author: nevin
3 * @Date: 2025-02-18 22:32:02
4 * @LastEditTime: 2025-05-06 13:47:50
5 * @LastEditors: nevin
6 * @Description:
7 */
8 import {
9 Body,
10 Controller,
11 Get,
12 NotFoundException,
13 Param,
14 Post,
15 Query,
16 } from '@nestjs/common';
17 import { ApiOperation, ApiTags } from '@nestjs/swagger';
18 import { GetToken, Public } from '../../auth/auth.guard';
19 import { TokenInfo } from '../../auth/interfaces/auth.interfaces';
20 import { ApiResult } from '../../common/decorators/api-result.decorator';
21 import { Task } from '../../db/schema/task.schema';
22 import { QueryMineTaskDto, QueryTaskDto } from './dto/query-task.dto';
23 import { TaskService } from './task.service';
24 import { UserTaskService } from './user-task.service';
25 import { SubmitTaskDto } from './dto/submit-task.dto';
26 import { UserTaskStatus } from 'src/db/schema/user-task.schema';
27 import { FinanceService } from '../finance/finance.service';
28 import {
29 UserWalletRecordStatus,
30 UserWalletRecordType,
31 } from 'src/db/schema/userWalletRecord.shema';
32 import { AppHttpException } from 'src/filters/http-exception.filter';
33 import { ErrHttpBack } from 'src/filters/http-exception.back-code';
34 import { ApplyTaskDto } from './dto/applyTask.dto';
35 import { TaskMaterial } from 'src/db/schema/taskMaterial.schema';
36 import { Queue } from 'bullmq';
37 import { InjectQueue } from '@nestjs/bullmq';
38 @ApiTags('tasks - 任务')
39 @Controller('tasks')
40 export class TaskController {
41 constructor(
42 private readonly taskService: TaskService,
43 private readonly userTaskService: UserTaskService,
44 private readonly financeService: FinanceService,
45 @InjectQueue('bull_aotu_task_audit') private bullTaskAuditQueue: Queue,
46 ) {}
47
48 @Get('list')
49 @ApiOperation({ summary: '获取任务列表' })
50 @ApiResult({ type: [Task], isPage: true })
51 async findAll(@GetToken() token: TokenInfo, @Query() query: QueryTaskDto) {
52 return await this.taskService.findAll(token.id, query);
53 }
54
55 @Get('mine/list')
56 @ApiOperation({ summary: '获取我的任务列表' })
57 @ApiResult({ type: [Task], isPage: true })
58 async findMineList(
59 @GetToken() token: TokenInfo,
60 @Query() query: QueryMineTaskDto,
61 ) {
62 return await this.userTaskService.getUserTasks(token.id, query);
63 }
64
65 @Public()
66 @Get('info/:id')
67 @ApiOperation({ summary: '获取任务详情' })
68 @ApiResult({ type: Task })
69 async findOne(@Param('id') id: string) {
70 return await this.taskService.findOne(id);
71 }
72
73 @ApiOperation({ summary: '申请任务: 保持一定时间' })
74 @ApiResult({ type: Boolean })
75 @Post('apply/:id')
76 async applyForTask(
77 @Param('id') id: string,
78 @GetToken() token: TokenInfo,
79 @Body() body: ApplyTaskDto,
80 ) {
81 const task = await this.taskService.findOne(id);
82 if (!task) throw new NotFoundException('任务不存在');
83
84 if (!!body.taskMaterialId) {
85 const taskMaterial = await this.taskService.getTaskMaterialById(
86 body.taskMaterialId,
87 );
88 if (!taskMaterial) throw new NotFoundException('任务素材不存在');
89 }
90
91 const res = await this.userTaskService.userApplyTask(token.id, task, body);
92
93 if (!!body.taskMaterialId)
94 this.taskService.upTaskMaterialUsedCount(body.taskMaterialId);
95
96 return res;
97 }
98
99 @ApiOperation({ summary: '提交任务 id是用户任务ID' })
100 @ApiResult({ type: Boolean })
101 @Post('submit/:id')
102 async submitTask(
103 @GetToken() token: TokenInfo,
104 @Param('id') id: string,
105 @Body() data: SubmitTaskDto,
106 ) {
107 const userTask = await this.userTaskService.getUserTaskInfoById(id);
108 if (!userTask || userTask.userId.toString() !== token.id)
109 throw new AppHttpException(ErrHttpBack.user_task_no_had);
110
111 const res = await this.userTaskService.submitTask(userTask, data);
112
113 if (res.status === UserTaskStatus.PENDING) {
114 this.bullTaskAuditQueue.add(
115 'start',
116 {
117 userTaskId: id,
118 },
119 {
120 attempts: 5, // 这个作业特定的重试次数
121 backoff: {
122 type: 'fixed', // 固定间隔重试
123 delay: 1000 * 30, // 每次重试间隔5秒
124 },
125 },
126 );
127 }
128
129 return res;
130 }
131
132 // 任务提现(创建提现数据)
133 @ApiOperation({ summary: '用户任务提现' })
134 @ApiResult({ type: Boolean })
135 @Post('withdraw/:id')
136 async withdrawCashUserTask(
137 @GetToken() token: TokenInfo,
138 @Param('id') id: string,
139 @Body() data: { accountId: string },
140 ) {
141 const userTask = await this.userTaskService.getUserTaskInfoById(id);
142 if (!userTask || userTask.userId.toString() !== token.id)
143 throw new NotFoundException('任务不存在');
144 if (userTask.status !== UserTaskStatus.APPROVED)
145 throw new NotFoundException('任务状态不正确');
146 const account = await this.financeService.getUserWalletAccountById(
147 data.accountId,
148 );
149 if (!account) throw new NotFoundException('钱包账户不存在');
150
151 return await this.financeService.createUserWalletRecord(token.id, account, {
152 dataId: userTask.id,
153 type: UserWalletRecordType.WITHDRAW,
154 balance: userTask.reward, // 将 number 转换为 Decimal128
155 des: '任务提现',
156 status: UserWalletRecordStatus.WAIT,
157 });
158 }
159
160 @ApiOperation({ summary: '统计合计进行中的任务的金额总数' })
161 @Get('reward/amount')
162 @ApiResult({ type: Number })
163 async getTotalAmountOfDoingTasks(@GetToken() token: TokenInfo) {
164 return await this.taskService.getTotalAmountOfDoingTasks(token.id);
165 }
166
167 @ApiOperation({ summary: '获取任务的最优素材' })
168 @Get('material/frist/:id')
169 @ApiResult({ type: TaskMaterial })
170 async getFristTaskMaterial(@Param('id') id: string) {
171 return await this.taskService.getFristTaskMaterial(id);
172 }
173 }
174
174 lines TYPESCRIPT