This commit is contained in:
Rao 2025-03-25 20:17:05 +08:00
parent fe0bc8d8d7
commit 656ba75ce7
15 changed files with 527 additions and 198 deletions

View File

@ -27,7 +27,11 @@ export class SportProjectRouter {
findMany:this.trpc.procedure.input(SportProjectFindManyArgsSchema) findMany:this.trpc.procedure.input(SportProjectFindManyArgsSchema)
.query(async ({input})=>{ .query(async ({input})=>{
return this.sportProjectService.findMany(input) return this.sportProjectService.findMany(input)
}) }),
softDeleteByIds:this.trpc.procedure.input(z.object({ ids: z.array(z.string()) }))
.mutation(async ({input})=>{
return this.sportProjectService.softDeleteByIds(input.ids)
}),
}) })
} }

View File

@ -23,7 +23,6 @@ export class sportProjectService extends BaseService<Prisma.SportProjectDelegate
super(db,ObjectType.SPORT_PROJECT,false); super(db,ObjectType.SPORT_PROJECT,false);
} }
async create(args: Prisma.SportProjectCreateArgs) { async create(args: Prisma.SportProjectCreateArgs) {
console.log(args)
const result = await super.create(args) const result = await super.create(args)
this.emitDataChanged(CrudOperation.CREATED,result) this.emitDataChanged(CrudOperation.CREATED,result)
return result return result
@ -41,6 +40,12 @@ export class sportProjectService extends BaseService<Prisma.SportProjectDelegate
return result; return result;
} }
async softDeleteByIds(ids: string[]) {
const result = await super.softDeleteByIds(ids);
this.emitDataChanged(CrudOperation.DELETED,result)
return result
}
private emitDataChanged(operation: CrudOperation, data: any) { private emitDataChanged(operation: CrudOperation, data: any) {
EventBus.emit('dataChanged', { EventBus.emit('dataChanged', {
type:ObjectType.SPORT_STANDARD, type:ObjectType.SPORT_STANDARD,

View File

@ -8,7 +8,7 @@ const SportStandardArgsSchema:ZodType<Prisma.SportStandardCreateArgs> = z.any()
const SportStandardUpdateArgsSchema:ZodType<Prisma.SportStandardUpdateArgs> = z.any() const SportStandardUpdateArgsSchema:ZodType<Prisma.SportStandardUpdateArgs> = z.any()
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()
interface AgeRange { interface AgeRange {
start: number | null; start: number | null;
end: number | null; end: number | null;
@ -48,6 +48,15 @@ export class SportStandardRouter {
scoreTable: input.data.scoreTable as Record scoreTable: input.data.scoreTable as Record
} }
return this.sportStandardService.createStandard(data,input.select,input.include) return this.sportStandardService.createStandard(data,input.select,input.include)
}),
updateStandard:this.trpc.procedure.input(SportStandardUpdateStandardArgsSchema)
.mutation(async ({input})=>{
const data = {
id: input.data.id as string,
ageRanges: input.data.ageRanges as any as AgeRange[],
scoreTable: input.data.scoreTable as Record
}
return this.sportStandardService.updateStandard(data)
}) })
}) })

View File

