create-dp-koa 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/package.json +1 -1
  2. package/template/.cursor/commands/cheatsheet-backend-controller.md +2 -2
  3. package/template/.cursor/commands/implement-backend-api-controller.md +6 -4
  4. package/template/.cursor/rules/11-backend-controller-recipes.skill.md +89 -10
  5. package/template/.trae/skills/11-backend-controller-recipes.skill.md +91 -10
  6. package/template/src/controllers/example/ExampleController.ts +14 -0
  7. package/template/src/entity/index.ts +1 -15
  8. package/template/src/framework/decorator/processor/AnnotationProcessor.ts +5 -1
  9. package/template/src/routers/index.ts +0 -35
  10. package/template/src/utils/testDataInitializer.ts +2 -269
  11. package/template/test/controllers/example/ExampleController.test.ts +29 -31
  12. package/template/test/framework/annotation/AnnotationDecorators.test.ts +15 -15
  13. package/template/test/framework/annotation/AnnotationExecutor.test.ts +27 -32
  14. package/template/test/framework/annotation/AnnotationProcessor.test.ts +25 -24
  15. package/template/test/framework/annotation/CustomProcessors.test.ts +15 -25
  16. package/template/test/framework/annotation/NewRouter.test.ts +9 -7
  17. package/template/test/framework/annotation/ProcessorManager.test.ts +14 -27
  18. package/template/test/framework/databaseConfig.test.ts +2 -2
  19. package/template/test/integration/integration.test.ts +15 -72
  20. package/template/src/controllers/cacheManagement.controller.ts +0 -131
  21. package/template/src/controllers/captcha.controller.ts +0 -57
  22. package/template/src/controllers/example/NewAnnotationExampleController.ts +0 -159
  23. package/template/src/controllers/example/SwaggerExampleController.ts +0 -205
  24. package/template/src/controllers/example/TransactionExample.controller.ts +0 -336
  25. package/template/src/controllers/health.controller.ts +0 -235
  26. package/template/src/controllers/home/register.controller.ts +0 -58
  27. package/template/src/controllers/home/ytGoods.controller.ts +0 -92
  28. package/template/src/controllers/home/ytShop.controller.ts +0 -135
  29. package/template/src/controllers/home/ytUser.controller.ts +0 -89
  30. package/template/src/controllers/logManagement.controller.ts +0 -396
  31. package/template/src/controllers/public/emailSend.controller.ts +0 -65
  32. package/template/src/controllers/public/ytUserAuth.controller.ts +0 -174
  33. package/template/src/controllers/testData.controller.ts +0 -253
  34. package/template/src/dto/controller/example/NewAnnotationExampleController.dto.ts +0 -73
  35. package/template/src/dto/controller/home/emailSend.controller.dto.ts +0 -40
  36. package/template/src/dto/controller/home/register.controller.dto.ts +0 -45
  37. package/template/src/dto/controller/home/ytGoods.controller.dto.ts +0 -55
  38. package/template/src/dto/controller/home/ytShop.controller.dto.ts +0 -69
  39. package/template/src/dto/controller/home/ytUser.controller.dto.ts +0 -44
  40. package/template/src/dto/controller/public/ytUserAuth.controller.dto.ts +0 -63
  41. package/template/src/dto/goods.dto.ts +0 -212
  42. package/template/src/dto/service/ytService.dto.ts +0 -13
  43. package/template/src/dto/user.dto.ts +0 -177
  44. package/template/src/entity/columnTypes.ts +0 -13
  45. package/template/src/entity/goodsImagesUnlockKey.entity.ts +0 -33
  46. package/template/src/entity/goodsUnlocker.entity.ts +0 -34
  47. package/template/src/entity/shop.entity.ts +0 -52
  48. package/template/src/entity/shopUser.entity.ts +0 -41
  49. package/template/src/entity/ytGoods.entity.ts +0 -94
  50. package/template/src/entity/ytUser.entity.ts +0 -96
  51. package/template/src/examples/SwaggerProcessorExample.ts +0 -169
  52. package/template/src/examples/TransactionManagerDemo.ts +0 -377
  53. package/template/src/framework/utils/dynamicSwagger.ts +0 -410
  54. package/template/src/repository/UserRepository.ts +0 -122
  55. package/template/src/service/paramValidateTest.service.ts +0 -139
  56. package/template/src/service/ytGoods.service.ts +0 -42
  57. package/template/src/service/ytShop.service.ts +0 -90
  58. package/template/src/service/ytUser.service.ts +0 -451
  59. package/template/src/test/swaggerParameterTest.ts +0 -90
  60. package/template/test/controllers/controllers.test.ts +0 -173
  61. package/template/test/controllers/example/NewAnnotationExampleController.test.ts +0 -200
  62. package/template/test/framework/TransactionManagerDemo.test.ts +0 -363
  63. package/template/test/service/business.test.ts +0 -87
  64. package/template/test/service/paramValidateTest.service.test.ts +0 -184
  65. package/template/test/service/ytUser.service.test.ts +0 -566
