123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 |
- <template>
- <div class="h-full bg-white">
- <div v-if="pageState" style="margin-top: 1rem">
- <n-form :label-width="200" inline>
- <n-form-item class="min-w-34" label="请选择查询学员" path="user.name">
- <n-input placeholder="请选择查询学员" />
- </n-form-item>
- <n-form-item class="min-w-34" label="请选择要查询的班级" path="classId">
- <n-select
- v-model:value="scheduleParamsOptions.classId"
- :options="groupList"
- clearable
- placeholder="请选择班级"
- />
- </n-form-item>
- <n-form-item class="min-w-34" label="请选择要查询的时间范围" path="user.name">
- <n-date-picker
- v-model:value="dateRange"
- type="daterange"
- clearable
- time-zone="Asia/Shanghai"
- placeholder="请选择时间范围"
- :on-confirm="differenceInSevenDays"
- :on-clear="
- () => {
- scheduleParamsOptions.startTime = '';
- scheduleParamsOptions.endTime = '';
- }
- "
- />
- </n-form-item>
- <n-form-item class="min-w-34" label="要查询的授课教师" path="user.name">
- <n-select
- v-model:value="scheduleParamsOptions.teacherId"
- :options="teacherOptions"
- placeholder="请选择授课教师"
- clearable
- />
- </n-form-item>
- </n-form>
- <n-button-group>
- <n-button type="primary" ghost @click="previousDateSchedule"> 上一周 </n-button>
- <n-button type="primary" ghost @click="nextDateSchedule"> 下一周 </n-button>
- <n-button type="primary" @click="loadScheduleQuery"> 搜索 </n-button>
- <n-button type="primary" @click="pageState = !pageState"> 新增排课 </n-button>
- </n-button-group>
- <div style="height: 1rem"></div>
- <n-spin :show="loading">
- <table border="1" style="width: 100%">
- <tbody width="100">
- <tr>
- <th class="w-20 color-blue-800">时间</th>
- <th v-for="weekDate in [0, 1, 2, 3, 4, 5, 6]" :key="weekDate" class="font-500 color-blue-800">
- {{ new Date(weekStartTime + weekDate * 86400000).getMonth() + 1 }}月{{
- new Date(weekStartTime + weekDate * 86400000).getDate()
- }}号 - 周{{ chineseNumbers[getDayOfTheWeekNow(weekStartTime, weekDate)] }}
- </th>
- </tr>
- <tr v-for="key in timeKey" :key="key">
- <td>{{ key }}</td>
- <template v-for="index in [0, 1, 2, 3, 4, 5, 6]" :key="index">
- <td
- v-if="
- scheduleList[getDayOfTheWeekNow(weekStartTime, index)][key] &&
- scheduleList[getDayOfTheWeekNow(weekStartTime, index)][key]['empty'] === false &&
- scheduleList[getDayOfTheWeekNow(weekStartTime, index)][key]['break'] === false
- "
- :rowspan="scheduleList[getDayOfTheWeekNow(weekStartTime, index)][key]['colspan']"
- >
- 时间:
- {{ scheduleList[getDayOfTheWeekNow(weekStartTime, index)][key]['startTime'] }} -
- {{ scheduleList[getDayOfTheWeekNow(weekStartTime, index)][key]['endTime'].split(' ').pop() }}<br />
- 讲师: {{ scheduleList[getDayOfTheWeekNow(weekStartTime, index)][key]['teacherName'] }}<br />
- 授课: {{ scheduleList[getDayOfTheWeekNow(weekStartTime, index)][key]['category'] }}
- {{ scheduleList[getDayOfTheWeekNow(weekStartTime, index)][key]['subjects'] }}<br />
- 教室: {{ scheduleList[getDayOfTheWeekNow(weekStartTime, index)][key]['classroom'] }}<br />
- 班级: {{ scheduleList[getDayOfTheWeekNow(weekStartTime, index)][key]['className'] }}
- </td>
- <td
- v-else-if="
- scheduleList[getDayOfTheWeekNow(weekStartTime, index)][key] &&
- scheduleList[getDayOfTheWeekNow(weekStartTime, index)][key]['empty'] === true
- "
- >
- 暂无
- </td>
- </template>
- </tr>
- </tbody>
- </table>
- </n-spin>
- </div>
- <div v-if="!pageState" class="wh-full flex-col-center">
- <n-spin :show="formLoading">
- <n-form ref="formRef" size="large" label-placement="left" style="margin-right: 5rem" :model="model">
- <n-form-item label="排课班级" path="groupList">
- <n-select v-model:value="model.classId" :options="groupList" />
- </n-form-item>
- <n-form-item label="所在教室" path="classRoomList">
- <n-select v-model:value="model.roomId" :options="classRoomList" />
- </n-form-item>
- <n-form-item label="任课老师" path="teacherId">
- <n-select
- v-model:value="model.teacherId"
- placeholder="请选择任课老师"
- :options="teacherOptions"
- clearable
- />
- </n-form-item>
- <n-form-item label="助教老师" path="multipleSelectValue">
- <n-select
- v-model:value="model.assistantId"
- placeholder="请选择助教老师"
- :options="teacherOptions"
- clearable
- />
- </n-form-item>
- <n-form-item label="教授科目" path="multipleSelectValue">
- <n-cascader
- v-model:value="model.subjectsId"
- placeholder="请选择课程"
- :options="categoryAndSubjectOptions"
- show-path
- check-strategy="child"
- remote
- :on-load="categoryAndSubjectLoad"
- />
- </n-form-item>
- <n-form-item label="上课时间" path="datetimeValue">
- <n-space>
- <n-date-picker v-model:value="dateValue" clearable time-zone="Asia/Shanghai" type="date" />
- <n-time-picker v-model:value="startTime" clearable time-zone="Asia/Shanghai" />
- <n-time-picker v-model:value="endTime" clearable time-zone="Asia/Shanghai" />
- </n-space>
- </n-form-item>
- <n-form-item label="是否连选" path="switchValue">
- <n-switch v-model:value="isRepeatTime" />
- </n-form-item>
- <n-form-item label="连选天数" path="sliderValue">
- <n-slider v-model:value="repeatTime" :step="1" :max="7" />
- </n-form-item>
- <n-form-item label="单节课时长" path="inputNumberValue">
- <n-input-number v-model:value="model.lessonTime" />
- </n-form-item>
- <div style="display: flex; justify-content: flex-end">
- <n-button-group>
- <n-button type="primary" @click="handleValidateButtonClick"> 确认提交 </n-button>
- <n-button type="primary" @click="pageState = !pageState"> 返回前一页 </n-button>
- </n-button-group>
- </div>
- </n-form>
- </n-spin>
- </div>
- <div style="width: 100%; height: 1rem"></div>
- </div>
- </template>
- <script setup lang="ts">
- import { ref, reactive } from 'vue';
- import { useRoute } from 'vue-router';
- import type { CascaderOption } from 'naive-ui';
- import { formatTimestamp } from '~/src/utils';
- import {
- queryUserAll,
- queryCategoryParams,
- querySubject,
- queryClassAll,
- addSchedule,
- queryClassRoomList,
- querySchedule
- } from './api';
- import type { ScheduleParams, QueryScheduleParams } from './api';
- const route = useRoute();
- const model = reactive<ScheduleParams>({
- week: 0,
- startTime: 0,
- endTime: 0,
- roomId: null,
- classId: null,
- assistantId: null,
- teacherId: null,
- categoryId: null,
- subjectsId: null,
- createTime: 0,
- modifyTime: 0,
- createUid: 0,
- disabled: 'N'
- });
- const classId = route.query.classId;
- const chineseNumbers: { [index: number]: string } = {
- 0: '零',
- 1: '一',
- 2: '二',
- 3: '三',
- 4: '四',
- 5: '五',
- 6: '六',
- 7: '日',
- 8: '八',
- 9: '九'
- };
- const dateValue = ref<number>(0);
- const startTime = ref<number>(0);
- const endTime = ref<number>(0);
- const isRepeatTime = ref<boolean>(true);
- const repeatTime = ref<number>(1);
- const pageState = ref<boolean>(true);
- const categoryAndSubjectOptions = ref<any[]>([]);
- const groupList = ref<any[]>([]);
- const classRoomList = ref<any[]>([]);
- const teacherOptions = ref<any[]>();
- const loading = ref<boolean>(false);
- const formLoading = ref<boolean>(false);
- const nowDate = new Date();
- nowDate.setHours(0, 0, 0, 0);
- const sevenDaysLater = new Date(nowDate);
- sevenDaysLater.setDate(nowDate.getDate() + 6);
- sevenDaysLater.setHours(0, 0, 0, 0);
- const dateRange = ref<[number, number]>([nowDate.getTime(), sevenDaysLater.getTime()]);
- const weekStartTime = ref<number>(nowDate.getTime());
- const scheduleParamsOptions = reactive<QueryScheduleParams>({
- studentId: null,
- classId: null,
- subjectId: null,
- teacherId: null,
- startTime: null,
- endTime: null,
- week: null,
- roomId: null,
- assistantId: null,
- categoryId: null
- });
- const scheduleList = ref<{ [index: string]: any }>({
- '1': {},
- '2': {},
- '3': {},
- '4': {},
- '5': {},
- '6': {},
- '7': {}
- });
- const timeKey = ref<string[]>([
- '08:00',
- '09:00',
- '10:00',
- '11:00',
- '12:00',
- '13:00',
- '14:00',
- '15:00',
- '16:00',
- '17:00',
- '18:00',
- '19:00',
- '20:00',
- '21:00',
- '22:00',
- '23:00'
- ]);
- function categoryAndSubjectLoad(option: CascaderOption) {
- model.categoryId = option.value as number;
- return new Promise<void>(resolve => {
- option.children = [];
- querySubject(1, 100, {
- categoryId: option.value as number
- }).then(respone => {
- respone.data?.map(r => {
- option.children?.push({
- label: r.name,
- value: r.id,
- depth: 2,
- isLeaf: true
- });
- return r;
- });
- resolve();
- });
- });
- }
- async function handleValidateButtonClick() {
- formLoading.value = true;
- const modelStartTime = new Date(startTime.value);
- const modelEndTime = new Date(endTime.value);
- if (modelStartTime.getTime() >= modelEndTime.getTime()) {
- window.$message?.error('开始时间不能大于或等于结束时间');
- formLoading.value = false;
- return;
- }
- const modelDate = new Date(dateValue.value);
- modelStartTime.setFullYear(modelDate.getFullYear(), modelDate.getMonth(), modelDate.getDate());
- modelEndTime.setFullYear(modelDate.getFullYear(), modelDate.getMonth(), modelDate.getDate());
- model.startTime = formatTimestamp(modelStartTime.getTime());
- model.endTime = formatTimestamp(modelEndTime.getTime());
- model.week = modelStartTime.getDay();
- const res = await addSchedule(repeatTime.value, model);
- formLoading.value = false;
- if (!res.status && res.msg !== null) {
- window.$message?.error(res.msg);
- return;
- }
- pageState.value = !pageState.value;
- loadScheduleQuery();
- window.$message?.success('操作成功!');
- }
- function validateDate(nowtime: [number, number]): boolean {
- if (!nowtime) {
- return false;
- }
- if (nowtime instanceof Array) {
- const differenceInMilliseconds: number = nowtime[1] + 86400000 - nowtime[0];
- const days = Math.floor(differenceInMilliseconds / (1000 * 60 * 60 * 24));
- if (days > 7) {
- return false;
- }
- return true;
- }
- return false;
- }
- function previousDateSchedule() {
- const startDateTime = new Date(dateRange.value[0] - 1);
- startDateTime.setHours(0, 0, 0, 0);
- const sevenDays = new Date(startDateTime);
- sevenDays.setDate(startDateTime.getDate() - 6);
- sevenDays.setHours(0, 0, 0, 0);
- dateRange.value = [sevenDays.getTime(), startDateTime.getTime()];
- loadScheduleQuery();
- }
- function nextDateSchedule() {
- const endDateTime = new Date(dateRange.value[1]);
- endDateTime.setHours(24, 0, 0, 0);
- const sevenDays = new Date(endDateTime);
- sevenDays.setDate(endDateTime.getDate() + 6);
- sevenDays.setHours(0, 0, 0, 0);
- dateRange.value = [endDateTime.getTime(), sevenDays.getTime()];
- loadScheduleQuery();
- }
- function differenceInSevenDays(nowtime: [number, number]): boolean {
- if (!validateDate(nowtime)) {
- scheduleParamsOptions.startTime = '';
- scheduleParamsOptions.endTime = '';
- window.$message?.error('查询时间范围不能超过7天');
- return false;
- }
- scheduleParamsOptions.startTime = formatTimestamp(Number(nowtime[0]));
- scheduleParamsOptions.endTime = formatTimestamp(Number(nowtime[1] + 86399999));
- return true;
- }
- function loadScheduleQuery() {
- if (differenceInSevenDays(dateRange.value)) {
- loadSchedule();
- }
- }
- function loadSchedule() {
- loading.value = true;
- querySchedule(scheduleParamsOptions).then(response => {
- scheduleList.value = [];
- for (let i = 1; i <= 7; i += 1) {
- scheduleList.value[i] = {};
- for (let j = 0; j < timeKey.value.length; j += 1) {
- scheduleList.value[i][timeKey.value[j]] = { empty: true, break: false };
- }
- }
- response.data?.forEach((r: any) => {
- if (!r.startTime) return;
- const time = r.startTime
- ?.split(' ')
- .pop()
- .replace(/(\d{2}):\d{2}/, '$1:00');
- const week = new Date(r.startTime).getDay();
- if (time && timeKey.value.indexOf(time) === -1) return;
- if (week && time && r.endTime && r.startTime && scheduleList.value[week][time].empty) {
- r.colspan = new Date(r.endTime).getHours() - new Date(r.startTime).getHours() + 1;
- r.empty = false;
- r.break = false;
- scheduleList.value[week][time] = r;
- let n = 1;
- while (n < r.colspan) {
- const index = timeKey.value.indexOf(time) + n;
- scheduleList.value[week][timeKey.value[index]] = { empty: false, break: true };
- n += 1;
- }
- }
- });
- weekStartTime.value = dateRange.value[0];
- loading.value = false;
- });
- }
- function getDayOfTheWeekNow(theWeekStartTime: number, weekDate: number): number {
- const week = new Date(theWeekStartTime + weekDate * 86400000).getDay();
- return week === 0 ? 7 : week;
- }
- function loadData() {
- queryUserAll().then(response => {
- teacherOptions.value = response.data?.map(r => {
- return {
- label: r.relname,
- value: r.id
- };
- });
- });
- queryCategoryParams(1, 100, {}).then(response => {
- response.data?.map(r => {
- categoryAndSubjectOptions.value.push({
- label: r.name,
- value: r.id,
- depth: 1,
- isLeaf: false
- });
- return r;
- });
- });
- queryClassAll().then(response => {
- response.data?.map(r => {
- groupList.value.push({
- label: r.name,
- value: r.id
- });
- return r;
- });
- });
- queryClassRoomList(1, 100, {}).then(response => {
- response.data?.map(r => {
- classRoomList.value.push({
- label: r.name,
- value: r.id
- });
- return r;
- });
- if (classId) {
- model.classId = Number(classId);
- }
- });
- loadScheduleQuery();
- }
- loadData();
- </script>
- <style scoped>
- table {
- table-layout: fixed;
- }
- th {
- font-size: calc(var(--baseSize, 14px) * 2);
- font-weight: bold;
- }
- th,
- td {
- padding: 16px 12px;
- font-size: var(--baseSize, 14px);
- outline: 1px solid rgb(226, 226, 226);
- text-align: center;
- }
- td {
- color: rgb(99, 99, 99);
- }
- </style>
|