rht
This commit is contained in:
parent
656ba75ce7
commit
96952ea0ce
|
@ -7,6 +7,7 @@ import { Prisma } from "@nice/common";
|
||||||
const SportProjectArgsSchema:ZodType<Prisma.SportProjectCreateArgs> = z.any()
|
const SportProjectArgsSchema:ZodType<Prisma.SportProjectCreateArgs> = z.any()
|
||||||
const SportProjectUpdateArgsSchema:ZodType<Prisma.SportProjectUpdateArgs> = z.any()
|
const SportProjectUpdateArgsSchema:ZodType<Prisma.SportProjectUpdateArgs> = z.any()
|
||||||
const SportProjectFindManyArgsSchema:ZodType<Prisma.SportProjectFindManyArgs> = z.any()
|
const SportProjectFindManyArgsSchema:ZodType<Prisma.SportProjectFindManyArgs> = z.any()
|
||||||
|
const SportProjectFindFirstArgsSchema:ZodType<Prisma.SportProjectFindFirstArgs> = z.any()
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SportProjectRouter {
|
export class SportProjectRouter {
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -32,6 +33,10 @@ export class SportProjectRouter {
|
||||||
.mutation(async ({input})=>{
|
.mutation(async ({input})=>{
|
||||||
return this.sportProjectService.softDeleteByIds(input.ids)
|
return this.sportProjectService.softDeleteByIds(input.ids)
|
||||||
}),
|
}),
|
||||||
|
findFirst:this.trpc.procedure.input(SportProjectFindFirstArgsSchema)
|
||||||
|
.query(async ({input})=>{
|
||||||
|
return this.sportProjectService.findFirst(input)
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
|
@ -39,7 +39,10 @@ export class sportProjectService extends BaseService<Prisma.SportProjectDelegate
|
||||||
const result = await super.findMany(args);
|
const result = await super.findMany(args);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
async findFirst(args: Prisma.SportProjectFindFirstArgs) {
|
||||||
|
const result = await super.findFirst(args)
|
||||||
|
return result
|
||||||
|
}
|
||||||
async softDeleteByIds(ids: string[]) {
|
async softDeleteByIds(ids: string[]) {
|
||||||
const result = await super.softDeleteByIds(ids);
|
const result = await super.softDeleteByIds(ids);
|
||||||
this.emitDataChanged(CrudOperation.DELETED,result)
|
this.emitDataChanged(CrudOperation.DELETED,result)
|
||||||
|
|
|
@ -9,6 +9,15 @@ const SportStandardUpdateArgsSchema:ZodType<Prisma.SportStandardUpdateArgs> = z.
|
||||||
const SportStandardFindManyArgsSchema: ZodType<Prisma.SportStandardFindManyArgs> = z.any()
|
const SportStandardFindManyArgsSchema: ZodType<Prisma.SportStandardFindManyArgs> = z.any()
|
||||||
const SportStandardCreateStandardArgsSchema: ZodType<Prisma.SportStandardCreateArgs> = z.any()
|
const SportStandardCreateStandardArgsSchema: ZodType<Prisma.SportStandardCreateArgs> = z.any()
|
||||||
const SportStandardUpdateStandardArgsSchema: ZodType<Prisma.SportStandardUpdateArgs> = z.any()
|
const SportStandardUpdateStandardArgsSchema: ZodType<Prisma.SportStandardUpdateArgs> = z.any()
|
||||||
|
const GetScoreArgsSchema = z.object({
|
||||||
|
projectId: z.string().nonempty(),
|
||||||
|
gender: z.boolean(),
|
||||||
|
age: z.number().min(0),
|
||||||
|
performance: z.number().min(0).or(z.string()),
|
||||||
|
personType: z.string().nonempty(),
|
||||||
|
projectUnit: z.string().nonempty()
|
||||||
|
});
|
||||||
|
|
||||||
interface AgeRange {
|
interface AgeRange {
|
||||||
start: number | null;
|
start: number | null;
|
||||||
end: number | null;
|
end: number | null;
|
||||||
|
@ -57,7 +66,13 @@ export class SportStandardRouter {
|
||||||
scoreTable: input.data.scoreTable as Record
|
scoreTable: input.data.scoreTable as Record
|
||||||
}
|
}
|
||||||
return this.sportStandardService.updateStandard(data)
|
return this.sportStandardService.updateStandard(data)
|
||||||
})
|
}),
|
||||||
|
|
||||||
|
getScore: this.trpc.procedure.input(GetScoreArgsSchema).query(async ({ input }) => {
|
||||||
|
console.log('计算')
|
||||||
|
console.log(input)
|
||||||
|
return this.sportStandardService.getScore(input);
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
|
@ -3,6 +3,7 @@ import { BaseService } from "../base/base.service";
|
||||||
import { db, ObjectType, Prisma, UserProfile } from "@nice/common";
|
import { db, ObjectType, Prisma, UserProfile } from "@nice/common";
|
||||||
import EventBus, { CrudOperation } from "@server/utils/event-bus";
|
import EventBus, { CrudOperation } from "@server/utils/event-bus";
|
||||||
import { DefaultArgs } from "@prisma/client/runtime/library";
|
import { DefaultArgs } from "@prisma/client/runtime/library";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
interface AgeRange {
|
interface AgeRange {
|
||||||
start: number | null;
|
start: number | null;
|
||||||
|
@ -10,13 +11,22 @@ interface AgeRange {
|
||||||
label: string;
|
label: string;
|
||||||
}
|
}
|
||||||
interface Record {
|
interface Record {
|
||||||
[key: number]: number[];
|
[key: number]: (number | string)[];
|
||||||
}
|
}
|
||||||
interface ScoreStandard {
|
interface ScoreStandard {
|
||||||
ageRanges: AgeRange[];
|
ageRanges: AgeRange[];
|
||||||
scoreTable: Record;
|
scoreTable: Record;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const GetScoreArgsSchema = z.object({
|
||||||
|
projectId: z.string().nonempty(),
|
||||||
|
gender: z.boolean(),
|
||||||
|
age: z.number().min(0),
|
||||||
|
performance: z.number().min(0).or(z.string()),
|
||||||
|
personType: z.string().nonempty(),
|
||||||
|
projectUnit: z.string().nonempty()
|
||||||
|
});
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SportStandardService extends BaseService<Prisma.SportStandardDelegate> {
|
export class SportStandardService extends BaseService<Prisma.SportStandardDelegate> {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -126,7 +136,7 @@ export class SportStandardService extends BaseService<Prisma.SportStandardDelega
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
public SportScoreCalculator(performance: number, age: number, scoreStandard: ScoreStandard): number {
|
public SportScoreCalculator(performance: number | string, age: number, scoreStandard: ScoreStandard, projectUnit: string, ): number {
|
||||||
// 1. 找到对应的年龄段索引
|
// 1. 找到对应的年龄段索引
|
||||||
const ageRangeIndex = scoreStandard.ageRanges.findIndex(range => {
|
const ageRangeIndex = scoreStandard.ageRanges.findIndex(range => {
|
||||||
const isAboveStart = range.start === null || age > range.start;
|
const isAboveStart = range.start === null || age > range.start;
|
||||||
|
@ -143,39 +153,65 @@ export class SportStandardService extends BaseService<Prisma.SportStandardDelega
|
||||||
.map(Number)
|
.map(Number)
|
||||||
.sort((a, b) => b - a);
|
.sort((a, b) => b - a);
|
||||||
|
|
||||||
|
const isTimeUnit = projectUnit.includes('time'); // 假设时间单位包含 '时间单位' 字符串
|
||||||
|
|
||||||
for (const score of scores) {
|
for (const score of scores) {
|
||||||
if (performance >= scoreStandard.scoreTable[score][ageRangeIndex]) {
|
const standard = scoreStandard.scoreTable[score.toString()][ageRangeIndex];
|
||||||
|
if (isTimeUnit) {
|
||||||
|
// 此时的performance和standard是时间字符串
|
||||||
|
// 需要将时间字符串转换为秒
|
||||||
|
if (this.timeStringToSeconds(performance) <= this.timeStringToSeconds(standard)) {
|
||||||
return score;
|
return score;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (performance >= standard) {
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getScore(data: {
|
async getScore(data: z.infer<typeof GetScoreArgsSchema>) {
|
||||||
id: string;
|
console.log("传入的参数",data)
|
||||||
projectId: string;
|
|
||||||
gender: boolean;
|
|
||||||
age: number;
|
|
||||||
performance: number;
|
|
||||||
personType: string;
|
|
||||||
}) {
|
|
||||||
const standard = await this.findUnique({
|
const standard = await this.findUnique({
|
||||||
where: {
|
where: {
|
||||||
id: data.id,
|
projectId_gender_personType: { // 使用复合唯一索引
|
||||||
projectId: data.projectId,
|
projectId: data.projectId,
|
||||||
gender: data.gender,
|
gender: data.gender,
|
||||||
personType: data.personType
|
personType: data.personType
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
console.log("找到的评分标准",standard)
|
||||||
if (!standard) {
|
if (!standard) {
|
||||||
throw new Error('未找到对应的评分标准');
|
throw new Error('未找到对应的评分标准');
|
||||||
}
|
}
|
||||||
|
const scoreTable:Record = JSON.parse(String(standard.scoreTable))
|
||||||
|
const ageRanges:AgeRange[] = JSON.parse(String(standard.ageRanges))
|
||||||
|
const scoreStandard:ScoreStandard = {
|
||||||
|
ageRanges,
|
||||||
|
scoreTable
|
||||||
|
}
|
||||||
|
console.log("评分标准",scoreStandard)
|
||||||
return this.SportScoreCalculator(
|
return this.SportScoreCalculator(
|
||||||
data.performance,
|
data.performance,
|
||||||
data.age,
|
data.age,
|
||||||
standard.scoreTable as any as ScoreStandard
|
scoreStandard,
|
||||||
|
data.projectUnit,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
// 将 13:45 格式的字符串转换为秒数
|
||||||
|
private timeStringToSeconds(timeStr) {
|
||||||
|
const [minutes, seconds] = timeStr.split(':').map(Number);
|
||||||
|
return minutes * 60 + seconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将秒数转换为 13:45 格式的字符串
|
||||||
|
private secondsToTimeString(seconds: number) {
|
||||||
|
const minutesPart = Math.floor(seconds / 60);
|
||||||
|
const secondsPart = seconds % 60;
|
||||||
|
return `${String(minutesPart).padStart(2, '0')}:${String(secondsPart).padStart(2, '0')}`;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -95,5 +95,10 @@ export class StaffRouter {
|
||||||
.query(async ({ input }) => {
|
.query(async ({ input }) => {
|
||||||
return await this.staffService.findUnique(input);
|
return await this.staffService.findUnique(input);
|
||||||
}),
|
}),
|
||||||
|
findSportStaffByDept:this.trpc.procedure
|
||||||
|
.input(StaffMethodSchema.findSportStaffByDept)
|
||||||
|
.query(async ({ input }) => {
|
||||||
|
return await this.staffService.findSportStaffByDept(input);
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,64 @@ import { BaseService } from '../base/base.service';
|
||||||
import * as argon2 from 'argon2';
|
import * as argon2 from 'argon2';
|
||||||
import EventBus, { CrudOperation } from '@server/utils/event-bus';
|
import EventBus, { CrudOperation } from '@server/utils/event-bus';
|
||||||
|
|
||||||
|
const StaffSelect = {
|
||||||
|
// 获取 Staff 模型的基础信息
|
||||||
|
id: true,
|
||||||
|
showname: true,
|
||||||
|
username: true,
|
||||||
|
avatar: true,
|
||||||
|
password: true,
|
||||||
|
phoneNumber: true,
|
||||||
|
age: true,
|
||||||
|
sex: true,
|
||||||
|
absent: true,
|
||||||
|
order: true,
|
||||||
|
createdAt: true,
|
||||||
|
updatedAt: true,
|
||||||
|
enabled: true,
|
||||||
|
deletedAt: true,
|
||||||
|
officerId: true,
|
||||||
|
registerToken: true,
|
||||||
|
// 获取关联的 Position 模型的基础信息
|
||||||
|
position: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
type: true,
|
||||||
|
categorize: true,
|
||||||
|
createdAt: true,
|
||||||
|
updatedAt: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 获取关联的 TrainSituation 模型的基础信息
|
||||||
|
trainSituations: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
score: true,
|
||||||
|
value: true,
|
||||||
|
alreadyTrainTime: true,
|
||||||
|
groupId:true,
|
||||||
|
// 获取关联的 TrainContent 模型的基础信息
|
||||||
|
trainContent: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
title: true,
|
||||||
|
type: true,
|
||||||
|
parentId: true,
|
||||||
|
deletedAt: true,
|
||||||
|
createdAt: true,
|
||||||
|
updatedAt: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
department:{
|
||||||
|
select:{
|
||||||
|
id:true,
|
||||||
|
name: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class StaffService extends BaseService<Prisma.StaffDelegate> {
|
export class StaffService extends BaseService<Prisma.StaffDelegate> {
|
||||||
constructor(private readonly departmentService: DepartmentService) {
|
constructor(private readonly departmentService: DepartmentService) {
|
||||||
|
@ -118,7 +176,36 @@ export class StaffService extends BaseService<Prisma.StaffDelegate> {
|
||||||
return staff;
|
return staff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async findSportStaffByDept(data: z.infer<typeof StaffMethodSchema.findSportStaffByDept>) {
|
||||||
|
const { deptId, domainId } = data;
|
||||||
|
let queryResult;
|
||||||
|
|
||||||
|
if (!deptId) {
|
||||||
|
// deptId 为空时执行 res 的请求
|
||||||
|
queryResult = await db.staff.findMany({
|
||||||
|
select: StaffSelect
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// deptId 不为空时执行 result 的请求
|
||||||
|
const childDepts = await this.departmentService.getDescendantIds(deptId, true);
|
||||||
|
queryResult = await db.staff.findMany({
|
||||||
|
where: {
|
||||||
|
deptId: { in: childDepts },
|
||||||
|
domainId,
|
||||||
|
},
|
||||||
|
select: StaffSelect
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选出 trainSituations 中 trainContent 的 type 为 'SPORT' 的记录
|
||||||
|
const filteredResult = queryResult.filter(staff => {
|
||||||
|
return staff.trainSituations.some(trainSituation => {
|
||||||
|
return trainSituation.trainContent.type === 'SPORT';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return filteredResult;
|
||||||
|
}
|
||||||
// /**
|
// /**
|
||||||
// * 根据关键词或ID集合查找员工
|
// * 根据关键词或ID集合查找员工
|
||||||
// * @param data 包含关键词、域ID和ID集合的对象
|
// * @param data 包含关键词、域ID和ID集合的对象
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { Prisma } from "@nice/common";
|
||||||
const TrainContentArgsSchema:ZodType<Prisma.TrainContentCreateArgs> = z.any()
|
const TrainContentArgsSchema:ZodType<Prisma.TrainContentCreateArgs> = z.any()
|
||||||
const TrainContentUpdateArgsSchema:ZodType<Prisma.TrainContentUpdateArgs> = z.any()
|
const TrainContentUpdateArgsSchema:ZodType<Prisma.TrainContentUpdateArgs> = z.any()
|
||||||
const TrainContentFindManyArgsSchema:ZodType<Prisma.TrainContentFindManyArgs> = z.any()
|
const TrainContentFindManyArgsSchema:ZodType<Prisma.TrainContentFindManyArgs> = z.any()
|
||||||
|
const TrainContentFindFirstArgsSchema:ZodType<Prisma.TrainContentFindFirstArgs> = z.any()
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TrainContentRouter {
|
export class TrainContentRouter {
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -26,7 +27,11 @@ export class TrainContentRouter {
|
||||||
findMany:this.trpc.procedure.input(TrainContentFindManyArgsSchema)
|
findMany:this.trpc.procedure.input(TrainContentFindManyArgsSchema)
|
||||||
.query(async ({input})=>{
|
.query(async ({input})=>{
|
||||||
return this.trainContentService.findMany(input)
|
return this.trainContentService.findMany(input)
|
||||||
})
|
}),
|
||||||
|
findFirst:this.trpc.procedure.input(TrainContentFindFirstArgsSchema)
|
||||||
|
.query(async ({input})=>{
|
||||||
|
return this.trainContentService.findFirst(input)
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
|
@ -28,7 +28,10 @@ export class TrainContentService extends BaseService<Prisma.TrainContentDelegate
|
||||||
const result = await super.findMany(args);
|
const result = await super.findMany(args);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
async findFirst(args: Prisma.TrainContentFindFirstArgs) {
|
||||||
|
const result = await super.findFirst(args)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
private emitDataChanged(operation: CrudOperation, data: any) {
|
private emitDataChanged(operation: CrudOperation, data: any) {
|
||||||
EventBus.emit('dataChanged', {
|
EventBus.emit('dataChanged', {
|
||||||
|
|
|
@ -4,9 +4,9 @@ import { StaffModule } from '../staff/staff.module';
|
||||||
import { TrainSituationController } from './trainSituation.controller';
|
import { TrainSituationController } from './trainSituation.controller';
|
||||||
import { TrainSituationRouter } from './trainSituation.router';
|
import { TrainSituationRouter } from './trainSituation.router';
|
||||||
import { TrpcService } from '@server/trpc/trpc.service';
|
import { TrpcService } from '@server/trpc/trpc.service';
|
||||||
|
import { SportStandardModule } from '../sport-standard/sportStandard.module';
|
||||||
@Module({
|
@Module({
|
||||||
imports: [StaffModule],
|
imports: [StaffModule,SportStandardModule],
|
||||||
controllers: [TrainSituationController],
|
controllers: [TrainSituationController],
|
||||||
providers: [TrainSituationService,TrainSituationRouter,TrpcService],
|
providers: [TrainSituationService,TrainSituationRouter,TrpcService],
|
||||||
exports: [TrainSituationService,TrainSituationRouter],
|
exports: [TrainSituationService,TrainSituationRouter],
|
||||||
|
|
|
@ -14,7 +14,6 @@ export class TrainSituationRouter {
|
||||||
private readonly trpc: TrpcService,
|
private readonly trpc: TrpcService,
|
||||||
private readonly trainSituationService: TrainSituationService,
|
private readonly trainSituationService: TrainSituationService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
router = this.trpc.router({
|
router = this.trpc.router({
|
||||||
create: this.trpc.protectProcedure
|
create: this.trpc.protectProcedure
|
||||||
.input(TrainSituationArgsSchema)
|
.input(TrainSituationArgsSchema)
|
||||||
|
@ -39,6 +38,33 @@ export class TrainSituationRouter {
|
||||||
}))
|
}))
|
||||||
.query(async ({ input }) => {
|
.query(async ({ input }) => {
|
||||||
return this.trainSituationService.findManyByDeptId(input)
|
return this.trainSituationService.findManyByDeptId(input)
|
||||||
|
}),
|
||||||
|
createManyTrainSituation: this.trpc.protectProcedure
|
||||||
|
.input(z.array(
|
||||||
|
z.object({
|
||||||
|
staffId: z.string(),
|
||||||
|
trainContentId: z.string(),
|
||||||
|
mustTrainTime: z.number(),
|
||||||
|
alreadyTrainTime: z.number(),
|
||||||
|
value: z.string(),
|
||||||
|
projectUnit: z.string(),
|
||||||
|
personType: z.string(),
|
||||||
|
projectId: z.string(),
|
||||||
|
gender: z.boolean(),
|
||||||
|
age: z.number(),
|
||||||
|
performance: z.number().or(z.string())
|
||||||
|
})
|
||||||
|
))
|
||||||
|
.mutation(async ({ input }) => {
|
||||||
|
console.log(input)
|
||||||
|
return this.trainSituationService.createManyTrainSituation(input)
|
||||||
|
}),
|
||||||
|
deleteSameGroupTrainSituation:this.trpc.protectProcedure
|
||||||
|
.input(z.object({
|
||||||
|
groupId:z.string()
|
||||||
|
}))
|
||||||
|
.mutation(async ({input})=>{
|
||||||
|
return this.trainSituationService.deleteSameGroupTrainSituation(input)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,13 @@ import { db, ObjectType, Prisma, UserProfile } from "@nice/common";
|
||||||
import EventBus, { CrudOperation } from "@server/utils/event-bus";
|
import EventBus, { CrudOperation } from "@server/utils/event-bus";
|
||||||
import { DefaultArgs } from "@prisma/client/runtime/library";
|
import { DefaultArgs } from "@prisma/client/runtime/library";
|
||||||
import { StaffService } from "../staff/staff.service";
|
import { StaffService } from "../staff/staff.service";
|
||||||
|
import { SportStandardService } from "../sport-standard/sportStandard.service";
|
||||||
|
import { uuidv4 } from "lib0/random";
|
||||||
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TrainSituationService extends BaseService<Prisma.TrainSituationDelegate> {
|
export class TrainSituationService extends BaseService<Prisma.TrainSituationDelegate> {
|
||||||
constructor(private readonly staffService:StaffService) {
|
constructor(private readonly staffService:StaffService,private readonly sportStandardService:SportStandardService) {
|
||||||
super(db,ObjectType.TRAIN_SITUATION,false);
|
super(db,ObjectType.TRAIN_SITUATION,false);
|
||||||
}
|
}
|
||||||
// 创建培训情况
|
// 创建培训情况
|
||||||
|
@ -30,14 +32,7 @@ export class TrainSituationService extends BaseService<Prisma.TrainSituationDele
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查找培训情况
|
// 查找培训情况
|
||||||
async findMany(args: Prisma.TrainSituationFindManyArgs): Promise<{
|
async findMany(args: Prisma.TrainSituationFindManyArgs)
|
||||||
id: string;
|
|
||||||
staffId: string;
|
|
||||||
trainContentId: string;
|
|
||||||
mustTrainTime: number;
|
|
||||||
alreadyTrainTime: number;
|
|
||||||
score: number;
|
|
||||||
}[]>
|
|
||||||
{
|
{
|
||||||
const result = await super.findMany(args);
|
const result = await super.findMany(args);
|
||||||
return result;
|
return result;
|
||||||
|
@ -68,6 +63,76 @@ export class TrainSituationService extends BaseService<Prisma.TrainSituationDele
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
//async createDailyTrainTime()
|
//async createDailyTrainTime()
|
||||||
|
async createTrainSituation(args:{
|
||||||
|
staffId?:string,
|
||||||
|
trainContentId?:string,
|
||||||
|
mustTrainTime?:number,
|
||||||
|
alreadyTrainTime?:number,
|
||||||
|
value?:string,
|
||||||
|
|
||||||
|
projectUnit?:string,
|
||||||
|
personType?:string,
|
||||||
|
projectId?:string,
|
||||||
|
gender?:boolean,
|
||||||
|
age?:number,
|
||||||
|
performance?:number|string,
|
||||||
|
},groupId?:string){
|
||||||
|
console.log("传入的参数",args)
|
||||||
|
const score = await this.sportStandardService.getScore({
|
||||||
|
projectId:args.projectId,
|
||||||
|
gender:args.gender,
|
||||||
|
age:args.age,
|
||||||
|
performance:args.performance,
|
||||||
|
personType:args.personType,
|
||||||
|
projectUnit:args.projectUnit
|
||||||
|
})
|
||||||
|
console.log("计算出的分数",score)
|
||||||
|
const data : Prisma.TrainSituationCreateArgs = {
|
||||||
|
data:{
|
||||||
|
staffId:args.staffId,
|
||||||
|
trainContentId:args.trainContentId,
|
||||||
|
mustTrainTime:args.mustTrainTime,
|
||||||
|
alreadyTrainTime:args.alreadyTrainTime,
|
||||||
|
value:args.value,
|
||||||
|
score:score,
|
||||||
|
groupId:groupId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log("创建的数据",data)
|
||||||
|
const result = await super.create(data);
|
||||||
|
this.emitDataChanged(CrudOperation.CREATED, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
async createManyTrainSituation(args:{
|
||||||
|
staffId?:string,
|
||||||
|
trainContentId?:string,
|
||||||
|
mustTrainTime?:number,
|
||||||
|
alreadyTrainTime?:number,
|
||||||
|
value?:string,
|
||||||
|
|
||||||
|
projectUnit?:string,
|
||||||
|
personType?:string,
|
||||||
|
projectId?:string,
|
||||||
|
gender?:boolean,
|
||||||
|
age?:number,
|
||||||
|
performance?:number|string,
|
||||||
|
}[]){
|
||||||
|
console.log("传入的参数",args)
|
||||||
|
const groupId = uuidv4();
|
||||||
|
args.forEach(async (item)=>{
|
||||||
|
await this.createTrainSituation(item,groupId)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
async deleteSameGroupTrainSituation(args:{groupId?:string}){
|
||||||
|
const {groupId} = args
|
||||||
|
const result = await super.deleteMany({
|
||||||
|
where:{
|
||||||
|
groupId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.emitDataChanged(CrudOperation.DELETED,result)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// 发送数据变化事件
|
// 发送数据变化事件
|
||||||
private emitDataChanged(operation: CrudOperation, data: any) {
|
private emitDataChanged(operation: CrudOperation, data: any) {
|
||||||
|
|
|
@ -117,6 +117,25 @@ export class InitService {
|
||||||
this.logger.log('Root account already exists');
|
this.logger.log('Root account already exists');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private async createTrainContent() {
|
||||||
|
this.logger.log('Checking for sport train content');
|
||||||
|
const existingTrainContent = await db.trainContent.findFirst({
|
||||||
|
where: {
|
||||||
|
type: 'SPORTS',
|
||||||
|
title: '体能考核'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!existingTrainContent) {
|
||||||
|
await db.trainContent.create({
|
||||||
|
data: {
|
||||||
|
type: 'SPORTS',
|
||||||
|
title: '体能考核'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.logger.log('Sport train already exists');
|
||||||
|
}
|
||||||
|
}
|
||||||
private async createBucket() {
|
private async createBucket() {
|
||||||
await this.minioService.createBucket('app');
|
await this.minioService.createBucket('app');
|
||||||
}
|
}
|
||||||
|
@ -140,6 +159,7 @@ export class InitService {
|
||||||
await this.createRoot();
|
await this.createRoot();
|
||||||
await this.createOrUpdateTaxonomy();
|
await this.createOrUpdateTaxonomy();
|
||||||
await this.initAppConfigs();
|
await this.initAppConfigs();
|
||||||
|
await this.createTrainContent();
|
||||||
try {
|
try {
|
||||||
this.logger.log('Initialize minio');
|
this.logger.log('Initialize minio');
|
||||||
await this.createBucket();
|
await this.createBucket();
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Form, InputNumber, Modal } from "antd";
|
import { Form, Input, InputNumber, Modal } from "antd";
|
||||||
import { useAssessmentStandardContext } from "./assessment-standard-provider";
|
import { useAssessmentStandardContext } from "./assessment-standard-provider";
|
||||||
export default function AssessmentModal() {
|
export default function AssessmentModal() {
|
||||||
const { isAgeModalVisible, isScoreModalVisible, ageForm, scoreForm, handleAgeOk, handleAgeCancel, handleScoreOk, handleScoreCancel, ageRanges } = useAssessmentStandardContext();
|
const { isAgeModalVisible, isScoreModalVisible, ageForm, scoreForm, handleAgeOk, handleAgeCancel, handleScoreOk, handleScoreCancel, ageRanges } = useAssessmentStandardContext();
|
||||||
|
@ -28,11 +28,11 @@ export default function AssessmentModal() {
|
||||||
>
|
>
|
||||||
<Form form={scoreForm} onFinish={handleScoreOk}>
|
<Form form={scoreForm} onFinish={handleScoreOk}>
|
||||||
<Form.Item name="score" label="分数" rules={[{ required: true }]}>
|
<Form.Item name="score" label="分数" rules={[{ required: true }]}>
|
||||||
<InputNumber min={0} />
|
<Input min={0} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{ageRanges.map((range, index) => (
|
{ageRanges.map((range, index) => (
|
||||||
<Form.Item key={index} name={`standards_${index}`} label={range.label}>
|
<Form.Item key={index} name={`standards_${index}`} label={range.label}>
|
||||||
<InputNumber min={0} />
|
<Input min={0} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
))}
|
))}
|
||||||
</Form>
|
</Form>
|
||||||
|
|
|
@ -15,6 +15,7 @@ interface AssessmentStandardContextType {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
unit: string;
|
unit: string;
|
||||||
|
deletedAt?: string | null;
|
||||||
}[];
|
}[];
|
||||||
sportProjectLoading: boolean;
|
sportProjectLoading: boolean;
|
||||||
ageRanges: { start: number; end: number; label: string; }[];
|
ageRanges: { start: number; end: number; label: string; }[];
|
||||||
|
@ -103,7 +104,8 @@ export function AssessmentStandardProvider({ children }: AssessmentStandardProvi
|
||||||
sportProjectList: sportProjectList?.map((item) => ({
|
sportProjectList: sportProjectList?.map((item) => ({
|
||||||
id: item.id,
|
id: item.id,
|
||||||
name: item.name,
|
name: item.name,
|
||||||
unit: item.unit
|
unit: item.unit,
|
||||||
|
deletedAt:item.deletedAt
|
||||||
})),
|
})),
|
||||||
sportProjectLoading,
|
sportProjectLoading,
|
||||||
ageRanges,
|
ageRanges,
|
||||||
|
|
|
@ -1,20 +1,33 @@
|
||||||
import { Button, Form, Input, Select, Skeleton } from "antd";
|
import { Button, Form, Input, Select, Skeleton } from "antd";
|
||||||
import { useAssessmentStandardContext } from "./assessment-standard-provider";
|
import { useAssessmentStandardContext } from "./assessment-standard-provider";
|
||||||
import { useSport } from "@nice/client";
|
import { api, useSport } from "@nice/client";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
|
import create from "@ant-design/icons/lib/components/IconFont";
|
||||||
|
|
||||||
export default function SportCreateContent() {
|
export default function SportCreateContent() {
|
||||||
const { form, sportProjectList, sportProjectLoading } = useAssessmentStandardContext();
|
const { form, sportProjectList, sportProjectLoading } = useAssessmentStandardContext();
|
||||||
const { createSportProject, softDeleteByIds } = useSport();
|
const { createSportProject, softDeleteByIds } = useSport();
|
||||||
|
const { data: fatherTrainContent } = api.trainContent.findFirst.useQuery({
|
||||||
|
where: {
|
||||||
|
type: "SPORTS",
|
||||||
|
title: "体能考核"
|
||||||
|
}
|
||||||
|
})
|
||||||
const handleCreateProject = async () => {
|
const handleCreateProject = async () => {
|
||||||
console.log(form.getFieldsValue().createProjectName)
|
|
||||||
if (form.getFieldsValue().createProjectName && form.getFieldsValue().unit) {
|
if (form.getFieldsValue().createProjectName && form.getFieldsValue().unit) {
|
||||||
await createSportProject.mutateAsync({
|
await createSportProject.mutateAsync({
|
||||||
data: {
|
data: {
|
||||||
name: form.getFieldsValue().createProjectName,
|
name: form.getFieldsValue().createProjectName,
|
||||||
type: "sport",
|
type: "sport",
|
||||||
unit: form.getFieldsValue().unit,
|
unit: form.getFieldsValue().unit,
|
||||||
isAscending: true
|
isAscending: true,
|
||||||
|
trainContent: {
|
||||||
|
create: {
|
||||||
|
title: form.getFieldsValue().createProjectName,
|
||||||
|
type: "SPORT",
|
||||||
|
parentId: fatherTrainContent?.id
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} as any)
|
} as any)
|
||||||
toast.success("创建项目成功")
|
toast.success("创建项目成功")
|
||||||
|
@ -52,7 +65,7 @@ export default function SportCreateContent() {
|
||||||
{sportProjectLoading ?
|
{sportProjectLoading ?
|
||||||
<Skeleton></Skeleton> :
|
<Skeleton></Skeleton> :
|
||||||
<div className='w-1/3 my-3 max-h-48 overflow-y-auto'>
|
<div className='w-1/3 my-3 max-h-48 overflow-y-auto'>
|
||||||
{sportProjectList?.map((item) => (
|
{sportProjectList?.filter(item=>item.deletedAt === null)?.map((item) => (
|
||||||
<div key={item.id} className='w-full flex justify-between p-4 mt-2 bg-white rounded-md'>
|
<div key={item.id} className='w-full flex justify-between p-4 mt-2 bg-white rounded-md'>
|
||||||
<div className='font-bold'>{item.name}({item.unit})</div>
|
<div className='font-bold'>{item.name}({item.unit})</div>
|
||||||
<span className='text-red-500 cursor-pointer' onClick={() => handleDeleteProject(item.id)}>删除</span>
|
<span className='text-red-500 cursor-pointer' onClick={() => handleDeleteProject(item.id)}>删除</span>
|
||||||
|
|
|
@ -114,7 +114,6 @@ export default function StandardCreateContent() {
|
||||||
}
|
}
|
||||||
}, [data])
|
}, [data])
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form form={form} layout="vertical">
|
<Form form={form} layout="vertical">
|
||||||
|
|
||||||
|
@ -123,7 +122,7 @@ export default function StandardCreateContent() {
|
||||||
<Select
|
<Select
|
||||||
style={{ width: 200 }}
|
style={{ width: 200 }}
|
||||||
placeholder="选择考核项目"
|
placeholder="选择考核项目"
|
||||||
options={sportProjectList?.map((item) => ({ value: item.id, label: `${item.name}(${item.unit})` })) || []}
|
options={sportProjectList?.filter(item=>item.deletedAt === null)?.map((item) => ({ value: item.id, label: `${item.name}(${item.unit})` })) || []}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
|
|
@ -1,200 +1,54 @@
|
||||||
import { Button, Select, Table, Modal, Form, Input, InputNumber, Upload, message } from "antd";
|
import { Button, Table, Modal, Form, Upload, Skeleton } from "antd";
|
||||||
import { MagnifyingGlassIcon, ArrowUpTrayIcon, ArrowDownTrayIcon } from "@heroicons/react/24/outline";
|
import { useEffect, useState,} from "react";
|
||||||
import { useEffect, useState, useCallback, useContext } from "react";
|
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import React from "react";
|
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { useMainContext } from "../layout/MainProvider";
|
|
||||||
import { EditableRow, EditableContext, EditableCell } from '../sport/context/EditableContext';
|
|
||||||
import * as XLSX from 'xlsx';
|
import * as XLSX from 'xlsx';
|
||||||
import { UploadOutlined, DownloadOutlined } from '@ant-design/icons';
|
import { UploadOutlined, DownloadOutlined } from '@ant-design/icons';
|
||||||
|
import { useSportPageContext } from "./sportPageProvider";
|
||||||
|
import SportPageModal from "./sportPageModal";
|
||||||
|
import { api, useTrainSituation } from "@nice/client";
|
||||||
|
|
||||||
export default function SportPage() {
|
export default function SportPage() {
|
||||||
const { form, setVisible, searchValue, setSearchValue } = useMainContext();
|
const [sportsData, setSportsData] = useState([]);
|
||||||
const { editingRecord, setEditingRecord } = useMainContext();
|
const { sportProjectList, handlNewScoreOpen, staffsWithScore, staffsWithScoreLoading } = useSportPageContext()
|
||||||
// 模拟数据,实际使用时应替换为API调用
|
const {deleteSameGroupTrainSituation} = useTrainSituation()
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
const [sportsData, setSportsData] = useState([
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
name: "张三",
|
|
||||||
gender: "男",
|
|
||||||
age: 25,
|
|
||||||
unit: "信息部",
|
|
||||||
threeKm: "85",
|
|
||||||
pullUp: 72,
|
|
||||||
shuttle: "65",
|
|
||||||
sitUp: 90,
|
|
||||||
bodyType: "标准",
|
|
||||||
totalScore: 85
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
name: "李四",
|
|
||||||
gender: "女",
|
|
||||||
age: 22,
|
|
||||||
unit: "市场部",
|
|
||||||
threeKm: "79",
|
|
||||||
pullUp: 58,
|
|
||||||
shuttle: "81",
|
|
||||||
sitUp: 63,
|
|
||||||
bodyType: "偏瘦",
|
|
||||||
totalScore: 78
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
name: "王五",
|
|
||||||
gender: "男",
|
|
||||||
age: 28,
|
|
||||||
unit: "技术部",
|
|
||||||
threeKm: "92",
|
|
||||||
pullUp: 85,
|
|
||||||
shuttle: "77",
|
|
||||||
sitUp: 88,
|
|
||||||
bodyType: "标准",
|
|
||||||
totalScore: 90
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
name: "赵六",
|
|
||||||
gender: "女",
|
|
||||||
age: 24,
|
|
||||||
unit: "人力资源部",
|
|
||||||
threeKm: "75",
|
|
||||||
pullUp: 56,
|
|
||||||
shuttle: "71",
|
|
||||||
sitUp: 67,
|
|
||||||
bodyType: "偏瘦",
|
|
||||||
totalScore: 75
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
name: "钱七",
|
|
||||||
gender: "男",
|
|
||||||
age: 30,
|
|
||||||
unit: "财务部",
|
|
||||||
threeKm: "68",
|
|
||||||
pullUp: 77,
|
|
||||||
shuttle: "59",
|
|
||||||
sitUp: 82,
|
|
||||||
bodyType: "偏胖",
|
|
||||||
totalScore: 82
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 6,
|
|
||||||
name: "孙八",
|
|
||||||
gender: "男",
|
|
||||||
age: 26,
|
|
||||||
unit: "销售部",
|
|
||||||
threeKm: "93",
|
|
||||||
pullUp: 88,
|
|
||||||
shuttle: "84",
|
|
||||||
sitUp: 95,
|
|
||||||
bodyType: "标准",
|
|
||||||
totalScore: 92
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 7,
|
|
||||||
name: "周九",
|
|
||||||
gender: "女",
|
|
||||||
age: 23,
|
|
||||||
unit: "客服部",
|
|
||||||
threeKm: "73",
|
|
||||||
pullUp: 60,
|
|
||||||
shuttle: "65",
|
|
||||||
sitUp: 75,
|
|
||||||
bodyType: "标准",
|
|
||||||
totalScore: 79
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 8,
|
|
||||||
name: "吴十",
|
|
||||||
gender: "男",
|
|
||||||
age: 32,
|
|
||||||
unit: "研发部",
|
|
||||||
threeKm: "82",
|
|
||||||
pullUp: 70,
|
|
||||||
shuttle: "68",
|
|
||||||
sitUp: 79,
|
|
||||||
bodyType: "偏胖",
|
|
||||||
totalScore: 80
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 9,
|
|
||||||
name: "郑十一",
|
|
||||||
gender: "女",
|
|
||||||
age: 27,
|
|
||||||
unit: "市场营销部",
|
|
||||||
threeKm: "62",
|
|
||||||
pullUp: 53,
|
|
||||||
shuttle: "69",
|
|
||||||
sitUp: 71,
|
|
||||||
bodyType: "偏瘦",
|
|
||||||
totalScore: 76
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 10,
|
|
||||||
name: "刘十二",
|
|
||||||
gender: "男",
|
|
||||||
age: 29,
|
|
||||||
unit: "产品部",
|
|
||||||
threeKm: "87",
|
|
||||||
pullUp: 82,
|
|
||||||
shuttle: "78",
|
|
||||||
sitUp: 86,
|
|
||||||
bodyType: "标准",
|
|
||||||
totalScore: 88
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
// 新增搜索功能
|
|
||||||
const filteredData = sportsData.filter(item =>
|
|
||||||
item.name.toLowerCase().includes(searchValue.toLowerCase()) ||
|
|
||||||
item.unit.toLowerCase().includes(searchValue.toLowerCase())
|
|
||||||
);
|
|
||||||
const handleNew = () => {
|
|
||||||
form.resetFields();
|
|
||||||
setEditingRecord(null);
|
|
||||||
setVisible(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 计算总成绩的函数
|
|
||||||
const calculateTotalScore = (record) => {
|
|
||||||
// 确保所有值都转为数字
|
|
||||||
const threeKmScore = parseInt(record.threeKm, 10) || 0;
|
|
||||||
const pullUpScore = parseInt(record.pullUp, 10) || 0;
|
|
||||||
const shuttleScore = parseInt(record.shuttle, 10) || 0;
|
|
||||||
const sitUpScore = parseInt(record.sitUp, 10) || 0;
|
|
||||||
|
|
||||||
// 计算总分
|
|
||||||
return threeKmScore + pullUpScore + shuttleScore + sitUpScore;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 初始化时计算所有记录的总成绩
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const updatedData = sportsData.map(record => ({
|
if (!staffsWithScore) return;
|
||||||
...record,
|
const newSportsData = []
|
||||||
totalScore: calculateTotalScore(record)
|
staffsWithScore.forEach(item => {
|
||||||
}));
|
const groupedTrainSituations = {};
|
||||||
setSportsData(updatedData);
|
item.trainSituations.forEach(train => {
|
||||||
}, []);
|
if(train.groupId === null) return
|
||||||
|
const groupId = train.groupId;
|
||||||
const handleSave = (row) => {
|
if (!groupedTrainSituations[groupId]) {
|
||||||
const newData = [...sportsData];
|
groupedTrainSituations[groupId] = {
|
||||||
const index = newData.findIndex(item => row.id === item.id);
|
totalScore: 0,
|
||||||
const item = newData[index];
|
trainScore: {},
|
||||||
|
situations: []
|
||||||
// 创建更新后的记录
|
|
||||||
const updatedRecord = { ...item, ...row };
|
|
||||||
|
|
||||||
// 重新计算总成绩
|
|
||||||
updatedRecord.totalScore = calculateTotalScore(updatedRecord);
|
|
||||||
|
|
||||||
// 更新数据
|
|
||||||
newData.splice(index, 1, updatedRecord);
|
|
||||||
setSportsData(newData);
|
|
||||||
toast.success("保存成功");
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
groupedTrainSituations[groupId].totalScore += train.score;
|
||||||
|
groupedTrainSituations[groupId].trainScore[train.trainContent.title] = `${train.score}分(${train.value})`;
|
||||||
|
groupedTrainSituations[groupId].situations.push(train);
|
||||||
|
console.log(groupedTrainSituations[groupId])
|
||||||
|
newSportsData.push({
|
||||||
|
id: item.id,
|
||||||
|
name: item.username,
|
||||||
|
gender: item.sex ? "男" : "女",
|
||||||
|
bodyType: "标准",
|
||||||
|
age: item.age,
|
||||||
|
unit: item.department?.name,
|
||||||
|
situationIds: groupedTrainSituations[groupId].situations.map(train => train.id),
|
||||||
|
totalScore:groupedTrainSituations[groupId].totalScore,
|
||||||
|
...groupedTrainSituations[groupId].trainScore,
|
||||||
|
groupId
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
console.log(newSportsData)
|
||||||
|
setSportsData(newSportsData);
|
||||||
|
}, [staffsWithScore])
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: "姓名",
|
title: "姓名",
|
||||||
|
@ -216,30 +70,12 @@ export default function SportPage() {
|
||||||
dataIndex: "unit",
|
dataIndex: "unit",
|
||||||
key: "unit",
|
key: "unit",
|
||||||
},
|
},
|
||||||
{
|
...sportProjectList?.filter(item=>item.deletedAt === null).map((item) => ({
|
||||||
title: "三公里",
|
title: item.name,
|
||||||
dataIndex: "threeKm",
|
dataIndex: item.name,
|
||||||
key: "threeKm",
|
key: item.name,
|
||||||
editable: true,
|
editable: true,
|
||||||
},
|
})),
|
||||||
{
|
|
||||||
title: "单杠",
|
|
||||||
dataIndex: "pullUp",
|
|
||||||
key: "pullUp",
|
|
||||||
editable: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "30x2折返跑",
|
|
||||||
dataIndex: "shuttle",
|
|
||||||
key: "shuttle",
|
|
||||||
editable: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "仰卧卷腹",
|
|
||||||
dataIndex: "sitUp",
|
|
||||||
key: "sitUp",
|
|
||||||
editable: true,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: "BMI",
|
title: "BMI",
|
||||||
dataIndex: "bodyType",
|
dataIndex: "bodyType",
|
||||||
|
@ -252,58 +88,22 @@ export default function SportPage() {
|
||||||
key: "totalScore",
|
key: "totalScore",
|
||||||
editable: true,
|
editable: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
title: "操作",
|
title: "操作",
|
||||||
key: "action",
|
key: "action",
|
||||||
render: (_, record) => (
|
render: (_, record) => (
|
||||||
<div className="flex space-x-2">
|
<div className="flex space-x-2">
|
||||||
<Button
|
<Button type="primary" key={record.groupId} onClick={() => handleEdit(record)}>编辑</Button>
|
||||||
type="primary"
|
<Button danger onClick={() => handleDelete(record)}>删除</Button>
|
||||||
key={record.id}
|
|
||||||
onClick={() => handleEdit(record)}
|
|
||||||
>
|
|
||||||
编辑
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
danger
|
|
||||||
onClick={() => handleDelete(record.id)}
|
|
||||||
>
|
|
||||||
删除
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const mergedColumns = columns.map(col => {
|
|
||||||
if (!col.editable) {
|
|
||||||
return col;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...col,
|
|
||||||
onCell: record => ({
|
|
||||||
record,
|
|
||||||
editable: col.editable,
|
|
||||||
dataIndex: col.dataIndex,
|
|
||||||
title: col.title,
|
|
||||||
handleSave,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (editingRecord) {
|
|
||||||
form.setFieldsValue(editingRecord);
|
|
||||||
}
|
|
||||||
}, [editingRecord, form]);
|
|
||||||
|
|
||||||
const handleEdit = (record) => {
|
const handleEdit = (record) => {
|
||||||
setEditingRecord(record);
|
|
||||||
form.setFieldsValue(record);
|
|
||||||
setVisible(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDelete = (id) => {
|
};
|
||||||
|
const handleDelete = (record) => {
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: '确认删除',
|
title: '确认删除',
|
||||||
content: '确定要删除该记录吗?',
|
content: '确定要删除该记录吗?',
|
||||||
|
@ -312,7 +112,12 @@ export default function SportPage() {
|
||||||
onOk: async () => {
|
onOk: async () => {
|
||||||
try {
|
try {
|
||||||
// 模拟删除操作
|
// 模拟删除操作
|
||||||
setSportsData(sportsData.filter(item => item.id !== id));
|
console.log(record)
|
||||||
|
await deleteSameGroupTrainSituation.mutateAsync(
|
||||||
|
{
|
||||||
|
groupId:record.groupId
|
||||||
|
}
|
||||||
|
)
|
||||||
toast.success("删除成功");
|
toast.success("删除成功");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('删除记录时出错:', error);
|
console.error('删除记录时出错:', error);
|
||||||
|
@ -321,14 +126,6 @@ export default function SportPage() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const components = {
|
|
||||||
body: {
|
|
||||||
row: EditableRow,
|
|
||||||
cell: EditableCell,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// 导出成绩为Excel
|
// 导出成绩为Excel
|
||||||
const handleExport = () => {
|
const handleExport = () => {
|
||||||
// 创建工作簿
|
// 创建工作簿
|
||||||
|
@ -386,19 +183,12 @@ export default function SportPage() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-2 min-h-screen bg-gradient-to-br">
|
<div className="p-2 min-h-screen bg-gradient-to-br">
|
||||||
|
{/* {JSON.stringify(staffsWithScore)} */}
|
||||||
<Form>
|
<Form>
|
||||||
<div className="p-4 h-full flex flex-col">
|
<div className="p-4 h-full flex flex-col">
|
||||||
<div className="max-w-full mx-auto flex-1 flex flex-col">
|
<div className="max-w-full mx-auto flex-1 flex flex-col">
|
||||||
<div className="flex justify-between mb-4 space-x-4 items-center">
|
<div className="flex justify-between mb-4 space-x-4 items-center">
|
||||||
<div className="text-2xl">成绩总览</div>
|
<div className="text-2xl">成绩总览</div>
|
||||||
<div className="relative w-1/3">
|
|
||||||
<Input
|
|
||||||
placeholder="输入姓名搜索"
|
|
||||||
onChange={(e) => setSearchValue(e.target.value)}
|
|
||||||
className="pl-10 w-full border"
|
|
||||||
/>
|
|
||||||
<MagnifyingGlassIcon className="absolute left-3 top-1/2 transform -translate-y-1/2 h-5 w-5 " />
|
|
||||||
</div>
|
|
||||||
<div className="flex space-x-2">
|
<div className="flex space-x-2">
|
||||||
<Upload
|
<Upload
|
||||||
beforeUpload={handleImport}
|
beforeUpload={handleImport}
|
||||||
|
@ -415,7 +205,7 @@ export default function SportPage() {
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={handleNew}
|
onClick={handlNewScoreOpen}
|
||||||
className="font-bold py-2 px-4 rounded"
|
className="font-bold py-2 px-4 rounded"
|
||||||
>
|
>
|
||||||
新建成绩
|
新建成绩
|
||||||
|
@ -423,14 +213,13 @@ export default function SportPage() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isLoading ? (
|
{staffsWithScoreLoading ? (
|
||||||
<div>加载中...</div>
|
<Skeleton></Skeleton>
|
||||||
) : (
|
) : (
|
||||||
<Table
|
<Table
|
||||||
components={components}
|
|
||||||
rowClassName={() => 'editable-row'}
|
rowClassName={() => 'editable-row'}
|
||||||
columns={mergedColumns}
|
columns={columns}
|
||||||
dataSource={filteredData}
|
dataSource={sportsData}
|
||||||
tableLayout="fixed"
|
tableLayout="fixed"
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
pagination={{
|
pagination={{
|
||||||
|
@ -443,6 +232,7 @@ export default function SportPage() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
|
<SportPageModal />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
import { Button, Form, Input, InputNumber, Modal, Select } from "antd";
|
||||||
|
import { useSportPageContext } from "./sportPageProvider";
|
||||||
|
import { api, useTrainSituation } from "@nice/client";
|
||||||
|
import toast from "react-hot-toast";
|
||||||
|
|
||||||
|
export default function SportPageModal() {
|
||||||
|
const { newScoreForm, isNewScoreModalVisible, handleNewScoreCancel, sportProjectList, staffs, staffsLoading } = useSportPageContext()
|
||||||
|
const { createManyTrainSituation } = useTrainSituation()
|
||||||
|
// 修改后的提交处理逻辑
|
||||||
|
const handleNewScoreOk = async () => {
|
||||||
|
const userId = newScoreForm.getFieldValue("user");
|
||||||
|
if (!userId) {
|
||||||
|
console.error("未选择人员");
|
||||||
|
toast.error('请选择人员');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const userMsg = staffs?.find((item) => item.id === userId);
|
||||||
|
const createTrainSituationMsg = sportProjectList?.filter(item=>item.deletedAt === null).map((item) => {
|
||||||
|
const performanceValue = newScoreForm.getFieldValue(['sports', item.id, 'score']);
|
||||||
|
if (!performanceValue) {
|
||||||
|
console.error(`未输入 ${item.name} 的成绩`);
|
||||||
|
toast.error(`请输入 ${item.name} 的成绩`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 处理数值类型转换
|
||||||
|
const parsedPerformance = item.unit.includes('time')
|
||||||
|
? performanceValue // 保持时间字符串
|
||||||
|
: Number(performanceValue);
|
||||||
|
console.log('解析后的成绩:', parsedPerformance);
|
||||||
|
return {
|
||||||
|
staffId: userId,
|
||||||
|
trainContentId: item.trainContentId,
|
||||||
|
mustTrainTime: 0.0,
|
||||||
|
alreadyTrainTime: 0.0,
|
||||||
|
value: String(parsedPerformance),
|
||||||
|
projectId: item.id,
|
||||||
|
gender: userMsg?.sex ?? false, // 提供默认值
|
||||||
|
age: userMsg?.age ?? 0, // 提供默认值
|
||||||
|
performance: parsedPerformance,
|
||||||
|
personType: userMsg?.position?.categorize || "OFFICER",
|
||||||
|
projectUnit: item.unit
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await createManyTrainSituation.mutateAsync([...createTrainSituationMsg])
|
||||||
|
|
||||||
|
console.log("提交成功", createTrainSituationMsg);
|
||||||
|
toast.success('成绩提交成功');
|
||||||
|
handleNewScoreCancel();
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
title="添加考核成绩"
|
||||||
|
onOk={newScoreForm.submit}
|
||||||
|
visible={isNewScoreModalVisible}
|
||||||
|
onCancel={handleNewScoreCancel}
|
||||||
|
>
|
||||||
|
<Form
|
||||||
|
form={newScoreForm}
|
||||||
|
name="dynamic_form"
|
||||||
|
onFinish={handleNewScoreOk}
|
||||||
|
className="p-4 space-y-4"
|
||||||
|
>
|
||||||
|
<Form.Item
|
||||||
|
name="user"
|
||||||
|
label="选择人员"
|
||||||
|
rules={[{ required: true, message: '请选择人员!' }]}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
placeholder="选择人员"
|
||||||
|
options={staffsLoading ? [] : staffs?.map((item) => ({
|
||||||
|
label: item.username,
|
||||||
|
value: item.id
|
||||||
|
})) || []}
|
||||||
|
>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
{sportProjectList?.filter(item=>item.deletedAt === null).map((field) => (
|
||||||
|
<div key={field.id} className="flex w-full space-x-4">
|
||||||
|
<Form.Item
|
||||||
|
label={`${field.name}(${field.unit})`}
|
||||||
|
name={['sports', field.id, 'score']}
|
||||||
|
rules={[{ required: true, message: '请输入成绩!' }]}
|
||||||
|
>
|
||||||
|
<Input className="w-full" placeholder="请输入成绩" />
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
import React, {
|
||||||
|
createContext,
|
||||||
|
ReactNode,
|
||||||
|
useContext,
|
||||||
|
useEffect,
|
||||||
|
useState,
|
||||||
|
} from "react";
|
||||||
|
import { api } from "@nice/client";
|
||||||
|
import { Form, FormInstance } from "antd";
|
||||||
|
import { useAuth } from "@web/src/providers/auth-provider";
|
||||||
|
import { RolePerms, UserProfile } from "@nice/common";
|
||||||
|
interface SportPageContextType {
|
||||||
|
sportProjectList: {
|
||||||
|
id: string,
|
||||||
|
name: string,
|
||||||
|
unit: string,
|
||||||
|
trainContentId:string,
|
||||||
|
deletedAt?: string | null
|
||||||
|
}[],
|
||||||
|
newScoreForm: FormInstance,
|
||||||
|
isNewScoreModalVisible: boolean,
|
||||||
|
staffsWithScoreLoading:boolean,
|
||||||
|
handleNewScoreCancel: () => void,
|
||||||
|
handlNewScoreOpen: () => void,
|
||||||
|
staffs: UserProfile[] | null,
|
||||||
|
staffsLoading: boolean
|
||||||
|
staffsWithScore: any[] | null,
|
||||||
|
}
|
||||||
|
|
||||||
|
const SportPageContext = createContext<SportPageContextType | null>(null);
|
||||||
|
interface SportPageProviderProps {
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SportPageProvider({ children }: SportPageProviderProps) {
|
||||||
|
const { data: sportProjectList, isLoading: sportProjectLoading } = api.sportProject.findMany.useQuery()
|
||||||
|
const [newScoreForm] = Form.useForm()
|
||||||
|
const [isNewScoreModalVisible, setIsNewScoreModalVisible] = useState(false)
|
||||||
|
const [isUpdateScoreModalVisble,setIsUpdateScoreModalVisible] = useState(false)
|
||||||
|
const handleNewScoreCancel = () => {
|
||||||
|
setIsNewScoreModalVisible(false)
|
||||||
|
}
|
||||||
|
const handlNewScoreOpen = () => {
|
||||||
|
newScoreForm.resetFields()
|
||||||
|
setIsNewScoreModalVisible(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const { user, isAuthenticated, hasSomePermissions } = useAuth()
|
||||||
|
// 获取当前员工的单位下的所有staff的记录
|
||||||
|
const { data: staffs, isLoading: staffsLoading } = isAuthenticated ?
|
||||||
|
(hasSomePermissions(RolePerms.MANAGE_ANY_STAFF, RolePerms.MANAGE_DOM_STAFF) ?
|
||||||
|
api.staff.findMany.useQuery() :
|
||||||
|
api.staff.findByDept.useQuery({
|
||||||
|
deptId: user.deptId
|
||||||
|
})
|
||||||
|
)
|
||||||
|
: { data: null, isLoading: false }
|
||||||
|
// 获取当前有体育成绩的员工的记录
|
||||||
|
const {data:staffsWithScore,isLoading:staffsWithScoreLoading} = isAuthenticated ?
|
||||||
|
api.staff.findSportStaffByDept.useQuery({deptId:user.deptId})
|
||||||
|
: { data: null, isLoading: false }
|
||||||
|
return (
|
||||||
|
<SportPageContext.Provider
|
||||||
|
value={{
|
||||||
|
sportProjectList: sportProjectList?.map((item) => ({
|
||||||
|
id: item.id,
|
||||||
|
name: item.name,
|
||||||
|
unit: item.unit,
|
||||||
|
trainContentId:item.trainContentId,
|
||||||
|
deletedAt:item.deletedAt,
|
||||||
|
})) || [],
|
||||||
|
newScoreForm,
|
||||||
|
isNewScoreModalVisible,
|
||||||
|
staffsWithScore,
|
||||||
|
handlNewScoreOpen,
|
||||||
|
handleNewScoreCancel,
|
||||||
|
staffs: staffs as any as UserProfile[],
|
||||||
|
staffsLoading,
|
||||||
|
staffsWithScoreLoading
|
||||||
|
}}>
|
||||||
|
{children}
|
||||||
|
</SportPageContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
export const useSportPageContext = () => {
|
||||||
|
const context = useContext(SportPageContext);
|
||||||
|
if (!context) {
|
||||||
|
throw new Error("useSportPageContext must be used within SportPageProvider");
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
};
|
|
@ -0,0 +1,41 @@
|
||||||
|
import { Button, Form, Input, InputNumber, Modal, Select } from "antd";
|
||||||
|
import { useSportPageContext } from "./sportPageProvider";
|
||||||
|
import { api } from "@nice/client";
|
||||||
|
import toast from "react-hot-toast";
|
||||||
|
|
||||||
|
export default function SportPageModal() {
|
||||||
|
const { newScoreForm, isNewScoreModalVisible, handleNewScoreCancel, sportProjectList, staffs, staffsLoading } = useSportPageContext()
|
||||||
|
const createManyTrainSituation = api.trainSituation.createManyTrainSituation.useMutation()
|
||||||
|
// 修改后的提交处理逻辑
|
||||||
|
const handleUpdateScoreOk = async () => {
|
||||||
|
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
title="更改考核成绩"
|
||||||
|
onOk={newScoreForm.submit}
|
||||||
|
visible={isNewScoreModalVisible}
|
||||||
|
onCancel={handleNewScoreCancel}
|
||||||
|
>
|
||||||
|
<Form
|
||||||
|
form={newScoreForm}
|
||||||
|
name="dynamic_form"
|
||||||
|
onFinish={handleUpdateScoreOk}
|
||||||
|
className="p-4 space-y-4"
|
||||||
|
>
|
||||||
|
{sportProjectList.map((field) => (
|
||||||
|
<div key={field.id} className="flex w-full space-x-4">
|
||||||
|
<Form.Item
|
||||||
|
label={`${field.name}(${field.unit})`}
|
||||||
|
name={['sports', field.id, 'score']}
|
||||||
|
rules={[{ required: true, message: '请输入成绩!' }]}
|
||||||
|
>
|
||||||
|
<Input className="w-full" placeholder="请输入成绩" />
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import WeekPlanPage from "../app/main/plan/weekplan/page";
|
||||||
import AdminLayout from "../components/layout/admin/AdminLayout";
|
import AdminLayout from "../components/layout/admin/AdminLayout";
|
||||||
import { adminRoute } from "./admin-route";
|
import { adminRoute } from "./admin-route";
|
||||||
import SportPage from "../app/main/sport/page";
|
import SportPage from "../app/main/sport/page";
|
||||||
|
import { SportPageProvider } from "../app/main/sport/sportPageProvider";
|
||||||
interface CustomIndexRouteObject extends IndexRouteObject {
|
interface CustomIndexRouteObject extends IndexRouteObject {
|
||||||
name?: string;
|
name?: string;
|
||||||
breadcrumb?: string;
|
breadcrumb?: string;
|
||||||
|
@ -88,7 +89,9 @@ export const routes: CustomRouteObject[] = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path:"sportsassessment",
|
path:"sportsassessment",
|
||||||
element:<SportPage></SportPage>
|
element:<SportPageProvider>
|
||||||
|
<SportPage></SportPage>
|
||||||
|
</SportPageProvider>
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,7 +2,6 @@ import { getQueryKey } from "@trpc/react-query";
|
||||||
import { api } from "../trpc"; // Adjust path as necessary
|
import { api } from "../trpc"; // Adjust path as necessary
|
||||||
import { useQueryClient } from "@tanstack/react-query";
|
import { useQueryClient } from "@tanstack/react-query";
|
||||||
import { ObjectType, Staff } from "@nice/common";
|
import { ObjectType, Staff } from "@nice/common";
|
||||||
import { findQueryData } from "../utils";
|
|
||||||
import { CrudOperation, emitDataChange } from "../../event";
|
import { CrudOperation, emitDataChange } from "../../event";
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,8 +23,28 @@ export function useTrainSituation(){
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const deleteSameGroupTrainSituation = api.trainSituation.deleteSameGroupTrainSituation.useMutation({
|
||||||
|
onSuccess:(res:any) => {
|
||||||
|
queryClient.invalidateQueries({queryKey})
|
||||||
|
queryClient.invalidateQueries({queryKey:getQueryKey(api.trainContent)})
|
||||||
|
queryClient.invalidateQueries({queryKey:getQueryKey(api.staff)})
|
||||||
|
emitDataChange(ObjectType.TRAIN_SITUATION,res,CrudOperation.DELETED)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const createManyTrainSituation = api.trainSituation.createManyTrainSituation.useMutation({
|
||||||
|
onSuccess:(res:any) => {
|
||||||
|
queryClient.invalidateQueries({queryKey})
|
||||||
|
queryClient.invalidateQueries({queryKey:getQueryKey(api.trainContent)})
|
||||||
|
queryClient.invalidateQueries({queryKey:getQueryKey(api.staff)})
|
||||||
|
emitDataChange(ObjectType.TRAIN_SITUATION,res,CrudOperation.CREATED)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
create,
|
create,
|
||||||
update
|
update,
|
||||||
|
deleteSameGroupTrainSituation,
|
||||||
|
createManyTrainSituation
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -341,7 +341,8 @@ model TrainContent {
|
||||||
title String @map("title")
|
title String @map("title")
|
||||||
trainSituations TrainSituation[]
|
trainSituations TrainSituation[]
|
||||||
trainPlans TrainPlan[] @relation("TrainPlanContent")
|
trainPlans TrainPlan[] @relation("TrainPlanContent")
|
||||||
|
sportProjectId String? @unique @map("sport_project_id") // 新增字段,用于关联 SportProject
|
||||||
|
sportProject SportProject? @relation("TrainContentSportProject") // 可选的一对一关系
|
||||||
type String @map("type")
|
type String @map("type")
|
||||||
parentId String? @map("parent_id")
|
parentId String? @map("parent_id")
|
||||||
parent TrainContent? @relation("ContentParent", fields: [parentId], references: [id]) // 指向自身
|
parent TrainContent? @relation("ContentParent", fields: [parentId], references: [id]) // 指向自身
|
||||||
|
@ -360,12 +361,18 @@ model TrainSituation {
|
||||||
staff Staff @relation(fields: [staffId], references: [id])
|
staff Staff @relation(fields: [staffId], references: [id])
|
||||||
trainContentId String @map("train_content_id")
|
trainContentId String @map("train_content_id")
|
||||||
trainContent TrainContent @relation(fields: [trainContentId], references: [id])
|
trainContent TrainContent @relation(fields: [trainContentId], references: [id])
|
||||||
|
groupId String? @map("group_id")
|
||||||
|
|
||||||
score Float @default(0.0) @map("score")
|
score Float @default(0.0) @map("score")
|
||||||
|
value String? @map("value")
|
||||||
mustTrainTime Float @map("must_train_time")
|
mustTrainTime Float @map("must_train_time")
|
||||||
alreadyTrainTime Float @map("already_train_time")
|
alreadyTrainTime Float @map("already_train_time")
|
||||||
dailyTrainTime DailyTrainTime[] @relation("DailyTrainSituation")
|
dailyTrainTime DailyTrainTime[] @relation("DailyTrainSituation")
|
||||||
|
|
||||||
|
deletedAt DateTime? @map("deleted_at")
|
||||||
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
|
|
||||||
@@map("train_situation")
|
@@map("train_situation")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,7 +389,7 @@ model DailyTrainTime {
|
||||||
model Position {
|
model Position {
|
||||||
id String @id @default(cuid()) @map("id")
|
id String @id @default(cuid()) @map("id")
|
||||||
type String @map("type")
|
type String @map("type")
|
||||||
|
categorize String @map("categorize")
|
||||||
staff Staff[] @relation("StaffPosition")
|
staff Staff[] @relation("StaffPosition")
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
|
@ -427,9 +434,9 @@ model Staff {
|
||||||
avatar String? @map("avatar")
|
avatar String? @map("avatar")
|
||||||
password String? @map("password")
|
password String? @map("password")
|
||||||
phoneNumber String? @unique @map("phone_number")
|
phoneNumber String? @unique @map("phone_number")
|
||||||
age Int? @map("age")
|
age Int? @default(22) @map("age")
|
||||||
sex Boolean? @map("sex")
|
sex Boolean? @default(true) @map("sex")
|
||||||
absent Boolean? @map("absent")@default(false)
|
absent Boolean? @default(false) @map("absent")
|
||||||
|
|
||||||
trainSituations TrainSituation[]
|
trainSituations TrainSituation[]
|
||||||
position Position? @relation("StaffPosition", fields: [positionId], references: [id])
|
position Position? @relation("StaffPosition", fields: [positionId], references: [id])
|
||||||
|
@ -487,7 +494,6 @@ model TrainPlan {
|
||||||
@@map("train_plan")
|
@@map("train_plan")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
model SportProject {
|
model SportProject {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
name String @map("name") // 项目名称
|
name String @map("name") // 项目名称
|
||||||
|
@ -495,10 +501,13 @@ model SportProject {
|
||||||
description String? @map("description") // 项目描述
|
description String? @map("description") // 项目描述
|
||||||
unit String @map("unit") // 成绩单位(如:秒、米、个)
|
unit String @map("unit") // 成绩单位(如:秒、米、个)
|
||||||
isAscending Boolean @map("is_ascending") // 是否为升序计分
|
isAscending Boolean @map("is_ascending") // 是否为升序计分
|
||||||
|
trainContentId String? @unique @map("train_content_id") // 新增字段,用于关联 TrainContent
|
||||||
|
trainContent TrainContent? @relation("TrainContentSportProject", fields: [trainContentId], references: [id]) // 可选的一对一关系
|
||||||
standards SportStandard[]
|
standards SportStandard[]
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
deletedAt DateTime? @map("deleted_at")
|
deletedAt DateTime? @map("deleted_at")
|
||||||
|
|
||||||
@@map("sport_project")
|
@@map("sport_project")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,6 +527,6 @@ model SportStandard {
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
deletedAt DateTime? @map("deleted_at")
|
deletedAt DateTime? @map("deleted_at")
|
||||||
|
|
||||||
@@unique([projectId, gender, personType])
|
@@unique([projectId, gender, personType], name: "projectId_gender_personType")
|
||||||
@@map("sport_standard")
|
@@map("sport_standard")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { Staff, Department } from "@prisma/client";
|
import { Staff, Department, Position, TrainSituation } from "@prisma/client";
|
||||||
import { RolePerms } from "../enum";
|
import { RolePerms } from "../enum";
|
||||||
|
import { trainSituationDto } from "./train";
|
||||||
|
|
||||||
export type StaffRowModel = {
|
export type StaffRowModel = {
|
||||||
avatar: string;
|
avatar: string;
|
||||||
|
@ -15,11 +16,14 @@ export type UserProfile = Staff & {
|
||||||
parentDeptIds: string[];
|
parentDeptIds: string[];
|
||||||
domain: Department;
|
domain: Department;
|
||||||
department: Department;
|
department: Department;
|
||||||
|
position: Position;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type StaffDto = Staff & {
|
export type StaffDto = Staff & {
|
||||||
domain?: Department;
|
domain?: Department;
|
||||||
department?: Department;
|
department?: Department;
|
||||||
|
position?: Position;
|
||||||
|
trainSituation?: trainSituationDto;
|
||||||
};
|
};
|
||||||
export interface AuthDto {
|
export interface AuthDto {
|
||||||
token: string;
|
token: string;
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { TrainContent, TrainSituation } from "@prisma/client";
|
||||||
|
|
||||||
|
export type trainSituationDto = TrainSituation & {
|
||||||
|
trainContent: TrainContent
|
||||||
|
}
|
|
@ -125,6 +125,10 @@ export const StaffMethodSchema = {
|
||||||
getRows: RowRequestSchema.extend({
|
getRows: RowRequestSchema.extend({
|
||||||
domainId: z.string().nullish(),
|
domainId: z.string().nullish(),
|
||||||
}),
|
}),
|
||||||
|
findSportStaffByDept: z.object({
|
||||||
|
deptId: z.string().nullish(),
|
||||||
|
domainId: z.string().nullish(),
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DepartmentMethodSchema = {
|
export const DepartmentMethodSchema = {
|
||||||
|
|
Loading…
Reference in New Issue