feat
parent
8dfff0c4a1
commit
03332b3d05
|
|
@ -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" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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": "响应数据" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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",
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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) => (
|
||||
<TableAction>
|
||||
<Button
|
||||
type="link"
|
||||
|
|
@ -96,7 +91,23 @@ function ClassCourseTab(props) {
|
|||
danger
|
||||
type="link"
|
||||
size="small"
|
||||
onClick={() => message.info("删除课程接口待接入")}
|
||||
onClick={() =>
|
||||
Modal.confirm({
|
||||
title: "确认删除该课程?",
|
||||
content: `删除后不可恢复,确认删除课程「${
|
||||
record.courseName || ""
|
||||
}」吗?`,
|
||||
onOk: async () => {
|
||||
const res = await props.classCourseRemove({
|
||||
data: record.id,
|
||||
});
|
||||
if (res?.success !== false) {
|
||||
message.success("删除成功");
|
||||
handleSearch();
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
>
|
||||
删除
|
||||
</Button>
|
||||
|
|
@ -144,11 +155,11 @@ function ClassCourseTab(props) {
|
|||
<Table
|
||||
rowKey="id"
|
||||
columns={columns}
|
||||
dataSource={mergedSource}
|
||||
dataSource={tableSource}
|
||||
scroll={{ x: 1000 }}
|
||||
loading={loading}
|
||||
pagination={{
|
||||
total: total + pendingCourses.length,
|
||||
total,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (t) => `共 ${t} 条`,
|
||||
|
|
@ -165,25 +176,25 @@ function ClassCourseTab(props) {
|
|||
<CourseSelectModal
|
||||
open={selectOpen}
|
||||
loading={props.courseware?.courseLoading}
|
||||
confirmLoading={props.courseware?.classCourseConfirmLoading}
|
||||
dataSource={props.courseware?.courseList}
|
||||
total={props.courseware?.courseTotal}
|
||||
requestPage={props.coursePage}
|
||||
selectedIds={[
|
||||
...tableSource.map((item) => 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 }}
|
||||
|
|
|
|||
Loading…
Reference in New Issue