diff --git a/.api/safetyEval-classCourse-batchSave-post/spec.json b/.api/safetyEval-classCourse-batchSave-post/spec.json new file mode 100644 index 0000000..e11a20a --- /dev/null +++ b/.api/safetyEval-classCourse-batchSave-post/spec.json @@ -0,0 +1,63 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "批量新增班级课程", + "version": "1.0.0", + "description": "同步自 Apifox 项目(api-505127646),班级课程" + }, + "paths": { + "/safetyEval/classCourse/batchSave": { + "post": { + "summary": "批量新增班级课程", + "description": "批量新增班级课程", + "tags": ["班级课程"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { "$ref": "#/components/schemas/ClassCourseDTO" } + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/SingleResponseBoolean" } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "ClassCourseDTO": { + "type": "object", + "properties": { + "id": { "type": "string", "description": "主键(后端 Long;前端按字符串保证精度)" }, + "classId": { "type": "string", "description": "所属班级ID(后端 Long;前端按字符串保证精度)" }, + "courseName": { "type": "string", "description": "课程名称" }, + "courseId": { "type": "string", "description": "课程id(后端 Long;前端按字符串保证精度)" }, + "requiredTotalHours": { "type": "number", "description": "要求完成总学时(小时)" }, + "videoDuration": { "type": "number", "description": "视频累计时长(小时)" }, + "coursewareId": { "type": "array", "items": { "type": "string" }, "description": "课件id集合" } + } + }, + "SingleResponseBoolean": { + "type": "object", + "properties": { + "success": { "type": "boolean" }, + "code": { "type": "string", "description": "响应码" }, + "message": { "type": "string", "description": "响应消息" }, + "errMessage": { "type": "string", "description": "错误响应消息" }, + "data": { "type": "boolean" } + } + } + } + } +} diff --git a/.api/safetyEval-classCourse-batchSave-post/type.d.ts b/.api/safetyEval-classCourse-batchSave-post/type.d.ts new file mode 100644 index 0000000..92fe202 --- /dev/null +++ b/.api/safetyEval-classCourse-batchSave-post/type.d.ts @@ -0,0 +1,34 @@ +/** + * POST /safetyEval/classCourse/batchSave —— 批量新增班级课程 + * 契约见同目录 spec.json + */ + +/** 班级课程 DTO(请求体为数组) */ +export interface ClassCourseDTO { + /** 主键(后端 Long;前端按字符串保证精度) */ + id?: string; + /** 所属班级ID(后端 Long;前端按字符串保证精度) */ + classId?: string; + /** 课程名称 */ + courseName?: string; + /** 课程id(后端 Long;前端按字符串保证精度) */ + courseId?: string; + /** 要求完成总学时(小时) */ + requiredTotalHours?: number; + /** 视频累计时长(小时) */ + videoDuration?: number; + /** 课件id集合 */ + coursewareId?: string[]; +} + +/** 请求体:ClassCourseDTO 数组 */ +export type ClassCourseBatchSaveBody = ClassCourseDTO[]; + +/** 响应体 */ +export interface SingleResponseBoolean { + success?: boolean; + code?: string; + message?: string; + errMessage?: string; + data?: boolean; +} diff --git a/.api/safetyEval-classCourse-delete-post/spec.json b/.api/safetyEval-classCourse-delete-post/spec.json new file mode 100644 index 0000000..74e7804 --- /dev/null +++ b/.api/safetyEval-classCourse-delete-post/spec.json @@ -0,0 +1,57 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "删除班级课程", + "version": "1.0.0", + "description": "同步自 Apifox 项目(api-503642492),班级课程" + }, + "paths": { + "/safetyEval/classCourse/delete": { + "post": { + "summary": "删除班级课程", + "tags": ["班级课程"], + "requestBody": { + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ReqLong" } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/SingleResponseVoid" } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "ReqLong": { + "type": "object", + "properties": { + "data": { + "type": "string", + "description": "班级课程主键ID(后端 Long / Apifox 显示 int64;前端按字符串保证精度)" + } + }, + "required": ["data"] + }, + "SingleResponseVoid": { + "type": "object", + "properties": { + "success": { "type": "boolean", "description": "是否成功" }, + "code": { "type": "string", "description": "响应码" }, + "message": { "type": "string", "description": "响应消息" }, + "errMessage": { "type": "string", "description": "错误响应消息" }, + "data": { "type": "null", "description": "响应数据" } + } + } + } + } +} diff --git a/.api/safetyEval-classCourse-delete-post/type.d.ts b/.api/safetyEval-classCourse-delete-post/type.d.ts new file mode 100644 index 0000000..08d2efd --- /dev/null +++ b/.api/safetyEval-classCourse-delete-post/type.d.ts @@ -0,0 +1,18 @@ +/** + * POST /safetyEval/classCourse/delete —— 删除班级课程 + * 契约见同目录 spec.json + */ + +/** 请求体:{ data: 班级课程主键ID }(后端 Long;前端按字符串传递保证精度) */ +export interface ClassCourseDeleteBody { + data: string; +} + +/** 响应体 */ +export interface SingleResponseVoid { + success?: boolean; + code?: string; + message?: string; + errMessage?: string; + data?: null; +} diff --git a/src/api/courseware/index.js b/src/api/courseware/index.js index 05a9fea..8185714 100644 --- a/src/api/courseware/index.js +++ b/src/api/courseware/index.js @@ -102,3 +102,15 @@ export const classCoursePage = declareRequest( "Get > /safetyEval/classCourse/page", "classCourseList: [] | res.data || [] & classCourseTotal: 0 | res.total || 0", ); + +/** 批量新增班级课程(请求体为 ClassCourseDTO 数组) */ +export const classCourseBatchSave = declareRequest( + "classCourseConfirmLoading", + "Post > @/safetyEval/classCourse/batchSave", +); + +/** 删除班级课程(请求体:{ data: 班级课程主键id }) */ +export const classCourseRemove = declareRequest( + "classCourseLoading", + "Post > @/safetyEval/classCourse/delete", +); diff --git a/src/pages/Container/EduTraining/ClassManage/Add/CourseTab.js b/src/pages/Container/EduTraining/ClassManage/Add/CourseTab.js index a0b03ca..f10b825 100644 --- a/src/pages/Container/EduTraining/ClassManage/Add/CourseTab.js +++ b/src/pages/Container/EduTraining/ClassManage/Add/CourseTab.js @@ -20,17 +20,12 @@ function ClassCourseTab(props) { const [searchForm] = Form.useForm(); const [query, setQuery] = useState({ current: 1, size: 10 }); const [selectOpen, setSelectOpen] = useState(false); - // 本地暂存:接口未就绪,确认选择的课程先追加到表格展示 - const [pendingCourses, setPendingCourses] = useState([]); const { classCourseList: dataSource, classCourseTotal: total, classCourseLoading: loading, } = props.courseware || {}; const tableSource = Array.isArray(dataSource) ? dataSource : []; - // 本地暂存行仅在第一页合并展示,避免翻页重复 - const mergedSource = - query.current === 1 ? [...pendingCourses, ...tableSource] : tableSource; const handleSearch = (params = query) => { props.classCoursePage({ ...params, classId }); @@ -83,7 +78,7 @@ function ClassCourseTab(props) { title: "操作", width: 140, fixed: "right", - render: () => ( + render: (_, record) => ( @@ -144,11 +155,11 @@ function ClassCourseTab(props) { `共 ${t} 条`, @@ -165,25 +176,25 @@ function ClassCourseTab(props) { item.courseId), - ...pendingCourses.map((item) => item.courseId), - ]} - onOk={(rows) => { - // 班级添加课程接口待接入:先本地暂存并填充表格,接入后改为提交请求 + handleSearch() 刷新 - setPendingCourses((prev) => [ - ...prev, - ...rows.map(({ id, courseName, classHourDuration }) => ({ - id, + selectedIds={tableSource.map((item) => item.courseId)} + onOk={async (rows) => { + // 批量新增班级课程 + const res = await props.classCourseBatchSave( + rows.map(({ id, courseName, classHourDuration }) => ({ + classId, courseId: id, courseName, requiredTotalHours: classHourDuration, })), - ]); + ); + if (res?.success === false) return; + message.success("添加成功"); setSelectOpen(false); + handleSearch(); }} onCancel={() => setSelectOpen(false)} /> @@ -195,6 +206,7 @@ function ClassCourseTab(props) { function CourseSelectModal({ open, loading, + confirmLoading, dataSource, total, requestPage, @@ -225,6 +237,7 @@ function CourseSelectModal({ title="选择课程" width={860} loading={loading} + confirmLoading={confirmLoading} destroyOnHidden okText={`确定${selectedRows.length ? `(已选 ${selectedRows.length})` : ""}`} okButtonProps={{ disabled: !selectedRows.length }}