This commit is contained in:
Rao 2025-03-25 07:52:33 +08:00
parent 67ab433e77
commit 960366282f
14 changed files with 377 additions and 1503 deletions

View File

@ -0,0 +1,9 @@
import { Controller, UseGuards } from "@nestjs/common";
import { AuthGuard } from '@server/auth/auth.guard';
import { sportProjectService } from "./sportProject.service";
@Controller('sportProject')
export class sportProjectController {
constructor(private readonly sportProjectService: sportProjectService) {}
//@UseGuards(AuthGuard)
}

View File

@ -0,0 +1,13 @@
import { Module } from '@nestjs/common';
import { StaffModule } from '../staff/staff.module';
import { TrpcService } from '@server/trpc/trpc.service';
import { sportProjectService } from './sportProject.service';
import { sportProjectController } from './sportProject.controller';
import { SportProjectRouter } from './sportProject.router';
@Module({
imports: [StaffModule],
controllers: [sportProjectController],
providers: [sportProjectService,SportProjectRouter,TrpcService],
exports: [sportProjectService,SportProjectRouter],
})
export class SportProjectModule {}

View File

@ -0,0 +1,32 @@
import { Injectable } from "@nestjs/common";
import { TrpcService } from "@server/trpc/trpc.service";
import { sportProjectService } from "./sportProject.service";
import { z, ZodType } from "zod";
import { Prisma } from "@nice/common";
const SportProjectArgsSchema:ZodType<Prisma.SportProjectCreateArgs> = z.any()
const SportProjectUpdateArgsSchema:ZodType<Prisma.SportProjectUpdateArgs> = z.any()
const SportProjectFindManyArgsSchema:ZodType<Prisma.SportProjectFindManyArgs> = z.any()
@Injectable()
export class SportProjectRouter {
constructor(
private readonly trpc: TrpcService,
private readonly sportProjectService: sportProjectService,
) { }
router = this.trpc.router({
create:this.trpc.procedure.input(SportProjectArgsSchema)
.mutation(async ({input})=>{
return this.sportProjectService.create(input)
}),
update:this.trpc.procedure.input(SportProjectUpdateArgsSchema)
.mutation(async ({input})=>{
return this.sportProjectService.update(input)
}),
findMany:this.trpc.procedure.input(SportProjectFindManyArgsSchema)
.query(async ({input})=>{
return this.sportProjectService.findMany(input)
})
})
}

View File

@ -0,0 +1,51 @@
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";
interface AgeRange {
start: number | null;
end: number | null;
label: string;
}
interface ScoreStandard {
ageRanges: AgeRange[];
scoreTable: {
[score: string]: number[];
}
}
@Injectable()
export class sportProjectService extends BaseService<Prisma.SportProjectDelegate> {
constructor() {
super(db,ObjectType.SPORT_PROJECT,true);
}
async create(args: Prisma.SportProjectCreateArgs) {
console.log(args)
const result = await super.create(args)
this.emitDataChanged(CrudOperation.CREATED,result)
return result
}
async update(args:Prisma.SportProjectUpdateArgs){
const result = await super.update(args)
this.emitDataChanged(CrudOperation.UPDATED,result)
return result
}
async findMany(args: Prisma.SportProjectFindManyArgs) {
const result = await super.findMany(args);
return result;
}
private emitDataChanged(operation: CrudOperation, data: any) {
EventBus.emit('dataChanged', {
type:ObjectType.SPORT_STANDARD,
operation,
data,
});
}
}

View File

@ -0,0 +1,9 @@
import { Controller, UseGuards } from "@nestjs/common";
import { AuthGuard } from '@server/auth/auth.guard';
import { SportStandardService } from "./sportStandard.service";
@Controller('sportStandard')
export class SportStandardController {
constructor(private readonly sportStandardService: SportStandardService) {}
//@UseGuards(AuthGuard)
}

View File

@ -0,0 +1,13 @@
import { Module } from '@nestjs/common';
import { StaffModule } from '../staff/staff.module';
import { TrpcService } from '@server/trpc/trpc.service';
import { SportStandardService } from './sportStandard.service';
import { SportStandardController } from './sportStandard.controller';
import { SportStandardRouter } from './sportStandard.router';
@Module({
imports: [StaffModule],
controllers: [SportStandardController],
providers: [SportStandardService,SportStandardRouter,TrpcService],
exports: [SportStandardService,SportStandardRouter],
})
export class SportStandardModule {}

View File

