feat: 排课/预约优化与国际化
- main.ts: dayjs 时间国际化使用中文 - 排课日期禁止选择过去时间(学校端、教师端、校本课程预约) - 移除选择课程套餐,租户仅一个套餐直接展示课程包 - 教师端预约上课增加排课计划参考表格 Made-with: Cursor
This commit is contained in:
parent
824ce7ad80
commit
ed9371b21f
@ -2,6 +2,10 @@ import { createApp } from 'vue';
|
|||||||
import { createPinia } from 'pinia';
|
import { createPinia } from 'pinia';
|
||||||
import Antd from 'ant-design-vue';
|
import Antd from 'ant-design-vue';
|
||||||
import 'ant-design-vue/dist/reset.css';
|
import 'ant-design-vue/dist/reset.css';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import 'dayjs/locale/zh-cn';
|
||||||
|
|
||||||
|
dayjs.locale('zh-cn');
|
||||||
import 'virtual:uno.css';
|
import 'virtual:uno.css';
|
||||||
import App from './App.vue';
|
import App from './App.vue';
|
||||||
import router from './router';
|
import router from './router';
|
||||||
|
|||||||
@ -137,7 +137,11 @@
|
|||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="排课日期" name="scheduledDate">
|
<a-form-item label="排课日期" name="scheduledDate">
|
||||||
<a-date-picker v-model:value="formState.scheduledDate" style="width: 100%" />
|
<a-date-picker
|
||||||
|
v-model:value="formState.scheduledDate"
|
||||||
|
style="width: 100%"
|
||||||
|
:disabled-date="(current) => current && current < dayjs().startOf('day')"
|
||||||
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="时间段" name="scheduledTimeRange">
|
<a-form-item label="时间段" name="scheduledTimeRange">
|
||||||
<a-time-range-picker
|
<a-time-range-picker
|
||||||
|
|||||||
@ -16,28 +16,11 @@
|
|||||||
</a-steps>
|
</a-steps>
|
||||||
|
|
||||||
<div class="step-content">
|
<div class="step-content">
|
||||||
<!-- 步骤1: 选择课程套餐和课程包 -->
|
<!-- 步骤1: 选择课程包(租户仅一个套餐,直接展示套餐下课程包) -->
|
||||||
<div v-show="currentStep === 0" class="step-panel">
|
<div v-show="currentStep === 0" class="step-panel">
|
||||||
<h3>选择课程套餐</h3>
|
<h3>选择课程包</h3>
|
||||||
<a-select
|
<a-spin :spinning="loadingPackages">
|
||||||
v-model:value="formData.collectionId"
|
|
||||||
placeholder="请选择课程套餐"
|
|
||||||
style="width: 100%"
|
|
||||||
show-search
|
|
||||||
:filter-option="filterCollection"
|
|
||||||
@change="handleCollectionChange"
|
|
||||||
>
|
|
||||||
<a-select-option v-for="collection in collections" :key="collection.id" :value="collection.id">
|
|
||||||
<div class="collection-option">
|
|
||||||
<div class="collection-name">{{ collection.name }}</div>
|
|
||||||
<div class="collection-info">{{ collection.packageCount }} 个课程包 · {{ collection.gradeLevels?.join(', ') }}</div>
|
|
||||||
</div>
|
|
||||||
</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
|
|
||||||
<!-- 选择课程包 -->
|
|
||||||
<div v-if="selectedCollection && selectedCollection.packages && selectedCollection.packages.length > 0" class="packages-section">
|
<div v-if="selectedCollection && selectedCollection.packages && selectedCollection.packages.length > 0" class="packages-section">
|
||||||
<h4>选择课程包</h4>
|
|
||||||
<div class="packages-grid">
|
<div class="packages-grid">
|
||||||
<div
|
<div
|
||||||
v-for="pkg in selectedCollection.packages"
|
v-for="pkg in selectedCollection.packages"
|
||||||
@ -51,11 +34,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 调试信息:如果没有课程包,显示提示 -->
|
<div v-else-if="!loadingPackages && collections.length > 0" class="packages-section">
|
||||||
<div v-else-if="selectedCollection" class="packages-section">
|
<a-alert message="暂无课程包" type="warning" show-icon />
|
||||||
<h4>选择课程包</h4>
|
|
||||||
<a-alert message="该套餐暂无课程包" type="warning" show-icon />
|
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else-if="!loadingPackages && collections.length === 0" class="packages-section">
|
||||||
|
<a-alert message="暂无课程套餐,请联系管理员" type="info" show-icon />
|
||||||
|
</div>
|
||||||
|
</a-spin>
|
||||||
|
|
||||||
<!-- 排课计划参考(与管理端课程包详情一致) -->
|
<!-- 排课计划参考(与管理端课程包详情一致) -->
|
||||||
<div v-if="scheduleRefDisplay.length > 0" class="schedule-ref-card">
|
<div v-if="scheduleRefDisplay.length > 0" class="schedule-ref-card">
|
||||||
@ -175,6 +160,7 @@
|
|||||||
v-model:value="formData.scheduledDate"
|
v-model:value="formData.scheduledDate"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
placeholder="选择日期"
|
placeholder="选择日期"
|
||||||
|
:disabled-date="(current) => current && current < dayjs().startOf('day')"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
@ -275,6 +261,7 @@ const currentStep = ref(0);
|
|||||||
|
|
||||||
// 课程套餐列表
|
// 课程套餐列表
|
||||||
const collections = ref<CourseCollection[]>([]);
|
const collections = ref<CourseCollection[]>([]);
|
||||||
|
const loadingPackages = ref(false);
|
||||||
const selectedGrade = ref('');
|
const selectedGrade = ref('');
|
||||||
|
|
||||||
// 课程类型列表
|
// 课程类型列表
|
||||||
@ -410,13 +397,27 @@ const resetForm = () => {
|
|||||||
classTeacherMap.value = {};
|
classTeacherMap.value = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
// 加载课程套餐列表
|
// 加载课程套餐列表,租户仅一个套餐时自动加载其课程包
|
||||||
const loadCollections = async () => {
|
const loadCollections = async () => {
|
||||||
|
loadingPackages.value = true;
|
||||||
try {
|
try {
|
||||||
collections.value = await getCourseCollections();
|
collections.value = await getCourseCollections();
|
||||||
|
if (collections.value.length > 0) {
|
||||||
|
const first = collections.value[0];
|
||||||
|
formData.collectionId = first.id as number;
|
||||||
|
const packages = await getCourseCollectionPackages(first.id);
|
||||||
|
if (first) {
|
||||||
|
(first as any).packages = packages;
|
||||||
|
}
|
||||||
|
if (!packages || packages.length === 0) {
|
||||||
|
message.warning('该套餐暂无课程包');
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ 加载课程套餐失败:', error);
|
console.error('❌ 加载课程套餐失败:', error);
|
||||||
message.error('加载课程套餐失败');
|
message.error('加载课程套餐失败');
|
||||||
|
} finally {
|
||||||
|
loadingPackages.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -439,35 +440,6 @@ const loadTeachers = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 课程套餐变化 - 加载课程包列表
|
|
||||||
const handleCollectionChange = async (collectionId: number) => {
|
|
||||||
// 重置后续选择
|
|
||||||
formData.packageId = undefined;
|
|
||||||
formData.courseId = undefined;
|
|
||||||
scheduleRefData.value = [];
|
|
||||||
|
|
||||||
if (!collectionId) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 获取课程包列表(API: GET /v1/school/packages/{collectionId}/packages)
|
|
||||||
const packages = await getCourseCollectionPackages(collectionId);
|
|
||||||
|
|
||||||
if (!packages || packages.length === 0) {
|
|
||||||
message.warning('该套餐暂无课程包');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新当前套餐的课程包列表
|
|
||||||
const collection = collections.value.find(c => c.id === collectionId);
|
|
||||||
if (collection) {
|
|
||||||
collection.packages = packages;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('❌ 加载课程包失败:', error);
|
|
||||||
message.error('加载课程包失败');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 选择课程包
|
// 选择课程包
|
||||||
const selectPackage = async (packageId: number) => {
|
const selectPackage = async (packageId: number) => {
|
||||||
formData.packageId = packageId;
|
formData.packageId = packageId;
|
||||||
@ -536,12 +508,6 @@ const isClassSelected = (classId: number): boolean => {
|
|||||||
return formData.classIds.includes(classId);
|
return formData.classIds.includes(classId);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 过滤课程套餐
|
|
||||||
const filterCollection = (input: string, option: any) => {
|
|
||||||
const collection = collections.value.find(c => c.id === option.value);
|
|
||||||
return collection?.name?.toLowerCase().includes(input.toLowerCase()) || false;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 过滤教师
|
// 过滤教师
|
||||||
const filterTeacher = (input: string, option: any) => {
|
const filterTeacher = (input: string, option: any) => {
|
||||||
const teacher = teachers.value.find(t => t.id === option.value);
|
const teacher = teachers.value.find(t => t.id === option.value);
|
||||||
|
|||||||
@ -220,6 +220,7 @@
|
|||||||
format="YYYY-MM-DD HH:mm"
|
format="YYYY-MM-DD HH:mm"
|
||||||
placeholder="选择预约时间"
|
placeholder="选择预约时间"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
|
:disabled-date="(current) => current && current < dayjs().startOf('day')"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="备注">
|
<a-form-item label="备注">
|
||||||
@ -235,6 +236,7 @@
|
|||||||
import { ref, computed, onMounted } from 'vue';
|
import { ref, computed, onMounted } from 'vue';
|
||||||
import { useRouter, useRoute } from 'vue-router';
|
import { useRouter, useRoute } from 'vue-router';
|
||||||
import { message } from 'ant-design-vue';
|
import { message } from 'ant-design-vue';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
import {
|
import {
|
||||||
ArrowLeftOutlined,
|
ArrowLeftOutlined,
|
||||||
CalendarOutlined,
|
CalendarOutlined,
|
||||||
|
|||||||
@ -180,6 +180,7 @@
|
|||||||
format="YYYY-MM-DD HH:mm"
|
format="YYYY-MM-DD HH:mm"
|
||||||
placeholder="选择预约时间"
|
placeholder="选择预约时间"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
|
:disabled-date="(current) => current && current < dayjs().startOf('day')"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="备注">
|
<a-form-item label="备注">
|
||||||
|
|||||||
@ -16,27 +16,11 @@
|
|||||||
</a-steps>
|
</a-steps>
|
||||||
|
|
||||||
<div class="step-content">
|
<div class="step-content">
|
||||||
<!-- 步骤1: 选择课程套餐和课程包 -->
|
<!-- 步骤1: 选择课程包(租户仅一个套餐,直接展示套餐下课程包) -->
|
||||||
<div v-show="currentStep === 0" class="step-panel">
|
<div v-show="currentStep === 0" class="step-panel">
|
||||||
<h3>选择课程套餐</h3>
|
<h3>选择课程包</h3>
|
||||||
<a-select
|
<a-spin :spinning="loadingPackages">
|
||||||
v-model:value="formData.collectionId"
|
|
||||||
placeholder="请选择课程套餐"
|
|
||||||
style="width: 100%"
|
|
||||||
show-search
|
|
||||||
:filter-option="filterCollection"
|
|
||||||
@change="handleCollectionChange"
|
|
||||||
>
|
|
||||||
<a-select-option v-for="collection in collections" :key="collection.id" :value="collection.id">
|
|
||||||
<div class="collection-option">
|
|
||||||
<div class="collection-name">{{ collection.name }}</div>
|
|
||||||
<div class="collection-info">{{ collection.packageCount }} 个课程包 · {{ collection.gradeLevels?.join(', ') }}</div>
|
|
||||||
</div>
|
|
||||||
</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
|
|
||||||
<div v-if="selectedCollection && selectedCollection.packages && selectedCollection.packages.length > 0" class="packages-section">
|
<div v-if="selectedCollection && selectedCollection.packages && selectedCollection.packages.length > 0" class="packages-section">
|
||||||
<h4>选择课程包</h4>
|
|
||||||
<div class="packages-grid">
|
<div class="packages-grid">
|
||||||
<div
|
<div
|
||||||
v-for="pkg in selectedCollection.packages"
|
v-for="pkg in selectedCollection.packages"
|
||||||
@ -50,9 +34,39 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="selectedCollection" class="packages-section">
|
<div v-else-if="!loadingPackages && collections.length > 0" class="packages-section">
|
||||||
<h4>选择课程包</h4>
|
<a-alert message="暂无课程包" type="warning" show-icon />
|
||||||
<a-alert message="该套餐暂无课程包" type="warning" show-icon />
|
</div>
|
||||||
|
<div v-else-if="!loadingPackages && collections.length === 0" class="packages-section">
|
||||||
|
<a-alert message="暂无课程套餐,请联系管理员" type="info" show-icon />
|
||||||
|
</div>
|
||||||
|
</a-spin>
|
||||||
|
|
||||||
|
<!-- 排课计划参考(与学校端一致) -->
|
||||||
|
<div v-if="scheduleRefDisplay.length > 0" class="schedule-ref-card">
|
||||||
|
<div class="ref-header">
|
||||||
|
<CalendarOutlined class="ref-icon" />
|
||||||
|
<span class="ref-title">排课计划参考</span>
|
||||||
|
</div>
|
||||||
|
<a-table
|
||||||
|
:columns="scheduleRefColumns"
|
||||||
|
:data-source="scheduleRefDisplay"
|
||||||
|
:pagination="false"
|
||||||
|
size="small"
|
||||||
|
bordered
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'dayOfWeek'">
|
||||||
|
{{ formatDayOfWeek(record.dayOfWeek) }}
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'lessonType'">
|
||||||
|
<a-tag v-if="record.lessonType" size="small" :style="getLessonTagStyle(record.lessonType)">
|
||||||
|
{{ getLessonTypeName(record.lessonType) }}
|
||||||
|
</a-tag>
|
||||||
|
<span v-else>-</span>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -119,6 +133,7 @@
|
|||||||
v-model:value="formData.scheduledDate"
|
v-model:value="formData.scheduledDate"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
placeholder="选择日期"
|
placeholder="选择日期"
|
||||||
|
:disabled-date="(current) => current && current < dayjs().startOf('day')"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
@ -164,6 +179,7 @@ import { message } from 'ant-design-vue';
|
|||||||
import dayjs, { Dayjs } from 'dayjs';
|
import dayjs, { Dayjs } from 'dayjs';
|
||||||
import {
|
import {
|
||||||
BookOutlined,
|
BookOutlined,
|
||||||
|
CalendarOutlined,
|
||||||
TeamOutlined,
|
TeamOutlined,
|
||||||
HeartOutlined,
|
HeartOutlined,
|
||||||
SoundOutlined,
|
SoundOutlined,
|
||||||
@ -192,9 +208,70 @@ const loadingLessonTypes = ref(false);
|
|||||||
const currentStep = ref(0);
|
const currentStep = ref(0);
|
||||||
|
|
||||||
const collections = ref<CourseCollection[]>([]);
|
const collections = ref<CourseCollection[]>([]);
|
||||||
|
const loadingPackages = ref(false);
|
||||||
const lessonTypes = ref<LessonTypeInfo[]>([]);
|
const lessonTypes = ref<LessonTypeInfo[]>([]);
|
||||||
const myClasses = ref<TeacherClass[]>([]);
|
const myClasses = ref<TeacherClass[]>([]);
|
||||||
|
|
||||||
|
// 排课计划参考数据
|
||||||
|
const scheduleRefData = ref<any[]>([]);
|
||||||
|
|
||||||
|
// 排课计划参考表格列(与学校端一致)
|
||||||
|
const scheduleRefColumns = [
|
||||||
|
{ title: '时间', dataIndex: 'dayOfWeek', key: 'dayOfWeek', width: 80 },
|
||||||
|
{ title: '课程类型', dataIndex: 'lessonType', key: 'lessonType', width: 100 },
|
||||||
|
{ title: '课程名称', dataIndex: 'lessonName', key: 'lessonName' },
|
||||||
|
{ title: '区域活动', dataIndex: 'activity', key: 'activity' },
|
||||||
|
{ title: '备注', dataIndex: 'note', key: 'note' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const weekDayNames: Record<number, string> = {
|
||||||
|
1: '周一',
|
||||||
|
2: '周二',
|
||||||
|
3: '周三',
|
||||||
|
4: '周四',
|
||||||
|
5: '周五',
|
||||||
|
6: '周六',
|
||||||
|
0: '周日',
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatDayOfWeek = (val: number | string | undefined): string => {
|
||||||
|
if (val === undefined || val === null) return '-';
|
||||||
|
if (typeof val === 'string') {
|
||||||
|
if (/^[一二三四五六日]/.test(val) || val.startsWith('周')) return val;
|
||||||
|
const n = parseInt(val, 10);
|
||||||
|
if (!isNaN(n)) return weekDayNames[n] ?? weekDayNames[n as 0] ?? '-';
|
||||||
|
}
|
||||||
|
if (typeof val === 'number') return weekDayNames[val as 0] ?? '-';
|
||||||
|
return '-';
|
||||||
|
};
|
||||||
|
|
||||||
|
const normalizeScheduleRefData = (raw: any[]): any[] => {
|
||||||
|
if (!Array.isArray(raw) || raw.length === 0) return [];
|
||||||
|
const first = raw[0];
|
||||||
|
const isWeeklyFormat = 'dayOfWeek' in first || 'lessonName' in first || 'activity' in first;
|
||||||
|
const isLessonMetaFormat = 'title' in first && ('suggestedOrder' in first || 'description' in first);
|
||||||
|
if (isWeeklyFormat && !isLessonMetaFormat) {
|
||||||
|
return raw.map((r, i) => ({
|
||||||
|
key: r.key ?? `row_${i}`,
|
||||||
|
dayOfWeek: r.dayOfWeek,
|
||||||
|
lessonType: r.lessonType,
|
||||||
|
lessonName: r.lessonName ?? r.title ?? '-',
|
||||||
|
activity: r.activity ?? r.description ?? '-',
|
||||||
|
note: r.note ?? r.tips ?? r.frequency ?? '-',
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return raw.map((r, i) => ({
|
||||||
|
key: r.key ?? `row_${i}`,
|
||||||
|
dayOfWeek: r.dayOfWeek ?? '-',
|
||||||
|
lessonType: r.lessonType,
|
||||||
|
lessonName: r.title ?? r.lessonName ?? '-',
|
||||||
|
activity: r.description ?? r.activity ?? (Array.isArray(r.keyPoints) ? r.keyPoints.join(';') : '-'),
|
||||||
|
note: r.tips ?? r.frequency ?? r.note ?? '-',
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const scheduleRefDisplay = computed(() => normalizeScheduleRefData(scheduleRefData.value));
|
||||||
|
|
||||||
interface FormData {
|
interface FormData {
|
||||||
collectionId?: number;
|
collectionId?: number;
|
||||||
packageId?: number;
|
packageId?: number;
|
||||||
@ -261,15 +338,31 @@ const resetForm = () => {
|
|||||||
formData.classId = undefined;
|
formData.classId = undefined;
|
||||||
formData.scheduledDate = undefined;
|
formData.scheduledDate = undefined;
|
||||||
formData.scheduledTimeRange = undefined;
|
formData.scheduledTimeRange = undefined;
|
||||||
|
scheduleRefData.value = [];
|
||||||
lessonTypes.value = [];
|
lessonTypes.value = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 租户仅一个套餐,自动加载其课程包
|
||||||
const loadCollections = async () => {
|
const loadCollections = async () => {
|
||||||
|
loadingPackages.value = true;
|
||||||
try {
|
try {
|
||||||
collections.value = await getCourseCollections();
|
collections.value = await getCourseCollections();
|
||||||
|
if (collections.value.length > 0) {
|
||||||
|
const first = collections.value[0];
|
||||||
|
formData.collectionId = first.id as number;
|
||||||
|
const packages = await getCourseCollectionPackages(first.id);
|
||||||
|
if (first) {
|
||||||
|
(first as any).packages = packages;
|
||||||
|
}
|
||||||
|
if (!packages || packages.length === 0) {
|
||||||
|
message.warning('该套餐暂无课程包');
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载课程套餐失败:', error);
|
console.error('加载课程套餐失败:', error);
|
||||||
message.error('加载课程套餐失败');
|
message.error('加载课程套餐失败');
|
||||||
|
} finally {
|
||||||
|
loadingPackages.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -281,29 +374,6 @@ const loadMyClasses = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCollectionChange = async (collectionId: number) => {
|
|
||||||
formData.packageId = undefined;
|
|
||||||
formData.courseId = undefined;
|
|
||||||
formData.lessonType = undefined;
|
|
||||||
lessonTypes.value = [];
|
|
||||||
|
|
||||||
if (!collectionId) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const packages = await getCourseCollectionPackages(collectionId);
|
|
||||||
const collection = collections.value.find(c => c.id === collectionId);
|
|
||||||
if (collection) {
|
|
||||||
collection.packages = packages as CoursePackageItem[];
|
|
||||||
}
|
|
||||||
if (!packages || packages.length === 0) {
|
|
||||||
message.warning('该套餐暂无课程包');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('加载课程包失败:', error);
|
|
||||||
message.error('加载课程包失败');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const selectPackage = async (packageId: number) => {
|
const selectPackage = async (packageId: number) => {
|
||||||
formData.packageId = packageId;
|
formData.packageId = packageId;
|
||||||
|
|
||||||
@ -312,8 +382,24 @@ const selectPackage = async (packageId: number) => {
|
|||||||
const pkg = collection.packages.find((p: any) => p.id === packageId);
|
const pkg = collection.packages.find((p: any) => p.id === packageId);
|
||||||
if (pkg?.courses && pkg.courses.length > 0) {
|
if (pkg?.courses && pkg.courses.length > 0) {
|
||||||
formData.courseId = pkg.courses[0].id;
|
formData.courseId = pkg.courses[0].id;
|
||||||
|
|
||||||
|
// 加载排课计划参考(从课程包中任一课程的 scheduleRefData 获取)
|
||||||
|
const courseWithRef = pkg.courses.find((c: any) => c.scheduleRefData);
|
||||||
|
const rawRef = courseWithRef?.scheduleRefData ?? (pkg as any).scheduleRefData;
|
||||||
|
if (rawRef) {
|
||||||
|
try {
|
||||||
|
const parsed = typeof rawRef === 'string' ? JSON.parse(rawRef) : rawRef;
|
||||||
|
scheduleRefData.value = Array.isArray(parsed) ? parsed : [];
|
||||||
|
} catch (e) {
|
||||||
|
console.error('解析排课计划参考失败:', e);
|
||||||
|
scheduleRefData.value = [];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
scheduleRefData.value = [];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
formData.courseId = undefined;
|
formData.courseId = undefined;
|
||||||
|
scheduleRefData.value = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,11 +421,6 @@ const selectLessonType = (lessonType: string) => {
|
|||||||
formData.lessonType = lessonType;
|
formData.lessonType = lessonType;
|
||||||
};
|
};
|
||||||
|
|
||||||
const filterCollection = (input: string, option: any) => {
|
|
||||||
const collection = collections.value.find(c => c.id === option.value);
|
|
||||||
return collection?.name?.toLowerCase().includes(input.toLowerCase()) || false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const lessonTypeIconMap: Record<string, any> = {
|
const lessonTypeIconMap: Record<string, any> = {
|
||||||
INTRODUCTION: BookOutlined,
|
INTRODUCTION: BookOutlined,
|
||||||
INTRO: BookOutlined,
|
INTRO: BookOutlined,
|
||||||
@ -524,6 +605,29 @@ defineExpose({ open, openWithPreset });
|
|||||||
.package-count { font-size: 11px; color: #722ed1; }
|
.package-count { font-size: 11px; color: #722ed1; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.schedule-ref-card {
|
||||||
|
margin-top: 24px;
|
||||||
|
padding: 16px;
|
||||||
|
background: #f9f0ff;
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
.ref-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
|
||||||
|
.ref-icon {
|
||||||
|
color: #722ed1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ref-title {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #2D3436;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.lesson-type-empty {
|
.lesson-type-empty {
|
||||||
padding: 40px;
|
padding: 40px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user