diff --git a/src/App.vue b/src/App.vue index dc20bfa..4336d4a 100644 --- a/src/App.vue +++ b/src/App.vue @@ -3,6 +3,59 @@ import { onMounted } from 'vue' import { RouterView } from 'vue-router' import { useUserStore } from '@/stores/user' import AppLayout from '@/components/layout/AppLayout.vue' +import { NConfigProvider } from 'naive-ui' +import type { GlobalThemeOverrides } from 'naive-ui'; + + +// 自定义naive-ui主题颜色 +const themeOverrides: GlobalThemeOverrides = { + common: { + primaryColor: '#0288D1', + primaryColorHover: '#0277BD', // A slightly darker shade for hover + primaryColorPressed: '#01579B', // A darker shade for pressed + errorColor: '#FF4D4F', + errorColorHover: '#E54547', + errorColorPressed: '#C0383A', + }, + Button: { + // For ghost primary buttons + textColorGhostPrimary: '#0288D1', + borderPrimary: '1px solid #0288D1', + // For ghost error buttons + textColorGhostError: '#FF4D4F', + borderError: '1px solid #FF4D4F', + }, + Tag: { + colorPrimary: '#0288D1', + colorPrimaryHover: '#0277BD', + colorPrimaryPressed: '#01579B', + textColorPrimary: '#ffffff', + }, + Card: { + borderColor: '#E6E6E6', + }, + Input: { + borderHover: '#0288D1', + borderFocus: '#0288D1', + boxShadowFocus: '0 0 0 1px rgba(2, 136, 209, 0.5)', + }, + InputNumber: { + borderHover: '#0288D1', + borderFocus: '#0288D1', + boxShadowFocus: '0 0 0 1px rgba(2, 136, 209, 0.5)', + }, + Select: { + borderHover: '#0288D1', + borderFocus: '#0288D1', + boxShadowFocus: '0 0 0 1px rgba(2, 136, 209, 0.5)', + }, + Modal: { + borderRadius: '8px', + }, + Dialog: { + borderRadius: '8px', + } +}; const userStore = useUserStore() @@ -14,9 +67,11 @@ onMounted(() => { diff --git a/src/components/admin/ExamComponents/ExamSettingsModal.vue b/src/components/admin/ExamComponents/ExamSettingsModal.vue index 5438fa3..315bd13 100644 --- a/src/components/admin/ExamComponents/ExamSettingsModal.vue +++ b/src/components/admin/ExamComponents/ExamSettingsModal.vue @@ -25,6 +25,12 @@ + +
+ + +
+
@@ -292,6 +298,7 @@ interface ExamSettings { participants: 'all' | 'by_school'; selectedClasses: string[]; instructions: string; + examCount: number; // 考试模式专用 enforceOrder: boolean; @@ -365,6 +372,7 @@ const formData = ref({ participants: 'all', selectedClasses: [], instructions: '', + examCount: 0, // 考试模式专用 enforceOrder: false, diff --git a/src/components/common/ImportModal.vue b/src/components/common/ImportModal.vue new file mode 100644 index 0000000..418cecb --- /dev/null +++ b/src/components/common/ImportModal.vue @@ -0,0 +1,475 @@ + + + + + diff --git a/src/components/common/README.md b/src/components/common/README.md new file mode 100644 index 0000000..b78c318 --- /dev/null +++ b/src/components/common/README.md @@ -0,0 +1,136 @@ +# ImportModal 通用导入组件 + +一个可复用的数据导入弹窗组件,支持模板下载、文件上传、拖拽上传等功能。 + +## 功能特性 + +- 📄 **模板下载**:支持下载 Excel 导入模板 +- 📤 **文件上传**:支持点击上传和拖拽上传 +- 📊 **进度显示**:实时显示上传进度 +- ✅ **结果反馈**:详细的导入结果提示 +- 🔒 **文件校验**:文件格式和大小限制 +- 📱 **响应式设计**:适配不同屏幕尺寸 + +## 使用方法 + +### 1. 导入组件 + +```vue + +``` + +### 2. 在模板中使用 + +```vue + +``` + +### 3. 处理事件 + +```vue + +``` + +## Props + +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| show | boolean | - | 控制弹窗显示/隐藏 | +| templateName | string | 'import_template.xlsx' | 模板文件名 | +| importType | string | 'default' | 导入类型标识 | + +## Events + +| 事件名 | 参数 | 说明 | +|--------|------|------| +| update:show | boolean | 弹窗显示状态变化 | +| success | result: ImportResult | 导入成功回调 | +| template-download | type?: string | 模板下载回调 | + +## ImportResult 类型 + +```typescript +interface ImportResult { + success: boolean; + message: string; + details?: { + success: number; + failed: number; + }; +} +``` + +## 自定义配置 + +### 文件限制 +- 支持格式:`.xlsx`, `.xls` +- 文件大小:最大 10MB +- 同时上传:仅支持单文件 + +### 样式自定义 +组件使用 scoped 样式,可通过 CSS 变量或深度选择器自定义样式。 + +## API 集成点 + +组件中预留了以下 API 集成点,需要根据实际项目进行实现: + +1. **模板下载 API** + ```javascript + // 在 downloadTemplate 函数中实现 + const downloadTemplate = () => { + // TODO: 调用模板下载 API + }; + ``` + +2. **文件上传 API** + ```javascript + // 在 handleUpload 函数中实现 + const handleUpload = (options) => { + // TODO: 调用文件上传 API + }; + ``` + +3. **数据导入 API** + ```javascript + // 在 startImport 函数中实现 + const startImport = async () => { + // TODO: 调用数据导入 API + }; + ``` + +## 注意事项 + +1. 确保后端支持对应的文件格式 +2. 模板格式要与后端解析逻辑一致 +3. 合理设置文件大小限制 +4. 提供清晰的错误提示信息 +5. 考虑网络异常情况的处理 diff --git a/src/router/index.ts b/src/router/index.ts index b4db1d0..dccb627 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -54,7 +54,10 @@ import GeneralManagement from '@/views/teacher/course/GeneralManagement.vue' // 作业子组件 import HomeworkLibrary from '@/views/teacher/course/HomeworkLibrary.vue' import HomeworkReview from '@/views/teacher/course/HomeworkReview.vue' -// 练考通菜单组件 +// 考试管理组件 + +import ExamManagement from '@/views/teacher/course/ExamPages/ExamPage.vue' +import QuestionManagement from '@/views/teacher/course/ExamPages/QuestionManagement.vue' import ExamLibrary from '@/views/teacher/course/ExamPages/ExamLibrary.vue' import MarkingCenter from '@/views/teacher/course/ExamPages/MarkingCenter.vue' import AddExam from '@/views/teacher/course/ExamPages/AddExam.vue' @@ -156,7 +159,7 @@ const routes: RouteRecordRaw[] = [ path: 'practice', name: 'PracticeManagement', component: PracticeManagement, - meta: { title: '练考通管理' }, + meta: { title: '考试管理' }, redirect: (to) => `/teacher/course-editor/${to.params.id}/practice/exam-library`, children: [ { @@ -241,7 +244,40 @@ const routes: RouteRecordRaw[] = [ name: 'ChapterEditor', component: ChapterEditor, meta: { title: '章节编辑' } - } + }, + { + path: 'exam-management', + name: 'ExamManagement', + component: ExamManagement, + meta: { title: '考试管理' }, + redirect: '/teacher/exam-management/question-management', + children: [ + { + path: 'question-management', + name: 'QuestionManagement', + component: QuestionManagement, + meta: { title: '试题管理' } + }, + { + path: 'exam-library', + name: 'ExamLibrary', + component: ExamLibrary, + meta: { title: '试卷管理' } + }, + { + path: 'marking-center', + name: 'MarkingCenter', + component: MarkingCenter, + meta: { title: '阅卷中心' } + }, + { + path: 'add', + name: 'AddExam', + component: AddExam, + meta: { title: '添加试卷' } + } + ] + }, ] }, diff --git a/src/views/teacher/AdminDashboard.vue b/src/views/teacher/AdminDashboard.vue index 340e96c..3710937 100644 --- a/src/views/teacher/AdminDashboard.vue +++ b/src/views/teacher/AdminDashboard.vue @@ -24,6 +24,44 @@ 课程管理 + + + + + + + @@ -50,7 +88,7 @@