瀏覽代碼

添加 libphonenumber-js 库以支持电话号码解析,更新 TgUser 实体和服务以包含区号和号码字段,同时重构 TgUser 控制器以处理导入的用户数据,增强代码一致性和可维护性。

wuyi 3 周之前
父節點
當前提交
aa09b93b75

+ 1 - 0
package.json

@@ -29,6 +29,7 @@
     "decimal.js": "^10.6.0",
     "decimal.js": "^10.6.0",
     "dotenv": "^16.4.7",
     "dotenv": "^16.4.7",
     "fastify": "^5.2.2",
     "fastify": "^5.2.2",
+    "libphonenumber-js": "^1.12.31",
     "mysql2": "^3.14.0",
     "mysql2": "^3.14.0",
     "reflect-metadata": "^0.2.2",
     "reflect-metadata": "^0.2.2",
     "telegraf": "^4.16.3",
     "telegraf": "^4.16.3",

+ 3 - 3
src/controllers/fish.controller.ts

@@ -1,6 +1,6 @@
 import { FastifyRequest, FastifyReply, FastifyInstance } from 'fastify'
 import { FastifyRequest, FastifyReply, FastifyInstance } from 'fastify'
 import { FishService } from '../services/fish.service'
 import { FishService } from '../services/fish.service'
