member.service.ts 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. import { In, Repository, DataSource } from 'typeorm'
  2. import { FastifyInstance } from 'fastify'
  3. import { Member, VipLevel, MemberStatus } from '../entities/member.entity'
  4. import { PaginationResponse } from '../dto/common.dto'
  5. import { User, UserRole } from '../entities/user.entity'
  6. import * as randomstring from 'randomstring'
  7. import { Team } from '../entities/team.entity'
  8. import { TeamDomain } from '../entities/team-domain.entity'
  9. import { TeamMembers } from '../entities/team-members.entity'
  10. import { LandingDomainPool } from '../entities/landing-domain-pool.entity'
  11. import bcrypt from 'bcryptjs'
  12. export class MemberService {
  13. private memberRepository: Repository<Member>
  14. private dataSource: DataSource
  15. private vipDurations: Record<VipLevel, number | null> = {
  16. [VipLevel.GUEST]: null,
  17. [VipLevel.FREE]: null,
  18. [VipLevel.HOURLY]: 60 * 60 * 1000,
  19. [VipLevel.DAILY]: 24 * 60 * 60 * 1000,
  20. [VipLevel.WEEKLY]: 7 * 24 * 60 * 60 * 1000,
  21. [VipLevel.MONTHLY]: 30 * 24 * 60 * 60 * 1000,
  22. [VipLevel.QUARTERLY]: 90 * 24 * 60 * 60 * 1000,
  23. [VipLevel.YEARLY]: 365 * 24 * 60 * 60 * 1000,
  24. [VipLevel.LIFETIME]: new Date('2099-12-31').getTime() - Date.now()
  25. }
  26. constructor(app: FastifyInstance) {
  27. this.memberRepository = app.dataSource.getRepository(Member)
  28. this.dataSource = app.dataSource
  29. }
  30. async createGuest(code?: string, domain?: string, ip?: string, landingDomain?: string): Promise<User> {
  31. return await this.dataSource.transaction(async manager => {
  32. const randomSuffix = randomstring.generate({
  33. length: 10,
  34. charset: 'alphanumeric'
  35. })
  36. const guestName = `m_${randomSuffix}`
  37. let finalGuestName = guestName
  38. let counter = 0
  39. while (await manager.findOne(User, { where: { name: finalGuestName } })) {
  40. counter++
  41. finalGuestName = `${guestName}${counter}`
  42. }
  43. let parentId = 1
  44. let teamId = 0
  45. let domainId = 0
  46. // 校验顺序:推广码 -> 跳转域名 -> 落地域名
  47. // 1. 优先使用推广码
  48. if (code && code.trim() !== '') {
  49. // 先尝试查找团队成员的推广码
  50. const teamMember = await manager.findOne(TeamMembers, { where: { promoCode: code } })
  51. if (teamMember) {
  52. // 如果找到团队成员,使用团队成员的 userId 作为 parentId
  53. parentId = teamMember.userId
  54. teamId = teamMember.teamId
  55. } else {
  56. // 如果没有找到团队成员,尝试查找团队的推广码
  57. const team = await manager.findOne(Team, { where: { affCode: code } })
  58. if (team) {
  59. parentId = team.userId
  60. teamId = team.id
  61. }
  62. }
  63. }
  64. // 2. 如果推广码没有找到,使用跳转域名(team-domain)
  65. if (parentId === 1 && teamId === 0 && domain) {
  66. let domainName = domain
  67. try {
  68. if (domain.includes('://')) {
  69. const url = new URL(domain)
  70. domainName = url.hostname
  71. } else {
  72. domainName = domain
  73. }
  74. } catch (error) {
  75. domainName = domain
  76. }
  77. const teamDomain = await manager.findOne(TeamDomain, { where: { domain: domainName } })
  78. if (teamDomain) {
  79. // 如果domain绑定到teamMember,使用teamMember的userId作为parentId
  80. // 这样在分润时可以从teamMember向上查找到team
  81. if (teamDomain.teamMemberId) {
  82. const teamMember = await manager.findOne(TeamMembers, { where: { id: teamDomain.teamMemberId } })
  83. if (teamMember) {
  84. parentId = teamMember.userId
  85. teamId = teamMember.teamId
  86. }
  87. } else {
  88. // 如果domain只绑定到team,使用team的userId作为parentId
  89. const team = await manager.findOne(Team, { where: { id: teamDomain.teamId } })
  90. if (team) {
  91. parentId = team.userId
  92. teamId = team.id
  93. }
  94. }
  95. domainId = teamDomain.id
  96. }
  97. }
  98. // 3. 如果跳转域名没有找到,使用落地域名(landing-domain)
  99. if (parentId === 1 && teamId === 0 && landingDomain && landingDomain.trim() !== '') {
  100. const landingDomainPoolRepository = manager.getRepository(LandingDomainPool)
  101. const landingDomainRecord = await landingDomainPoolRepository.findOne({
  102. where: { domain: landingDomain.trim() }
  103. })
  104. if (landingDomainRecord) {
  105. // 如果落地域名绑定到团队成员(userId不为空),使用teamMember的userId作为parentId
  106. // 这样在分润时可以从teamMember向上查找到team
  107. if (landingDomainRecord.userId) {
  108. const teamMember = await manager.findOne(TeamMembers, { where: { userId: landingDomainRecord.userId } })
  109. if (teamMember) {
  110. parentId = teamMember.userId
  111. teamId = teamMember.teamId
  112. }
  113. } else {
  114. // 如果落地域名只绑定到团队,使用team的userId作为parentId
  115. teamId = landingDomainRecord.teamId
  116. const foundTeam = await manager.findOne(Team, { where: { id: teamId } })
  117. if (foundTeam) {
  118. parentId = foundTeam.userId
  119. }
  120. }
  121. }
  122. }
  123. // 4. 如果以上都没有找到有效注册信息,统一分给当天注册最多的渠道(排除team0和team1)
  124. if (parentId === 1 && teamId === 0) {
  125. // 查询当天注册最多的渠道(teamId)
  126. const today = new Date()
  127. today.setHours(0, 0, 0, 0)
  128. const tomorrow = new Date(today)
  129. tomorrow.setDate(tomorrow.getDate() + 1)
  130. // 统计当天每个渠道(teamId)的注册数量,排除teamId为0或1的渠道
  131. const teamCounts = await manager
  132. .createQueryBuilder(Member, 'member')
  133. .select('member.teamId', 'teamId')
  134. .addSelect('COUNT(member.id)', 'count')
  135. .where('member.createdAt >= :today', { today })
  136. .andWhere('member.createdAt < :tomorrow', { tomorrow })
  137. .andWhere('member.teamId > 1') // 排除team0和team1
  138. .groupBy('member.teamId')
  139. .orderBy('count', 'DESC')
  140. .limit(1)
  141. .getRawMany()
  142. if (teamCounts.length > 0 && teamCounts[0].teamId) {
  143. const mostRegisteredTeamId = teamCounts[0].teamId
  144. // 根据teamId查找团队,获取userId作为parentId
  145. const foundTeam = await manager.findOne(Team, { where: { id: mostRegisteredTeamId } })
  146. if (foundTeam) {
  147. parentId = foundTeam.userId
  148. teamId = foundTeam.id
  149. domainId = 0
  150. }
  151. }
  152. }
  153. const defaultPassword = 'password123'
  154. const hashedPassword = await bcrypt.hash(defaultPassword, 10)
  155. const user = manager.create(User, {
  156. name: finalGuestName,
  157. role: UserRole.USER,
  158. parentId,
  159. password: hashedPassword
  160. })
  161. const savedUser = await manager.save(user)
  162. const member = manager.create(Member, {
  163. userId: savedUser.id,
  164. teamId,
  165. domainId,
  166. vipLevel: VipLevel.GUEST,
  167. status: MemberStatus.ACTIVE,
  168. ip: ip || 'unknown',
  169. lastLoginAt: new Date()
  170. })
  171. await manager.save(member)
  172. return savedUser
  173. })
  174. }
  175. async upgradeGuest(userId: number, name: string, password: string, email?: string, phone?: string): Promise<void> {
  176. await this.dataSource.transaction(async manager => {
  177. const user = await manager.findOne(User, { where: { id: userId } })
  178. if (!user) {
  179. throw new Error('用户不存在')
  180. }
  181. const existingUser = await manager.findOne(User, { where: { name } })
  182. if (existingUser && existingUser.id !== userId) {
  183. throw new Error('用户名已被使用')
  184. }
  185. const hashedPassword = await bcrypt.hash(password, 10)
  186. await manager.update(User, userId, {
  187. name,
  188. password: hashedPassword
  189. })
  190. const member = await manager.findOne(Member, { where: { userId } })
  191. if (!member) {
  192. throw new Error('会员信息不存在')
  193. }
  194. if (email) {
  195. const existingEmail = await manager.findOne(Member, { where: { email } })
  196. if (existingEmail && existingEmail.id !== member.id) {
  197. throw new Error('邮箱已被使用')
  198. }
  199. }
  200. if (phone) {
  201. const existingPhone = await manager.findOne(Member, { where: { phone } })
  202. if (existingPhone && existingPhone.id !== member.id) {
  203. throw new Error('手机号已被使用')
  204. }
  205. }
  206. const updateData: Partial<Member> = {}
  207. if (email) {
  208. updateData.email = email
  209. }
  210. if (phone) {
  211. updateData.phone = phone
  212. }
  213. updateData.vipLevel = VipLevel.FREE
  214. await manager.update(Member, member.id, updateData)
  215. })
  216. }
  217. async validateMemberLogin(name: string, password: string): Promise<{ user: User; member: Member } | null> {
  218. const user = await this.dataSource.getRepository(User).findOne({ where: { name } })
  219. if (!user) {
  220. return null
  221. }
  222. if (!user.password) {
  223. return null
  224. }
  225. const isPasswordValid = await bcrypt.compare(password, user.password)
  226. if (!isPasswordValid) {
  227. return null
  228. }
  229. const member = await this.findByUserId(user.id)
  230. if (!member) {
  231. return null
  232. }
  233. if (member.status !== MemberStatus.ACTIVE) {
  234. return null
  235. }
  236. await this.updateLastLogin(member.id)
  237. return { user, member }
  238. }
  239. async create(data: {
  240. userId: number
  241. teamId?: number
  242. domainId?: number
  243. email?: string
  244. phone?: string
  245. vipLevel?: VipLevel
  246. status?: MemberStatus
  247. vipExpireTime?: Date
  248. ip?: string
  249. }): Promise<Member> {
  250. const member = this.memberRepository.create({
  251. userId: data.userId,
  252. teamId: data.teamId,
  253. domainId: data.domainId,
  254. email: data.email,
  255. phone: data.phone,
  256. vipLevel: data.vipLevel || VipLevel.GUEST,
  257. status: data.status || MemberStatus.ACTIVE,
  258. vipExpireTime: data.vipExpireTime,
  259. ip: data.ip
  260. })
  261. return this.memberRepository.save(member)
  262. }
  263. async findById(id: number): Promise<Member> {
  264. return this.memberRepository.findOneOrFail({ where: { id } })
  265. }
  266. async findByUserId(userId: number): Promise<Member | null> {
  267. return this.memberRepository.findOne({ where: { userId } })
  268. }
  269. async findByEmail(email: string): Promise<Member | null> {
  270. return this.memberRepository.findOne({ where: { email } })
  271. }
  272. async findByPhone(phone: string): Promise<Member | null> {
  273. return this.memberRepository.findOne({ where: { phone } })
  274. }
  275. async list(
  276. page: number,
  277. size: number,
  278. filters?: {
  279. vipLevel?: VipLevel | VipLevel[]
  280. status?: MemberStatus | MemberStatus[]
  281. userId?: number
  282. }
  283. ): Promise<PaginationResponse<Member>> {
  284. const where: any = {}
  285. if (filters?.vipLevel) {
  286. where.vipLevel = filters.vipLevel instanceof Array ? In(filters.vipLevel) : filters.vipLevel
  287. }
  288. if (filters?.status) {
  289. where.status = filters.status instanceof Array ? In(filters.status) : filters.status
  290. }
  291. if (filters?.userId) {
  292. where.userId = filters.userId
  293. }
  294. const [members, total] = await this.memberRepository.findAndCount({
  295. skip: (Number(page) || 0) * (Number(size) || 20),
  296. take: Number(size) || 20,
  297. where,
  298. order: { createdAt: 'DESC' }
  299. })
  300. return {
  301. content: members,
  302. metadata: {
  303. total: Number(total),
  304. page: Number(page),
  305. size: Number(size)
  306. }
  307. }
  308. }
  309. async update(id: number, data: Partial<Member>): Promise<Member> {
  310. await this.memberRepository.update(id, data)
  311. return this.findById(id)
  312. }
  313. async delete(id: number): Promise<void> {
  314. await this.memberRepository.delete(id)
  315. }
  316. async updateLastLogin(id: number): Promise<void> {
  317. await this.memberRepository.update(id, { lastLoginAt: new Date() })
  318. }
  319. async updateVipLevel(id: number, vipLevel: VipLevel, vipExpireTime?: Date): Promise<Member> {
  320. const updateData: Partial<Member> = { vipLevel }
  321. if (vipExpireTime) {
  322. updateData.vipExpireTime = vipExpireTime
  323. } else {
  324. const duration = this.vipDurations[vipLevel]
  325. updateData.vipExpireTime = duration ? new Date(Date.now() + duration) : undefined
  326. }
  327. return this.update(id, updateData)
  328. }
  329. async updateStatus(id: number, status: MemberStatus): Promise<Member> {
  330. return this.update(id, { status })
  331. }
  332. async findAllMembers(): Promise<Partial<Member>[]> {
  333. return this.memberRepository.find({
  334. select: ['id', 'userId', 'email', 'phone', 'vipLevel', 'status', 'vipExpireTime', 'lastLoginAt']
  335. })
  336. }
  337. async countByVipLevel(): Promise<Record<VipLevel, number>> {
  338. const result: Record<VipLevel, number> = {} as Record<VipLevel, number>
  339. for (const level of Object.values(VipLevel)) {
  340. const count = await this.memberRepository.count({ where: { vipLevel: level } })
  341. result[level] = count
  342. }
  343. return result
  344. }
  345. async countByStatus(): Promise<Record<MemberStatus, number>> {
  346. const result: Record<MemberStatus, number> = {} as Record<MemberStatus, number>
  347. for (const status of Object.values(MemberStatus)) {
  348. const count = await this.memberRepository.count({ where: { status } })
  349. result[status] = count
  350. }
  351. return result
  352. }
  353. async checkVipExpireTime(member: Member): Promise<void> {
  354. if (member.vipExpireTime && member.vipExpireTime < new Date()) {
  355. member.vipLevel = VipLevel.FREE
  356. await this.update(member.id, member)
  357. }
  358. }
  359. async register(
  360. name: string,
  361. password: string,
  362. email?: string,
  363. phone?: string,
  364. code?: string,
  365. ip?: string,
  366. memberCode?: string,
  367. landingDomain?: string
  368. ): Promise<{ user: User; member: Member }> {
  369. return await this.dataSource.transaction(async manager => {
  370. // 检查用户名是否已存在
  371. const existingUser = await manager.findOne(User, { where: { name } })
  372. if (existingUser) {
  373. throw new Error('用户名已被使用')
  374. }
  375. // 检查邮箱是否已存在
  376. if (email) {
  377. const existingEmail = await manager.findOne(Member, { where: { email } })
  378. if (existingEmail) {
  379. throw new Error('邮箱已被使用')
  380. }
  381. }
  382. // 检查手机号是否已存在
  383. if (phone) {
  384. const existingPhone = await manager.findOne(Member, { where: { phone } })
  385. if (existingPhone) {
  386. throw new Error('手机号已被使用')
  387. }
  388. }
  389. // 获取推荐团队或根据IP查找历史注册信息
  390. // 校验顺序:推广码 -> 落地域名 -> IP历史记录
  391. let team = null
  392. let parentId = 1
  393. let teamId = 0
  394. let domainId = 0
  395. // 1. 优先使用推广码(memberCode 或 code)
  396. const promoCode = memberCode || code
  397. if (promoCode && promoCode.trim() !== '') {
  398. // 如果提供了 memberCode,优先查找团队成员的推广码
  399. if (memberCode && memberCode.trim() !== '') {
  400. const teamMember = await manager.findOne(TeamMembers, { where: { promoCode: memberCode } })
  401. if (teamMember) {
  402. // 如果找到团队成员,使用团队成员的 userId 作为 parentId
  403. parentId = teamMember.userId
  404. teamId = teamMember.teamId
  405. domainId = 0
  406. }
  407. }
  408. // 如果没有找到团队成员(或者使用的是 code),尝试查找团队的推广码
  409. if (parentId === 1 && teamId === 0) {
  410. team = await manager.findOne(Team, { where: { affCode: promoCode } })
  411. if (team) {
  412. parentId = team.userId
  413. teamId = team.id
  414. domainId = 0
  415. }
  416. }
  417. }
  418. // 2. 如果推广码没有找到,使用落地域名(landing-domain)
  419. if (parentId === 1 && teamId === 0 && landingDomain && landingDomain.trim() !== '') {
  420. const landingDomainPoolRepository = manager.getRepository(LandingDomainPool)
  421. const landingDomainRecord = await landingDomainPoolRepository.findOne({
  422. where: { domain: landingDomain.trim() }
  423. })
  424. if (landingDomainRecord) {
  425. // 如果落地域名绑定到团队成员(userId不为空),使用teamMember的userId作为parentId
  426. // 这样在分润时可以从teamMember向上查找到team
  427. if (landingDomainRecord.userId) {
  428. const teamMember = await manager.findOne(TeamMembers, { where: { userId: landingDomainRecord.userId } })
  429. if (teamMember) {
  430. parentId = teamMember.userId
  431. teamId = teamMember.teamId
  432. }
  433. } else {
  434. // 如果落地域名只绑定到团队,使用team的userId作为parentId
  435. teamId = landingDomainRecord.teamId
  436. const foundTeam = await manager.findOne(Team, { where: { id: teamId } })
  437. if (foundTeam) {
  438. parentId = foundTeam.userId
  439. }
  440. }
  441. }
  442. }
  443. // 3. 如果以上都没有找到,根据IP查找历史注册信息
  444. if (parentId === 1 && teamId === 0 && ip && ip !== 'unknown') {
  445. // 如果没有推广参数,检查注册IP是否之前注册过账号
  446. const existingMemberByIp = await manager.findOne(Member, {
  447. where: { ip },
  448. order: { createdAt: 'DESC' }
  449. })
  450. if (existingMemberByIp) {
  451. // 如果该IP之前注册过账号,使用之前注册的teamId和domainId
  452. teamId = existingMemberByIp.teamId || 0
  453. domainId = existingMemberByIp.domainId || 0
  454. // 如果domainId存在,检查domain是否绑定到teamMember
  455. if (domainId > 0) {
  456. const teamDomain = await manager.findOne(TeamDomain, { where: { id: domainId } })
  457. if (teamDomain && teamDomain.teamMemberId) {
  458. // 如果domain绑定到teamMember,使用teamMember的userId作为parentId
  459. const teamMember = await manager.findOne(TeamMembers, { where: { id: teamDomain.teamMemberId } })
  460. if (teamMember) {
  461. parentId = teamMember.userId
  462. teamId = teamMember.teamId
  463. }
  464. } else if (teamDomain && teamDomain.teamId) {
  465. // 如果domain只绑定到team,使用team的userId作为parentId
  466. const existingTeam = await manager.findOne(Team, { where: { id: teamDomain.teamId } })
  467. if (existingTeam) {
  468. parentId = existingTeam.userId
  469. teamId = existingTeam.id
  470. }
  471. }
  472. } else if (teamId > 0) {
  473. // 如果没有domainId,根据teamId查找team,获取userId作为parentId(agentId)
  474. const existingTeam = await manager.findOne(Team, { where: { id: teamId } })
  475. if (existingTeam) {
  476. parentId = existingTeam.userId
  477. }
  478. }
  479. }
  480. }
  481. // 4. 如果以上都没有找到有效注册信息,统一分给当天注册最多的渠道(排除team0和team1)
  482. if (parentId === 1 && teamId === 0) {
  483. // 查询当天注册最多的渠道(teamId)
  484. const today = new Date()
  485. today.setHours(0, 0, 0, 0)
  486. const tomorrow = new Date(today)
  487. tomorrow.setDate(tomorrow.getDate() + 1)
  488. // 统计当天每个渠道(teamId)的注册数量,排除teamId为0或1的渠道
  489. const teamCounts = await manager
  490. .createQueryBuilder(Member, 'member')
  491. .select('member.teamId', 'teamId')
  492. .addSelect('COUNT(member.id)', 'count')
  493. .where('member.createdAt >= :today', { today })
  494. .andWhere('member.createdAt < :tomorrow', { tomorrow })
  495. .andWhere('member.teamId > 1') // 排除team0和team1
  496. .groupBy('member.teamId')
  497. .orderBy('count', 'DESC')
  498. .limit(1)
  499. .getRawMany()
  500. if (teamCounts.length > 0 && teamCounts[0].teamId) {
  501. const mostRegisteredTeamId = teamCounts[0].teamId
  502. // 根据teamId查找团队,获取userId作为parentId
  503. const foundTeam = await manager.findOne(Team, { where: { id: mostRegisteredTeamId } })
  504. if (foundTeam) {
  505. parentId = foundTeam.userId
  506. teamId = foundTeam.id
  507. domainId = 0
  508. }
  509. }
  510. }
  511. // 创建用户
  512. const hashedPassword = await bcrypt.hash(password, 10)
  513. const user = manager.create(User, {
  514. name,
  515. password: hashedPassword,
  516. role: UserRole.USER,
  517. parentId
  518. })
  519. const savedUser = await manager.save(user)
  520. // 创建会员
  521. const member = manager.create(Member, {
  522. userId: savedUser.id,
  523. teamId,
  524. domainId,
  525. email,
  526. phone,
  527. vipLevel: VipLevel.FREE,
  528. status: MemberStatus.ACTIVE,
  529. ip: ip || 'unknown',
  530. lastLoginAt: new Date()
  531. })
  532. const savedMember = await manager.save(member)
  533. return { user: savedUser, member: savedMember }
  534. })
  535. }
  536. async updateProfile(userId: number, name: string, email?: string): Promise<void> {
  537. await this.dataSource.transaction(async manager => {
  538. // 检查用户名是否已被其他用户使用
  539. const existingUser = await manager.findOne(User, { where: { name } })
  540. if (existingUser && existingUser.id !== userId) {
  541. throw new Error('用户名已被使用')
  542. }
  543. // 检查邮箱是否已被其他会员使用
  544. if (email) {
  545. const existingEmail = await manager.findOne(Member, { where: { email } })
  546. if (existingEmail && existingEmail.userId !== userId) {
  547. throw new Error('邮箱已被使用')
  548. }
  549. }
  550. // 更新用户名
  551. await manager.update(User, userId, { name })
  552. // 更新会员邮箱
  553. if (email) {
  554. const member = await manager.findOne(Member, { where: { userId } })
  555. if (member) {
  556. await manager.update(Member, member.id, { email })
  557. }
  558. }
  559. })
  560. }
  561. /**
  562. * 封禁当前用户的member
  563. * @param userId 用户ID
  564. * @returns 封禁后的member
  565. */
  566. async banMember(userId: number): Promise<Member> {
  567. const member = await this.findByUserId(userId)
  568. if (!member) {
  569. throw new Error('会员信息不存在')
  570. }
  571. // 将status修改为INACTIVE
  572. return await this.updateStatus(member.id, MemberStatus.INACTIVE)
  573. }
  574. /**
  575. * 检查当前IP是否在被封禁的member的ip中
  576. * @param ip 要检查的IP地址
  577. * @returns 如果IP被封禁返回true,否则返回false
  578. */
  579. async checkBan(ip: string): Promise<boolean> {
  580. // 查找所有被封禁的member(status为INACTIVE)
  581. const bannedMembers = await this.memberRepository.find({
  582. where: { status: MemberStatus.INACTIVE }
  583. })
  584. // 检查当前IP是否匹配任何被封禁member的ip
  585. return bannedMembers.some((member: Member) => member.ip === ip)
  586. }
  587. }