wuheng 1 rok pred
rodič
commit
2a80431ada

+ 1 - 1
src/config/service.ts

@@ -40,7 +40,7 @@ export const ERROR_STATUS = {
 };
 
 /** 不弹出错误信息的code */
-export const NO_ERROR_MSG_CODE: (string | number)[] = [];
+export const NO_ERROR_MSG_CODE: (string | number | null)[] = [];
 
 /** token失效需要刷新token的code(需要将后端表示token过期的code填进来) */
 export const REFRESH_TOKEN_CODE: (string | number)[] = ['token'];

+ 8 - 7
src/service/request/instance.ts

@@ -27,11 +27,12 @@ export default class CustomAxiosInstance {
   constructor(
     axiosConfig: AxiosRequestConfig,
     backendConfig: Service.BackendResultConfig = {
-      codeKey: 'status',
+      statusKey: 'status',
       dataKey: 'data',
       msgKey: 'msg',
       successCode: true,
-      total: 'total'
+      total: 'total',
+      codeKey: 'code'
     }
   ) {
     this.backendConfig = backendConfig;
@@ -63,10 +64,10 @@ export default class CustomAxiosInstance {
         const { status } = response;
         if (status === 200 || status < 300 || status === 304) {
           const backend = response.data;
-          const { codeKey, dataKey, successCode, total } = this.backendConfig;
+          const { codeKey, dataKey, successCode, statusKey } = this.backendConfig;
           // 请求成功
-          if (backend[codeKey] === successCode) {
-            return handleServiceResult(null, backend[dataKey], backend[total]);
+          if (backend[statusKey] === successCode) {
+            return handleServiceResult(null, backend[dataKey], backend);
           }
           // token失效, 刷新token
           if (REFRESH_TOKEN_CODE.includes(backend[codeKey])) {
@@ -77,10 +78,10 @@ export default class CustomAxiosInstance {
           }
 
           const error = handleBackendError(backend, this.backendConfig);
-          return handleServiceResult(error, null, null);
+          return handleServiceResult(error, null, backend);
         }
         const error = handleResponseError(response);
-        return handleServiceResult(error, null, null);
+        return handleServiceResult(error, null, response.data);
       }) as (response: AxiosResponse<any, any>) => Promise<AxiosResponse<any, any>>,
       (axiosError: AxiosError) => {
         const error = handleAxiosError(axiosError);

+ 0 - 1
src/service/request/request.ts

@@ -40,7 +40,6 @@ export function createRequest(axiosConfig: AxiosRequestConfig, backendConfig?: S
       data: param.data,
       config: param.axiosConfig
     })) as Service.RequestResult<T>;
-
     return res;
   }
 

+ 12 - 5
src/typings/system.d.ts

@@ -13,9 +13,9 @@ declare namespace Service {
     /** 请求服务的错误类型 */
     type: RequestErrorType;
     /** 错误码 */
-    code: string | number;
+    code: number | string | null;
     /** 错误信息 */
-    msg: string;
+    msg: string | null;
   }
 
   /** 后端接口返回的数据结构配置 */
@@ -29,15 +29,19 @@ declare namespace Service {
     /** 后端业务上定义的成功请求的状态 */
     successCode: boolean;
     total: string;
+    statusKey: string;
   }
 
   /** 自定义的请求成功结果 */
   interface SuccessResult<T = any> {
     /** 请求错误 */
-    error: null;
+    error: RequestError | null;
     /** 请求数据 */
     data: T;
-    total: string;
+    status: boolean;
+    total: number | null;
+    msg: string | null;
+    code: number | string | null;
   }
 
   /** 自定义的请求失败结果 */
@@ -46,7 +50,10 @@ declare namespace Service {
     error: RequestError | null;
     /** 请求数据 */
     data: null;
-    total: null;
+    total: null | number;
+    status: boolean;
+    msg: string | null;
+    code: number | string | null;
   }
 
   /** 自定义的请求结果 */

+ 30 - 8
src/utils/service/handler.ts

@@ -1,17 +1,33 @@
+const backendCode: Service.BackendResultConfig = {
+  statusKey: 'status',
+  dataKey: 'data',
+  msgKey: 'msg',
+  successCode: true,
+  total: 'total',
+  codeKey: 'code'
+};
+
 /** 统一失败和成功的请求结果的数据类型 */
-export async function handleServiceResult<T = any>(error: Service.RequestError | null, data: any, total: any) {
+export async function handleServiceResult<T = any>(error: Service.RequestError | null, data: any, backend?: any) {
   if (error) {
+    const failMsg = error.msg ? error.msg : 'fail';
     const fail: Service.FailedResult = {
       error,
-      data: null,
-      total: null
+      code: error.code,
+      data: backend ? backend[backendCode.dataKey] : null,
+      total: backend ? backend[backendCode.total] : 0,
+      status: backend ? backend[backendCode.statusKey] : false,
+      msg: backend ? backend[backendCode.msgKey] : failMsg
     };
     return fail;
   }
   const success: Service.SuccessResult<T> = {
     error: null,
     data,
-    total
+    total: backend ? backend[backendCode.total] : 0,
+    status: backend ? backend[backendCode.statusKey] : true,
+    msg: backend ? backend[backendCode.msgKey] : 'success',
+    code: backend ? backend[backendCode.codeKey] : 200
   };
   return success;
 }
@@ -24,12 +40,15 @@ export function adapter<T extends Service.ServiceAdapter>(
   let result: Service.RequestResult | undefined;
 
   const hasError = args.some(item => {
-    const flag = Boolean(item.error);
+    const flag = Boolean(item.status === false);
     if (flag) {
       result = {
         error: item.error,
-        data: null,
-        total: null
+        data: item.data,
+        total: null,
+        status: false,
+        code: item.code,
+        msg: item.msg
       };
     }
     return flag;
@@ -41,7 +60,10 @@ export function adapter<T extends Service.ServiceAdapter>(
     result = {
       error: null,
       data: adapterFun(...adapterFunArgs),
-      total: adapterFun(...adapterFunArgss)
+      total: adapterFun(...adapterFunArgss),
+      status: true,
+      msg: 'success',
+      code: 200
     };
   }
 

+ 1 - 1
src/utils/service/msg.ts

@@ -1,7 +1,7 @@
 import { ERROR_MSG_DURATION, NO_ERROR_MSG_CODE } from '@/config';
 
 /** 错误消息栈,防止同一错误同时出现 */
-const errorMsgStack = new Map<string | number, string>([]);
+const errorMsgStack = new Map<string | number | null, string | null>([]);
 
 function addErrorMsg(error: Service.RequestError) {
   errorMsgStack.set(error.code, error.msg);

+ 2 - 2
src/views/lesson/classroom/crud.ts

@@ -53,8 +53,8 @@ function curd(): CreateCrudOptionsRet {
           if (isString(context.form.createUid)) {
             context.form.createUid = null;
           }
-          if (isString(context.form.manageId)) {
-            context.form.manageId = null;
+          if (isString(context.form.managerId)) {
+            context.form.managerId = null;
           }
           return true;
         }

+ 92 - 13
src/views/lesson/schedule/api.ts

@@ -3,20 +3,20 @@ import { request } from '@/service/request';
 // 参数接口
 export interface ScheduleParams {
   id?: number;
-  week?: number;
-  startTime?: number;
-  endTime?: number;
-  roomId?: number;
-  classId?: number;
-  assistantId?: number;
-  teacherId?: number;
-  categoryId?: number;
+  week: number;
+  startTime: string | number;
+  endTime: string | number;
+  roomId: number;
+  classId: number;
+  assistantId: number;
+  teacherId: number;
+  categoryId: number;
   lessonTime?: number;
-  subjectsId?: number;
-  createTime?: number;
-  modifyTime?: number;
-  createUid?: number;
-  disabled?: string;
+  subjectsId: number;
+  createTime: number;
+  modifyTime: number;
+  createUid: number;
+  disabled: string;
 }
 
 // 响应接口
@@ -161,3 +161,82 @@ export function querySubject(
 ): Promise<Service.RequestResult<SubjectParams[]>> {
   return request.post(`/subject/selectByCondition?pageNum=${pageNum}&pageSize=${pageSize}`, params);
 }
+
+export interface ClassParams {
+  id?: number;
+  name?: string;
+  manageId?: number;
+  assistantId?: number;
+  createTime?: Record<string, unknown>;
+  modifyTime?: Record<string, unknown>;
+  createUid?: number;
+  disabled?: string;
+}
+
+/**
+ * 查询所有的班级类
+ * @returns
+ */
+export function queryClassAll(): Promise<Service.RequestResult<ClassParams[]>> {
+  return request.get(`/class/selectTotal`);
+}
+
+export interface ClassRoomParams {
+  id?: number;
+  name?: string;
+  managerId?: number;
+  address?: string;
+  manager?: string;
+  floor?: number;
+  capacity?: number;
+  comment?: string;
+  disabled?: string;
+  createTime?: Record<string, unknown>;
+  modifyTime?: Record<string, unknown>;
+  createUid?: number;
+}
+
+export function queryClassRoomList(
+  pageNum: number,
+  pageSize: number,
+  params: ClassRoomParams
+): Promise<Service.RequestResult<ClassRoomParams[]>> {
+  return request.post(`/classroom/query?pageNum=${pageNum}&pageSize=${pageSize}`, params);
+}
+
+export interface ScheduleParamsList {
+  id?: number;
+  week?: number;
+  startTime?: string;
+  endTime?: string;
+  roomId?: number;
+  classId?: number;
+  assistantId?: number;
+  teacherId?: number;
+  categoryId?: number;
+  lessonTime?: number;
+  subjectsId?: number;
+  createTime?: number;
+  modifyTime?: number;
+  createUid?: number;
+  disabled?: string;
+  colspan?: number;
+  empty?: boolean;
+  break?: boolean;
+}
+
+export interface PageResponse<T = any> {
+  pageNum?: number;
+  pageSize?: number;
+  total?: number;
+  pages?: number;
+  data: T;
+}
+
+export function querySchedule(
+  pageNum: number,
+  pageSize: number,
+  params: ScheduleParamsList
+): Promise<Service.RequestResult<PageResponse<ScheduleParamsList[]>>> {
+  return request.post(`/schedule/query?pageNum=${pageNum}&pageSize=${pageSize}`, params);
+}

+ 142 - 24
src/views/lesson/schedule/index.vue

@@ -5,11 +5,9 @@
     </n-space>
     <div v-if="pageState">
       <table border="1" style="width: 100%">
-        <caption>
-          排课表
-        </caption>
         <tbody width="100">
           <tr>
+            <th>时间</th>
             <th>周一</th>
             <th>周二</th>
             <th>周三</th>
@@ -18,22 +16,29 @@
             <th>周六</th>
             <th>周日</th>
           </tr>
-          <tr class="text-center">
-            <td>李四</td>
-            <td>员工</td>
-            <td>李四</td>
-            <td>李四</td>
-            <td>李四</td>
-            <td>李四</td>
-            <td>李四</td>
+          <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]['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]['empty'] === true">暂无</td>
+            </template>
           </tr>
         </tbody>
       </table>
     </div>
     <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="inputValue">
-          <n-input-number v-model:value="model.classId" type="number" disabled placeholder="请选择排课的班级" />
+        <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
@@ -70,9 +75,9 @@
         </n-form-item>
         <n-form-item label="上课时间" path="datetimeValue">
           <n-space>
-            <n-date-picker v-model:value="dateValue" type="date" />
-            <n-time-picker v-model:value="model.startTime" />
-            <n-time-picker v-model:value="model.endTime" />
+            <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">
@@ -93,9 +98,20 @@
 </template>
 <script setup lang="ts">
 import { ref, reactive } from 'vue';
+import { useRoute } from 'vue-router';
 import type { CascaderOption } from 'naive-ui';
-import { queryByRealname, queryCategoryParams, querySubject } from './api';
+import { formatTimestamp } from '~/src/utils';
+import {
+  queryByRealname,
+  queryCategoryParams,
+  querySubject,
+  queryClassAll,
+  addSchedule,
+  queryClassRoomList,
+  querySchedule
+} from './api';
 import type { ScheduleParams } from './api';
+const route = useRoute();
 const model = reactive<ScheduleParams>({
   week: 0,
   startTime: 0,
@@ -111,14 +127,53 @@ const model = reactive<ScheduleParams>({
   createUid: 0,
   disabled: 'N'
 });
-
-const dateValue = ref<number>();
+const classId = route.query.classId;
+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();
+const generalOptions = ref();
+
+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'
+]);
+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 };
+  }
+}
+
 function teacherSearch(keyword: string) {
   if (keyword.length <= 0 || !keyword.length) {
     teacherOptions.value = [];
@@ -134,7 +189,6 @@ function teacherSearch(keyword: string) {
   });
 }
 
-const generalOptions = ref();
 function assistantSearch(keyword: string) {
   if (keyword.length <= 0 || !keyword.length) {
     generalOptions.value = [];
@@ -171,8 +225,16 @@ function categoryAndSubjectLoad(option: CascaderOption) {
   });
 }
 
-function handleValidateButtonClick() {
-  // console.log(model);
+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;
+  const res = await addSchedule(repeatTime.value, model);
+  if (!res.status && res.msg !== null) {
+    return window.$message?.error(res.msg);
+  }
+  pageState.value = !pageState.value;
+  return window.$message?.success('操作成功!');
 }
 
 function loadData() {
@@ -187,7 +249,63 @@ function loadData() {
       return r;
     });
   });
+  queryClassAll().then(respone => {
+    respone.data?.map(r => {
+      groupList.value.push({
+        label: r.name,
+        value: r.id
+      });
+      return r;
+    });
+  });
+
+  queryClassRoomList(1, 100, {}).then(respone => {
+    respone.data?.map(r => {
+      classRoomList.value.push({
+        label: r.name,
+        value: r.id
+      });
+      return r;
+    });
+    if (classId) {
+      model.classId = Number(classId);
+    }
+  });
+  querySchedule(1, 100, {}).then(response => {
+    response.data?.data.forEach(r => {
+      const time = r.startTime?.split(' ').pop();
+      const week = r.week;
+      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;
+        }
+      }
+    });
+  });
 }
+
 loadData();
 </script>
-<style scoped></style>
+<style scoped>
+th {
+  color: rgb(141, 141, 141);
+  font-size: calc(var(--baseSize, 14px) * 1.1);
+  font-weight: bold;
+}
+
+th,
+td {
+  padding: 16px 12px;
+  font-size: var(--baseSize, 14px);
+  outline: 1px solid rgb(226, 226, 226);
+  text-align: center;
+  color: rgb(99, 99, 99);
+}
+</style>