@ -40,7 +40,7 @@ export class SportStandardService extends BaseService<Prisma.SportStandardDelega
const result = await super.findMany(args); const result = await super.findMany(args);
return result; 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; }> { async findUnique(args: Prisma.SportStandardFindUniqueArgs) {
const result = await super.findUnique(args) const result = await super.findUnique(args)
return result return result
} }
@ -104,6 +104,28 @@ export class SportStandardService extends BaseService<Prisma.SportStandardDelega
}); });
} }
async updateStandard(
data: {
id: string;
ageRanges: AgeRange[];
scoreTable: Record;
}
) {
this.validateAgeRanges(data.ageRanges);
this.validateScoreTable(data.scoreTable, data.ageRanges.length);
const result = await super.update({
where: {
id: data.id
},
data: {
ageRanges: JSON.stringify(data.ageRanges),
scoreTable: JSON.stringify(data.scoreTable)
}
})
this.emitDataChanged(CrudOperation.UPDATED, result)
return result
}
public SportScoreCalculator(performance: number, age: number, scoreStandard: ScoreStandard): number { public SportScoreCalculator(performance: number, age: number, scoreStandard: ScoreStandard): number {
// 1. 找到对应的年龄段索引 // 1. 找到对应的年龄段索引
const ageRangeIndex = scoreStandard.ageRanges.findIndex(range => { const ageRangeIndex = scoreStandard.ageRanges.findIndex(range => {

View File

@ -0,0 +1,42 @@
import { Form, InputNumber, Modal } from "antd";
import { useAssessmentStandardContext } from "./assessment-standard-provider";
export default function AssessmentModal() {
const { isAgeModalVisible, isScoreModalVisible, ageForm, scoreForm, handleAgeOk, handleAgeCancel, handleScoreOk, handleScoreCancel, ageRanges } = useAssessmentStandardContext();
return (
<div>
<Modal
title="添加年龄范围"
visible={isAgeModalVisible}
onOk={ageForm.submit}
onCancel={handleAgeCancel}
>
<Form form={ageForm} onFinish={handleAgeOk}>
<Form.Item name="start" label="起始年龄" rules={[{ required: true }]}>
<InputNumber min={0} />
</Form.Item>
<Form.Item name="end" label="结束年龄">
<InputNumber min={0} />
</Form.Item>
</Form>
</Modal>
<Modal
title="添加分数与对应标准"
visible={isScoreModalVisible}
onOk={scoreForm.submit}
onCancel={handleScoreCancel}
>
<Form form={scoreForm} onFinish={handleScoreOk}>
<Form.Item name="score" label="分数" rules={[{ required: true }]}>
<InputNumber min={0} />
</Form.Item>
{ageRanges.map((range, index) => (
<Form.Item key={index} name={`standards_${index}`} label={range.label}>
<InputNumber min={0} />
</Form.Item>
))}
</Form>
</Modal>
</div>
)
}

View File

@ -0,0 +1,14 @@
import AssessmentModal from "./assessment-modal";
import SportCreateContent from "./sport-create-content";
import StandardCreateContent from "./standard-create-content";
export default function AssessmentStandardLayout() {
return (
<div className="p-6">
<h1 className="text-2xl font-bold mb-6"></h1>
<AssessmentModal></AssessmentModal>
<SportCreateContent></SportCreateContent>
<StandardCreateContent></StandardCreateContent>
</div>
)
}

View File

@ -0,0 +1,138 @@
import React, {
createContext,
ReactNode,
useContext,
useMemo,
useState,
} from "react";
// import { useDebounce } from "use-debounce";
import { Form, FormInstance } from 'antd';
import { api } from "@nice/client";
interface AssessmentStandardContextType {
form: FormInstance;
sportProjectList: {
id: string;
name: string;
unit: string;
}[];
sportProjectLoading: boolean;
ageRanges: { start: number; end: number; label: string; }[];
records: { score: number, standards: number[] }[];
isAgeModalVisible: boolean;
isScoreModalVisible: boolean;
showAgeModal: () => void;
handleAgeOk: (values: any) => void;
handleAgeCancel: () => void;
showScoreModal: () => void;
handleScoreOk: (values: any) => void;
handleScoreCancel: () => void;
setRecords: (records: { score: number, standards: number[] }[]) => void;
setIsAgeModalVisible: (isAgeModalVisible: boolean) => void;
setIsScoreModalVisible: (isScoreModalVisible: boolean) => void;
ageForm: FormInstance;
scoreForm: FormInstance;
setAgeRanges: (ageRanges: { start: number; end: number; label: string; }[]) => void;
isStandardCreate: boolean;
setIsStandardCreate: (isStandardCreate: boolean) => void;
}
const AssessmentStandardContext = createContext<AssessmentStandardContextType | null>(null);
interface AssessmentStandardProviderProps {
children: ReactNode;
}
export function AssessmentStandardProvider({ children }: AssessmentStandardProviderProps) {
const [form] = Form.useForm();
const [ageForm] = Form.useForm();
const [scoreForm] = Form.useForm();
const { data: sportProjectList, isLoading: sportProjectLoading } = api.sportProject.findMany.useQuery()
const [ageRanges, setAgeRanges] = useState<{ start: number; end: number; label: string; }[]>([]);
const [records, setRecords] = useState<{ score: number, standards: number[] }[]>([]);
const [isAgeModalVisible, setIsAgeModalVisible] = useState(false);
const [isScoreModalVisible, setIsScoreModalVisible] = useState(false);
const [isStandardCreate, setIsStandardCreate] = useState(true);
// 显示年龄范围模态框
const showAgeModal = () => {
setIsAgeModalVisible(true);
};
// 处理年龄范围模态框确定
const handleAgeOk = (values: any) => {
console.log('values',values)
const { start, end } = values;
const newRange = {
start,
end,
label: end ? `${start}-${end}` : `${start}岁以上`,
};
setAgeRanges([...ageRanges, newRange]);
setIsAgeModalVisible(false);
};
// 处理年龄范围模态框取消
const handleAgeCancel = () => {
setIsAgeModalVisible(false);
};
// 显示分数标准模态框
const showScoreModal = () => {
setIsScoreModalVisible(true);
};
// 处理分数标准模态框确定
const handleScoreOk = async (values: any) => {
const { score, standards } = values;
console.log(values)
const standardsArray = Object.keys(values)
.filter(key => key.startsWith('standards_'))
.map(key => values[key]);
setRecords([...records, { score, standards: standardsArray }]);
setIsScoreModalVisible(false);
};
// 处理分数标准模态框取消
const handleScoreCancel = () => {
setIsScoreModalVisible(false);
};
return (
<AssessmentStandardContext.Provider
value={{
form,
sportProjectList: sportProjectList?.map((item) => ({
id: item.id,
name: item.name,
unit: item.unit
})),
sportProjectLoading,
ageRanges,
records,
isAgeModalVisible,
isScoreModalVisible,
setIsAgeModalVisible,
setIsScoreModalVisible,
showAgeModal,
handleAgeOk,
handleAgeCancel,
showScoreModal,
handleScoreOk,
handleScoreCancel,
setRecords,
ageForm,
scoreForm,
setAgeRanges,
isStandardCreate,
setIsStandardCreate
}}>
{children}
</AssessmentStandardContext.Provider>
);
}
export const useAssessmentStandardContext = () => {
const context = useContext(AssessmentStandardContext);
if (!context) {
throw new Error("useAssessmentStandardContext must be used within AssessmentStandardProvider");
}
return context;
};

View File

@ -1,181 +0,0 @@
import { Table, Select, Form, Button, Space, InputNumber, Modal } from 'antd';
import { useState } from 'react';
// 模拟接口调用函数
const addAgeRangeApi = async (start: number, end: number | null) => {
// 这里替换为实际的接口调用
console.log(`调用接口添加年龄范围: start=${start}, end=${end}`);
};
const addScoreStandardApi = async (score: number, standards: (number | null)[]) => {
// 这里替换为实际的接口调用
console.log(`调用接口添加分数标准: score=${score}, standards=${standards}`);
};
export default function AssessmentStandardPage() {
const [form] = Form.useForm();
const [ageRanges, setAgeRanges] = useState<{ start: number; end: number; label: string; }[]>([
{ start: 18, end: 24, label: '18-24岁' },
{ start: 25, end: 34, label: '25-34岁' },
{ start: 35, end: 44, label: '35-44岁' },
{ start: 45, end: null, label: '45岁以上' },
]);
const [isAgeModalVisible, setIsAgeModalVisible] = useState(false);
const [isScoreModalVisible, setIsScoreModalVisible] = useState(false);
const columns = [
{
title: '分数',
dataIndex: 'score',
key: 'score',
width: 100,
},
...ageRanges.map((range, index) => ({
title: range.label,
dataIndex: `standard_${index}`,
key: `standard_${index}`,
render: (_: any, record: any) => (
<InputNumber
style={{ width: '100%' }}
value={record[`standard_${index}`]}
onChange={(value) => handleStandardChange(record.score, index, value)}
/>
),
})),
];
const handleStandardChange = (score: number, ageIndex: number, value: number | null) => {
// 处理标准值变化
};
const showAgeModal = () => {
setIsAgeModalVisible(true);
};
const handleAgeOk = async (values: any) => {
const { start, end } = values;
await addAgeRangeApi(start, end);
const newRange = {
start,
end,
label: end ? `${start}-${end}` : `${start}岁以上`,
};
setAgeRanges([...ageRanges, newRange]);
setIsAgeModalVisible(false);
};
const handleAgeCancel = () => {
setIsAgeModalVisible(false);
};
const showScoreModal = () => {
setIsScoreModalVisible(true);
};
const handleScoreOk = async (values: any) => {
const { score, standards } = values;
await addScoreStandardApi(score, standards);
// 这里可以更新表格的数据源
setIsScoreModalVisible(false);
};
const handleScoreCancel = () => {
setIsScoreModalVisible(false);
};
return (
<div className="p-6">
<h1 className="text-2xl font-bold mb-6"></h1>
<Button onClick={showAgeModal} className="mb-2"></Button>
<Button onClick={showScoreModal} className="mb-2 ml-2"></Button>
<Form form={form} layout="vertical">
<Space size="large" className="mb-6">
<Form.Item label="项目" name="projectId">
<Select
style={{ width: 200 }}
placeholder="选择考核项目"
options={[
{ value: '1', label: '引体向上' },
{ value: '2', label: '3000米跑' },
// 更多项目...
]}
/>
</Form.Item>
<Form.Item label="性别" name="gender">
<Select
style={{ width: 120 }}
placeholder="选择性别"
options={[
{ value: true, label: '男' },
{ value: false, label: '女' },
]}
/>
</Form.Item>
<Form.Item label="人员类型" name="personType">
<Select
style={{ width: 160 }}
placeholder="选择人员类型"
options={[
{ value: 'OFFICER', label: '警员' },
{ value: 'STAFF', label: '职工' },
]}
/>
</Form.Item>
</Space>
<Table
columns={columns}
dataSource={[
{ score: 100, standard_0: 20, standard_1: 18, standard_2: 15, standard_3: 12 },
{ score: 90, standard_0: 18, standard_1: 16, standard_2: 13, standard_3: 10 },
{ score: 80, standard_0: 16, standard_1: 14, standard_2: 11, standard_3: 8 },
// 更多分数标准...
]}
bordered
pagination={false}
scroll={{ x: 'max-content' }}
/>
<div className="mt-6">
<Button type="primary"></Button>
</div>
</Form>
<Modal
title="添加年龄范围"
visible={isAgeModalVisible}
onOk={form.submit}
onCancel={handleAgeCancel}
>
<Form form={form} onFinish={handleAgeOk}>
<Form.Item name="start" label="起始年龄" rules={[{ required: true }]}>
<InputNumber min={1} />
</Form.Item>
<Form.Item name="end" label="结束年龄">
<InputNumber min={1} />
</Form.Item>
</Form>
</Modal>
<Modal
title="添加分数标准"
visible={isScoreModalVisible}
onOk={form.submit}
onCancel={handleScoreCancel}
>
<Form form={form} onFinish={handleScoreOk}>
<Form.Item name="score" label="分数" rules={[{ required: true }]}>
<InputNumber min={0} />
</Form.Item>
{ageRanges.map((range, index) => (
<Form.Item key={index} name={`standards[${index}]`} label={range.label}>
<InputNumber min={0} />
</Form.Item>
))}
</Form>
</Modal>
</div>
);
}

View File

@ -0,0 +1,66 @@
import { Button, Form, Input, Select, Skeleton } from "antd";
import { useAssessmentStandardContext } from "./assessment-standard-provider";
import { useSport } from "@nice/client";
import toast from "react-hot-toast";
export default function SportCreateContent() {
const { form, sportProjectList, sportProjectLoading } = useAssessmentStandardContext();
const { createSportProject, softDeleteByIds } = useSport();
const handleCreateProject = async () => {
console.log(form.getFieldsValue().createProjectName)
if (form.getFieldsValue().createProjectName && form.getFieldsValue().unit) {
await createSportProject.mutateAsync({
data: {
name: form.getFieldsValue().createProjectName,
type: "sport",
unit: form.getFieldsValue().unit,
isAscending: true
}
} as any)
toast.success("创建项目成功")
form.resetFields()
} else {
toast.error("请输入项目名称或成绩单位")
}
}
const handleDeleteProject = async (id: string) => {
console.log(id)
await softDeleteByIds.mutateAsync({
ids: [id]
} as any)
toast.success("删除项目成功")
}
return (
<>
<Form form={form} layout="vertical">
<div className="flex items-center space-x-4 w-1/2">
<Form.Item label="创建项目" name="createProjectName">
<Input placeholder="请输入创建的项目名称" className="mr-2" />
</Form.Item>
<Form.Item label="成绩单位" name="unit" className='w-32'>
<Select
className='mr-2 w-24'
placeholder="请选择成绩单位"
options={[
{ value: 'time', label: '时间' },
{ value: 'count', label: '次数' },
]}
></Select>
</Form.Item>
<Button type="primary" className='mt-10 ml-2' onClick={handleCreateProject}></Button>
</div>
{sportProjectLoading ?
<Skeleton></Skeleton> :
<div className='w-1/3 my-3 max-h-48 overflow-y-auto'>
{sportProjectList?.map((item) => (
<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>
<span className='text-red-500 cursor-pointer' onClick={() => handleDeleteProject(item.id)}></span>
</div>
))}
</div>
}
</Form>
</>
)
}

View File

@ -0,0 +1,165 @@
import { Button, Form, Input, Select, Space, Table } from "antd";
import { useAssessmentStandardContext } from "./assessment-standard-provider";
import toast from "react-hot-toast";
import { api, useSport } from "@nice/client";
import { useEffect, useMemo } from "react";
export default function StandardCreateContent() {
const {form,sportProjectList,ageRanges,records,showAgeModal,showScoreModal,setRecords,setAgeRanges,isStandardCreate,setIsStandardCreate} = useAssessmentStandardContext();
const { createSportStandard,updateSportStandard } = useSport();
const projectId = Form.useWatch('projectId', form);
const gender = Form.useWatch('gender', form);
const personType = Form.useWatch('personType', form);
const transformedObject = useMemo(()=>{
return records.reduce((acc, current) => {
const scoreKey = current.score.toString(); // 将 score 转换为字符串作为键
if (acc[scoreKey]) {
// 如果键已存在,将当前 standard 数组合并到已有的数组中
acc[scoreKey] = acc[scoreKey].concat(current.standards);
} else {
// 如果键不存在,创建一个新的数组
acc[scoreKey] = current.standards;
}
return acc;
}, {});
},[records])
const columns = [
{
title: '分数',
dataIndex: 'score',
key: 'score',
width: 100,
},
...ageRanges.map((range, index) => ({
title: range.label,
dataIndex: `standard[${index}]`,
key: `standard[${index}]`,
render: (_: any, record: any) => (
<Input
style={{ width: '80px' }}
value={record.standards[index]}
onChange={(e) => {
const inputValue = e.target.value;
const numericValue = inputValue ? Number(inputValue) : null;
handleStandardChange(record.score, index, numericValue);
}}
/>
),
})),
];
// 处理标准值变化
const handleStandardChange = (score: number, ageIndex: number, value: number | null) => {
const updatedRecords = records.map(record => {
if (record.score === score) {
const updatedStandards = [...record.standards];
updatedStandards[ageIndex] = value;
return { ...record, standards: updatedStandards };
}
return record;
});
setRecords(updatedRecords);
};
const handleSave = async () => {
// 转换为新格式
if(isStandardCreate){
await createStandard()
}else{
await updateStandard()
}
}
const createStandard = async ()=>{
const result = await createSportStandard.mutateAsync({
data: {
projectId: form.getFieldsValue().projectId,
gender: form.getFieldsValue().gender,
personType: form.getFieldsValue().personType,
ageRanges: ageRanges,
scoreTable: transformedObject
}
} as any)
console.log(result)
toast.success("保存标准成功")
}
const updateStandard = async ()=>{
const result = await updateSportStandard.mutateAsync({
data: {
id: data[0].id,
ageRanges: ageRanges,
scoreTable: transformedObject
}
} as any)
console.log(result)
toast.success("更新标准成功")
}
const { data, isLoading } = api.sportStandard.findMany.useQuery({
where: {
projectId: projectId || "", // 空值处理
gender: gender ?? undefined,
personType: personType || ""
}
}, {
enabled: !!projectId && gender !== undefined && !!personType // 查询启用条件
});
useEffect(() => {
if (data && data.length) {
setIsStandardCreate(false)
const records: {
score: number;
standards: number[];
}[] = Object.entries(JSON.parse(String(data[0].scoreTable))).map(([score, standards]) => ({
score: Number(score),
standards: standards as number[]
}));
setAgeRanges(JSON.parse(String(data[0].ageRanges)))
setRecords(records)
}
}, [data])
return (
<Form form={form} layout="vertical">
<Space size="large" className="my-6">
<Form.Item label="项目" name="projectId">
<Select
style={{ width: 200 }}
placeholder="选择考核项目"
options={sportProjectList?.map((item) => ({ value: item.id, label: `${item.name}${item.unit}` })) || []}
/>
</Form.Item>
<Form.Item label="性别" name="gender">
<Select
style={{ width: 120 }}
placeholder="选择性别"
options={[
{ value: true, label: '男' },
{ value: false, label: '女' },
]}
/>
</Form.Item>
<Form.Item label="人员类型" name="personType">
<Select
style={{ width: 160 }}
placeholder="选择人员类型"
options={[
{ value: 'OFFICER', label: '警员' },
{ value: 'STAFF', label: '职工' },
]}
/>
</Form.Item>
<Button onClick={showAgeModal} className="mt-9"></Button>
<Button onClick={showScoreModal} className="mt-9 ml-2"></Button>
<Button type="primary" onClick={handleSave} className='mt-9 ml-2'></Button>
</Space>
<Table
columns={columns}
dataSource={records}
bordered
pagination={false}
scroll={{ x: 'max-content' }}
/>
</Form>
)
}

View File

@ -5,11 +5,11 @@ import { useSport } from "@nice/client"
export default function Dashboard() { export default function Dashboard() {
const { createSportStandard } = useSport() const { createSportStandard } = useSport()
const handleCreateSportStandard = async () => { const handleCreateSportStandard = async () => {
await createSportStandard.mutateAsync({ const res = await createSportStandard.mutateAsync({
data: { data: {
projectId: "cm8nsk1c0000czg9ix8d4yzml", projectId: "cm8o6jzp908bp846bv513aqvo",
gender: true, gender: true,
personType: "学生", personType: "STAFF",
ageRanges: [ ageRanges: [
{ start: null, end: 24, label: "24岁以下" }, { start: null, end: 24, label: "24岁以下" },
{ start: 24, end: 27, label: "25-27岁" }, { start: 24, end: 27, label: "25-27岁" },
@ -23,6 +23,7 @@ export default function Dashboard() {
} }
} }
} as any) } as any)
console.log(res)
} }
return ( return (
<div > <div >

View File

@ -15,8 +15,8 @@ import WithAuth from "../components/utils/with-auth";
import { CustomRouteObject } from "./types"; import { CustomRouteObject } from "./types";
import StaffPage from "../app/admin/staff/page"; import StaffPage from "../app/admin/staff/page";
import AdminLayout from "../components/layout/admin/AdminLayout"; import AdminLayout from "../components/layout/admin/AdminLayout";
import AssessmentStandardPage from "../app/admin/assessmentstandard/assessment-standardpage"; import { AssessmentStandardProvider } from "../app/admin/assessmentstandard/assessment-standard-provider";
import AssessmentStandardLayout from "../app/admin/assessmentstandard/assessment-standard-layout";
export const adminRoute: CustomRouteObject = { export const adminRoute: CustomRouteObject = {
path: "admin", path: "admin",
name: "系统设置", name: "系统设置",
@ -83,7 +83,9 @@ export const adminRoute: CustomRouteObject = {
path: "assessment-standard", path: "assessment-standard",
name: "考核标准管理", name: "考核标准管理",
icon: <TagsOutlined />, icon: <TagsOutlined />,
element: <AssessmentStandardPage></AssessmentStandardPage> element: <AssessmentStandardProvider>
<AssessmentStandardLayout></AssessmentStandardLayout>
</AssessmentStandardProvider>
}, },
// { // {
// path: "term", // path: "term",

View File

@ -100,7 +100,7 @@ server {
# 仅供内部使用 # 仅供内部使用
internal; internal;
# 代理到认证服务 # 代理到认证服务
proxy_pass http://192.168.252.77:3001/auth/file; proxy_pass http://192.168.252.77:3000/auth/file;
# 请求优化:不传递请求体 # 请求优化:不传递请求体
proxy_pass_request_body off; proxy_pass_request_body off;

View File

@ -3,10 +3,32 @@ import { api, RouterOutputs } from "../trpc"; // Adjust path as necessary
import { useQueryClient, UseMutationResult } from "@tanstack/react-query"; import { useQueryClient, UseMutationResult } from "@tanstack/react-query";
import { ObjectType } from "@nice/common"; import { ObjectType } from "@nice/common";
import { CrudOperation, emitDataChange } from "../../event"; import { CrudOperation, emitDataChange } from "../../event";
import { UseTRPCMutationResult } from "@trpc/react-query/shared";
interface SportOperation { interface SportOperation {
createSportProject: UseMutationResult<RouterOutputs["sportProject"]["create"], Error, Parameters<typeof api.sportProject.create.useMutation>[0], unknown>; createSportProject: UseTRPCMutationResult<
createSportStandard: UseMutationResult<RouterOutputs["sportStandard"]["createStandard"], Error, Parameters<typeof api.sportStandard.createStandard.useMutation<RouterOutputs["sportStandard"]["createStandard"]>>[0], unknown>; RouterOutputs["sportProject"]["create"],
Error, // 统一使用Error类型
Parameters<typeof api.sportProject.create.useMutation>[0],
unknown
>;
createSportStandard: UseTRPCMutationResult<
RouterOutputs["sportStandard"]["createStandard"],
Error, Parameters<typeof api.sportStandard.createStandard.useMutation<RouterOutputs["sportStandard"]["createStandard"]>>[0],
unknown
>;
softDeleteByIds: UseTRPCMutationResult<
RouterOutputs["sportProject"]["softDeleteByIds"],
Error,
Parameters<typeof api.sportProject.softDeleteByIds.useMutation>[0],
unknown
>;
updateSportStandard: UseTRPCMutationResult<
RouterOutputs["sportStandard"]["updateStandard"],
Error,
Parameters<typeof api.sportStandard.updateStandard.useMutation<RouterOutputs["sportStandard"]["updateStandard"]>>[0],
unknown
>;
} }
export function useSport(): SportOperation { export function useSport(): SportOperation {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
@ -26,8 +48,24 @@ export function useSport(): SportOperation {
emitDataChange(ObjectType.SPORT_STANDARD, result, CrudOperation.CREATED); emitDataChange(ObjectType.SPORT_STANDARD, result, CrudOperation.CREATED);
}, },
}); });
const softDeleteByIds = api.sportProject.softDeleteByIds.useMutation({
onSuccess: (result) => {
queryClient.invalidateQueries({ queryKey });
emitDataChange(ObjectType.SPORT_PROJECT, result, CrudOperation.DELETED);
},
});
const updateSportStandard = api.sportStandard.updateStandard.useMutation<RouterOutputs["sportStandard"]["updateStandard"]>({
onSuccess: (result) => {
queryClient.invalidateQueries({ queryKey: queryKeyStandard });
emitDataChange(ObjectType.SPORT_STANDARD, result, CrudOperation.UPDATED);
},
});
return { return {
createSportProject: createSportProject as any as UseMutationResult<RouterOutputs["sportProject"]["create"], Error, Parameters<typeof api.sportProject.create.useMutation>[0], unknown>, createSportProject: createSportProject as any as UseTRPCMutationResult<RouterOutputs["sportProject"]["create"], Error, Parameters<typeof api.sportProject.create.useMutation>[0], unknown>,
createSportStandard: createSportStandard as any as UseMutationResult<RouterOutputs["sportStandard"]["createStandard"], Error, Parameters<typeof api.sportStandard.createStandard.useMutation<RouterOutputs["sportStandard"]["createStandard"]>>[0], unknown>, createSportStandard: createSportStandard as any as UseTRPCMutationResult<RouterOutputs["sportStandard"]["createStandard"], Error, Parameters<typeof api.sportStandard.createStandard.useMutation<RouterOutputs["sportStandard"]["createStandard"]>>[0], unknown>,
softDeleteByIds: softDeleteByIds as any as UseTRPCMutationResult<RouterOutputs["sportProject"]["softDeleteByIds"], Error, Parameters<typeof api.sportProject.softDeleteByIds.useMutation>[0], unknown>,
updateSportStandard: updateSportStandard as any as UseTRPCMutationResult<RouterOutputs["sportStandard"]["updateStandard"], Error, Parameters<typeof api.sportStandard.updateStandard.useMutation<RouterOutputs["sportStandard"]["updateStandard"]>>[0], unknown>,
}; };
} }

View File

@ -498,7 +498,7 @@ model SportProject {
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")
@@map("sport_project") @@map("sport_project")
} }
@ -514,6 +514,10 @@ model SportStandard {
ageRanges Json @map("age_ranges") // 年龄段定义 ageRanges Json @map("age_ranges") // 年龄段定义
scoreTable Json @map("score_table") // 评分标准表 scoreTable Json @map("score_table") // 评分标准表
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
deletedAt DateTime? @map("deleted_at")
@@unique([projectId, gender, personType]) @@unique([projectId, gender, personType])
@@map("sport_standard") @@map("sport_standard")
} }