feat: 展播模式优化与排课表修复

- 展播模式:空状态/错误状态添加返回上课按钮
- 展播模式:退出时自动跳转回上课页面或关闭标签页
- 数据库:lesson表id添加AUTO_INCREMENT,修复预约上课报错

Made-with: Cursor
This commit is contained in:
zhonghua 2026-03-16 19:22:06 +08:00
parent 50efe68f62
commit 709e59e142
3 changed files with 53 additions and 4 deletions

View File

@ -11,11 +11,16 @@ declare module 'vue' {
AAvatar: typeof import('ant-design-vue/es')['Avatar'] AAvatar: typeof import('ant-design-vue/es')['Avatar']
ABadge: typeof import('ant-design-vue/es')['Badge'] ABadge: typeof import('ant-design-vue/es')['Badge']
AButton: typeof import('ant-design-vue/es')['Button'] AButton: typeof import('ant-design-vue/es')['Button']
AButtonGroup: typeof import('ant-design-vue/es')['ButtonGroup']
ACard: typeof import('ant-design-vue/es')['Card'] ACard: typeof import('ant-design-vue/es')['Card']
ACheckbox: typeof import('ant-design-vue/es')['Checkbox'] ACheckbox: typeof import('ant-design-vue/es')['Checkbox']
ACheckboxGroup: typeof import('ant-design-vue/es')['CheckboxGroup'] ACheckboxGroup: typeof import('ant-design-vue/es')['CheckboxGroup']
ACol: typeof import('ant-design-vue/es')['Col'] ACol: typeof import('ant-design-vue/es')['Col']
ADatePicker: typeof import('ant-design-vue/es')['DatePicker']
ADescriptions: typeof import('ant-design-vue/es')['Descriptions']
ADescriptionsItem: typeof import('ant-design-vue/es')['DescriptionsItem']
ADivider: typeof import('ant-design-vue/es')['Divider'] ADivider: typeof import('ant-design-vue/es')['Divider']
ADrawer: typeof import('ant-design-vue/es')['Drawer']
ADropdown: typeof import('ant-design-vue/es')['Dropdown'] ADropdown: typeof import('ant-design-vue/es')['Dropdown']
AEmpty: typeof import('ant-design-vue/es')['Empty'] AEmpty: typeof import('ant-design-vue/es')['Empty']
AForm: typeof import('ant-design-vue/es')['Form'] AForm: typeof import('ant-design-vue/es')['Form']
@ -34,25 +39,33 @@ declare module 'vue' {
AMenuItem: typeof import('ant-design-vue/es')['MenuItem'] AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
AModal: typeof import('ant-design-vue/es')['Modal'] AModal: typeof import('ant-design-vue/es')['Modal']
APageHeader: typeof import('ant-design-vue/es')['PageHeader'] APageHeader: typeof import('ant-design-vue/es')['PageHeader']
APagination: typeof import('ant-design-vue/es')['Pagination']
APopconfirm: typeof import('ant-design-vue/es')['Popconfirm'] APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
AProgress: typeof import('ant-design-vue/es')['Progress'] AProgress: typeof import('ant-design-vue/es')['Progress']
ARadio: typeof import('ant-design-vue/es')['Radio'] ARadio: typeof import('ant-design-vue/es')['Radio']
ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup'] ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']
ARangePicker: typeof import('ant-design-vue/es')['RangePicker']
ARate: typeof import('ant-design-vue/es')['Rate']
ARow: typeof import('ant-design-vue/es')['Row'] ARow: typeof import('ant-design-vue/es')['Row']
ASelect: typeof import('ant-design-vue/es')['Select'] ASelect: typeof import('ant-design-vue/es')['Select']
ASelectOptGroup: typeof import('ant-design-vue/es')['SelectOptGroup'] ASelectOptGroup: typeof import('ant-design-vue/es')['SelectOptGroup']
ASelectOption: typeof import('ant-design-vue/es')['SelectOption'] ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
ASkeleton: typeof import('ant-design-vue/es')['Skeleton']
ASpace: typeof import('ant-design-vue/es')['Space'] ASpace: typeof import('ant-design-vue/es')['Space']
ASpin: typeof import('ant-design-vue/es')['Spin'] ASpin: typeof import('ant-design-vue/es')['Spin']
AStatistic: typeof import('ant-design-vue/es')['Statistic']
AStep: typeof import('ant-design-vue/es')['Step'] AStep: typeof import('ant-design-vue/es')['Step']
ASteps: typeof import('ant-design-vue/es')['Steps'] ASteps: typeof import('ant-design-vue/es')['Steps']
ASubMenu: typeof import('ant-design-vue/es')['SubMenu']
ASwitch: typeof import('ant-design-vue/es')['Switch'] ASwitch: typeof import('ant-design-vue/es')['Switch']
ATable: typeof import('ant-design-vue/es')['Table'] ATable: typeof import('ant-design-vue/es')['Table']
ATabPane: typeof import('ant-design-vue/es')['TabPane'] ATabPane: typeof import('ant-design-vue/es')['TabPane']
ATabs: typeof import('ant-design-vue/es')['Tabs'] ATabs: typeof import('ant-design-vue/es')['Tabs']
ATag: typeof import('ant-design-vue/es')['Tag'] ATag: typeof import('ant-design-vue/es')['Tag']
ATextarea: typeof import('ant-design-vue/es')['Textarea'] ATextarea: typeof import('ant-design-vue/es')['Textarea']
ATimeRangePicker: typeof import('ant-design-vue/es')['TimeRangePicker']
ATooltip: typeof import('ant-design-vue/es')['Tooltip'] ATooltip: typeof import('ant-design-vue/es')['Tooltip']
ATypographyText: typeof import('ant-design-vue/es')['TypographyText']
AUpload: typeof import('ant-design-vue/es')['Upload'] AUpload: typeof import('ant-design-vue/es')['Upload']
FilePreviewModal: typeof import('./components/FilePreviewModal.vue')['default'] FilePreviewModal: typeof import('./components/FilePreviewModal.vue')['default']
FileUploader: typeof import('./components/course/FileUploader.vue')['default'] FileUploader: typeof import('./components/course/FileUploader.vue')['default']

View File

@ -10,7 +10,10 @@
<div v-else-if="error" class="error-container"> <div v-else-if="error" class="error-container">
<ExclamationCircleOutlined style="font-size: 48px; color: #ff4d4f;" /> <ExclamationCircleOutlined style="font-size: 48px; color: #ff4d4f;" />
<p>{{ error }}</p> <p>{{ error }}</p>
<a-space>
<a-button type="primary" @click="loadData">重新加载</a-button> <a-button type="primary" @click="loadData">重新加载</a-button>
<a-button @click="goBackToLesson">返回上课</a-button>
</a-space>
</div> </div>
<!-- 展播内容 --> <!-- 展播内容 -->
@ -30,19 +33,22 @@
<div v-else class="empty-container"> <div v-else class="empty-container">
<InboxOutlined style="font-size: 48px; color: #ccc;" /> <InboxOutlined style="font-size: 48px; color: #ccc;" />
<p>暂无展播内容</p> <p>暂无展播内容</p>
<p class="empty-hint">请先在上课页面选择教学环节或确认课程已配置教学流程</p>
<a-button type="primary" @click="goBackToLesson">返回上课</a-button>
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, onMounted, onUnmounted } from 'vue'; import { ref, computed, onMounted, onUnmounted } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { ExclamationCircleOutlined, InboxOutlined } from '@ant-design/icons-vue'; import { ExclamationCircleOutlined, InboxOutlined } from '@ant-design/icons-vue';
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
import KidsMode from './components/KidsMode.vue'; import KidsMode from './components/KidsMode.vue';
import * as teacherApi from '@/api/teacher'; import * as teacherApi from '@/api/teacher';
const route = useRoute(); const route = useRoute();
const router = useRouter();
// //
const loading = ref(true); const loading = ref(true);
@ -273,9 +279,24 @@ const loadData = async () => {
} }
}; };
// 退 //
const goBackToLesson = () => {
if (lessonId) {
router.push(`/teacher/lessons/${lessonId}`);
} else {
router.push('/teacher/lessons');
}
};
// 退
const handleExit = () => { const handleExit = () => {
message.info('展播模式已关闭,您可以关闭此标签页'); // opener
if (window.opener && !window.opener.closed) {
window.opener.focus();
window.close();
} else {
goBackToLesson();
}
}; };
// //
@ -358,6 +379,12 @@ onUnmounted(() => {
font-size: 18px; font-size: 18px;
opacity: 0.8; opacity: 0.8;
} }
.empty-hint {
font-size: 14px !important;
opacity: 0.6;
margin: 0;
}
} }
.error-container { .error-container {

View File

@ -0,0 +1,9 @@
-- =====================================================
-- 幼儿园阅读平台数据库迁移脚本
-- 版本V12
-- 描述:为 lesson 表(排课表)添加 id 自增,修复预约上课报错
-- =====================================================
-- 说明V11 迁移遗漏了 lesson 表,导致插入时 "Field 'id' doesn't have a default value"
ALTER TABLE `lesson`
MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键 ID';