-import { SenderService } from '../services/tg-user.service'
+import { TgUserService } from '../services/tg-user.service'
 import { ResultEnum } from '../entities/fish.entity'
 import { ResultEnum } from '../entities/fish.entity'
 import { UserRole } from '../entities/user.entity'
 import { UserRole } from '../entities/user.entity'
 import {
 import {
@@ -17,13 +17,13 @@ import { buildStringSession } from '../utils/tg.util'
 
 
 export class FishController {
 export class FishController {
   private fishService: FishService
   private fishService: FishService
-  private senderService: SenderService
+  private senderService: TgUserService
   private app: FastifyInstance
   private app: FastifyInstance
 
 
   constructor(app: FastifyInstance) {
   constructor(app: FastifyInstance) {
     this.app = app
     this.app = app
     this.fishService = new FishService(app)
     this.fishService = new FishService(app)
-    this.senderService = new SenderService(app)
+    this.senderService = new TgUserService(app)
   }
   }
 
 
   async create(request: FastifyRequest<{ Body: CreateFishBody }>, reply: FastifyReply) {
   async create(request: FastifyRequest<{ Body: CreateFishBody }>, reply: FastifyReply) {

+ 30 - 3
src/controllers/tg-user.controller.ts

@@ -3,6 +3,7 @@ import fs from 'fs/promises'
 import path from 'path'
 import path from 'path'
 import { TgUserService } from '../services/tg-user.service'
 import { TgUserService } from '../services/tg-user.service'
 import { CreateSenderBody, UpdateSenderBody, ListSenderQuery } from '../dto/tg-user.dto'
 import { CreateSenderBody, UpdateSenderBody, ListSenderQuery } from '../dto/tg-user.dto'
+import { parsePhoneNumber } from '../utils/tg.util'
 
 
 export class TgUserController {
 export class TgUserController {
   private tgUserService: TgUserService
   private tgUserService: TgUserService
@@ -21,12 +22,20 @@ export class TgUserController {
         return reply.code(400).send({ message: '文件格式错误,应为数组' })
         return reply.code(400).send({ message: '文件格式错误,应为数组' })
       }
       }
 
 
-      const importList: { id: string; dcId?: number; authKey?: string }[] = []
+      const importList: {
+        id: string
+        dcId?: number
+        authKey?: string
+        name?: string
+        username?: string
+        areaCode?: string
+        phone?: string
+      }[] = []
       let parseFailed = 0
       let parseFailed = 0
 
 
       for (const item of parsed) {
       for (const item of parsed) {
         try {
         try {
-          const { id, token } = item ?? {}
+          const { id, token, name, username, phone } = item ?? {}
           if (!id || !token) {
           if (!id || !token) {
             parseFailed++
             parseFailed++
             continue
             continue
@@ -41,10 +50,28 @@ export class TgUserController {
             continue
             continue
           }
           }
 
 
+          // 解析电话号码,将区号和号码分开
+          let areaCode: string | undefined
+          let phoneNumber: string | undefined
+          if (phone) {
+            const parsedPhone = parsePhoneNumber(phone)
+            if (parsedPhone) {
+              areaCode = parsedPhone.areaCode
+              phoneNumber = parsedPhone.phone
+            } else {
+              // 如果无法解析,将整个电话号码保存到 phone 字段
+              phoneNumber = phone.replace(/\D/g, '')
+            }
+          }
+
           importList.push({
           importList.push({
             id: String(id),
             id: String(id),
             dcId: Number(dcId),
             dcId: Number(dcId),
-            authKey: String(authKey)
+            authKey: String(authKey),
+            name: name ? String(name).trim() : undefined,
+            username: username ? String(username).trim() : undefined,
+            areaCode,
+            phone: phoneNumber
           })
           })
         } catch {
         } catch {
           parseFailed++
           parseFailed++

+ 7 - 1
src/entities/tg-user.entity.ts

@@ -1,4 +1,4 @@
-import { Column, Entity, Index, PrimaryColumn } from 'typeorm'
+import { Column, CreateDateColumn, Entity, Index, PrimaryColumn, UpdateDateColumn } from 'typeorm'
 
 
 @Entity()
 @Entity()
 @Index('idx_sender_del_usage_last', ['delFlag', 'usageCount', 'lastUsageTime'])
 @Index('idx_sender_del_usage_last', ['delFlag', 'usageCount', 'lastUsageTime'])
@@ -35,4 +35,10 @@ export class TgUser {
 
 
   @Column({ type: 'datetime', precision: 6, default: () => 'CURRENT_TIMESTAMP(6)' })
   @Column({ type: 'datetime', precision: 6, default: () => 'CURRENT_TIMESTAMP(6)' })
   lastUsageTime: Date
   lastUsageTime: Date
+
+  @CreateDateColumn()
+  createdAt: Date
+
+  @UpdateDateColumn()
+  updatedAt: Date
 }
 }

+ 29 - 3
src/services/tg-user.service.ts

@@ -92,7 +92,16 @@ export class TgUserService {
   }
   }
 
 
   async importFromJson(
   async importFromJson(
-    senders: Array<{ id: string; dcId?: number; authKey?: string; sessionStr?: string }>
+    senders: Array<{
+      id: string
+      dcId?: number
+      authKey?: string
+      sessionStr?: string
+      name?: string
+      username?: string
+      areaCode?: string
+      phone?: string
+    }>
   ): Promise<{ created: number; updated: number; failed: number; total: number }> {
   ): Promise<{ created: number; updated: number; failed: number; total: number }> {
     let created = 0
     let created = 0
     let updated = 0
     let updated = 0
@@ -122,11 +131,28 @@ export class TgUserService {
           await this.senderRepository.update(sender.id, {
           await this.senderRepository.update(sender.id, {
             dcId: sender.dcId ?? existing.dcId,
             dcId: sender.dcId ?? existing.dcId,
             authKey: sender.authKey ?? existing.authKey,
             authKey: sender.authKey ?? existing.authKey,
-            sessionStr: sessionStr ?? existing.sessionStr
+            sessionStr: sessionStr ?? existing.sessionStr,
+            name: sender.name !== undefined ? sender.name : existing.name,
+            username: sender.username !== undefined ? sender.username : existing.username,
+            areaCode: sender.areaCode !== undefined ? sender.areaCode : existing.areaCode,
+            phone: sender.phone !== undefined ? sender.phone : existing.phone
           })
           })
           updated++
           updated++
         } else {
         } else {
-          await this.create(sender.id, sender.dcId, sender.authKey, sessionStr)
+          const newSender = this.senderRepository.create({
+            id: sender.id,
+            dcId: sender.dcId,
+            authKey: sender.authKey,
+            sessionStr,
+            name: sender.name,
+            username: sender.username,
+            areaCode: sender.areaCode,
+            phone: sender.phone,
+            usageCount: 0,
+            delFlag: false,
+            lastUsageTime: new Date()
+          })
+          await this.senderRepository.save(newSender)
           created++
           created++
         }
         }
       } catch {
       } catch {

+ 42 - 0
src/utils/tg.util.ts

@@ -1,3 +1,5 @@
+import { parsePhoneNumberFromString } from 'libphonenumber-js'
+
 interface DCConfig {
 interface DCConfig {
   id: number
   id: number
   host: string
   host: string
@@ -211,3 +213,43 @@ function inferDcIdFromAuthKeys(account: Partial<TelegramAccountSession>): number
   if (account.dc4_auth_key) return 4
   if (account.dc4_auth_key) return 4
   return undefined
   return undefined
 }
 }
+
+/**
+ * 解析电话号码,将区号和号码分开
+ * 使用 libphonenumber-js 库进行解析
+ * @param phone 完整的电话号码(可能包含区号)
+ * @returns 包含 areaCode 和 phone 的对象,如果无法解析则返回 null
+ */
+export function parsePhoneNumber(phone: string): { areaCode: string; phone: string } | null {
+  if (!phone || typeof phone !== 'string') {
+    return null
+  }
+
+  try {
+    // 尝试解析电话号码
+    // 如果号码以 + 开头,直接解析;否则尝试添加 + 前缀
+    const phoneToParse = phone.startsWith('+') ? phone : `+${phone.replace(/\D/g, '')}`
+    const phoneNumber = parsePhoneNumberFromString(phoneToParse)
+
+    if (phoneNumber && phoneNumber.isValid()) {
+      return {
+        areaCode: phoneNumber.countryCallingCode,
+        phone: phoneNumber.nationalNumber
+      }
+    }
+
+    // 如果解析失败,尝试不添加 + 前缀直接解析
+    const phoneNumber2 = parsePhoneNumberFromString(phone)
+    if (phoneNumber2 && phoneNumber2.isValid()) {
+      return {
+        areaCode: phoneNumber2.countryCallingCode,
+        phone: phoneNumber2.nationalNumber
+      }
+    }
+
+    return null
+  } catch {
+    // 解析失败时返回 null
+    return null
+  }
+}

+ 5 - 0
yarn.lock

@@ -1946,6 +1946,11 @@ libphonenumber-js@^1.10.53:
   resolved "https://registry.npmmirror.com/libphonenumber-js/-/libphonenumber-js-1.12.6.tgz"
   resolved "https://registry.npmmirror.com/libphonenumber-js/-/libphonenumber-js-1.12.6.tgz"
   integrity sha512-PJiS4ETaUfCOFLpmtKzAbqZQjCCKVu2OhTV4SVNNE7c2nu/dACvtCqj4L0i/KWNnIgRv7yrILvBj5Lonv5Ncxw==
   integrity sha512-PJiS4ETaUfCOFLpmtKzAbqZQjCCKVu2OhTV4SVNNE7c2nu/dACvtCqj4L0i/KWNnIgRv7yrILvBj5Lonv5Ncxw==
 
 
+libphonenumber-js@^1.12.31:
+  version "1.12.31"
+  resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.12.31.tgz#3cdb45641c6b77228dd1238f3d810c3bb5d91199"
+  integrity sha512-Z3IhgVgrqO1S5xPYM3K5XwbkDasU67/Vys4heW+lfSBALcUZjeIIzI8zCLifY+OCzSq+fpDdywMDa7z+4srJPQ==
+
 light-my-request@^6.0.0:
 light-my-request@^6.0.0:
   version "6.6.0"
   version "6.6.0"
   resolved "https://registry.npmmirror.com/light-my-request/-/light-my-request-6.6.0.tgz"
   resolved "https://registry.npmmirror.com/light-my-request/-/light-my-request-6.6.0.tgz"