hookehuyr

feat(teacher): 新增教师作业设置功能及相关API接口

添加教师作业设置页面表单提交功能,包括作业名称、频次、目标总数等字段
实现获取作业设置参数和提交作业设置的API接口
移除未使用的活动和小组成员选择功能
根据API返回数据动态加载年级、班级、课程和章节信息
/*
* @Date: 2025-06-23 11:46:21
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-06-25 10:51:28
* @LastEditTime: 2025-06-25 15:48:41
* @FilePath: /mlaj/src/api/teacher.js
* @Description: 文件描述
*/
......@@ -9,12 +9,37 @@ import { fn, fetch } from './fn'
const Api = {
TEACHER_GRADE_CLASS_LIST: '/srv/?a=user&t=teacher_grade_class_group_list',
TEACHER_FIND_SETTINGS: '/srv/?a=task&t=teacher_find_settings',
TEACHER_ADD_TASK: '/srv/?a=task&t=teacher_add',
}
/**
* 获取老师的年级、班级、课程列表信息
* @param {*} grade_id 年级ID 用来缩小班级、课程的筛选范围
* @param {*} class_id 班级ID 用来缩小课程的筛选范围
* @returns {Array} data { grade_list [{id, grade_name}], class_list [{id, class_name}], group_list [{id, title}] }
* @returns {Object} data { grade_list [{id, grade_name}], class_list [{id, class_name}], group_list [{id, title}] }
*/
export const getTeacherGradeClassListAPI = (params) => fn(fetch.get(Api.TEACHER_GRADE_CLASS_LIST, params))
/**
* 获取老师查询作业参数
* @returns {Object} data { grade_list [{id, grade_name}], class_list [{id, class_name}], group_list [{id, title, schedule_list[{id, title}]}], task_type, task_frequency }
*/
export const getTeacherFindSettingsAPI = (params) => fn(fetch.get(Api.TEACHER_FIND_SETTINGS, params))
/**
* 老师设置作业
* @param {*} title 作业名称
* @param {*} begin_date 开始日期
* @param {*} end_date 结束日期
* @param {*} target_number 目标总数
* @param {*} class_id 班级ID
* @param {*} group_id 年级ID
* @param {*} lesson_id 课程ID
* @param {*} task_type 任务类型
* @param {*} frequency 任务频率
* @param {*} schedule[{id, begin_date, end_date}] 批量设置课程章节的作业
* @returns {Object} data { id }
*/
export const setTeacherTaskAPI = (params) => fn(fetch.post(Api.TEACHER_ADD_TASK, params))
......
......@@ -2,7 +2,7 @@
* @Author: hookehuyr hookehuyr@gmail.com
* @Date: 2025-01-20 10:00:00
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-06-24 11:46:49
* @LastEditTime: 2025-06-25 15:49:50
* @FilePath: /mlaj/src/views/teacher/formPage.vue
* @Description: 教师作业新增表单页面
-->
......@@ -16,8 +16,8 @@
<!-- 作业名称输入框 -->
<div class="mb-6">
<van-field
v-model="formData.homework_name"
name="homework_name"
v-model="formData.title"
name="title"
:placeholder="`请输入${pageTitle === '设置作业' ? '作业' : '打卡'}名称(必填)`"
required
:border="false"
......@@ -28,8 +28,8 @@
<!-- 作业要求说明 -->
<div class="mb-6">
<van-field
v-model="formData.description"
name="description"
v-model="formData.note"
name="note"
type="textarea"
:placeholder="`请输入${pageTitle === '设置作业' ? '作业' : '打卡'}要求和说明`"
:border="false"
......@@ -45,11 +45,11 @@
<van-col span="12">
<label class="setting-label">{{ pageTitle === '设置作业' ? '作业' : '打卡' }}频次</label>
<van-field
v-model="formData.frequency"
v-model="formData.frequency_text"
is-link
readonly
name="frequency"
placeholder="每天"
name="frequency_text"
placeholder="请选择频次"
:border="false"
@click="showFrequencyPicker = true"
class="frequency-field"
......@@ -59,7 +59,7 @@
<label class="setting-label">目标总数</label>
<div class="target-count-container">
<van-stepper
v-model="formData.target_count"
v-model="formData.target_number"
min="1"
max="100"
integer
......@@ -122,7 +122,7 @@
<van-icon name="arrow" class="arrow-icon" @click="showCoursePicker = true" />
</div>
</div>
<div class="select-row" v-if="formData.course">
<div class="select-row" v-if="courseChapters[formData.course]?.length">
<div class="select-item">
<van-icon name="bookmark-o" class="select-icon" />
<span class="select-label">课程章节:</span>
......@@ -170,11 +170,6 @@
</div>
</div>
<!-- 类型选择器 -->
<van-popup v-model:show="showTypePicker" position="bottom">
<van-picker :columns="typeOptions" @confirm="onTypeConfirm" @cancel="showTypePicker = false" />
</van-popup>
<!-- 频次选择器 -->
<van-popup v-model:show="showFrequencyPicker" position="bottom">
<van-picker :columns="frequencyOptions" @confirm="onFrequencyConfirm" @cancel="showFrequencyPicker = false" />
......@@ -269,7 +264,7 @@
</van-popup>
<!-- 活动选择器 -->
<van-popup v-model:show="showActivityPicker" position="bottom">
<!-- <van-popup v-model:show="showActivityPicker" position="bottom">
<div class="p-4">
<van-search v-model="activitySearchValue" placeholder="搜索活动" @search="searchActivity" />
<van-list>
......@@ -277,7 +272,7 @@
:border="false" @click="onActivitySelect(activity)" />
</van-list>
</div>
</van-popup>
</van-popup> -->
<!-- 年级选择器 -->
<van-popup v-model:show="showGradePicker" position="bottom">
......@@ -302,7 +297,7 @@
</van-popup>
<!-- 小组选择器 -->
<van-popup v-model:show="showGroupPicker" position="bottom">
<!-- <van-popup v-model:show="showGroupPicker" position="bottom">
<div class="p-4">
<van-search v-model="groupSearchValue" placeholder="搜索小组" @search="searchGroup" />
<van-list>
......@@ -310,7 +305,7 @@
@click="onGroupSelect(group)" />
</van-list>
</div>
</van-popup>
</van-popup> -->
</AppLayout>
</template>
......@@ -322,6 +317,8 @@ import AppLayout from '@/components/layout/AppLayout.vue';
import FrostedGlass from '@/components/ui/FrostedGlass.vue';
import { useTitle } from '@vueuse/core';
import { getTeacherFindSettingsAPI, setTeacherTaskAPI } from "@/api/teacher";
const $route = useRoute();
const $router = useRouter();
......@@ -331,40 +328,41 @@ const pageTitle = computed(() => {
useTitle(pageTitle);
const type = ref('');
// 表单数据
const formData = ref({
homework_name: '',
description: '',
type: $route.query.type === 'homework' ? '上传附件' : '签到',
title: '',
note: '',
task_type: $route.query.type === 'homework' ? 'upload' : 'checkin',
frequency_text: '',
frequency: '',
target_count: 1,
target_number: 1,
start_time: new Date(),
end_time: new Date(),
course: '',
lesson_id: '',
chapter: '',
activity: '',
// activity: '',
grade: '',
grade_id: '',
class_name: '',
group_name: ''
class_id: '',
// group_name: ''
});
// 加载状态
const loading = ref(false);
// 弹窗显示状态
const showTypePicker = ref(false);
const showFrequencyPicker = ref(false);
const showStartTimePicker = ref(false);
const showEndTimePicker = ref(false);
const showCoursePicker = ref(false);
const showChapterPicker = ref(false);
const showChapterTimePicker = ref(false);
const showActivityPicker = ref(false);
// const showActivityPicker = ref(false);
const showGradePicker = ref(false);
const showClassPicker = ref(false);
const showGroupPicker = ref(false);
// const showGroupPicker = ref(false);
// 日期选择器相关
const startDate = ref(['2024', '01', '01']);
......@@ -372,67 +370,24 @@ const endDate = ref(['2024', '12', '31']);
const minDate = new Date(2020, 0, 1);
const maxDate = new Date(2035, 11, 31);
// 选项数据
const typeOptions = ref([
{ text: '签到', value: 'checkin' },
{ text: '作业', value: 'homework' },
{ text: '考试', value: 'exam' },
{ text: '活动', value: 'activity' }
]);
const frequencyOptions = ref([
{ text: '一次', value: 'once' },
{ text: '每日', value: 'daily' },
{ text: '每周', value: 'weekly' },
{ text: '每月', value: 'monthly' }
]);
const frequencyOptions = ref([]);
// 搜索值
const courseSearchValue = ref('');
const chapterSearchValue = ref('');
const activitySearchValue = ref('');
// const activitySearchValue = ref('');
const gradeSearchValue = ref('');
const classSearchValue = ref('');
const groupSearchValue = ref('');
// const groupSearchValue = ref('');
// 数据列表
const courses = ref([
{ id: 1, name: '数学课程' },
{ id: 2, name: '语文课程' },
{ id: 3, name: '英语课程' },
{ id: 4, name: '物理课程' }
]);
const courses = ref([]);
// 章节数据 - 根据课程动态变化
const chapters = ref([]);
// 各课程对应的章节数据
const courseChapters = {
'数学课程': [
{ id: 1, name: '第一章 数与代数', selected: false, startTime: '', endTime: '' },
{ id: 2, name: '第二章 几何图形', selected: false, startTime: '', endTime: '' },
{ id: 3, name: '第三章 统计与概率', selected: false, startTime: '', endTime: '' },
{ id: 4, name: '第四章 函数与方程', selected: false, startTime: '', endTime: '' }
],
'语文课程': [
{ id: 5, name: '第一单元 现代文阅读', selected: false, startTime: '', endTime: '' },
{ id: 6, name: '第二单元 古诗文阅读', selected: false, startTime: '', endTime: '' },
{ id: 7, name: '第三单元 写作训练', selected: false, startTime: '', endTime: '' },
{ id: 8, name: '第四单元 口语交际', selected: false, startTime: '', endTime: '' }
],
'英语课程': [
{ id: 9, name: 'Unit 1 Hello World', selected: false, startTime: '', endTime: '' },
{ id: 10, name: 'Unit 2 My Family', selected: false, startTime: '', endTime: '' },
{ id: 11, name: 'Unit 3 School Life', selected: false, startTime: '', endTime: '' },
{ id: 12, name: 'Unit 4 Hobbies', selected: false, startTime: '', endTime: '' }
],
'物理课程': [
{ id: 13, name: '第一章 力学基础', selected: false, startTime: '', endTime: '' },
{ id: 14, name: '第二章 热学原理', selected: false, startTime: '', endTime: '' },
{ id: 15, name: '第三章 电磁学', selected: false, startTime: '', endTime: '' },
{ id: 16, name: '第四章 光学现象', selected: false, startTime: '', endTime: '' }
]
};
const courseChapters = ref({});
// 已选择的章节列表
const selectedChapters = ref([]);
......@@ -442,33 +397,23 @@ const currentChapterTime = ref(['2024', '01', '01']);
const currentChapter = ref(null);
const currentTimeType = ref(''); // 'start' or 'end'
const activities = ref([
{ id: 1, name: '春游活动' },
{ id: 2, name: '运动会' },
{ id: 3, name: '文艺汇演' },
{ id: 4, name: '科技节' }
]);
const grades = ref([
{ id: 1, name: '一年级' },
{ id: 2, name: '二年级' },
{ id: 3, name: '三年级' },
{ id: 4, name: '四年级' }
]);
const classes = ref([
{ id: 1, name: '一班' },
{ id: 2, name: '二班' },
{ id: 3, name: '三班' },
{ id: 4, name: '四班' }
]);
const groups = ref([
{ id: 1, name: '第一小组' },
{ id: 2, name: '第二小组' },
{ id: 3, name: '第三小组' },
{ id: 4, name: '第四小组' }
]);
// const activities = ref([
// { id: 1, name: '春游活动' },
// { id: 2, name: '运动会' },
// { id: 3, name: '文艺汇演' },
// { id: 4, name: '科技节' }
// ]);
const grades = ref([]);
const classes = ref([]);
// const groups = ref([
// { id: 1, name: '第一小组' },
// { id: 2, name: '第二小组' },
// { id: 3, name: '第三小组' },
// { id: 4, name: '第四小组' }
// ]);
// 计算属性 - 时间显示格式
const startTimeDisplay = computed(() => {
......@@ -517,12 +462,12 @@ const selectedChaptersCount = computed(() => {
return chapters.value.filter(chapter => chapter.selected).length;
});
const filteredActivities = computed(() => {
if (!activitySearchValue.value) return activities.value;
return activities.value.filter(activity =>
activity.name.toLowerCase().includes(activitySearchValue.value.toLowerCase())
);
});
// const filteredActivities = computed(() => {
// if (!activitySearchValue.value) return activities.value;
// return activities.value.filter(activity =>
// activity.name.toLowerCase().includes(activitySearchValue.value.toLowerCase())
// );
// });
const filteredGrades = computed(() => {
if (!gradeSearchValue.value) return grades.value;
......@@ -538,12 +483,12 @@ const filteredClasses = computed(() => {
);
});
const filteredGroups = computed(() => {
if (!groupSearchValue.value) return groups.value;
return groups.value.filter(group =>
group.name.toLowerCase().includes(groupSearchValue.value.toLowerCase())
);
});
// const filteredGroups = computed(() => {
// if (!groupSearchValue.value) return groups.value;
// return groups.value.filter(group =>
// group.name.toLowerCase().includes(groupSearchValue.value.toLowerCase())
// );
// });
/**
* 格式化日期时间
......@@ -560,20 +505,12 @@ const formatDateTime = (date) => {
};
/**
* 类型选择确认
* @param {Object} option - 选中的选项
*/
const onTypeConfirm = (option) => {
formData.value.type = option.selectedOptions[0].text;
showTypePicker.value = false;
};
/**
* 频次选择确认
* @param {Object} option - 选中的选项
*/
const onFrequencyConfirm = (option) => {
formData.value.frequency = option.selectedOptions[0].text;
formData.value.frequency_text = option.selectedOptions[0].text;
formData.value.frequency = option.selectedOptions[0].value;
showFrequencyPicker.value = false;
};
......@@ -633,10 +570,11 @@ const onEndTimeConfirm = () => {
*/
const onCourseSelect = (course) => {
formData.value.course = course.name;
formData.value.lesson_id = course.id;
// 清空之前选择的章节
selectedChapters.value = [];
// 根据选择的课程更新章节数据
chapters.value = courseChapters[course.name] ? JSON.parse(JSON.stringify(courseChapters[course.name])) : [];
chapters.value = courseChapters.value[course.name] ? JSON.parse(JSON.stringify(courseChapters.value[course.name])) : [];
showCoursePicker.value = false;
courseSearchValue.value = '';
};
......@@ -758,11 +696,11 @@ const confirmChapterSelection = () => {
* 活动选择
* @param {Object} activity - 选中的活动
*/
const onActivitySelect = (activity) => {
formData.value.activity = activity.name;
showActivityPicker.value = false;
activitySearchValue.value = '';
};
// const onActivitySelect = (activity) => {
// formData.value.activity = activity.name;
// showActivityPicker.value = false;
// activitySearchValue.value = '';
// };
/**
* 年级选择
......@@ -770,6 +708,7 @@ const onActivitySelect = (activity) => {
*/
const onGradeSelect = (grade) => {
formData.value.grade = grade.name;
formData.value.grade_id = grade.id;
showGradePicker.value = false;
gradeSearchValue.value = '';
};
......@@ -780,6 +719,7 @@ const onGradeSelect = (grade) => {
*/
const onClassSelect = (classItem) => {
formData.value.class_name = classItem.name;
formData.value.class_id = classItem.id;
showClassPicker.value = false;
classSearchValue.value = '';
};
......@@ -788,11 +728,11 @@ const onClassSelect = (classItem) => {
* 小组选择
* @param {Object} group - 选中的小组
*/
const onGroupSelect = (group) => {
formData.value.group_name = group.name;
showGroupPicker.value = false;
groupSearchValue.value = '';
};
// const onGroupSelect = (group) => {
// formData.value.group_name = group.name;
// showGroupPicker.value = false;
// groupSearchValue.value = '';
// };
/**
* 搜索课程
......@@ -814,9 +754,9 @@ const searchChapter = (value) => {
* 搜索活动
* @param {string} value - 搜索值
*/
const searchActivity = (value) => {
activitySearchValue.value = value;
};
// const searchActivity = (value) => {
// activitySearchValue.value = value;
// };
/**
* 搜索年级
......@@ -838,9 +778,9 @@ const searchClass = (value) => {
* 搜索小组
* @param {string} value - 搜索值
*/
const searchGroup = (value) => {
groupSearchValue.value = value;
};
// const searchGroup = (value) => {
// groupSearchValue.value = value;
// };
/**
* 表单提交处理
......@@ -851,7 +791,7 @@ const handleSubmit = async (values) => {
loading.value = true;
// 验证必填项
if (!formData.value.homework_name) {
if (!formData.value.title) {
showToast('请输入作业名称');
return;
}
......@@ -860,27 +800,24 @@ const handleSubmit = async (values) => {
const submitData = {
...formData.value,
// 格式化日期为YYYY-MM-DD格式
start_time: formatDateTime(formData.value.start_time),
end_time: formatDateTime(formData.value.end_time),
begin_date: formatDateTime(formData.value.start_time),
end_date: formatDateTime(formData.value.end_time),
// 添加课程章节选择数据
selected_chapters: selectedChapters.value.map(chapter => ({
schedule: selectedChapters.value.map(chapter => ({
id: chapter.id,
name: chapter.name,
start_time: formatDateTime(chapter.startTime),
end_time: formatDateTime(chapter.endTime)
begin_date: formatDateTime(chapter.startTime),
end_date: formatDateTime(chapter.endTime)
}))
};
// 这里可以调用API提交数据
console.log('提交的表单数据:', submitData);
// 模拟API调用
await new Promise(resolve => setTimeout(resolve, 1000));
const { code, data } = await setTeacherTaskAPI(submitData);
if (code) {
showToast('保存成功');
// 返回上一页或跳转到列表页
// $router.back();
$router.back();
}
} catch (error) {
console.error('提交失败:', error);
......@@ -893,9 +830,37 @@ const handleSubmit = async (values) => {
/**
* 组件挂载时初始化数据
*/
onMounted(() => {
onMounted(async () => {
// 这里可以调用API获取课程、活动、年级、班级、小组等数据
console.log('页面初始化');
const { code, data } = await getTeacherFindSettingsAPI();
if (code) {
frequencyOptions.value = Object.entries(data.task_frequency).map(([value, text]) => ({
text,
value: String(value) // 确保值为字符串类型
}));
grades.value = data.grade_list.map(grade => ({
name: grade.grade_name,
id: String(grade.id)
}));
classes.value = data.class_list.map(classItem => ({
name: classItem.class_name,
id: String(classItem.id)
}));
courses.value = data.group_list.map(course => ({
name: course.title,
id: String(course.id),
schedule_list: course.schedule_list
}));
data.group_list.forEach(course => {
courseChapters.value[course.title] = course.schedule_list.map(chapter => ({
id: chapter.id,
name: chapter.title,
selected: false,
startTime: '',
endTime: ''
}));
});
}
});
</script>
......