feat(课程包): 未提交状态与草稿分流,草稿不可发布审核;保存草稿跳过校验
Made-with: Cursor
This commit is contained in:
parent
40782a8905
commit
b551af1355
@ -232,7 +232,7 @@ export function submitCourse(id: number | string): Promise<any> {
|
||||
|
||||
// 撤销审核 (暂时使用更新接口,需要确认后端是否有此功能)
|
||||
export function withdrawCourse(id: number): Promise<any> {
|
||||
return api.updateCourse(id, { status: "DRAFT" }) as any;
|
||||
return api.updateCourse(id, { status: "UNSUBMITTED" }) as any;
|
||||
}
|
||||
|
||||
// 审核通过
|
||||
@ -304,6 +304,7 @@ export const COURSE_STATUS_MAP: Record<
|
||||
{ label: string; color: string }
|
||||
> = {
|
||||
DRAFT: { label: "草稿", color: "default" },
|
||||
UNSUBMITTED: { label: "未提交", color: "geekblue" },
|
||||
PENDING: { label: "审核中", color: "processing" },
|
||||
REJECTED: { label: "已驳回", color: "error" },
|
||||
PUBLISHED: { label: "已发布", color: "success" },
|
||||
|
||||
@ -400,6 +400,7 @@ export function getStepTypeStyle(type: string): {
|
||||
// 课程状态映射(英文 → 中文)
|
||||
export const COURSE_STATUS_MAP: Record<string, string> = {
|
||||
DRAFT: "草稿",
|
||||
UNSUBMITTED: "未提交",
|
||||
PENDING: "审核中",
|
||||
APPROVED: "已通过",
|
||||
REJECTED: "已驳回",
|
||||
@ -423,6 +424,7 @@ export const COURSE_STATUS_COLORS: Record<
|
||||
{ bg: string; text: string }
|
||||
> = {
|
||||
草稿: { bg: "#F5F5F5", text: "#666666" },
|
||||
未提交: { bg: "#E8EAF6", text: "#5C6BC0" },
|
||||
审核中: { bg: "#E3F2FD", text: "#1976D2" },
|
||||
已驳回: { bg: "#FFEBEE", text: "#E53935" },
|
||||
已通过:{ bg: "#E8F5E9", text: "#43A047" },
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
<a-button @click="viewStats">
|
||||
<BarChartOutlined /> 数据
|
||||
</a-button>
|
||||
<a-popconfirm v-if="course.status === 'DRAFT' || course.status === 'ARCHIVED'" title="确定删除此课程包吗?"
|
||||
<a-popconfirm v-if="course.status === 'DRAFT' || course.status === 'UNSUBMITTED' || course.status === 'ARCHIVED'" title="确定删除此课程包吗?"
|
||||
@confirm="deleteCourse">
|
||||
<a-button danger>
|
||||
<DeleteOutlined /> 删除
|
||||
@ -509,7 +509,7 @@ const themeTagStyle = computed(() =>
|
||||
// 审核中(待审核)不可编辑,仅草稿/已驳回/已下架可编辑
|
||||
const canEdit = computed(() => {
|
||||
const s = course.value.status;
|
||||
return s === 'DRAFT' || s === 'REJECTED' || s === 'ARCHIVED';
|
||||
return s === 'DRAFT' || s === 'UNSUBMITTED' || s === 'REJECTED' || s === 'ARCHIVED';
|
||||
});
|
||||
|
||||
// 是否有课程介绍内容
|
||||
@ -658,6 +658,7 @@ const getStatusStyle = (status: string) => {
|
||||
const translateStatus = (status: string) => {
|
||||
const map: Record<string, string> = {
|
||||
'DRAFT': '草稿',
|
||||
'UNSUBMITTED': '未提交',
|
||||
'PENDING': '待审核',
|
||||
'PUBLISHED': '已发布',
|
||||
'ARCHIVED': '已下架',
|
||||
|
||||
@ -316,9 +316,11 @@ const handleSaveDraft = async () => {
|
||||
|
||||
// 保存
|
||||
const handleSave = async (isDraft = false) => {
|
||||
// 保存前校验当前步骤
|
||||
// 正式保存才校验当前步骤;保存草稿允许未完成配置,不校验
|
||||
if (!isDraft) {
|
||||
const ok = await validateCurrentStep();
|
||||
if (!ok) return;
|
||||
}
|
||||
|
||||
// 防止重复提交
|
||||
if (saving.value) return;
|
||||
@ -351,7 +353,15 @@ const handleSave = async (isDraft = false) => {
|
||||
scheduleRefData: formData.scheduleRefData,
|
||||
// 环创建设
|
||||
environmentConstruction: formData.environmentConstruction,
|
||||
};
|
||||
} as Record<string, unknown>;
|
||||
|
||||
if (isDraft) {
|
||||
courseData.status = 'DRAFT';
|
||||
} else if (currentStep.value === 6) {
|
||||
// 最后一步「保存/创建」:表单完整且本步校验通过 → 未提交(可提交审核/发布)
|
||||
courseData.status = 'UNSUBMITTED';
|
||||
}
|
||||
// 编辑态在中间步骤点「保存」:不传 status,避免把未提交误改回草稿
|
||||
|
||||
console.log('Saving course data...', { isDraft, isEdit: isEdit.value });
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
<a-select v-model:value="filters.status" placeholder="状态" style="width: 120px" allow-clear
|
||||
@change="fetchCourses">
|
||||
<a-select-option value="DRAFT">草稿</a-select-option>
|
||||
<a-select-option value="UNSUBMITTED">未提交</a-select-option>
|
||||
<a-select-option value="PENDING">审核中</a-select-option>
|
||||
<a-select-option value="REJECTED">已驳回</a-select-option>
|
||||
<a-select-option value="PUBLISHED">已发布</a-select-option>
|
||||
@ -91,8 +92,16 @@
|
||||
|
||||
<template v-else-if="column.key === 'actions'">
|
||||
<a-space>
|
||||
<!-- 草稿状态 -->
|
||||
<!-- 草稿:未完成保存为未提交,不允许发布/提交审核 -->
|
||||
<template v-if="record.status === 'DRAFT'">
|
||||
<a-button size="small" @click="editCourse(record.id)">编辑</a-button>
|
||||
<a-popconfirm title="确定删除此课程包吗?" @confirm="deleteCourseHandler(record.id)">
|
||||
<a-button size="small" danger>删除</a-button>
|
||||
</a-popconfirm>
|
||||
</template>
|
||||
|
||||
<!-- 未提交:可提交审核或直接发布 -->
|
||||
<template v-else-if="record.status === 'UNSUBMITTED'">
|
||||
<a-button size="small" @click="editCourse(record.id)">编辑</a-button>
|
||||
<a-dropdown>
|
||||
<a-button type="primary" size="small">
|
||||
|
||||
@ -9,6 +9,8 @@ import lombok.Getter;
|
||||
public enum CourseStatus {
|
||||
|
||||
DRAFT("DRAFT", "草稿"),
|
||||
/** 表单已完整保存、可提交审核或直接发布,与草稿区分 */
|
||||
UNSUBMITTED("UNSUBMITTED", "未提交"),
|
||||
PENDING("PENDING", "待审核"),
|
||||
REJECTED("REJECTED", "已驳回"),
|
||||
PUBLISHED("PUBLISHED", "已发布"),
|
||||
|
||||
@ -138,4 +138,7 @@ public class CourseCreateRequest {
|
||||
@Schema(description = "是否有集体课")
|
||||
private Boolean hasCollectiveLesson;
|
||||
|
||||
@Schema(description = "初始状态:DRAFT 草稿、UNSUBMITTED 未提交,默认草稿")
|
||||
private String status;
|
||||
|
||||
}
|
||||
|
||||
@ -52,7 +52,7 @@ public class CoursePackageServiceImpl extends ServiceImpl<CoursePackageMapper, C
|
||||
CoursePackage entity = buildEntityFromRequest(request);
|
||||
entity.setTenantId(tenantId);
|
||||
entity.setIsSystem(0);
|
||||
entity.setStatus(CourseStatus.DRAFT.getCode());
|
||||
entity.setStatus(resolveInitialStatus(request));
|
||||
entity.setUsageCount(0);
|
||||
coursePackageMapper.insert(entity);
|
||||
log.info("课程创建成功,id={}", entity.getId());
|
||||
@ -66,7 +66,7 @@ public class CoursePackageServiceImpl extends ServiceImpl<CoursePackageMapper, C
|
||||
CoursePackage entity = buildEntityFromRequest(request);
|
||||
entity.setTenantId(null);
|
||||
entity.setIsSystem(1);
|
||||
entity.setStatus(CourseStatus.DRAFT.getCode());
|
||||
entity.setStatus(resolveInitialStatus(request));
|
||||
entity.setUsageCount(0);
|
||||
coursePackageMapper.insert(entity);
|
||||
log.info("系统课程创建成功,id={}", entity.getId());
|
||||
@ -204,10 +204,15 @@ public class CoursePackageServiceImpl extends ServiceImpl<CoursePackageMapper, C
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void publishCourse(Long id) {
|
||||
CoursePackage entity = getCourseById(id);
|
||||
String st = entity.getStatus();
|
||||
if (CourseStatus.UNSUBMITTED.getCode().equals(st) || CourseStatus.PENDING.getCode().equals(st)) {
|
||||
entity.setStatus(CourseStatus.PUBLISHED.getCode());
|
||||
entity.setPublishedAt(LocalDateTime.now());
|
||||
coursePackageMapper.updateById(entity);
|
||||
log.info("课程发布成功,id={}", id);
|
||||
return;
|
||||
}
|
||||
throw new BusinessException("仅「未提交」或「待审核」状态的课程包可发布,当前状态不允许发布");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -239,6 +244,16 @@ public class CoursePackageServiceImpl extends ServiceImpl<CoursePackageMapper, C
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void submitCourse(Long id) {
|
||||
CoursePackage entity = getCourseById(id);
|
||||
String st = entity.getStatus();
|
||||
if (CourseStatus.DRAFT.getCode().equals(st)) {
|
||||
throw new BusinessException("草稿状态请先完成全部步骤并保存为「未提交」后再提交审核");
|
||||
}
|
||||
if (CourseStatus.PENDING.getCode().equals(st)) {
|
||||
throw new BusinessException("课程已在审核中");
|
||||
}
|
||||
if (CourseStatus.PUBLISHED.getCode().equals(st)) {
|
||||
throw new BusinessException("课程已发布,无需提交审核");
|
||||
}
|
||||
entity.setStatus(CourseStatus.PENDING.getCode());
|
||||
entity.setSubmittedAt(LocalDateTime.now());
|
||||
coursePackageMapper.updateById(entity);
|
||||
@ -411,6 +426,17 @@ public class CoursePackageServiceImpl extends ServiceImpl<CoursePackageMapper, C
|
||||
return coursePackageMapper.selectPage(page, wrapper);
|
||||
}
|
||||
|
||||
private static String resolveInitialStatus(CourseCreateRequest request) {
|
||||
if (!StringUtils.hasText(request.getStatus())) {
|
||||
return CourseStatus.DRAFT.getCode();
|
||||
}
|
||||
String code = request.getStatus();
|
||||
if (CourseStatus.UNSUBMITTED.getCode().equals(code) || CourseStatus.DRAFT.getCode().equals(code)) {
|
||||
return code;
|
||||
}
|
||||
return CourseStatus.DRAFT.getCode();
|
||||
}
|
||||
|
||||
private CoursePackage buildEntityFromRequest(CourseCreateRequest request) {
|
||||
CoursePackage entity = new CoursePackage();
|
||||
entity.setName(request.getName());
|
||||
|
||||
Loading…
Reference in New Issue
Block a user