@ -0,0 +1,32 @@
import { Injectable } from "@nestjs/common";
import { TrpcService } from "@server/trpc/trpc.service";
import { SportStandardService } from "./sportStandard.service";
import { z, ZodType } from "zod";
import { Prisma } from "@nice/common";
const SportStandardArgsSchema:ZodType<Prisma.SportStandardCreateArgs> = z.any()
const SportStandardUpdateArgsSchema:ZodType<Prisma.SportStandardUpdateArgs> = z.any()
const SportStandardFindManyArgsSchema:ZodType<Prisma.SportStandardFindManyArgs> = z.any()
@Injectable()
export class SportStandardRouter {
constructor(
private readonly trpc: TrpcService,
private readonly sportStandardService: SportStandardService,
) { }
router = this.trpc.router({
create:this.trpc.procedure.input(SportStandardArgsSchema)
.mutation(async ({input})=>{
return this.sportStandardService.create(input)
}),
update:this.trpc.procedure.input(SportStandardUpdateArgsSchema)
.mutation(async ({input})=>{
return this.sportStandardService.update(input)
}),
findMany:this.trpc.procedure.input(SportStandardFindManyArgsSchema)
.query(async ({input})=>{
return this.sportStandardService.findMany(input)
})
})
}

View File

@ -0,0 +1,108 @@
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";
interface AgeRange {
start: number | null;
end: number | null;
label: string;
}
interface ScoreStandard {
ageRanges: AgeRange[];
scoreTable: {
[score: string]: number[];
}
}
@Injectable()
export class SportStandardService extends BaseService<Prisma.SportStandardDelegate> {
constructor() {
super(db,ObjectType.SPORT_STANDARD,true);
}
async create(args: Prisma.SportStandardCreateArgs) {
console.log(args)
const result = await super.create(args)
this.emitDataChanged(CrudOperation.CREATED,result)
return result
}
async update(args:Prisma.SportStandardUpdateArgs){
const result = await super.update(args)
this.emitDataChanged(CrudOperation.UPDATED,result)
return result
}
async findMany(args: Prisma.SportStandardFindManyArgs) {
const result = await super.findMany(args);
return result;
}
async findUnique(args: { select?: Prisma.SportStandardSelect<DefaultArgs>; include?: Prisma.SportStandardInclude<DefaultArgs>; where: Prisma.SportStandardWhereUniqueInput; }): Promise<{ id: string; projectId: string; gender: boolean; personType: string; ageRanges: Prisma.JsonValue; scoreTable: Prisma.JsonValue; }> {
const result = await super.findUnique(args)
return result
}
private emitDataChanged(operation: CrudOperation, data: any) {
EventBus.emit('dataChanged', {
type:ObjectType.SPORT_STANDARD,
operation,
data,
});
}
public SportScoreCalculator(performance:number,age:number,scoreStandard:ScoreStandard):number{
// 1. 找到对应的年龄段索引
const ageRangeIndex = scoreStandard.ageRanges.findIndex(range => {
const isAboveStart = range.start === null || age > range.start;
const isBelowEnd = range.end === null || age <= range.end;
return isAboveStart && isBelowEnd;
});
if (ageRangeIndex === -1) {
throw new Error('未找到匹配的年龄段');
}
// 2. 查找对应分数
const scores = Object.keys(scoreStandard.scoreTable)
.map(Number)
.sort((a, b) => b - a);
for (const score of scores) {
if (performance >= scoreStandard.scoreTable[score][ageRangeIndex]) {
return score;
}
}
return 0;
}
async getScore(data: {
id:string;
projectId: string;
gender: boolean;
age: number;
performance: number;
personType: string;
}){
const standard = await this.findUnique({
where:{
id:data.id,
projectId: data.projectId,
gender: data.gender,
personType: data.personType
}
})
if (!standard) {
throw new Error('未找到对应的评分标准');
}
return this.SportScoreCalculator(
data.performance,
data.age,
standard.scoreTable as any as ScoreStandard
)
}
}

View File

