Compare commits
2 Commits
71d8819361
...
01897a7ecc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01897a7ecc | ||
|
|
18170609d9 |
@ -108,7 +108,7 @@ export function getCourses(params: CourseQueryParams): Promise<{
|
|||||||
page: number;
|
page: number;
|
||||||
pageSize: number;
|
pageSize: number;
|
||||||
}> {
|
}> {
|
||||||
return http.get('/courses', { params });
|
return http.get('/admin/courses', { params });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取审核列表
|
// 获取审核列表
|
||||||
@ -118,82 +118,82 @@ export function getReviewList(params: CourseQueryParams): Promise<{
|
|||||||
page: number;
|
page: number;
|
||||||
pageSize: number;
|
pageSize: number;
|
||||||
}> {
|
}> {
|
||||||
return http.get('/courses/review', { params });
|
return http.get('/admin/courses/review', { params });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取课程包详情
|
// 获取课程包详情
|
||||||
export function getCourse(id: number): Promise<any> {
|
export function getCourse(id: number): Promise<any> {
|
||||||
return http.get(`/courses/${id}`);
|
return http.get(`/admin/courses/${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建课程包
|
// 创建课程包
|
||||||
export function createCourse(data: any): Promise<any> {
|
export function createCourse(data: any): Promise<any> {
|
||||||
return http.post('/courses', data);
|
return http.post('/admin/courses', data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新课程包
|
// 更新课程包
|
||||||
export function updateCourse(id: number, data: any): Promise<any> {
|
export function updateCourse(id: number, data: any): Promise<any> {
|
||||||
return http.put(`/courses/${id}`, data);
|
return http.put(`/admin/courses/${id}`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除课程包
|
// 删除课程包
|
||||||
export function deleteCourse(id: number): Promise<any> {
|
export function deleteCourse(id: number): Promise<any> {
|
||||||
return http.delete(`/courses/${id}`);
|
return http.delete(`/admin/courses/${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证课程完整性
|
// 验证课程完整性
|
||||||
export function validateCourse(id: number): Promise<ValidationResult> {
|
export function validateCourse(id: number): Promise<ValidationResult> {
|
||||||
return http.get(`/courses/${id}/validate`);
|
return http.get(`/admin/courses/${id}/validate`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提交审核
|
// 提交审核
|
||||||
export function submitCourse(id: number, copyrightConfirmed: boolean): Promise<any> {
|
export function submitCourse(id: number, copyrightConfirmed: boolean): Promise<any> {
|
||||||
return http.post(`/courses/${id}/submit`, { copyrightConfirmed });
|
return http.post(`/admin/courses/${id}/submit`, { copyrightConfirmed });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 撤销审核
|
// 撤销审核
|
||||||
export function withdrawCourse(id: number): Promise<any> {
|
export function withdrawCourse(id: number): Promise<any> {
|
||||||
return http.post(`/courses/${id}/withdraw`);
|
return http.post(`/admin/courses/${id}/withdraw`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 审核通过
|
// 审核通过
|
||||||
export function approveCourse(id: number, data: { checklist?: any; comment?: string }): Promise<any> {
|
export function approveCourse(id: number, data: { checklist?: any; comment?: string }): Promise<any> {
|
||||||
return http.post(`/courses/${id}/approve`, data);
|
return http.post(`/admin/courses/${id}/approve`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 审核驳回
|
// 审核驳回
|
||||||
export function rejectCourse(id: number, data: { checklist?: any; comment: string }): Promise<any> {
|
export function rejectCourse(id: number, data: { checklist?: any; comment: string }): Promise<any> {
|
||||||
return http.post(`/courses/${id}/reject`, data);
|
return http.post(`/admin/courses/${id}/reject`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 直接发布(超级管理员)
|
// 直接发布(超级管理员)
|
||||||
export function directPublishCourse(id: number, skipValidation?: boolean): Promise<any> {
|
export function directPublishCourse(id: number, skipValidation?: boolean): Promise<any> {
|
||||||
return http.post(`/courses/${id}/direct-publish`, { skipValidation });
|
return http.post(`/admin/courses/${id}/direct-publish`, { skipValidation });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 发布课程包(兼容旧API)
|
// 发布课程包(兼容旧API)
|
||||||
export function publishCourse(id: number): Promise<any> {
|
export function publishCourse(id: number): Promise<any> {
|
||||||
return http.post(`/courses/${id}/publish`);
|
return http.post(`/admin/courses/${id}/publish`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 下架课程包
|
// 下架课程包
|
||||||
export function unpublishCourse(id: number): Promise<any> {
|
export function unpublishCourse(id: number): Promise<any> {
|
||||||
return http.post(`/courses/${id}/unpublish`);
|
return http.post(`/admin/courses/${id}/unpublish`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重新发布
|
// 重新发布
|
||||||
export function republishCourse(id: number): Promise<any> {
|
export function republishCourse(id: number): Promise<any> {
|
||||||
return http.post(`/courses/${id}/republish`);
|
return http.post(`/admin/courses/${id}/republish`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取课程包统计数据
|
// 获取课程包统计数据
|
||||||
export function getCourseStats(id: number): Promise<any> {
|
export function getCourseStats(id: number): Promise<any> {
|
||||||
return http.get(`/courses/${id}/stats`);
|
return http.get(`/admin/courses/${id}/stats`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取版本历史
|
// 获取版本历史
|
||||||
export function getCourseVersions(id: number): Promise<any[]> {
|
export function getCourseVersions(id: number): Promise<any[]> {
|
||||||
return http.get(`/courses/${id}/versions`);
|
return http.get(`/admin/courses/${id}/versions`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 课程状态映射
|
// 课程状态映射
|
||||||
|
|||||||
@ -447,21 +447,31 @@ router.beforeEach((to, from, next) => {
|
|||||||
const token = localStorage.getItem('token');
|
const token = localStorage.getItem('token');
|
||||||
const userRole = localStorage.getItem('role');
|
const userRole = localStorage.getItem('role');
|
||||||
|
|
||||||
|
// 检测无效 token 或角色缺失,清除旧数据强制重新登录
|
||||||
|
const validRoles = ['admin', 'school', 'teacher', 'parent'];
|
||||||
|
const isValidToken = token && token.split('.').length === 3;
|
||||||
|
const isValidRole = userRole && validRoles.includes(userRole);
|
||||||
|
if ((token && !isValidToken) || (userRole && !isValidRole) || (isValidToken && !userRole)) {
|
||||||
|
localStorage.clear();
|
||||||
|
next('/login');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 设置页面标题
|
// 设置页面标题
|
||||||
if (to.meta.title) {
|
if (to.meta.title) {
|
||||||
document.title = `${to.meta.title} - 幼儿阅读教学服务平台`;
|
document.title = `${to.meta.title} - 幼儿阅读教学服务平台`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 需要认证但未登录
|
// 需要认证但未登录
|
||||||
if (to.meta.requiresAuth && !token) {
|
if (to.meta.requiresAuth && !isValidToken) {
|
||||||
message.warning('请先登录');
|
message.warning('请先登录');
|
||||||
next('/login');
|
next('/login');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 已登录用户访问登录页,跳转到对应首页
|
// 已登录用户访问登录页,跳转到对应首页
|
||||||
if (to.path === '/login' && token) {
|
if (to.path === '/login' && isValidToken) {
|
||||||
const defaultRoute = userRole ? `/${userRole}/dashboard` : '/admin/dashboard';
|
const defaultRoute = isValidRole ? `/${userRole}/dashboard` : '/admin/dashboard';
|
||||||
next(defaultRoute);
|
next(defaultRoute);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -469,7 +479,7 @@ router.beforeEach((to, from, next) => {
|
|||||||
// 角色权限检查
|
// 角色权限检查
|
||||||
if (to.meta.role && userRole !== to.meta.role) {
|
if (to.meta.role && userRole !== to.meta.role) {
|
||||||
message.error('没有权限访问该页面');
|
message.error('没有权限访问该页面');
|
||||||
next(`/${userRole}/dashboard`);
|
next(isValidRole ? `/${userRole}/dashboard` : '/login');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -45,14 +45,24 @@ public class AdminCourseController {
|
|||||||
return Result.success(courseService.getCourseById(id));
|
return Result.success(courseService.getCourseById(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "Get system course page")
|
@Operation(summary = "Get system course page (all statuses)")
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public Result<PageResult<Course>> getCoursePage(
|
public Result<PageResult<Course>> getCoursePage(
|
||||||
@RequestParam(value = "page", required = false) Integer pageNum,
|
@RequestParam(value = "page", required = false) Integer pageNum,
|
||||||
@RequestParam(required = false) Integer pageSize,
|
@RequestParam(required = false) Integer pageSize,
|
||||||
@RequestParam(required = false) String keyword,
|
@RequestParam(required = false) String keyword,
|
||||||
@RequestParam(required = false) String category) {
|
@RequestParam(required = false) String category,
|
||||||
Page<Course> page = courseService.getSystemCoursePage(pageNum, pageSize, keyword, category);
|
@RequestParam(required = false) String status) {
|
||||||
|
Page<Course> page = courseService.getSystemCoursePage(pageNum, pageSize, keyword, category, status);
|
||||||
|
return Result.success(PageResult.of(page));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "Get courses pending review")
|
||||||
|
@GetMapping("/review")
|
||||||
|
public Result<PageResult<Course>> getReviewCoursePage(
|
||||||
|
@RequestParam(value = "page", required = false) Integer pageNum,
|
||||||
|
@RequestParam(required = false) Integer pageSize) {
|
||||||
|
Page<Course> page = courseService.getReviewCoursePage(pageNum, pageSize);
|
||||||
return Result.success(PageResult.of(page));
|
return Result.success(PageResult.of(page));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,6 +73,38 @@ public class AdminCourseController {
|
|||||||
return Result.success();
|
return Result.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "Submit course for review")
|
||||||
|
@PostMapping("/{id}/submit")
|
||||||
|
public Result<Void> submitCourse(@PathVariable Long id) {
|
||||||
|
courseService.submitCourse(id);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "Withdraw course from review")
|
||||||
|
@PostMapping("/{id}/withdraw")
|
||||||
|
public Result<Void> withdrawCourse(@PathVariable Long id) {
|
||||||
|
courseService.withdrawCourse(id);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "Approve course")
|
||||||
|
@PostMapping("/{id}/approve")
|
||||||
|
public Result<Void> approveCourse(
|
||||||
|
@PathVariable Long id,
|
||||||
|
@RequestParam(required = false) String comment) {
|
||||||
|
courseService.approveCourse(id, comment);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "Reject course")
|
||||||
|
@PostMapping("/{id}/reject")
|
||||||
|
public Result<Void> rejectCourse(
|
||||||
|
@PathVariable Long id,
|
||||||
|
@RequestParam(required = false) String comment) {
|
||||||
|
courseService.rejectCourse(id, comment);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
@Operation(summary = "Publish course")
|
@Operation(summary = "Publish course")
|
||||||
@PostMapping("/{id}/publish")
|
@PostMapping("/{id}/publish")
|
||||||
public Result<Void> publishCourse(@PathVariable Long id) {
|
public Result<Void> publishCourse(@PathVariable Long id) {
|
||||||
@ -70,6 +112,27 @@ public class AdminCourseController {
|
|||||||
return Result.success();
|
return Result.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "Direct publish course (skip review)")
|
||||||
|
@PostMapping("/{id}/direct-publish")
|
||||||
|
public Result<Void> directPublishCourse(@PathVariable Long id) {
|
||||||
|
courseService.publishCourse(id);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "Unpublish (archive) course")
|
||||||
|
@PostMapping("/{id}/unpublish")
|
||||||
|
public Result<Void> unpublishCourse(@PathVariable Long id) {
|
||||||
|
courseService.archiveCourse(id);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "Republish course")
|
||||||
|
@PostMapping("/{id}/republish")
|
||||||
|
public Result<Void> republishCourse(@PathVariable Long id) {
|
||||||
|
courseService.publishCourse(id);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
@Operation(summary = "Archive course")
|
@Operation(summary = "Archive course")
|
||||||
@PostMapping("/{id}/archive")
|
@PostMapping("/{id}/archive")
|
||||||
public Result<Void> archiveCourse(@PathVariable Long id) {
|
public Result<Void> archiveCourse(@PathVariable Long id) {
|
||||||
|
|||||||
@ -20,7 +20,7 @@ public interface CourseService {
|
|||||||
|
|
||||||
Page<Course> getCoursePage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String category, String status);
|
Page<Course> getCoursePage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String category, String status);
|
||||||
|
|
||||||
Page<Course> getSystemCoursePage(Integer pageNum, Integer pageSize, String keyword, String category);
|
Page<Course> getSystemCoursePage(Integer pageNum, Integer pageSize, String keyword, String category, String status);
|
||||||
|
|
||||||
void deleteCourse(Long id);
|
void deleteCourse(Long id);
|
||||||
|
|
||||||
@ -30,4 +30,14 @@ public interface CourseService {
|
|||||||
|
|
||||||
List<Course> getCoursesByTenantId(Long tenantId);
|
List<Course> getCoursesByTenantId(Long tenantId);
|
||||||
|
|
||||||
|
Page<Course> getReviewCoursePage(Integer pageNum, Integer pageSize);
|
||||||
|
|
||||||
|
void submitCourse(Long id);
|
||||||
|
|
||||||
|
void withdrawCourse(Long id);
|
||||||
|
|
||||||
|
void approveCourse(Long id, String comment);
|
||||||
|
|
||||||
|
void rejectCourse(Long id, String comment);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -250,13 +250,15 @@ public class CourseServiceImpl implements CourseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Page<Course> getSystemCoursePage(Integer pageNum, Integer pageSize, String keyword, String category) {
|
public Page<Course> getSystemCoursePage(Integer pageNum, Integer pageSize, String keyword, String category, String status) {
|
||||||
Page<Course> page = PageUtils.of(pageNum, pageSize);
|
Page<Course> page = PageUtils.of(pageNum, pageSize);
|
||||||
LambdaQueryWrapper<Course> wrapper = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<Course> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
|
||||||
wrapper.eq(Course::getIsSystem, 1)
|
wrapper.eq(Course::getIsSystem, 1);
|
||||||
.eq(Course::getStatus, "published");
|
|
||||||
|
|
||||||
|
if (StringUtils.hasText(status)) {
|
||||||
|
wrapper.eq(Course::getStatus, status.toLowerCase());
|
||||||
|
}
|
||||||
if (StringUtils.hasText(keyword)) {
|
if (StringUtils.hasText(keyword)) {
|
||||||
wrapper.and(w -> w
|
wrapper.and(w -> w
|
||||||
.like(Course::getName, keyword)
|
.like(Course::getName, keyword)
|
||||||
@ -309,4 +311,56 @@ public class CourseServiceImpl implements CourseService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<Course> getReviewCoursePage(Integer pageNum, Integer pageSize) {
|
||||||
|
Page<Course> page = PageUtils.of(pageNum, pageSize);
|
||||||
|
LambdaQueryWrapper<Course> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(Course::getIsSystem, 1)
|
||||||
|
.eq(Course::getStatus, "pending")
|
||||||
|
.orderByDesc(Course::getSubmittedAt);
|
||||||
|
return courseMapper.selectPage(page, wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void submitCourse(Long id) {
|
||||||
|
Course course = getCourseById(id);
|
||||||
|
course.setStatus("pending");
|
||||||
|
course.setSubmittedAt(LocalDateTime.now());
|
||||||
|
courseMapper.updateById(course);
|
||||||
|
log.info("Course submitted for review: id={}", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void withdrawCourse(Long id) {
|
||||||
|
Course course = getCourseById(id);
|
||||||
|
course.setStatus("draft");
|
||||||
|
courseMapper.updateById(course);
|
||||||
|
log.info("Course withdrawn from review: id={}", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void approveCourse(Long id, String comment) {
|
||||||
|
Course course = getCourseById(id);
|
||||||
|
course.setStatus("published");
|
||||||
|
course.setReviewComment(comment);
|
||||||
|
course.setReviewedAt(LocalDateTime.now());
|
||||||
|
course.setPublishedAt(LocalDateTime.now());
|
||||||
|
courseMapper.updateById(course);
|
||||||
|
log.info("Course approved: id={}", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void rejectCourse(Long id, String comment) {
|
||||||
|
Course course = getCourseById(id);
|
||||||
|
course.setStatus("rejected");
|
||||||
|
course.setReviewComment(comment);
|
||||||
|
course.setReviewedAt(LocalDateTime.now());
|
||||||
|
courseMapper.updateById(course);
|
||||||
|
log.info("Course rejected: id={}", id);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user