import { Method } from "alova"; import { alovaInstance } from "@/utils/alova/alova-iview"; import conf from "@/assets/config/host.config"; import type { ClassTreeNode, EffectiveSettingVo, GradeSettingVo, ModNode, MyClassesVo, MyTimetableVo, NowYearTermVo, SettingGetVo, SubjectVo, TemplateSaveRequest, TimeSettingVo, TimetableOverviewVo, TimetableSaveRequest, TimetableVo, UpFileResultVo, UserInfoVo, } from "@/types/syllabus"; /** * 课程表(AcaSyllabu)接口封装。 * * 前缀说明:conf.serviceHost 本地为空(走 vite 同源代理),线上为基础平台域名; * platform 固定使用 "api",与后端 Config.API_PATH 中的 api 匹配。 * 统一响应 {code,msg,data} 由 alova-iview 解包为 data(code==0),页面直接使用返回值。 * * 约定: * - postJSON 用于 @RequestBody 接口;postForm 用于 @RequestParam 接口(表单提交)。 */ const BASE = "/api/base"; const FILE = "/api/file"; const TIMETABLE = "/api/timetable"; const SETTING = "/api/setting"; /** GET 请求,T 为返回数据类型 */ function get(url: string, params?: Record): Method { return new Method("GET", alovaInstance, url, { params }); } /** POST JSON body(与后端 @RequestBody 对齐),T 为返回数据类型 */ function postJSON(url: string, data?: Record | any[]): Method { return new Method( "POST", alovaInstance, url, { headers: { "Content-Type": "application/json;charset=UTF-8" } }, data ? JSON.stringify(data) : undefined ); } /** POST 表单(与后端 @RequestParam 对齐,application/x-www-form-urlencoded),T 为返回数据类型 */ function postForm(url: string, data?: Record): Method { const pairs = data ? Object.entries(data).filter(([, v]) => v !== undefined && v !== null) : []; const form = pairs.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`).join("&"); // 只发 body,不拼 URL query:Spring @RequestParam 会把 query 与 body 同名值以逗号合并(单值变 "X,X" 直接 500) return new Method( "POST", alovaInstance, url, { headers: { "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8" } }, form || undefined ); } /** 附件下载直链(浏览器 location.href 跳转) */ function fileDownUrl(fileId: number): string { return `${conf.serviceHost}${FILE}/Down?id=${fileId}`; } /** 附件在线预览直链(照片课表展示用) */ export function filePreviewUrl(fileId: number): string { return `${conf.serviceHost}${FILE}/Preview?id=${fileId}`; } /** 照片课表上传地址(FormData 字段名 file) */ export function fileUploadUrl(): string { return `${conf.serviceHost}${FILE}/Upload`; } /** 年级照片课表打包下载地址(ZIP,条目按年级+班级名命名;前端 fetch 取 Blob 后落盘) */ export function gradePhotoZipUrl(gradeName: string): string { return `${conf.serviceHost}${TIMETABLE}/DownloadGradePhotos?gradeName=${encodeURIComponent(gradeName)}`; } /** 课表导入模板下载地址(按班级年级生效节次模板生成 xlsx) */ export function timetableImportTemplateUrl(classId: number): string { return `${conf.serviceHost}${TIMETABLE}/ImportTemplate?classId=${classId}`; } /** 班级电子课表导出地址(xlsx,当前学年学期) */ export function timetableExportUrl(classId: number): string { return `${conf.serviceHost}${TIMETABLE}/Export?classId=${classId}`; } /** 课表导入上传地址(FormData:classId + file,整表替换该班当前课表) */ export function timetableImportUrl(): string { return `${conf.serviceHost}${TIMETABLE}/Import`; } class BaseApi { // ========== 用户信息 & 模块权限 ========== /** 获取当前登录用户信息 */ getUserInfo() { return get(`${BASE}/GetUserInfo`); } /** 获取当前用户已授权的模块列表 */ getUserMod() { return get(`${BASE}/GetUserMod`); } /** 当前学校组织树(部门→教师) */ getSchoolAll() { return get(`${BASE}/GetSchoolAll`); } /** 年级→班级树(叶子=班级,附学生数;课程表按班级维护) */ getClassTree() { return get(`${BASE}/GetClassTree`); } /** 端分离入口:切换当前视角(teacher / parent) */ setRole(as: "teacher" | "parent") { return postJSON<{ role: string }>(`${BASE}/SetRole`, { as }); } } class SyllabusApi { // ========== 电子课程表 ========== /** 查询班级课程表(无数据时返回空节次,前端补默认 10 节) */ get(classId: number) { return get(`${TIMETABLE}/Get`, { classId }); } /** 整表保存电子课程表(全量替换节次),返回课表ID */ save(data: TimetableSaveRequest) { return postJSON(`${TIMETABLE}/Save`, data); } // ========== 照片课程表 ========== /** 绑定/替换照片课表(fileId 为已上传附件ID) */ savePhoto(classId: number, fileId: number) { return postForm(`${TIMETABLE}/SavePhoto`, { classId, fileId }); } /** 移除照片课表 */ removePhoto(classId: number) { return postForm(`${TIMETABLE}/RemovePhoto`, { classId }); } // ========== 学科 ========== /** 本校学科列表(学科下拉数据源;不可达时返回空列表) */ subjects() { return get(`${TIMETABLE}/Subjects`); } // ========== 学年学期 ========== /** 当前学年学期(课表按学年学期维护,页头展示用;班级服务不可达时报错) */ nowYearTerm() { return get(`${TIMETABLE}/NowYearTerm`); } // ========== 排课情况 ========== /** 全校排课情况汇总(每班电子版 / 照片版编排状态,按年级→班级排序) */ overview() { return get(`${TIMETABLE}/Overview`); } // ========== 我的课表(按角色过滤的只读视图) ========== /** 可查看班级列表 + 身份标识(管理员/班主任/任教老师,前端按身份切换视图) */ myClasses() { return get(`${TIMETABLE}/MyClasses`); } /** 班级课表(权限校验;任教老师只返回任教科目格) */ myGet(classId: number) { return get(`${TIMETABLE}/MyGet`, { classId }); } // ========== 应用设置(时段判定 + 节次模板) ========== /** 查询本校应用设置(时间设置 + 全部节次模板含行) */ getSetting() { return get(`${SETTING}/Get`); } /** * 保存时段判定时间设置(四边界 HH:mm 依次递增)。 * 页面已无调用:启用时段与节次/课间时长自 2026-10-12 起随模板保存(见 saveTemplate), * 界面也不再维护四个边界;保留此方法仅为后端接口仍然可用。 */ saveTimeSetting(data: TimeSettingVo) { return postJSON(`${SETTING}/SaveTime`, data); } /** 新建/更新节次模板(全量替换行),返回模板ID */ saveTemplate(data: TemplateSaveRequest) { return postJSON(`${SETTING}/SaveTemplate`, data); } /** 删除节次模板(连带行) */ deleteTemplate(id: number) { return postForm(`${SETTING}/DeleteTemplate`, { id }); } /** 保存节次模板的「显示全部/只显示节次」偏好(绑定模板记忆,预览课表/我的课表同随此值) */ saveTemplateShowBreakRows(id: number, showBreakRows: boolean) { return postForm(`${SETTING}/SaveTemplateShowBreakRows`, { id, showBreakRows }); } /** 保存节次模板的「节次名称 显示/隐藏」偏好(绑定模板记忆,预览课表/我的课表同随此值) */ saveTemplateShowPeriodName(id: number, showPeriodName: boolean) { return postForm(`${SETTING}/SaveTemplateShowPeriodName`, { id, showPeriodName }); } /** 课表编辑页生效设置:时间边界 + 当前学期下指定年级启用模板的行(term 1=上学期 2=下学期) */ effectiveForGrade(gradeName: string, term?: number) { return get(`${SETTING}/ForGrade`, { gradeName, term }); } /** 年级设置列表(启用 + 使用电子版/照片版;未配置的年级默认全启用) */ gradeSettings() { return get(`${SETTING}/Grades`); } /** 批量保存年级设置(按年级名 upsert;作用于「我的课表」电子/照片视图切换) */ saveGradeSettings(data: GradeSettingVo[]) { return postJSON(`${SETTING}/SaveGrades`, data); } // ========== 附件 ========== fileDownUrl = fileDownUrl; } export const baseApi = new BaseApi(); export const syllabusApi = new SyllabusApi(); export type { UpFileResultVo }; export default syllabusApi;