Przeglądaj źródła

约课 完善 查询

wuheng 1 rok temu
rodzic
commit
f79645afa8

+ 4 - 0
src/views/lesson/group/crud.ts

@@ -12,6 +12,7 @@ const dictOpt = {
 };
 };
 function curd({ context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
 function curd({ context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
   const openModel = context?.openModel;
   const openModel = context?.openModel;
+  const goToSchedule = context?.goToSchedule;
   return {
   return {
     crudOptions: {
     crudOptions: {
       request: {
       request: {
@@ -199,6 +200,9 @@ function curd({ context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
                   return '查看排课计划';
                   return '查看排课计划';
                 }
                 }
               }
               }
+            },
+            click: ({ row }) => {
+              goToSchedule(row.id);
             }
             }
           }
           }
         }
         }

+ 10 - 0
src/views/lesson/group/index.vue

@@ -15,6 +15,7 @@
 
 
 <script setup lang="ts">
 <script setup lang="ts">
 import { onMounted, ref } from 'vue';
 import { onMounted, ref } from 'vue';
+import { useRouter } from 'vue-router';
 import type { Option, OptionValue } from 'naive-ui/es/transfer/src/interface';
 import type { Option, OptionValue } from 'naive-ui/es/transfer/src/interface';
 import { useFs } from '@fast-crud/fast-crud';
 import { useFs } from '@fast-crud/fast-crud';
 import createCrudOptions from './crud';
 import createCrudOptions from './crud';
@@ -23,12 +24,21 @@ const pageType = ref<boolean>(false);
 const classStuList = ref<number[] | undefined>([]);
 const classStuList = ref<number[] | undefined>([]);
 const studentsAll = ref<Option[]>();
 const studentsAll = ref<Option[]>();
 const groupId = ref<number>(0);
 const groupId = ref<number>(0);
+const router = useRouter();
 async function submitGroupStudent() {
 async function submitGroupStudent() {
   await submitGroupStudentForm(groupId.value, classStuList.value);
   await submitGroupStudentForm(groupId.value, classStuList.value);
   window.$message?.success('操作成功!');
   window.$message?.success('操作成功!');
   pageType.value = !pageType.value;
   pageType.value = !pageType.value;
 }
 }
 const context: any = {
 const context: any = {
+  goToSchedule: (classId: number) => {
+    router.push({
+      path: '/lesson/schedule',
+      query: {
+        classId
+      }
+    });
+  },
   openModel: async (classId: number) => {
   openModel: async (classId: number) => {
     groupId.value = classId;
     groupId.value = classId;
     const classStudent = await queryClassStudentById(classId);
     const classStudent = await queryClassStudentById(classId);

+ 1 - 9
src/views/lesson/schedule/api.ts

@@ -225,19 +225,11 @@ export interface ScheduleParamsList {
   break?: boolean;
   break?: boolean;
 }
 }
 
 
-export interface PageResponse<T = any> {
-  pageNum?: number;
-  pageSize?: number;
-  total?: number;
-  pages?: number;
-  data: T;
-}
-
 export function querySchedule(
 export function querySchedule(
   pageNum: number,
   pageNum: number,
   pageSize: number,
   pageSize: number,
   params: ScheduleParamsList
   params: ScheduleParamsList
-): Promise<Service.RequestResult<PageResponse<ScheduleParamsList[]>>> {
+): Promise<Service.RequestResult<ScheduleParamsList[]>> {
   return request.post(`/schedule/query?pageNum=${pageNum}&pageSize=${pageSize}`, params);
   return request.post(`/schedule/query?pageNum=${pageNum}&pageSize=${pageSize}`, params);
 }
 }
 
 

+ 209 - 121
src/views/lesson/schedule/index.vue

@@ -1,11 +1,11 @@
 <template>
 <template>
   <div class="h-full bg-white">
   <div class="h-full bg-white">
     <div v-if="pageState" style="margin-top: 1rem">
     <div v-if="pageState" style="margin-top: 1rem">
-      <n-form inline>
-        <n-form-item label="请选择查询学员" path="user.name">
+      <n-form :label-width="200" inline>
+        <n-form-item class="min-w-34" label="请选择查询学员" path="user.name">
           <n-input placeholder="请选择查询学员" />
           <n-input placeholder="请选择查询学员" />
         </n-form-item>
         </n-form-item>
-        <n-form-item label="请选择要查询的班级" path="classId">
+        <n-form-item class="min-w-34" label="请选择要查询的班级" path="classId">
           <n-select
           <n-select
             v-model:value="scheduleParamsOptions.classId"
             v-model:value="scheduleParamsOptions.classId"
             :options="groupList"
             :options="groupList"
@@ -13,7 +13,7 @@
             placeholder="请选择班级"
             placeholder="请选择班级"
           />
           />
         </n-form-item>
         </n-form-item>
-        <n-form-item label="请选择要查询的时间范围" path="user.name">
+        <n-form-item class="min-w-34" label="请选择要查询的时间范围" path="user.name">
           <n-date-picker
           <n-date-picker
             v-model:value="dateRange"
             v-model:value="dateRange"
             type="daterange"
             type="daterange"
@@ -29,7 +29,7 @@
             "
             "
           />
           />
         </n-form-item>
         </n-form-item>
-        <n-form-item label="请选择要查询的授课教师" path="user.name">
+        <n-form-item class="min-w-34" label="要查询的授课教师" path="user.name">
           <n-select
           <n-select
             v-model:value="scheduleParamsOptions.teacherId"
             v-model:value="scheduleParamsOptions.teacherId"
             :options="teacherOptions"
             :options="teacherOptions"
@@ -37,102 +37,113 @@
             clearable
             clearable
           />
           />
         </n-form-item>
         </n-form-item>
-        <n-form-item>
-          <n-button-group>
-            <n-button type="primary" ghost> 上一周 </n-button>
-            <n-button type="primary" ghost> 下一周 </n-button>
-            <n-button type="primary" ghost @click="loadScheduleQuery"> 搜索 </n-button>
-            <n-button type="primary" @click="pageState = !pageState"> 新增排课 </n-button>
-          </n-button-group>
-        </n-form-item>
       </n-form>
       </n-form>
-      <div style="width: 100%; height: 1rem"></div>
-      <div style="width: 100%; height: 1rem"></div>
-      <table border="1" style="width: 100%">
-        <tbody width="100">
-          <tr>
-            <th>时间</th>
-            <th>周一</th>
-            <th>周二</th>
-            <th>周三</th>
-            <th>周四</th>
-            <th>周五</th>
-            <th>周六</th>
-            <th>周日</th>
-          </tr>
-          <tr v-for="key in timeKey" :key="key">
-            <td>{{ key }}</td>
-            <template v-for="index in [1, 2, 3, 4, 5, 6, 7]" :key="index">
-              <td
-                v-if="
-                  scheduleList[index][key] &&
-                  scheduleList[index][key]['empty'] === false &&
-                  scheduleList[index][key]['break'] === false
-                "
-                :rowspan="scheduleList[index][key]['colspan']"
-              >
-                {{ scheduleList[index][key]['startTime'] }} <br />
-                {{ scheduleList[index][key]['endTime'] }}
-              </td>
-              <td v-else-if="scheduleList[index][key] && scheduleList[index][key]['empty'] === true">暂无</td>
-            </template>
-          </tr>
-        </tbody>
-      </table>
+      <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 - 1, 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'] }} <br />
+                  {{ scheduleList[getDayOfTheWeekNow(weekStartTime, index)][key]['endTime'] }}
+                </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>
     <div v-if="!pageState" class="wh-full flex-col-center">
     <div v-if="!pageState" class="wh-full flex-col-center">
-      <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" time-zone="Asia/Shanghai" type="date" />
-            <n-time-picker v-model:value="startTime" time-zone="Asia/Shanghai" />
-            <n-time-picker v-model:value="endTime" 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 :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>
     <div style="width: 100%; height: 1rem"></div>
     <div style="width: 100%; height: 1rem"></div>
   </div>
   </div>
@@ -169,6 +180,18 @@ const model = reactive<ScheduleParams>({
   disabled: 'N'
   disabled: 'N'
 });
 });
 const classId = route.query.classId;
 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 dateValue = ref<number>(0);
 const startTime = ref<number>(0);
 const startTime = ref<number>(0);
 const endTime = ref<number>(0);
 const endTime = ref<number>(0);
@@ -178,8 +201,16 @@ const pageState = ref<boolean>(true);
 const categoryAndSubjectOptions = ref<any[]>([]);
 const categoryAndSubjectOptions = ref<any[]>([]);
 const groupList = ref<any[]>([]);
 const groupList = ref<any[]>([]);
 const classRoomList = ref<any[]>([]);
 const classRoomList = ref<any[]>([]);
-const teacherOptions = ref();
-const dateRange = ref<[number, number]>([new Date().getTime(), new Date().getTime() + 86400000]);
+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<ScheduleParamsList>({
 const scheduleParamsOptions = reactive<ScheduleParamsList>({
   startTime: '',
   startTime: '',
   endTime: '',
   endTime: '',
@@ -241,40 +272,87 @@ function categoryAndSubjectLoad(option: CascaderOption) {
 }
 }
 
 
 async function handleValidateButtonClick() {
 async function handleValidateButtonClick() {
-  model.startTime = formatTimestamp(dateValue.value + startTime.value);
-  model.endTime = formatTimestamp(dateValue.value + endTime.value);
-  model.week = new Date(dateValue.value + startTime.value).getDay() + 1;
+  formLoading.value = true;
+  const modelStartTime = new Date(startTime.value);
+  const modelEndTime = new Date(endTime.value);
+  if (modelStartTime >= modelEndTime) {
+    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);
   const res = await addSchedule(repeatTime.value, model);
+  formLoading.value = false;
   if (!res.status && res.msg !== null) {
   if (!res.status && res.msg !== null) {
-    return window.$message?.error(res.msg);
+    window.$message?.error(res.msg);
+    return;
   }
   }
   pageState.value = !pageState.value;
   pageState.value = !pageState.value;
-  return window.$message?.success('操作成功!');
+  loadScheduleQuery();
+  window.$message?.success('操作成功!');
 }
 }
 
 
-function differenceInSevenDays(nowtime: number | [number, number] | null) {
+function validateDate(nowtime: [number, number]): boolean {
   if (!nowtime) {
   if (!nowtime) {
-    return;
+    return false;
   }
   }
   if (nowtime instanceof Array) {
   if (nowtime instanceof Array) {
-    const differenceInMilliseconds: number = nowtime[1] - nowtime[0] + 86400000;
+    const differenceInMilliseconds: number = nowtime[1] + 86400000 - nowtime[0];
     const days = Math.floor(differenceInMilliseconds / (1000 * 60 * 60 * 24));
     const days = Math.floor(differenceInMilliseconds / (1000 * 60 * 60 * 24));
     if (days > 7) {
     if (days > 7) {
-      scheduleParamsOptions.startTime = '';
-      scheduleParamsOptions.endTime = '';
-      window.$message?.error('查询时间范围不能超过7天');
-    } else {
-      scheduleParamsOptions.startTime = formatTimestamp(Number(nowtime[1]));
-      scheduleParamsOptions.endTime = formatTimestamp(Number(nowtime[0] + 86400000));
+      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] + 86400000));
+
+  return true;
 }
 }
 
 
 function loadScheduleQuery() {
 function loadScheduleQuery() {
-  loadSchedule();
+  if (differenceInSevenDays(dateRange.value)) {
+    loadSchedule();
+  }
 }
 }
 
 
 function loadSchedule() {
 function loadSchedule() {
+  loading.value = true;
   querySchedule(1, 100, scheduleParamsOptions).then(response => {
   querySchedule(1, 100, scheduleParamsOptions).then(response => {
     scheduleList.value = [];
     scheduleList.value = [];
     for (let i = 1; i <= 7; i += 1) {
     for (let i = 1; i <= 7; i += 1) {
@@ -283,9 +361,11 @@ function loadSchedule() {
         scheduleList.value[i][timeKey.value[j]] = { empty: true, break: false };
         scheduleList.value[i][timeKey.value[j]] = { empty: true, break: false };
       }
       }
     }
     }
-    response.data?.data.forEach(r => {
+    response.data?.forEach((r: any) => {
+      if (!r.startTime) return;
       const time = r.startTime?.split(' ').pop();
       const time = r.startTime?.split(' ').pop();
-      const week = r.week;
+      const week = new Date(r.startTime).getDay() + 1;
+      if (time && timeKey.value.indexOf(time) === -1) return;
       if (week && time && r.endTime && r.startTime && scheduleList.value[week][time].empty) {
       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.colspan = new Date(r.endTime).getHours() - new Date(r.startTime).getHours() + 1;
         r.empty = false;
         r.empty = false;
@@ -299,9 +379,13 @@ function loadSchedule() {
         }
         }
       }
       }
     });
     });
+    weekStartTime.value = dateRange.value[0];
+    loading.value = false;
   });
   });
 }
 }
-
+function getDayOfTheWeekNow(theWeekStartTime: number, weekDate: number): number {
+  return new Date(theWeekStartTime + weekDate * 86400000).getDay() + 1;
+}
 function loadData() {
 function loadData() {
   queryUserAll().then(response => {
   queryUserAll().then(response => {
     teacherOptions.value = response.data?.map(r => {
     teacherOptions.value = response.data?.map(r => {
@@ -343,15 +427,17 @@ function loadData() {
       model.classId = Number(classId);
       model.classId = Number(classId);
     }
     }
   });
   });
-  loadSchedule();
+  loadScheduleQuery();
 }
 }
 
 
 loadData();
 loadData();
 </script>
 </script>
 <style scoped>
 <style scoped>
+table {
+  table-layout: fixed;
+}
 th {
 th {
-  color: rgb(141, 141, 141);
-  font-size: calc(var(--baseSize, 14px) * 1.1);
+  font-size: calc(var(--baseSize, 14px) * 2);
   font-weight: bold;
   font-weight: bold;
 }
 }
 
 
@@ -361,6 +447,8 @@ td {
   font-size: var(--baseSize, 14px);
   font-size: var(--baseSize, 14px);
   outline: 1px solid rgb(226, 226, 226);
   outline: 1px solid rgb(226, 226, 226);
   text-align: center;
   text-align: center;
+}
+td {
   color: rgb(99, 99, 99);
   color: rgb(99, 99, 99);
 }
 }
 </style>
 </style>