training_data/apps/server/src/models/sport-standard/sportStandard.service.ts

159 lines
5.0 KiB
TypeScript
Raw Normal View History

2025-03-25 07:52:33 +08:00
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;
2025-03-25 08:22:17 +08:00
}
interface Record {
2025-03-25 10:46:28 +08:00
[key: number]: number[];
2025-03-25 08:22:17 +08:00
}
2025-03-25 07:52:33 +08:00
interface ScoreStandard {
ageRanges: AgeRange[];
2025-03-25 08:22:17 +08:00
scoreTable: Record;
}
2025-03-25 07:52:33 +08:00
@Injectable()
export class SportStandardService extends BaseService<Prisma.SportStandardDelegate> {
constructor() {
2025-03-25 10:46:28 +08:00
super(db, ObjectType.SPORT_STANDARD, false);
2025-03-25 07:52:33 +08:00
}
async create(args: Prisma.SportStandardCreateArgs) {
console.log(args)
const result = await super.create(args)
2025-03-25 08:22:17 +08:00
this.emitDataChanged(CrudOperation.CREATED, result)
return result
2025-03-25 07:52:33 +08:00
}
2025-03-25 08:22:17 +08:00
async update(args: Prisma.SportStandardUpdateArgs) {
2025-03-25 07:52:33 +08:00
const result = await super.update(args)
2025-03-25 08:22:17 +08:00
this.emitDataChanged(CrudOperation.UPDATED, result)
2025-03-25 07:52:33 +08:00
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', {
2025-03-25 08:22:17 +08:00
type: ObjectType.SPORT_STANDARD,
operation,
data,
});
}
async createStandard(
data: {
projectId: string;
gender: boolean;
personType: string;
ageRanges: AgeRange[];
scoreTable: Record;
},
select?: Prisma.SportStandardSelect<DefaultArgs>,
include?: Prisma.SportStandardInclude<DefaultArgs>
) {
2025-03-25 10:46:28 +08:00
console.log(data)
2025-03-25 08:22:17 +08:00
this.validateAgeRanges(data.ageRanges);
this.validateScoreTable(data.scoreTable, data.ageRanges.length);
2025-03-25 10:46:28 +08:00
const result = await super.create({
2025-03-25 08:22:17 +08:00
data: {
projectId: data.projectId,
gender: data.gender,
personType: data.personType,
ageRanges: JSON.stringify(data.ageRanges),
scoreTable: JSON.stringify(data.scoreTable)
},
select,
include
})
2025-03-25 10:46:28 +08:00
this.emitDataChanged(CrudOperation.CREATED, result)
return result
2025-03-25 08:22:17 +08:00
}
private validateAgeRanges(ranges: AgeRange[]) {
// 检查年龄段是否按顺序排列且无重叠
for (let i = 0; i < ranges.length - 1; i++) {
const current = ranges[i];
const next = ranges[i + 1];
if (current.end !== next.start) {
throw new Error('年龄段必须连续且不重叠');
}
}
}
private validateScoreTable(
scoreTable: Record,
expectedLength: number
) {
Object.values(scoreTable).forEach(standards => {
if (standards.length !== expectedLength) {
throw new Error('分数表的每行数据长度必须与年龄段数量匹配');
}
2025-03-25 07:52:33 +08:00
});
}
2025-03-25 08:22:17 +08:00
public SportScoreCalculator(performance: number, age: number, scoreStandard: ScoreStandard): number {
2025-03-25 07:52:33 +08:00
// 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;
});
2025-03-25 08:22:17 +08:00
2025-03-25 07:52:33 +08:00
if (ageRangeIndex === -1) {
throw new Error('未找到匹配的年龄段');
}
2025-03-25 08:22:17 +08:00
2025-03-25 07:52:33 +08:00
// 2. 查找对应分数
const scores = Object.keys(scoreStandard.scoreTable)
.map(Number)
.sort((a, b) => b - a);
2025-03-25 08:22:17 +08:00
2025-03-25 07:52:33 +08:00
for (const score of scores) {
if (performance >= scoreStandard.scoreTable[score][ageRangeIndex]) {
return score;
}
}
2025-03-25 08:22:17 +08:00
2025-03-25 07:52:33 +08:00
return 0;
}
async getScore(data: {
2025-03-25 08:22:17 +08:00
id: string;
2025-03-25 07:52:33 +08:00
projectId: string;
gender: boolean;
age: number;
performance: number;
personType: string;
2025-03-25 08:22:17 +08:00
}) {
2025-03-25 07:52:33 +08:00
const standard = await this.findUnique({
2025-03-25 08:22:17 +08:00
where: {
id: data.id,
2025-03-25 07:52:33 +08:00
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
)
2025-03-25 08:22:17 +08:00
}
2025-03-25 07:52:33 +08:00
}