@@ -1,396 +0,0 @@
1
- import { Context } from 'koa'
2
- import { logger } from '@src/framework/utils/logger'
3
- import { BaseController } from '@src/controllers/base.controller'
4
- import fs from 'fs'
5
- import path from 'path'
6
-
7
- /**
8
- * 日志管理控制器
9
- * 提供日志查询、下载、清理等功能
10
- */
11
- export class LogManagementController extends BaseController {
12
-
13
- /**
14
- * 获取日志统计信息
15
- */
16
- async getLogStats(ctx: Context) {
17
- try {
18
- const logsDir = path.join(process.cwd(), 'logs')
19
- const stats = {
20
- totalFiles: 0,
21
- totalSize: 0,
22
- fileTypes: {} as Record<string, { count: number, size: number }>,
23
- lastModified: null as Date | null
24
- }
25
-
26
- if (fs.existsSync(logsDir)) {
27
- const files = fs.readdirSync(logsDir)
28
-
29
- for (const file of files) {
30
- const filePath = path.join(logsDir, file)
31
- const fileStat = fs.statSync(filePath)
32
-
33
- if (fileStat.isFile()) {
34
- stats.totalFiles++
35
- stats.totalSize += fileStat.size
36
-
37
- const ext = path.extname(file) || 'log'
38
- if (!stats.fileTypes[ext]) {
39
- stats.fileTypes[ext] = { count: 0, size: 0 }
40
- }
41
- stats.fileTypes[ext].count++
42
- stats.fileTypes[ext].size += fileStat.size
43
-
44
- if (!stats.lastModified || fileStat.mtime > stats.lastModified) {
45
- stats.lastModified = fileStat.mtime
46
- }
47
- }
48
- }
49
- }
50
-
51
- logger.info('Log stats retrieved', { stats })
52
-
53
- ctx.body = {
54
- code: 0,
55
- data: stats,
56
- message: '日志统计信息获取成功'
57
- }
58
- } catch (error) {
59
- logger.error('Failed to get log stats', error as Error)
60
- ctx.status = 500
61
- ctx.body = {
62
- code: 500,
63
- message: '获取日志统计信息失败'
64
- }
65
- }
66
- }
67
-
68
- /**
69
- * 获取日志文件列表
70
- */
71
- async getLogFiles(ctx: Context) {
72
- try {
73
- const logsDir = path.join(process.cwd(), 'logs')
74
- const files: any[] = []
75
-
76
- if (fs.existsSync(logsDir)) {
77
- const fileList = fs.readdirSync(logsDir)
78
-
79
- for (const file of fileList) {
80
- const filePath = path.join(logsDir, file)
81
- const fileStat = fs.statSync(filePath)
82
-
83
- if (fileStat.isFile()) {
84
- files.push({
85
- name: file,
86
- size: fileStat.size,
87
- modified: fileStat.mtime,
88
- created: fileStat.birthtime,
89
- type: path.extname(file) || 'log'
90
- })
91
- }
92
- }
93
- }
94
-
95
- // 按修改时间排序
96
- files.sort((a, b) => b.modified.getTime() - a.modified.getTime())
97
-
98
- logger.info('Log files list retrieved', { fileCount: files.length })
99
-
100
- ctx.body = {
101
- code: 0,
102
- data: files,
103
- message: '日志文件列表获取成功'
104
- }
105
- } catch (error) {
106
- logger.error('Failed to get log files', error as Error)
107
- ctx.status = 500
108
- ctx.body = {
109
- code: 500,
110
- message: '获取日志文件列表失败'
111
- }
112
- }
113
- }
114
-
115
- /**
116
- * 下载日志文件
117
- */
118
- async downloadLogFile(ctx: Context) {
119
- try {
120
- const { filename } = ctx.params
121
-
122
- if (!filename || !filename.match(/^[a-zA-Z0-9._-]+$/)) {
123
- ctx.status = 400
124
- ctx.body = {
125
- code: 400,
126
- message: '无效的文件名'
127
- }
128
- return
129
- }
130
-
131
- const filePath = path.join(process.cwd(), 'logs', filename)
132
-
133
- if (!fs.existsSync(filePath)) {
134
- ctx.status = 404
135
- ctx.body = {
136
- code: 404,
137
- message: '日志文件不存在'
138
- }
139
- return
140
- }
141
-
142
- // 审计日志
143
- logger.audit('LOG_DOWNLOAD', filename, {
144
- userId: ctx.state.user?.id,
145
- ip: ctx.ip,
146
- userAgent: ctx.get('User-Agent')
147
- })
148
-
149
- ctx.set('Content-Type', 'application/octet-stream')
150
- ctx.set('Content-Disposition', `attachment; filename="${filename}"`)
151
- ctx.body = fs.createReadStream(filePath)
152
-
153
- } catch (error) {
154
- logger.error('Failed to download log file', error as Error, {
155
- filename: ctx.params.filename
156
- })
157
- ctx.status = 500
158
- ctx.body = {
159
- code: 500,
160
- message: '下载日志文件失败'
161
- }
162
- }
163
- }
164
-
165
- /**
166
- * 查看日志内容
167
- */
168
- async viewLogContent(ctx: Context) {
169
- try {
170
- const { filename } = ctx.params
171
- const { lines = 100, offset = 0 } = ctx.query
172
-
173
- if (!filename || !filename.match(/^[a-zA-Z0-9._-]+$/)) {
174
- ctx.status = 400
175
- ctx.body = {
176
- code: 400,
177
- message: '无效的文件名'
178
- }
179
- return
180
- }
181
-
182
- const filePath = path.join(process.cwd(), 'logs', filename)
183
-
184
- if (!fs.existsSync(filePath)) {
185
- ctx.status = 404
186
- ctx.body = {
187
- code: 404,
188
- message: '日志文件不存在'
189
- }
190
- return
191
- }
192
-
193
- const content = fs.readFileSync(filePath, 'utf8')
194
- const linesArray = content.split('\n')
195
- const startLine = Math.max(0, Number(offset))
196
- const endLine = Math.min(linesArray.length, startLine + Number(lines))
197
-
198
- const selectedLines = linesArray.slice(startLine, endLine)
199
-
200
- // 审计日志
201
- logger.audit('LOG_VIEW', filename, {
202
- userId: ctx.state.user?.id,
203
- lines: Number(lines),
204
- offset: Number(offset),
205
- ip: ctx.ip
206
- })
207
-
208
- ctx.body = {
209
- code: 0,
210
- data: {
211
- filename,
212
- totalLines: linesArray.length,
213
- selectedLines: selectedLines,
214
- startLine,
215
- endLine,
216
- hasMore: endLine < linesArray.length
217
- },
218
- message: '日志内容获取成功'
219
- }
220
-
221
- } catch (error) {
222
- logger.error('Failed to view log content', error as Error, {
223
- filename: ctx.params.filename
224
- })
225
- ctx.status = 500
226
- ctx.body = {
227
- code: 500,
228
- message: '查看日志内容失败'
229
- }
230
- }
231
- }
232
-
233
- /**
234
- * 清理过期日志
235
- */
236
- async cleanExpiredLogs(ctx: Context) {
237
- try {
238
- const { days = 30 } = ctx.request.body
239
- const logsDir = path.join(process.cwd(), 'logs')
240
- const cutoffDate = new Date()
241
- cutoffDate.setDate(cutoffDate.getDate() - Number(days))
242
-
243
- let deletedCount = 0
244
- let deletedSize = 0
245
-
246
- if (fs.existsSync(logsDir)) {
247
- const files = fs.readdirSync(logsDir)
248
-
249
- for (const file of files) {
250
- const filePath = path.join(logsDir, file)
251
- const fileStat = fs.statSync(filePath)
252
-
253
- if (fileStat.isFile() && fileStat.mtime < cutoffDate) {
254
- deletedSize += fileStat.size
255
- fs.unlinkSync(filePath)
256
- deletedCount++
257
- }
258
- }
259
- }
260
-
261
- // 审计日志
262
- logger.audit('LOG_CLEANUP', 'expired_logs', {
263
- userId: ctx.state.user?.id,
264
- days: Number(days),
265
- deletedCount,
266
- deletedSize,
267
- ip: ctx.ip
268
- })
269
-
270
- ctx.body = {
271
- code: 0,
272
- data: {
273
- deletedCount,
274
- deletedSize,
275
- cutoffDate: cutoffDate.toISOString()
276
- },
277
- message: `成功清理 ${deletedCount} 个过期日志文件`
278
- }
279
-
280
- } catch (error) {
281
- logger.error('Failed to clean expired logs', error as Error)
282
- ctx.status = 500
283
- ctx.body = {
284
- code: 500,
285
- message: '清理过期日志失败'
286
- }
287
- }
288
- }
289
-
290
- /**
291
- * 设置日志级别
292
- */
293
- async setLogLevel(ctx: Context) {
294
- try {
295
- const { level, category = 'default' } = ctx.request.body
296
-
297
- const validLevels = ['trace', 'debug', 'info', 'warn', 'error', 'fatal']
298
- if (!validLevels.includes(level)) {
299
- ctx.status = 400
300
- ctx.body = {
301
- code: 400,
302
- message: '无效的日志级别'
303
- }
304
- return
305
- }
306
-
307
- // 这里需要实现动态设置日志级别的逻辑
308
- // 由于log4js的限制,可能需要重启应用才能生效
309
-
310
- // 审计日志
311
- logger.audit('LOG_LEVEL_CHANGE', category, {
312
- userId: ctx.state.user?.id,
313
- oldLevel: 'unknown',
314
- newLevel: level,
315
- ip: ctx.ip
316
- })
317
-
318
- ctx.body = {
319
- code: 0,
320
- data: {
321
- category,
322
- level,
323
- message: '日志级别设置成功,重启应用后生效'
324
- },
325
- message: '日志级别设置成功'
326
- }
327
-
328
- } catch (error) {
329
- logger.error('Failed to set log level', error as Error)
330
- ctx.status = 500
331
- ctx.body = {
332
- code: 500,
333
- message: '设置日志级别失败'
334
- }
335
- }
336
- }
337
-
338
- /**
339
- * 获取实时日志流
340
- */
341
- async getLogStream(ctx: Context) {
342
- try {
343
- const { filename } = ctx.params
344
-
345
- if (!filename || !filename.match(/^[a-zA-Z0-9._-]+$/)) {
346
- ctx.status = 400
347
- ctx.body = {
348
- code: 400,
349
- message: '无效的文件名'
350
- }
351
- return
352
- }
353
-
354
- const filePath = path.join(process.cwd(), 'logs', filename)
355
-
356
- if (!fs.existsSync(filePath)) {
357
- ctx.status = 404
358
- ctx.body = {
359
- code: 404,
360
- message: '日志文件不存在'
361
- }
362
- return
363
- }
364
-
365
- // 设置SSE响应头
366
- ctx.set({
367
- 'Content-Type': 'text/event-stream',
368
- 'Cache-Control': 'no-cache',
369
- 'Connection': 'keep-alive',
370
- 'Access-Control-Allow-Origin': '*',
371
- 'Access-Control-Allow-Headers': 'Cache-Control'
372
- })
373
-
374
- // 审计日志
375
- logger.audit('LOG_STREAM_START', filename, {
376
- userId: ctx.state.user?.id,
377
- ip: ctx.ip
378
- })
379
-
380
- // 创建可读流
381
- const stream = fs.createReadStream(filePath, { encoding: 'utf8' })
382
-
383
- ctx.body = stream
384
-
385
- } catch (error) {
386
- logger.error('Failed to get log stream', error as Error, {
387
- filename: ctx.params.filename
388
- })
389
- ctx.status = 500
390
- ctx.body = {
391
- code: 500,
392
- message: '获取日志流失败'
393
- }
394
- }
395
- }
396
- }
@@ -1,65 +0,0 @@
1
- import { Body,Post, ResponseValidateIf, ResponseValidator } from "@src/framework/decorator/controller";
2
- import { BaseController, ControllerResponse } from "@src/controllers/base.controller";
3
- import { SendEmailDto, SendEmailResponseDto } from "@src/dto/controller/home/emailSend.controller.dto";
4
- import { Inject } from "dp-ioc2";
5
- import * as jwt from "jsonwebtoken";
6
- import { YtUserService } from "@src/service/ytUser.service";
7
- import { logger } from "@src/framework/utils/logger";
8
- import { AokEmailSender } from "@src/libs/aokEmailSender";
9
-
10
- const emailSender = new AokEmailSender(process.env.aok_email_api_key ?? "330b853af20ef6762f259545ef7b4c17")
11
-
12
- export class EmailSendController extends BaseController {
13
-
14
- @Inject(YtUserService)
15
- ytUserService: YtUserService;
16
-
17
- /**
18
- * 短信验证码邮件
19
- * @param body
20
- * @returns
21
- */
22
- @ResponseValidateIf(SendEmailResponseDto, (data) => data && data.data)
23
- @Post()
24
- async sendRegisterEmail(
25
- @Body(SendEmailDto) body: SendEmailDto
26
- ): Promise<ControllerResponse<SendEmailResponseDto>> {
27
-
28
- // 1. 检查邮箱是否已注册
29
- // const exist = await this.ytUserService.findByEmail(body.email);
30
- // if (exist) {
31
- // return this.fail(-1, "该邮箱已注册");
32
- // }
33
-
34
- // 2. 生成随机验证码(4位数字)
35
- const vcode = Math.floor(1000 + Math.random() * 9000).toString();
36
-
37
- // 3. 设置验证码过期时间(5分钟后)
38
- const expire = Date.now() + 5 * 60 * 1000;
39
-
40
- // 4. 生成JWT token包含验证码和过期时间
41
- const vcodeToken = jwt.sign(
42
- { vcode, expire, email: body.email },
43
- process.env.jwt_secret ?? "123456",
44
- { expiresIn: "5m" }
45
- );
46
-
47
- // 5. 发送邮件验证码(模拟)
48
- const result = await emailSender.sendEmail({
49
- templateId: "E_106565864351",
50
- templateData: {
51
- vcode: String(vcode),
52
- login_link: `
53
- <a href="https://ytfx.yndaopu.com/login/${vcode}">快捷登录链接</a>
54
- `
55
- },
56
- to: body.email,
57
- })
58
- // console.log(result)
59
- // logger.info(`发送邮件验证码到${body.email}: ${vcode}`);
60
- return this.success({
61
- expire,
62
- vcodeToken
63
- }, "验证码发送成功");
64
- }
65
- }
@@ -1,174 +0,0 @@
1
- import { Body, ControllerCache, Get, Post, Query, ResponseValidateIf } from "@src/framework/decorator/controller";
2
- import { BaseController, ControllerResponse } from "@src/controllers/base.controller";
3
- import { Inject } from "dp-ioc2";
4
- import { YtUserService } from "@src/service/ytUser.service";
5
- import jwt from 'jsonwebtoken';
6
- import md5 from 'md5';
7
- import svgCaptcha from 'svg-captcha';
8
- import { GetYtUserBasicInfoDto, GetYtUserBasicInfoResponseDto, YtUserLoginAutoDto, YtUserLoginDto } from "@src/dto/controller/public/ytUserAuth.controller.dto";
9
- import { YtUserEntity, YtUserStatusEnum, YtUserTypeEnum } from "@src/entity/ytUser.entity";
10
- import { CommonServiceResultCode } from "@src/framework/types/ServiceResult";
11
- import { logger } from "@src/framework/utils/logger";
12
- import { isDebug } from "@src/framework/utils/function";
13
-
14
- interface IvcodeInfo {
15
- vcode: string
16
- expire: number
17
- }
18
-
19
- export class YtUserAuthController extends BaseController {
20
- @Inject(YtUserService)
21
- ytUserService: YtUserService;
22
-
23
- @Post()
24
- async login(
25
- @Body(YtUserLoginDto) body: YtUserLoginDto
26
- ): Promise<ControllerResponse<string>> {
27
-
28
- // 验证注册码
29
- let vcodeInfo: IvcodeInfo | null = null;
30
- try {
31
- vcodeInfo = jwt.verify(body.vcodeToken, process.env.jwt_secret ?? "123456") as any;
32
- } catch (err) {
33
- return this.fail(-1, "验证码可能失效");
34
- }
35
-
36
- if (!vcodeInfo) {
37
- return this.fail(-1, "验证码解析失败");
38
- }
39
-
40
- if (vcodeInfo?.expire < new Date().getTime()) {
41
- return this.fail(-1, "验证码过期");
42
- }
43
-
44
- if (vcodeInfo.vcode !== body.vcode) {
45
- return this.fail(-1, "验证码不正确");
46
- }
47
-
48
- // 1. 验证用户是否存在
49
- let user = await this.ytUserService.findByEmail(body.email);
50
- if (!user) {
51
- const ytUser = new YtUserEntity();
52
- ytUser.nickName = '用户' + body.email.split("@")[0].slice(0, 5);
53
- ytUser.email = body.email;
54
- ytUser.avatar = "https://ytfx.yndaopu.com/static/images/Avatar-1.png";
55
- // ytUser.password = md5(body.password);
56
- let result = await this.ytUserService.add(ytUser);
57
- // if (result.code != CommonServiceResultCode.SUCCESS) {
58
- // logger.warn(`注册注册失败` + JSON.stringify(body), result.message);
59
- // return this.fail(-1, "注册失败");
60
- // }
61
- user = result
62
- }
63
-
64
- if (user.status == YtUserStatusEnum.FORBIDDEN) {
65
- return this.fail(-1, "用户已被禁用");
66
- }
67
-
68
-
69
- // 3. 生成JWT token
70
- const token = jwt.sign(
71
- { userId: user.id, type: user.userType },
72
- process.env.jwt_secret ?? "123456",
73
- { expiresIn: "7d" }
74
- );
75
-
76
- return this.success(token, "登录成功");
77
- }
78
-
79
-
80
- /**
81
- * 自动注册和登录
82
- * @param body
83
- * @returns
84
- */
85
- @Post()
86
- async loginAuto(
87
- @Body(YtUserLoginAutoDto) body: YtUserLoginAutoDto
88
- ): Promise<ControllerResponse<string>> {
89
-
90
- // 验证注册码
91
- let vcodeInfo: IvcodeInfo | null = null;
92
- try {
93
- vcodeInfo = jwt.verify(body.vcodeToken, process.env.jwt_secret ?? "123456") as any;
94
- } catch (err) {
95
- return this.fail(-1, "验证码可能失效");
96
- }
97
-
98
- if (!vcodeInfo) {
99
- return this.fail(-1, "验证码解析失败");
100
- }
101
-
102
- if (vcodeInfo?.expire < new Date().getTime()) {
103
- return this.fail(-1, "验证码过期");
104
- }
105
-
106
- if (String(vcodeInfo.vcode).toLowerCase() !== String(body.vcode).toLowerCase()) {
107
- return this.fail(-1, "验证码不正确");
108
- }
109
-
110
- let user = new YtUserEntity();
111
- user.nickName = `新用户-${vcodeInfo.vcode}`;
112
- user.email = `${vcodeInfo.vcode}@example.com`
113
- user.avatar = "https://ytfx.yndaopu.com/static/images/Avatar-1.png";
114
- user = await this.ytUserService.add(user)
115
- // 3. 生成JWT token
116
- const token = jwt.sign(
117
- { userId: user.id, type: user.userType },
118
- process.env.jwt_secret ?? "123456",
119
- { expiresIn: "360d" }
120
- );
121
-
122
- return this.success(token, "登录成功");
123
- }
124
-
125
- @ControllerCache((query: GetYtUserBasicInfoDto) => `YtUserAuthController-getYtUserBasicInfo-${query.id}`, {
126
- ttl: {
127
- max: 60 * 5,
128
- min: 30,
129
- },
130
- enable: !isDebug()
131
- })
132
- @ResponseValidateIf(GetYtUserBasicInfoResponseDto, (data) => data && data.data)
133
- @Get()
134
- async getYtUserBasicInfo(
135
- @Query(GetYtUserBasicInfoDto) query: GetYtUserBasicInfoDto,
136
- ): Promise<ControllerResponse<GetYtUserBasicInfoResponseDto | null>> {
137
- let userResult = await this.ytUserService.getById(YtUserEntity, query.id);
138
-
139
- if (!userResult) {
140
- return this.fail(-1, "用户不存在");
141
- }
142
- return this.success({
143
- id: userResult.id,
144
- name: userResult.nickName,
145
- avatar: userResult.avatar,
146
- }, "获取成功");
147
- }
148
-
149
-
150
-
151
- /**
152
- * 创建验证码
153
- * @returns
154
- */
155
- @Get()
156
- async getCaptcha() {
157
- const captcha = svgCaptcha.create({
158
- size: 4,
159
- ignoreChars: '0o1i',
160
- noise: 2,
161
- color: true
162
- });
163
- const token = jwt.sign(
164
- { vcode: captcha.text, expire: new Date().getTime() + 1000 * 60 * 5 },
165
- process.env.jwt_secret ?? "123456"
166
- );
167
- return {
168
- svg: captcha.data,
169
- token
170
- };
171
- }
172
-
173
-
174
- }