@ -18,6 +18,8 @@ import { TrainContentModule } from '@server/models/train-content/trainContent.mo
import { ResourceModule } from '@server/models/resource/resource.module'; import { ResourceModule } from '@server/models/resource/resource.module';
import { TrainSituationModule } from '@server/models/train-situation/trainSituation.module'; import { TrainSituationModule } from '@server/models/train-situation/trainSituation.module';
import { DailyTrainModule } from '@server/models/daily-train/dailyTrain.module'; import { DailyTrainModule } from '@server/models/daily-train/dailyTrain.module';
import { SportStandardModule } from '@server/models/sport-standard/sportStandard.module';
import { SportProjectModule } from '@server/models/sport-project/sportProject.module';
@Module({ @Module({
imports: [ imports: [
AuthModule, AuthModule,
@ -28,6 +30,7 @@ import { DailyTrainModule } from '@server/models/daily-train/dailyTrain.module';
TaxonomyModule, TaxonomyModule,
RoleMapModule, RoleMapModule,
TransformModule, TransformModule,
SportStandardModule,
MessageModule, MessageModule,
AppConfigModule, AppConfigModule,
PostModule, PostModule,
@ -36,7 +39,8 @@ import { DailyTrainModule } from '@server/models/daily-train/dailyTrain.module';
ResourceModule, ResourceModule,
TrainContentModule, TrainContentModule,
TrainSituationModule, TrainSituationModule,
DailyTrainModule DailyTrainModule,
SportProjectModule
], ],
controllers: [], controllers: [],
providers: [TrpcService, TrpcRouter, Logger], providers: [TrpcService, TrpcRouter, Logger],

View File

@ -17,7 +17,8 @@ import { ResourceRouter } from '../models/resource/resource.router';
import { TrainContentRouter } from '@server/models/train-content/trainContent.router'; import { TrainContentRouter } from '@server/models/train-content/trainContent.router';
import { TrainSituationRouter } from '@server/models/train-situation/trainSituation.router'; import { TrainSituationRouter } from '@server/models/train-situation/trainSituation.router';
import { DailyTrainRouter } from '@server/models/daily-train/dailyTrain.router'; import { DailyTrainRouter } from '@server/models/daily-train/dailyTrain.router';
import { SportStandardRouter } from '@server/models/sport-standard/sportStandard.router';
import { SportProjectRouter } from '@server/models/sport-project/sportProject.router';
@Injectable() @Injectable()
export class TrpcRouter { export class TrpcRouter {
logger = new Logger(TrpcRouter.name); logger = new Logger(TrpcRouter.name);
@ -37,7 +38,9 @@ export class TrpcRouter {
private readonly resource: ResourceRouter, private readonly resource: ResourceRouter,
private readonly trainContent: TrainContentRouter, private readonly trainContent: TrainContentRouter,
private readonly trainSituation:TrainSituationRouter, private readonly trainSituation:TrainSituationRouter,
private readonly dailyTrain:DailyTrainRouter private readonly dailyTrain:DailyTrainRouter,
private readonly sportStandard:SportStandardRouter,
private readonly sportProject:SportProjectRouter
) {} ) {}
getRouter() { getRouter() {
return; return;
@ -57,7 +60,9 @@ export class TrpcRouter {
resource: this.resource.router, resource: this.resource.router,
trainContent:this.trainContent.router, trainContent:this.trainContent.router,
trainSituation:this.trainSituation.router, trainSituation:this.trainSituation.router,
dailyTrain:this.dailyTrain.router dailyTrain:this.dailyTrain.router,
sportStandard:this.sportStandard.router,
sportProject:this.sportProject.router
}); });
wss: WebSocketServer = undefined; wss: WebSocketServer = undefined;

View File

@ -58,7 +58,6 @@
"framer-motion": "^11.15.0", "framer-motion": "^11.15.0",
"hls.js": "^1.5.18", "hls.js": "^1.5.18",
"idb-keyval": "^6.2.1", "idb-keyval": "^6.2.1",
"mind-elixir": "workspace:^",
"mitt": "^3.0.1", "mitt": "^3.0.1",
"quill": "2.0.3", "quill": "2.0.3",
"react": "18.2.0", "react": "18.2.0",

View File

@ -486,3 +486,34 @@ model TrainPlan {
@@map("train_plan") @@map("train_plan")
} }
model SportProject {
id String @id @default(cuid())
name String @map("name") // 项目名称
type String @map("type") // 项目类型
description String? @map("description") // 项目描述
unit String @map("unit") // 成绩单位(如:秒、米、个)
isAscending Boolean @map("is_ascending") // 是否为升序计分
standards SportStandard[]
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("sport_project")
}
model SportStandard {
id String @id @default(cuid())
projectId String @map("project_id")
project SportProject @relation(fields: [projectId], references: [id])
gender Boolean @map("gender") // true为男false为女
personType String @map("person_type") // 人员类型
ageRanges Json @map("age_ranges") // 年龄段定义
scoreTable Json @map("score_table") // 评分标准表
@@unique([projectId, gender, personType])
@@map("sport_standard")
}

View File

@ -61,7 +61,9 @@ export enum ObjectType {
RESOURCE = "resource", RESOURCE = "resource",
TRAIN_CONTENT = "trainContent", TRAIN_CONTENT = "trainContent",
TRAIN_SITUATION = "trainSituation", TRAIN_SITUATION = "trainSituation",
DAILY_TRAIN = "dailyTrainTime" DAILY_TRAIN = "dailyTrainTime",
SPORT_STANDARD = "sportStandard",
SPORT_PROJECT = "sportProject"
} }
export enum RolePerms { export enum RolePerms {
// Create Permissions 创建权限 // Create Permissions 创建权限
@ -208,4 +210,9 @@ export const LessonTypeLabel = {
export enum TrainContentType { export enum TrainContentType {
SUBJECTS = "科目", SUBJECTS = "科目",
COURSE = "课目" COURSE = "课目"
}
export enum SportStandardType {
STANDARD = "标准",
OTHER = "其他"
} }

File diff suppressed because it is too large Load Diff