diff --git a/apps/server/src/models/daily-train/dailyTrain.controller.ts b/apps/server/src/models/daily-train/dailyTrain.controller.ts new file mode 100644 index 0000000..c091dba --- /dev/null +++ b/apps/server/src/models/daily-train/dailyTrain.controller.ts @@ -0,0 +1,9 @@ +import { Controller, UseGuards } from "@nestjs/common"; +import { AuthGuard } from '@server/auth/auth.guard'; +import { DailyTrainService } from "./dailyTrain.service"; + +@Controller('train-content') +export class DailyTrainController { + constructor(private readonly dailyTrainService: DailyTrainService) {} + //@UseGuards(AuthGuard) +} \ No newline at end of file diff --git a/apps/server/src/models/daily-train/dailyTrain.module.ts b/apps/server/src/models/daily-train/dailyTrain.module.ts new file mode 100644 index 0000000..702ed7d --- /dev/null +++ b/apps/server/src/models/daily-train/dailyTrain.module.ts @@ -0,0 +1,15 @@ +import { Module } from '@nestjs/common'; +import { StaffModule } from '../staff/staff.module'; +import { TrpcService } from '@server/trpc/trpc.service'; +import { DailyTrainController } from './dailyTrain.controller'; +import { DailyTrainService } from './dailyTrain.service'; +import { DailyTrainRouter } from './dailyTrain.router'; + + +@Module({ + imports: [StaffModule], + controllers: [DailyTrainController], + providers: [DailyTrainService,DailyTrainRouter,TrpcService], + exports: [DailyTrainService,DailyTrainRouter], +}) +export class DailyTrainModule {} \ No newline at end of file diff --git a/apps/server/src/models/daily-train/dailyTrain.router.ts b/apps/server/src/models/daily-train/dailyTrain.router.ts new file mode 100644 index 0000000..d3e9d18 --- /dev/null +++ b/apps/server/src/models/daily-train/dailyTrain.router.ts @@ -0,0 +1,16 @@ +import { Injectable } from "@nestjs/common"; +import { TrpcService } from "@server/trpc/trpc.service"; +import { DailyTrainService } from "./dailyTrain.service"; + +@Injectable() +export class DailyTrainRouter { + constructor( + private readonly trpc: TrpcService, + private readonly dailyTrainService: DailyTrainService, + ) { } + + router = this.trpc.router({ + + }) + +} \ No newline at end of file diff --git a/apps/server/src/models/daily-train/dailyTrain.service.ts b/apps/server/src/models/daily-train/dailyTrain.service.ts new file mode 100644 index 0000000..1b5a182 --- /dev/null +++ b/apps/server/src/models/daily-train/dailyTrain.service.ts @@ -0,0 +1,40 @@ +import { Injectable } from "@nestjs/common"; +import { BaseService } from "../base/base.service"; +import { db, ObjectType, Prisma, UserProfile } from "@nice/common"; +import { DefaultArgs } from "@prisma/client/runtime/library"; +import EventBus, { CrudOperation } from "@server/utils/event-bus"; + + +@Injectable() +export class DailyTrainService extends BaseService { + constructor() { + super(db,ObjectType.DAILY_TRAIN,true); + } + async create(args: Prisma.DailyTrainTimeCreateArgs) { + console.log(args) + const result = await super.create(args) + this.emitDataChanged(CrudOperation.CREATED,result) + return result + } + + async update(args:Prisma.DailyTrainTimeUpdateArgs){ + const result = await super.update(args) + this.emitDataChanged(CrudOperation.UPDATED,result) + return result + } + + + async findMany(args: Prisma.DailyTrainTimeFindManyArgs) { + const result = await super.findMany(args); + return result; + } + + + private emitDataChanged(operation: CrudOperation, data: any) { + EventBus.emit('dataChanged', { + type:ObjectType.DAILY_TRAIN, + operation, + data, + }); + } +} \ No newline at end of file diff --git a/apps/server/src/models/position/dailyTrain.controller.ts b/apps/server/src/models/position/dailyTrain.controller.ts new file mode 100644 index 0000000..c091dba --- /dev/null +++ b/apps/server/src/models/position/dailyTrain.controller.ts @@ -0,0 +1,9 @@ +import { Controller, UseGuards } from "@nestjs/common"; +import { AuthGuard } from '@server/auth/auth.guard'; +import { DailyTrainService } from "./dailyTrain.service"; + +@Controller('train-content') +export class DailyTrainController { + constructor(private readonly dailyTrainService: DailyTrainService) {} + //@UseGuards(AuthGuard) +} \ No newline at end of file diff --git a/apps/server/src/models/position/dailyTrain.module.ts b/apps/server/src/models/position/dailyTrain.module.ts new file mode 100644 index 0000000..702ed7d --- /dev/null +++ b/apps/server/src/models/position/dailyTrain.module.ts @@ -0,0 +1,15 @@ +import { Module } from '@nestjs/common'; +import { StaffModule } from '../staff/staff.module'; +import { TrpcService } from '@server/trpc/trpc.service'; +import { DailyTrainController } from './dailyTrain.controller'; +import { DailyTrainService } from './dailyTrain.service'; +import { DailyTrainRouter } from './dailyTrain.router'; + + +@Module({ + imports: [StaffModule], + controllers: [DailyTrainController], + providers: [DailyTrainService,DailyTrainRouter,TrpcService], + exports: [DailyTrainService,DailyTrainRouter], +}) +export class DailyTrainModule {} \ No newline at end of file diff --git a/apps/server/src/models/position/dailyTrain.router.ts b/apps/server/src/models/position/dailyTrain.router.ts new file mode 100644 index 0000000..d3e9d18 --- /dev/null +++ b/apps/server/src/models/position/dailyTrain.router.ts @@ -0,0 +1,16 @@ +import { Injectable } from "@nestjs/common"; +import { TrpcService } from "@server/trpc/trpc.service"; +import { DailyTrainService } from "./dailyTrain.service"; + +@Injectable() +export class DailyTrainRouter { + constructor( + private readonly trpc: TrpcService, + private readonly dailyTrainService: DailyTrainService, + ) { } + + router = this.trpc.router({ + + }) + +} \ No newline at end of file diff --git a/apps/server/src/models/position/dailyTrain.service.ts b/apps/server/src/models/position/dailyTrain.service.ts new file mode 100644 index 0000000..1b5a182 --- /dev/null +++ b/apps/server/src/models/position/dailyTrain.service.ts @@ -0,0 +1,40 @@ +import { Injectable } from "@nestjs/common"; +import { BaseService } from "../base/base.service"; +import { db, ObjectType, Prisma, UserProfile } from "@nice/common"; +import { DefaultArgs } from "@prisma/client/runtime/library"; +import EventBus, { CrudOperation } from "@server/utils/event-bus"; + + +@Injectable() +export class DailyTrainService extends BaseService { + constructor() { + super(db,ObjectType.DAILY_TRAIN,true); + } + async create(args: Prisma.DailyTrainTimeCreateArgs) { + console.log(args) + const result = await super.create(args) + this.emitDataChanged(CrudOperation.CREATED,result) + return result + } + + async update(args:Prisma.DailyTrainTimeUpdateArgs){ + const result = await super.update(args) + this.emitDataChanged(CrudOperation.UPDATED,result) + return result + } + + + async findMany(args: Prisma.DailyTrainTimeFindManyArgs) { + const result = await super.findMany(args); + return result; + } + + + private emitDataChanged(operation: CrudOperation, data: any) { + EventBus.emit('dataChanged', { + type:ObjectType.DAILY_TRAIN, + operation, + data, + }); + } +} \ No newline at end of file diff --git a/apps/server/src/models/train-content/trainContent.service.ts b/apps/server/src/models/train-content/trainContent.service.ts index 8015cf2..6f57562 100644 --- a/apps/server/src/models/train-content/trainContent.service.ts +++ b/apps/server/src/models/train-content/trainContent.service.ts @@ -1,6 +1,8 @@ import { Injectable } from "@nestjs/common"; import { BaseService } from "../base/base.service"; import { db, ObjectType, Prisma, UserProfile } from "@nice/common"; +import { DefaultArgs } from "@prisma/client/runtime/library"; +import EventBus, { CrudOperation } from "@server/utils/event-bus"; @Injectable() @@ -8,5 +10,31 @@ export class TrainContentService extends BaseService = z.any() - +const TrainSituationUpdateArgsSchema:ZodType = z.any() +const TrainSituationFindManyArgsSchema:ZodType = z.any() @Injectable() export class TrainSituationRouter { @@ -18,8 +19,27 @@ export class TrainSituationRouter { create:this.trpc.protectProcedure .input(TrainSituationArgsSchema) .mutation(async ({ input }) => { - this.trainSituationService.create(input) + return this.trainSituationService.create(input) }), + update:this.trpc.protectProcedure + .input(TrainSituationUpdateArgsSchema) + .mutation(async ({ input }) => { + return this.trainSituationService.update(input) + }), + findMany:this.trpc.protectProcedure + .input(TrainSituationFindManyArgsSchema) + .mutation(async ({input}) =>{ + return this.trainSituationService.findMany(input) + }), + findManyByDepId:this.trpc.protectProcedure + .input(z.object({ + deptId: z.string().optional(), + domainId: z.string().optional(), + trainContentId: z.string().optional() + })) + .mutation(async ({input}) => { + return this.trainSituationService.findManyByDeptId(input) + }) }) } \ No newline at end of file diff --git a/apps/server/src/models/train-situation/trainSituation.service.ts b/apps/server/src/models/train-situation/trainSituation.service.ts index 1b54509..26968ce 100644 --- a/apps/server/src/models/train-situation/trainSituation.service.ts +++ b/apps/server/src/models/train-situation/trainSituation.service.ts @@ -2,13 +2,16 @@ import { Injectable } from "@nestjs/common"; import { BaseService } from "../base/base.service"; import { db, ObjectType, Prisma, UserProfile } from "@nice/common"; import EventBus, { CrudOperation } from "@server/utils/event-bus"; +import { DefaultArgs } from "@prisma/client/runtime/library"; +import { StaffService } from "../staff/staff.service"; @Injectable() export class TrainSituationService extends BaseService { - constructor() { + constructor(private readonly staffService:StaffService) { super(db,ObjectType.TRAIN_SITUATION,false); } + // 创建培训情况 async create( args: Prisma.TrainSituationCreateArgs, ){ @@ -17,12 +20,61 @@ export class TrainSituationService extends BaseService + { + const result = await super.findMany(args); + return result; + } + // 查找某一单位所有人员的培训情况 + async findManyByDeptId(args:{ + deptId?:string, + domainId?:string, + trainContentId?:string + }):Promise<{ + id: string; + staffId: string; + trainContentId: string; + mustTrainTime: number; + alreadyTrainTime: number; + score: number; + }[]> + { + const staffs = await this.staffService.findByDept({deptId:args.deptId,domainId:args.domainId}) + const result = await super.findMany({ + where:{ + staffId:{ + in:staffs.map(staff=>staff.id) + }, + ...(args.trainContentId ? {trainContentId:args.trainContentId} : {}) + } + }) + return result + } + //async createDailyTrainTime() + + // 发送数据变化事件 private emitDataChanged(operation: CrudOperation, data: any) { EventBus.emit('dataChanged', { type:ObjectType.TRAIN_SITUATION, operation, data, }); - } + } } \ No newline at end of file diff --git a/apps/server/src/tasks/init/gendev.service.ts b/apps/server/src/tasks/init/gendev.service.ts index 441ef91..ea3f0ee 100755 --- a/apps/server/src/tasks/init/gendev.service.ts +++ b/apps/server/src/tasks/init/gendev.service.ts @@ -49,10 +49,11 @@ export class GenDevService { try { await this.calculateCounts(); await this.generateDepartments(3, 6); - await this.generateTerms(2, 6); + //await this.generateTerms(2, 6); await this.generateStaffs(4); - await this.generateCourses(8); + //await this.generateCourses(8); await this.generateTrainContent(2,6) + await this.generateTrainSituations() } catch (err) { this.logger.error(err); } @@ -209,7 +210,7 @@ export class GenDevService { } } } - private async generateStaffs(countPerDept: number = 3) { + private async generateStaffs(countPerDept: number = 2) { if (this.counts.staffCount === 1) { this.logger.log('Generating staffs...'); // Calculate the total number of staffs to be generated @@ -344,7 +345,7 @@ export class GenDevService { await createTermTree(null, 1); } - + // 生成培训内容 private async createTrainContent( type:string, title:string, @@ -359,7 +360,7 @@ export class GenDevService { }); return trainContent; } - + // 生成培训内容 private async generateTrainContent(depth:number=3,count:number=6){ if(this.counts.trainContentCount !== 0) return; const totalTrainContent = this.calculateTotalTrainContent(depth,count) @@ -368,6 +369,7 @@ export class GenDevService { this.trainContents = await db.trainContent.findMany() this.logger.log(`Completed: Generated ${this.trainContents.length} departments.`); } + // 生成培训内容子内容 private async generateSubTrainContent( parentId: string | null, currentDepth:number, @@ -404,4 +406,47 @@ export class GenDevService { } return total; } -} + + + private async createTrainSituation(staffId:string,trainContentId:string){ + const trainSituation = await db.trainSituation.create({ + data:{ + staffId, + trainContentId, + mustTrainTime:Math.floor(Math.random()*100), + alreadyTrainTime:Math.floor(Math.random()*100), + score:Math.floor(Math.random()*100), + } + }) + return trainSituation + } + + private async generateTrainSituations(probability: number = 0.7){ + this.logger.log("Start generating train situations...") + const allTrainContents = await db.trainContent.findMany(); + // 这里相当于两次遍历 找到没有parentID的即是 + const leafNodes = allTrainContents.filter((item)=>item.parentId !== null) + console.log(leafNodes.length) + const staffs = await db.staff.findMany() + + let situationCount = 0 + const totalPossibleSituations = leafNodes.length * staffs.length + + for (const staff of staffs){ + for(const leaf of leafNodes){ + if(Math.random() < probability){ + await this.createTrainSituation(staff.id,leaf.id) + situationCount++ + if (situationCount % 100 === 0) { + this.logger.log( + `Generated ${situationCount} train situations` + ); + } + } + } + } + this.logger.log( + `Completed: Generated ${situationCount} train situations out of ${totalPossibleSituations} possible combinations.` + ); + } +} \ No newline at end of file diff --git a/apps/server/src/trpc/trpc.module.ts b/apps/server/src/trpc/trpc.module.ts index dff231d..5ae0760 100755 --- a/apps/server/src/trpc/trpc.module.ts +++ b/apps/server/src/trpc/trpc.module.ts @@ -17,7 +17,7 @@ import { TransformModule } from '@server/models/transform/transform.module'; import { TrainContentModule } from '@server/models/train-content/trainContent.module'; import { ResourceModule } from '@server/models/resource/resource.module'; import { TrainSituationModule } from '@server/models/train-situation/trainSituation.module'; - +import { DailyTrainModule } from '@server/models/daily-train/dailyTrain.module'; @Module({ imports: [ AuthModule, @@ -35,7 +35,8 @@ import { TrainSituationModule } from '@server/models/train-situation/trainSituat WebSocketModule, ResourceModule, TrainContentModule, - TrainSituationModule + TrainSituationModule, + DailyTrainModule ], controllers: [], providers: [TrpcService, TrpcRouter, Logger], diff --git a/apps/server/src/trpc/trpc.router.ts b/apps/server/src/trpc/trpc.router.ts index 4556791..dec98f9 100755 --- a/apps/server/src/trpc/trpc.router.ts +++ b/apps/server/src/trpc/trpc.router.ts @@ -16,6 +16,7 @@ import { RoleRouter } from '@server/models/rbac/role.router'; import { ResourceRouter } from '../models/resource/resource.router'; import { TrainContentRouter } from '@server/models/train-content/trainContent.router'; import { TrainSituationRouter } from '@server/models/train-situation/trainSituation.router'; +import { DailyTrainRouter } from '@server/models/daily-train/dailyTrain.router'; @Injectable() export class TrpcRouter { @@ -36,6 +37,7 @@ export class TrpcRouter { private readonly resource: ResourceRouter, private readonly trainContent: TrainContentRouter, private readonly trainSituation:TrainSituationRouter, + private readonly dailyTrain:DailyTrainRouter ) {} getRouter() { return; @@ -54,7 +56,8 @@ export class TrpcRouter { visitor: this.visitor.router, resource: this.resource.router, trainContent:this.trainContent.router, - trainSituation:this.trainSituation.router + trainSituation:this.trainSituation.router, + dailyTrain:this.dailyTrain.router }); wss: WebSocketServer = undefined; diff --git a/packages/client/src/api/hooks/useTrainSituation.ts b/packages/client/src/api/hooks/useTrainSituation.ts index 441e113..8779f65 100644 --- a/packages/client/src/api/hooks/useTrainSituation.ts +++ b/packages/client/src/api/hooks/useTrainSituation.ts @@ -16,8 +16,16 @@ export function useTrainSituation(){ emitDataChange(ObjectType.TRAIN_SITUATION, res, CrudOperation.CREATED); }, }); + + const update = api.trainSituation.update.useMutation({ + onSuccess:(res:any)=>{ + queryClient.invalidateQueries({queryKey}); + emitDataChange(ObjectType.TRAIN_SITUATION,res,CrudOperation.UPDATED) + } + }) return { - create + create, + update } } \ No newline at end of file diff --git a/packages/common/prisma/schema.prisma b/packages/common/prisma/schema.prisma index 5922d7b..8d8a97e 100755 --- a/packages/common/prisma/schema.prisma +++ b/packages/common/prisma/schema.prisma @@ -359,13 +359,24 @@ model TrainSituation { trainContentId String @map("train_content_id") trainContent TrainContent @relation(fields: [trainContentId], references: [id]) - score Float @default(0.0) @map("score") - mustTrainTime String @map("must_train_time") - alreadyTrainTime String @map("already_train_time") + score Float @default(0.0) @map("score") + mustTrainTime Float @map("must_train_time") + alreadyTrainTime Float @map("already_train_time") + dailyTrainTime DailyTrainTime[] @relation("DailyTrainSituation") @@map("train_situation") } +model DailyTrainTime { + id String @id @default(cuid()) + trainSituationId String @map("train_situatio_id") + trainSituation TrainSituation @relation("DailyTrainSituation", fields: [trainSituationId], references: [id]) + trainTime Float @default(0.0) @map("trainTime") + createdAt DateTime @default(now()) @map("created_at") + + @@map("daily_train_situation") +} + model Position { id String @id @default(cuid()) @map("id") type String @map("type") diff --git a/packages/common/src/enum.ts b/packages/common/src/enum.ts index 9028b44..4fc900a 100755 --- a/packages/common/src/enum.ts +++ b/packages/common/src/enum.ts @@ -60,7 +60,8 @@ export enum ObjectType { ENROLLMENT = "enrollment", RESOURCE = "resource", TRAIN_CONTENT = "trainContent", - TRAIN_SITUATION = "trainSituation" + TRAIN_SITUATION = "trainSituation", + DAILY_TRAIN = "dailyTrainTime" } export enum RolePerms { // Create Permissions 创建权限 diff --git a/packages/common/src/models/select.ts b/packages/common/src/models/select.ts index f21f1a6..f97fdf2 100755 --- a/packages/common/src/models/select.ts +++ b/packages/common/src/models/select.ts @@ -135,3 +135,35 @@ export const lectureDetailSelect: Prisma.PostSelect = { meta: true, }; + +export const trainSituationDetailSelect: Prisma.TrainSituationSelect = { + id: true, + staffId: true, + trainContentId: true, + mustTrainTime: true, + alreadyTrainTime: true, + score: true, + staff: { + select: { + id: true, + showname: true, + avatar: true, + department: { + select: { + id: true, + name: true, + }, + }, + age: true, + sex: true, + absent: true, + }, + }, + trainContent: { + select: { + id: true, + title: true, + + }, + }, +};