初始化游戏小组管理系统后端项目
- 基于 NestJS + TypeScript + MySQL + Redis 架构 - 完整的模块化设计(认证、用户、小组、游戏、预约等) - JWT 认证和 RBAC 权限控制系统 - Docker 容器化部署支持 - 添加 CLAUDE.md 项目开发指南 - 配置 .gitignore 忽略文件 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
48
src/entities/appointment-participant.entity.ts
Normal file
48
src/entities/appointment-participant.entity.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
Unique,
|
||||
} from 'typeorm';
|
||||
import { ParticipantStatus } from '../common/enums';
|
||||
import { Appointment } from './appointment.entity';
|
||||
import { User } from './user.entity';
|
||||
|
||||
@Entity('appointment_participants')
|
||||
@Unique(['appointmentId', 'userId'])
|
||||
export class AppointmentParticipant {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column()
|
||||
appointmentId: string;
|
||||
|
||||
@ManyToOne(() => Appointment, (appointment) => appointment.participants, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn({ name: 'appointmentId' })
|
||||
appointment: Appointment;
|
||||
|
||||
@Column()
|
||||
userId: string;
|
||||
|
||||
@ManyToOne(() => User)
|
||||
@JoinColumn({ name: 'userId' })
|
||||
user: User;
|
||||
|
||||
@Column({
|
||||
type: 'enum',
|
||||
enum: ParticipantStatus,
|
||||
default: ParticipantStatus.JOINED,
|
||||
})
|
||||
status: ParticipantStatus;
|
||||
|
||||
@Column({ type: 'text', nullable: true, comment: '备注' })
|
||||
note: string;
|
||||
|
||||
@CreateDateColumn()
|
||||
joinedAt: Date;
|
||||
}
|
||||
81
src/entities/appointment.entity.ts
Normal file
81
src/entities/appointment.entity.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
OneToMany,
|
||||
} from 'typeorm';
|
||||
import { AppointmentStatus } from '../common/enums';
|
||||
import { Group } from './group.entity';
|
||||
import { Game } from './game.entity';
|
||||
import { User } from './user.entity';
|
||||
import { AppointmentParticipant } from './appointment-participant.entity';
|
||||
|
||||
@Entity('appointments')
|
||||
export class Appointment {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column()
|
||||
groupId: string;
|
||||
|
||||
@ManyToOne(() => Group, (group) => group.appointments, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn({ name: 'groupId' })
|
||||
group: Group;
|
||||
|
||||
@Column()
|
||||
gameId: string;
|
||||
|
||||
@ManyToOne(() => Game, (game) => game.appointments)
|
||||
@JoinColumn({ name: 'gameId' })
|
||||
game: Game;
|
||||
|
||||
@Column()
|
||||
initiatorId: string;
|
||||
|
||||
@ManyToOne(() => User, (user) => user.appointments)
|
||||
@JoinColumn({ name: 'initiatorId' })
|
||||
initiator: User;
|
||||
|
||||
@Column({ type: 'varchar', length: 200, nullable: true })
|
||||
title: string;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
description: string;
|
||||
|
||||
@Column({ type: 'datetime' })
|
||||
startTime: Date;
|
||||
|
||||
@Column({ type: 'datetime', nullable: true })
|
||||
endTime: Date;
|
||||
|
||||
@Column({ comment: '最大参与人数' })
|
||||
maxParticipants: number;
|
||||
|
||||
@Column({ default: 0, comment: '当前参与人数' })
|
||||
currentParticipants: number;
|
||||
|
||||
@Column({
|
||||
type: 'enum',
|
||||
enum: AppointmentStatus,
|
||||
default: AppointmentStatus.OPEN,
|
||||
})
|
||||
status: AppointmentStatus;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
|
||||
@UpdateDateColumn()
|
||||
updatedAt: Date;
|
||||
|
||||
@OneToMany(
|
||||
() => AppointmentParticipant,
|
||||
(participant) => participant.appointment,
|
||||
)
|
||||
participants: AppointmentParticipant[];
|
||||
}
|
||||
43
src/entities/asset-log.entity.ts
Normal file
43
src/entities/asset-log.entity.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
} from 'typeorm';
|
||||
import { AssetLogAction } from '../common/enums';
|
||||
import { Asset } from './asset.entity';
|
||||
import { User } from './user.entity';
|
||||
|
||||
@Entity('asset_logs')
|
||||
export class AssetLog {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column()
|
||||
assetId: string;
|
||||
|
||||
@ManyToOne(() => Asset, (asset) => asset.logs, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'assetId' })
|
||||
asset: Asset;
|
||||
|
||||
@Column()
|
||||
userId: string;
|
||||
|
||||
@ManyToOne(() => User)
|
||||
@JoinColumn({ name: 'userId' })
|
||||
user: User;
|
||||
|
||||
@Column({ type: 'enum', enum: AssetLogAction })
|
||||
action: AssetLogAction;
|
||||
|
||||
@Column({ default: 1, comment: '数量' })
|
||||
quantity: number;
|
||||
|
||||
@Column({ type: 'text', nullable: true, comment: '备注' })
|
||||
note: string;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
}
|
||||
60
src/entities/asset.entity.ts
Normal file
60
src/entities/asset.entity.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
OneToMany,
|
||||
} from 'typeorm';
|
||||
import { AssetType, AssetStatus } from '../common/enums';
|
||||
import { Group } from './group.entity';
|
||||
import { AssetLog } from './asset-log.entity';
|
||||
|
||||
@Entity('assets')
|
||||
export class Asset {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column()
|
||||
groupId: string;
|
||||
|
||||
@ManyToOne(() => Group, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'groupId' })
|
||||
group: Group;
|
||||
|
||||
@Column({ type: 'enum', enum: AssetType })
|
||||
type: AssetType;
|
||||
|
||||
@Column({ length: 100 })
|
||||
name: string;
|
||||
|
||||
@Column({ type: 'text', nullable: true, comment: '描述' })
|
||||
description: string;
|
||||
|
||||
@Column({ type: 'text', nullable: true, comment: '加密的账号凭据' })
|
||||
accountCredentials?: string | null;
|
||||
|
||||
@Column({ default: 1, comment: '数量(用于物品)' })
|
||||
quantity: number;
|
||||
|
||||
@Column({
|
||||
type: 'enum',
|
||||
enum: AssetStatus,
|
||||
default: AssetStatus.AVAILABLE,
|
||||
})
|
||||
status: AssetStatus;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true, comment: '当前借用人ID' })
|
||||
currentBorrowerId?: string | null;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
|
||||
@UpdateDateColumn()
|
||||
updatedAt: Date;
|
||||
|
||||
@OneToMany(() => AssetLog, (log) => log.asset)
|
||||
logs: AssetLog[];
|
||||
}
|
||||
50
src/entities/bet.entity.ts
Normal file
50
src/entities/bet.entity.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
} from 'typeorm';
|
||||
import { BetStatus } from '../common/enums';
|
||||
import { Appointment } from './appointment.entity';
|
||||
import { User } from './user.entity';
|
||||
|
||||
@Entity('bets')
|
||||
export class Bet {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column()
|
||||
appointmentId: string;
|
||||
|
||||
@ManyToOne(() => Appointment, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'appointmentId' })
|
||||
appointment: Appointment;
|
||||
|
||||
@Column()
|
||||
userId: string;
|
||||
|
||||
@ManyToOne(() => User, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'userId' })
|
||||
user: User;
|
||||
|
||||
@Column({ length: 100, comment: '下注选项' })
|
||||
betOption: string;
|
||||
|
||||
@Column({ type: 'int', comment: '下注积分' })
|
||||
amount: number;
|
||||
|
||||
@Column({ type: 'enum', enum: BetStatus, default: BetStatus.PENDING })
|
||||
status: BetStatus;
|
||||
|
||||
@Column({ type: 'int', default: 0, comment: '赢得的积分' })
|
||||
winAmount: number;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
|
||||
@UpdateDateColumn()
|
||||
updatedAt: Date;
|
||||
}
|
||||
52
src/entities/blacklist.entity.ts
Normal file
52
src/entities/blacklist.entity.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
} from 'typeorm';
|
||||
import { BlacklistStatus } from '../common/enums';
|
||||
import { User } from './user.entity';
|
||||
|
||||
@Entity('blacklists')
|
||||
export class Blacklist {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ length: 100, comment: '目标游戏ID或用户名' })
|
||||
targetGameId: string;
|
||||
|
||||
@Column({ type: 'text' })
|
||||
reason: string;
|
||||
|
||||
@Column()
|
||||
reporterId: string;
|
||||
|
||||
@ManyToOne(() => User)
|
||||
@JoinColumn({ name: 'reporterId' })
|
||||
reporter: User;
|
||||
|
||||
@Column({ type: 'simple-json', nullable: true, comment: '证据图片' })
|
||||
proofImages: string[];
|
||||
|
||||
@Column({
|
||||
type: 'enum',
|
||||
enum: BlacklistStatus,
|
||||
default: BlacklistStatus.PENDING,
|
||||
})
|
||||
status: BlacklistStatus;
|
||||
|
||||
@Column({ nullable: true, comment: '审核人ID' })
|
||||
reviewerId: string;
|
||||
|
||||
@ManyToOne(() => User, { nullable: true })
|
||||
@JoinColumn({ name: 'reviewerId' })
|
||||
reviewer: User;
|
||||
|
||||
@Column({ type: 'text', nullable: true, comment: '审核意见' })
|
||||
reviewNote: string;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
}
|
||||
48
src/entities/game.entity.ts
Normal file
48
src/entities/game.entity.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
OneToMany,
|
||||
} from 'typeorm';
|
||||
import { Appointment } from './appointment.entity';
|
||||
|
||||
@Entity('games')
|
||||
export class Game {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ length: 100 })
|
||||
name: string;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true, length: 255 })
|
||||
coverUrl: string;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
description: string;
|
||||
|
||||
@Column({ comment: '最大玩家数' })
|
||||
maxPlayers: number;
|
||||
|
||||
@Column({ default: 1, comment: '最小玩家数' })
|
||||
minPlayers: number;
|
||||
|
||||
@Column({ length: 50, nullable: true, comment: '平台' })
|
||||
platform: string;
|
||||
|
||||
@Column({ type: 'simple-array', nullable: true, comment: '游戏标签' })
|
||||
tags: string[];
|
||||
|
||||
@Column({ default: true })
|
||||
isActive: boolean;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
|
||||
@UpdateDateColumn()
|
||||
updatedAt: Date;
|
||||
|
||||
@OneToMany(() => Appointment, (appointment) => appointment.game)
|
||||
appointments: Appointment[];
|
||||
}
|
||||
49
src/entities/group-member.entity.ts
Normal file
49
src/entities/group-member.entity.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
Unique,
|
||||
} from 'typeorm';
|
||||
import { GroupMemberRole } from '../common/enums';
|
||||
import { User } from './user.entity';
|
||||
import { Group } from './group.entity';
|
||||
|
||||
@Entity('group_members')
|
||||
@Unique(['groupId', 'userId'])
|
||||
export class GroupMember {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column()
|
||||
groupId: string;
|
||||
|
||||
@ManyToOne(() => Group, (group) => group.members, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'groupId' })
|
||||
group: Group;
|
||||
|
||||
@Column()
|
||||
userId: string;
|
||||
|
||||
@ManyToOne(() => User, (user) => user.groupMembers, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'userId' })
|
||||
user: User;
|
||||
|
||||
@Column({
|
||||
type: 'enum',
|
||||
enum: GroupMemberRole,
|
||||
default: GroupMemberRole.MEMBER,
|
||||
})
|
||||
role: GroupMemberRole;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true, length: 50, comment: '组内昵称' })
|
||||
nickname: string;
|
||||
|
||||
@Column({ default: true })
|
||||
isActive: boolean;
|
||||
|
||||
@CreateDateColumn()
|
||||
joinedAt: Date;
|
||||
}
|
||||
69
src/entities/group.entity.ts
Normal file
69
src/entities/group.entity.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
OneToMany,
|
||||
} from 'typeorm';
|
||||
import { User } from './user.entity';
|
||||
import { GroupMember } from './group-member.entity';
|
||||
import { Appointment } from './appointment.entity';
|
||||
|
||||
@Entity('groups')
|
||||
export class Group {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ length: 100 })
|
||||
name: string;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
description: string;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true, length: 255 })
|
||||
avatar: string;
|
||||
|
||||
@Column()
|
||||
ownerId: string;
|
||||
|
||||
@ManyToOne(() => User)
|
||||
@JoinColumn({ name: 'ownerId' })
|
||||
owner: User;
|
||||
|
||||
@Column({ default: 'normal', length: 20, comment: '类型: normal/guild' })
|
||||
type: string;
|
||||
|
||||
@Column({ nullable: true, comment: '父组ID,用于子组' })
|
||||
parentId: string;
|
||||
|
||||
@ManyToOne(() => Group, { nullable: true })
|
||||
@JoinColumn({ name: 'parentId' })
|
||||
parent: Group;
|
||||
|
||||
@Column({ type: 'text', nullable: true, comment: '公示信息' })
|
||||
announcement: string;
|
||||
|
||||
@Column({ default: 50, comment: '最大成员数' })
|
||||
maxMembers: number;
|
||||
|
||||
@Column({ default: 1, comment: '当前成员数' })
|
||||
currentMembers: number;
|
||||
|
||||
@Column({ default: true })
|
||||
isActive: boolean;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
|
||||
@UpdateDateColumn()
|
||||
updatedAt: Date;
|
||||
|
||||
@OneToMany(() => GroupMember, (member) => member.group)
|
||||
members: GroupMember[];
|
||||
|
||||
@OneToMany(() => Appointment, (appointment) => appointment.group)
|
||||
appointments: Appointment[];
|
||||
}
|
||||
48
src/entities/honor.entity.ts
Normal file
48
src/entities/honor.entity.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
} from 'typeorm';
|
||||
import { Group } from './group.entity';
|
||||
import { User } from './user.entity';
|
||||
|
||||
@Entity('honors')
|
||||
export class Honor {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column()
|
||||
groupId: string;
|
||||
|
||||
@ManyToOne(() => Group, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'groupId' })
|
||||
group: Group;
|
||||
|
||||
@Column({ length: 200 })
|
||||
title: string;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
description: string;
|
||||
|
||||
@Column({ type: 'simple-json', nullable: true, comment: '媒体文件URLs' })
|
||||
mediaUrls: string[];
|
||||
|
||||
@Column({ type: 'date', comment: '事件日期' })
|
||||
eventDate: Date;
|
||||
|
||||
@Column({ type: 'simple-json', nullable: true, comment: '参与者ID列表' })
|
||||
participantIds: string[];
|
||||
|
||||
@Column()
|
||||
creatorId: string;
|
||||
|
||||
@ManyToOne(() => User)
|
||||
@JoinColumn({ name: 'creatorId' })
|
||||
creator: User;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
}
|
||||
49
src/entities/ledger.entity.ts
Normal file
49
src/entities/ledger.entity.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
} from 'typeorm';
|
||||
import { LedgerType } from '../common/enums';
|
||||
import { Group } from './group.entity';
|
||||
import { User } from './user.entity';
|
||||
|
||||
@Entity('ledgers')
|
||||
export class Ledger {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column()
|
||||
groupId: string;
|
||||
|
||||
@ManyToOne(() => Group, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'groupId' })
|
||||
group: Group;
|
||||
|
||||
@Column()
|
||||
creatorId: string;
|
||||
|
||||
@ManyToOne(() => User)
|
||||
@JoinColumn({ name: 'creatorId' })
|
||||
creator: User;
|
||||
|
||||
@Column({ type: 'decimal', precision: 10, scale: 2 })
|
||||
amount: number;
|
||||
|
||||
@Column({ type: 'enum', enum: LedgerType })
|
||||
type: LedgerType;
|
||||
|
||||
@Column({ type: 'varchar', length: 50, nullable: true, comment: '分类' })
|
||||
category: string;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
description: string;
|
||||
|
||||
@Column({ type: 'simple-json', nullable: true, comment: '凭证图片' })
|
||||
proofImages: string[];
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
}
|
||||
45
src/entities/point.entity.ts
Normal file
45
src/entities/point.entity.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
} from 'typeorm';
|
||||
import { User } from './user.entity';
|
||||
import { Group } from './group.entity';
|
||||
|
||||
@Entity('points')
|
||||
export class Point {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column()
|
||||
userId: string;
|
||||
|
||||
@ManyToOne(() => User, (user) => user.points, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'userId' })
|
||||
user: User;
|
||||
|
||||
@Column()
|
||||
groupId: string;
|
||||
|
||||
@ManyToOne(() => Group, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'groupId' })
|
||||
group: Group;
|
||||
|
||||
@Column({ type: 'int', comment: '积分变动值,正为增加,负为减少' })
|
||||
amount: number;
|
||||
|
||||
@Column({ length: 100, comment: '原因' })
|
||||
reason: string;
|
||||
|
||||
@Column({ type: 'text', nullable: true, comment: '详细说明' })
|
||||
description: string;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true, comment: '关联ID(如活动ID、预约ID)' })
|
||||
relatedId: string;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
}
|
||||
43
src/entities/schedule.entity.ts
Normal file
43
src/entities/schedule.entity.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
} from 'typeorm';
|
||||
import { User } from './user.entity';
|
||||
import { Group } from './group.entity';
|
||||
|
||||
@Entity('schedules')
|
||||
export class Schedule {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column()
|
||||
userId: string;
|
||||
|
||||
@ManyToOne(() => User, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'userId' })
|
||||
user: User;
|
||||
|
||||
@Column()
|
||||
groupId: string;
|
||||
|
||||
@ManyToOne(() => Group, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'groupId' })
|
||||
group: Group;
|
||||
|
||||
@Column({
|
||||
type: 'simple-json',
|
||||
comment: '空闲时间段 JSON: { "mon": ["20:00-23:00"], ... }',
|
||||
})
|
||||
availableSlots: Record<string, string[]>;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
|
||||
@UpdateDateColumn()
|
||||
updatedAt: Date;
|
||||
}
|
||||
63
src/entities/user.entity.ts
Normal file
63
src/entities/user.entity.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
OneToMany,
|
||||
} from 'typeorm';
|
||||
import { UserRole } from '../common/enums';
|
||||
import { GroupMember } from './group-member.entity';
|
||||
import { Appointment } from './appointment.entity';
|
||||
import { Point } from './point.entity';
|
||||
|
||||
@Entity('users')
|
||||
export class User {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ unique: true, length: 50 })
|
||||
username: string;
|
||||
|
||||
@Column({ unique: true, nullable: true, length: 100 })
|
||||
email: string;
|
||||
|
||||
@Column({ unique: true, nullable: true, length: 20 })
|
||||
phone: string;
|
||||
|
||||
@Column({ select: false })
|
||||
password: string;
|
||||
|
||||
@Column({ nullable: true, length: 255 })
|
||||
avatar: string;
|
||||
|
||||
@Column({ type: 'enum', enum: UserRole, default: UserRole.USER })
|
||||
role: UserRole;
|
||||
|
||||
@Column({ default: false, comment: '是否为会员' })
|
||||
isMember: boolean;
|
||||
|
||||
@Column({ type: 'datetime', nullable: true, comment: '会员到期时间' })
|
||||
memberExpireAt: Date;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true, length: 50, comment: '最后登录IP' })
|
||||
lastLoginIp: string | null;
|
||||
|
||||
@Column({ type: 'datetime', nullable: true, comment: '最后登录时间' })
|
||||
lastLoginAt: Date;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
|
||||
@UpdateDateColumn()
|
||||
updatedAt: Date;
|
||||
|
||||
@OneToMany(() => GroupMember, (groupMember) => groupMember.user)
|
||||
groupMembers: GroupMember[];
|
||||
|
||||
@OneToMany(() => Appointment, (appointment) => appointment.initiator)
|
||||
appointments: Appointment[];
|
||||
|
||||
@OneToMany(() => Point, (point) => point.user)
|
||||
points: Point[];
|
||||
}
|
||||
Reference in New Issue
Block a user