feat:初始化 -融骅
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Body,
|
||||
Patch,
|
||||
Param,
|
||||
Delete,
|
||||
Query,
|
||||
} from '@nestjs/common';
|
||||
|
||||
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||
import { TokenData } from 'src/common/decorator/token-data.decorator';
|
||||
|
||||
import { CreateLiveTeachingDto } from '../dto/live-create.dto';
|
||||
import { UpdateLiveTeachingDto } from '../dto/live-update.dto';
|
||||
import { LiveClassService } from '../service/live-class.service';
|
||||
import { PaginationDTO } from '../../online-course/common/pagination.dto';
|
||||
import { CreateCourseclassifyDto } from 'src/online-course/dto/course-manage/course-classify.dto';
|
||||
import { updateCourseclassifyDto } from 'src/online-course/dto/course-manage/update-course-classify.dto';
|
||||
import { DeleteDto } from 'src/online-course/common/delete-dto';
|
||||
import { get } from 'http';
|
||||
import { NoAuthToken } from 'src/common/decorator/no-token.decorator';
|
||||
import {
|
||||
SearchLsitDto,
|
||||
SearchNoClassLsitDto,
|
||||
} from 'src/online-course/dto/course-manage/get-course-list-dto';
|
||||
import { LiveAnsweringDto } from '../dto/live-question-answer.dto';
|
||||
@ApiTags('在线教学-学员端')
|
||||
@ApiBearerAuth()
|
||||
// @NoAuthToken()
|
||||
@Controller('live-class')
|
||||
export class LiveClassController {
|
||||
constructor(private readonly LiveClassService: LiveClassService) {}
|
||||
// 获取需要参加的直播列表
|
||||
@Get()
|
||||
@ApiOperation({ summary: '获取我的直播列表' })
|
||||
findLiveForMy(@Query() pageInfo: PaginationDTO, @TokenData() tokenInfo: any) {
|
||||
return this.LiveClassService.findMyLiveList(pageInfo, tokenInfo);
|
||||
}
|
||||
@Get('search')
|
||||
@ApiOperation({ summary: '搜索我的直播列表' })
|
||||
searchMyLiveList(
|
||||
@Query() searchInfo: SearchNoClassLsitDto,
|
||||
@TokenData() tokenInfo: any,
|
||||
) {
|
||||
return this.LiveClassService.searchMyLiveList(searchInfo, tokenInfo);
|
||||
}
|
||||
@Get('question/:liveId')
|
||||
@ApiOperation({ summary: '获取所有试题列表' })
|
||||
getLiveQuestionList(@Param('liveId') liveId: number) {
|
||||
return this.LiveClassService.getLiveQuestionList(liveId);
|
||||
}
|
||||
@Get('liveStudent/:id')
|
||||
@ApiOperation({ summary: '参加直播时获取详情' })
|
||||
getStudentList(@Param('id') id: number, @TokenData() tokenInfo: any) {
|
||||
return this.LiveClassService.getStudentList(id, tokenInfo);
|
||||
}
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: '参加直播时获取详情' })
|
||||
getLiveInfo(@Param('id') id: number, @TokenData() tokenInfo: any) {
|
||||
return this.LiveClassService.getLiveInfo(id, tokenInfo);
|
||||
}
|
||||
|
||||
@Post('answering')
|
||||
@ApiOperation({ summary: '回答直播的练习题' })
|
||||
answeringQuestions(
|
||||
@Body() answerData: LiveAnsweringDto,
|
||||
@TokenData() tokenData,
|
||||
) {
|
||||
return this.LiveClassService.answeringQuestions(answerData, tokenData);
|
||||
}
|
||||
}
|
||||
116
serve/src/online-teaching/controller/live-teaching.controller.ts
Normal file
116
serve/src/online-teaching/controller/live-teaching.controller.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Body,
|
||||
Patch,
|
||||
Param,
|
||||
Delete,
|
||||
Query,
|
||||
} from '@nestjs/common';
|
||||
|
||||
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||
import { TokenData } from 'src/common/decorator/token-data.decorator';
|
||||
|
||||
import { CreateLiveTeachingDto } from '../dto/live-create.dto';
|
||||
import { UpdateLiveTeachingDto } from '../dto/live-update.dto';
|
||||
import { LiveTeachingService } from '../service/live-teaching.service';
|
||||
import { PaginationDTO } from '../../online-course/common/pagination.dto';
|
||||
import { CreateCourseclassifyDto } from 'src/online-course/dto/course-manage/course-classify.dto';
|
||||
import { updateCourseclassifyDto } from 'src/online-course/dto/course-manage/update-course-classify.dto';
|
||||
import { DeleteDto } from 'src/online-course/common/delete-dto';
|
||||
import { get } from 'http';
|
||||
import { SearchLsitDto } from 'src/online-course/dto/course-manage/get-course-list-dto';
|
||||
import { NoAuthToken } from 'src/common/decorator/no-token.decorator';
|
||||
@ApiTags('在线教学')
|
||||
@ApiBearerAuth()
|
||||
// @NoAuthToken()
|
||||
@Controller('live-teaching')
|
||||
export class LiveTeachingController {
|
||||
constructor(private readonly LiveTeachingService: LiveTeachingService) {}
|
||||
// 获取直播列表
|
||||
@Get()
|
||||
@ApiOperation({ summary: '获取直播列表' })
|
||||
findLiveList(@Query() pageInfo: PaginationDTO, @TokenData() tokenInfo: any) {
|
||||
return this.LiveTeachingService.findLiveList(pageInfo, tokenInfo);
|
||||
}
|
||||
|
||||
@Get('live-publish/:id')
|
||||
@ApiOperation({ summary: '教员端直播时获取直播详情' })
|
||||
getLiveInfo(@Param('id') id: number, @TokenData() tokenInfo: any) {
|
||||
return this.LiveTeachingService.getLiveInfo(id, tokenInfo);
|
||||
}
|
||||
|
||||
// 编辑时获取某个直播的详细信息
|
||||
@Get(':id')
|
||||
@NoAuthToken()
|
||||
@ApiOperation({ summary: '获取某个直播的详细信息' })
|
||||
findOneInfo(@Param('id') id: number, @TokenData() tokenInfo: any) {
|
||||
return this.LiveTeachingService.findOneInfo(id, tokenInfo);
|
||||
}
|
||||
// 搜索直播名称
|
||||
@NoAuthToken()
|
||||
@Post('search')
|
||||
@ApiOperation({ summary: '搜索直播' })
|
||||
searchSomeLive(@Body() searchInfo: SearchLsitDto) {
|
||||
return this.LiveTeachingService.searchSomeLive(searchInfo);
|
||||
}
|
||||
// 更新课件的学习信息
|
||||
@Post()
|
||||
@ApiOperation({ summary: '新建直播' })
|
||||
createLive(
|
||||
@Body() LiveInfo: CreateLiveTeachingDto,
|
||||
@TokenData() tokenInfo: any,
|
||||
) {
|
||||
return this.LiveTeachingService.createLive(LiveInfo, tokenInfo);
|
||||
}
|
||||
|
||||
@Patch()
|
||||
@ApiOperation({ summary: '更新直播信息' })
|
||||
updateLive(
|
||||
@Body() LiveInfo: UpdateLiveTeachingDto,
|
||||
@TokenData() tokenInfo: any,
|
||||
) {
|
||||
return this.LiveTeachingService.updateLive(LiveInfo, tokenInfo);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@ApiOperation({ summary: '删除直播' })
|
||||
deleteLive(@Param('id') id: [string], @TokenData() tokenInfo: any) {
|
||||
let sId: any = id;
|
||||
sId = sId.split(',');
|
||||
return this.LiveTeachingService.deleteLive(sId, tokenInfo);
|
||||
}
|
||||
@Post('update')
|
||||
updateLiveInfo(@Body() data: object) {
|
||||
return this.LiveTeachingService.updateLiveInfo(data);
|
||||
}
|
||||
// -------------------分类模块------------------ //
|
||||
// 分类查询
|
||||
@Get('classify')
|
||||
@ApiOperation({ summary: '查询所有分类' })
|
||||
getclassifyList() {
|
||||
return this.LiveTeachingService.getclassifyList();
|
||||
}
|
||||
// 新建分类
|
||||
@Post('classify')
|
||||
@ApiOperation({ summary: '新增分类' })
|
||||
createclassify(@Body() createclassify: CreateCourseclassifyDto) {
|
||||
return this.LiveTeachingService.createclassify(createclassify);
|
||||
}
|
||||
// 编辑分类
|
||||
@Patch('classify/:id')
|
||||
@ApiOperation({ summary: '编辑分类' })
|
||||
updateCourseclassify(
|
||||
@Param('id') id: number,
|
||||
@Body() updateclassify: updateCourseclassifyDto,
|
||||
) {
|
||||
return this.LiveTeachingService.updateclassify(id, updateclassify);
|
||||
}
|
||||
// 删除分类
|
||||
@Post('classify/delete')
|
||||
@ApiOperation({ summary: '删除分类' })
|
||||
deleteCourseclassify(@Body() id: DeleteDto) {
|
||||
return this.LiveTeachingService.deleteclassify(id);
|
||||
}
|
||||
}
|
||||
18
serve/src/online-teaching/dto/live-classify.dto.ts
Normal file
18
serve/src/online-teaching/dto/live-classify.dto.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { isNotEmpty, IsNotEmpty, IsNumber, IsString } from 'class-validator';
|
||||
import { CreateDto } from 'src/common/dto/create.dto';
|
||||
export class CreateLiveclassifyDto extends CreateDto {
|
||||
@ApiProperty({ description: '分类父级ID', default: 0 })
|
||||
@IsNotEmpty({ message: '分类父级ID不可为空' })
|
||||
@IsNumber()
|
||||
pid: number;
|
||||
|
||||
@ApiProperty({ description: '分类名称', default: '新增的分类' })
|
||||
@IsNotEmpty({ message: '分类名称不可为空' })
|
||||
name: string;
|
||||
|
||||
@ApiProperty({ description: '分类层级', default: 1 })
|
||||
@IsNotEmpty({ message: '分类层级不可为空' })
|
||||
@IsNumber()
|
||||
level: number;
|
||||
}
|
||||
102
serve/src/online-teaching/dto/live-create.dto.ts
Normal file
102
serve/src/online-teaching/dto/live-create.dto.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import {
|
||||
IsArray,
|
||||
IsDate,
|
||||
IsNotEmpty,
|
||||
IsNumber,
|
||||
isString,
|
||||
IsString,
|
||||
} from 'class-validator';
|
||||
import { CreateDto } from 'src/common/dto/create.dto';
|
||||
/**
|
||||
* 直播信息
|
||||
*/
|
||||
export class CreateLiveTeachingDto extends CreateDto {
|
||||
@ApiProperty({ description: '直播标题' })
|
||||
@IsNotEmpty({ message: '直播标题不可为空' })
|
||||
@IsString()
|
||||
title: string;
|
||||
|
||||
@ApiProperty({ description: '直播开始时间', default: new Date() })
|
||||
@IsNotEmpty({ message: '直播开始时间不可为空' })
|
||||
startTime: Date;
|
||||
|
||||
@ApiProperty({ description: '直播真实开始时间', default: new Date() })
|
||||
actualStartTime: Date;
|
||||
|
||||
@ApiProperty({ description: '直播真实结束时间', default: new Date() })
|
||||
actualEndTime: Date;
|
||||
|
||||
@ApiProperty({ description: '直播时长' })
|
||||
duration: number;
|
||||
|
||||
@ApiProperty({ description: '直播分类' })
|
||||
@IsNotEmpty({ message: '直播分类不可为空' })
|
||||
@IsNumber()
|
||||
classify: number;
|
||||
|
||||
@ApiProperty({ description: '直播分类' })
|
||||
@IsString()
|
||||
explain: string;
|
||||
|
||||
@ApiProperty({ description: '直播封面地址' })
|
||||
cover: string;
|
||||
|
||||
@ApiProperty({ description: ' 直播状态 0/1/2 未开始/进行中/已结束' })
|
||||
status: string;
|
||||
|
||||
@ApiProperty({ description: '暖场图片' })
|
||||
warmUpPicture: string;
|
||||
|
||||
@ApiProperty({ description: '暖场音乐' })
|
||||
warmUpMusice: string;
|
||||
|
||||
@ApiProperty({ description: '是否支持回放', default: 0 })
|
||||
@IsNumber()
|
||||
playback: number;
|
||||
|
||||
@ApiProperty({ description: '回放停止观看时间', default: null })
|
||||
playbackDeadline: Date;
|
||||
|
||||
@ApiProperty({ description: '讲师' })
|
||||
@IsNotEmpty({ message: '直播讲师不可为空' })
|
||||
@IsString()
|
||||
lecturer: string;
|
||||
|
||||
@ApiProperty({ description: '是否开启讨论', default: 0 })
|
||||
@IsNumber()
|
||||
openDiscussion: number;
|
||||
|
||||
@ApiProperty({ description: '是否开启评价', default: 0 })
|
||||
@IsNumber()
|
||||
openEval: number;
|
||||
|
||||
@ApiProperty({ description: '文本评价或维度评价', default: 0 })
|
||||
@IsNumber()
|
||||
txtOrGradeEvealute: number;
|
||||
|
||||
@ApiProperty({ description: '文本评价标题', default: '' })
|
||||
@IsString()
|
||||
textEvaluateTitle: string;
|
||||
|
||||
@ApiProperty({ description: '可以观看直播的学生ID', default: [] })
|
||||
@IsArray()
|
||||
liveStudent: [number];
|
||||
|
||||
@ApiProperty({ description: '直播的课后试题', default: [] })
|
||||
@IsArray()
|
||||
liveQuestion: [number];
|
||||
|
||||
@ApiProperty({ description: '直播的评价维度设置', default: [] })
|
||||
@IsArray()
|
||||
evalDimension: [
|
||||
{
|
||||
dimensionality: string;
|
||||
type: number;
|
||||
},
|
||||
];
|
||||
|
||||
@ApiProperty({ description: '直播的课件ID', default: [] })
|
||||
@IsArray()
|
||||
liveCourseware: [number];
|
||||
}
|
||||
22
serve/src/online-teaching/dto/live-msg-data.dto.ts
Normal file
22
serve/src/online-teaching/dto/live-msg-data.dto.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { User } from 'src/system/entities/user.entity';
|
||||
|
||||
/**
|
||||
* 课程评价维度
|
||||
*/
|
||||
export class LiveMsgDataDto {
|
||||
@ApiProperty({ description: '消息发送人' })
|
||||
from: User;
|
||||
|
||||
@ApiProperty({ description: '房间ID' })
|
||||
roomId: string;
|
||||
|
||||
@ApiProperty({ description: '消息类型' })
|
||||
type: string;
|
||||
|
||||
@ApiProperty({ description: '消息' })
|
||||
msg: string;
|
||||
|
||||
@ApiProperty({ description: '发送时间' })
|
||||
timestamp: number;
|
||||
}
|
||||
36
serve/src/online-teaching/dto/live-question-answer.dto.ts
Normal file
36
serve/src/online-teaching/dto/live-question-answer.dto.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsNotEmpty, IsNumber } from 'class-validator';
|
||||
import { CreateDto } from 'src/common/dto/create.dto';
|
||||
|
||||
/**
|
||||
* 学员课程课后习题
|
||||
*/
|
||||
export class LiveQuestionAnswerDto extends CreateDto {
|
||||
@ApiProperty({ description: '所属的直播ID' })
|
||||
@IsNotEmpty({ message: '所属的直播ID不能为空' })
|
||||
@IsNumber()
|
||||
liveId: number;
|
||||
|
||||
@ApiProperty({ description: '练习题ID' })
|
||||
@IsNotEmpty({ message: '练习题ID不能为空' })
|
||||
@IsNumber()
|
||||
exerciseId: number;
|
||||
|
||||
@ApiProperty({ description: '答案信息' })
|
||||
@IsNotEmpty({ message: '答案信息不可为空' })
|
||||
answer: string;
|
||||
@ApiProperty({ description: '是否正确' })
|
||||
@IsNotEmpty({ message: '是否正确不可为空' })
|
||||
isRight: number;
|
||||
}
|
||||
|
||||
export class LiveAnsweringDto {
|
||||
@ApiProperty({ description: '练习题答案信息提交' })
|
||||
@IsNotEmpty({ message: '答题不可为空' })
|
||||
answerInfo: [{ questionId: number; answer: [string] }];
|
||||
@ApiProperty({ description: '当前答案所属的直播id' })
|
||||
@IsNotEmpty({ message: '当前问题所属的直播id不可为空' })
|
||||
liveId: number;
|
||||
@ApiProperty({ description: '练习题创建时间' })
|
||||
createTime: Date;
|
||||
}
|
||||
9
serve/src/online-teaching/dto/live-update.dto.ts
Normal file
9
serve/src/online-teaching/dto/live-update.dto.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { CreateLiveTeachingDto } from './live-create.dto';
|
||||
/**
|
||||
* 直播信息
|
||||
*/
|
||||
export class UpdateLiveTeachingDto extends CreateLiveTeachingDto {
|
||||
@ApiProperty({ description: '需要更新的id' })
|
||||
id: number;
|
||||
}
|
||||
28
serve/src/online-teaching/entities/live-classify.entity.ts
Normal file
28
serve/src/online-teaching/entities/live-classify.entity.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { IncrementIdEntity } from 'src/common/entities/increment-id.entity';
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
|
||||
|
||||
/**
|
||||
* 在线教学课件
|
||||
*/
|
||||
@Entity()
|
||||
export class LiveClassify {
|
||||
@PrimaryGeneratedColumn('increment')
|
||||
id: number;
|
||||
|
||||
@Column({ comment: '父级ID' })
|
||||
pid: number;
|
||||
|
||||
@Column({ comment: '分类名称', type: 'text' })
|
||||
name: string;
|
||||
|
||||
@Column({ comment: '层级' })
|
||||
level: number;
|
||||
|
||||
@Column({
|
||||
default: 0,
|
||||
select: false,
|
||||
name: 'del_flag',
|
||||
comment: '是否删除:0否/1是',
|
||||
})
|
||||
delFlag: number;
|
||||
}
|
||||
25
serve/src/online-teaching/entities/live-courseware.entity.ts
Normal file
25
serve/src/online-teaching/entities/live-courseware.entity.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { IncrementIdEntity } from 'src/common/entities/increment-id.entity';
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
|
||||
|
||||
/**
|
||||
* 在线教学课件
|
||||
*/
|
||||
@Entity()
|
||||
export class LiveCourseware {
|
||||
@PrimaryGeneratedColumn('increment')
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'file_id', comment: '课件id' })
|
||||
fileId: number;
|
||||
|
||||
@Column({ name: 'live_id', comment: '直播id' })
|
||||
liveId: number;
|
||||
|
||||
@Column({
|
||||
default: 0,
|
||||
select: false,
|
||||
name: 'del_flag',
|
||||
comment: '是否删除:0否/1是',
|
||||
})
|
||||
delFlag: number;
|
||||
}
|
||||
27
serve/src/online-teaching/entities/live-evaluate.entity.ts
Normal file
27
serve/src/online-teaching/entities/live-evaluate.entity.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
|
||||
|
||||
/**
|
||||
* 课程评价维度
|
||||
*/
|
||||
@Entity()
|
||||
export class LiveEvaluate {
|
||||
@PrimaryGeneratedColumn('increment')
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'coruse_id', comment: '课程ID' })
|
||||
liveId: number;
|
||||
|
||||
@Column({ comment: '维度名称', type: 'text' })
|
||||
dimensionality: string;
|
||||
|
||||
@Column({ comment: '0/1 直播评价或学院自评', default: 0 })
|
||||
type: number;
|
||||
|
||||
@Column({
|
||||
default: 0,
|
||||
select: false,
|
||||
name: 'del_flag',
|
||||
comment: '是否删除:0否/1是',
|
||||
})
|
||||
delFlag: number;
|
||||
}
|
||||
45
serve/src/online-teaching/entities/live-msg-data.entity.ts
Normal file
45
serve/src/online-teaching/entities/live-msg-data.entity.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
|
||||
|
||||
@Entity()
|
||||
export class LiveMsgData {
|
||||
@PrimaryGeneratedColumn('increment')
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'from_id', type: 'text', comment: '发送人ID' })
|
||||
fromId: string;
|
||||
|
||||
@Column({ name: 'room_id', type: 'text', comment: '房间ID' })
|
||||
roomId: string;
|
||||
|
||||
@Column({ type: 'text', comment: '消息类型' })
|
||||
type: string;
|
||||
|
||||
@Column({ type: 'text', nullable: true, comment: '消息' })
|
||||
msg: string;
|
||||
|
||||
@Column({ type: 'bigint', comment: '发送时间' })
|
||||
timestamp: number;
|
||||
|
||||
@Column({
|
||||
name: 'total_user',
|
||||
comment: '当前房间总人数',
|
||||
default: 0,
|
||||
})
|
||||
totalUser: number;
|
||||
|
||||
@Column({
|
||||
type: 'text',
|
||||
nullable: true,
|
||||
name: 'mag_srt',
|
||||
comment: 'string 消息',
|
||||
})
|
||||
msgStr: string;
|
||||
|
||||
@Column({
|
||||
default: 0,
|
||||
select: false,
|
||||
name: 'del_flag',
|
||||
comment: '是否删除:0否/1是',
|
||||
})
|
||||
delFlag: number;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { IncrementIdEntity } from 'src/common/entities/increment-id.entity';
|
||||
import { Column, Entity } from 'typeorm';
|
||||
|
||||
/**
|
||||
* 学员课程课后习题
|
||||
*/
|
||||
@Entity()
|
||||
export class LiveQuestionAnswer extends IncrementIdEntity {
|
||||
@Column({ name: 'record_id', comment: '学习记录Id' })
|
||||
liveId: number;
|
||||
|
||||
@Column({ name: 'question_id', comment: '试题ID' })
|
||||
questionId: number;
|
||||
|
||||
@Column({ name: 'question_score', comment: '该题分值' })
|
||||
questionScore: number;
|
||||
|
||||
@Column({ comment: '我的得分' })
|
||||
score: number;
|
||||
|
||||
@Column({ name: 'mistake_score', comment: '错题得分', default: 0 })
|
||||
mistakeScore: number;
|
||||
|
||||
@Column({ name: 'user_answer', type: 'longtext', comment: '我的答案' })
|
||||
userAnswer: string;
|
||||
|
||||
@Column({ comment: '老师的评语', default: null, type: 'longtext' })
|
||||
comment: string;
|
||||
}
|
||||
34
serve/src/online-teaching/entities/live-question.entity.ts
Normal file
34
serve/src/online-teaching/entities/live-question.entity.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { IncrementIdEntity } from 'src/common/entities/increment-id.entity';
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
|
||||
|
||||
/**
|
||||
* 在线教学答题
|
||||
*/
|
||||
@Entity()
|
||||
export class LiveQuestion {
|
||||
@PrimaryGeneratedColumn('increment')
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'live_id', comment: '直播id' })
|
||||
liveId: number;
|
||||
|
||||
@Column({ name: 'question_id', comment: '试题ID(对应Question表)' })
|
||||
questionId: number;
|
||||
|
||||
@Column({ comment: '该题分值' })
|
||||
score: number;
|
||||
|
||||
@Column({ comment: '题类型' })
|
||||
type: number;
|
||||
|
||||
@Column({ name: 'is_fixed', comment: '固定选题、随机选题' })
|
||||
isFixed: number;
|
||||
|
||||
@Column({
|
||||
default: 0,
|
||||
select: false,
|
||||
name: 'del_flag',
|
||||
comment: '是否删除:0否/1是',
|
||||
})
|
||||
delFlag: number;
|
||||
}
|
||||
25
serve/src/online-teaching/entities/live-student.entity.ts
Normal file
25
serve/src/online-teaching/entities/live-student.entity.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { IncrementIdEntity } from 'src/common/entities/increment-id.entity';
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
|
||||
|
||||
/**
|
||||
* 在线教学观众
|
||||
*/
|
||||
@Entity()
|
||||
export class LiveStudent {
|
||||
@PrimaryGeneratedColumn('increment')
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'student_id', type: 'longtext', comment: '学员id' })
|
||||
studentId: string;
|
||||
|
||||
@Column({ name: 'live_id', comment: '直播id' })
|
||||
liveId: number;
|
||||
|
||||
@Column({
|
||||
default: 0,
|
||||
select: false,
|
||||
name: 'del_flag',
|
||||
comment: '是否删除:0否/1是',
|
||||
})
|
||||
delFlag: number;
|
||||
}
|
||||
95
serve/src/online-teaching/entities/live-teaching.entity.ts
Normal file
95
serve/src/online-teaching/entities/live-teaching.entity.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { IncrementIdEntity } from 'src/common/entities/increment-id.entity';
|
||||
import { Column, Entity } from 'typeorm';
|
||||
|
||||
/**
|
||||
* 在线教学
|
||||
*/
|
||||
@Entity()
|
||||
export class LiveTeaching extends IncrementIdEntity {
|
||||
@Column({ type: 'longtext', comment: '直播名称' })
|
||||
title: string;
|
||||
|
||||
@Column({ name: 'start_time', comment: '开始时间' })
|
||||
startTime: Date;
|
||||
|
||||
@Column({
|
||||
name: 'actual_start_time',
|
||||
comment: '真实开始时间',
|
||||
nullable: true,
|
||||
default: null,
|
||||
})
|
||||
actualStartTime: Date;
|
||||
|
||||
@Column({
|
||||
name: 'actual_end_time',
|
||||
comment: '真实结束时间',
|
||||
nullable: true,
|
||||
default: null,
|
||||
})
|
||||
actualEndTime: Date;
|
||||
|
||||
@Column({ comment: '直播时长', default: 0 })
|
||||
duration: number;
|
||||
|
||||
@Column({ comment: '直播分类' })
|
||||
classify: number;
|
||||
|
||||
@Column({ comment: '直播简介', type: 'longtext' })
|
||||
explain: string;
|
||||
|
||||
@Column({ comment: '直播封面', type: 'longtext' })
|
||||
cover: string;
|
||||
|
||||
@Column({ comment: '直播状态 0/1/2 未开始/进行中/已结束', default: 0 })
|
||||
status: number;
|
||||
|
||||
@Column({ name: 'warm_up_picture', comment: '暖场图片', type: 'longtext' })
|
||||
warmUpPicture: string;
|
||||
|
||||
@Column({ name: 'warm_up_musice', comment: '暖场音乐', type: 'longtext' })
|
||||
warmUpMusice: string;
|
||||
|
||||
@Column({ comment: '是否回放0/1' })
|
||||
playback: number;
|
||||
|
||||
@Column({
|
||||
name: 'playback_deadline',
|
||||
comment: '回放期限',
|
||||
nullable: true,
|
||||
default: null,
|
||||
})
|
||||
playbackDeadline: Date;
|
||||
|
||||
@Column({ name: 'open_quiz', comment: '0/1开启课程问答' })
|
||||
openQuiz: number;
|
||||
|
||||
@Column({ type: 'longtext', comment: '讲师' })
|
||||
lecturer: string;
|
||||
|
||||
@Column({ name: 'open_discussion', comment: '是否开启讨论', default: 0 })
|
||||
openDiscussion: number;
|
||||
|
||||
@Column({
|
||||
name: 'open_self_evaluation',
|
||||
default: 0,
|
||||
comment: '0/1开启学员自评',
|
||||
})
|
||||
openSelfEvaluation: number;
|
||||
|
||||
@Column({ name: 'open_eval', comment: '是否开启评价', default: 0 })
|
||||
openEval: number;
|
||||
|
||||
@Column({
|
||||
name: 'txt_or_grade_evealute',
|
||||
comment: '文本或维度评价',
|
||||
default: 0,
|
||||
})
|
||||
txtOrGradeEvealute: number;
|
||||
|
||||
@Column({
|
||||
type: 'longtext',
|
||||
name: 'text_evaluate_title',
|
||||
comment: '文本评价标题',
|
||||
})
|
||||
textEvaluateTitle: string;
|
||||
}
|
||||
109
serve/src/online-teaching/gateway/online-teaching.gateway.ts
Normal file
109
serve/src/online-teaching/gateway/online-teaching.gateway.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import {
|
||||
WebSocketGateway,
|
||||
SubscribeMessage,
|
||||
OnGatewayDisconnect,
|
||||
} from '@nestjs/websockets';
|
||||
import { Socket } from 'socket.io';
|
||||
import { Repository } from 'typeorm';
|
||||
import { LiveMsgDataDto } from '../dto/live-msg-data.dto';
|
||||
import { LiveMsgData } from '../entities/live-msg-data.entity';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
@WebSocketGateway()
|
||||
export class OnlineTeachingGateway implements OnGatewayDisconnect {
|
||||
constructor(
|
||||
private jwtService: JwtService,
|
||||
@InjectRepository(LiveMsgData)
|
||||
private lmdRepository: Repository<LiveMsgData>,
|
||||
) {}
|
||||
|
||||
rooms = {};
|
||||
handleDisconnect(socket: Socket) {
|
||||
const authToken: string = socket.handshake?.auth?.token;
|
||||
const user = this.jwtService.decode(authToken.replace('Bearer ', ''));
|
||||
console.log(user, this.rooms);
|
||||
let roomId = null;
|
||||
Object.keys(this.rooms).forEach((item) => {
|
||||
if (Object.keys(this.rooms[item].users).includes(user.sub)) {
|
||||
roomId = item;
|
||||
}
|
||||
});
|
||||
|
||||
if (user?.sub && roomId) {
|
||||
const data = {
|
||||
fromId: user.sub,
|
||||
roomId: roomId,
|
||||
type: 'leave',
|
||||
msg: 'leave',
|
||||
timestamp: new Date().getTime(),
|
||||
msgStr: null,
|
||||
};
|
||||
// socket.leave(roomId);
|
||||
// delete this.rooms[roomId]?.users[user.sub];
|
||||
// this.sendRoomInfo(socket, roomId);
|
||||
return this.lmdRepository.insert(data);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@SubscribeMessage('join_live_room')
|
||||
joinLiveRoom(socket: Socket, data: LiveMsgDataDto) {
|
||||
socket.join(data.roomId);
|
||||
this.rooms[data.roomId] ??= {};
|
||||
this.rooms[data.roomId].users ??= {};
|
||||
this.rooms[data.roomId].users[data.from.id] = data.from;
|
||||
this.sendRoomInfo(socket, data.roomId);
|
||||
return this.sendLiveMsg(socket, data);
|
||||
}
|
||||
|
||||
@SubscribeMessage('send_live_msg')
|
||||
sendLiveMsg(socket: Socket, data: LiveMsgDataDto) {
|
||||
data.timestamp = new Date().getTime();
|
||||
socket.to(data.roomId).emit('received_live_msg', data);
|
||||
this.saveMsg(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
@SubscribeMessage('leave_live_room')
|
||||
leaveRoom(socket: Socket, data: LiveMsgDataDto) {
|
||||
if (Array.isArray(data)) {
|
||||
data = data[0];
|
||||
}
|
||||
socket.leave(data.roomId);
|
||||
delete this.rooms[data.roomId]?.users[data.from.id];
|
||||
this.sendRoomInfo(socket, data.roomId);
|
||||
if (!Object.keys(this.rooms[data.roomId]?.users ?? {})) {
|
||||
delete this.rooms[data.roomId];
|
||||
}
|
||||
this.saveMsg(data);
|
||||
return this.sendLiveMsg(socket, data);
|
||||
}
|
||||
|
||||
@SubscribeMessage('find_room_info')
|
||||
findRoomInfo(socket: Socket, roomId: string) {
|
||||
return {
|
||||
users: Object.values(this.rooms[roomId]?.users ?? {}),
|
||||
};
|
||||
}
|
||||
|
||||
async saveMsg(data: LiveMsgDataDto) {
|
||||
const { from, roomId, type, msg, timestamp, ...other } = data;
|
||||
console.log(this.rooms);
|
||||
if (!from?.id) return null;
|
||||
return this.lmdRepository.insert({
|
||||
fromId: from.id,
|
||||
roomId,
|
||||
type,
|
||||
msg,
|
||||
timestamp: timestamp ? timestamp : new Date().getTime(),
|
||||
totalUser: this.rooms?.[roomId]
|
||||
? Object.keys(this.rooms[roomId].users).length
|
||||
: 0,
|
||||
msgStr: Object.keys(other).length ? JSON.stringify(other) : null,
|
||||
});
|
||||
}
|
||||
|
||||
sendRoomInfo(socket: Socket, roomId: string) {
|
||||
socket.to(roomId).emit('room_info', this.findRoomInfo(socket, roomId));
|
||||
}
|
||||
}
|
||||
51
serve/src/online-teaching/online-teaching.module.ts
Normal file
51
serve/src/online-teaching/online-teaching.module.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { LiveTeachingService } from './service/live-teaching.service';
|
||||
import { LiveTeachingController } from './controller/live-teaching.controller';
|
||||
import { LiveTeaching } from './entities/live-teaching.entity';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { LiveCourseware } from './entities/live-courseware.entity';
|
||||
import { LiveQuestion } from './entities/live-question.entity';
|
||||
import { LiveEvaluate } from './entities/live-evaluate.entity';
|
||||
import { LiveStudent } from './entities/live-student.entity';
|
||||
import { LiveClassify } from './entities/live-classify.entity';
|
||||
import { LiveClassController } from './controller/live-class.controller';
|
||||
import { LiveClassService } from './service/live-class.service';
|
||||
import { OnlineTeachingGateway } from './gateway/online-teaching.gateway';
|
||||
import { LiveMsgData } from './entities/live-msg-data.entity';
|
||||
import { LiveQuestionAnswer } from './entities/live-question-answer.entity';
|
||||
import { Question } from 'src/assessment-evaluation/entities/entities-question-manager/question.entity';
|
||||
import { JwtAuthGuard } from 'src/system/jwt/jwt-auth.guard';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { APP_GUARD } from '@nestjs/core';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([
|
||||
LiveTeaching,
|
||||
LiveCourseware,
|
||||
LiveQuestion,
|
||||
LiveEvaluate,
|
||||
LiveStudent,
|
||||
LiveClassify,
|
||||
LiveMsgData,
|
||||
LiveQuestion,
|
||||
LiveQuestionAnswer,
|
||||
Question,
|
||||
]),
|
||||
JwtModule.register({
|
||||
secret: 'jwtConstants.secret',
|
||||
signOptions: { expiresIn: '7d' },
|
||||
}),
|
||||
],
|
||||
controllers: [LiveTeachingController, LiveClassController],
|
||||
providers: [
|
||||
LiveTeachingService,
|
||||
LiveClassService,
|
||||
OnlineTeachingGateway,
|
||||
{
|
||||
provide: APP_GUARD,
|
||||
useClass: JwtAuthGuard,
|
||||
},
|
||||
],
|
||||
})
|
||||
export class OnlineTeachingModule {}
|
||||
242
serve/src/online-teaching/service/live-class.service.ts
Normal file
242
serve/src/online-teaching/service/live-class.service.ts
Normal file
@@ -0,0 +1,242 @@
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { checkAnswer } from 'src/assessment-evaluation/controller/sim-test/mistake-again.controller';
|
||||
import { QuestionType } from 'src/assessment-evaluation/entities/entities-question-manager/question-type.entity';
|
||||
import { Question } from 'src/assessment-evaluation/entities/entities-question-manager/question.entity';
|
||||
import { SearchNoClassLsitDto } from 'src/online-course/dto/course-manage/get-course-list-dto';
|
||||
import { Resource } from 'src/resource/entities/resource.entity';
|
||||
import { User } from 'src/system/entities/user.entity';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { LiveAnsweringDto } from '../dto/live-question-answer.dto';
|
||||
import { LiveClassify } from '../entities/live-classify.entity';
|
||||
import { LiveCourseware } from '../entities/live-courseware.entity';
|
||||
import { LiveEvaluate } from '../entities/live-evaluate.entity';
|
||||
import { LiveQuestionAnswer } from '../entities/live-question-answer.entity';
|
||||
import { LiveQuestion } from '../entities/live-question.entity';
|
||||
import { LiveStudent } from '../entities/live-student.entity';
|
||||
import { LiveTeaching } from '../entities/live-teaching.entity';
|
||||
export class LiveClassService {
|
||||
constructor(
|
||||
// 课程学习记录
|
||||
private dataSource: DataSource,
|
||||
@InjectRepository(LiveTeaching)
|
||||
private Live_Sql: Repository<LiveTeaching>,
|
||||
@InjectRepository(LiveCourseware)
|
||||
private LiveCourseware_Sql: Repository<LiveCourseware>,
|
||||
@InjectRepository(LiveEvaluate)
|
||||
private LiveEvaluate_Sql: Repository<LiveEvaluate>,
|
||||
@InjectRepository(LiveQuestion)
|
||||
private LiveQuestion_Sql: Repository<LiveQuestion>,
|
||||
@InjectRepository(LiveStudent)
|
||||
private LiveStudent_Sql: Repository<LiveStudent>,
|
||||
@InjectRepository(LiveClassify)
|
||||
private LiveClassify_Sql: Repository<LiveClassify>,
|
||||
@InjectRepository(LiveQuestionAnswer)
|
||||
private LiveQuesstionAnswer_Sql: Repository<LiveQuestionAnswer>,
|
||||
// 试题表
|
||||
@InjectRepository(Question)
|
||||
private Questions_sql: Repository<Question>,
|
||||
) {}
|
||||
// 查询课程列表
|
||||
async findMyLiveList(pageInfo, tokenInfo) {
|
||||
const page = pageInfo.page - 1;
|
||||
const pageSize = pageInfo.pageSize;
|
||||
const sql = `
|
||||
SELECT
|
||||
huai_li.live_teaching.*,
|
||||
huai_li.live_teaching.start_time AS startTime,
|
||||
huai_li.live_teaching.create_time AS createTime,
|
||||
huai_li.\`user\`.id AS userId,
|
||||
huai_li.\`user\`.name AS userName
|
||||
FROM
|
||||
huai_li.live_student
|
||||
INNER JOIN
|
||||
huai_li.live_teaching
|
||||
ON
|
||||
huai_li.live_student.live_id = huai_li.live_teaching.id
|
||||
LEFT JOIN
|
||||
huai_li.\`user\`
|
||||
ON
|
||||
huai_li.live_teaching.lecturer = huai_li.\`user\`.id
|
||||
WHERE
|
||||
huai_li.live_student.student_id = ? AND
|
||||
huai_li.live_student.del_flag = 0 AND
|
||||
huai_li.live_teaching.del_flag = 0
|
||||
ORDER BY
|
||||
huai_li.live_teaching.update_time DESC
|
||||
LIMIT ?,?
|
||||
`;
|
||||
let res = await this.LiveStudent_Sql.query(sql, [
|
||||
tokenInfo.userId,
|
||||
+page,
|
||||
+pageSize,
|
||||
]);
|
||||
const total = await this.LiveStudent_Sql.query(
|
||||
`SELECT FOUND_ROWS() as total;`,
|
||||
);
|
||||
// console.log(total);
|
||||
// res.total = total[0];
|
||||
res = { data: res, total: +total[0].total };
|
||||
return res;
|
||||
}
|
||||
// 搜索直播
|
||||
async searchMyLiveList(searchInfo: SearchNoClassLsitDto, tokenInfo) {
|
||||
const page = searchInfo.page - 1;
|
||||
const pageSize = searchInfo.pageSize;
|
||||
const sql = `
|
||||
SELECT
|
||||
huai_li.live_teaching.*,
|
||||
huai_li.live_teaching.start_time AS startTime,
|
||||
huai_li.live_teaching.create_time AS createTime,
|
||||
huai_li.\`user\`.id AS userId,
|
||||
huai_li.\`user\`.name AS userName
|
||||
FROM
|
||||
huai_li.live_student
|
||||
INNER JOIN
|
||||
huai_li.live_teaching
|
||||
ON
|
||||
huai_li.live_student.live_id = huai_li.live_teaching.id
|
||||
LEFT JOIN
|
||||
huai_li.\`user\`
|
||||
ON
|
||||
huai_li.live_teaching.lecturer = huai_li.\`user\`.id
|
||||
WHERE
|
||||
huai_li.live_student.student_id = ? AND
|
||||
huai_li.live_teaching.title LIKE ? AND
|
||||
huai_li.live_teaching.del_flag = 0 AND
|
||||
huai_li.live_student.del_flag = 0
|
||||
ORDER BY
|
||||
huai_li.live_teaching.update_time DESC
|
||||
LIMIT ?, ?
|
||||
`;
|
||||
let res = await this.LiveStudent_Sql.query(sql, [
|
||||
tokenInfo.userId,
|
||||
`%${searchInfo.value}%`,
|
||||
+page,
|
||||
+pageSize,
|
||||
]);
|
||||
const total = await this.LiveStudent_Sql.query(
|
||||
`SELECT FOUND_ROWS() as total;`,
|
||||
);
|
||||
// console.log(total);
|
||||
// res.total = total[0];
|
||||
res = { data: res, total: +total[0].total };
|
||||
return res;
|
||||
}
|
||||
// 查询直播详情
|
||||
async getLiveInfo(id, tokenInfo) {
|
||||
const judgeIsviewerSql = `ls.del_flag = 0 AND ls.liveId = l.id AND ls.studentId = '${tokenInfo.userId}'`;
|
||||
const res = this.Live_Sql.createQueryBuilder('l')
|
||||
.innerJoin(LiveStudent, 'ls', judgeIsviewerSql)
|
||||
.leftJoinAndMapMany(
|
||||
'l.courseware',
|
||||
LiveCourseware,
|
||||
'lc',
|
||||
'lc.delFlag = 0 AND lc.liveId = l.id',
|
||||
)
|
||||
.leftJoinAndMapMany(
|
||||
'l.evealuate',
|
||||
LiveEvaluate,
|
||||
'le',
|
||||
'le.delFlag = 0 AND le.liveId = l.id',
|
||||
)
|
||||
.leftJoinAndMapMany(
|
||||
'l.question',
|
||||
LiveQuestion,
|
||||
'lq',
|
||||
'lq.delFlag = 0 AND lq.liveId = l.id',
|
||||
)
|
||||
.leftJoinAndMapOne('l.lecturerInfo', User, 'u', 'u.id = l.lecturer')
|
||||
.leftJoinAndMapOne('u.photo', Resource, 'photo', 'photo.id = u.photo')
|
||||
.where({ id })
|
||||
.getOne();
|
||||
return res;
|
||||
}
|
||||
// 获取直播学员列表
|
||||
async getStudentList(id, tokenInfo) {
|
||||
return await this.dataSource.query(
|
||||
`select u.id id,u.name name,rr.diskname photo,0 status from (select ls.student_id uid from live_student ls where ls.live_id = ?
|
||||
union all (select lt.lecturer uid from live_teaching lt where lt.id = ?)) tdd left join user u on u.id = tdd.uid left join resource rr on rr.id = u.photo`,
|
||||
[id, id],
|
||||
);
|
||||
}
|
||||
/**
|
||||
* 获取当前直播下所有试题
|
||||
*/
|
||||
async getLiveQuestionList(liveId) {
|
||||
const res = await this.LiveQuestion_Sql.createQueryBuilder('lqs')
|
||||
.leftJoinAndMapOne('lqs.info', Question, 'q', 'q.id = lqs.question_id')
|
||||
.leftJoinAndMapOne('q.typeInfo', QuestionType, 'qt', 'qt.id = q.type')
|
||||
.leftJoinAndMapOne(
|
||||
'lqs.answer',
|
||||
LiveQuestionAnswer,
|
||||
'lqa',
|
||||
'lqa.question_id = lqs.question_id AND lqa.del_flag = 0 AND lqa.liveId = ' +
|
||||
liveId,
|
||||
)
|
||||
.where({ liveId })
|
||||
.getMany();
|
||||
return res;
|
||||
}
|
||||
// 回答练习题
|
||||
async answeringQuestions(
|
||||
{ answerInfo, liveId, createTime }: LiveAnsweringDto,
|
||||
TokenData,
|
||||
) {
|
||||
const ids = answerInfo.map((_) => _.questionId);
|
||||
console.log(ids, '====================>');
|
||||
|
||||
const questions = await this.Questions_sql.query(
|
||||
`
|
||||
SELECT
|
||||
q.id as id,
|
||||
q.type as typeId,
|
||||
q.difficulty_level as difficultyLevelId,
|
||||
q.classify_id as classifyId,
|
||||
q.knowledge_id as knowledgeId,
|
||||
q.title as title,
|
||||
q.answer as answer ,
|
||||
q.analysis as analysis,
|
||||
q.options as options,
|
||||
qs.score as score
|
||||
FROM question q LEFT JOIN live_question qs ON q.id = qs.question_id
|
||||
where qs.live_id = ? AND qs.del_flag =0 AND
|
||||
q.id IN (?)`,
|
||||
[liveId, ids],
|
||||
);
|
||||
console.log(questions);
|
||||
|
||||
const res = { quesInfo: [...questions], score: 0, errorNum: 0 };
|
||||
questions.forEach((quesItem) => {
|
||||
const answerItem = answerInfo.find((an) => an.questionId === quesItem.id);
|
||||
quesItem.questionScore = quesItem.score;
|
||||
if (answerItem) {
|
||||
const result = checkAnswer(quesItem, answerItem.answer);
|
||||
res.score += result.score;
|
||||
quesItem.isPass = result.pass;
|
||||
if (result.isPass) res.errorNum++;
|
||||
quesItem.userAnswer = JSON.stringify(answerItem.answer);
|
||||
quesItem.score = result.score;
|
||||
quesItem.createTime = createTime;
|
||||
quesItem.mistakeScor = 0;
|
||||
} else {
|
||||
quesItem.score = 0;
|
||||
quesItem.createTime = new Date();
|
||||
quesItem.userAnswer = '';
|
||||
}
|
||||
quesItem.comment = '';
|
||||
quesItem.liveId = liveId;
|
||||
quesItem.questionId = quesItem.id;
|
||||
quesItem.creator = TokenData.userId;
|
||||
quesItem.updater = TokenData.userId;
|
||||
delete quesItem.id;
|
||||
});
|
||||
await this.LiveQuesstionAnswer_Sql.update(
|
||||
{ liveId, creator: TokenData.userId },
|
||||
{ delFlag: 1 },
|
||||
);
|
||||
console.log(questions);
|
||||
|
||||
await this.LiveQuesstionAnswer_Sql.insert(questions);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
240
serve/src/online-teaching/service/live-teaching.service.ts
Normal file
240
serve/src/online-teaching/service/live-teaching.service.ts
Normal file
@@ -0,0 +1,240 @@
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Question } from 'src/assessment-evaluation/entities/entities-question-manager/question.entity';
|
||||
import { CreateCourseclassifyDto } from 'src/online-course/dto/course-manage/course-classify.dto';
|
||||
import { SearchLsitDto } from 'src/online-course/dto/course-manage/get-course-list-dto';
|
||||
import { Resource } from 'src/resource/entities/resource.entity';
|
||||
import { User } from 'src/system/entities/user.entity';
|
||||
import { Like, Repository } from 'typeorm';
|
||||
import { UpdateLiveTeachingDto } from '../dto/live-update.dto';
|
||||
import { LiveClassify } from '../entities/live-classify.entity';
|
||||
import { LiveCourseware } from '../entities/live-courseware.entity';
|
||||
import { LiveEvaluate } from '../entities/live-evaluate.entity';
|
||||
import { LiveQuestion } from '../entities/live-question.entity';
|
||||
import { LiveStudent } from '../entities/live-student.entity';
|
||||
import { LiveTeaching } from '../entities/live-teaching.entity';
|
||||
export class LiveTeachingService {
|
||||
constructor(
|
||||
// 课程学习记录
|
||||
@InjectRepository(LiveTeaching)
|
||||
private Live_Sql: Repository<LiveTeaching>,
|
||||
@InjectRepository(LiveCourseware)
|
||||
private LiveCourseware_Sql: Repository<LiveCourseware>,
|
||||
@InjectRepository(LiveEvaluate)
|
||||
private LiveEvaluate_Sql: Repository<LiveEvaluate>,
|
||||
@InjectRepository(LiveQuestion)
|
||||
private LiveQuestion_Sql: Repository<LiveQuestion>,
|
||||
@InjectRepository(LiveStudent)
|
||||
private LiveStudent_Sql: Repository<LiveStudent>,
|
||||
@InjectRepository(LiveClassify)
|
||||
private LiveClassify_Sql: Repository<LiveClassify>,
|
||||
) {}
|
||||
// 查询直播列表
|
||||
async findLiveList(pageInfo, { userId }) {
|
||||
const page = pageInfo.page;
|
||||
const pageSize = pageInfo.pageSize;
|
||||
const res = await this.Live_Sql.createQueryBuilder('live')
|
||||
.leftJoinAndMapOne(
|
||||
'live.lecturerInfo',
|
||||
User,
|
||||
'user',
|
||||
'user.id = live.lecturer',
|
||||
)
|
||||
.where({
|
||||
delFlag: 0,
|
||||
lecturer: userId,
|
||||
})
|
||||
.orderBy('live.updateTime', 'DESC')
|
||||
.skip((page - 1) * pageSize)
|
||||
.take(pageSize)
|
||||
.getManyAndCount();
|
||||
return {
|
||||
data: res[0],
|
||||
total: res[1],
|
||||
};
|
||||
}
|
||||
// 新建直播
|
||||
async createLive(liveData: any, tokenData) {
|
||||
liveData.creator = tokenData.userId;
|
||||
liveData.updater = tokenData.userId;
|
||||
|
||||
const res = await this.Live_Sql.save(liveData);
|
||||
|
||||
const liveId = res.id;
|
||||
const courseware = liveData.liveCourseware.map((ware) => {
|
||||
return { fileId: ware.fileId, liveId };
|
||||
});
|
||||
const evealuate = liveData.evalDimension.map((eveal) => {
|
||||
return {
|
||||
liveId,
|
||||
dimensionality: eveal.dimensionality,
|
||||
type: eveal.type,
|
||||
};
|
||||
});
|
||||
const question = liveData.liveQuestion.map((lq) => {
|
||||
delete lq.liveId;
|
||||
return {
|
||||
liveId,
|
||||
...lq,
|
||||
};
|
||||
});
|
||||
const students = liveData.liveStudent.map((id) => {
|
||||
return {
|
||||
studentId: id,
|
||||
liveId,
|
||||
};
|
||||
});
|
||||
this.LiveCourseware_Sql.insert(courseware);
|
||||
this.LiveEvaluate_Sql.insert(evealuate);
|
||||
this.LiveQuestion_Sql.insert(question);
|
||||
this.LiveStudent_Sql.insert(students);
|
||||
return res;
|
||||
}
|
||||
// 搜索直播
|
||||
async searchSomeLive(searchInfo: SearchLsitDto) {
|
||||
const page = searchInfo.page - 1;
|
||||
const pageSize = searchInfo.pageSize;
|
||||
const res: any = await this.Live_Sql.createQueryBuilder('live')
|
||||
.leftJoinAndMapOne(
|
||||
'live.lecturerInfo',
|
||||
User,
|
||||
'user',
|
||||
'user.id = live.lecturer',
|
||||
)
|
||||
.where({
|
||||
delFlag: 0,
|
||||
title: Like(`%${searchInfo.value}%`),
|
||||
})
|
||||
.skip(page * pageSize)
|
||||
.take(pageSize)
|
||||
.getManyAndCount();
|
||||
return {
|
||||
total: res[1],
|
||||
data: res[0],
|
||||
};
|
||||
}
|
||||
// 编辑直播时某个直播的详细信息
|
||||
async findOneInfo(id, tokenInfo) {
|
||||
const res = this.Live_Sql.createQueryBuilder('live')
|
||||
.leftJoinAndMapMany(
|
||||
'live.liveCourseware',
|
||||
LiveCourseware,
|
||||
'lcs',
|
||||
`lcs.liveId = live.id AND lcs.del_flag = 0`,
|
||||
)
|
||||
.leftJoinAndMapOne(
|
||||
'live.lecturerInfo',
|
||||
User,
|
||||
'user',
|
||||
'user.id = live.lecturer',
|
||||
)
|
||||
.leftJoinAndMapMany(
|
||||
'live.evalDimension',
|
||||
LiveEvaluate,
|
||||
'le',
|
||||
'le.liveId = live.id AND le.del_flag = 0',
|
||||
)
|
||||
.leftJoinAndMapMany(
|
||||
'live.liveQuestion',
|
||||
LiveQuestion,
|
||||
'lq',
|
||||
'lq.liveId = live.id AND lq.del_flag = 0',
|
||||
)
|
||||
.leftJoinAndMapMany(
|
||||
'live.liveStudent',
|
||||
LiveStudent,
|
||||
'ls',
|
||||
'ls.liveId = live.id AND ls.del_flag = 0',
|
||||
)
|
||||
.leftJoinAndMapOne(
|
||||
'ls.info',
|
||||
User,
|
||||
'student',
|
||||
'student.id = ls.student_id ',
|
||||
)
|
||||
.leftJoinAndMapOne(
|
||||
'lcs.info',
|
||||
Resource,
|
||||
'lcsInfo',
|
||||
'lcs.file_id = lcsInfo.id',
|
||||
)
|
||||
.leftJoinAndMapOne(
|
||||
'lq.info',
|
||||
Question,
|
||||
'lqInfo',
|
||||
'lq.question_id = lqInfo.id',
|
||||
)
|
||||
.leftJoinAndMapOne('ls.info', User, 'lsInfo', 'ls.studentId = lsInfo.id')
|
||||
.where({ id })
|
||||
.getOne();
|
||||
return res;
|
||||
}
|
||||
// 编辑直播
|
||||
async updateLive(liveData: UpdateLiveTeachingDto, tokenInfo) {
|
||||
this.Live_Sql.update(liveData.id, { delFlag: 1 });
|
||||
delete liveData.id;
|
||||
return this.createLive(liveData, tokenInfo);
|
||||
}
|
||||
// 删除直播
|
||||
async deleteLive(id: [], tokenInfo) {
|
||||
const res = await this.Live_Sql.update(id, {
|
||||
delFlag: 1,
|
||||
updater: tokenInfo.userId,
|
||||
});
|
||||
return res;
|
||||
}
|
||||
// 开始直播时查询直播详情
|
||||
async getLiveInfo(id, tokenInfo) {
|
||||
const res = this.Live_Sql.createQueryBuilder('l')
|
||||
.leftJoinAndMapMany(
|
||||
'l.courseware',
|
||||
LiveCourseware,
|
||||
'lc',
|
||||
'lc.delFlag = 0 AND lc.liveId = l.id',
|
||||
)
|
||||
.leftJoinAndMapOne('l.lecturerInfo', User, 'user', 'user.id = l.lecturer')
|
||||
.leftJoinAndMapOne('user.photo', Resource, 'r', 'r.id = user.photo')
|
||||
.leftJoinAndMapMany(
|
||||
'l.evealuate',
|
||||
LiveEvaluate,
|
||||
'le',
|
||||
'le.delFlag = 0 AND le.liveId = l.id',
|
||||
)
|
||||
.leftJoinAndMapMany(
|
||||
'l.question',
|
||||
LiveQuestion,
|
||||
'lq',
|
||||
'lq.delFlag = 0 AND lq.liveId = l.id',
|
||||
)
|
||||
.where({ id })
|
||||
.getOne();
|
||||
return res;
|
||||
}
|
||||
/*
|
||||
* 更新直播某部分信息 如(开始直播时,直播状态调整)
|
||||
*/
|
||||
async updateLiveInfo(data) {
|
||||
return await this.Live_Sql.update(data.id, data);
|
||||
}
|
||||
// -------------------分类模块------------------ //
|
||||
// 分类查询
|
||||
// 查询所有分类
|
||||
async getclassifyList() {
|
||||
const res = await this.LiveClassify_Sql.findBy({ delFlag: 0 });
|
||||
return res;
|
||||
}
|
||||
// 新建分类
|
||||
async createclassify(classify: CreateCourseclassifyDto) {
|
||||
const res = await this.LiveClassify_Sql.save(classify);
|
||||
return res;
|
||||
}
|
||||
// 编辑分类
|
||||
async updateclassify(id, classify) {
|
||||
const res = await this.LiveClassify_Sql.update(id, classify);
|
||||
return res;
|
||||
}
|
||||
// 删除分类
|
||||
async deleteclassify({ id }) {
|
||||
const res = await this.LiveClassify_Sql.update(id, { delFlag: 1 });
|
||||
return res;
|
||||
}
|
||||
}
|
||||
24
serve/src/online-teaching/ws-jwt-guard.ts
Normal file
24
serve/src/online-teaching/ws-jwt-guard.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { WsException } from '@nestjs/websockets';
|
||||
import { Socket } from 'socket.io';
|
||||
|
||||
@Injectable()
|
||||
export class WsJwtGuard implements CanActivate {
|
||||
constructor(private jwtService: JwtService) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
try {
|
||||
const client: Socket = context.switchToWs().getClient<Socket>();
|
||||
const authToken: string = client.handshake?.auth?.token;
|
||||
client.join(`house_${authToken}`);
|
||||
const user = this.jwtService.decode(authToken.replace('Bearer ', ''));
|
||||
|
||||
context.switchToHttp().getRequest().user = user;
|
||||
|
||||
return Boolean(user);
|
||||
} catch (err) {
|
||||
throw new WsException(err.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user