Procházet zdrojové kódy

更新依赖项,新增随机字符串生成库和十进制库;在团队实体中添加推广码字段;在成员和团队服务中实现推广码生成逻辑。

wuyi před 3 měsíci
rodič
revize
e4d9590447

+ 40 - 0
package-lock.json

@@ -20,9 +20,11 @@
         "bcryptjs": "^3.0.2",
         "class-transformer": "^0.5.1",
         "class-validator": "^0.14.1",
+        "decimal.js": "^10.6.0",
         "dotenv": "^16.4.7",
         "fastify": "^5.2.2",
         "mysql2": "^3.14.0",
+        "randomstring": "^1.3.1",
         "reflect-metadata": "^0.2.2",
         "tronweb": "^5.3.3",
         "typeorm": "^0.3.21",
@@ -32,6 +34,7 @@
       "devDependencies": {
         "@types/bcryptjs": "^3.0.0",
         "@types/node": "^22.13.14",
+        "@types/randomstring": "^1.3.0",
         "pino-pretty": "^13.0.0",
         "ts-node-dev": "^2.0.0",
         "typescript": "^5.8.2"
@@ -1127,6 +1130,13 @@
         "undici-types": "~6.20.0"
       }
     },
+    "node_modules/@types/randomstring": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/@types/randomstring/-/randomstring-1.3.0.tgz",
+      "integrity": "sha512-kCP61wludjY7oNUeFiMxfswHB3Wn/aC03Cu82oQsNTO6OCuhVN/rCbBs68Cq6Nkgjmp2Sh3Js6HearJPkk7KQA==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/@types/strip-bom": {
       "version": "3.0.0",
       "resolved": "https://registry.npmmirror.com/@types/strip-bom/-/strip-bom-3.0.0.tgz",
@@ -1882,6 +1892,12 @@
         }
       }
     },
+    "node_modules/decimal.js": {
+      "version": "10.6.0",
+      "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz",
+      "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==",
+      "license": "MIT"
+    },
     "node_modules/default-user-agent": {
       "version": "1.0.0",
       "resolved": "https://registry.npmmirror.com/default-user-agent/-/default-user-agent-1.0.0.tgz",
@@ -3740,6 +3756,30 @@
       "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==",
       "license": "MIT"
     },
