fix: 课程包下架后需重新提交审核才能发布
- ARCHIVED 状态改为「提交审核」按钮,移除直接重新发布 - CollectionEditView/PackageEditView: 选择弹窗回显与分页保持选中 Made-with: Cursor
This commit is contained in:
parent
fdf34e9352
commit
0e77fae390
@ -100,6 +100,7 @@
|
||||
v-model:open="showPackageSelector"
|
||||
title="选择课程包"
|
||||
width="800px"
|
||||
:confirm-loading="addingPackages"
|
||||
@ok="handleAddPackages"
|
||||
>
|
||||
<a-table
|
||||
@ -109,6 +110,18 @@
|
||||
row-key="id"
|
||||
size="small"
|
||||
:loading="loadingPackages"
|
||||
:pagination="{
|
||||
current: selectorPagination.current,
|
||||
pageSize: selectorPagination.pageSize,
|
||||
total: selectorPagination.total,
|
||||
showSizeChanger: true,
|
||||
showTotal: (t: number) => `共 ${t} 条`,
|
||||
onChange: (page: number, size: number) => {
|
||||
selectorPagination.current = page;
|
||||
selectorPagination.pageSize = size;
|
||||
fetchAvailablePackages();
|
||||
},
|
||||
}"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'gradeTags'">
|
||||
@ -121,13 +134,12 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, onMounted } from 'vue';
|
||||
import { ref, reactive, computed, watch, onMounted } from 'vue';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { message } from 'ant-design-vue';
|
||||
import type { FormInstance } from 'ant-design-vue';
|
||||
import { PlusOutlined } from '@ant-design/icons-vue';
|
||||
import { getCollectionDetail, createCollection, updateCollection, setCollectionPackages } from '@/api/package';
|
||||
import { getCoursePackageList } from '@/api/package';
|
||||
import { getCollectionDetail, createCollection, updateCollection, setCollectionPackages, getCoursePackageList, getCoursePackage } from '@/api/package';
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
@ -141,6 +153,8 @@ const loadingPackages = ref(false);
|
||||
const showPackageSelector = ref(false);
|
||||
const availablePackages = ref<any[]>([]);
|
||||
const selectedRowKeys = ref<(number | string)[]>([]);
|
||||
const selectorPagination = reactive({ current: 1, pageSize: 10, total: 0 });
|
||||
const addingPackages = ref(false);
|
||||
|
||||
const formState = ref({
|
||||
name: '',
|
||||
@ -268,9 +282,13 @@ const fetchCollectionDetail = async () => {
|
||||
const fetchAvailablePackages = async () => {
|
||||
loadingPackages.value = true;
|
||||
try {
|
||||
// 获取已发布的课程包列表
|
||||
const res = await getCoursePackageList({ pageNum: 1, pageSize: 100, status: 'PUBLISHED' });
|
||||
const res = await getCoursePackageList({
|
||||
pageNum: selectorPagination.current,
|
||||
pageSize: selectorPagination.pageSize,
|
||||
status: 'PUBLISHED',
|
||||
});
|
||||
availablePackages.value = res.list || [];
|
||||
selectorPagination.total = res.total || 0;
|
||||
} catch (error) {
|
||||
console.error('获取课程包列表失败', error);
|
||||
} finally {
|
||||
@ -278,18 +296,50 @@ const fetchAvailablePackages = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleAddPackages = () => {
|
||||
// 打开选择弹窗时:回显已选课程包,加载第一页数据
|
||||
watch(showPackageSelector, (visible) => {
|
||||
if (visible) {
|
||||
selectedRowKeys.value = selectedPackages.value.map((p) => p.packageId);
|
||||
selectorPagination.current = 1;
|
||||
fetchAvailablePackages();
|
||||
}
|
||||
});
|
||||
|
||||
const handleAddPackages = async () => {
|
||||
const existingIds = new Set(selectedPackages.value.map((p) => p.packageId));
|
||||
const newPackages = availablePackages.value
|
||||
.filter((p) => selectedRowKeys.value.includes(p.id) && !existingIds.has(p.id))
|
||||
.map((p) => ({
|
||||
packageId: p.id,
|
||||
packageName: p.name,
|
||||
gradeLevel: parseGradeTags(p.gradeTags)?.[0] || '小班',
|
||||
sortOrder: selectedPackages.value.length,
|
||||
}));
|
||||
const idsToAdd = selectedRowKeys.value.filter((id) => !existingIds.has(id));
|
||||
if (idsToAdd.length === 0) {
|
||||
showPackageSelector.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
addingPackages.value = true;
|
||||
try {
|
||||
const pkgMap = new Map(availablePackages.value.map((p) => [p.id, p]));
|
||||
const newPackages: { packageId: number | string; packageName: string; gradeLevel: string; sortOrder: number }[] = [];
|
||||
let sortOrder = selectedPackages.value.length;
|
||||
|
||||
for (const id of idsToAdd) {
|
||||
let pkg = pkgMap.get(id);
|
||||
if (!pkg) {
|
||||
try {
|
||||
pkg = await getCoursePackage(id);
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
newPackages.push({
|
||||
packageId: pkg.id,
|
||||
packageName: pkg.name,
|
||||
gradeLevel: parseGradeTags(pkg.gradeTags)?.[0] || '小班',
|
||||
sortOrder: sortOrder++,
|
||||
});
|
||||
}
|
||||
|
||||
selectedPackages.value.push(...newPackages);
|
||||
} finally {
|
||||
addingPackages.value = false;
|
||||
}
|
||||
selectedRowKeys.value = [];
|
||||
showPackageSelector.value = false;
|
||||
};
|
||||
@ -374,7 +424,6 @@ const handleCancel = () => {
|
||||
|
||||
onMounted(() => {
|
||||
fetchCollectionDetail();
|
||||
fetchAvailablePackages();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@ -148,11 +148,11 @@
|
||||
</a-dropdown>
|
||||
</template>
|
||||
|
||||
<!-- 已下架状态 -->
|
||||
<!-- 已下架状态:需重新提交审核后才能发布 -->
|
||||
<template v-else-if="record.status === 'ARCHIVED'">
|
||||
<a-button size="small" @click="viewCourse(record.id)">查看</a-button>
|
||||
<a-button size="small" @click="viewStats(record.id)">数据</a-button>
|
||||
<a-button type="primary" size="small" @click="republishCourse(record.id)">重新发布</a-button>
|
||||
<a-button type="primary" size="small" @click="submitForReview(record)">提交审核</a-button>
|
||||
<a-popconfirm title="确定删除此课程包吗?删除后无法恢复" @confirm="deleteCourseHandler(record.id)">
|
||||
<a-button size="small" danger>删除</a-button>
|
||||
</a-popconfirm>
|
||||
@ -494,23 +494,6 @@ const unpublishCourse = async (id: number) => {
|
||||
});
|
||||
};
|
||||
|
||||
// 重新发布
|
||||
const republishCourse = async (id: number) => {
|
||||
Modal.confirm({
|
||||
title: '确认重新发布',
|
||||
content: '重新发布后所有活跃租户将可以查看并使用此课程包,确认继续?',
|
||||
onOk: async () => {
|
||||
try {
|
||||
await courseApi.republishCourse(id);
|
||||
message.success('重新发布成功');
|
||||
fetchCourses();
|
||||
} catch (error) {
|
||||
message.error('重新发布失败');
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const iterateCourse = (id: number) => {
|
||||
router.push(`/admin/packages/${id}/iterate`);
|
||||
};
|
||||
|
||||
@ -103,6 +103,7 @@
|
||||
v-model:open="showPackageSelector"
|
||||
title="选择课程包"
|
||||
width="800px"
|
||||
:confirm-loading="addingPackages"
|
||||
@ok="handleAddPackages"
|
||||
>
|
||||
<a-table
|
||||
@ -112,6 +113,18 @@
|
||||
row-key="id"
|
||||
size="small"
|
||||
:loading="loadingPackages"
|
||||
:pagination="{
|
||||
current: selectorPagination.current,
|
||||
pageSize: selectorPagination.pageSize,
|
||||
total: selectorPagination.total,
|
||||
showSizeChanger: true,
|
||||
showTotal: (t: number) => `共 ${t} 条`,
|
||||
onChange: (page: number, size: number) => {
|
||||
selectorPagination.current = page;
|
||||
selectorPagination.pageSize = size;
|
||||
fetchAvailablePackages();
|
||||
},
|
||||
}"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'gradeTags'">
|
||||
@ -129,8 +142,7 @@ import { useRouter, useRoute } from 'vue-router';
|
||||
import { message } from 'ant-design-vue';
|
||||
import type { FormInstance } from 'ant-design-vue';
|
||||
import { PlusOutlined } from '@ant-design/icons-vue';
|
||||
import { getCollectionDetail, createCollection, updateCollection, setCollectionPackages } from '@/api/package';
|
||||
import { getCoursePackageList } from '@/api/package';
|
||||
import { getCollectionDetail, createCollection, updateCollection, setCollectionPackages, getCoursePackageList, getCoursePackage } from '@/api/package';
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
@ -144,6 +156,8 @@ const loadingPackages = ref(false);
|
||||
const showPackageSelector = ref(false);
|
||||
const availablePackages = ref<any[]>([]);
|
||||
const selectedRowKeys = ref<(number | string)[]>([]);
|
||||
const selectorPagination = reactive({ current: 1, pageSize: 10, total: 0 });
|
||||
const addingPackages = ref(false);
|
||||
|
||||
const form = reactive({
|
||||
name: '',
|
||||
@ -280,9 +294,13 @@ const fetchPackageDetail = async () => {
|
||||
const fetchAvailablePackages = async () => {
|
||||
loadingPackages.value = true;
|
||||
try {
|
||||
// 获取已发布的课程包列表
|
||||
const res = await getCoursePackageList({ pageNum: 1, pageSize: 100, status: 'PUBLISHED' });
|
||||
const res = await getCoursePackageList({
|
||||
pageNum: selectorPagination.current,
|
||||
pageSize: selectorPagination.pageSize,
|
||||
status: 'PUBLISHED',
|
||||
});
|
||||
availablePackages.value = res.list || [];
|
||||
selectorPagination.total = res.total || 0;
|
||||
} catch (error) {
|
||||
console.error('获取课程包列表失败', error);
|
||||
} finally {
|
||||
@ -290,21 +308,51 @@ const fetchAvailablePackages = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleAddPackages = () => {
|
||||
// 打开选择弹窗时:回显已选课程包,加载第一页数据
|
||||
watch(showPackageSelector, (visible) => {
|
||||
if (visible) {
|
||||
selectedRowKeys.value = selectedPackages.value.map((p) => p.packageId);
|
||||
selectorPagination.current = 1;
|
||||
fetchAvailablePackages();
|
||||
}
|
||||
});
|
||||
|
||||
const handleAddPackages = async () => {
|
||||
const existingIds = new Set(selectedPackages.value.map((p) => p.packageId));
|
||||
const newPackages = availablePackages.value
|
||||
.filter((p) => selectedRowKeys.value.includes(p.id) && !existingIds.has(p.id))
|
||||
.map((p) => {
|
||||
const tags = parseGradeTags(p.gradeTags);
|
||||
return {
|
||||
packageId: p.id,
|
||||
packageName: p.name,
|
||||
const idsToAdd = selectedRowKeys.value.filter((id) => !existingIds.has(id));
|
||||
if (idsToAdd.length === 0) {
|
||||
showPackageSelector.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
addingPackages.value = true;
|
||||
try {
|
||||
const pkgMap = new Map(availablePackages.value.map((p) => [p.id, p]));
|
||||
const newPackages: { packageId: number | string; packageName: string; gradeLevels: string[]; sortOrder: number }[] = [];
|
||||
let sortOrder = selectedPackages.value.length;
|
||||
|
||||
for (const id of idsToAdd) {
|
||||
let pkg = pkgMap.get(id);
|
||||
if (!pkg) {
|
||||
try {
|
||||
pkg = await getCoursePackage(id);
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const tags = parseGradeTags(pkg.gradeTags);
|
||||
newPackages.push({
|
||||
packageId: pkg.id,
|
||||
packageName: pkg.name,
|
||||
gradeLevels: Array.isArray(tags) && tags.length > 0 ? tags : ['小班'],
|
||||
sortOrder: selectedPackages.value.length,
|
||||
};
|
||||
sortOrder: sortOrder++,
|
||||
});
|
||||
}
|
||||
|
||||
selectedPackages.value.push(...newPackages);
|
||||
} finally {
|
||||
addingPackages.value = false;
|
||||
}
|
||||
selectedRowKeys.value = [];
|
||||
showPackageSelector.value = false;
|
||||
};
|
||||
@ -384,7 +432,6 @@ const handleSave = async () => {
|
||||
|
||||
onMounted(() => {
|
||||
fetchPackageDetail();
|
||||
fetchAvailablePackages();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user