feat: admin course list
This commit is contained in:
parent
9ffd6abac7
commit
aab88ebc0f
|
@ -9,9 +9,12 @@ export interface IGetVodeResponse {
|
|||
}
|
||||
|
||||
export interface ICourseBasic {
|
||||
course_title: string;
|
||||
course_cover_url: string;
|
||||
course_summary: string;
|
||||
course_id?: string;
|
||||
course_title?: string;
|
||||
course_cover_url?: string;
|
||||
course_summary?: string;
|
||||
course_createtime?: string;
|
||||
valid?: boolean;
|
||||
}
|
||||
|
||||
export interface ICreateCourseRequest extends ICourseBasic {
|
||||
|
@ -28,3 +31,19 @@ export interface IXcode {
|
|||
expiretime: string;
|
||||
code: string;
|
||||
}
|
||||
|
||||
export interface ISelectCourse {
|
||||
all?: boolean;
|
||||
}
|
||||
|
||||
export interface IChapter {
|
||||
chapter_course_id?: string;
|
||||
chapter_file_id?: string;
|
||||
chapter_id?: string;
|
||||
chapter_level?: string;
|
||||
chapter_title?: string;
|
||||
media_cover_url?: string;
|
||||
media_time?: string;
|
||||
media_url?: string;
|
||||
order?: number;
|
||||
}
|
||||
|
|
|
@ -2,8 +2,11 @@ import R from "./request";
|
|||
import P from "./process";
|
||||
import {
|
||||
IAdminLogin,
|
||||
IChapter,
|
||||
ICourseBasic,
|
||||
ICreateCourseRequest,
|
||||
IgetVodRequest,
|
||||
ISelectCourse,
|
||||
IXcode,
|
||||
} from "./dto";
|
||||
|
||||
|
@ -23,3 +26,27 @@ export const createXCode = (codeList: IXcode[]) =>
|
|||
R.post("/api/xcode/admin/create", codeList);
|
||||
|
||||
export const selectXCodeList = () => R.post("/api/xcode/admin/select/all");
|
||||
|
||||
export const selectCourseList = (p: ISelectCourse) =>
|
||||
R.post("/api/course/select/all", { ...p });
|
||||
|
||||
export const updateCourse = (course: ICourseBasic) =>
|
||||
R.post("/api/course/update", course);
|
||||
|
||||
export const selectChapterList = ({
|
||||
chapter_course_id,
|
||||
}: {
|
||||
chapter_course_id: string;
|
||||
}) => R.post("/api/course/chapter/select", { chapter_course_id });
|
||||
|
||||
export const updateChapter = (chapter: any) =>
|
||||
R.post("/api/course/chapter/update", chapter);
|
||||
|
||||
export const removeCourse = (course: ICourseBasic) =>
|
||||
R.post("/api/course/remove", course);
|
||||
|
||||
export const createChapter = (chapterList: IChapter[]) =>
|
||||
R.post("/api/course/chapter/create", chapterList);
|
||||
|
||||
export const removeChapter = (chapter: IChapter) =>
|
||||
R.post("/api/course/chapter/remove", chapter);
|
||||
|
|
|
@ -31,7 +31,7 @@ instance.interceptors.response.use(
|
|||
break;
|
||||
case 40000:
|
||||
message.error(msg);
|
||||
window.location.href = "/";
|
||||
// window.location.href = "/";
|
||||
break;
|
||||
default:
|
||||
// TODO ...
|
||||
|
|
|
@ -22,6 +22,10 @@ const sideMenus: MenuProps["items"] = [
|
|||
key: "create",
|
||||
label: "创建",
|
||||
},
|
||||
{
|
||||
key: "list",
|
||||
label: "课程列表",
|
||||
},
|
||||
{
|
||||
key: "library",
|
||||
label: "视频库",
|
||||
|
|
|
@ -28,6 +28,11 @@ export const sideMenuRoutes: IRoute[] = [
|
|||
element: lazy(() => import("../view/Course/Create")),
|
||||
name: "创建课程",
|
||||
},
|
||||
{
|
||||
path: "/course/list",
|
||||
element: lazy(() => import("../view/Course/List")),
|
||||
name: "课程列表",
|
||||
},
|
||||
{
|
||||
path: "/course/library",
|
||||
element: lazy(() => import("../view/Course/Library")),
|
||||
|
|
|
@ -7,11 +7,8 @@ import {
|
|||
Space,
|
||||
Table,
|
||||
Input,
|
||||
Segmented,
|
||||
Tooltip,
|
||||
Image,
|
||||
Typography,
|
||||
Modal,
|
||||
Tag,
|
||||
} from "antd";
|
||||
import dayjs from "dayjs";
|
||||
|
@ -65,7 +62,7 @@ const Library = () => {
|
|||
key: "key",
|
||||
},
|
||||
{
|
||||
title: "m3u8 大小",
|
||||
title: "hls",
|
||||
dataIndex: "m3u8Size",
|
||||
key: "m3u8Size",
|
||||
},
|
||||
|
@ -86,7 +83,7 @@ const Library = () => {
|
|||
key: "m3u8",
|
||||
},
|
||||
{
|
||||
title: "视频封面图",
|
||||
title: "封面图",
|
||||
dataIndex: "cover",
|
||||
key: "cover",
|
||||
},
|
||||
|
|
3
apps/admin/src/view/Course/List/index.less
Normal file
3
apps/admin/src/view/Course/List/index.less
Normal file
|
@ -0,0 +1,3 @@
|
|||
.list {
|
||||
padding: 24px 0;
|
||||
}
|
499
apps/admin/src/view/Course/List/index.tsx
Normal file
499
apps/admin/src/view/Course/List/index.tsx
Normal file
|
@ -0,0 +1,499 @@
|
|||
import {
|
||||
DeleteOutlined,
|
||||
EditFilled,
|
||||
EditOutlined,
|
||||
FieldTimeOutlined,
|
||||
FileAddOutlined,
|
||||
InfoCircleOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
DatePicker,
|
||||
Image,
|
||||
Input,
|
||||
Popconfirm,
|
||||
Space,
|
||||
Switch,
|
||||
Table,
|
||||
Modal,
|
||||
Tooltip,
|
||||
Form,
|
||||
} from "antd";
|
||||
import dayjs, { Dayjs } from "dayjs";
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
removeCourse,
|
||||
selectChapterList,
|
||||
selectCourseList,
|
||||
updateChapter,
|
||||
updateCourse,
|
||||
createChapter,
|
||||
removeChapter,
|
||||
} from "../../../api";
|
||||
import { IChapter } from "../../../api/dto";
|
||||
import { useMount } from "../../../hooks";
|
||||
import "./index.less";
|
||||
|
||||
interface IEditItem {
|
||||
key: string;
|
||||
value: string | boolean | number;
|
||||
}
|
||||
|
||||
const defaultEditItem = { key: "", value: "" };
|
||||
|
||||
export default function List() {
|
||||
const [courseList, setCourseList] = useState<any>([]);
|
||||
const [chapterList, setChapterList] = useState([]);
|
||||
const [editChapterItem, setEditChapterItem] =
|
||||
useState<IEditItem>(defaultEditItem);
|
||||
const [editCourseItem, setEditCourseItem] =
|
||||
useState<IEditItem>(defaultEditItem);
|
||||
const [addChapterForm] = Form.useForm();
|
||||
|
||||
const onConfirmEditCourseItem = (record: any) => {
|
||||
const { key, value } = editCourseItem;
|
||||
updateCourse({ ...record, [key]: value }).then((res: any) => {
|
||||
if (res?.code === 10000) {
|
||||
renderCourseTable();
|
||||
setEditCourseItem(defaultEditItem);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onConfirmEditChapterItem = (record: any) => {
|
||||
const { key, value } = editChapterItem;
|
||||
updateChapter({ ...record, [key]: value }).then((res: any) => {
|
||||
if (res?.code === 10000) {
|
||||
const { chapter_course_id } = record;
|
||||
renderChapterList(chapter_course_id);
|
||||
setEditChapterItem(defaultEditItem);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onConfirmDeleteCourseItem = (record: any) => {
|
||||
const { course_id } = record;
|
||||
removeCourse({ course_id }).then((res: any) => {
|
||||
if (res?.code === 10000) renderCourseTable();
|
||||
});
|
||||
};
|
||||
|
||||
const onAddChapter = (record: any) => {
|
||||
const { course_id: chapter_course_id } = record;
|
||||
Modal.info({
|
||||
title: "添加章节",
|
||||
icon: <InfoCircleOutlined />,
|
||||
content: (
|
||||
<Form form={addChapterForm}>
|
||||
<Form.Item name="chapterList">
|
||||
<Input.TextArea
|
||||
placeholder="级别 | 章节名 | 文件FileID"
|
||||
autoSize={{ minRows: 12, maxRows: 20 }}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
),
|
||||
onOk: async () => {
|
||||
const origin = addChapterForm.getFieldValue("chapterList");
|
||||
const chapterList = origin
|
||||
.split("\n")
|
||||
.filter((i: string) => i.replace(/\s/, "").length > 0)
|
||||
.map((row: string) => {
|
||||
const [chapter_level, chapter_title, chapter_file_id] =
|
||||
row.split("|");
|
||||
return !chapter_file_id
|
||||
? { chapter_level, chapter_title, chapter_course_id }
|
||||
: {
|
||||
chapter_level,
|
||||
chapter_title,
|
||||
chapter_file_id,
|
||||
chapter_course_id,
|
||||
};
|
||||
});
|
||||
createChapter(chapterList).then((res: any) => {
|
||||
if (res?.code === 10000) renderChapterList(chapter_course_id);
|
||||
});
|
||||
},
|
||||
okText: "确认",
|
||||
cancelText: "取消",
|
||||
});
|
||||
};
|
||||
|
||||
const onConfirmDeleteChapterItem = (record: any) => {
|
||||
const { chapter_id, chapter_course_id } = record;
|
||||
removeChapter({ chapter_id }).then((res: any) => {
|
||||
if (res?.code === 10000) renderChapterList(chapter_course_id);
|
||||
});
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: "课程",
|
||||
dataIndex: "course_title",
|
||||
key: "course_title",
|
||||
render: (_: any, record: any) => {
|
||||
return (
|
||||
<Space>
|
||||
<span>{record.course_title}</span>
|
||||
<Popconfirm
|
||||
placement="top"
|
||||
title="修改课程标题"
|
||||
description={
|
||||
<Input
|
||||
defaultValue={record.course_title}
|
||||
onChange={(e: any) =>
|
||||
setEditCourseItem({
|
||||
key: "course_title",
|
||||
value: e.target.value,
|
||||
})
|
||||
}
|
||||
/>
|
||||
}
|
||||
onConfirm={() => onConfirmEditCourseItem(record)}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Button type="text" icon={<EditFilled />} />
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "摘要",
|
||||
dataIndex: "course_summary",
|
||||
key: "course_summary",
|
||||
render: (_: any, record: any) => {
|
||||
return (
|
||||
<Space>
|
||||
<span>{record.course_summary}</span>
|
||||
<Popconfirm
|
||||
placement="top"
|
||||
title="修改摘要"
|
||||
description={
|
||||
<Input
|
||||
defaultValue={record.course_summary}
|
||||
onChange={(e: any) =>
|
||||
setEditCourseItem({
|
||||
key: "course_summary",
|
||||
value: e.target.value,
|
||||
})
|
||||
}
|
||||
/>
|
||||
}
|
||||
onConfirm={() => onConfirmEditCourseItem(record)}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Button type="text" icon={<EditFilled />} />
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "创建时间",
|
||||
dataIndex: "course_createtime",
|
||||
key: "course_createtime",
|
||||
render: (_: any, record: any) => {
|
||||
return (
|
||||
<Space>
|
||||
<span>
|
||||
{dayjs(+record.course_createtime).format("YYYY-MM-DD HH:mm:ss")}
|
||||
</span>
|
||||
<Popconfirm
|
||||
placement="top"
|
||||
title="时间"
|
||||
description={
|
||||
<DatePicker
|
||||
onChange={(date: any) => {
|
||||
setEditCourseItem({
|
||||
key: "course_createtime",
|
||||
value: "" + new Date(date).getTime(),
|
||||
});
|
||||
}}
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
showTime={{ defaultValue: dayjs("00:00:00", "HH:mm:ss") }}
|
||||
/>
|
||||
}
|
||||
onConfirm={() => onConfirmEditCourseItem(record)}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Button type="text" icon={<FieldTimeOutlined />} />
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "封面",
|
||||
dataIndex: "course_cover_url",
|
||||
key: "course_cover_url",
|
||||
render: (_: any, record: any) => {
|
||||
return <Image width={120} src={record.course_cover_url} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "可见",
|
||||
dataIndex: "visible",
|
||||
key: "visible",
|
||||
render: (_: any, record: any) => {
|
||||
return (
|
||||
<Switch
|
||||
checkedChildren="开启"
|
||||
unCheckedChildren="关闭"
|
||||
defaultChecked={record.valid}
|
||||
onChange={(value: boolean) =>
|
||||
updateCourse({ ...record, valid: value }).then((res: any) => {
|
||||
if (res?.code === 10000) {
|
||||
renderCourseTable();
|
||||
setEditCourseItem(defaultEditItem);
|
||||
}
|
||||
})
|
||||
}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
dataIndex: "operation",
|
||||
key: "operation",
|
||||
render: (_: any, record: any) => {
|
||||
return (
|
||||
<Space>
|
||||
<Popconfirm
|
||||
placement="top"
|
||||
title="确定删除课程嘛"
|
||||
onConfirm={() => onConfirmDeleteCourseItem(record)}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Button type="dashed" danger icon={<DeleteOutlined />}></Button>
|
||||
</Popconfirm>
|
||||
<Tooltip title="添加章节">
|
||||
<Button
|
||||
type="default"
|
||||
onClick={() => onAddChapter(record)}
|
||||
icon={<FileAddOutlined />}
|
||||
></Button>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
useEffect(() => {}, [courseList]);
|
||||
|
||||
const renderCourseTable = () => {
|
||||
selectCourseList({ all: true }).then((res) => {
|
||||
const { data } = res;
|
||||
setCourseList(data.map((i: any) => ({ ...i, key: i.course_id })));
|
||||
});
|
||||
};
|
||||
|
||||
useMount(() => {
|
||||
renderCourseTable();
|
||||
});
|
||||
|
||||
const expandedRowRender = () => {
|
||||
const col: any = [
|
||||
{
|
||||
title: "级别",
|
||||
dataIndex: "chapter_level",
|
||||
key: "chapter_level",
|
||||
render: (_: any, record: any) => {
|
||||
return (
|
||||
<Space>
|
||||
<span>{record.chapter_level}</span>
|
||||
<Popconfirm
|
||||
placement="top"
|
||||
title="修改级别"
|
||||
description={
|
||||
<Input
|
||||
defaultValue={record.chapter_level}
|
||||
onChange={(e: any) =>
|
||||
setEditChapterItem({
|
||||
key: "chapter_level",
|
||||
value: e.target.value,
|
||||
})
|
||||
}
|
||||
/>
|
||||
}
|
||||
onConfirm={() => onConfirmEditChapterItem(record)}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Button type="text" icon={<EditOutlined />} />
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
title: "章节",
|
||||
dataIndex: "chapter_title",
|
||||
key: "chapter_title",
|
||||
render: (_: any, record: any) => {
|
||||
return (
|
||||
<Space>
|
||||
<span>{record.chapter_title}</span>
|
||||
<Popconfirm
|
||||
placement="top"
|
||||
title="修改章节标题名"
|
||||
description={
|
||||
<Input
|
||||
defaultValue={record.chapter_title}
|
||||
onChange={(e: any) =>
|
||||
setEditChapterItem({
|
||||
key: "chapter_title",
|
||||
value: e.target.value,
|
||||
})
|
||||
}
|
||||
/>
|
||||
}
|
||||
onConfirm={() => onConfirmEditChapterItem(record)}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Button type="text" icon={<EditOutlined />} />
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "FileID",
|
||||
dataIndex: "chapter_file_id",
|
||||
key: "chapter_file_id",
|
||||
render: (_: any, record: any) => {
|
||||
return +record.chapter_level === 2 ? (
|
||||
<Space>
|
||||
<span>{record.chapter_file_id}</span>
|
||||
<Popconfirm
|
||||
placement="top"
|
||||
title="修改FileID"
|
||||
description={
|
||||
<Input
|
||||
defaultValue={record.chapter_file_id}
|
||||
onChange={(e: any) =>
|
||||
setEditChapterItem({
|
||||
key: "chapter_file_id",
|
||||
value: e.target.value,
|
||||
})
|
||||
}
|
||||
/>
|
||||
}
|
||||
onConfirm={() => onConfirmEditChapterItem(record)}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Button type="text" icon={<EditOutlined />} />
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
) : (
|
||||
"-"
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "顺序",
|
||||
dataIndex: "order",
|
||||
key: "order",
|
||||
render: (_: any, record: any) => {
|
||||
return (
|
||||
<Space>
|
||||
<span>{record.order}</span>
|
||||
<Popconfirm
|
||||
placement="top"
|
||||
title="修改顺序"
|
||||
description={
|
||||
<Input
|
||||
defaultValue={record.order}
|
||||
onChange={(e: any) =>
|
||||
setEditChapterItem({
|
||||
key: "order",
|
||||
value: +e.target.value,
|
||||
})
|
||||
}
|
||||
/>
|
||||
}
|
||||
onConfirm={() => onConfirmEditChapterItem(record)}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Button type="text" icon={<EditOutlined />} />
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "时长",
|
||||
dataIndex: "media_time",
|
||||
key: "media_time",
|
||||
render: (_: any, record: any) => {
|
||||
return +record.chapter_level === 2 ? (
|
||||
<Space>
|
||||
<span>{record.media_time}</span>
|
||||
</Space>
|
||||
) : (
|
||||
"-"
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
dataIndex: "operation_chapter",
|
||||
key: "operation_chapter",
|
||||
render: (_: any, record: any) => {
|
||||
return (
|
||||
<Space>
|
||||
<Popconfirm
|
||||
placement="top"
|
||||
title="确定删除章节嘛"
|
||||
onConfirm={() => onConfirmDeleteChapterItem(record)}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Button type="dashed" danger icon={<DeleteOutlined />}></Button>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
return <Table columns={col} dataSource={chapterList} pagination={false} />;
|
||||
};
|
||||
|
||||
const renderChapterList = (chapter_course_id: string) => {
|
||||
selectChapterList({ chapter_course_id }).then((res: any) => {
|
||||
const { data = [] } = res;
|
||||
setChapterList(data.map((i: any) => ({ ...i, key: i.chapter_id })));
|
||||
});
|
||||
};
|
||||
|
||||
const onExpand = (expand: boolean, record: any) => {
|
||||
if (expand) {
|
||||
const { course_id: chapter_course_id } = record;
|
||||
renderChapterList(chapter_course_id);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="list">
|
||||
<Card>
|
||||
<Table
|
||||
dataSource={courseList}
|
||||
columns={columns}
|
||||
expandable={{ expandedRowRender }}
|
||||
onExpand={onExpand}
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -3,6 +3,8 @@ import { Context } from '@midwayjs/koa';
|
|||
import { BizCode } from '../biz/code';
|
||||
import { WEB } from '../config/base.config';
|
||||
import { CourseCreateDTO } from '../dto/course.dto';
|
||||
import { Chapter } from '../entity/chapter.entity';
|
||||
import { Course } from '../entity/course.entity';
|
||||
import { ChapterService } from '../service/chapter.service';
|
||||
import { CourseService } from '../service/course.service';
|
||||
import { GuideService } from '../service/guide.service';
|
||||
|
@ -52,8 +54,9 @@ export class CourseController {
|
|||
}
|
||||
|
||||
@Post('/select/all')
|
||||
async selectAll() {
|
||||
const courseList = await this.courseService.selectAll();
|
||||
async selectAll(@Body() params) {
|
||||
const { all = false } = params;
|
||||
const courseList = await this.courseService.selectAll(all);
|
||||
return { code: BizCode.OK, data: courseList };
|
||||
}
|
||||
|
||||
|
@ -72,7 +75,75 @@ export class CourseController {
|
|||
const guide = await this.guideService.select(course_id);
|
||||
return { code: BizCode.OK, data: { chapterList, guide, course } };
|
||||
} catch (error) {
|
||||
this.ctx.logger.error(error);
|
||||
return { code: BizCode.ERROR, msg: '[error] /chapter/select error' };
|
||||
}
|
||||
}
|
||||
|
||||
@Post('/update')
|
||||
async updateCourse(@Body() course: Course) {
|
||||
try {
|
||||
await this.courseService.update(course);
|
||||
return { code: BizCode.OK };
|
||||
} catch (error) {
|
||||
this.ctx.logger.error(error);
|
||||
return { code: BizCode.ERROR, msg: error };
|
||||
}
|
||||
}
|
||||
|
||||
@Post('/chapter/select')
|
||||
async selectChapterList(@Body() chapter: Chapter) {
|
||||
const { chapter_course_id } = chapter;
|
||||
const chapterList = await this.chapterService.select(chapter_course_id);
|
||||
return { code: BizCode.OK, data: chapterList };
|
||||
}
|
||||
|
||||
@Post('/chapter/update')
|
||||
async updateChapter(@Body() chapter: Chapter) {
|
||||
try {
|
||||
await this.chapterService.update(chapter);
|
||||
return { code: BizCode.OK };
|
||||
} catch (error) {
|
||||
this.ctx.logger.error(error);
|
||||
return { code: BizCode.ERROR, msg: error };
|
||||
}
|
||||
}
|
||||
|
||||
@Post('/remove')
|
||||
async remove(@Body() course: Course) {
|
||||
const { course_id } = course;
|
||||
try {
|
||||
await this.courseService.remove(course_id);
|
||||
await this.chapterService.removeByCourseId(course_id);
|
||||
await this.guideService.removeByCourseId(course_id);
|
||||
return { code: BizCode.OK };
|
||||
} catch (error) {
|
||||
this.ctx.logger.error(error);
|
||||
return { code: BizCode.ERROR, msg: error };
|
||||
}
|
||||
}
|
||||
|
||||
@Post('/chapter/create')
|
||||
async createChapter(@Body() chapterList: Chapter[]) {
|
||||
try {
|
||||
// order默认为-1
|
||||
await this.chapterService.create(chapterList);
|
||||
return { code: BizCode.OK };
|
||||
} catch (error) {
|
||||
this.ctx.logger.error(error);
|
||||
return { code: BizCode.ERROR, msg: error };
|
||||
}
|
||||
}
|
||||
|
||||
@Post('/chapter/remove')
|
||||
async removeChapter(@Body() chapter: Chapter) {
|
||||
try {
|
||||
const { chapter_id } = chapter;
|
||||
await this.chapterService.remove(chapter_id);
|
||||
return { code: BizCode.OK };
|
||||
} catch (error) {
|
||||
this.ctx.logger.error(error);
|
||||
return { code: BizCode.ERROR, msg: error };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,18 +6,18 @@ export class Chapter {
|
|||
chapter_id?: string;
|
||||
|
||||
@Column({ type: 'text' })
|
||||
chapter_title: string;
|
||||
chapter_title?: string;
|
||||
|
||||
@Column()
|
||||
chapter_level: '1' | '2';
|
||||
chapter_level?: '1' | '2';
|
||||
|
||||
@Column({ default: '' })
|
||||
chapter_file_id?: string;
|
||||
|
||||
@Column()
|
||||
chapter_course_id: string;
|
||||
chapter_course_id?: string;
|
||||
|
||||
@Column()
|
||||
@Column({ default: -1 })
|
||||
order?: number;
|
||||
|
||||
@Column({ default: '' })
|
||||
|
|
|
@ -43,6 +43,7 @@ export class AuthMiddleware implements IMiddleware<Context, NextFunction> {
|
|||
}
|
||||
await next();
|
||||
} catch (error) {
|
||||
ctx.logger.error(error);
|
||||
return { code: BizCode.AUTH, msg: '身份验证错误' };
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -36,4 +36,16 @@ export class ChapterService {
|
|||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
async update(chapter: Chapter) {
|
||||
await this.chapterModel.save(chapter);
|
||||
}
|
||||
|
||||
async removeByCourseId(course_id: string) {
|
||||
await this.chapterModel.delete({ chapter_course_id: course_id });
|
||||
}
|
||||
|
||||
async remove(chapter_id: string) {
|
||||
await this.chapterModel.delete({ chapter_id });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,12 +24,21 @@ export class CourseService {
|
|||
return courseCreateRes.course_id;
|
||||
}
|
||||
|
||||
async selectAll() {
|
||||
return await this.courseModel.find({ where: { valid: true } });
|
||||
async selectAll(all) {
|
||||
if (!all) return await this.courseModel.find({ where: { valid: true } });
|
||||
else return await this.courseModel.find();
|
||||
}
|
||||
|
||||
async select(course: Course) {
|
||||
const { course_id } = course;
|
||||
return await this.courseModel.findOne({ where: { course_id } });
|
||||
}
|
||||
|
||||
async update(course: Course) {
|
||||
return await this.courseModel.save(course);
|
||||
}
|
||||
|
||||
async remove(course_id: string) {
|
||||
await this.courseModel.delete({ course_id });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,4 +21,8 @@ export class GuideService {
|
|||
where: { guide_course_id: course_id },
|
||||
});
|
||||
}
|
||||
|
||||
async removeByCourseId(course_id: string) {
|
||||
await this.guideModel.delete({ guide_course_id: course_id });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
grid-row-gap: 10px;
|
||||
|
||||
.course-card {
|
||||
cursor: pointer;
|
||||
border-radius: 3px;
|
||||
.cover {
|
||||
height: 120px;
|
||||
|
|
Loading…
Reference in New Issue
Block a user