+    "node_modules/randombytes": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+      "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+      "license": "MIT",
+      "dependencies": {
+        "safe-buffer": "^5.1.0"
+      }
+    },
+    "node_modules/randomstring": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/randomstring/-/randomstring-1.3.1.tgz",
+      "integrity": "sha512-lgXZa80MUkjWdE7g2+PZ1xDLzc7/RokXVEQOv5NN2UOTChW1I8A9gha5a9xYBOqgaSoI6uJikDmCU8PyRdArRQ==",
+      "license": "MIT",
+      "dependencies": {
+        "randombytes": "2.1.0"
+      },
+      "bin": {
+        "randomstring": "bin/randomstring"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
     "node_modules/readable-stream": {
       "version": "2.3.8",
       "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz",

+ 2 - 0
package.json

@@ -26,6 +26,7 @@
     "dotenv": "^16.4.7",
     "fastify": "^5.2.2",
     "mysql2": "^3.14.0",
+    "randomstring": "^1.3.1",
     "reflect-metadata": "^0.2.2",
     "tronweb": "^5.3.3",
     "typeorm": "^0.3.21",
@@ -35,6 +36,7 @@
   "devDependencies": {
     "@types/bcryptjs": "^3.0.0",
     "@types/node": "^22.13.14",
+    "@types/randomstring": "^1.3.0",
     "pino-pretty": "^13.0.0",
     "ts-node-dev": "^2.0.0",
     "typescript": "^5.8.2"

+ 3 - 0
src/entities/team.entity.ts

@@ -20,6 +20,9 @@ export class Team {
   @Column({ type: 'decimal', precision: 5, scale: 2, default: 0 })
   commissionRate: number
 
+  @Column({ unique: true, length: 10, nullable: true })
+  affCode: string
+
   @CreateDateColumn()
   createdAt: Date
 

+ 8 - 5
src/services/member.service.ts

@@ -3,21 +3,24 @@ import { FastifyInstance } from 'fastify'
 import { Member, VipLevel, MemberStatus } from '../entities/member.entity'
 import { PaginationResponse } from '../dto/common.dto'
 import { User, UserRole } from '../entities/user.entity'
+import * as randomstring from 'randomstring'
+import { Team } from '../entities/team.entity'
 
 export class MemberService {
   private memberRepository: Repository<Member>
-  private userRepository: Repository<User>
   private dataSource: DataSource
 
   constructor(app: FastifyInstance) {
     this.memberRepository = app.dataSource.getRepository(Member)
-    this.userRepository = app.dataSource.getRepository(User)
     this.dataSource = app.dataSource
   }
 
   async createGuest(code?: string, ip?: string): Promise<{ user: User; member: Member }> {
     return await this.dataSource.transaction(async manager => {
-      const randomSuffix = Math.random().toString(36).substring(2, 10)
+      const randomSuffix = randomstring.generate({
+        length: 10,
+        charset: 'alphanumeric'
+      })
       const guestName = `m_${randomSuffix}`
 
       let finalGuestName = guestName
@@ -27,8 +30,8 @@ export class MemberService {
         finalGuestName = `${guestName}${counter}`
       }
 
-      // 后续校验推广码是哪个团队
-      const parentId = code ? parseInt(code) : 1
+      const team = await manager.findOne(Team, { where: { affCode: code } })
+      const parentId = team ? team.userId : 1
 
       const user = manager.create(User, {
         name: finalGuestName,

+ 14 - 1
src/services/team.service.ts

@@ -5,6 +5,7 @@ import { PaginationResponse } from '../dto/common.dto'
 import { CreateTeamBody, UpdateTeamBody, ListTeamQuery } from '../dto/team.dto'
 import { UserService } from './user.service'
 import { UserRole } from '../entities/user.entity'
+import * as randomstring from 'randomstring'
 
 export class TeamService {
   private teamRepository: Repository<Team>
@@ -26,9 +27,21 @@ export class TeamService {
     const userPassword = password || 'password123'
     const createdUser = await this.userService.create(userPassword, teamData.name, UserRole.TEAM, creatorId)
 
+    const randomSuffix = randomstring.generate({
+      length: 10,
+      charset: 'alphanumeric'
+    })
+    let finalAffCode = randomSuffix
+    let counter = 0
+    while (await this.teamRepository.findOne({ where: { affCode: finalAffCode } })) {
+      counter++
+      finalAffCode = `${randomSuffix}${counter}`
+    }
+
     const team = this.teamRepository.create({
       ...teamData,
-      userId: createdUser.id
+      userId: createdUser.id,
+      affCode: finalAffCode
     })
     const savedTeam = await this.teamRepository.save(team)
 

+ 21 - 2
yarn.lock

@@ -492,6 +492,11 @@
   dependencies:
     undici-types "~6.19.2"
 
+"@types/randomstring@^1.3.0":
+  version "1.3.0"
+  resolved "https://registry.npmjs.org/@types/randomstring/-/randomstring-1.3.0.tgz"
+  integrity sha512-kCP61wludjY7oNUeFiMxfswHB3Wn/aC03Cu82oQsNTO6OCuhVN/rCbBs68Cq6Nkgjmp2Sh3Js6HearJPkk7KQA==
+
 "@types/strip-bom@^3.0.0":
   version "3.0.0"
   resolved "https://registry.npmmirror.com/@types/strip-bom/-/strip-bom-3.0.0.tgz"
@@ -973,7 +978,7 @@ debug@^4.1.1, debug@^4.3.4:
 
 decimal.js@^10.6.0:
   version "10.6.0"
-  resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.6.0.tgz#e649a43e3ab953a72192ff5983865e509f37ed9a"
+  resolved "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz"
   integrity sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==
 
 default-user-agent@^1.0.0:
@@ -2137,6 +2142,20 @@ quick-format-unescaped@^4.0.3:
   resolved "https://registry.npmmirror.com/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz"
   integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==
 
+randombytes@2.1.0:
+  version "2.1.0"
+  resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz"
+  integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
+  dependencies:
+    safe-buffer "^5.1.0"
+
+randomstring@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.npmjs.org/randomstring/-/randomstring-1.3.1.tgz"
+  integrity sha512-lgXZa80MUkjWdE7g2+PZ1xDLzc7/RokXVEQOv5NN2UOTChW1I8A9gha5a9xYBOqgaSoI6uJikDmCU8PyRdArRQ==
+  dependencies:
+    randombytes "2.1.0"
+
 readable-stream@^2.3.6:
   version "2.3.8"
   resolved "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz"
@@ -2208,7 +2227,7 @@ rimraf@^2.6.1:
   dependencies:
     glob "^7.1.3"
 
-safe-buffer@5.2.1, safe-buffer@^5.0.1:
+safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0:
   version "5.2.1"
   resolved "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz"
   integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==