diff --git a/.idea/data_source_mapping.xml b/.idea/data_source_mapping.xml new file mode 100644 index 000000000..f6dfee277 --- /dev/null +++ b/.idea/data_source_mapping.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/CourseRunningController.java b/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/CourseRunningController.java index 6ff05f272..d13505346 100644 --- a/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/CourseRunningController.java +++ b/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/CourseRunningController.java @@ -3,7 +3,6 @@ package com.roomroot.web.controller.jwgl; import com.roomroot.jwgl.dto.courserunning.ClassesImportDTO; import com.roomroot.jwgl.dto.courserunning.ImportRemoveDTO; import com.roomroot.jwgl.dto.courserunning.ScheduleAdjustApplyDTO; -import com.roomroot.jwgl.dto.courserunning.ScheduleAdjustStrategyDTO; import com.roomroot.jwgl.dto.courserunning.ScheduleAdjustAuditDTO; import com.roomroot.jwgl.dto.courserunning.ScheduleAdjustQueryDTO; import com.roomroot.jwgl.dto.courserunning.SemesterImportDTO; @@ -290,24 +289,26 @@ public class CourseRunningController { /** * 分页查询调课申请列表。 - *

- * 根据查询条件分页查询调课申请列表,支持按实施_课程表编号、申请教员、 - * 年度、审批状态、查收状态、删除状态、申请日期范围筛选。 - *

- * - * @param query 查询参数(包含分页信息和筛选条件) - * @return 分页调课申请列表 */ @GetMapping("/adjust/list") public Result> queryScheduleAdjustList(ScheduleAdjustQueryDTO query) { return Result.success(courseRunningImportService.queryScheduleAdjustList(query)); } + /** + * 查询当前教员可供调课的课次(学员队任务表 + 课表 + 课程表)。 + */ + @GetMapping("/adjust/lessons") + public Result> listAdjustableLessons( + @RequestParam(value = "nd", required = false) Integer nd) { + return Result.success(courseRunningImportService.listAdjustableLessons(nd)); + } + /** * 查询单个调课申请的完整详情。 *

* 根据调课申请编号查询该申请的完整信息,包括申请信息、调整后的内容、 - * 教研室审批状态、机关审批记录、关联的教室、辅助教员、学员队、保障明细等。 + * 教研室审批与查收状态、关联的教室、辅助教员、学员队、保障明细等。 *

* * @param ssdksqbh 调课申请编号 @@ -336,148 +337,30 @@ public class CourseRunningController { /** * 教研室审批调课申请。 *

- * 教研室审批教员提交的调课申请,包含同意、发回、拒绝三种处理方式。 + * 教研室审批调课申请。点审批即已查收,审批人同时记为查收人。 + * 同意、发回、拒绝均为已查收;教员撤回后为未查收。 *

* - * @param dto 教研室审批参数(auditRole 传 "jys") + * @param dto 教研室审批参数 * @return 操作结果 */ @PostMapping("/adjust/audit/jys") public Result auditByTeachingOffice(@Valid @RequestBody ScheduleAdjustAuditDTO dto) { - // 自动设置审批角色为教研室 - dto.setAuditRole("jys"); courseRunningImportService.auditByTeachingOffice(dto); return Result.success(); } - - /** - * 教研室查收调课申请。 - *

- * 教研室查收调课申请,标记查收状态和查收时间。 - *

- * - * @param ssdksqbh 调课申请编号 - * @param csrbh 查收人编号 - * @return 操作结果 - */ - @PostMapping("/adjust/receive/jys") - public Result receiveByTeachingOffice(@RequestParam("ssdksqbh") String ssdksqbh, - @RequestParam("csrbh") String csrbh) { - courseRunningImportService.receiveByTeachingOffice(ssdksqbh, csrbh); - return Result.success(); - } - - /** - * 教学系审批调课申请。 - *

- * 教学系审批教研室已同意的调课申请,包含同意、发回、拒绝三种处理方式。 - * 构成三级审批流程的中间环节(教研室→教学系→机关)。 - *

- * - * @param dto 教学系审批参数(auditRole 传 "jxx") - * @return 操作结果 - */ - @PostMapping("/adjust/audit/jxx") - public Result auditByTeachingDepartment(@Valid @RequestBody ScheduleAdjustAuditDTO dto) { - // 自动设置审批角色为教学系 - dto.setAuditRole("jxx"); - courseRunningImportService.auditByTeachingDepartment(dto); - return Result.success(); - } - - /** - * 机关审批调课申请。 - *

- * 机关审批教研室已同意的调课申请,包含同意、发回、拒绝三种处理方式。 - *

- * - * @param dto 机关审批参数(auditRole 传 "jg",需传 jgbh) - * @return 操作结果 - */ - @PostMapping("/adjust/audit/jg") - public Result auditByAuthority(@Valid @RequestBody ScheduleAdjustAuditDTO dto) { - // 自动设置审批角色为机关 - dto.setAuditRole("jg"); - courseRunningImportService.auditByAuthority(dto); - return Result.success(); - } - - /** - * 机关查收调课申请。 - *

- * 机关查收调课申请,标记查收状态和查收时间。 - *

- * - * @param ssdksqbh 调课申请编号 - * @param jgbh 机关编号 - * @param csrbh 查收人编号 - * @return 操作结果 - */ - @PostMapping("/adjust/receive/jg") - public Result receiveByAuthority(@RequestParam("ssdksqbh") String ssdksqbh, - @RequestParam("jgbh") String jgbh, - @RequestParam("csrbh") String csrbh) { - courseRunningImportService.receiveByAuthority(ssdksqbh, jgbh, csrbh); - return Result.success(); - } - /** * 撤销调课申请。 *

- * 教员撤销自己提交的、未经过审批的调课申请。 + * 教员撤销未经过审批的调课申请。列表已按登录教员过滤,只需传申请编号。 *

* * @param ssdksqbh 调课申请编号 - * @param sqjybh 申请教员编号 * @return 操作结果 */ @DeleteMapping("/adjust/cancel") - public Result cancelScheduleAdjust(@RequestParam("ssdksqbh") String ssdksqbh, - @RequestParam("sqjybh") String sqjybh) { - courseRunningImportService.cancelScheduleAdjust(ssdksqbh, sqjybh); - return Result.success(); - } - - // ==================== 调课策略管理 ==================== - - /** - * 查询调课策略列表。 - *

- * 支持按策略类型筛选,返回所有策略(含停用)。 - *

- * - * @param cllx 策略类型:TIME_LIMIT=时间段限制,AUTO_APPROVE=免审批,为空时查询全部 - * @return 调课策略列表 - */ - @GetMapping("/adjust/strategy/list") - public Result> listScheduleAdjustStrategies( - @RequestParam(required = false) String cllx) { - return Result.success(courseRunningImportService.listScheduleAdjustStrategies(cllx)); - } - - /** - * 保存调课策略(新增或修改)。 - *

- * 策略编号为空时执行新增,非空时执行修改。 - *

- * - * @param dto 策略参数 - * @return 策略编号 - */ - @PostMapping("/adjust/strategy/save") - public Result saveScheduleAdjustStrategy(@Valid @RequestBody ScheduleAdjustStrategyDTO dto) { - return Result.success("保存成功", courseRunningImportService.saveScheduleAdjustStrategy(dto)); - } - - /** - * 删除调课策略。 - * - * @param clbh 策略编号 - * @return 操作结果 - */ - @DeleteMapping("/adjust/strategy/delete") - public Result deleteScheduleAdjustStrategy(@RequestParam("clbh") String clbh) { - courseRunningImportService.deleteScheduleAdjustStrategy(clbh); + public Result cancelScheduleAdjust(@RequestParam("ssdksqbh") String ssdksqbh) { + courseRunningImportService.cancelScheduleAdjust(ssdksqbh); return Result.success(); } diff --git a/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/JYSController.java b/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/JYSController.java index bc1d1148f..dd492ca49 100644 --- a/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/JYSController.java +++ b/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/JYSController.java @@ -1,20 +1,41 @@ package com.roomroot.web.controller.jwgl; import com.roomroot.jwgl.dto.faculty.AddTeacherDTO; +import com.roomroot.jwgl.dto.jys.ElectiveCourseBatchDTO; +import com.roomroot.jwgl.dto.jys.ElectiveCourseQuery; +import com.roomroot.jwgl.dto.jys.ElectiveCourseSaveDTO; +import com.roomroot.jwgl.dto.jys.TeachingTaskQuery; +import com.roomroot.jwgl.dto.jys.TeachingTaskSaveDTO; import com.roomroot.jwgl.entity.JYB; import com.roomroot.jwgl.entity.JYSB; import com.roomroot.jwgl.entity.JYSX; import com.roomroot.jwgl.entity.KB; +import com.roomroot.jwgl.service.ElectiveCourseService; import com.roomroot.jwgl.service.FacultyService; import com.roomroot.jwgl.service.KBService; +import com.roomroot.jwgl.service.TeachingTaskManageService; import com.roomroot.jwgl.unit.PageQuery; import com.roomroot.jwgl.unit.PageResult; import com.roomroot.jwgl.unit.Result; import com.roomroot.jwgl.vo.faculty.TeacherListVO; +import com.roomroot.jwgl.vo.jys.ElectiveCourseVO; +import com.roomroot.jwgl.vo.jys.TeachingOfficeBookCourseVO; +import com.roomroot.jwgl.vo.jys.TeachingOfficeBookVO; +import com.roomroot.jwgl.vo.jys.TeachingTaskDetailVO; +import com.roomroot.jwgl.vo.jys.TeachingTaskSquadVO; +import com.roomroot.jwgl.vo.jys.TeachingTaskVO; +import com.roomroot.jwgl.unit.PageQuery; +import com.roomroot.jwgl.unit.PageResult; +import com.roomroot.jwgl.unit.Result; +import com.roomroot.jwgl.vo.faculty.TeacherListVO; +import com.roomroot.jwgl.vo.jys.ElectiveCourseVO; import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; +import java.util.List; + /** * 教研室管理(教研室管理 * 教员管理 @@ -32,6 +53,12 @@ public class JYSController { @Resource private KBService kbService; + + @Resource + private ElectiveCourseService electiveCourseService; + + @Resource + private TeachingTaskManageService teachingTaskManageService; // ======================== 教研室管理 ======================== /** @@ -194,6 +221,25 @@ public class JYSController { return Result.success(pageResult); } + /** + * 教员数据文件导入(.xls/.xlsx) + *

表头顺序:教员编号, 教员姓名, 教研室代号, 职称, 专业技术职务等级, 教员类别, + * 性别, 手机号, 身份证号, 备注, 序号, 虚实类型。教员编号不填自动创建,离职状态默认 0。

+ */ + @PostMapping("/teacher/import") + public Result importTeacher(@RequestParam("file") MultipartFile file) throws Exception { + int count = facultyService.importJYBFromExcel(file); + return Result.success("导入成功,共" + count + "条", count); + } + + /** + * 导出全部在职教员到 Excel(.xlsx)。 + */ + @GetMapping("/teacher/export") + public void exportTeacher(HttpServletResponse response) throws Exception { + facultyService.exportJYBExcel(response); + } + // ======================== 教员属性管理 ======================== /** @@ -303,4 +349,233 @@ public class JYSController { cond.setJc(jc); return Result.success(kbService.pageList(new PageQuery(pageNum, pageSize), cond)); } + + // ======================== 选修课管理 ======================== + + /** + * 分页查询选修课。 + *

+ * 联查学员队任务表、学员队表、课表,课类型含“选修”。 + * 支持按授课教员、课程科目名称、可选班次年级、选修班名称、选择课状态、培训层次筛选。 + *

+ */ + @GetMapping("/elective/list") + public Result> listElective( + @RequestParam(defaultValue = "1") Integer pageNum, + @RequestParam(defaultValue = "20") Integer pageSize, + @RequestParam(required = false) String jyxm, + @RequestParam(required = false) String kmc, + @RequestParam(required = false) String kxbcnj, + @RequestParam(required = false) String xxbmc, + @RequestParam(required = false) String xkzt, + @RequestParam(required = false) String pxcc) { + ElectiveCourseQuery cond = new ElectiveCourseQuery(); + cond.setJyxm(jyxm); + cond.setKmc(kmc); + cond.setKxbcnj(kxbcnj); + cond.setXxbmc(xxbmc); + cond.setXkzt(xkzt); + cond.setPxcc(pxcc); + return Result.success(electiveCourseService.pageList(new PageQuery(pageNum, pageSize), cond)); + } + + /** + * 新建选修课。 + */ + @PostMapping("/elective/add") + public Result addElective(@RequestBody ElectiveCourseSaveDTO dto) { + electiveCourseService.add(dto); + return Result.success(); + } + + /** + * 所选批量开放报名。 + */ + @PostMapping("/elective/batch-open") + public Result batchOpenElective(@RequestBody ElectiveCourseBatchDTO dto) { + int count = electiveCourseService.batchOpenRegistration(dto == null ? null : dto.getBhList()); + return Result.success("已开放报名 " + count + " 条", count); + } + + /** + * 所选批量取消开放报名。 + */ + @PostMapping("/elective/batch-cancel-open") + public Result batchCancelOpenElective(@RequestBody ElectiveCourseBatchDTO dto) { + int count = electiveCourseService.batchCancelOpenRegistration(dto == null ? null : dto.getBhList()); + return Result.success("已取消开放报名 " + count + " 条", count); + } + + /** + * 批量停止报名。 + */ + @PostMapping("/elective/batch-stop") + public Result batchStopElective(@RequestBody ElectiveCourseBatchDTO dto) { + int count = electiveCourseService.batchStopRegistration(dto == null ? null : dto.getBhList()); + return Result.success("已停止报名 " + count + " 条", count); + } + + /** + * 所选批量根据学员反向确定班次范围。 + */ + @PostMapping("/elective/batch-reverse-range") + public Result batchReverseRangeElective(@RequestBody ElectiveCourseBatchDTO dto) { + int count = electiveCourseService.batchReverseClassRange(dto == null ? null : dto.getBhList()); + return Result.success("已根据学员反向确定班次范围 " + count + " 条", count); + } + + /** + * 下载选修班列表。 + */ + @GetMapping("/elective/export") + public void exportElective( + @RequestParam(required = false) String jyxm, + @RequestParam(required = false) String kmc, + @RequestParam(required = false) String kxbcnj, + @RequestParam(required = false) String xxbmc, + @RequestParam(required = false) String xkzt, + @RequestParam(required = false) String pxcc, + HttpServletResponse response) { + ElectiveCourseQuery cond = new ElectiveCourseQuery(); + cond.setJyxm(jyxm); + cond.setKmc(kmc); + cond.setKxbcnj(kxbcnj); + cond.setXxbmc(xxbmc); + cond.setXkzt(xkzt); + cond.setPxcc(pxcc); + electiveCourseService.exportClassList(cond, response); + } + + /** + * 下载选修班学员名单 Excel。 + */ + @GetMapping("/elective/students/export-excel") + public void exportElectiveStudentExcel(@RequestParam("bhList") List bhList, + HttpServletResponse response) { + electiveCourseService.exportStudentExcel(bhList, response); + } + + /** + * 下载选修班学员名单 Word。 + */ + @GetMapping("/elective/students/export-word") + public void exportElectiveStudentWord(@RequestParam("bhList") List bhList, + HttpServletResponse response) { + electiveCourseService.exportStudentWord(bhList, response); + } + + + + /** + * 上传选修课数据。 + */ + @PostMapping("/elective/import") + public Result importElective(@RequestParam("file") MultipartFile file) throws Exception { + int count = electiveCourseService.importData(file); + return Result.success("导入成功,共" + count + "条", count); + } + + // ======================== 教学任务管理 ======================== + + /** + * 分页查询教学任务列表。 + *

含教研室数、学员队数、合班前后课程任务数和学时。未传年度时按当前学期。

+ */ + @GetMapping("/task/list") + public Result> listTask( + @RequestParam(defaultValue = "1") Integer pageNum, + @RequestParam(defaultValue = "20") Integer pageSize, + @RequestParam(required = false) String rwmc, + @RequestParam(required = false) Integer nd, + @RequestParam(required = false) Integer xqdc, + @RequestParam(required = false) String zt) { + TeachingTaskQuery cond = new TeachingTaskQuery(); + cond.setRwmc(rwmc); + cond.setNd(nd); + cond.setXqdc(xqdc); + cond.setZt(zt); + return Result.success(teachingTaskManageService.pageList(new PageQuery(pageNum, pageSize), cond)); + } + + /** + * 教学任务详情(含教研室任务书、学员队两个页签)。 + */ + @GetMapping("/task/get") + public Result getTask(@RequestParam("bh") String bh) { + return Result.success(teachingTaskManageService.getDetail(bh)); + } + + /** + * 新增教学任务。 + *

机关发布;关联学员队后按专业教学计划和课表归属教研室生成教研室任务书。

+ */ + @PostMapping("/task/add") + public Result addTask(@RequestBody TeachingTaskSaveDTO dto) { + teachingTaskManageService.add(dto); + return Result.success(); + } + + /** + * 编辑教学任务。 + */ + @PostMapping("/task/update") + public Result updateTask(@RequestBody TeachingTaskSaveDTO dto) { + teachingTaskManageService.update(dto); + return Result.success(); + } + + /** + * 删除教学任务(同时逻辑删除教研室任务书,并解除学员队关联)。 + */ + @PostMapping("/task/delete") + public Result deleteTask(@RequestParam("bh") String bh) { + teachingTaskManageService.delete(bh); + return Result.success(); + } + + /** + * 发布教学任务,并同步发布关联的教研室任务书。 + */ + @PostMapping("/task/publish") + public Result publishTask(@RequestParam("bh") String bh) { + int count = teachingTaskManageService.publish(bh); + return Result.success("已发布,同步教研室任务书 " + count + " 份", count); + } + + /** + * 教研室任务书列表。 + */ + @GetMapping("/task/office-book/list") + public Result> listTaskOfficeBooks(@RequestParam("jxrwbh") String jxrwbh) { + return Result.success(teachingTaskManageService.listOfficeBooks(jxrwbh)); + } + + /** + * 教研室任务书详细(该教研室在本任务下的课程任务)。 + */ + @GetMapping("/task/office-book/courses") + public Result> listTaskOfficeBookCourses( + @RequestParam("jxrwbh") String jxrwbh, + @RequestParam("jysdh") String jysdh) { + return Result.success(teachingTaskManageService.listOfficeBookCourses(jxrwbh, jysdh)); + } + + /** + * 教学任务已关联学员队。 + */ + @GetMapping("/task/squad/list") + public Result> listTaskSquads(@RequestParam("jxrwbh") String jxrwbh) { + return Result.success(teachingTaskManageService.listBoundSquads(jxrwbh)); + } + + /** + * 某学期可选学员队(未占用或占用当前任务)。年度、学期第次为空时取当前学期。 + */ + @GetMapping("/task/squad/available") + public Result> listAvailableTaskSquads( + @RequestParam(required = false) Integer nd, + @RequestParam(required = false) Integer xqdc, + @RequestParam(required = false) String jxrwbh) { + return Result.success(teachingTaskManageService.listAvailableSquads(nd, xqdc, jxrwbh)); + } } diff --git a/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/KCBController.java b/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/KCBController.java index a15091370..5b55c747c 100644 --- a/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/KCBController.java +++ b/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/KCBController.java @@ -1,8 +1,14 @@ package com.roomroot.web.controller.jwgl; +import com.roomroot.jwgl.dto.kcb.TimetableQuery; import com.roomroot.jwgl.entity.KCB; import com.roomroot.jwgl.service.KCBService; +import com.roomroot.jwgl.unit.PageQuery; +import com.roomroot.jwgl.unit.PageResult; import com.roomroot.jwgl.unit.Result; +import com.roomroot.jwgl.vo.kcb.ClassTimetableVO; +import com.roomroot.jwgl.vo.kcb.DailyWeeklyTimetableVO; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.web.bind.annotation.*; import jakarta.annotation.Resource; @@ -69,4 +75,52 @@ public class KCBController { public Result> list() { return Result.success(kcbService.list()); } + + /** + * 今日课表。未传年度时按当前时间取本学期,可按队别班次筛选。 + */ + @GetMapping("/today/list") + public Result> listToday(TimetableQuery cond) { + return Result.success(kcbService.listToday(cond)); + } + + /** + * 本周课表(周一至周日)。未传年度时按当前时间取本学期,可按队别班次筛选。 + */ + @GetMapping("/week/list") + public Result> listWeek(TimetableQuery cond) { + return Result.success(kcbService.listWeek(cond)); + } + + /** + * 班次课表。未传年度时按当前时间取本学期,可按队别班次筛选。 + */ + @GetMapping("/class/list") + public Result> listClass(PageQuery query, TimetableQuery cond) { + return Result.success(kcbService.pageClassTimetable(query, cond)); + } + + /** + * 下载学期教学实施计划 Excel。 + */ + @GetMapping("/class/export-plan") + public void exportSemesterPlan(TimetableQuery cond, HttpServletResponse response) { + kcbService.exportSemesterPlan(cond, response); + } + + /** + * 下载学期成绩表 Excel。 + */ + @GetMapping("/class/export-grades") + public void exportSemesterGrades(TimetableQuery cond, HttpServletResponse response) { + kcbService.exportSemesterGrades(cond, response); + } + + /** + * 班次课程列表另存 Excel。 + */ + @GetMapping("/class/export-courses") + public void exportClassCourses(TimetableQuery cond, HttpServletResponse response) { + kcbService.exportClassCourses(cond, response); + } } diff --git a/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/SemesterController.java b/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/SemesterController.java index 304b6cc92..732c3345f 100644 --- a/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/SemesterController.java +++ b/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/SemesterController.java @@ -25,6 +25,10 @@ public class SemesterController { */ @PostMapping("/add") public Result add(@RequestBody XQ xq) { + + if (semesterService.getById(xq.getNd()) != null) { + return Result.error(400, "该年度已存在,不能重复添加"); + } semesterService.add(xq); return Result.success(); } diff --git a/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/TrainingProgramController.java b/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/TrainingProgramController.java index c5c6d27bd..40b3ce4c8 100644 --- a/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/TrainingProgramController.java +++ b/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/TrainingProgramController.java @@ -5,7 +5,9 @@ import com.roomroot.jwgl.service.TrainingProgramService; import com.roomroot.jwgl.unit.PageQuery; import com.roomroot.jwgl.unit.PageResult; import com.roomroot.jwgl.unit.Result; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import jakarta.annotation.Resource; @@ -115,4 +117,23 @@ public class TrainingProgramController { PageResult pageResult = trainingProgramService.pageList(query, cond); return Result.success(pageResult); } + + /** + * 培养方案(专业)数据文件导入(.xls/.xlsx)。 + *

表头顺序:专业代号, 专业名称, 专业代码, 专业版本, 培训类型, 培训层次, 学年制, + * 学期数, 专业方向, 专业备注, 学员类别, 简称, 培训类型2。专业代号不填自动生成。

+ */ + @PostMapping("/import") + public Result importData(@RequestParam("file") MultipartFile file) throws Exception { + int count = trainingProgramService.importZYBFromExcel(file); + return Result.success("导入成功,共" + count + "条", count); + } + + /** + * 导出培养方案(专业)到 Excel(.xlsx)。 + */ + @GetMapping("/export") + public void exportData(HttpServletResponse response) throws Exception { + trainingProgramService.exportZYBExcel(response); + } } diff --git a/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/ZYJXJHBController.java b/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/ZYJXJHBController.java index 1bfe5a55a..b4584d920 100644 --- a/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/ZYJXJHBController.java +++ b/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/ZYJXJHBController.java @@ -3,7 +3,9 @@ package com.roomroot.web.controller.jwgl; import com.roomroot.jwgl.entity.ZYJXJHB; import com.roomroot.jwgl.service.ZYJXJHBService; import com.roomroot.jwgl.unit.Result; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import jakarta.annotation.Resource; import java.util.List; @@ -81,4 +83,23 @@ public class ZYJXJHBController { @RequestParam("ty") Integer ty) { return Result.success(zyjxjhbService.listByZydhAndTy(zydh, ty)); } + + /** + * 专业教学计划表数据文件导入(.xls/.xlsx)。 + *

表头顺序:专业代号, 课编号, 学期第次, 课类型, 学时, 学分, 周课时, 课程定位, + * 模块, 成绩分制, 理论学时, 实践学时, 考试课时, 教研室代号, 简称。编号由系统自动生成。

+ */ + @PostMapping("/import") + public Result importData(@RequestParam("file") MultipartFile file) throws Exception { + int count = zyjxjhbService.importZYJXJHBFromExcel(file); + return Result.success("导入成功,共" + count + "条", count); + } + + /** + * 导出专业教学计划到 Excel(.xlsx)。 + */ + @GetMapping("/export") + public void exportData(HttpServletResponse response) throws Exception { + zyjxjhbService.exportZYJXJHBExcel(response); + } } diff --git a/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwtest/TestPkController.java b/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwtest/TestPkController.java new file mode 100644 index 000000000..8702c8b59 --- /dev/null +++ b/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwtest/TestPkController.java @@ -0,0 +1,90 @@ +package com.roomroot.web.controller.jwtest; + +import com.roomroot.jwgl.mapper.TestPkMapper; +import com.roomroot.jwgl.unit.Result; +import com.roomroot.jwgl.vo.jwtest.PkConflictCheckVO; +import com.roomroot.jwgl.vo.jwtest.PkConflictVO; +import com.roomroot.jwgl.vo.jwtest.PkLessonVO; +import jakarta.annotation.Resource; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 排课测试接口。 + */ +@RestController +@RequestMapping("/jwtest/pk") +public class TestPkController { + + @Resource + private TestPkMapper testPkMapper; + + /** + * 全查排课记录,无筛选条件。 + *

+ * 回显:课堂名称、课程名称、教师名称、班级名称、教室名称、 + * 上课日期、开始时间、结束时间、学年学期、周次、应到人数。 + *

+ */ + @GetMapping("/all") + public Result> all() { + return Result.success(testPkMapper.selectAll()); + } + + /** + * 教学班时间冲突:同一个班在同一日期同一节次被安排多门课程。 + */ + @GetMapping("/conflict/class") + public Result classTimeConflict(@RequestParam(required = false) Integer nd) { + return Result.success(wrap( + "教学班时间冲突", + "同一班次在同一天同一节次被安排了多门课程", + testPkMapper.selectClassTimeConflict(nd))); + } + + /** + * 必修课与选修课时间冲突:同一班次同一时间既有必修又有选修。 + */ + @GetMapping("/conflict/elective-required") + public Result electiveRequiredConflict(@RequestParam(required = false) Integer nd) { + return Result.success(wrap( + "必修选修时间冲突", + "同一班次在同一天同一节次同时安排了必修课和选修课", + testPkMapper.selectElectiveRequiredConflict(nd))); + } + + /** + * 教员时间冲突:同一教员在同一时间段被安排多门课程。 + */ + @GetMapping("/conflict/teacher") + public Result teacherTimeConflict(@RequestParam(required = false) Integer nd) { + return Result.success(wrap( + "教员时间冲突", + "同一教员在同一天同一节次被安排了多门课程", + testPkMapper.selectTeacherTimeConflict(nd))); + } + + /** + * 教室时间冲突:同一教室在同一时间段被多门课程占用。 + */ + @GetMapping("/conflict/classroom") + public Result classroomTimeConflict(@RequestParam(required = false) Integer nd) { + return Result.success(wrap( + "教室时间冲突", + "同一教室在同一天同一节次被多门课程占用", + testPkMapper.selectClassroomTimeConflict(nd))); + } + + private PkConflictCheckVO wrap(String ctlx, String jcsm, List mx) { + PkConflictCheckVO vo = new PkConflictCheckVO(); + vo.setCtlx(ctlx); + vo.setJcsm(jcsm); + vo.setMx(mx); + vo.setTs(mx == null ? 0 : mx.size()); + return vo; + } +} diff --git a/backend/roomroot-admin/src/main/resources/application.yml b/backend/roomroot-admin/src/main/resources/application.yml index 0352a5cca..b062c7d3b 100644 --- a/backend/roomroot-admin/src/main/resources/application.yml +++ b/backend/roomroot-admin/src/main/resources/application.yml @@ -107,6 +107,7 @@ mybatis-plus: typeAliasesPackage: com.roomroot.**.domain # 配置mapper的扫描,找到所有的mapper.xml映射文件 mapperLocations: classpath*:mapper/**/*Mapper.xml,classpath*:com/roomroot/**/mapper/*.xml + typeHandlersPackage: com.roomroot.jwgl.handler # 加载全局的配置文件 configLocation: classpath:mybatis/mybatis-config.xml diff --git a/backend/roomroot-admin/src/main/resources/mybatis/mybatis-config.xml b/backend/roomroot-admin/src/main/resources/mybatis/mybatis-config.xml index ac47c038e..ae179d434 100644 --- a/backend/roomroot-admin/src/main/resources/mybatis/mybatis-config.xml +++ b/backend/roomroot-admin/src/main/resources/mybatis/mybatis-config.xml @@ -13,7 +13,7 @@ PUBLIC "-//mybatis.org//DTD Config 3.0//EN" - + diff --git a/backend/roomroot-framework/src/main/java/com/roomroot/framework/config/SecurityConfig.java b/backend/roomroot-framework/src/main/java/com/roomroot/framework/config/SecurityConfig.java index 3d8fe7d85..4503e41c0 100644 --- a/backend/roomroot-framework/src/main/java/com/roomroot/framework/config/SecurityConfig.java +++ b/backend/roomroot-framework/src/main/java/com/roomroot/framework/config/SecurityConfig.java @@ -100,7 +100,7 @@ public class SecurityConfig .authorizeHttpRequests((requests) -> { permitAllUrl.getUrls().forEach(url -> requests.requestMatchers(url).permitAll()); // 对于登录login 注册register 验证码captchaImage 允许匿名访问 - requests.requestMatchers("/login", "/register", "/captchaImage","/jys/teacher/list").permitAll() + requests.requestMatchers("/login", "/register", "/captchaImage", "/jwtest/pk/all").permitAll() // 静态资源,可匿名访问 .requestMatchers(HttpMethod.GET, "/", "/*.html", "/**.html", "/**.css", "/**.js", "/profile/**").permitAll() .requestMatchers("/swagger-ui.html", "/v3/api-docs/**", "/swagger-ui/**", "/druid/**").permitAll() diff --git a/backend/roomroot-framework/src/main/java/com/roomroot/framework/web/service/TokenService.java b/backend/roomroot-framework/src/main/java/com/roomroot/framework/web/service/TokenService.java index 107a5d955..3b641a9db 100644 --- a/backend/roomroot-framework/src/main/java/com/roomroot/framework/web/service/TokenService.java +++ b/backend/roomroot-framework/src/main/java/com/roomroot/framework/web/service/TokenService.java @@ -73,6 +73,10 @@ public class TokenService String uuid = (String) claims.get(Constants.LOGIN_USER_KEY); String userKey = getTokenKey(uuid); LoginUser user = redisCache.getCacheObject(userKey); + if (user == null) + { + log.warn("令牌签名有效,但登录缓存已失效,请重新登录"); + } return user; } catch (Exception e) @@ -218,14 +222,42 @@ public class TokenService */ private String getToken(HttpServletRequest request) { - String token = request.getHeader(header); - if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX)) + String token = firstHeader(request, header, "Authorization", "token"); + if (StringUtils.isNotEmpty(token)) { - token = token.replace(Constants.TOKEN_PREFIX, ""); + token = token.trim(); + if (StringUtils.startsWithIgnoreCase(token, Constants.TOKEN_PREFIX)) + { + token = token.substring(Constants.TOKEN_PREFIX.length()).trim(); + } } return token; } + /** + * 按顺序读取请求头,兼容 Authorization / token。 + */ + private String firstHeader(HttpServletRequest request, String... names) + { + if (names == null) + { + return null; + } + for (String name : names) + { + if (StringUtils.isEmpty(name)) + { + continue; + } + String value = request.getHeader(name); + if (StringUtils.isNotEmpty(value)) + { + return value; + } + } + return null; + } + private String getTokenKey(String uuid) { return CacheConstants.LOGIN_TOKEN_KEY + uuid; diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/config/AccountManagementWebMvcConfig.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/config/AccountManagementWebMvcConfig.java index f3977cbd3..5b88fe42a 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/config/AccountManagementWebMvcConfig.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/config/AccountManagementWebMvcConfig.java @@ -1,88 +1,25 @@ package com.roomroot.jwgl.config; -import com.roomroot.jwgl.interceptor.AccountManagementAuthorizationInterceptor; -import com.roomroot.jwgl.interceptor.JwglApiAccessInterceptor; import com.roomroot.jwgl.interceptor.OperationLogInterceptor; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** - * 在线账户状态和账户管理权限 Web MVC 配置。 - * - *

该配置对已有在线会话执行账户状态校验,同时保持普通匿名请求的原有访问规则; - * 账户管理路径继续执行超级管理员权限校验,并在校验通过后采集操作日志上下文。

+ * 操作日志采集 Web MVC 配置。 + *

页面菜单权限由前端控制;后台只校验登录态,查询时再按角色和用户ID过滤数据。

*/ @Configuration public class AccountManagementWebMvcConfig implements WebMvcConfigurer { - /** - * 账户管理身份和权限拦截器。 - */ - private final AccountManagementAuthorizationInterceptor - authorizationInterceptor; - - /** - * 操作日志统一请求采集拦截器。 - */ private final OperationLogInterceptor operationLogInterceptor; - private final JwglApiAccessInterceptor jwglApiAccessInterceptor; - - /** - * 构造账户管理和操作日志统一 Web MVC 配置。 - * - * @param authorizationInterceptor 账户管理身份和权限拦截器 - * @param operationLogInterceptor 操作日志统一请求采集拦截器 - * @param jwglApiAccessInterceptor 教务角色接口访问拦截器 - */ - public AccountManagementWebMvcConfig( - AccountManagementAuthorizationInterceptor - authorizationInterceptor, - OperationLogInterceptor operationLogInterceptor, - JwglApiAccessInterceptor jwglApiAccessInterceptor) { - // 第一步:保存账户管理专用拦截器,供 MVC 注册阶段使用。 - this.authorizationInterceptor = authorizationInterceptor; - - // 第二步:保存操作日志采集拦截器,供 MVC 注册阶段使用。 + public AccountManagementWebMvcConfig(OperationLogInterceptor operationLogInterceptor) { this.operationLogInterceptor = operationLogInterceptor; - - this.jwglApiAccessInterceptor = jwglApiAccessInterceptor; } - /** - * 注册账户状态校验、账户管理权限和操作日志采集规则。 - * - * @param registry Spring MVC 拦截器注册器 - */ @Override public void addInterceptors(InterceptorRegistry registry) { - /* - * 第一步:注册账户管理鉴权拦截器。 - * 第二步:覆盖全部 Controller 请求,使停用或已合并账户不能绕过 - * 账户管理路径继续访问其他业务接口。 - * 第三步:拦截器内部会放行没有 Servlet 会话的普通匿名请求, - * 因此不会改变项目现有公开接口的访问方式。 - */ - // registry.addInterceptor(authorizationInterceptor) - // .addPathPatterns("/**"); - - /* - * 第四步:在账户状态和账户管理权限校验通过后采集日志上下文。 - * 第五步:覆盖全部 Controller 请求,由采集拦截器自行跳过 - * 非 Controller 处理器和没有有效登录记录的请求。 - */ - registry.addInterceptor(jwglApiAccessInterceptor) - .addPathPatterns("/**") - .excludePathPatterns( - "/login", - "/register", - "/captchaImage", - "/jys/teacher/list", - "/swagger-ui/**", - "/v3/api-docs/**", - "/druid/**"); - registry.addInterceptor(operationLogInterceptor) .addPathPatterns("/**"); } diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/courserunning/ScheduleAdjustApplyDTO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/courserunning/ScheduleAdjustApplyDTO.java index 5695af78c..877a19cba 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/courserunning/ScheduleAdjustApplyDTO.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/courserunning/ScheduleAdjustApplyDTO.java @@ -17,17 +17,17 @@ import java.util.List; public class ScheduleAdjustApplyDTO { /** - * 实施_课程表编号,必填,标识需要调整的课次。 + * 实施_课程表编号,必填,对应实施_调课申请.实施_课程表编号。 */ @NotBlank(message = "课次编号不能为空") @Size(max = 50, message = "课次编号不能超过50个字符") private String sskcbbh; /** - * 调课事由,必填,描述本次调课的原因和依据。 + * 调课事由,对应 实施_调课申请.事由 VARCHAR(200)。 */ @NotBlank(message = "调课事由不能为空") - @Size(max = 500, message = "调课事由不能超过500个字符") + @Size(max = 200, message = "调课事由不能超过200个字符") private String sy; /** @@ -49,16 +49,39 @@ public class ScheduleAdjustApplyDTO { private Integer nd; /** - * 申请教员编号,必填,标识提交申请的教员。 + * 申请教员编号,教员提交时由服务端按登录人写入,前端可不传。 */ - @NotBlank(message = "申请教员编号不能为空") @Size(max = 50, message = "申请教员编号不能超过50个字符") private String sqjybh; /** - * 调课后教学内容,调整后的本节课教学主题或知识点。 + * 学员队任务表编号,由服务端根据实施课次反查,前端可不传。 */ - @Size(max = 2000, message = "教学内容不能超过2000个字符") + @Size(max = 50, message = "学员队任务编号不能超过50个字符") + private String xydrwbh; + + /** + * 课表.课编号。 + */ + @Size(max = 50, message = "课编号不能超过50个字符") + private String kbh; + + /** + * 课程表编号。 + */ + @Size(max = 50, message = "课程表编号不能超过50个字符") + private String kcbbh; + + /** + * 拟调整教室编号。 + */ + @Size(max = 50, message = "教室编号不能超过50个字符") + private String xjsbh; + + /** + * 调课后教学内容,对应 实施_调课申请.教学内容 VARCHAR(500)。 + */ + @Size(max = 500, message = "教学内容不能超过500个字符") private String jxnr; /** @@ -68,9 +91,9 @@ public class ScheduleAdjustApplyDTO { private String jxyd; /** - * 调课后教学方法,调整后的教学方法。 + * 调课后教学方法,对应 实施_调课申请.教学方法 VARCHAR(50)。 */ - @Size(max = 200, message = "教学方法不能超过200个字符") + @Size(max = 50, message = "教学方法不能超过50个字符") private String jxff; /** @@ -86,9 +109,9 @@ public class ScheduleAdjustApplyDTO { private String ycxx; /** - * 备注,补充说明信息。 + * 备注,对应 实施_调课申请.备注 VARCHAR(50)。 */ - @Size(max = 500, message = "备注不能超过500个字符") + @Size(max = 50, message = "备注不能超过50个字符") private String bz; /** diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/courserunning/ScheduleAdjustAuditDTO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/courserunning/ScheduleAdjustAuditDTO.java index d8ffbbf38..68fb81838 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/courserunning/ScheduleAdjustAuditDTO.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/courserunning/ScheduleAdjustAuditDTO.java @@ -2,54 +2,42 @@ package com.roomroot.jwgl.dto.courserunning; import lombok.Data; -import jakarta.validation.constraints.*; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; /** - * 调课申请审批参数。 - *

- * 用于教研室或机关审批调课申请,包含审批结果、审批意见和审批人编号。 - *

+ * 教研室审批调课申请参数。 */ @Data public class ScheduleAdjustAuditDTO { /** - * 调课申请编号,必填,标识需要审批的调课申请。 + * 调课申请编号。 */ @NotBlank(message = "调课申请编号不能为空") @Size(max = 50, message = "调课申请编号不能超过50个字符") private String ssdksqbh; /** - * 审批角色,必填:jys(教研室审批)、jg(机关审批)。 - */ - @NotBlank(message = "审批角色不能为空") - @Size(max = 20, message = "审批角色不能超过20个字符") - private String auditRole; - - /** - * 审批结果,必填:1-同意,2-发回修改,3-拒绝。 + * 审批结果:1-同意,2-发回,3-拒绝。点审批即已查收。 */ @NotNull(message = "审批结果不能为空") + @Min(value = 1, message = "审批结果不正确") + @Max(value = 3, message = "审批结果不正确") private Integer spzt; /** - * 审批意见,可选,记录审批的具体意见或发回原因。 + * 审批意见,发回时填写原因。 */ @Size(max = 500, message = "审批意见不能超过500个字符") private String fhyj; /** - * 审批人编号,必填,标识审批人身份。 + * 审批人编号,不传时取当前登录人;同时记为查收人。 */ - @NotBlank(message = "审批人编号不能为空") @Size(max = 50, message = "审批人编号不能超过50个字符") private String sprbh; - - /** - * 机关编号,机关审批时必填,标识审批机关。 - */ - @Size(max = 50, message = "机关编号不能超过50个字符") - private String jgbh; } diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/courserunning/ScheduleAdjustQueryDTO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/courserunning/ScheduleAdjustQueryDTO.java index 44b6ce5dd..776d8d94a 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/courserunning/ScheduleAdjustQueryDTO.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/courserunning/ScheduleAdjustQueryDTO.java @@ -38,20 +38,30 @@ public class ScheduleAdjustQueryDTO extends PageQuery { private Integer jyspzzt; /** - * 教研室查收状态:0-未查收,1-已查收。 + * 教研室查收状态:0-未查收,1-已查收。点了审批即为已查收。 */ private Integer jyscszt; - /** - * 机关审批状态:0-未审批,1-已同意,2-已发回,3-已拒绝。 - */ - private Integer jgspzt; - /** * 删除状态:0-正常,1-已删除。 */ private Integer sczt; + /** + * 教研室代号,教研室角色由服务端强制写入,前端不必传。 + */ + private String jysdh; + + /** + * 学员队任务表编号。 + */ + private String xydrwbh; + + /** + * 课编号。 + */ + private String kbh; + /** * 申请日期范围开始。 */ diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/courserunning/ScheduleAdjustStrategyDTO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/courserunning/ScheduleAdjustStrategyDTO.java deleted file mode 100644 index 7ae2004e3..000000000 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/courserunning/ScheduleAdjustStrategyDTO.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.roomroot.jwgl.dto.courserunning; - -import lombok.Data; - -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.Size; -import java.time.LocalDateTime; - -/** - * 调课策略新增/修改参数。 - *

- * 统一处理新增和修改:策略编号为空时执行新增,非空时执行修改。 - * 策略类型为 TIME_LIMIT 时需填写截止星期和截止节次; - * 策略类型为 AUTO_APPROVE 时截止星期和截止节次不生效。 - *

- */ -@Data -public class ScheduleAdjustStrategyDTO { - - /** 策略编号(修改时必填,新增时为空) */ - @Size(max = 50, message = "策略编号不能超过50个字符") - private String clbh; - - /** 策略名称 */ - @NotBlank(message = "策略名称不能为空") - @Size(max = 100, message = "策略名称不能超过100个字符") - private String clmc; - - /** 策略类型:TIME_LIMIT=时间段限制,AUTO_APPROVE=免审批 */ - @NotBlank(message = "策略类型不能为空") - @Size(max = 20, message = "策略类型不能超过20个字符") - private String cllx; - - /** 是否启用:0=停用,1=启用(为空时默认1) */ - private Integer sfqy; - - /** 截止星期:0-6(仅 TIME_LIMIT 类型使用) */ - private Integer jzxq; - - /** 截止节次(仅 TIME_LIMIT 类型使用) */ - private Integer jzjc; - - /** 生效开始时间 */ - private LocalDateTime sxkssj; - - /** 生效结束时间 */ - private LocalDateTime sxjssj; - - /** 备注 */ - @Size(max = 500, message = "备注不能超过500个字符") - private String bz; -} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/jys/ElectiveCourseBatchDTO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/jys/ElectiveCourseBatchDTO.java new file mode 100644 index 000000000..08bf7fbca --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/jys/ElectiveCourseBatchDTO.java @@ -0,0 +1,15 @@ +package com.roomroot.jwgl.dto.jys; + +import lombok.Data; + +import java.util.List; + +/** + * 选修课批量操作参数。 + */ +@Data +public class ElectiveCourseBatchDTO { + + /** 学员队任务编号列表 */ + private List bhList; +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/jys/ElectiveCourseImportDTO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/jys/ElectiveCourseImportDTO.java new file mode 100644 index 000000000..3c3c25c72 --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/jys/ElectiveCourseImportDTO.java @@ -0,0 +1,62 @@ +package com.roomroot.jwgl.dto.jys; + +import com.roomroot.common.annotation.Excel; +import lombok.Data; + +/** + * 选修课数据文件导入行。 + */ +@Data +public class ElectiveCourseImportDTO { + + @Excel(name = "授课教员") + private String jyxm; + + @Excel(name = "课程科目名称") + private String kmc; + + @Excel(name = "可选班次年级") + private String kxbcnj; + + @Excel(name = "选修班名称") + private String xxbmc; + + @Excel(name = "选择课状态") + private String xkzt; + + @Excel(name = "培训层次") + private String pxcc; + + @Excel(name = "教材") + private String jcmc; + + @Excel(name = "教学场地") + private String jsmc; + + @Excel(name = "计划学时") + private Integer jhxs; + + @Excel(name = "运行学时") + private Integer yxxs; + + @Excel(name = "学分") + private Float xf; + + @Excel(name = "开课日期") + private String kkrq; + + @Excel(name = "结课日期") + private String jkrq; + + @Excel(name = "报名开始日期") + private String bmkssj; + + @Excel(name = "报名结束日期") + private String bmjssj; + + @Excel(name = "计划人数") + private Integer jhrs; + + @Excel(name = "要求说明") + private String yqsm; +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/jys/ElectiveCourseQuery.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/jys/ElectiveCourseQuery.java new file mode 100644 index 000000000..011441de6 --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/jys/ElectiveCourseQuery.java @@ -0,0 +1,33 @@ +package com.roomroot.jwgl.dto.jys; + +import lombok.Data; + +import java.util.List; + +/** + * 选修课管理查询条件。 + */ +@Data +public class ElectiveCourseQuery { + + /** 授课教员姓名(模糊) */ + private String jyxm; + + /** 课程科目名称(模糊) */ + private String kmc; + + /** 可选班次年级(模糊,匹配年级或可选队列班次) */ + private String kxbcnj; + + /** 选修班名称(模糊) */ + private String xxbmc; + + /** 选择课状态:拟制 / 开放报名 / 停止报名 */ + private String xkzt; + + /** 培训层次 */ + private String pxcc; + + /** 任务编号列表(学员名单导出时使用) */ + private List bhList; +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/jys/ElectiveCourseSaveDTO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/jys/ElectiveCourseSaveDTO.java new file mode 100644 index 000000000..69fbcc10c --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/jys/ElectiveCourseSaveDTO.java @@ -0,0 +1,70 @@ +package com.roomroot.jwgl.dto.jys; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 新建选修课。 + *

写入学员队任务表(课类型含“选修”),并同步拼班信息中的报名日期与要求说明。

+ */ +@Data +public class ElectiveCourseSaveDTO { + + /** 年度,空则取当前年 */ + private Integer nd; + + /** 学员队编号(选修班),与选修班名称二选一 */ + private String xydbh; + + /** 选修班名称。学员队编号为空时按名称查找或新建选修班 */ + private String xxbmc; + + /** 年级(新建选修班时使用) */ + private String nj; + + /** 课编号 */ + private String kbh; + + /** 学期第次 */ + private Integer xqdc; + + /** 授课教员编号 */ + private String jybh; + + /** 教室编号 */ + private String jsbh; + + /** 计划人数 */ + private Integer rs; + + /** 计划学时 */ + private Integer xs; + + /** 学分 */ + private Float xf; + + /** 教研室代号 */ + private String jysdh; + + /** 备注 */ + private String bz; + + /** 要求说明 */ + private String yqsm; + + /** 显示可选队列班次 */ + private String kxdlbc; + + /** 开课日期 */ + private LocalDateTime kkrq; + + /** 结课日期 */ + private LocalDateTime jkrq; + + /** 报名开始日期 */ + private LocalDateTime bmkssj; + + /** 报名结束日期 */ + private LocalDateTime bmjssj; +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/jys/TeachingTaskQuery.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/jys/TeachingTaskQuery.java new file mode 100644 index 000000000..93b9533bc --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/jys/TeachingTaskQuery.java @@ -0,0 +1,22 @@ +package com.roomroot.jwgl.dto.jys; + +import lombok.Data; + +/** + * 教学任务列表查询条件。 + */ +@Data +public class TeachingTaskQuery { + + /** 任务名称(模糊) */ + private String rwmc; + + /** 年度,空则本学期年度 */ + private Integer nd; + + /** 学期第次 */ + private Integer xqdc; + + /** 状态:上报 / 发布 */ + private String zt; +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/jys/TeachingTaskSaveDTO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/jys/TeachingTaskSaveDTO.java new file mode 100644 index 000000000..f76585e98 --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/jys/TeachingTaskSaveDTO.java @@ -0,0 +1,32 @@ +package com.roomroot.jwgl.dto.jys; + +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 新增 / 编辑教学任务。 + *

机关发布教学任务,并关联学员队(班次);教研室任务书按课程归属教研室自动生成。

+ */ +@Data +public class TeachingTaskSaveDTO { + + /** 编号,编辑时必填 */ + private String bh; + + /** 年度,空则取当前学期 */ + private Integer nd; + + /** 学期第次,空则取当前学期 */ + private Integer xqdc; + + /** 任务名称 */ + private String rwmc; + + /** 结束时间 */ + private LocalDateTime jssj; + + /** 关联的学员队年度学期基本信息编号 */ + private List xydxqbhList; +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/kcb/TimetableQuery.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/kcb/TimetableQuery.java new file mode 100644 index 000000000..cc837ed50 --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/kcb/TimetableQuery.java @@ -0,0 +1,23 @@ +package com.roomroot.jwgl.dto.kcb; + +import lombok.Data; + +/** + * 今日 / 本周 / 班次课表查询条件。 + *

未传年度、学期时按当前时间取本学期。

+ */ +@Data +public class TimetableQuery { + + /** 年度,空则本学期年度 */ + private Integer nd; + + /** 学期第次,空则本学期序号 */ + private Integer xqdc; + + /** 学员队编号(队别班次) */ + private String xydbh; + + /** 学员队名称(队别班次模糊) */ + private String xydmc; +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/DKSQBZMX.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/DKSQBZMX.java index 2415b9675..d009e03bd 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/DKSQBZMX.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/DKSQBZMX.java @@ -1,8 +1,9 @@ package com.roomroot.jwgl.entity; -import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; import com.roomroot.jwgl.unit.BaseEntity; import lombok.Data; import lombok.EqualsAndHashCode; @@ -17,55 +18,48 @@ import java.time.LocalDateTime; @TableName("调课申请_保障明细") public class DKSQBZMX extends BaseEntity { - /** - * 编号 - */ @TableId(value = "编号", type = IdType.INPUT) private String bh; - /** - * 申请编号 - */ + @TableField("申请编号") private String sqbh; - /** - * 保障提供明细编号 - */ + @TableField("保障提供明细编号") private String bztgmxbh; - /** - * 数量 - */ + @TableField("数量") private Integer sl; - /** - * 备注 - */ + @TableField("备注") private String bz; - /** - * 查收状态 - */ + @TableField("查收状态") private Integer cszt; - /** - * 查收时间 - */ + @TableField("查收时间") private LocalDateTime cssj; - /** - * 年度 - */ + @TableField("年度") private Integer nd; - /** - * 日期 - */ + @TableField("日期") private LocalDateTime rq; - /** - * 节次 - */ + @TableField("节次") private Integer jc; + @TableField(exist = false) + private LocalDateTime createTime; + + @TableField(exist = false) + private LocalDateTime updateTime; + + @TableField(exist = false) + private String createBy; + + @TableField(exist = false) + private String updateBy; + + @TableField(exist = false) + private Integer delFlag; } diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/DKSQFZJY.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/DKSQFZJY.java index f9c0524aa..48fbf05e5 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/DKSQFZJY.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/DKSQFZJY.java @@ -1,8 +1,9 @@ package com.roomroot.jwgl.entity; -import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; import com.roomroot.jwgl.unit.BaseEntity; import lombok.Data; import lombok.EqualsAndHashCode; @@ -17,60 +18,51 @@ import java.time.LocalDateTime; @TableName("调课申请_辅助教员") public class DKSQFZJY extends BaseEntity { - /** - * 编号 - */ @TableId(value = "编号", type = IdType.INPUT) private String bh; - /** - * 调课申请编号 - */ + @TableField("调课申请编号") private String dksqbh; - /** - * 辅助教员编号 - */ + @TableField("辅助教员编号") private String fzjybh; - /** - * 查收状态 - */ + @TableField("查收状态") private Integer cszt; - /** - * 查收时间 - */ + @TableField("查收时间") private LocalDateTime cssj; - /** - * 主教员 - */ + @TableField("主教员") private Integer zjy; - /** - * 移除状态 - */ + @TableField("移除状态") private Integer yczt; - /** - * 年度 - */ + @TableField("年度") private Integer nd; - /** - * 备注 - */ + @TableField("备注") private String bz; - /** - * 日期 - */ + @TableField("日期") private LocalDateTime rq; - /** - * 节次 - */ + @TableField("节次") private Integer jc; + @TableField(exist = false) + private LocalDateTime createTime; + + @TableField(exist = false) + private LocalDateTime updateTime; + + @TableField(exist = false) + private String createBy; + + @TableField(exist = false) + private String updateBy; + + @TableField(exist = false) + private Integer delFlag; } diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/DKSQJS.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/DKSQJS.java index eeee15723..6b3241405 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/DKSQJS.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/DKSQJS.java @@ -1,8 +1,9 @@ package com.roomroot.jwgl.entity; -import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; import com.roomroot.jwgl.unit.BaseEntity; import lombok.Data; import lombok.EqualsAndHashCode; @@ -17,40 +18,39 @@ import java.time.LocalDateTime; @TableName("调课申请_教室") public class DKSQJS extends BaseEntity { - /** - * 编号 - */ @TableId(value = "编号", type = IdType.INPUT) private String bh; - /** - * 调课申请编号 - */ + @TableField("调课申请编号") private String dksqbh; - /** - * 教室编号 - */ + @TableField("教室编号") private String jsbh; - /** - * 备注 - */ + @TableField("备注") private String bz; - /** - * 年度 - */ + @TableField("年度") private Integer nd; - /** - * 日期 - */ + @TableField("日期") private LocalDateTime rq; - /** - * 节次 - */ + @TableField("节次") private Integer jc; + @TableField(exist = false) + private LocalDateTime createTime; + + @TableField(exist = false) + private LocalDateTime updateTime; + + @TableField(exist = false) + private String createBy; + + @TableField(exist = false) + private String updateBy; + + @TableField(exist = false) + private Integer delFlag; } diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/DKSQXYD.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/DKSQXYD.java index 094602c4d..9a4ccf559 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/DKSQXYD.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/DKSQXYD.java @@ -1,8 +1,9 @@ package com.roomroot.jwgl.entity; -import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; import com.roomroot.jwgl.unit.BaseEntity; import lombok.Data; import lombok.EqualsAndHashCode; @@ -17,50 +18,45 @@ import java.time.LocalDateTime; @TableName("调课申请_学员队") public class DKSQXYD extends BaseEntity { - /** - * 编号 - */ @TableId(value = "编号", type = IdType.INPUT) private String bh; - /** - * 调课申请编号 - */ + @TableField("调课申请编号") private String dksqbh; - /** - * 学员队编号 - */ + @TableField("学员队编号") private String xydbh; - /** - * 查收状态 - */ + @TableField("查收状态") private Integer cszt; - /** - * 查收时间 - */ + @TableField("查收时间") private LocalDateTime cssj; - /** - * 移除状态 - */ + @TableField("移除状态") private Integer yczt; - /** - * 年度 - */ + @TableField("年度") private Integer nd; - /** - * 日期 - */ + @TableField("日期") private LocalDateTime rq; - /** - * 节次 - */ + @TableField("节次") private Integer jc; + @TableField(exist = false) + private LocalDateTime createTime; + + @TableField(exist = false) + private LocalDateTime updateTime; + + @TableField(exist = false) + private String createBy; + + @TableField(exist = false) + private String updateBy; + + @TableField(exist = false) + private Integer delFlag; } diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/SSDKSQ.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/SSDKSQ.java index 8abcfde66..6fc9bbe83 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/SSDKSQ.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/SSDKSQ.java @@ -3,6 +3,7 @@ package com.roomroot.jwgl.entity; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableField; import com.roomroot.jwgl.unit.BaseEntity; import lombok.Data; import lombok.EqualsAndHashCode; @@ -24,163 +25,134 @@ public class SSDKSQ extends BaseEntity { private String bh; /** - * 实施_课程表编号 + * 实施_课程表编号(原表主关联:指向实施_课程表) */ + @TableField("实施_课程表编号") private String sskcbbh; - /** - * 预调时间安排 - */ + @TableField("预调时间安排") private Integer ydsjap; - /** - * 创建时间 - */ + @TableField("创建时间") private LocalDateTime cjsj; - /** - * 执行人编号 - */ + @TableField("执行人编号") private String zxrbh; - /** - * 执行时间 - */ + @TableField("执行时间") private LocalDateTime zxsj; - /** - * 执行状态 - */ + @TableField("执行状态") private Integer zxzt; - /** - * 事由 - */ + @TableField("事由") private String sy; - /** - * 教研室批准状态 - */ + @TableField("教研室批准状态") private Integer jyspzzt; - /** - * 教研室批准时间 - */ + @TableField("教研室批准时间") private LocalDateTime jyspzsj; - /** - * 教研室批准人编号 - */ + @TableField("教研室批准人编号") private String jyspzrbh; - /** - * 教学系批准状态 - */ - private Integer jxxspzzt; - - /** - * 教学系批准时间 - */ - private LocalDateTime jxxspzsj; - - /** - * 教学系批准人编号 - */ - private String jxxspzrbh; - - /** - * 备注 - */ + @TableField("备注") private String bz; - /** - * 申请教员编号 - */ + @TableField("申请教员编号") private String sqjybh; - /** - * 延时状态 - */ + @TableField("延时状态") private Integer yszt; - /** - * 教研室查收状态 - */ + @TableField("教研室查收状态") private Integer jyscszt; - /** - * 教研室查收时间 - */ + @TableField("教研室查收时间") private LocalDateTime jyscssj; - /** - * 教研室查收人编号 - */ + @TableField("教研室查收人编号") private String jyscsrbh; - /** - * 删除状态 - */ + @TableField("删除状态") private Integer sczt; - /** - * 发回状态 - */ + @TableField("发回状态") private Integer fhzt; - /** - * 发回意见 - */ + @TableField("发回意见") private String fhyj; - /** - * 发回时间 - */ + @TableField("发回时间") private LocalDateTime fhsj; - /** - * 调课 - */ + @TableField("调课") private Integer dk; - /** - * 年度 - */ + @TableField("年度") private Integer nd; - /** - * 日期 - */ + /** 拟调整后的上课日期 */ + @TableField("日期") private LocalDateTime rq; - /** - * 节次 - */ + /** 拟调整后的节次 */ + @TableField("节次") private Integer jc; - /** - * 教学内容 - */ + @TableField("教学内容") private String jxnr; - /** - * 教学要点 - */ + @TableField("教学要点") private String jxyd; - /** - * 教学方法 - */ + @TableField("教学方法") private String jxff; - /** - * 教学保障备注 - */ + @TableField("教学保障备注") private String jxbzbz; - /** - * 用车信息 - */ + @TableField("用车信息") private String ycxx; + /** 学员队任务表编号 */ + @TableField("学员队任务编号") + private String xydrwbh; + + /** 课表.课编号 */ + @TableField("课编号") + private String kbh; + + /** 课程表编号 */ + @TableField("课程表编号") + private String kcbbh; + + /** 申请教员所属教研室代号,用于教研室数据范围过滤 */ + @TableField("教研室代号") + private String jysdh; + + /** 原教室编号 */ + @TableField("原教室编号") + private String yjsbh; + + /** 拟调整教室编号 */ + @TableField("新教室编号") + private String xjsbh; + + @TableField(exist = false) + private LocalDateTime createTime; + + @TableField(exist = false) + private LocalDateTime updateTime; + + @TableField(exist = false) + private String createBy; + + @TableField(exist = false) + private String updateBy; + + @TableField(exist = false) + private Integer delFlag; + } diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/SSDKSQSP.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/SSDKSQSP.java deleted file mode 100644 index 1a7f64a1e..000000000 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/SSDKSQSP.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.roomroot.jwgl.entity; - -import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import com.roomroot.jwgl.unit.BaseEntity; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.time.LocalDateTime; - -/** - * 实施_调课申请审批 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@TableName("实施_调课申请审批") -public class SSDKSQSP extends BaseEntity { - - /** - * 编号 - */ - @TableId(value = "编号", type = IdType.INPUT) - private String bh; - - /** - * 实施_调课申请编号 - */ - private String ssdksqbh; - - /** - * 机关编号 - */ - private String jgbh; - - /** - * 创建时间 - */ - private LocalDateTime cjsj; - - /** - * 审批时间 - */ - private LocalDateTime spsj; - - /** - * 审批状态 - */ - private Integer spzt; - - /** - * 审批人编号 - */ - private String sprbh; - - /** - * 查收状态 - */ - private Integer cszt; - - /** - * 查收时间 - */ - private LocalDateTime cssj; - - /** - * 查收人编号 - */ - private String csrbh; - - /** - * 发回意见 - */ - private String fhyj; - - /** - * 年度 - */ - private Integer nd; - -} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/SSKC.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/SSKC.java index da7c9efbf..883c299b7 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/SSKC.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/SSKC.java @@ -5,7 +5,9 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableField; import com.fasterxml.jackson.annotation.JsonFormat; +import com.roomroot.jwgl.handler.DmGuidTypeHandler; import lombok.Data; +import org.apache.ibatis.type.JdbcType; import java.time.LocalDateTime; @@ -13,13 +15,14 @@ import java.time.LocalDateTime; * 实施_课程 */ @Data -@TableName(value = "实施_课程") +@TableName(value = "实施_课程", autoResultMap = true) public class SSKC { /** - * 编号 + * 编号(库内 VARBINARY(16),Java 侧按 36 位 UUID 字符串使用) */ @TableId(value = "编号", type = IdType.INPUT) + @TableField(value = "编号", jdbcType = JdbcType.VARBINARY, typeHandler = DmGuidTypeHandler.class) private String bh; /** diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/ScheduleAdjustStrategy.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/ScheduleAdjustStrategy.java deleted file mode 100644 index 953a6e161..000000000 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/entity/ScheduleAdjustStrategy.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.roomroot.jwgl.entity; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.Data; - -import java.time.LocalDateTime; - -/** - * 实施_调课策略 - *

- * 管理调课的时间段限制策略与免审批策略。 - * 策略类型为 TIME_LIMIT 时,用于限制教员在规定时间后不得调整下周课程; - * 策略类型为 AUTO_APPROVE 时,用于在生效范围内自动通过调课申请,跳过三级审批。 - *

- */ -@Data -@TableName("实施_调课策略") -public class ScheduleAdjustStrategy { - - /** 策略编号 */ - @TableId(value = "策略编号", type = IdType.INPUT) - private String clbh; - - /** 策略名称 */ - @TableField("策略名称") - private String clmc; - - /** - * 策略类型:TIME_LIMIT=时间段限制,AUTO_APPROVE=免审批 - */ - @TableField("策略类型") - private String cllx; - - /** 是否启用:0=停用,1=启用 */ - @TableField("是否启用") - private Integer sfqy; - - /** - * 截止星期:0-6(周日到周六),仅 TIME_LIMIT 类型使用。 - * 含义:当前时间超过该星期时,不允许调整下周课程。为空表示不限制星期。 - */ - @TableField("截止星期") - private Integer jzxq; - - /** - * 截止节次:仅 TIME_LIMIT 类型使用。 - * 含义:到达截止星期当天的该节次后不允许调整下周课程。为空表示不限制节次。 - */ - @TableField("截止节次") - private Integer jzjc; - - /** 生效开始时间(包含),为空表示不限制开始时间 */ - @TableField("生效开始时间") - private LocalDateTime sxkssj; - - /** 生效结束时间(包含),为空表示不限制结束时间 */ - @TableField("生效结束时间") - private LocalDateTime sxjssj; - - /** 备注 */ - @TableField("备注") - private String bz; - - /** 创建时间 */ - @TableField("创建时间") - private LocalDateTime cjsj; - - /** 更新时间 */ - @TableField("更新时间") - private LocalDateTime gxsj; -} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/handler/DmGuidTypeHandler.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/handler/DmGuidTypeHandler.java new file mode 100644 index 000000000..50e94b337 --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/handler/DmGuidTypeHandler.java @@ -0,0 +1,41 @@ +package com.roomroot.jwgl.handler; + +import com.roomroot.jwgl.utils.UuidUtil; +import org.apache.ibatis.type.BaseTypeHandler; +import org.apache.ibatis.type.JdbcType; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * 达梦 VARBINARY(16) GUID 与 Java 字符串互转。 + *

+ * 仅通过实体 / resultMap 显式引用,避免把其它 VARBINARY 字段都当成 UUID。 + * 禁止把带横线的 CHAR UUID 直接绑定到 VARBINARY,达梦会按十六进制解析并报 -6147。 + *

+ */ +public class DmGuidTypeHandler extends BaseTypeHandler { + + @Override + public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) + throws SQLException { + ps.setBytes(i, UuidUtil.toBytes(parameter)); + } + + @Override + public String getNullableResult(ResultSet rs, String columnName) throws SQLException { + return UuidUtil.fromBytes(rs.getBytes(columnName)); + } + + @Override + public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException { + return UuidUtil.fromBytes(rs.getBytes(columnIndex)); + } + + @Override + public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { + return UuidUtil.fromBytes(cs.getBytes(columnIndex)); + } +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/interceptor/JwglApiAccessInterceptor.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/interceptor/JwglApiAccessInterceptor.java index a22db4680..3f39dff6f 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/interceptor/JwglApiAccessInterceptor.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/interceptor/JwglApiAccessInterceptor.java @@ -62,27 +62,18 @@ public class JwglApiAccessInterceptor implements HandlerInterceptor { if (isTeacherDenied(path)) { return deny(response, "教员无权访问该功能"); } - if (isTeacherAdjustDenied(path, request.getMethod())) { - return deny(response, "教员只能提交、查看和撤销本人的调课申请"); - } return true; } if (roleHelper.isResearchOffice()) { if (isOfficeDenied(path)) { return deny(response, "教研室无权访问系统管理功能"); } - if (isResearchOfficeAdjustDenied(path)) { - return deny(response, "教研室仅可查看和审批本室调课申请"); - } return true; } if (roleHelper.isDepartmentPersonnel()) { if (isOfficeDenied(path)) { return deny(response, "机关人员无权访问系统管理功能"); } - if (isOfficeAdjustDenied(path, request.getMethod())) { - return deny(response, "机关人员仅可查看和审批调课申请"); - } return true; } return true; @@ -92,63 +83,38 @@ public class JwglApiAccessInterceptor implements HandlerInterceptor { if (startsWithAny(path, "/getInfo", "/getRouters", "/logout", "/system/user/profile")) { return true; } + // 通知已读属于个人操作,布局顶栏会调用。 + if (HttpMethod.POST.matches(method) + && startsWithAny(path, "/system/notice/markRead", "/system/notice/markReadAll")) { + return true; + } if (!HttpMethod.GET.matches(method)) { return false; } return startsWithAny(path, + // 学期列表 / 学期校历(只读;新增、修改、删除仍拦截) + "/semester", "/xqxlb", - "/kcb", - "/studentTeamOutputSchedule", "/classCalendar", + // 本人课表 + "/kcb/today", + "/kcb/week", + "/kcb/class", + "/studentTeamOutputSchedule", "/course-running/plan/list", "/course-running/plan/detail", "/course-running/plan/export", + // 本人学籍预警、个人信息、成绩 "/student-records/warning-result", + "/student-records/warning-condition", "/student-records/get", "/student-records/list", "/student-records/grades", - "/student-records/process-grades"); - } - - private boolean isTeacherAdjustDenied(String path, String method) { - if (!path.startsWith("/course-running/adjust")) { - return false; - } - if (path.startsWith("/course-running/adjust/audit") - || path.startsWith("/course-running/adjust/receive")) { - return true; - } - if (path.equals("/course-running/adjust/submit")) { - return !HttpMethod.POST.matches(method); - } - return false; - } - - private boolean isResearchOfficeAdjustDenied(String path) { - if (!path.startsWith("/course-running/adjust")) { - return false; - } - if (path.equals("/course-running/adjust/submit") - || path.equals("/course-running/adjust/cancel") - || path.startsWith("/course-running/adjust/lessons") - || path.startsWith("/course-running/adjust/audit/jg") - || path.startsWith("/course-running/adjust/audit/jxx") - || path.startsWith("/course-running/adjust/receive/jg")) { - return true; - } - return false; - } - - private boolean isOfficeAdjustDenied(String path, String method) { - if (!path.startsWith("/course-running/adjust")) { - return false; - } - if (HttpMethod.GET.matches(method)) { - return path.startsWith("/course-running/adjust/lessons") - || path.startsWith("/course-running/adjust/strategy"); - } - return !(path.startsWith("/course-running/adjust/audit/jg") - || path.startsWith("/course-running/adjust/receive/jg")); + "/student-records/process-grades", + // 布局公共只读:字典、参数、通知 + "/system/dict/data/type", + "/system/config/configKey", + "/system/notice"); } private boolean isTeacherDenied(String path) { diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/DKSQBZMXMapper.xml b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/DKSQBZMXMapper.xml index 4a544ab1f..091b5f55a 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/DKSQBZMXMapper.xml +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/DKSQBZMXMapper.xml @@ -19,7 +19,7 @@ a.数量, a.备注 FROM "调课申请_保障明细" a - LEFT JOIN "保障提供明细表" m ON a.保障提供明细编号 = m.编号 + LEFT JOIN "保障提供明细" m ON TRIM(m.编号) = TRIM(a.保障提供明细编号) WHERE a.申请编号 = #{dksqbh} ORDER BY a.编号 diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/DKSQFZJYMapper.xml b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/DKSQFZJYMapper.xml index 78943a055..ff5430be1 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/DKSQFZJYMapper.xml +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/DKSQFZJYMapper.xml @@ -15,11 +15,11 @@ SELECT a.编号, a.辅助教员编号, - t.姓名 AS 辅助教员姓名, + t.教员姓名 AS 辅助教员姓名, a.主教员, a.备注 FROM "调课申请_辅助教员" a - LEFT JOIN "教员表" t ON a.辅助教员编号 = t.编号 + LEFT JOIN "教员表" t ON TRIM(t.教员编号) = TRIM(a.辅助教员编号) WHERE a.调课申请编号 = #{dksqbh} ORDER BY a.编号 diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/DKSQJSMapper.xml b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/DKSQJSMapper.xml index 3fb2f2d90..8865aa146 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/DKSQJSMapper.xml +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/DKSQJSMapper.xml @@ -17,7 +17,7 @@ r.教室名称, a.备注 FROM "调课申请_教室" a - LEFT JOIN "教室表" r ON a.教室编号 = r.编号 + LEFT JOIN "教室表" r ON TRIM(r.教室编号) = TRIM(a.教室编号) WHERE a.调课申请编号 = #{dksqbh} ORDER BY a.编号 diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/DKSQXYDMapper.xml b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/DKSQXYDMapper.xml index c2480439f..551298d59 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/DKSQXYDMapper.xml +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/DKSQXYDMapper.xml @@ -15,7 +15,7 @@ a.学员队编号, d.学员队名称 FROM "调课申请_学员队" a - LEFT JOIN "学员队表" d ON a.学员队编号 = d.编号 + LEFT JOIN "学员队表" d ON TRIM(d.学员队编号) = TRIM(a.学员队编号) WHERE a.调课申请编号 = #{dksqbh} ORDER BY a.编号 diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/ElectiveCourseMapper.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/ElectiveCourseMapper.java new file mode 100644 index 000000000..6754b273f --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/ElectiveCourseMapper.java @@ -0,0 +1,37 @@ +package com.roomroot.jwgl.mapper; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.roomroot.jwgl.dto.jys.ElectiveCourseQuery; +import com.roomroot.jwgl.vo.jys.ElectiveCourseStudentVO; +import com.roomroot.jwgl.vo.jys.ElectiveCourseVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 选修课管理自定义查询(学员队任务表 + 学员队表 + 课表)。 + */ +@Mapper +public interface ElectiveCourseMapper { + + Page selectElectiveCoursePage(Page page, + @Param("cond") ElectiveCourseQuery cond); + + List selectElectiveCourseList(@Param("cond") ElectiveCourseQuery cond); + + List selectElectiveStudents(@Param("xydbh") String xydbh); + + List selectOriginalClassNames(@Param("xydbh") String xydbh); + + Integer countPinban(@Param("xydbh") String xydbh); + + int insertPinban(@Param("xydbh") String xydbh, @Param("zt") String zt, + @Param("jhkssj") LocalDateTime jhkssj, @Param("jhjssj") LocalDateTime jhjssj, + @Param("yqsm") String yqsm, @Param("bmdtj") String bmdtj, @Param("bz") String bz); + + int updatePinban(@Param("xydbh") String xydbh, @Param("zt") String zt, + @Param("jhkssj") LocalDateTime jhkssj, @Param("jhjssj") LocalDateTime jhjssj, + @Param("yqsm") String yqsm, @Param("bmdtj") String bmdtj); +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/ElectiveCourseMapper.xml b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/ElectiveCourseMapper.xml new file mode 100644 index 000000000..86bacaec5 --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/ElectiveCourseMapper.xml @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + t."编号" AS bh, + t."年度" AS nd, + t."学员队编号" AS xydbh, + t."课编号" AS kbh, + t."教员编号" AS jybh, + t."教室编号" AS jsbh, + k."课名称" AS kmc, + (SELECT WM_CONCAT(DISTINCT jc."名称") + FROM "课程教材" kj + LEFT JOIN "教材信息" jc ON jc."编号" = kj."教材编号" + WHERE kj."课编号" = t."课编号") AS jcmc, + jy."教员姓名" AS jyxm, + (SELECT MAX(js."教室名称") FROM "教室表" js WHERE js."教室编号" = t."教室编号") AS jsmc, + COALESCE(pb."白名单条件", xyd."学员队名称") AS kxdlbc, + COALESCE(sskc.jhxs, t."学时", k."学时") AS jhxs, + sskc.yxxs AS yxxs, + COALESCE(sskc.xf, t."学分", k."学分") AS xf, + (NVL(TO_CHAR(COALESCE(sskc.jhxs, t."学时", k."学时")), '-') + || ' / ' || NVL(TO_CHAR(sskc.yxxs), '-') + || ' / ' || NVL(TO_CHAR(COALESCE(sskc.xf, t."学分", k."学分")), '-')) AS jhyxxsxf, + CASE + WHEN COALESCE(xq.kxrq, xyd."入学日期") IS NULL THEN NULL + ELSE TO_CHAR(COALESCE(xq.kxrq, xyd."入学日期"), 'YYYY-MM-DD') + || ' ~ ' + || NVL(TO_CHAR(COALESCE(xq.jsrq, xyd."毕业日期"), 'YYYY-MM-DD'), '-') + END AS kkjkrq, + CASE + WHEN COALESCE(pb."计划开始时间", q."入学日期") IS NULL THEN NULL + ELSE TO_CHAR(COALESCE(pb."计划开始时间", q."入学日期"), 'YYYY-MM-DD') + || ' ~ ' + || NVL(TO_CHAR(COALESCE(pb."计划结束时间", q."结束注册时间"), 'YYYY-MM-DD'), '-') + END AS bmrq, + COALESCE(t."人数", xyd."学员队人数") AS jhrs, + pb."要求说明" AS yqsm, + xyd."学员队名称" AS xxbmc, + COALESCE(pb."状态", + CASE t."选择" WHEN 1 THEN '开放报名' WHEN 2 THEN '停止报名' ELSE '拟制' END) AS xkzt, + k."培训层次" AS pxcc + + + + FROM "学员队任务表" t + INNER JOIN "学员队表" xyd ON t."学员队编号" = xyd."学员队编号" + INNER JOIN "课表" k ON t."课编号" = k."课编号" + LEFT JOIN "教员表" jy ON t."教员编号" = jy."教员编号" + LEFT JOIN "学员队拼班信息" pb ON pb."学员队编号" = t."学员队编号" + LEFT JOIN "学员队期表" q ON q."学员队编号" = t."学员队编号" + LEFT JOIN ( + SELECT "学员队编号", "年度", "学期第次", + MIN("开学日期") AS kxrq, MAX("结束日期") AS jsrq + FROM "学员队年度学期基本信息表" + GROUP BY "学员队编号", "年度", "学期第次" + ) xq ON xq."学员队编号" = t."学员队编号" + AND xq."年度" = t."年度" + AND xq."学期第次" = t."学期第次" + LEFT JOIN ( + SELECT "科目编号", "教员编号", "年度", + MAX("学时") AS jhxs, MAX("运行学时") AS yxxs, MAX("学分") AS xf + FROM "实施_课程" + GROUP BY "科目编号", "教员编号", "年度" + ) sskc ON sskc."科目编号" = t."课编号" + AND (sskc."教员编号" = t."教员编号" OR t."教员编号" IS NULL) + AND (sskc."年度" = t."年度" OR t."年度" IS NULL) + + t."课类型" LIKE '%选修%' + AND (t.DEL_FLAG = 0 OR t.DEL_FLAG IS NULL) + + AND jy."教员姓名" LIKE CONCAT('%', #{cond.jyxm}, '%') + + + AND k."课名称" LIKE CONCAT('%', #{cond.kmc}, '%') + + + AND (xyd."年级" LIKE CONCAT('%', #{cond.kxbcnj}, '%') + OR pb."白名单条件" LIKE CONCAT('%', #{cond.kxbcnj}, '%') + OR xyd."学员队名称" LIKE CONCAT('%', #{cond.kxbcnj}, '%')) + + + AND xyd."学员队名称" LIKE CONCAT('%', #{cond.xxbmc}, '%') + + + AND COALESCE(pb."状态", + CASE t."选择" WHEN 1 THEN '开放报名' WHEN 2 THEN '停止报名' ELSE '拟制' END) = #{cond.xkzt} + + + AND k."培训层次" = #{cond.pxcc} + + + AND t."编号" IN + + #{id} + + + + + + + + + + + + + + + + + INSERT INTO "学员队拼班信息"( + "学员队编号", "状态", "计划开始时间", "计划结束时间", "要求说明", "白名单条件", "备注" + ) VALUES ( + #{xydbh}, #{zt}, #{jhkssj}, #{jhjssj}, #{yqsm}, #{bmdtj}, #{bz} + ) + + + + UPDATE "学员队拼班信息" + + "状态" = #{zt}, + "计划开始时间" = #{jhkssj}, + "计划结束时间" = #{jhjssj}, + "要求说明" = #{yqsm}, + "白名单条件" = #{bmdtj}, + + WHERE "学员队编号" = #{xydbh} + + diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/JYBMapper.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/JYBMapper.java index 538a746dc..26187d006 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/JYBMapper.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/JYBMapper.java @@ -6,6 +6,7 @@ import com.roomroot.jwgl.entity.JYB; import com.roomroot.jwgl.vo.faculty.TeacherListVO; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; /** * 教员表 Mapper @@ -27,4 +28,9 @@ public interface JYBMapper extends BaseMapper { /** 教员列表双表联查分页 */ Page selectTeacherPageList(Page page, @Param("jyb") JYB cond); + + @Select("SELECT TRIM(b.\"教员编号\") FROM \"教员登录表\" b " + + "JOIN \"登录信息表\" a ON TRIM(a.\"编号\") = TRIM(b.\"登录信息编号\") " + + "WHERE TRIM(a.\"账号\") = #{username}") + String selectTeacherIdByAccount(@Param("username") String username); } diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/KcbTimetableMapper.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/KcbTimetableMapper.java new file mode 100644 index 000000000..7f44867a5 --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/KcbTimetableMapper.java @@ -0,0 +1,28 @@ +package com.roomroot.jwgl.mapper; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.roomroot.jwgl.dto.kcb.TimetableQuery; +import com.roomroot.jwgl.vo.kcb.ClassTimetableVO; +import com.roomroot.jwgl.vo.kcb.DailyWeeklyTimetableVO; +import com.roomroot.jwgl.vo.kcb.SemesterGradeExportVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 今日 / 本周 / 班次课表查询。 + */ +@Mapper +public interface KcbTimetableMapper { + + List selectLessonTimetable(@Param("cond") TimetableQuery cond, + @Param("startDate") String startDate, @Param("endDate") String endDate); + + Page selectClassTimetable(Page page, + @Param("cond") TimetableQuery cond); + + List selectClassTimetableList(@Param("cond") TimetableQuery cond); + + List selectSemesterGrades(@Param("cond") TimetableQuery cond); +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/KcbTimetableMapper.xml b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/KcbTimetableMapper.xml new file mode 100644 index 000000000..4567c9f16 --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/KcbTimetableMapper.xml @@ -0,0 +1,176 @@ + + + + + + + AND EXISTS ( + SELECT 1 FROM "实施_课程表_学员队" txf + WHERE txf."实施_课程表编号" = s."编号" + AND txf."学员队编号" = #{cond.xydbh} + ) + + + AND EXISTS ( + SELECT 1 FROM "实施_课程表_学员队" txf + INNER JOIN "学员队表" xydf ON xydf."学员队编号" = txf."学员队编号" + WHERE txf."实施_课程表编号" = s."编号" + AND xydf."学员队名称" LIKE CONCAT('%', #{cond.xydmc}, '%') + ) + + + AND EXISTS ( + SELECT 1 FROM "实施_课程学员队" cxf + WHERE LOWER(RAWTOHEX(c."编号")) = LOWER(REPLACE(TRIM(cxf."实施_课程编号"), '-', '')) + AND cxf."学期第次" = #{cond.xqdc} + ) + + + + + + + WHERE 1 = 1 + + AND COALESCE(cx."年度", c."年度") = #{cond.nd} + + + AND cx."学期第次" = #{cond.xqdc} + + + AND cx."学员队编号" = #{cond.xydbh} + + + AND xyd."学员队名称" LIKE CONCAT('%', #{cond.xydmc}, '%') + + + + + SELECT + LOWER( + SUBSTR(RAWTOHEX(c."编号"), 1, 8) || '-' || + SUBSTR(RAWTOHEX(c."编号"), 9, 4) || '-' || + SUBSTR(RAWTOHEX(c."编号"), 13, 4) || '-' || + SUBSTR(RAWTOHEX(c."编号"), 17, 4) || '-' || + SUBSTR(RAWTOHEX(c."编号"), 21, 12) + ) AS sskcbh, + (NVL(k."课名称", c."科目编号") + || ' / ' + || NVL(TO_CHAR(c."课程课时系数"), '-')) AS kcmcksxs, + (NVL(zjy."教员姓名", '-') + || ' / ' + || NVL(TO_CHAR(c."教员课次序号"), + TO_CHAR((SELECT COUNT(1) FROM "实施_课程表" t + WHERE LOWER(RAWTOHEX(c."编号")) = LOWER(REPLACE(TRIM(t."实施_课程编号"), '-', '')) + AND COALESCE(t."删除状态", 0) = 0)))) AS zrjykc, + c."学时" AS jhxs, + c."运行学时" AS yxxs, + COALESCE(k."考核方式", c."成绩分制") AS khlxfs, + sjy."教员姓名" AS ssjy, + (NVL(TO_CHAR(cx."人数"), NVL(TO_CHAR(xyd."学员队人数"), '-')) + || ' / ' + || NVL((SELECT WM_CONCAT(DISTINCT js."教室名称") + FROM "实施_课程表" t + LEFT JOIN "实施_课程表_教室" jsx ON jsx."实施_课程表编号" = t."编号" + LEFT JOIN "教室表" js ON js."教室编号" = jsx."教室编号" + WHERE LOWER(RAWTOHEX(c."编号")) = LOWER(REPLACE(TRIM(t."实施_课程编号"), '-', '')) + AND COALESCE(t."删除状态", 0) = 0), + NVL(js0."教室名称", '-'))) AS rscd, + (SELECT WM_CONCAT(DISTINCT sq."事由") + FROM "实施_调课申请" sq + INNER JOIN "实施_课程表" t ON t."编号" = sq."实施_课程表编号" + WHERE LOWER(RAWTOHEX(c."编号")) = LOWER(REPLACE(TRIM(t."实施_课程编号"), '-', ''))) AS ssjhbg + FROM "实施_课程" c + INNER JOIN "实施_课程学员队" cx ON LOWER(RAWTOHEX(c."编号")) = LOWER(REPLACE(TRIM(cx."实施_课程编号"), '-', '')) + LEFT JOIN "学员队表" xyd ON xyd."学员队编号" = cx."学员队编号" + LEFT JOIN "课表" k ON (k."课编号" = c."科目编号" OR k."科目代码" = c."科目编号") + LEFT JOIN "教员表" zjy ON zjy."教员编号" = c."责任教员编号" + LEFT JOIN "教员表" sjy ON sjy."教员编号" = c."教员编号" + LEFT JOIN "教室表" js0 ON js0."教室编号" = c."教室编号" + + + + + + + + diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSDKSQMapper.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSDKSQMapper.java index 88d2b0ee5..667876142 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSDKSQMapper.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSDKSQMapper.java @@ -3,43 +3,30 @@ package com.roomroot.jwgl.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.roomroot.jwgl.entity.SSDKSQ; +import com.roomroot.jwgl.vo.courserunning.AdjustableLessonVO; import com.roomroot.jwgl.vo.courserunning.ScheduleAdjustApplyVO; import com.roomroot.jwgl.vo.courserunning.ScheduleAdjustDetailVO; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; +import java.util.List; + /** * 实施_调课申请 Mapper。 - *

- * 提供调课申请数据的CRUD操作及调课管理相关的自定义查询。 - *

*/ @Mapper public interface SSDKSQMapper extends BaseMapper { /** * 分页查询调课申请列表。 - *

- * 支持按实施_课程表编号、申请教员编号、年度、教研室审批状态、 - * 教研室查收状态、删除状态和申请日期范围筛选。 - * 关联课程表获取课程名称,关联教员表获取申请教员姓名。 - *

- * - * @param page MyBatis-Plus 分页对象 - * @param sskcbbh 实施_课程表编号 - * @param sqjybh 申请教员编号 - * @param nd 年度 - * @param jyspzzt 教研室审批状态 - * @param jyscszt 教研室查收状态 - * @param sczt 删除状态 - * @param cjsjStart 申请日期范围开始 - * @param cjsjEnd 申请日期范围结束 - * @return 分页调课申请列表 */ Page selectPageList( Page page, @Param("sskcbbh") String sskcbbh, + @Param("xydrwbh") String xydrwbh, + @Param("kbh") String kbh, @Param("sqjybh") String sqjybh, + @Param("jysdh") String jysdh, @Param("nd") Integer nd, @Param("jyspzzt") Integer jyspzzt, @Param("jyscszt") Integer jyscszt, @@ -48,13 +35,12 @@ public interface SSDKSQMapper extends BaseMapper { @Param("cjsjEnd") String cjsjEnd); /** - * 根据调课申请编号查询调课申请详情。 - *

- * 关联课程表获取课程名称,关联教员表获取申请教员姓名。 - *

- * - * @param ssdksqbh 调课申请编号 - * @return 调课申请详情 + * 根据调课申请编号查询详情。 */ ScheduleAdjustDetailVO selectDetailById(@Param("ssdksqbh") String ssdksqbh); + + /** + * 查询可供调课的课次(学员队任务表 + 课表 + 课程表)。 + */ + List selectAdjustableLessons(@Param("jybh") String jybh, @Param("nd") Integer nd); } diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSDKSQMapper.xml b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSDKSQMapper.xml index 8182e7c52..2cf0f29f7 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSDKSQMapper.xml +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSDKSQMapper.xml @@ -2,11 +2,17 @@ - + + + + + + + @@ -20,11 +26,17 @@ - + + + + + + + @@ -44,16 +56,46 @@ + - + + + + + + + + + + + + + + + + + + - + + + diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSDKSQSPMapper.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSDKSQSPMapper.java deleted file mode 100644 index 5000e557f..000000000 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSDKSQSPMapper.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.roomroot.jwgl.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.roomroot.jwgl.entity.SSDKSQSP; -import com.roomroot.jwgl.vo.courserunning.ScheduleAdjustAuditVO; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; - -import java.util.List; - -/** - * 实施_调课申请审批 Mapper。 - *

- * 提供调课申请审批记录数据的CRUD操作及自定义查询。 - *

- */ -@Mapper -public interface SSDKSQSPMapper extends BaseMapper { - - /** - * 根据调课申请编号查询审批记录列表。 - *

- * 关联机构表获取机关名称,关联教员表获取审批人姓名。 - *

- * - * @param ssdksqbh 调课申请编号 - * @return 审批记录列表 - */ - List selectBySsdksqbh(@Param("ssdksqbh") String ssdksqbh); -} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSDKSQSPMapper.xml b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSDKSQSPMapper.xml deleted file mode 100644 index e17421a9e..000000000 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSDKSQSPMapper.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSKCBFZJYMapper.xml b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSKCBFZJYMapper.xml index cf2781ecd..1622959d3 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSKCBFZJYMapper.xml +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSKCBFZJYMapper.xml @@ -61,7 +61,7 @@ * 内层:按教员编号+日期+节次 GROUP BY,筛选出现>1课次的冲突 * * 关键修正: - * 1. 关联链路:SSKCB → 实施_课程 c → 课表 k;必须 CAST(c.编号 AS CHAR(36)) + * 1. 关联链路:SSKCB → 实施_课程 c → 课表 k;VARBINARY 主键用 RAWTOHEX 对齐 CHAR 外键 * 2. 主讲/辅讲字段:真实列名「主教员」(1主/0辅) * 3. 日期节次:统一取主表 s * @@ -92,7 +92,7 @@ /* 维度过滤主关联:只看该教员的课次(GROUP BY 维度)*/ INNER JOIN "实施_课程表_辅助教员" f ON f."实施_课程表编号" = s."编号" /* 课表信息三层关联 */ - LEFT JOIN "实施_课程" c ON CAST(c."编号" AS CHAR(36)) = s."实施_课程编号" + LEFT JOIN "实施_课程" c ON LOWER(RAWTOHEX(c."编号")) = LOWER(REPLACE(TRIM(s."实施_课程编号"), '-', '')) LEFT JOIN "课表" k ON k."科目代码" = c."科目编号" /* ========== 新增 JOIN:聚合该冲突课次的班次/教员/场地所有信息 ========== */ LEFT JOIN "实施_课程表_学员队" xyd_link ON xyd_link."实施_课程表编号" = s."编号" diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSKCBJSMapper.xml b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSKCBJSMapper.xml index dbe611a7d..db27329e4 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSKCBJSMapper.xml +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSKCBJSMapper.xml @@ -62,7 +62,7 @@ * 内层:按教室编号+日期+节次 GROUP BY,筛选 COUNT(DISTINCT 课次) > 1 * * 关键修正: - * 1. 三层关联 JOIN:SSKCB → 实施_课程 → 课表;CAST(ss.编号 AS CHAR(36)) + * 1. 三层关联 JOIN:SSKCB → 实施_课程 → 课表;VARBINARY 主键用 RAWTOHEX 对齐 CHAR 外键 * 2. 日期节次统一取主表 s * * 新增 JOIN(同其他维度):聚合该冲突课次的班次/教员/场地所有明细信息 @@ -88,7 +88,7 @@ /* 维度过滤主关联:教室维度分组 */ INNER JOIN "实施_课程表_教室" c ON c."实施_课程表编号" = s."编号" /* 课表信息三层关联(ss=实施_课程别名,避免与聚合JOIN的别名冲突)*/ - LEFT JOIN "实施_课程" ss ON CAST(ss."编号" AS CHAR(36)) = s."实施_课程编号" + LEFT JOIN "实施_课程" ss ON LOWER(RAWTOHEX(ss."编号")) = LOWER(REPLACE(TRIM(s."实施_课程编号"), '-', '')) LEFT JOIN "课表" k ON k."科目代码" = ss."科目编号" /* ========== 新增 JOIN:聚合该冲突课次的班次/教员/场地所有信息 ========== */ LEFT JOIN "实施_课程表_学员队" xyd_link ON xyd_link."实施_课程表编号" = s."编号" diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSKCBMapper.xml b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSKCBMapper.xml index 753db9cad..c39294bbb 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSKCBMapper.xml +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSKCBMapper.xml @@ -60,7 +60,7 @@ b.创建时间, b.变动时间 FROM "实施_课程表" b - LEFT JOIN "实施_课程" a ON b.实施_课程编号 = a.编号 + LEFT JOIN "实施_课程" a ON LOWER(RAWTOHEX(a."编号")) = LOWER(REPLACE(TRIM(b.实施_课程编号), '-', '')) LEFT JOIN "课程表" c ON a.课编号 = c.课编号 WHERE b.删除状态 = 0 @@ -116,7 +116,7 @@ b.创建时间, b.变动时间 FROM "实施_课程表" b - LEFT JOIN "实施_课程" a ON b.实施_课程编号 = a.编号 + LEFT JOIN "实施_课程" a ON LOWER(RAWTOHEX(a."编号")) = LOWER(REPLACE(TRIM(b.实施_课程编号), '-', '')) LEFT JOIN "课程表" c ON a.课编号 = c.课编号 WHERE b.编号 = #{sskcbbh} AND b.删除状态 = 0 diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSKCBXYDMapper.xml b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSKCBXYDMapper.xml index 7047f0e7c..536556b6d 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSKCBXYDMapper.xml +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSKCBXYDMapper.xml @@ -32,10 +32,11 @@ JOIN "实施_课程表_学员队" t ON t."实施_课程表编号" = s."编号" - LEFT JOIN "实施_课程" c ON CAST(c."编号" AS CHAR(36)) = s."实施_课程编号" + LEFT JOIN "实施_课程" c ON LOWER(RAWTOHEX(c."编号")) = LOWER(REPLACE(TRIM(s."实施_课程编号"), '-', '')) LEFT JOIN "课表" k ON k."科目代码" = c."科目编号" WHERE t."学员队编号" = #{xydbh} @@ -126,7 +127,7 @@ /* 维度过滤用:主关联"教学班(学员队)" —— 教学班冲突就是按这个维度 GROUP BY */ INNER JOIN "实施_课程表_学员队" t ON t."实施_课程表编号" = s."编号" /* 课表信息三层关联 */ - LEFT JOIN "实施_课程" c ON CAST(c."编号" AS CHAR(36)) = s."实施_课程编号" + LEFT JOIN "实施_课程" c ON LOWER(RAWTOHEX(c."编号")) = LOWER(REPLACE(TRIM(s."实施_课程编号"), '-', '')) LEFT JOIN "课表" k ON k."科目代码" = c."科目编号" /* ========== 新增 JOIN:聚合该冲突课次涉及的所有班次/教员/教室信息 ========== */ LEFT JOIN "实施_课程表_学员队" xyd_link ON xyd_link."实施_课程表编号" = s."编号" @@ -206,7 +207,7 @@ WM_CONCAT(DISTINCT xyd_info."所属单位") AS responsible_dept_list FROM "实施_课程表" s INNER JOIN "实施_课程表_学员队" t ON t."实施_课程表编号" = s."编号" - LEFT JOIN "实施_课程" c ON CAST(c."编号" AS CHAR(36)) = s."实施_课程编号" + LEFT JOIN "实施_课程" c ON LOWER(RAWTOHEX(c."编号")) = LOWER(REPLACE(TRIM(s."实施_课程编号"), '-', '')) LEFT JOIN "课表" k ON k."科目代码" = c."科目编号" /* ========== 新增 JOIN:三类业务信息 ========== */ LEFT JOIN "实施_课程表_学员队" xyd_link ON xyd_link."实施_课程表编号" = s."编号" diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSKCMapper.xml b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSKCMapper.xml index 307ca4cfa..7229643d9 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSKCMapper.xml +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SSKCMapper.xml @@ -2,20 +2,32 @@ - SELECT * FROM 实施_课程 WHERE 年度 = #{nd} AND 学期第次 = #{xqdc} AND 停用 = 0 - SELECT DISTINCT sc.* FROM 实施_课程 sc - INNER JOIN 实施_课程学员队 scxd ON sc.编号 = scxd.实施_课程编号 + INNER JOIN 实施_课程学员队 scxd + ON LOWER(RAWTOHEX(sc."编号")) = LOWER(REPLACE(TRIM(scxd."实施_课程编号"), '-', '')) WHERE scxd.学员队编号 = #{classBh} AND sc.年度 = #{nd} AND sc.停用 = 0 - SELECT sc.* FROM 实施_课程 sc - INNER JOIN 实施_课程学员队 scxd ON sc.编号 = scxd.实施_课程编号 + INNER JOIN 实施_课程学员队 scxd + ON LOWER(RAWTOHEX(sc."编号")) = LOWER(REPLACE(TRIM(scxd."实施_课程编号"), '-', '')) WHERE sc.课编号 = #{courseBh} AND scxd.学员队编号 = #{classBh} AND sc.年度 = #{nd} AND sc.停用 = 0 diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/ScheduleAdjustStrategyMapper.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/ScheduleAdjustStrategyMapper.java deleted file mode 100644 index ddca3f581..000000000 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/ScheduleAdjustStrategyMapper.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.roomroot.jwgl.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.roomroot.jwgl.entity.ScheduleAdjustStrategy; -import org.apache.ibatis.annotations.Mapper; - -/** - * 实施_调课策略 Mapper。 - *

- * 提供调课策略的基础 CRUD 能力,时间段限制与免审批策略的匹配查询 - * 由 Service 层调用 BaseMapper 方法完成。 - *

- */ -@Mapper -public interface ScheduleAdjustStrategyMapper extends BaseMapper { -} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/TeachingTaskMapper.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/TeachingTaskMapper.java index 373cfa1d4..b71673892 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/TeachingTaskMapper.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/TeachingTaskMapper.java @@ -2,10 +2,17 @@ package com.roomroot.jwgl.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.roomroot.jwgl.dto.jys.TeachingTaskQuery; import com.roomroot.jwgl.entity.JXRW; +import com.roomroot.jwgl.vo.jys.TeachingOfficeBookCourseVO; +import com.roomroot.jwgl.vo.jys.TeachingOfficeBookVO; +import com.roomroot.jwgl.vo.jys.TeachingTaskSquadVO; +import com.roomroot.jwgl.vo.jys.TeachingTaskVO; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; +import java.util.List; + /** * 教学任务 Mapper */ @@ -20,4 +27,31 @@ public interface TeachingTaskMapper extends BaseMapper { * @return 分页结果 */ Page selectPageList(Page page, @Param("jxrw") JXRW jxrw); -} \ No newline at end of file + + /** + * 教学任务管理分页(含教研室数、学员队数、合班前后课程任务/学时)。 + */ + Page selectManagePage(Page page, @Param("cond") TeachingTaskQuery cond); + + /** + * 教研室任务书列表(含课程任务数、完成指定数)。 + */ + List selectOfficeBooks(@Param("jxrwbh") String jxrwbh); + + /** + * 教学任务已关联学员队。 + */ + List selectBoundSquads(@Param("jxrwbh") String jxrwbh); + + /** + * 某学期可选学员队(未占用或占用当前任务)。 + */ + List selectAvailableSquads(@Param("nd") Integer nd, + @Param("xqdc") Integer xqdc, @Param("jxrwbh") String jxrwbh); + + /** + * 教研室任务书课程明细。 + */ + List selectOfficeBookCourses(@Param("jxrwbh") String jxrwbh, + @Param("jysdh") String jysdh); +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/TeachingTaskMapper.xml b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/TeachingTaskMapper.xml index 1d358ebf3..760a49c52 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/TeachingTaskMapper.xml +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/TeachingTaskMapper.xml @@ -38,4 +38,194 @@ ORDER BY 编号 + + FROM "学员队任务表" r + INNER JOIN "学员队年度学期基本信息表" s ON s."编号" = r."学员队学期编号" + WHERE s."教学任务编号" = t."编号" + AND NVL(r.DEL_FLAG, 0) = 0 + AND NVL(s.DEL_FLAG, 0) = 0 + + + + + + + + SELECT + s."编号" AS xydxqbh, + s."学员队编号" AS xydbh, + d."学员队名称" AS xydmc, + d."年级" AS nj, + d."专业代号" AS zydh, + z."专业名称" AS zymc, + d."学员队人数" AS xydrs, + s."年度" AS nd, + s."学期第次" AS xqdc, + s."开学日期" AS kxrq, + s."结束日期" AS jsrq, + CASE + WHEN s."教学任务编号" IS NOT NULL + AND s."教学任务编号" != '' + AND (#{jxrwbh} IS NULL OR s."教学任务编号" != #{jxrwbh}) + THEN 1 ELSE 0 + END AS occupied + FROM "学员队年度学期基本信息表" s + LEFT JOIN "学员队表" d ON d."学员队编号" = s."学员队编号" + LEFT JOIN "专业表" z ON z."专业代号" = d."专业代号" + + + + + + + +
\ No newline at end of file diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/TestPkMapper.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/TestPkMapper.java new file mode 100644 index 000000000..6954d5e02 --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/TestPkMapper.java @@ -0,0 +1,40 @@ +package com.roomroot.jwgl.mapper; + +import com.roomroot.jwgl.vo.jwtest.PkConflictVO; +import com.roomroot.jwgl.vo.jwtest.PkLessonVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 排课测试全查与冲突检查。 + */ +@Mapper +public interface TestPkMapper { + + /** + * 查询全部排课记录,无筛选条件。 + */ + List selectAll(); + + /** + * 同一班次同一日期节次被安排多门课程。 + */ + List selectClassTimeConflict(@Param("nd") Integer nd); + + /** + * 同一班次同一日期节次必修课与选修课重叠。 + */ + List selectElectiveRequiredConflict(@Param("nd") Integer nd); + + /** + * 同一教员同一日期节次被安排多门课程。 + */ + List selectTeacherTimeConflict(@Param("nd") Integer nd); + + /** + * 同一教室同一日期节次被多门课程占用。 + */ + List selectClassroomTimeConflict(@Param("nd") Integer nd); +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/TestPkMapper.xml b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/TestPkMapper.xml new file mode 100644 index 000000000..864eff14e --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/TestPkMapper.xml @@ -0,0 +1,310 @@ + + + + + + + + + + SELECT + s."编号" AS kcbh, + TO_CHAR(s."日期", 'YYYY-MM-DD') AS skrq, + s."日期" AS rq, + s."节次" AS jc, + MAX(jc."开始时间") AS kssj, + MAX(jc."结束时间") AS jssj, + COALESCE(NULLIF(TRIM(MAX(s."教学内容")), ''), MAX(k."课名称")) AS ktmc, + MAX(k."课名称") AS kcmc, + MAX(NVL(k."课程类型", NVL(k."课类型", c."课类型"))) AS kclx, + COALESCE(WM_CONCAT(DISTINCT jyf."教员姓名"), MAX(jy."教员姓名")) AS jymc, + WM_CONCAT(DISTINCT xyd."学员队名称") AS bjmc, + COALESCE(WM_CONCAT(DISTINCT jsb."教室名称"), MAX(js."教室名称")) AS jsmc + FROM "实施_课程表" s + LEFT JOIN "实施_课程" c + ON LOWER(RAWTOHEX(c."编号")) = LOWER(REPLACE(TRIM(s."实施_课程编号"), '-', '')) + LEFT JOIN "课表" k + ON (k."课编号" = c."科目编号" OR k."科目代码" = c."科目编号") + LEFT JOIN "课程表" kcb + ON kcb."年度" = s."年度" + AND kcb."安排时间" = s."计划时间安排" + AND TRIM(kcb."教员编号") = TRIM(c."教员编号") + LEFT JOIN "教员表" jy + ON TRIM(jy."教员编号") = TRIM(NVL(kcb."授课教员编号", c."教员编号")) + LEFT JOIN "实施_课程表_辅助教员" fz ON TRIM(fz."实施_课程表编号") = TRIM(s."编号") + LEFT JOIN "教员表" jyf ON TRIM(jyf."教员编号") = TRIM(fz."辅助教员编号") + LEFT JOIN "实施_课程表_学员队" tx ON TRIM(tx."实施_课程表编号") = TRIM(s."编号") + LEFT JOIN "学员队表" xyd ON xyd."学员队编号" = tx."学员队编号" + LEFT JOIN "实施_课程表_教室" jsx ON TRIM(jsx."实施_课程表编号") = TRIM(s."编号") + LEFT JOIN "教室表" jsb ON jsb."教室编号" = jsx."教室编号" + LEFT JOIN "教室表" js ON js."教室编号" = NVL(kcb."教室编号", c."教室编号") + LEFT JOIN "节次时间表" jc ON TRIM(jc."节次索引") = TRIM(CAST(s."节次" AS VARCHAR)) + WHERE NVL(s."删除状态", 0) = 0 + + AND s."年度" = #{nd} + + GROUP BY s."编号", s."日期", s."节次" + + + + + + + + + + + + + + + diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/XYJXQJBMapper.xml b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/XYJXQJBMapper.xml index e2e3baa89..ea4c549eb 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/XYJXQJBMapper.xml +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/XYJXQJBMapper.xml @@ -216,7 +216,7 @@ LEFT JOIN "教员表" j ON j."教员编号" = sp."审批人编号" LEFT JOIN "请假课堂表" qjkt ON qjkt."请假编号" = q."编号" LEFT JOIN "实施_课程表" sskcb ON sskcb."编号" = qjkt."实施_课堂编号" - LEFT JOIN "实施_课程" sskc ON sskcb."实施_课程编号" = sskc."编号" + LEFT JOIN "实施_课程" sskc ON LOWER(RAWTOHEX(sskc."编号")) = LOWER(REPLACE(TRIM(sskcb."实施_课程编号"), '-', '')) LEFT JOIN "课表" kb ON sskc."科目编号" = kb."课编号" WHERE q."编号" = #{qjbh} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/CourseRunningImportService.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/CourseRunningImportService.java index 177918c8c..2c367a146 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/CourseRunningImportService.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/CourseRunningImportService.java @@ -18,8 +18,8 @@ import com.roomroot.jwgl.dto.courserunning.StudentLeaveApplyDTO; import com.roomroot.jwgl.dto.courserunning.StudentLeaveAuditDTO; import com.roomroot.jwgl.dto.courserunning.StudentLeaveQueryDTO; import com.roomroot.jwgl.dto.courserunning.OperationAnalysisQueryDTO; -import com.roomroot.jwgl.dto.courserunning.ScheduleAdjustStrategyDTO; import com.roomroot.jwgl.unit.PageResult; +import com.roomroot.jwgl.vo.courserunning.AdjustableLessonVO; import com.roomroot.jwgl.vo.courserunning.CourseRunningImportResultVO; import com.roomroot.jwgl.vo.courserunning.ScheduleAdjustApplyVO; import com.roomroot.jwgl.vo.courserunning.ScheduleAdjustDetailVO; @@ -36,7 +36,6 @@ import com.roomroot.jwgl.vo.courserunning.OperationOverviewVO; import com.roomroot.jwgl.vo.courserunning.CourseCompletionByDeptVO; import com.roomroot.jwgl.vo.courserunning.VenueUsageRateVO; import com.roomroot.jwgl.vo.courserunning.ScheduleAdjustTrendVO; -import com.roomroot.jwgl.vo.courserunning.ScheduleAdjustStrategyVO; import java.util.List; @@ -178,6 +177,14 @@ public interface CourseRunningImportService { */ PageResult queryScheduleAdjustList(ScheduleAdjustQueryDTO query); + /** + * 查询当前教员可供调课的课次,关联学员队任务表、课表、课程表。 + * + * @param nd 年度,可空 + * @return 可选课次列表 + */ + List listAdjustableLessons(Integer nd); + /** * 查询单个调课申请的完整详情。 *

@@ -206,101 +213,23 @@ public interface CourseRunningImportService { /** * 教研室审批调课申请。 *

- * 教研室审批教员提交的调课申请,包含同意、发回、拒绝三种处理方式。 - * 同意时同步更新课次数据,发回时记录发回原因,拒绝时标记申请为已拒绝。 + * 教研室审批调课申请。点审批即已查收,审批人同时记为查收人。 + * 同意后写回课次;发回、拒绝也记为已查收。 *

* * @param dto 教研室审批参数 */ void auditByTeachingOffice(ScheduleAdjustAuditDTO dto); - /** - * 教研室查收调课申请。 - *

- * 教研室查收调课申请,标记查收状态和查收时间。 - *

- * - * @param ssdksqbh 调课申请编号 - * @param csrbh 查收人编号 - */ - void receiveByTeachingOffice(String ssdksqbh, String csrbh); - - /** - * 教学系审批调课申请。 - *

- * 教学系审批教研室已同意的调课申请,包含同意、发回、拒绝三种处理方式。 - * 教学系同意后流转到机关审批。 - *

- * - * @param dto 教学系审批参数 - */ - void auditByTeachingDepartment(ScheduleAdjustAuditDTO dto); - - /** - * 机关审批调课申请。 - *

- * 机关审批教研室已同意的调课申请,包含同意、发回、拒绝三种处理方式。 - * 机关全部同意后调课申请最终生效,课次按调整后的内容执行。 - *

- * - * @param dto 机关审批参数 - */ - void auditByAuthority(ScheduleAdjustAuditDTO dto); - - /** - * 机关查收调课申请。 - *

- * 机关查收调课申请,标记查收状态和查收时间。 - *

- * - * @param ssdksqbh 调课申请编号 - * @param jgbh 机关编号 - * @param csrbh 查收人编号 - */ - void receiveByAuthority(String ssdksqbh, String jgbh, String csrbh); - /** * 撤销调课申请。 *

- * 教员撤销自己提交的、未经过审批的调课申请。 - * 软删除调课申请,标记删除状态为1。 + * 教员撤销未经过审批的调课申请。列表已按登录教员过滤。 *

* * @param ssdksqbh 调课申请编号 - * @param sqjybh 申请教员编号(用于权限校验) */ - void cancelScheduleAdjust(String ssdksqbh, String sqjybh); - - // ==================== 调课策略管理 ==================== - - /** - * 查询调课策略列表。 - *

- * 支持按策略类型筛选,返回所有策略(含停用)。 - *

- * - * @param cllx 策略类型:TIME_LIMIT/AUTO_APPROVE,为空时查询全部 - * @return 调课策略列表 - */ - List listScheduleAdjustStrategies(String cllx); - - /** - * 保存调课策略(新增或修改)。 - *

- * 策略编号为空时执行新增,非空时执行修改。 - *

- * - * @param dto 策略参数 - * @return 策略编号 - */ - String saveScheduleAdjustStrategy(ScheduleAdjustStrategyDTO dto); - - /** - * 删除调课策略。 - * - * @param clbh 策略编号 - */ - void deleteScheduleAdjustStrategy(String clbh); + void cancelScheduleAdjust(String ssdksqbh); // ==================== 教学保障管理 ==================== diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/ElectiveCourseService.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/ElectiveCourseService.java new file mode 100644 index 000000000..3640c9533 --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/ElectiveCourseService.java @@ -0,0 +1,40 @@ +package com.roomroot.jwgl.service; + +import com.roomroot.jwgl.dto.jys.ElectiveCourseQuery; +import com.roomroot.jwgl.dto.jys.ElectiveCourseSaveDTO; +import com.roomroot.jwgl.unit.PageQuery; +import com.roomroot.jwgl.unit.PageResult; +import com.roomroot.jwgl.vo.jys.ElectiveCourseVO; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +/** + * 选修课管理。 + *

数据来源:学员队任务表 INNER JOIN 学员队表 INNER JOIN 课表,课类型含“选修”。

+ */ +public interface ElectiveCourseService { + + PageResult pageList(PageQuery query, ElectiveCourseQuery cond); + + void add(ElectiveCourseSaveDTO dto); + + int batchOpenRegistration(List bhList); + + int batchCancelOpenRegistration(List bhList); + + int batchStopRegistration(List bhList); + + int batchReverseClassRange(List bhList); + + void exportClassList(ElectiveCourseQuery cond, HttpServletResponse response); + + void exportStudentExcel(List bhList, HttpServletResponse response); + + void exportStudentWord(List bhList, HttpServletResponse response); + + void downloadTemplate(HttpServletResponse response); + + int importData(MultipartFile file) throws Exception; +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/FacultyService.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/FacultyService.java index f203db276..f7c50b4ca 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/FacultyService.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/FacultyService.java @@ -76,6 +76,16 @@ public interface FacultyService { */ JYB getJYBById(String jYBH); + /** + * 从 Excel(.xls/.xlsx) 导入教员 + */ + int importJYBFromExcel(MultipartFile file) throws Exception; + + /** + * 导出教员到 Excel(.xlsx) + */ + void exportJYBExcel(jakarta.servlet.http.HttpServletResponse response) throws Exception; + /** * 分页条件查询教员列表 */ diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/KCBService.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/KCBService.java index 6571f31c1..d1c116e45 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/KCBService.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/KCBService.java @@ -1,6 +1,12 @@ package com.roomroot.jwgl.service; +import com.roomroot.jwgl.dto.kcb.TimetableQuery; import com.roomroot.jwgl.entity.KCB; +import com.roomroot.jwgl.unit.PageQuery; +import com.roomroot.jwgl.unit.PageResult; +import com.roomroot.jwgl.vo.kcb.ClassTimetableVO; +import com.roomroot.jwgl.vo.kcb.DailyWeeklyTimetableVO; +import jakarta.servlet.http.HttpServletResponse; import java.util.List; @@ -51,4 +57,34 @@ public interface KCBService { * @return 所有数据列表 */ List list(); + + /** + * 今日课表。未传年度时按当前时间取本学期。 + */ + List listToday(TimetableQuery cond); + + /** + * 本周课表(周一至周日)。未传年度时按当前时间取本学期。 + */ + List listWeek(TimetableQuery cond); + + /** + * 班次课表。未传年度时按当前时间取本学期,可按队别班次筛选。 + */ + PageResult pageClassTimetable(PageQuery query, TimetableQuery cond); + + /** + * 下载学期教学实施计划(课次明细 Excel)。 + */ + void exportSemesterPlan(TimetableQuery cond, HttpServletResponse response); + + /** + * 下载学期成绩表 Excel。 + */ + void exportSemesterGrades(TimetableQuery cond, HttpServletResponse response); + + /** + * 班次课程列表另存 Excel。 + */ + void exportClassCourses(TimetableQuery cond, HttpServletResponse response); } diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/TeachingTaskManageService.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/TeachingTaskManageService.java new file mode 100644 index 000000000..f5ac03780 --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/TeachingTaskManageService.java @@ -0,0 +1,39 @@ +package com.roomroot.jwgl.service; + +import com.roomroot.jwgl.dto.jys.TeachingTaskQuery; +import com.roomroot.jwgl.dto.jys.TeachingTaskSaveDTO; +import com.roomroot.jwgl.unit.PageQuery; +import com.roomroot.jwgl.unit.PageResult; +import com.roomroot.jwgl.vo.jys.TeachingOfficeBookCourseVO; +import com.roomroot.jwgl.vo.jys.TeachingOfficeBookVO; +import com.roomroot.jwgl.vo.jys.TeachingTaskDetailVO; +import com.roomroot.jwgl.vo.jys.TeachingTaskSquadVO; +import com.roomroot.jwgl.vo.jys.TeachingTaskVO; + +import java.util.List; + +/** + * 教学任务管理(机关发布,关联教研室任务书与学员队,供排课使用)。 + */ +public interface TeachingTaskManageService { + + PageResult pageList(PageQuery query, TeachingTaskQuery cond); + + TeachingTaskDetailVO getDetail(String bh); + + void add(TeachingTaskSaveDTO dto); + + void update(TeachingTaskSaveDTO dto); + + void delete(String bh); + + int publish(String bh); + + List listOfficeBooks(String jxrwbh); + + List listOfficeBookCourses(String jxrwbh, String jysdh); + + List listBoundSquads(String jxrwbh); + + List listAvailableSquads(Integer nd, Integer xqdc, String jxrwbh); +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/TrainingProgramService.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/TrainingProgramService.java index 6ab673595..31dccfa1a 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/TrainingProgramService.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/TrainingProgramService.java @@ -53,4 +53,10 @@ public interface TrainingProgramService { * @return 分页结果 */ PageResult pageList(PageQuery query, ZYB cond); + + /** 从 Excel(.xls/.xlsx) 导入培养方案(专业) */ + int importZYBFromExcel(org.springframework.web.multipart.MultipartFile file) throws Exception; + + /** 导出培养方案(专业)到 Excel(.xlsx) */ + void exportZYBExcel(jakarta.servlet.http.HttpServletResponse response) throws Exception; } diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/ZYJXJHBService.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/ZYJXJHBService.java index 6fe74b485..1813b9bb2 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/ZYJXJHBService.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/ZYJXJHBService.java @@ -60,4 +60,10 @@ public interface ZYJXJHBService { * @return 列表 */ List listByZydhAndTy(String zydh, Integer ty); + + /** 从 Excel(.xls/.xlsx) 导入专业教学计划 */ + int importZYJXJHBFromExcel(org.springframework.web.multipart.MultipartFile file) throws Exception; + + /** 导出专业教学计划到 Excel(.xlsx) */ + void exportZYJXJHBExcel(jakarta.servlet.http.HttpServletResponse response) throws Exception; } diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/CourseRunningImportServiceImpl.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/CourseRunningImportServiceImpl.java index 9a068ca30..7a08bd9e7 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/CourseRunningImportServiceImpl.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/CourseRunningImportServiceImpl.java @@ -2,17 +2,18 @@ package com.roomroot.jwgl.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.roomroot.common.utils.SecurityUtils; +import com.roomroot.common.utils.StringUtils; import com.roomroot.jwgl.dto.courserunning.*; import com.roomroot.jwgl.entity.*; import com.roomroot.jwgl.mapper.*; -import com.roomroot.jwgl.vo.courserunning.*; -import com.roomroot.jwgl.mapper.*; import com.roomroot.jwgl.service.CourseRunningImportService; import com.roomroot.jwgl.service.DictDataService; import com.roomroot.jwgl.unit.BusinessException; import com.roomroot.jwgl.unit.PageResult; import com.roomroot.jwgl.utils.BasicManagementConstants; import com.roomroot.jwgl.utils.ExcelExportUtil; +import com.roomroot.jwgl.utils.JwglRoleHelper; import com.roomroot.jwgl.utils.UuidUtil; import com.roomroot.jwgl.validator.StudentLeaveValidator; import com.roomroot.jwgl.vo.courserunning.*; @@ -102,11 +103,14 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic @Resource private SSDKSQMapper ssdksqMapper; - /** - * 实施_调课申请审批 Mapper,用于调课申请审批记录的数据访问。 - */ @Resource - private SSDKSQSPMapper ssdksqspMapper; + private JwglRoleHelper jwglRoleHelper; + + @Resource + private StudentTeamTaskMapper studentTeamTaskMapper; + + @Resource + private KCBMapper kcbMapper; /** * 调课申请_教室 Mapper,用于调课申请中教室关联的数据访问。 @@ -186,12 +190,6 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic @Resource private OperationAnalysisMapper operationAnalysisMapper; - /** - * 调课策略 Mapper,用于调课时间段限制策略与免审批策略的数据访问。 - */ - @Resource - private ScheduleAdjustStrategyMapper scheduleAdjustStrategyMapper; - /** * 教员表数据访问接口,用于审批时根据教员编号查询教研室代号。 */ @@ -523,16 +521,17 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic * @param operationContent 操作内容描述 */ private void recordOperationLog(String targetId, String operationType, String operationContent) { - // 创建日志实体 - KCJXYX_CZRZ log = new KCJXYX_CZRZ(); - log.setBh(UuidUtil.getOriginalUUID()); // 生成唯一编号 - log.setTybh(targetId); // 目标编号 - log.setCzlx(operationType); // 操作类型 - log.setCznr(operationContent); // 操作内容 - log.setCzsj(LocalDateTime.now()); // 操作时间 - - // 写入数据库 - kcjxyxCzrzMapper.insert(log); + try { + KCJXYX_CZRZ log = new KCJXYX_CZRZ(); + log.setBh(UuidUtil.getOriginalUUID()); + log.setTybh(targetId); + log.setCzlx(operationType); + log.setCznr(operationContent); + log.setCzsj(LocalDateTime.now()); + kcjxyxCzrzMapper.insert(log); + } catch (Exception ignored) { + // 操作日志表缺失或字段不匹配时,不影响调课主流程 + } } // ==================== 教学实施计划填写 ==================== @@ -863,26 +862,25 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic */ @Override public PageResult queryScheduleAdjustList(ScheduleAdjustQueryDTO query) { - // 步骤1:校验查询参数,确保分页参数有效 if (query == null) { throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "查询参数不能为空"); } if (query.getPageNum() == null || query.getPageSize() == null) { throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "分页参数不能为空"); } + applyScheduleAdjustDataScope(query); - // 步骤2:构建MyBatis-Plus分页对象 Page page = new Page<>(query.getPageNum(), query.getPageSize()); - - // 步骤3:将日期范围转换为字符串格式,便于XML中直接拼接SQL String cjsjStartStr = query.getCjsjStart() != null ? query.getCjsjStart().format(DATE_TIME_FORMATTER) : null; String cjsjEndStr = query.getCjsjEnd() != null ? query.getCjsjEnd().format(DATE_TIME_FORMATTER) : null; - // 步骤4:调用Mapper执行分页查询,关联课程表和教员表 Page resultPage = ssdksqMapper.selectPageList( page, query.getSskcbbh(), + query.getXydrwbh(), + query.getKbh(), query.getSqjybh(), + query.getJysdh(), query.getNd(), query.getJyspzzt(), query.getJyscszt(), @@ -890,8 +888,6 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic cjsjStartStr, cjsjEndStr ); - - // 步骤5:封装分页结果并返回 return new PageResult<>( resultPage.getRecords(), resultPage.getTotal(), @@ -900,6 +896,34 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic ); } + @Override + public List listAdjustableLessons(Integer nd) { + return ssdksqMapper.selectAdjustableLessons(jwglRoleHelper.requireTeacherId(), nd); + } + + private void applyScheduleAdjustDataScope(ScheduleAdjustQueryDTO query) { + if (jwglRoleHelper.isTeacher()) { + query.setSqjybh(jwglRoleHelper.requireTeacherId()); + query.setJysdh(null); + } + } + + private String currentOperatorId() { + try { + String teacherId = jwglRoleHelper.findTeacherId(); + if (StringUtils.isNotEmpty(teacherId)) { + return teacherId.trim(); + } + String username = SecurityUtils.getUsername(); + if (StringUtils.isNotEmpty(username)) { + return username; + } + } catch (Exception ignored) { + // 未登录时由调用方继续校验 + } + return null; + } + /** * 查询单个调课申请的完整详情。 *

@@ -912,33 +936,17 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic */ @Override public ScheduleAdjustDetailVO getScheduleAdjustDetail(String ssdksqbh) { - // 步骤1:校验调课申请编号参数 if (ssdksqbh == null || ssdksqbh.trim().isEmpty()) { throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "调课申请编号不能为空"); } - - // 步骤2:查询调课申请主表信息 ScheduleAdjustDetailVO detail = ssdksqMapper.selectDetailById(ssdksqbh); if (detail == null) { throw new BusinessException(BasicManagementConstants.NOT_FOUND, "未找到该调课申请"); } - - // 步骤3:查询关联的机关审批记录列表 - detail.setAuditList(ssdksqspMapper.selectBySsdksqbh(ssdksqbh)); - - // 步骤4:查询关联的新教室列表 detail.setRoomList(dksqjsMapper.selectByDksqbh(ssdksqbh)); - - // 步骤5:查询关联的新辅助教员列表 detail.setTeacherList(dksqfzjyMapper.selectByDksqbh(ssdksqbh)); - - // 步骤6:查询关联的新学员队列表 detail.setTeamList(dksqxydMapper.selectByDksqbh(ssdksqbh)); - - // 步骤7:查询关联的新保障明细列表 detail.setSupportList(dksqbzmxMapper.selectByDksqbh(ssdksqbh)); - - // 步骤8:返回调课申请完整详情 return detail; } @@ -957,147 +965,209 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic @Override @Transactional(rollbackFor = Exception.class) public String submitScheduleAdjust(ScheduleAdjustApplyDTO dto) { - // 步骤1:校验调课申请参数 - if (dto == null) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "调课申请参数不能为空"); - } - if (dto.getSskcbbh() == null || dto.getSskcbbh().trim().isEmpty()) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "课次编号不能为空"); - } - if (dto.getSqjybh() == null || dto.getSqjybh().trim().isEmpty()) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "申请教员编号不能为空"); - } - if (dto.getSy() == null || dto.getSy().trim().isEmpty()) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "调课事由不能为空"); - } - - // 步骤2:查询课次实体,校验课次是否存在 - SSKCB lesson = sskcbMapper.selectById(dto.getSskcbbh()); - if (lesson == null) { + String teacherId = jwglRoleHelper.requireTeacherId(); + SSKCB lesson = sskcbMapper.selectById(dto.getSskcbbh().trim()); + if (lesson == null || (lesson.getSczt() != null && lesson.getSczt() == 1)) { throw new BusinessException(BasicManagementConstants.NOT_FOUND, "课次不存在"); } - if (lesson.getSczt() != null && lesson.getSczt() == 1) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "该课次已删除,不允许申请调课"); + + AdjustableLessonVO picked = null; + List mine = ssdksqMapper.selectAdjustableLessons(teacherId, lesson.getNd()); + if (mine != null) { + for (AdjustableLessonVO item : mine) { + if (lesson.getBh().equals(item.getSskcbbh())) { + picked = item; + break; + } + } + } + if (picked == null) { + throw new BusinessException(BasicManagementConstants.NOT_FOUND, "课次不存在"); } - // 调课时间段策略校验 - validateScheduleAdjustTimeLimitStrategy(dto.getRq()); - - // 判断是否命中免审批策略 - boolean autoApproved = matchAutoApproveStrategy(); - - // 步骤3:构建并保存调课申请主表实体 SSDKSQ apply = new SSDKSQ(); - String ssdksqbh = UuidUtil.getOriginalUUID(); // 生成唯一调课申请编号 + String ssdksqbh = UuidUtil.getOriginalUUID(); apply.setBh(ssdksqbh); - apply.setSskcbbh(dto.getSskcbbh()); // 课次编号 - apply.setSqjybh(dto.getSqjybh()); // 申请教员编号 - apply.setSy(dto.getSy()); // 调课事由 - apply.setRq(dto.getRq()); // 新日期 - apply.setJc(dto.getJc()); // 新节次 - apply.setNd(dto.getNd()); // 年度 - apply.setJxnr(dto.getJxnr()); // 教学内容 - apply.setJxyd(dto.getJxyd()); // 教学要点 - apply.setJxff(dto.getJxff()); // 教学方法 - apply.setJxbzbz(dto.getJxbzbz()); // 教学保障备注 - apply.setYcxx(dto.getYcxx()); // 用车信息 - apply.setBz(dto.getBz()); // 备注 - // 将原日期节次描述追加到备注中(ydsjap字段类型为Integer,用于存储其他业务数据) - String originalDesc = buildOriginalScheduleDesc(lesson); - if (dto.getBz() != null && !dto.getBz().trim().isEmpty()) { - apply.setBz(dto.getBz() + " | " + originalDesc); - } else { - apply.setBz(originalDesc); - } - // 命中免审批策略时在备注追加标记,便于教务人员识别 - if (autoApproved) { - apply.setBz((apply.getBz() == null ? "" : apply.getBz() + " | ") + "[免审批策略自动通过]"); - } - // 审批状态初始化:未审批、未查收、未删除 - if (autoApproved) { - // 命中免审批策略:教研室和教学系审批状态直接设为已通过,跳过三级审批 - apply.setJyspzzt(1); - apply.setJxxspzzt(1); - } else { - apply.setJyspzzt(0); - } + apply.setSskcbbh(lesson.getBh()); + apply.setYdsjap(resolveYdsjap(lesson)); + apply.setZxzt(0); + apply.setYszt(0); + apply.setXydrwbh(cut(StringUtils.isNotEmpty(dto.getXydrwbh()) ? dto.getXydrwbh() : picked.getXydrwbh(), 50)); + apply.setKbh(cut(StringUtils.isNotEmpty(dto.getKbh()) ? dto.getKbh() : picked.getKbh(), 50)); + apply.setKcbbh(cut(StringUtils.isNotEmpty(dto.getKcbbh()) ? dto.getKcbbh() : picked.getKcbbh(), 50)); + apply.setJysdh(cut(picked.getJysdh(), 50)); + apply.setYjsbh(cut(picked.getJsbh(), 50)); + apply.setXjsbh(cut(resolveNewClassroom(dto), 50)); + apply.setSqjybh(cut(teacherId, 50)); + apply.setSy(cut(dto.getSy(), 200)); + apply.setRq(dto.getRq()); + apply.setJc(dto.getJc() != null ? dto.getJc() : 0); + apply.setNd(dto.getNd() != null ? dto.getNd() : (lesson.getNd() != null ? lesson.getNd() : 0)); + apply.setJxnr(cut(dto.getJxnr(), 500)); + apply.setJxyd(dto.getJxyd()); + String jxff = cut(dto.getJxff(), 50); + apply.setJxff(jxff == null ? "" : jxff); + apply.setJxbzbz(dto.getJxbzbz()); + apply.setYcxx(dto.getYcxx()); + apply.setBz(cut(dto.getBz(), 50)); + apply.setJyspzzt(0); apply.setJyscszt(0); apply.setSczt(0); - // 时间字段 - LocalDateTime now = LocalDateTime.now(); - apply.setCreateTime(now); - apply.setUpdateTime(now); - - // 步骤4:插入调课申请主表数据 + apply.setFhzt(0); + apply.setDk(1); + apply.setCjsj(LocalDateTime.now()); ssdksqMapper.insert(apply); - // 步骤5:保存新教室关联数据 if (dto.getRoomList() != null && !dto.getRoomList().isEmpty()) { for (AdjustRoomDTO roomDto : dto.getRoomList()) { + if (StringUtils.isEmpty(roomDto.getJsbh())) { + continue; + } DKSQJS roomEntity = new DKSQJS(); roomEntity.setBh(UuidUtil.getOriginalUUID()); roomEntity.setDksqbh(ssdksqbh); roomEntity.setJsbh(roomDto.getJsbh()); roomEntity.setBz(roomDto.getBz()); + roomEntity.setNd(apply.getNd()); + roomEntity.setRq(apply.getRq()); + roomEntity.setJc(apply.getJc()); dksqjsMapper.insert(roomEntity); } + } else if (StringUtils.isNotEmpty(apply.getXjsbh())) { + DKSQJS roomEntity = new DKSQJS(); + roomEntity.setBh(UuidUtil.getOriginalUUID()); + roomEntity.setDksqbh(ssdksqbh); + roomEntity.setJsbh(apply.getXjsbh()); + roomEntity.setNd(apply.getNd()); + roomEntity.setRq(apply.getRq()); + roomEntity.setJc(apply.getJc()); + dksqjsMapper.insert(roomEntity); } - - // 步骤6:保存新辅助教员关联数据 if (dto.getTeacherList() != null && !dto.getTeacherList().isEmpty()) { for (AdjustTeacherDTO teacherDto : dto.getTeacherList()) { + if (StringUtils.isEmpty(teacherDto.getFzjybh())) { + continue; + } DKSQFZJY teacherEntity = new DKSQFZJY(); teacherEntity.setBh(UuidUtil.getOriginalUUID()); teacherEntity.setDksqbh(ssdksqbh); teacherEntity.setFzjybh(teacherDto.getFzjybh()); - teacherEntity.setZjy(teacherDto.getZjy()); + teacherEntity.setZjy(teacherDto.getZjy() == null ? 0 : teacherDto.getZjy()); teacherEntity.setBz(teacherDto.getBz()); + teacherEntity.setNd(apply.getNd()); + teacherEntity.setRq(apply.getRq()); + teacherEntity.setJc(apply.getJc()); dksqfzjyMapper.insert(teacherEntity); } } - - // 步骤7:保存新学员队关联数据 if (dto.getTeamList() != null && !dto.getTeamList().isEmpty()) { for (AdjustTeamDTO teamDto : dto.getTeamList()) { + if (StringUtils.isEmpty(teamDto.getXydbh())) { + continue; + } DKSQXYD teamEntity = new DKSQXYD(); teamEntity.setBh(UuidUtil.getOriginalUUID()); teamEntity.setDksqbh(ssdksqbh); teamEntity.setXydbh(teamDto.getXydbh()); + teamEntity.setNd(apply.getNd()); + teamEntity.setRq(apply.getRq()); + teamEntity.setJc(apply.getJc()); dksqxydMapper.insert(teamEntity); } } - - // 步骤8:保存新保障明细关联数据 if (dto.getSupportList() != null && !dto.getSupportList().isEmpty()) { for (AdjustSupportDTO supportDto : dto.getSupportList()) { + if (StringUtils.isEmpty(supportDto.getBztgmxbh()) || supportDto.getSl() == null) { + continue; + } DKSQBZMX supportEntity = new DKSQBZMX(); supportEntity.setBh(UuidUtil.getOriginalUUID()); supportEntity.setSqbh(ssdksqbh); supportEntity.setBztgmxbh(supportDto.getBztgmxbh()); supportEntity.setSl(supportDto.getSl()); supportEntity.setBz(supportDto.getBz()); + supportEntity.setNd(apply.getNd()); + supportEntity.setRq(apply.getRq()); + supportEntity.setJc(apply.getJc()); dksqbzmxMapper.insert(supportEntity); } } - // 步骤9:更新课次数据,将日期节次替换为调整后的新值 - lesson.setRq(dto.getRq()); - lesson.setJc(dto.getJc()); - lesson.setBdsj(now); - sskcbMapper.updateById(lesson); - - // 步骤10:记录调课申请操作日志 recordOperationLog(ssdksqbh, "申请", "提交调课申请:" + ssdksqbh); - - // 步骤11:返回调课申请编号 return ssdksqbh; } + private XYDRWB findRelatedTeamTask(SSKC course, SSKCB lesson) { + if (course == null || StringUtils.isEmpty(course.getKmbh()) || lesson == null) { + return null; + } + List teams = sskcbxyMapper.selectBySskcbh(lesson.getBh()); + String teamId = (teams == null || teams.isEmpty()) ? null : teams.get(0).getXydbh(); + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() + .eq(XYDRWB::getKbh, course.getKmbh()) + .eq(XYDRWB::getJybh, course.getJybh()) + .eq(lesson.getNd() != null, XYDRWB::getNd, lesson.getNd()); + if (StringUtils.isNotEmpty(teamId)) { + wrapper.eq(XYDRWB::getXydbh, teamId); + } + wrapper.last("LIMIT 1"); + return studentTeamTaskMapper.selectOne(wrapper); + } + + private KCB findRelatedScheduleSlot(SSKC course) { + if (course == null || StringUtils.isEmpty(course.getJybh()) || course.getJykcxh() == null) { + return null; + } + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() + .eq(KCB::getJybh, course.getJybh()) + .eq(KCB::getKcxh, course.getJykcxh()) + .eq(course.getNd() != null, KCB::getNd, course.getNd()) + .last("LIMIT 1"); + return kcbMapper.selectOne(wrapper); + } + + private int resolveYdsjap(SSKCB lesson) { + if (lesson == null) { + return 0; + } + if (lesson.getJhsjap() != null) { + return lesson.getJhsjap(); + } + if (lesson.getRq() != null) { + return lesson.getRq().getYear() * 10000 + + lesson.getRq().getMonthValue() * 100 + + lesson.getRq().getDayOfMonth(); + } + return 0; + } + + private String cut(String value, int max) { + if (value == null) { + return null; + } + String text = value.trim(); + if (text.isEmpty()) { + return null; + } + return text.length() <= max ? text : text.substring(0, max); + } + + private String resolveNewClassroom(ScheduleAdjustApplyDTO dto) { + if (StringUtils.isNotEmpty(dto.getXjsbh())) { + return dto.getXjsbh().trim(); + } + if (dto.getRoomList() != null && !dto.getRoomList().isEmpty() + && StringUtils.isNotEmpty(dto.getRoomList().get(0).getJsbh())) { + return dto.getRoomList().get(0).getJsbh().trim(); + } + return null; + } + /** * 教研室审批调课申请。 *

- * 教研室审批教员提交的调课申请,包含同意、发回、拒绝三种处理方式。 - * 同意时同步更新课次数据,发回时记录发回原因,拒绝时标记申请为已拒绝。 + * 教研室审批调课申请。点审批即已查收,审批人同时记为查收人。 + * 同意后写回课次;发回、拒绝也记为已查收。 *

* * @param dto 教研室审批参数 @@ -1105,19 +1175,6 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic @Override @Transactional(rollbackFor = Exception.class) public void auditByTeachingOffice(ScheduleAdjustAuditDTO dto) { - // 步骤1:校验审批参数 - if (dto == null) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "审批参数不能为空"); - } - if (!"jys".equals(dto.getAuditRole())) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "审批角色不正确,应为jys"); - } - if (dto.getSpzt() == null - || (dto.getSpzt() != 1 && dto.getSpzt() != 2 && dto.getSpzt() != 3)) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "审批结果不正确,应为1(同意)、2(发回)或3(拒绝)"); - } - - // 步骤2:查询调课申请实体,校验申请是否存在 SSDKSQ apply = ssdksqMapper.selectById(dto.getSsdksqbh()); if (apply == null) { throw new BusinessException(BasicManagementConstants.NOT_FOUND, "调课申请不存在"); @@ -1125,343 +1182,120 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic if (apply.getSczt() != null && apply.getSczt() == 1) { throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "该调课申请已撤销,不允许审批"); } - - // 步骤3:校验申请是否已审批,避免重复审批 if (apply.getJyspzzt() != null && apply.getJyspzzt() != 0) { throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "该调课申请已审批,无需重复审批"); } - // 步骤4:更新调课申请主表的教研室审批状态 LocalDateTime now = LocalDateTime.now(); - apply.setJyspzzt(dto.getSpzt()); // 教研室审批状态 - apply.setJyspzrbh(dto.getSprbh()); // 教研室审批人编号 - apply.setJyspzsj(now); // 教研室审批时间 - apply.setFhyj(dto.getFhyj()); // 发回意见 - apply.setUpdateTime(now); // 更新时间 + String auditor = StringUtils.isNotEmpty(dto.getSprbh()) ? dto.getSprbh() : currentOperatorId(); + apply.setJyspzzt(dto.getSpzt()); + apply.setJyspzrbh(auditor); + apply.setJyspzsj(now); + apply.setJyscszt(1); + apply.setJyscsrbh(auditor); + apply.setJyscssj(now); + apply.setFhyj(dto.getFhyj()); + if (dto.getSpzt() == 2) { + apply.setFhzt(1); + apply.setFhsj(now); + } ssdksqMapper.updateById(apply); - // 步骤5:根据审批结果执行不同的后续处理 - if (dto.getSpzt() == 3) { - // 拒绝:恢复课次原数据,标记申请最终结束 - restoreLessonSchedule(apply); - } else if (dto.getSpzt() == 2) { - // 发回:发回教员修改,课次保留调整后数据,由教员重新申请 - // 此处无需修改课次数据 - } else { - // 同意:课次数据已由申请时更新,无需重复处理 + if (dto.getSpzt() == 1) { + applyApprovedSchedule(apply); } - // 步骤6:记录审批操作日志 recordOperationLog(apply.getBh(), "教研室审批", "教研室审批调课申请:" + apply.getBh() + ",审批结果:" + dto.getSpzt() + ",审批意见:" + dto.getFhyj()); } - /** - * 教研室查收调课申请。 - *

- * 教研室查收调课申请,标记查收状态和查收时间。 - *

- * - * @param ssdksqbh 调课申请编号 - * @param csrbh 查收人编号 - */ - @Override - @Transactional(rollbackFor = Exception.class) - public void receiveByTeachingOffice(String ssdksqbh, String csrbh) { - // 步骤1:校验参数 - if (ssdksqbh == null || ssdksqbh.trim().isEmpty()) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "调课申请编号不能为空"); - } - if (csrbh == null || csrbh.trim().isEmpty()) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "查收人编号不能为空"); - } - - // 步骤2:查询调课申请实体 - SSDKSQ apply = ssdksqMapper.selectById(ssdksqbh); - if (apply == null) { - throw new BusinessException(BasicManagementConstants.NOT_FOUND, "调课申请不存在"); - } - - // 步骤3:校验是否已查收,避免重复查收 - if (apply.getJyscszt() != null && apply.getJyscszt() == 1) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "该调课申请已查收,无需重复查收"); - } - - // 步骤4:更新查收状态和查收时间 - apply.setJyscszt(1); // 教研室查收状态:已查收 - apply.setJyscsrbh(csrbh); // 教研室查收人编号 - apply.setJyscssj(LocalDateTime.now()); // 教研室查收时间 - apply.setUpdateTime(LocalDateTime.now()); // 更新时间 - ssdksqMapper.updateById(apply); - - // 步骤5:记录查收操作日志 - recordOperationLog(apply.getBh(), "教研室查收", "教研室查收调课申请:" + apply.getBh()); - } - - /** - * 教学系审批调课申请。 - *

- * 教学系审批教研室已同意的调课申请,包含同意、发回、拒绝三种处理方式。 - * 教学系同意后流转到机关审批,构成三级审批流程(教研室→教学系→机关)。 - *

- * - * @param dto 教学系审批参数 - */ - @Override - @Transactional(rollbackFor = Exception.class) - public void auditByTeachingDepartment(ScheduleAdjustAuditDTO dto) { - // 步骤1:校验审批参数 - if (dto == null) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "审批参数不能为空"); - } - if (!"jxx".equals(dto.getAuditRole())) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "审批角色不正确,应为jxx"); - } - if (dto.getSpzt() == null - || (dto.getSpzt() != 1 && dto.getSpzt() != 2 && dto.getSpzt() != 3)) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "审批结果不正确,应为1(同意)、2(发回)或3(拒绝)"); - } - - // 步骤2:查询调课申请实体 - SSDKSQ apply = ssdksqMapper.selectById(dto.getSsdksqbh()); - if (apply == null) { - throw new BusinessException(BasicManagementConstants.NOT_FOUND, "调课申请不存在"); - } - if (apply.getSczt() != null && apply.getSczt() == 1) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "该调课申请已撤销,不允许审批"); - } - - // 步骤3:校验教研室是否已同意,教学系审批应在教研室同意之后进行 - if (apply.getJyspzzt() == null || apply.getJyspzzt() != 1) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "教研室未同意或未审批,无法进行教学系审批"); - } - - // 步骤4:校验教学系是否已审批,避免重复审批 - if (apply.getJxxspzzt() != null && apply.getJxxspzzt() != 0) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "该调课申请教学系已审批,无需重复审批"); - } - - // 步骤5:更新调课申请主表的教学系审批状态 - LocalDateTime now = LocalDateTime.now(); - apply.setJxxspzzt(dto.getSpzt()); // 教学系审批状态 - apply.setJxxspzrbh(dto.getSprbh()); // 教学系审批人编号 - apply.setJxxspzsj(now); // 教学系审批时间 - apply.setFhyj(dto.getFhyj()); // 发回意见 - apply.setUpdateTime(now); // 更新时间 - ssdksqMapper.updateById(apply); - - // 步骤6:根据审批结果执行不同的后续处理 - if (dto.getSpzt() == 3) { - // 拒绝:恢复课次原数据,标记申请最终结束 - restoreLessonSchedule(apply); - } else if (dto.getSpzt() == 2) { - // 发回:发回教研室,课次保留调整后数据,由教研室重新处理 - } else { - // 同意:流转到机关审批 - } - - // 步骤7:记录教学系审批操作日志 - recordOperationLog(apply.getBh(), "教学系审批", "教学系审批调课申请:" + apply.getBh() - + ",审批结果:" + dto.getSpzt() + ",审批意见:" + dto.getFhyj()); - } - - /** - * 机关审批调课申请。 - *

- * 机关审批教研室已同意的调课申请,包含同意、发回、拒绝三种处理方式。 - * 机关全部同意后调课申请最终生效,课次按调整后的内容执行。 - *

- * - * @param dto 机关审批参数 - */ - @Override - @Transactional(rollbackFor = Exception.class) - public void auditByAuthority(ScheduleAdjustAuditDTO dto) { - // 步骤1:校验审批参数 - if (dto == null) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "审批参数不能为空"); - } - if (!"jg".equals(dto.getAuditRole())) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "审批角色不正确,应为jg"); - } - if (dto.getSpzt() == null - || (dto.getSpzt() != 1 && dto.getSpzt() != 2 && dto.getSpzt() != 3)) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "审批结果不正确"); - } - if (dto.getJgbh() == null || dto.getJgbh().trim().isEmpty()) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "机关编号不能为空"); - } - - // 步骤2:查询调课申请实体 - SSDKSQ apply = ssdksqMapper.selectById(dto.getSsdksqbh()); - if (apply == null) { - throw new BusinessException(BasicManagementConstants.NOT_FOUND, "调课申请不存在"); - } - if (apply.getSczt() != null && apply.getSczt() == 1) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "该调课申请已撤销,不允许审批"); - } - - // 步骤3:校验教研室是否已同意,机关审批应在教研室同意之后进行 - if (apply.getJyspzzt() == null || apply.getJyspzzt() != 1) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "教研室未同意或未审批,无法进行机关审批"); - } - - // 步骤4:校验教学系是否已同意,机关审批应在教学系同意之后进行(三级审批) - if (apply.getJxxspzzt() == null || apply.getJxxspzzt() != 1) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "教学系未同意或未审批,无法进行机关审批"); - } - - // 步骤5:构建并保存机关审批记录 - SSDKSQSP audit = new SSDKSQSP(); - audit.setBh(UuidUtil.getOriginalUUID()); - audit.setSsdksqbh(dto.getSsdksqbh()); - audit.setJgbh(dto.getJgbh()); - audit.setSprbh(dto.getSprbh()); - audit.setSpsj(LocalDateTime.now()); - audit.setSpzt(dto.getSpzt()); - audit.setFhyj(dto.getFhyj()); - audit.setNd(apply.getNd()); - audit.setCreateTime(LocalDateTime.now()); - audit.setUpdateTime(LocalDateTime.now()); - ssdksqspMapper.insert(audit); - - // 步骤5:根据审批结果执行不同的后续处理 - if (dto.getSpzt() == 3) { - // 拒绝:恢复课次原数据,标记申请最终结束 - restoreLessonSchedule(apply); - } else if (dto.getSpzt() == 2) { - // 发回:发回教研室或教员,课次保留调整后数据 - } else { - // 同意:课次数据已由申请时更新,无需重复处理 - } - - // 步骤6:记录机关审批操作日志 - recordOperationLog(apply.getBh(), "机关审批", "机关审批调课申请:" + apply.getBh() - + ",机关编号:" + dto.getJgbh() - + ",审批结果:" + dto.getSpzt() + ",审批意见:" + dto.getFhyj()); - } - - /** - * 机关查收调课申请。 - *

- * 机关查收调课申请,标记查收状态和查收时间。 - *

- * - * @param ssdksqbh 调课申请编号 - * @param jgbh 机关编号 - * @param csrbh 查收人编号 - */ - @Override - @Transactional(rollbackFor = Exception.class) - public void receiveByAuthority(String ssdksqbh, String jgbh, String csrbh) { - // 步骤1:校验参数 - if (ssdksqbh == null || ssdksqbh.trim().isEmpty()) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "调课申请编号不能为空"); - } - if (jgbh == null || jgbh.trim().isEmpty()) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "机关编号不能为空"); - } - if (csrbh == null || csrbh.trim().isEmpty()) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "查收人编号不能为空"); - } - - // 步骤2:查询调课申请实体 - SSDKSQ apply = ssdksqMapper.selectById(ssdksqbh); - if (apply == null) { - throw new BusinessException(BasicManagementConstants.NOT_FOUND, "调课申请不存在"); - } - - // 步骤3:检查当前机关是否已查收 - LambdaQueryWrapper checkWrapper = new LambdaQueryWrapper<>(); - checkWrapper.eq(SSDKSQSP::getSsdksqbh, ssdksqbh); - checkWrapper.eq(SSDKSQSP::getJgbh, jgbh); - checkWrapper.eq(SSDKSQSP::getCszt, 1); - if (ssdksqspMapper.selectCount(checkWrapper) > 0) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "当前机关已查收该调课申请,无需重复查收"); - } - - // 步骤4:构建并保存机关查收记录 - SSDKSQSP receive = new SSDKSQSP(); - receive.setBh(UuidUtil.getOriginalUUID()); - receive.setSsdksqbh(ssdksqbh); - receive.setJgbh(jgbh); - receive.setCsrbh(csrbh); - receive.setCszt(1); - receive.setCssj(LocalDateTime.now()); - receive.setNd(apply.getNd()); - receive.setCreateTime(LocalDateTime.now()); - receive.setUpdateTime(LocalDateTime.now()); - ssdksqspMapper.insert(receive); - - // 步骤5:记录查收操作日志 - recordOperationLog(apply.getBh(), "机关查收", "机关查收调课申请:" + apply.getBh() - + ",机关编号:" + jgbh); - } /** * 撤销调课申请。 *

- * 教员撤销自己提交的、未经过审批的调课申请。 - * 软删除调课申请,标记删除状态为1。 - * 事务保证主表软删除与课次原数据恢复的一致性。 + * 教员撤销未经过审批的调课申请。列表已按登录教员过滤。 *

* * @param ssdksqbh 调课申请编号 - * @param sqjybh 申请教员编号(用于权限校验) */ @Override @Transactional(rollbackFor = Exception.class) - public void cancelScheduleAdjust(String ssdksqbh, String sqjybh) { - // 步骤1:校验参数 - if (ssdksqbh == null || ssdksqbh.trim().isEmpty()) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "调课申请编号不能为空"); - } - if (sqjybh == null || sqjybh.trim().isEmpty()) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "申请教员编号不能为空"); - } - - // 步骤2:查询调课申请实体 + public void cancelScheduleAdjust(String ssdksqbh) { SSDKSQ apply = ssdksqMapper.selectById(ssdksqbh); if (apply == null) { throw new BusinessException(BasicManagementConstants.NOT_FOUND, "调课申请不存在"); } - - // 步骤3:校验是否已删除,避免重复撤销 if (apply.getSczt() != null && apply.getSczt() == 1) { throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "该调课申请已撤销,无需重复撤销"); } - - // 步骤4:校验权限,仅申请教员本人可撤销 - if (!sqjybh.equals(apply.getSqjybh())) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "仅申请教员本人可撤销该调课申请"); + if (apply.getJyspzzt() != null && apply.getJyspzzt() != 0) { + throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "该调课申请已审批,不允许撤销"); } - - // 步骤5:校验审批状态,已审批通过的申请不允许撤销 - if (apply.getJyspzzt() != null && apply.getJyspzzt() == 1) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "该调课申请教研室已同意,不允许撤销"); - } - - // 步骤6:软删除调课申请主表 - apply.setSczt(1); // 删除状态:已删除 - apply.setUpdateTime(LocalDateTime.now()); // 更新时间 + apply.setSczt(1); + apply.setJyscszt(0); + apply.setJyscsrbh(null); + apply.setJyscssj(null); ssdksqMapper.updateById(apply); - - // 步骤7:恢复课次原数据 - restoreLessonSchedule(apply); - - // 步骤8:记录撤销操作日志 recordOperationLog(apply.getBh(), "撤销", "撤销调课申请:" + apply.getBh()); } /** - * 构建原日期节次描述。 - *

- * 根据课次实体生成原日期节次的字符串描述,便于调课申请中保留原信息。 - *

- * - * @param lesson 课次实体 - * @return 原日期节次描述 + * 教研室同意后,将调整结果写回课次、学员队任务表和课程表。 */ + private void applyApprovedSchedule(SSDKSQ apply) { + if (apply == null || StringUtils.isEmpty(apply.getSskcbbh())) { + return; + } + SSKCB lesson = sskcbMapper.selectById(apply.getSskcbbh()); + if (lesson != null) { + lesson.setRq(apply.getRq()); + lesson.setJc(apply.getJc()); + lesson.setBdsj(LocalDateTime.now()); + if (StringUtils.isNotEmpty(apply.getJxnr())) { + lesson.setJxnr(apply.getJxnr()); + } + if (StringUtils.isNotEmpty(apply.getJxyd())) { + lesson.setJxyd(apply.getJxyd()); + } + if (StringUtils.isNotEmpty(apply.getJxff())) { + lesson.setJxff(apply.getJxff()); + } + sskcbMapper.updateById(lesson); + } + + String newRoom = apply.getXjsbh(); + if (StringUtils.isEmpty(newRoom)) { + List applyRooms = dksqjsMapper.selectByDksqbh(apply.getBh()); + if (applyRooms != null && !applyRooms.isEmpty()) { + newRoom = applyRooms.get(0).getJsbh(); + } + } + + XYDRWB task = StringUtils.isNotEmpty(apply.getXydrwbh()) + ? studentTeamTaskMapper.selectById(apply.getXydrwbh()) + : findRelatedTeamTask(null, lesson); + if (task != null && StringUtils.isNotEmpty(newRoom)) { + task.setJsbh(newRoom); + studentTeamTaskMapper.updateById(task); + } + + KCB slot = StringUtils.isNotEmpty(apply.getKcbbh()) + ? kcbMapper.selectById(apply.getKcbbh()) + : null; + if (slot != null) { + if (StringUtils.isNotEmpty(newRoom)) { + slot.setJsbh(newRoom); + } + if (apply.getRq() != null) { + int packed = apply.getRq().getYear() * 10000 + + apply.getRq().getMonthValue() * 100 + + apply.getRq().getDayOfMonth(); + slot.setApsj(packed); + } + kcbMapper.updateById(slot); + } + } + private String buildOriginalScheduleDesc(SSKCB lesson) { if (lesson == null) { return ""; @@ -1477,28 +1311,6 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic return sb.toString(); } - /** - * 恢复课次原数据。 - *

- * 当调课申请被拒绝或撤销时,恢复课次到申请前的原始数据。 - * 实际业务中通常需要从历史快照恢复,此处简化为清空日期节次。 - *

- * - * @param apply 调课申请实体 - */ - private void restoreLessonSchedule(SSDKSQ apply) { - // 步骤1:查询课次实体 - SSKCB lesson = sskcbMapper.selectById(apply.getSskcbbh()); - if (lesson == null) { - return; - } - - // 步骤2:清空课次因调课而设置的日期节次(恢复原状) - lesson.setRq(null); - lesson.setJc(null); - sskcbMapper.updateById(lesson); - } - // ==================== 教学保障管理 ==================== /** @@ -2806,192 +2618,6 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic return value == null ? "" : String.valueOf(value); } - // ============================================================ - // 调课策略管理实现(时间段限制策略 + 免审批策略) - // ============================================================ - - /** 策略类型常量:时间段限制 */ - private static final String STRATEGY_TIME_LIMIT = "TIME_LIMIT"; - /** 策略类型常量:免审批 */ - private static final String STRATEGY_AUTO_APPROVE = "AUTO_APPROVE"; - /** 星期中文描述 */ - private static final String[] WEEK_DAY_NAMES = {"周日", "周一", "周二", "周三", "周四", "周五", "周六"}; - - @Override - public List listScheduleAdjustStrategies(String cllx) { - LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - if (cllx != null && !cllx.trim().isEmpty()) { - wrapper.eq(ScheduleAdjustStrategy::getCllx, cllx); - } - wrapper.orderByDesc(ScheduleAdjustStrategy::getGxsj); - List list = scheduleAdjustStrategyMapper.selectList(wrapper); - - List result = new ArrayList<>(); - if (list == null) { - return result; - } - for (ScheduleAdjustStrategy strategy : list) { - result.add(buildStrategyVO(strategy)); - } - return result; - } - - @Override - @Transactional(rollbackFor = Exception.class) - public String saveScheduleAdjustStrategy(ScheduleAdjustStrategyDTO dto) { - if (!STRATEGY_TIME_LIMIT.equals(dto.getCllx()) && !STRATEGY_AUTO_APPROVE.equals(dto.getCllx())) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, - "策略类型不正确,应为 TIME_LIMIT 或 AUTO_APPROVE"); - } - if (STRATEGY_TIME_LIMIT.equals(dto.getCllx())) { - if (dto.getJzxq() != null && (dto.getJzxq() < 0 || dto.getJzxq() > 6)) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, - "截止星期取值范围为0-6(0=周日,6=周六)"); - } - } - if (dto.getSxkssj() != null && dto.getSxjssj() != null - && dto.getSxkssj().isAfter(dto.getSxjssj())) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, - "生效开始时间不能晚于生效结束时间"); - } - - LocalDateTime now = LocalDateTime.now(); - - if (dto.getClbh() == null || dto.getClbh().trim().isEmpty()) { - ScheduleAdjustStrategy strategy = new ScheduleAdjustStrategy(); - strategy.setClbh(UuidUtil.getOriginalUUID()); - strategy.setClmc(dto.getClmc()); - strategy.setCllx(dto.getCllx()); - strategy.setSfqy(dto.getSfqy() == null ? 1 : dto.getSfqy()); - strategy.setJzxq(dto.getJzxq()); - strategy.setJzjc(dto.getJzjc()); - strategy.setSxkssj(dto.getSxkssj()); - strategy.setSxjssj(dto.getSxjssj()); - strategy.setBz(dto.getBz()); - strategy.setCjsj(now); - strategy.setGxsj(now); - scheduleAdjustStrategyMapper.insert(strategy); - return strategy.getClbh(); - } else { - ScheduleAdjustStrategy existing = scheduleAdjustStrategyMapper.selectById(dto.getClbh()); - if (existing == null) { - throw new BusinessException(BasicManagementConstants.NOT_FOUND, "调课策略不存在"); - } - existing.setClmc(dto.getClmc()); - existing.setCllx(dto.getCllx()); - existing.setSfqy(dto.getSfqy() == null ? 1 : dto.getSfqy()); - existing.setJzxq(dto.getJzxq()); - existing.setJzjc(dto.getJzjc()); - existing.setSxkssj(dto.getSxkssj()); - existing.setSxjssj(dto.getSxjssj()); - existing.setBz(dto.getBz()); - existing.setGxsj(now); - scheduleAdjustStrategyMapper.updateById(existing); - return existing.getClbh(); - } - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void deleteScheduleAdjustStrategy(String clbh) { - if (clbh == null || clbh.trim().isEmpty()) { - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "策略编号不能为空"); - } - ScheduleAdjustStrategy existing = scheduleAdjustStrategyMapper.selectById(clbh); - if (existing == null) { - throw new BusinessException(BasicManagementConstants.NOT_FOUND, "调课策略不存在"); - } - scheduleAdjustStrategyMapper.deleteById(clbh); - } - - /** 调课时间段策略校验:超过截止星期时不允许调整下周课程 */ - private void validateScheduleAdjustTimeLimitStrategy(LocalDateTime newDate) { - if (newDate == null) { - return; - } - LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - wrapper.eq(ScheduleAdjustStrategy::getCllx, STRATEGY_TIME_LIMIT); - wrapper.eq(ScheduleAdjustStrategy::getSfqy, 1); - List strategies = scheduleAdjustStrategyMapper.selectList(wrapper); - - if (strategies == null || strategies.isEmpty()) { - return; - } - - LocalDateTime now = LocalDateTime.now(); - int currentDayOfWeek = now.getDayOfWeek().getValue(); - boolean isFutureWeek = newDate.toLocalDate().isAfter(now.toLocalDate().plusDays(7)); - - for (ScheduleAdjustStrategy strategy : strategies) { - if (strategy.getSxkssj() != null && now.isBefore(strategy.getSxkssj())) { - continue; - } - if (strategy.getSxjssj() != null && now.isAfter(strategy.getSxjssj())) { - continue; - } - Integer deadlineDay = strategy.getJzxq(); - if (deadlineDay == null) { - continue; - } - int deadlineDayOfWeek = (deadlineDay == 0) ? 7 : deadlineDay; - if (isFutureWeek && currentDayOfWeek > deadlineDayOfWeek) { - String dayName = (deadlineDay >= 0 && deadlineDay <= 6) ? WEEK_DAY_NAMES[deadlineDay] : String.valueOf(deadlineDay); - throw new BusinessException(BasicManagementConstants.BAD_REQUEST, - "根据调课策略[" + strategy.getClmc() + "]," + dayName + "之后不允许调整下周课程"); - } - } - } - - /** 判断当前是否命中免审批策略 */ - private boolean matchAutoApproveStrategy() { - LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - wrapper.eq(ScheduleAdjustStrategy::getCllx, STRATEGY_AUTO_APPROVE); - wrapper.eq(ScheduleAdjustStrategy::getSfqy, 1); - List strategies = scheduleAdjustStrategyMapper.selectList(wrapper); - - if (strategies == null || strategies.isEmpty()) { - return false; - } - - LocalDateTime now = LocalDateTime.now(); - for (ScheduleAdjustStrategy strategy : strategies) { - boolean inRange = true; - if (strategy.getSxkssj() != null && now.isBefore(strategy.getSxkssj())) { - inRange = false; - } - if (strategy.getSxjssj() != null && now.isAfter(strategy.getSxjssj())) { - inRange = false; - } - if (inRange) { - return true; - } - } - return false; - } - - /** 组装调课策略展示VO */ - private ScheduleAdjustStrategyVO buildStrategyVO(ScheduleAdjustStrategy strategy) { - ScheduleAdjustStrategyVO vo = new ScheduleAdjustStrategyVO(); - vo.setClbh(strategy.getClbh()); - vo.setClmc(strategy.getClmc()); - vo.setCllx(strategy.getCllx()); - vo.setCllxDesc(STRATEGY_TIME_LIMIT.equals(strategy.getCllx()) ? "时间段限制" : - (STRATEGY_AUTO_APPROVE.equals(strategy.getCllx()) ? "免审批" : strategy.getCllx())); - vo.setSfqy(strategy.getSfqy()); - vo.setSfqyDesc(strategy.getSfqy() != null && strategy.getSfqy() == 1 ? "启用" : "停用"); - vo.setJzxq(strategy.getJzxq()); - if (strategy.getJzxq() != null && strategy.getJzxq() >= 0 && strategy.getJzxq() <= 6) { - vo.setJzxqDesc(WEEK_DAY_NAMES[strategy.getJzxq()]); - } - vo.setJzjc(strategy.getJzjc()); - vo.setSxkssj(strategy.getSxkssj()); - vo.setSxjssj(strategy.getSxjssj()); - vo.setBz(strategy.getBz()); - vo.setCjsj(strategy.getCjsj()); - vo.setGxsj(strategy.getGxsj()); - return vo; - } - /** * 根据教员编号自动解析其归属的实施_机关编号。 *

diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/ElectiveCourseServiceImpl.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/ElectiveCourseServiceImpl.java new file mode 100644 index 000000000..28a0d6661 --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/ElectiveCourseServiceImpl.java @@ -0,0 +1,534 @@ +package com.roomroot.jwgl.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.roomroot.common.exception.ServiceException; +import com.roomroot.common.utils.StringUtils; +import com.roomroot.common.utils.file.FileUtils; +import com.roomroot.common.utils.poi.ExcelUtil; +import com.roomroot.jwgl.dto.jys.ElectiveCourseImportDTO; +import com.roomroot.jwgl.dto.jys.ElectiveCourseQuery; +import com.roomroot.jwgl.dto.jys.ElectiveCourseSaveDTO; +import com.roomroot.jwgl.entity.JSB; +import com.roomroot.jwgl.entity.JYB; +import com.roomroot.jwgl.entity.KB; +import com.roomroot.jwgl.entity.XYDB; +import com.roomroot.jwgl.entity.XYDQB; +import com.roomroot.jwgl.entity.XYDRWB; +import com.roomroot.jwgl.mapper.ClassRoomMapper; +import com.roomroot.jwgl.mapper.ElectiveCourseMapper; +import com.roomroot.jwgl.mapper.JYBMapper; +import com.roomroot.jwgl.mapper.KBMapper; +import com.roomroot.jwgl.mapper.StudentTeamTaskMapper; +import com.roomroot.jwgl.mapper.XYDBMapper; +import com.roomroot.jwgl.mapper.XYDQBMapper; +import com.roomroot.jwgl.service.ElectiveCourseService; +import com.roomroot.jwgl.unit.PageQuery; +import com.roomroot.jwgl.unit.PageResult; +import com.roomroot.jwgl.utils.UuidUtil; +import com.roomroot.jwgl.vo.jys.ElectiveCourseStudentVO; +import com.roomroot.jwgl.vo.jys.ElectiveCourseVO; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import org.apache.poi.xwpf.usermodel.ParagraphAlignment; +import org.apache.poi.xwpf.usermodel.XWPFDocument; +import org.apache.poi.xwpf.usermodel.XWPFParagraph; +import org.apache.poi.xwpf.usermodel.XWPFRun; +import org.apache.poi.xwpf.usermodel.XWPFTable; +import org.apache.poi.xwpf.usermodel.XWPFTableCell; +import org.apache.poi.xwpf.usermodel.XWPFTableRow; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.io.OutputStream; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import static com.roomroot.jwgl.utils.BasicManagementConstants.BAD_REQUEST; +import static com.roomroot.jwgl.utils.BasicManagementConstants.NOT_FOUND; + +/** + * 选修课管理实现。 + */ +@Service +public class ElectiveCourseServiceImpl implements ElectiveCourseService { + + private static final String COURSE_TYPE_ELECTIVE = "选修"; + private static final String STATUS_DRAFT = "拟制"; + private static final String STATUS_OPEN = "开放报名"; + private static final String STATUS_STOP = "停止报名"; + private static final String CLASS_TYPE_ELECTIVE = "选修班"; + private static final int FLAG_DRAFT = 0; + private static final int FLAG_OPEN = 1; + private static final int FLAG_STOP = 2; + + @Resource + private ElectiveCourseMapper electiveCourseMapper; + @Resource + private StudentTeamTaskMapper studentTeamTaskMapper; + @Resource + private XYDBMapper xydbMapper; + @Resource + private KBMapper kbMapper; + @Resource + private JYBMapper jybMapper; + @Resource + private ClassRoomMapper classRoomMapper; + @Resource + private XYDQBMapper xydqbMapper; + + @Override + public PageResult pageList(PageQuery query, ElectiveCourseQuery cond) { + ElectiveCourseQuery filter = normalizeQuery(cond); + int pageNum = query.getPageNum() == null ? 1 : query.getPageNum(); + int pageSize = query.getPageSize() == null ? 20 : query.getPageSize(); + Page page = new Page<>(pageNum, pageSize); + Page result = electiveCourseMapper.selectElectiveCoursePage(page, filter); + fillSerial(result.getRecords(), pageNum, pageSize); + return new PageResult<>(result.getRecords(), result.getTotal(), pageNum, pageSize); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void add(ElectiveCourseSaveDTO dto) { + if (dto == null) { + throw new ServiceException("选修课信息不能为空", BAD_REQUEST); + } + KB course = requireCourse(dto.getKbh()); + String xydbh = resolveTeamId(dto.getXydbh(), dto.getXxbmc(), dto.getNj(), true); + XYDRWB task = new XYDRWB(); + task.setBh(UuidUtil.getOriginalUUID()); + task.setDelFlag(0); + task.setNd(dto.getNd() != null ? dto.getNd() : LocalDate.now().getYear()); + task.setXydbh(xydbh); + task.setKbh(course.getKbh()); + task.setXqdc(dto.getXqdc()); + task.setJybh(blankToNull(dto.getJybh())); + task.setJsbh(blankToNull(dto.getJsbh())); + task.setRs(dto.getRs()); + task.setXs(dto.getXs() != null ? dto.getXs() : course.getXs()); + task.setXf(dto.getXf() != null ? dto.getXf() : course.getXf()); + task.setKlx(ensureElectiveType(null)); + task.setJysdh(StringUtils.isNotEmpty(dto.getJysdh()) ? dto.getJysdh() : course.getJysdh()); + task.setBz(dto.getBz()); + task.setXz(FLAG_DRAFT); + studentTeamTaskMapper.insert(task); + upsertPinban(xydbh, STATUS_DRAFT, dto.getBmkssj(), dto.getBmjssj(), + dto.getYqsm(), dto.getKxdlbc(), dto.getBz()); + updateTeamDates(xydbh, dto.getKkrq(), dto.getJkrq()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int batchOpenRegistration(List bhList) { + return changeStatus(bhList, STATUS_OPEN, FLAG_OPEN, 1, false); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int batchCancelOpenRegistration(List bhList) { + return changeStatus(bhList, STATUS_DRAFT, FLAG_DRAFT, 0, false); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int batchStopRegistration(List bhList) { + return changeStatus(bhList, STATUS_STOP, FLAG_STOP, 0, true); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int batchReverseClassRange(List bhList) { + List tasks = loadElectiveTasks(bhList); + int count = 0; + Set handled = new LinkedHashSet<>(); + for (XYDRWB task : tasks) { + if (!handled.add(task.getXydbh())) { + continue; + } + List names = electiveCourseMapper.selectOriginalClassNames(task.getXydbh()); + if (names == null || names.isEmpty()) { + throw new ServiceException("选修班暂无学员,无法根据学员反向确定班次范围", BAD_REQUEST); + } + upsertPinban(task.getXydbh(), null, null, null, null, String.join(";", names), null); + count++; + } + return count; + } + + @Override + public void exportClassList(ElectiveCourseQuery cond, HttpServletResponse response) { + List list = electiveCourseMapper.selectElectiveCourseList(normalizeQuery(cond)); + fillSerial(list, 1, list == null ? 0 : list.size()); + ExcelUtil util = new ExcelUtil<>(ElectiveCourseVO.class); + util.exportExcel(response, list, "选修班列表"); + } + + @Override + public void exportStudentExcel(List bhList, HttpServletResponse response) { + List students = loadStudents(bhList); + ExcelUtil util = new ExcelUtil<>(ElectiveCourseStudentVO.class); + util.exportExcel(response, students, "选修班学员名单"); + } + + @Override + public void exportStudentWord(List bhList, HttpServletResponse response) { + List students = loadStudents(bhList); + try (XWPFDocument doc = new XWPFDocument(); OutputStream os = response.getOutputStream()) { + response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document"); + FileUtils.setAttachmentResponseHeader(response, "选修班学员名单.docx"); + writeStudentWord(doc, students); + doc.write(os); + os.flush(); + } catch (ServiceException e) { + throw e; + } catch (Exception e) { + throw new ServiceException("导出Word失败:" + e.getMessage(), BAD_REQUEST); + } + } + + @Override + public void downloadTemplate(HttpServletResponse response) { + ExcelUtil util = new ExcelUtil<>(ElectiveCourseImportDTO.class); + util.importTemplateExcel(response, "选修课数据"); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int importData(MultipartFile file) throws Exception { + if (file == null || file.isEmpty()) { + throw new ServiceException("导入文件不能为空", BAD_REQUEST); + } + ExcelUtil util = new ExcelUtil<>(ElectiveCourseImportDTO.class); + List rows = util.importExcel(file.getInputStream()); + if (rows == null || rows.isEmpty()) { + throw new ServiceException("Excel中无有效数据", BAD_REQUEST); + } + int count = 0; + for (int i = 0; i < rows.size(); i++) { + ElectiveCourseImportDTO row = rows.get(i); + int line = i + 2; + if (StringUtils.isEmpty(row.getKmc())) { + throw new ServiceException("第" + line + "行课程科目名称未填写", BAD_REQUEST); + } + if (StringUtils.isEmpty(row.getXxbmc())) { + throw new ServiceException("第" + line + "行选修班名称未填写", BAD_REQUEST); + } + KB course = kbMapper.selectOne(new LambdaQueryWrapper().eq(KB::getKmc, row.getKmc().trim())); + if (course == null) { + throw new ServiceException("第" + line + "行课程科目名称不存在:" + row.getKmc(), NOT_FOUND); + } + String jybh = null; + if (StringUtils.isNotEmpty(row.getJyxm())) { + JYB teacher = jybMapper.selectOne(new LambdaQueryWrapper().eq(JYB::getJyxm, row.getJyxm().trim())); + if (teacher == null) { + throw new ServiceException("第" + line + "行授课教员不存在:" + row.getJyxm(), NOT_FOUND); + } + jybh = teacher.getJybh(); + } + String jsbh = null; + if (StringUtils.isNotEmpty(row.getJsmc())) { + JSB room = classRoomMapper.selectOne(new LambdaQueryWrapper().eq(JSB::getJsmc, row.getJsmc().trim())); + if (room == null) { + throw new ServiceException("第" + line + "行教学场地不存在:" + row.getJsmc(), NOT_FOUND); + } + jsbh = room.getJsbh(); + } + String xydbh = resolveTeamId(null, row.getXxbmc().trim(), row.getKxbcnj(), true); + XYDRWB task = new XYDRWB(); + task.setBh(UuidUtil.getOriginalUUID()); + task.setDelFlag(0); + task.setNd(LocalDate.now().getYear()); + task.setXydbh(xydbh); + task.setKbh(course.getKbh()); + task.setJybh(jybh); + task.setJsbh(jsbh); + task.setRs(row.getJhrs()); + task.setXs(row.getJhxs() != null ? row.getJhxs() : course.getXs()); + task.setXf(row.getXf() != null ? row.getXf() : course.getXf()); + task.setKlx(ensureElectiveType(null)); + task.setJysdh(course.getJysdh()); + task.setXz(statusToFlag(row.getXkzt())); + studentTeamTaskMapper.insert(task); + upsertPinban(xydbh, normalizeStatus(row.getXkzt()), parseDateTime(row.getBmkssj()), + parseDateTime(row.getBmjssj()), row.getYqsm(), row.getKxbcnj(), null); + updateTeamDates(xydbh, parseDateTime(row.getKkrq()), parseDateTime(row.getJkrq())); + count++; + } + return count; + } + + private int changeStatus(List bhList, String status, int xzFlag, Integer allowRegister, boolean stopNow) { + List tasks = loadElectiveTasks(bhList); + Set teams = new LinkedHashSet<>(); + for (XYDRWB task : tasks) { + task.setXz(xzFlag); + studentTeamTaskMapper.updateById(task); + teams.add(task.getXydbh()); + } + for (String xydbh : teams) { + upsertPinban(xydbh, status, null, null, null, null, null); + updatePeriodRegister(xydbh, allowRegister, stopNow); + } + return tasks.size(); + } + + private List loadElectiveTasks(List bhList) { + if (bhList == null || bhList.isEmpty()) { + throw new ServiceException("请先选择选修课", BAD_REQUEST); + } + List tasks = new ArrayList<>(); + for (String bh : bhList) { + if (StringUtils.isEmpty(bh)) { + continue; + } + XYDRWB task = studentTeamTaskMapper.selectById(bh); + if (task == null) { + throw new ServiceException("选修课不存在", NOT_FOUND); + } + if (task.getKlx() == null || !task.getKlx().contains(COURSE_TYPE_ELECTIVE)) { + throw new ServiceException("所选记录不是选修课", BAD_REQUEST); + } + tasks.add(task); + } + if (tasks.isEmpty()) { + throw new ServiceException("请先选择选修课", BAD_REQUEST); + } + return tasks; + } + + private List loadStudents(List bhList) { + List tasks = loadElectiveTasks(bhList); + List students = new ArrayList<>(); + Set teams = new LinkedHashSet<>(); + for (XYDRWB task : tasks) { + if (!teams.add(task.getXydbh())) { + continue; + } + KB course = kbMapper.selectById(task.getKbh()); + List rows = electiveCourseMapper.selectElectiveStudents(task.getXydbh()); + if (rows == null) { + continue; + } + for (ElectiveCourseStudentVO row : rows) { + if (course != null) { + row.setKmc(course.getKmc()); + } + students.add(row); + } + } + if (students.isEmpty()) { + throw new ServiceException("所选选修班暂无学员", BAD_REQUEST); + } + for (int i = 0; i < students.size(); i++) { + students.get(i).setXh(i + 1); + } + return students; + } + + private void upsertPinban(String xydbh, String zt, LocalDateTime start, LocalDateTime end, + String yqsm, String bmdtj, String bz) { + Integer exists = electiveCourseMapper.countPinban(xydbh); + if (exists == null || exists == 0) { + electiveCourseMapper.insertPinban(xydbh, zt == null ? STATUS_DRAFT : zt, start, end, yqsm, bmdtj, bz); + } else { + electiveCourseMapper.updatePinban(xydbh, zt, start, end, yqsm, bmdtj); + } + } + + private String resolveTeamId(String xydbh, String xxbmc, String nj, boolean createIfMissing) { + if (StringUtils.isNotEmpty(xydbh)) { + XYDB exists = xydbMapper.selectById(xydbh); + if (exists == null) { + throw new ServiceException("选修班不存在", NOT_FOUND); + } + return xydbh; + } + if (StringUtils.isEmpty(xxbmc)) { + throw new ServiceException("选修班编号或名称不能为空", BAD_REQUEST); + } + XYDB team = xydbMapper.selectOne(new LambdaQueryWrapper().eq(XYDB::getXydmc, xxbmc.trim())); + if (team != null) { + return team.getXydbh(); + } + if (!createIfMissing) { + throw new ServiceException("选修班不存在:" + xxbmc, NOT_FOUND); + } + XYDB created = new XYDB(); + created.setXydbh(UuidUtil.getOriginalUUID()); + created.setXydmc(xxbmc.trim()); + created.setNj(blankToNull(nj)); + created.setXydlx(CLASS_TYPE_ELECTIVE); + created.setXslx(0); + xydbMapper.insert(created); + return created.getXydbh(); + } + + private KB requireCourse(String kbh) { + if (StringUtils.isEmpty(kbh)) { + throw new ServiceException("课程科目不能为空", BAD_REQUEST); + } + KB course = kbMapper.selectById(kbh); + if (course == null) { + throw new ServiceException("课程科目不存在", NOT_FOUND); + } + return course; + } + + private void updateTeamDates(String xydbh, LocalDateTime start, LocalDateTime end) { + if (start == null && end == null) { + return; + } + XYDB patch = new XYDB(); + patch.setXydbh(xydbh); + if (start != null) { + patch.setRxrq(start); + } + if (end != null) { + patch.setByrq(end); + } + xydbMapper.updateById(patch); + } + + private void updatePeriodRegister(String xydbh, Integer allowRegister, boolean stopNow) { + List periods = xydqbMapper.selectList(new LambdaQueryWrapper().eq(XYDQB::getXydbh, xydbh)); + if (periods == null || periods.isEmpty()) { + return; + } + for (XYDQB period : periods) { + LambdaUpdateWrapper update = new LambdaUpdateWrapper() + .eq(XYDQB::getBh, period.getBh()) + .set(XYDQB::getYxzc, allowRegister); + if (stopNow) { + update.set(XYDQB::getJszcsj, LocalDateTime.now()); + } + xydqbMapper.update(null, update); + } + } + + private ElectiveCourseQuery normalizeQuery(ElectiveCourseQuery cond) { + ElectiveCourseQuery filter = cond == null ? new ElectiveCourseQuery() : cond; + filter.setJyxm(blankToNull(filter.getJyxm())); + filter.setKmc(blankToNull(filter.getKmc())); + filter.setKxbcnj(blankToNull(filter.getKxbcnj())); + filter.setXxbmc(blankToNull(filter.getXxbmc())); + filter.setPxcc(normalizeNone(filter.getPxcc())); + filter.setXkzt(normalizeNone(filter.getXkzt())); + return filter; + } + + private void fillSerial(List records, int pageNum, int pageSize) { + if (records == null) { + return; + } + int start = Math.max(pageNum - 1, 0) * Math.max(pageSize, 0); + for (int i = 0; i < records.size(); i++) { + records.get(i).setXh(start + i + 1); + } + } + + private void writeStudentWord(XWPFDocument doc, List students) { + XWPFParagraph title = doc.createParagraph(); + title.setAlignment(ParagraphAlignment.CENTER); + XWPFRun titleRun = title.createRun(); + titleRun.setText("选修班学员名单"); + titleRun.setBold(true); + titleRun.setFontSize(16); + + XWPFTable table = doc.createTable(students.size() + 1, 7); + String[] headers = {"序号", "选修班名称", "课程", "学号", "姓名", "性别", "联系电话"}; + XWPFTableRow headerRow = table.getRow(0); + for (int i = 0; i < headers.length; i++) { + setCellText(headerRow.getCell(i), headers[i]); + } + for (int i = 0; i < students.size(); i++) { + ElectiveCourseStudentVO row = students.get(i); + XWPFTableRow tableRow = table.getRow(i + 1); + setCellText(tableRow.getCell(0), String.valueOf(row.getXh())); + setCellText(tableRow.getCell(1), nvl(row.getXxbmc())); + setCellText(tableRow.getCell(2), nvl(row.getKmc())); + setCellText(tableRow.getCell(3), nvl(row.getXhNo())); + setCellText(tableRow.getCell(4), nvl(row.getXm())); + setCellText(tableRow.getCell(5), nvl(row.getXb())); + setCellText(tableRow.getCell(6), nvl(row.getLxdh())); + } + } + + private void setCellText(XWPFTableCell cell, String text) { + cell.removeParagraph(0); + XWPFParagraph paragraph = cell.addParagraph(); + XWPFRun run = paragraph.createRun(); + run.setText(text == null ? "" : text); + run.setFontSize(11); + } + + private String ensureElectiveType(String klx) { + if (StringUtils.isEmpty(klx)) { + return COURSE_TYPE_ELECTIVE; + } + return klx.contains(COURSE_TYPE_ELECTIVE) ? klx : klx + COURSE_TYPE_ELECTIVE; + } + + private String normalizeStatus(String status) { + String value = normalizeNone(status); + if (value == null) { + return STATUS_DRAFT; + } + if (STATUS_OPEN.equals(value) || STATUS_STOP.equals(value) || STATUS_DRAFT.equals(value)) { + return value; + } + return STATUS_DRAFT; + } + + private int statusToFlag(String status) { + String value = normalizeStatus(status); + if (STATUS_OPEN.equals(value)) { + return FLAG_OPEN; + } + if (STATUS_STOP.equals(value)) { + return FLAG_STOP; + } + return FLAG_DRAFT; + } + + private String normalizeNone(String value) { + String trimmed = blankToNull(value); + if (trimmed == null || "无".equals(trimmed)) { + return null; + } + return trimmed; + } + + private String blankToNull(String value) { + return StringUtils.isEmpty(value) ? null : value.trim(); + } + + private String nvl(String value) { + return value == null ? "" : value; + } + + private LocalDateTime parseDateTime(String text) { + String value = blankToNull(text); + if (value == null) { + return null; + } + try { + if (value.length() <= 10) { + if (value.contains("/")) { + return LocalDate.parse(value, DateTimeFormatter.ofPattern("yyyy/MM/dd")).atStartOfDay(); + } + return LocalDate.parse(value, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atStartOfDay(); + } + return LocalDateTime.parse(value, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + } catch (Exception e) { + throw new ServiceException("日期格式不正确:" + text, BAD_REQUEST); + } + } +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/FacultyServiceImpl.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/FacultyServiceImpl.java index e57c7c43a..4195177fc 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/FacultyServiceImpl.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/FacultyServiceImpl.java @@ -9,6 +9,7 @@ import com.roomroot.jwgl.service.FacultyService; import com.roomroot.jwgl.unit.BusinessException; import com.roomroot.jwgl.unit.PageQuery; import com.roomroot.jwgl.unit.PageResult; +import com.roomroot.jwgl.utils.ExcelExportUtil; import com.roomroot.jwgl.utils.ExcelParseUtil; import com.roomroot.jwgl.utils.UuidUtil; import com.roomroot.jwgl.vo.faculty.TeacherListVO; @@ -160,6 +161,52 @@ public class FacultyServiceImpl implements FacultyService { return jybMapper.selectById(jybh); } + @Override + @Transactional(rollbackFor = Exception.class) + public int importJYBFromExcel(MultipartFile file) throws Exception { + if (file == null || file.isEmpty()) { + throw new BusinessException("导入文件不能为空"); + } + List list = ExcelParseUtil.parseJYBExcel( + file.getInputStream(), file.getOriginalFilename()); + if (list.isEmpty()) { + throw new BusinessException("Excel中无有效数据"); + } + for (JYB entity : list) { + // 编号为空自动生成 + if (entity.getJybh() == null || entity.getJybh().isEmpty()) { + entity.setJybh(UuidUtil.getUUID()); + } + // 离职状态默认 0 + if (entity.getLzzt() == null) { + entity.setLzzt(0); + } + jybMapper.insert(entity); + } + return list.size(); + } + + @Override + public void exportJYBExcel(jakarta.servlet.http.HttpServletResponse response) throws Exception { + com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper w = + new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>(); + w.eq(JYB::getLzzt, 0).orderByAsc(JYB::getXh); + List list = jybMapper.selectList(w); + + String[] headers = {"教员编号", "教员姓名", "教研室代号", "职称", "专业技术职务等级", "教员类别", + "性别", "手机号", "身份证号", "备注", "序号", "虚实类型"}; + byte[] bytes = ExcelExportUtil.export("教员", headers, list, + JYB::getJybh, JYB::getJyxm, JYB::getJysdh, JYB::getZc, + JYB::getZyjszwdj, JYB::getJylb, JYB::getXb, JYB::getSjh, + JYB::getSfzh, JYB::getBz, JYB::getXh, JYB::getXslx); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setHeader("Content-Disposition", + "attachment; filename=" + java.net.URLEncoder.encode( + "教员列表.xlsx", java.nio.charset.StandardCharsets.UTF_8)); + response.getOutputStream().write(bytes); + response.getOutputStream().flush(); + } + @Override public PageResult pageJYBDetail(PageQuery query, JYB cond) { Page page = new Page<>(query.getPageNum(), query.getPageSize()); diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/KCBServiceImpl.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/KCBServiceImpl.java index 89e61c323..af08e13b1 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/KCBServiceImpl.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/KCBServiceImpl.java @@ -1,13 +1,30 @@ package com.roomroot.jwgl.service.impl; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.roomroot.common.utils.StringUtils; +import com.roomroot.common.utils.poi.ExcelUtil; +import com.roomroot.jwgl.dto.kcb.TimetableQuery; import com.roomroot.jwgl.entity.KCB; import com.roomroot.jwgl.mapper.KCBMapper; +import com.roomroot.jwgl.mapper.KcbTimetableMapper; +import com.roomroot.jwgl.mapper.SystemInitializationMapper; import com.roomroot.jwgl.service.KCBService; +import com.roomroot.jwgl.unit.PageQuery; +import com.roomroot.jwgl.unit.PageResult; import com.roomroot.jwgl.utils.UuidUtil; +import com.roomroot.jwgl.utils.JwglRoleHelper; +import com.roomroot.jwgl.vo.kcb.ClassTimetableVO; +import com.roomroot.jwgl.vo.kcb.DailyWeeklyTimetableVO; +import com.roomroot.jwgl.vo.kcb.SemesterGradeExportVO; +import com.roomroot.jwgl.vo.systeminitialization.SemesterInitializationVO; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.stereotype.Service; import jakarta.annotation.Resource; +import java.time.DayOfWeek; +import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.List; /** @@ -16,9 +33,20 @@ import java.util.List; @Service public class KCBServiceImpl implements KCBService { + private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + @Resource private KCBMapper kcbMapper; + @Resource + private KcbTimetableMapper kcbTimetableMapper; + + @Resource + private SystemInitializationMapper systemInitializationMapper; + + @Resource + private JwglRoleHelper jwglRoleHelper; + @Override public void add(KCB kcb) { if (kcb.getCjsj() == null) { @@ -56,4 +84,108 @@ public class KCBServiceImpl implements KCBService { return kcbMapper.selectList(null); } + @Override + public List listToday(TimetableQuery cond) { + TimetableQuery filter = prepareFilter(cond); + String today = LocalDate.now().format(DATE_FORMAT); + return kcbTimetableMapper.selectLessonTimetable(filter, today, today); + } + + @Override + public List listWeek(TimetableQuery cond) { + TimetableQuery filter = prepareFilter(cond); + LocalDate today = LocalDate.now(); + LocalDate monday = today.with(DayOfWeek.MONDAY); + LocalDate sunday = today.with(DayOfWeek.SUNDAY); + return kcbTimetableMapper.selectLessonTimetable(filter, + monday.format(DATE_FORMAT), sunday.format(DATE_FORMAT)); + } + + @Override + public PageResult pageClassTimetable(PageQuery query, TimetableQuery cond) { + TimetableQuery filter = prepareFilter(cond); + int pageNum = (query == null || query.getPageNum() == null) ? 1 : query.getPageNum(); + int pageSize = (query == null || query.getPageSize() == null) ? 20 : query.getPageSize(); + Page page = new Page<>(pageNum, pageSize); + Page result = kcbTimetableMapper.selectClassTimetable(page, filter); + return new PageResult<>(result.getRecords(), result.getTotal(), pageNum, pageSize); + } + + @Override + public void exportSemesterPlan(TimetableQuery cond, HttpServletResponse response) { + TimetableQuery filter = prepareFilter(cond); + String[] range = resolveSemesterDateRange(filter); + List list = kcbTimetableMapper.selectLessonTimetable(filter, range[0], range[1]); + ExcelUtil util = new ExcelUtil<>(DailyWeeklyTimetableVO.class); + util.exportExcel(response, list, "学期教学实施计划"); + } + + @Override + public void exportSemesterGrades(TimetableQuery cond, HttpServletResponse response) { + TimetableQuery filter = prepareFilter(cond); + List list = kcbTimetableMapper.selectSemesterGrades(filter); + ExcelUtil util = new ExcelUtil<>(SemesterGradeExportVO.class); + util.exportExcel(response, list, "学期成绩表"); + } + + @Override + public void exportClassCourses(TimetableQuery cond, HttpServletResponse response) { + TimetableQuery filter = prepareFilter(cond); + List list = kcbTimetableMapper.selectClassTimetableList(filter); + ExcelUtil util = new ExcelUtil<>(ClassTimetableVO.class); + util.exportExcel(response, list, "班次课程列表"); + } + + /** + * 未传年度时按当前学期填充;队别班次名称去空白。 + * 学员强制只看本人所在学员队课表。 + */ + private TimetableQuery prepareFilter(TimetableQuery cond) { + TimetableQuery filter = cond == null ? new TimetableQuery() : cond; + if (jwglRoleHelper.isStudent()) { + filter.setXydbh(jwglRoleHelper.requireStudentTeamId()); + filter.setXydmc(null); + } else { + if (StringUtils.isNotEmpty(filter.getXydbh())) { + filter.setXydbh(filter.getXydbh().trim()); + } + if (StringUtils.isNotEmpty(filter.getXydmc())) { + filter.setXydmc(filter.getXydmc().trim()); + } + } + if (filter.getNd() != null) { + return filter; + } + SemesterInitializationVO semester = systemInitializationMapper.selectCurrentSemester(); + if (semester != null && semester.getYear() != null) { + filter.setNd(semester.getYear()); + if (filter.getXqdc() == null) { + filter.setXqdc(semester.getSequenceNumber()); + } + } else { + filter.setNd(LocalDate.now().getYear()); + } + return filter; + } + + /** + * 本学期用开学/结束日期;查其他年度时退回该年 1 月 1 日至 12 月 31 日。 + */ + private String[] resolveSemesterDateRange(TimetableQuery filter) { + SemesterInitializationVO semester = systemInitializationMapper.selectCurrentSemester(); + if (semester != null && semester.getStartAt() != null && semester.getEndAt() != null + && filter.getNd() != null && filter.getNd().equals(semester.getYear()) + && (filter.getXqdc() == null || filter.getXqdc().equals(semester.getSequenceNumber()))) { + return new String[]{ + semester.getStartAt().toLocalDate().format(DATE_FORMAT), + semester.getEndAt().toLocalDate().format(DATE_FORMAT) + }; + } + LocalDate now = LocalDate.now(); + int year = filter.getNd() == null ? now.getYear() : filter.getNd(); + LocalDate start = LocalDate.of(year, 1, 1); + LocalDate end = LocalDate.of(year, 12, 31); + return new String[]{start.format(DATE_FORMAT), end.format(DATE_FORMAT)}; + } + } diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/SemesterServiceImpl.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/SemesterServiceImpl.java index 15ed26061..e6773798d 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/SemesterServiceImpl.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/SemesterServiceImpl.java @@ -39,10 +39,8 @@ public class SemesterServiceImpl extends ServiceImpl impleme if(insert > 0){ LocalDateTime kxrq = xq.getKxrq(); LocalDateTime jsrq = xq.getJsrq(); - String startDate = localDateTimeToDateStr(kxrq); String endDate = localDateTimeToDateStr(jsrq); - semesterCalendarService.add(startDate, endDate); } } diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/TeachingTaskManageServiceImpl.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/TeachingTaskManageServiceImpl.java new file mode 100644 index 000000000..2bb542c3a --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/TeachingTaskManageServiceImpl.java @@ -0,0 +1,412 @@ +package com.roomroot.jwgl.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.roomroot.common.exception.ServiceException; +import com.roomroot.common.utils.StringUtils; +import com.roomroot.jwgl.dto.jys.TeachingTaskQuery; +import com.roomroot.jwgl.dto.jys.TeachingTaskSaveDTO; +import com.roomroot.jwgl.entity.JXRW; +import com.roomroot.jwgl.entity.JYSRWS; +import com.roomroot.jwgl.entity.KB; +import com.roomroot.jwgl.entity.XYDB; +import com.roomroot.jwgl.entity.XYDNDXQJBXXB; +import com.roomroot.jwgl.entity.XYDRWB; +import com.roomroot.jwgl.entity.ZYJXJHB; +import com.roomroot.jwgl.mapper.ClassSemesterMapper; +import com.roomroot.jwgl.mapper.KBMapper; +import com.roomroot.jwgl.mapper.OfficeTaskBookMapper; +import com.roomroot.jwgl.mapper.StudentTeamTaskMapper; +import com.roomroot.jwgl.mapper.SystemInitializationMapper; +import com.roomroot.jwgl.mapper.TeachingTaskMapper; +import com.roomroot.jwgl.mapper.XYDBMapper; +import com.roomroot.jwgl.mapper.ZYJXJHBMapper; +import com.roomroot.jwgl.service.StudentTeamTaskService; +import com.roomroot.jwgl.service.TeachingTaskManageService; +import com.roomroot.jwgl.unit.PageQuery; +import com.roomroot.jwgl.unit.PageResult; +import com.roomroot.jwgl.utils.UuidUtil; +import com.roomroot.jwgl.vo.jys.TeachingOfficeBookCourseVO; +import com.roomroot.jwgl.vo.jys.TeachingOfficeBookVO; +import com.roomroot.jwgl.vo.jys.TeachingTaskDetailVO; +import com.roomroot.jwgl.vo.jys.TeachingTaskSquadVO; +import com.roomroot.jwgl.vo.jys.TeachingTaskVO; +import com.roomroot.jwgl.vo.systeminitialization.SemesterInitializationVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import jakarta.annotation.Resource; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import static com.roomroot.jwgl.utils.BasicManagementConstants.BAD_REQUEST; +import static com.roomroot.jwgl.utils.BasicManagementConstants.CONFLICT; +import static com.roomroot.jwgl.utils.BasicManagementConstants.NOT_FOUND; + +/** + * 教学任务管理实现。 + */ +@Service +public class TeachingTaskManageServiceImpl implements TeachingTaskManageService { + + private static final String STATUS_DRAFT = "上报"; + private static final String STATUS_PUBLISHED = "发布"; + private static final String OFFICE_STATUS_UNREPORTED = "未上报"; + private static final String OFFICE_STATUS_PUBLISHED = "发布"; + + @Resource + private TeachingTaskMapper teachingTaskMapper; + @Resource + private OfficeTaskBookMapper officeTaskBookMapper; + @Resource + private ClassSemesterMapper classSemesterMapper; + @Resource + private XYDBMapper xydbMapper; + @Resource + private KBMapper kbMapper; + @Resource + private ZYJXJHBMapper zyjxjhbMapper; + @Resource + private StudentTeamTaskMapper studentTeamTaskMapper; + @Resource + private StudentTeamTaskService studentTeamTaskService; + @Resource + private SystemInitializationMapper systemInitializationMapper; + + @Override + public PageResult pageList(PageQuery query, TeachingTaskQuery cond) { + TeachingTaskQuery filter = cond == null ? new TeachingTaskQuery() : cond; + if (StringUtils.isNotEmpty(filter.getRwmc())) { + filter.setRwmc(filter.getRwmc().trim()); + } + int pageNum = query == null || query.getPageNum() == null ? 1 : query.getPageNum(); + int pageSize = query == null || query.getPageSize() == null ? 20 : query.getPageSize(); + Page result = teachingTaskMapper.selectManagePage(new Page<>(pageNum, pageSize), filter); + if (result.getRecords() != null) { + for (TeachingTaskVO row : result.getRecords()) { + fillSemesterName(row); + } + } + return new PageResult<>(result.getRecords(), result.getTotal(), pageNum, pageSize); + } + + @Override + public TeachingTaskDetailVO getDetail(String bh) { + if (StringUtils.isEmpty(bh)) { + throw new ServiceException("教学任务编号不能为空", BAD_REQUEST); + } + JXRW entity = teachingTaskMapper.selectById(bh); + if (entity == null || Integer.valueOf(1).equals(entity.getDelFlag())) { + throw new ServiceException("教学任务不存在", NOT_FOUND); + } + TeachingTaskVO vo = toSimpleVo(entity); + List squads = listBoundSquads(bh); + if (!squads.isEmpty() && squads.get(0).getXqdc() != null) { + vo.setXqdc(squads.get(0).getXqdc()); + } + fillSemesterName(vo); + TeachingTaskDetailVO detail = new TeachingTaskDetailVO(); + detail.setTask(vo); + detail.setOfficeBooks(listOfficeBooks(bh)); + detail.setSquads(squads); + return detail; + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void add(TeachingTaskSaveDTO dto) { + if (dto == null || StringUtils.isEmpty(dto.getRwmc())) { + throw new ServiceException("任务名称不能为空", BAD_REQUEST); + } + fillSemester(dto); + JXRW entity = new JXRW(); + entity.setBh(UuidUtil.getOriginalUUID()); + entity.setRwmc(dto.getRwmc().trim()); + entity.setNd(dto.getNd()); + entity.setZt(STATUS_DRAFT); + entity.setCjsj(LocalDateTime.now()); + entity.setJssj(dto.getJssj() != null ? dto.getJssj() : defaultEndTime(dto.getNd(), dto.getXqdc())); + entity.setDelFlag(0); + teachingTaskMapper.insert(entity); + bindSquads(entity.getBh(), dto.getNd(), dto.getXqdc(), dto.getXydxqbhList()); + generateCourseTasksAndOfficeBooks(entity.getBh()); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void update(TeachingTaskSaveDTO dto) { + if (dto == null || StringUtils.isEmpty(dto.getBh())) { + throw new ServiceException("教学任务编号不能为空", BAD_REQUEST); + } + if (StringUtils.isEmpty(dto.getRwmc())) { + throw new ServiceException("任务名称不能为空", BAD_REQUEST); + } + JXRW entity = teachingTaskMapper.selectById(dto.getBh()); + if (entity == null || Integer.valueOf(1).equals(entity.getDelFlag())) { + throw new ServiceException("教学任务不存在", NOT_FOUND); + } + fillSemester(dto); + entity.setRwmc(dto.getRwmc().trim()); + if (dto.getJssj() != null) { + entity.setJssj(dto.getJssj()); + } + teachingTaskMapper.updateById(entity); + bindSquads(entity.getBh(), dto.getNd(), dto.getXqdc(), dto.getXydxqbhList()); + generateCourseTasksAndOfficeBooks(entity.getBh()); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void delete(String bh) { + if (StringUtils.isEmpty(bh)) { + throw new ServiceException("教学任务编号不能为空", BAD_REQUEST); + } + JXRW entity = teachingTaskMapper.selectById(bh); + if (entity == null || Integer.valueOf(1).equals(entity.getDelFlag())) { + return; + } + entity.setDelFlag(1); + teachingTaskMapper.updateById(entity); + + List books = officeTaskBookMapper.selectList(new LambdaQueryWrapper() + .eq(JYSRWS::getJxrwbh, bh) + .eq(JYSRWS::getDelFlag, 0)); + for (JYSRWS book : books) { + book.setDelFlag(1); + officeTaskBookMapper.updateById(book); + } + classSemesterMapper.update(null, new LambdaUpdateWrapper() + .eq(XYDNDXQJBXXB::getJxrwbh, bh) + .set(XYDNDXQJBXXB::getJxrwbh, null)); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public int publish(String bh) { + if (StringUtils.isEmpty(bh)) { + throw new ServiceException("教学任务编号不能为空", BAD_REQUEST); + } + JXRW entity = teachingTaskMapper.selectById(bh); + if (entity == null || Integer.valueOf(1).equals(entity.getDelFlag())) { + throw new ServiceException("教学任务不存在", NOT_FOUND); + } + if (STATUS_PUBLISHED.equals(entity.getZt())) { + throw new ServiceException("该教学任务已发布", CONFLICT); + } + generateCourseTasksAndOfficeBooks(bh); + entity.setZt(STATUS_PUBLISHED); + entity.setFbsj(LocalDateTime.now()); + teachingTaskMapper.updateById(entity); + + List books = officeTaskBookMapper.selectList(new LambdaQueryWrapper() + .eq(JYSRWS::getJxrwbh, bh) + .eq(JYSRWS::getDelFlag, 0)); + for (JYSRWS book : books) { + book.setZt(OFFICE_STATUS_PUBLISHED); + officeTaskBookMapper.updateById(book); + } + return books.size(); + } + + @Override + public List listOfficeBooks(String jxrwbh) { + if (StringUtils.isEmpty(jxrwbh)) { + return new ArrayList<>(); + } + List list = teachingTaskMapper.selectOfficeBooks(jxrwbh); + return list == null ? new ArrayList<>() : list; + } + + @Override + public List listOfficeBookCourses(String jxrwbh, String jysdh) { + if (StringUtils.isEmpty(jxrwbh) || StringUtils.isEmpty(jysdh)) { + throw new ServiceException("教学任务编号和教研室代号不能为空", BAD_REQUEST); + } + List list = teachingTaskMapper.selectOfficeBookCourses(jxrwbh, jysdh); + return list == null ? new ArrayList<>() : list; + } + + @Override + public List listBoundSquads(String jxrwbh) { + if (StringUtils.isEmpty(jxrwbh)) { + return new ArrayList<>(); + } + List list = teachingTaskMapper.selectBoundSquads(jxrwbh); + return list == null ? new ArrayList<>() : list; + } + + @Override + public List listAvailableSquads(Integer nd, Integer xqdc, String jxrwbh) { + if (nd == null || xqdc == null) { + SemesterInitializationVO semester = systemInitializationMapper.selectCurrentSemester(); + if (semester == null || semester.getYear() == null || semester.getSequenceNumber() == null) { + throw new ServiceException("未设置当前学期,请指定年度和学期第次", BAD_REQUEST); + } + nd = semester.getYear(); + xqdc = semester.getSequenceNumber(); + } + List list = teachingTaskMapper.selectAvailableSquads(nd, xqdc, jxrwbh); + return list == null ? new ArrayList<>() : list; + } + + private void fillSemester(TeachingTaskSaveDTO dto) { + if (dto.getNd() != null && dto.getXqdc() != null) { + return; + } + SemesterInitializationVO semester = systemInitializationMapper.selectCurrentSemester(); + if (semester == null || semester.getYear() == null) { + if (dto.getNd() == null) { + throw new ServiceException("请选择学期", BAD_REQUEST); + } + return; + } + if (dto.getNd() == null) { + dto.setNd(semester.getYear()); + } + if (dto.getXqdc() == null) { + dto.setXqdc(semester.getSequenceNumber()); + } + } + + private LocalDateTime defaultEndTime(Integer nd, Integer xqdc) { + if (nd == null || xqdc == null) { + return null; + } + SemesterInitializationVO semester = systemInitializationMapper.selectSemesterByKey(nd, xqdc); + return semester == null ? null : semester.getEndAt(); + } + + private void fillSemesterName(TeachingTaskVO row) { + if (row == null || row.getNd() == null || row.getXqdc() == null) { + return; + } + SemesterInitializationVO semester = systemInitializationMapper.selectSemesterByKey(row.getNd(), row.getXqdc()); + if (semester != null && StringUtils.isNotEmpty(semester.getSemesterName())) { + row.setXqmc(semester.getSemesterName()); + } else { + row.setXqmc(row.getNd() + "年第" + row.getXqdc() + "学期"); + } + } + + private TeachingTaskVO toSimpleVo(JXRW entity) { + TeachingTaskVO vo = new TeachingTaskVO(); + vo.setBh(entity.getBh()); + vo.setRwmc(entity.getRwmc()); + vo.setNd(entity.getNd()); + vo.setZt(entity.getZt()); + vo.setFbsj(entity.getFbsj()); + vo.setCjsj(entity.getCjsj()); + vo.setJssj(entity.getJssj()); + return vo; + } + + private void bindSquads(String jxrwbh, Integer nd, Integer xqdc, List xydxqbhList) { + classSemesterMapper.update(null, new LambdaUpdateWrapper() + .eq(XYDNDXQJBXXB::getJxrwbh, jxrwbh) + .set(XYDNDXQJBXXB::getJxrwbh, null)); + if (CollectionUtils.isEmpty(xydxqbhList)) { + return; + } + for (String xydxqbh : xydxqbhList) { + if (StringUtils.isEmpty(xydxqbh)) { + continue; + } + XYDNDXQJBXXB semester = classSemesterMapper.selectById(xydxqbh); + if (semester == null || Integer.valueOf(1).equals(semester.getDelFlag())) { + throw new ServiceException("学员队学期信息不存在:" + xydxqbh, NOT_FOUND); + } + if (nd != null && semester.getNd() != null && !nd.equals(semester.getNd())) { + throw new ServiceException("所选学员队不属于该学期", BAD_REQUEST); + } + if (xqdc != null && semester.getXqdc() != null && !xqdc.equals(semester.getXqdc())) { + throw new ServiceException("所选学员队不属于该学期", BAD_REQUEST); + } + if (StringUtils.isNotEmpty(semester.getJxrwbh()) && !jxrwbh.equals(semester.getJxrwbh())) { + throw new ServiceException("学员队已被其他教学任务占用", CONFLICT); + } + semester.setJxrwbh(jxrwbh); + classSemesterMapper.updateById(semester); + } + } + + private void generateCourseTasksAndOfficeBooks(String jxrwbh) { + List squads = classSemesterMapper.selectList(new LambdaQueryWrapper() + .eq(XYDNDXQJBXXB::getJxrwbh, jxrwbh) + .eq(XYDNDXQJBXXB::getDelFlag, 0)); + for (XYDNDXQJBXXB squad : squads) { + if (StringUtils.isEmpty(squad.getXydbh()) || squad.getXqdc() == null) { + continue; + } + try { + studentTeamTaskService.autoGenerateRequiredCourses(squad.getXydbh(), squad.getXqdc()); + } catch (Exception ignored) { + // 课程任务已存在或计划缺失时,仍继续生成教研室任务书 + } + } + Set jysdhSet = collectOfficeCodes(squads); + for (String jysdh : jysdhSet) { + Long exist = officeTaskBookMapper.selectCount(new LambdaQueryWrapper() + .eq(JYSRWS::getJxrwbh, jxrwbh) + .eq(JYSRWS::getJysdh, jysdh) + .eq(JYSRWS::getDelFlag, 0)); + if (exist != null && exist > 0) { + continue; + } + JYSRWS book = new JYSRWS(); + book.setBh(UuidUtil.getOriginalUUID()); + book.setJxrwbh(jxrwbh); + book.setJysdh(jysdh); + book.setZt(OFFICE_STATUS_UNREPORTED); + book.setDelFlag(0); + officeTaskBookMapper.insert(book); + } + } + + private Set collectOfficeCodes(List squads) { + Set codes = new LinkedHashSet<>(); + List xydxqbhList = new ArrayList<>(); + for (XYDNDXQJBXXB squad : squads) { + xydxqbhList.add(squad.getBh()); + if (StringUtils.isEmpty(squad.getXydbh()) || squad.getXqdc() == null) { + continue; + } + XYDB xyd = xydbMapper.selectById(squad.getXydbh()); + if (xyd == null || StringUtils.isEmpty(xyd.getZydh())) { + continue; + } + List plans = zyjxjhbMapper.selectList(new LambdaQueryWrapper() + .eq(ZYJXJHB::getZydh, xyd.getZydh()) + .eq(ZYJXJHB::getXqdc, squad.getXqdc()) + .eq(ZYJXJHB::getTy, 0)); + for (ZYJXJHB plan : plans) { + if (StringUtils.isNotEmpty(plan.getJysdh())) { + codes.add(plan.getJysdh()); + continue; + } + if (StringUtils.isEmpty(plan.getKbh())) { + continue; + } + KB kb = kbMapper.selectById(plan.getKbh()); + if (kb != null && StringUtils.isNotEmpty(kb.getJysdh())) { + codes.add(kb.getJysdh()); + } + } + } + if (!xydxqbhList.isEmpty()) { + List tasks = studentTeamTaskMapper.selectList(new LambdaQueryWrapper() + .in(XYDRWB::getXydxqbh, xydxqbhList) + .eq(XYDRWB::getDelFlag, 0)); + for (XYDRWB task : tasks) { + if (StringUtils.isNotEmpty(task.getJysdh())) { + codes.add(task.getJysdh()); + } + } + } + return codes; + } +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/TrainingProgramServiceImpl.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/TrainingProgramServiceImpl.java index 58fcb6e23..8ed448c19 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/TrainingProgramServiceImpl.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/TrainingProgramServiceImpl.java @@ -73,4 +73,45 @@ public class TrainingProgramServiceImpl implements TrainingProgramService { return new PageResult<>(result.getRecords(), result.getTotal(), query.getPageNum(), query.getPageSize()); } + + @Override + @Transactional(rollbackFor = Exception.class) + public int importZYBFromExcel(org.springframework.web.multipart.MultipartFile file) throws Exception { + if (file == null || file.isEmpty()) { + throw new RuntimeException("导入文件不能为空"); + } + java.util.List list = com.roomroot.jwgl.utils.ExcelParseUtil.parseZYBExcel( + file.getInputStream(), file.getOriginalFilename()); + if (list.isEmpty()) { + throw new RuntimeException("Excel中无有效数据"); + } + for (ZYB entity : list) { + if (entity.getZydh() == null || entity.getZydh().isEmpty()) { + entity.setZydh(com.roomroot.jwgl.utils.UuidUtil.getUUID()); + } + if (entity.getTy() == null) { + entity.setTy(false); + } + zybMapper.insert(entity); + } + return list.size(); + } + + @Override + public void exportZYBExcel(jakarta.servlet.http.HttpServletResponse response) throws Exception { + java.util.List list = zybMapper.selectList( + new LambdaQueryWrapper().orderByAsc(ZYB::getZydh)); + String[] headers = {"专业代号", "专业名称", "专业代码", "专业版本", "培训类型", "培训层次", + "学年制", "学期数", "专业方向", "专业备注", "学员类别", "简称", "培训类型2"}; + byte[] bytes = com.roomroot.jwgl.utils.ExcelExportUtil.export("培养方案", headers, list, + ZYB::getZydh, ZYB::getZymc, ZYB::getZydm, ZYB::getZybb, ZYB::getPxlx, + ZYB::getPxcc, ZYB::getXnz, ZYB::getXqs, ZYB::getZyfx, ZYB::getZybz, + ZYB::getXylb, ZYB::getJc, ZYB::getPxlx2); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setHeader("Content-Disposition", + "attachment; filename=" + java.net.URLEncoder.encode( + "培养方案.xlsx", java.nio.charset.StandardCharsets.UTF_8)); + response.getOutputStream().write(bytes); + response.getOutputStream().flush(); + } } diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/ZYJXJHBServiceImpl.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/ZYJXJHBServiceImpl.java index 2a2a49dbc..9ee21f514 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/ZYJXJHBServiceImpl.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/ZYJXJHBServiceImpl.java @@ -71,4 +71,43 @@ public class ZYJXJHBServiceImpl implements ZYJXJHBService { .eq(ZYJXJHB::getTy, ty); return zyjxjhbMapper.selectList(wrapper); } + + @Override + @org.springframework.transaction.annotation.Transactional(rollbackFor = Exception.class) + public int importZYJXJHBFromExcel(org.springframework.web.multipart.MultipartFile file) throws Exception { + if (file == null || file.isEmpty()) { + throw new RuntimeException("导入文件不能为空"); + } + List list = com.roomroot.jwgl.utils.ExcelParseUtil.parseZYJXJHBExcel( + file.getInputStream(), file.getOriginalFilename()); + if (list.isEmpty()) { + throw new RuntimeException("Excel中无有效数据"); + } + for (ZYJXJHB entity : list) { + if (entity.getTy() == null) { + entity.setTy(0); + } + zyjxjhbMapper.insert(entity); + } + return list.size(); + } + + @Override + public void exportZYJXJHBExcel(jakarta.servlet.http.HttpServletResponse response) throws Exception { + List list = zyjxjhbMapper.selectList( + new LambdaQueryWrapper().orderByAsc(ZYJXJHB::getZydh)); + String[] headers = {"专业代号", "课编号", "学期第次", "课类型", "学时", "学分", "周课时", + "课程定位", "模块", "成绩分制", "理论学时", "实践学时", "考试课时", "教研室代号", "简称"}; + byte[] bytes = com.roomroot.jwgl.utils.ExcelExportUtil.export("专业教学计划", headers, list, + ZYJXJHB::getZydh, ZYJXJHB::getKbh, ZYJXJHB::getXqdc, ZYJXJHB::getKlx, + ZYJXJHB::getXs, ZYJXJHB::getXf, ZYJXJHB::getZks, ZYJXJHB::getKcdw, + ZYJXJHB::getMk, ZYJXJHB::getCjfz, ZYJXJHB::getLlxs, ZYJXJHB::getSjxs, + ZYJXJHB::getKsks, ZYJXJHB::getJysdh, ZYJXJHB::getJc); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setHeader("Content-Disposition", + "attachment; filename=" + java.net.URLEncoder.encode( + "专业教学计划.xlsx", java.nio.charset.StandardCharsets.UTF_8)); + response.getOutputStream().write(bytes); + response.getOutputStream().flush(); + } } diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/utils/ExcelParseUtil.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/utils/ExcelParseUtil.java index b0feca1c8..99cbc355c 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/utils/ExcelParseUtil.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/utils/ExcelParseUtil.java @@ -5,10 +5,13 @@ import com.roomroot.jwgl.dto.courserunning.SemesterImportDTO; import com.roomroot.jwgl.dto.courserunning.SingleCourseImportDTO; import com.roomroot.jwgl.dto.departmentpersonnel.DepartmentPersonnelCreateDTO; import com.roomroot.jwgl.entity.JXSSJH; +import com.roomroot.jwgl.entity.JYB; import com.roomroot.jwgl.entity.JYSB; import com.roomroot.jwgl.entity.KSBZXM; import com.roomroot.jwgl.entity.XYDB; import com.roomroot.jwgl.entity.XYXX; +import com.roomroot.jwgl.entity.ZYB; +import com.roomroot.jwgl.entity.ZYJXJHB; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; @@ -386,6 +389,144 @@ public class ExcelParseUtil { return result; } + /** + * 解析教员管理导入 Excel 文件(支持 .xls / .xlsx)。 + *

表头顺序:

+ * 教员编号, 教员姓名, 教研室代号, 职称, 专业技术职务等级, 教员类别, + * 性别, 手机号, 身份证号, 备注, 序号, 虚实类型 + * + * @return 教员实体列表(离职状态由业务层默认填充) + * @throws Exception 解析异常 + */ + public static List parseJYBExcel(InputStream inputStream, String fileName) throws Exception { + List result = new ArrayList<>(); + Workbook workbook = createWorkbook(inputStream, fileName); + try { + Sheet sheet = workbook.getSheetAt(0); + int lastRowNum = sheet.getLastRowNum(); + for (int rowNum = 1; rowNum <= lastRowNum; rowNum++) { + Row row = sheet.getRow(rowNum); + if (row == null) { + continue; + } + JYB entity = new JYB(); + entity.setJybh(getCellStringValue(row.getCell(0))); + entity.setJyxm(getCellStringValue(row.getCell(1))); + entity.setJysdh(getCellStringValue(row.getCell(2))); + entity.setZc(getCellStringValue(row.getCell(3))); + entity.setZyjszwdj(getCellStringValue(row.getCell(4))); + entity.setJylb(getCellStringValue(row.getCell(5))); + entity.setXb(parseIntCell(row.getCell(6))); + entity.setSjh(getCellStringValue(row.getCell(7))); + entity.setSfzh(getCellStringValue(row.getCell(8))); + entity.setBz(getCellStringValue(row.getCell(9))); + entity.setXh(getCellStringValue(row.getCell(10))); + entity.setXslx(parseIntCell(row.getCell(11))); + // 至少要有姓名才视为有效行 + if (entity.getJyxm() != null && !entity.getJyxm().isEmpty()) { + result.add(entity); + } + } + } finally { + workbook.close(); + } + return result; + } + + /** + * 解析培养方案(专业表)导入 Excel 文件(支持 .xls / .xlsx)。 + *

表头顺序:

+ * 专业代号, 专业名称, 专业代码, 专业版本, 培训类型, 培训层次, 学年制, 学期数, + * 专业方向, 专业备注, 学员类别, 简称, 培训类型2 + * + * @return 专业实体列表 + * @throws Exception 解析异常 + */ + public static List parseZYBExcel(InputStream inputStream, String fileName) throws Exception { + List result = new ArrayList<>(); + Workbook workbook = createWorkbook(inputStream, fileName); + try { + Sheet sheet = workbook.getSheetAt(0); + int lastRowNum = sheet.getLastRowNum(); + for (int rowNum = 1; rowNum <= lastRowNum; rowNum++) { + Row row = sheet.getRow(rowNum); + if (row == null) { + continue; + } + ZYB entity = new ZYB(); + entity.setZydh(getCellStringValue(row.getCell(0))); + entity.setZymc(getCellStringValue(row.getCell(1))); + entity.setZydm(getCellStringValue(row.getCell(2))); + entity.setZybb(getCellStringValue(row.getCell(3))); + entity.setPxlx(getCellStringValue(row.getCell(4))); + entity.setPxcc(getCellStringValue(row.getCell(5))); + entity.setXnz(getCellStringValue(row.getCell(6))); + entity.setXqs(parseIntCell(row.getCell(7))); + entity.setZyfx(getCellStringValue(row.getCell(8))); + entity.setZybz(getCellStringValue(row.getCell(9))); + entity.setXylb(getCellStringValue(row.getCell(10))); + entity.setJc(getCellStringValue(row.getCell(11))); + entity.setPxlx2(getCellStringValue(row.getCell(12))); + // 至少要有专业代号或名称才视为有效行 + if (entity.getZydh() != null && !entity.getZydh().isEmpty() + || entity.getZymc() != null && !entity.getZymc().isEmpty()) { + result.add(entity); + } + } + } finally { + workbook.close(); + } + return result; + } + + /** + * 解析专业教学计划表导入 Excel 文件(支持 .xls / .xlsx)。 + *

表头顺序:

+ * 专业代号, 课编号, 学期第次, 课类型, 学时, 学分, 周课时, 课程定位, + * 模块, 成绩分制, 理论学时, 实践学时, 考试课时, 教研室代号, 简称 + * + * @return 专业教学计划实体列表 + * @throws Exception 解析异常 + */ + public static List parseZYJXJHBExcel(InputStream inputStream, String fileName) throws Exception { + List result = new ArrayList<>(); + Workbook workbook = createWorkbook(inputStream, fileName); + try { + Sheet sheet = workbook.getSheetAt(0); + int lastRowNum = sheet.getLastRowNum(); + for (int rowNum = 1; rowNum <= lastRowNum; rowNum++) { + Row row = sheet.getRow(rowNum); + if (row == null) { + continue; + } + ZYJXJHB entity = new ZYJXJHB(); + entity.setZydh(getCellStringValue(row.getCell(0))); + entity.setKbh(getCellStringValue(row.getCell(1))); + entity.setXqdc(parseIntCell(row.getCell(2))); + entity.setKlx(getCellStringValue(row.getCell(3))); + entity.setXs(parseIntCell(row.getCell(4))); + entity.setXf(parseFloatCell(row.getCell(5))); + entity.setZks(parseIntCell(row.getCell(6))); + entity.setKcdw(getCellStringValue(row.getCell(7))); + entity.setMk(getCellStringValue(row.getCell(8))); + entity.setCjfz(getCellStringValue(row.getCell(9))); + entity.setLlxs(parseIntCell(row.getCell(10))); + entity.setSjxs(parseIntCell(row.getCell(11))); + entity.setKsks(parseIntCell(row.getCell(12))); + entity.setJysdh(getCellStringValue(row.getCell(13))); + entity.setJc(getCellStringValue(row.getCell(14))); + // 至少要有专业代号或课编号才视为有效行 + if (entity.getZydh() != null && !entity.getZydh().isEmpty() + || entity.getKbh() != null && !entity.getKbh().isEmpty()) { + result.add(entity); + } + } + } finally { + workbook.close(); + } + return result; + } + private static Workbook createWorkbook(InputStream inputStream, String fileName) throws Exception { String name = fileName == null ? "" : fileName.toLowerCase(); if (!name.endsWith(".xlsx") && !name.endsWith(".xls")) { @@ -426,6 +567,21 @@ public class ExcelParseUtil { } } + /** + * 解析单元格浮点数值。 + */ + private static Float parseFloatCell(Cell cell) { + String value = getCellStringValue(cell); + if (value == null || value.isEmpty()) { + return null; + } + try { + return Float.valueOf(value); + } catch (NumberFormatException e) { + return null; + } + } + private static String getCellStringValue(Cell cell) { if (cell == null) { return null; diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/utils/JwglRoleHelper.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/utils/JwglRoleHelper.java index 9e886ae05..501d3f1e5 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/utils/JwglRoleHelper.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/utils/JwglRoleHelper.java @@ -9,9 +9,11 @@ import com.roomroot.common.exception.ServiceException; import com.roomroot.common.utils.SecurityUtils; import com.roomroot.common.utils.StringUtils; import com.roomroot.jwgl.entity.JYB; +import com.roomroot.jwgl.entity.XYDQB; import com.roomroot.jwgl.entity.XYXX; import com.roomroot.jwgl.mapper.JYBMapper; import com.roomroot.jwgl.mapper.JYSDLBMapper; +import com.roomroot.jwgl.mapper.XYDQBMapper; import com.roomroot.jwgl.mapper.XYXXMapper; import org.springframework.stereotype.Component; @@ -40,6 +42,9 @@ public class JwglRoleHelper { @Resource private JYSDLBMapper jysdlbMapper; + @Resource + private XYDQBMapper xydqbMapper; + public boolean isAdmin() { try { if (SecurityUtils.isAdmin()) { @@ -112,6 +117,34 @@ public class JwglRoleHelper { return studentId; } + /** + * 当前学员所属学员队编号。课表按班次过滤时使用。 + */ + public String requireStudentTeamId() { + String teamId = findStudentTeamId(); + if (StringUtils.isEmpty(teamId)) { + throw new ServiceException("当前学员未分班,无法查看课表", FORBIDDEN); + } + return teamId; + } + + public String findStudentTeamId() { + try { + String studentId = findStudentId(); + if (StringUtils.isEmpty(studentId)) { + return null; + } + XYXX student = xyxxMapper.selectById(studentId); + if (student == null || StringUtils.isEmpty(student.getXydqbh())) { + return null; + } + XYDQB period = xydqbMapper.selectById(student.getXydqbh()); + return period == null ? null : period.getXydbh(); + } catch (Exception ignored) { + return null; + } + } + public String findTeacherId() { try { String username = SecurityUtils.getUsername(); diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/utils/UuidUtil.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/utils/UuidUtil.java index b36195a01..9b6d8e13d 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/utils/UuidUtil.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/utils/UuidUtil.java @@ -37,4 +37,42 @@ public class UuidUtil { public static String getUuidWithPrefix(String prefix) { return prefix + getUUID(); } + + /** + * 将 32 位十六进制或 36 位带横线 UUID 转为 16 字节,供达梦 VARBINARY 主键写入。 + */ + public static byte[] toBytes(String guid) { + if (guid == null) { + return null; + } + String hex = guid.trim().replace("-", ""); + if (hex.length() < 32) { + throw new IllegalArgumentException("GUID hex length must be 32, actual=" + hex.length()); + } + hex = hex.substring(0, 32); + byte[] out = new byte[16]; + for (int i = 0; i < 16; i++) { + out[i] = (byte) Integer.parseInt(hex.substring(i * 2, i * 2 + 2), 16); + } + return out; + } + + /** + * 将 VARBINARY(16) 转为带横线的 36 位 UUID,与 CHAR(36) 外键存储格式一致。 + */ + public static String fromBytes(byte[] bytes) { + if (bytes == null || bytes.length == 0) { + return null; + } + StringBuilder hex = new StringBuilder(bytes.length * 2); + for (byte value : bytes) { + hex.append(String.format("%02x", value)); + } + String h = hex.toString(); + if (h.length() < 32) { + return h; + } + return h.substring(0, 8) + "-" + h.substring(8, 12) + "-" + h.substring(12, 16) + + "-" + h.substring(16, 20) + "-" + h.substring(20, 32); + } } \ No newline at end of file diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/courserunning/ScheduleAdjustApplyVO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/courserunning/ScheduleAdjustApplyVO.java index 2aa18ea18..8ac467416 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/courserunning/ScheduleAdjustApplyVO.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/courserunning/ScheduleAdjustApplyVO.java @@ -24,8 +24,29 @@ public class ScheduleAdjustApplyVO { */ private String sskcbbh; + /** 学员队任务表编号 */ + private String xydrwbh; + + /** 课编号 */ + private String kbh; + + /** 课程表编号 */ + private String kcbbh; + + /** 学员队名称 */ + private String xydmc; + + /** 教研室代号 */ + private String jysdh; + + /** 原教室编号 */ + private String yjsbh; + + /** 拟调整教室编号 */ + private String xjsbh; + /** - * 课程名称,关联课程表获取。 + * 课程名称,关联课表获取。 */ private String kcmc; @@ -79,11 +100,6 @@ public class ScheduleAdjustApplyVO { */ private Integer jyscszt; - /** - * 机关审批状态:0-未审批,1-已同意,2-已发回,3-已拒绝。 - */ - private Integer jgspzt; - /** * 发回意见。 */ diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/courserunning/ScheduleAdjustAuditVO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/courserunning/ScheduleAdjustAuditVO.java deleted file mode 100644 index 5c19db213..000000000 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/courserunning/ScheduleAdjustAuditVO.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.roomroot.jwgl.vo.courserunning; - -import lombok.Data; - -import java.time.LocalDateTime; - -/** - * 调课申请审批记录展示数据。 - *

- * 用于展示调课申请中机关审批环节的审批记录,包括机关编号、审批时间、 - * 审批状态、审批人、查收状态、发回意见等信息。 - *

- */ -@Data -public class ScheduleAdjustAuditVO { - - /** - * 审批记录编号。 - */ - private String bh; - - /** - * 调课申请编号。 - */ - private String ssdksqbh; - - /** - * 机关编号。 - */ - private String jgbh; - - /** - * 机关名称(关联机构表获取)。 - */ - private String jgmc; - - /** - * 审批时间。 - */ - private LocalDateTime spsj; - - /** - * 审批状态:0-未审批,1-已同意,2-已发回,3-已拒绝。 - */ - private Integer spzt; - - /** - * 审批人编号。 - */ - private String sprbh; - - /** - * 审批人姓名(关联教员表获取)。 - */ - private String sprxm; - - /** - * 查收状态:0-未查收,1-已查收。 - */ - private Integer cszt; - - /** - * 查收时间。 - */ - private LocalDateTime cssj; - - /** - * 查收人编号。 - */ - private String csrbh; - - /** - * 发回意见。 - */ - private String fhyj; - - /** - * 年度。 - */ - private Integer nd; -} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/courserunning/ScheduleAdjustDetailVO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/courserunning/ScheduleAdjustDetailVO.java index e2cfec1cc..beab837c9 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/courserunning/ScheduleAdjustDetailVO.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/courserunning/ScheduleAdjustDetailVO.java @@ -10,7 +10,7 @@ import java.util.List; *

* 用于展示调课申请的完整信息,包括课次信息、申请教员、调整后的日期节次、 * 教学内容变更、新的教室列表、辅助教员列表、学员队列表、保障明细列表, - * 以及教研室和机关的审批记录。 + * 以及教研室审批与查收信息。 *

*/ @Data @@ -26,6 +26,27 @@ public class ScheduleAdjustDetailVO { */ private String sskcbbh; + /** 学员队任务表编号 */ + private String xydrwbh; + + /** 课编号 */ + private String kbh; + + /** 课程表编号 */ + private String kcbbh; + + /** 学员队名称 */ + private String xydmc; + + /** 教研室代号 */ + private String jysdh; + + /** 原教室编号 */ + private String yjsbh; + + /** 拟调整教室编号 */ + private String xjsbh; + /** * 课程名称。 */ @@ -127,14 +148,14 @@ public class ScheduleAdjustDetailVO { private LocalDateTime jyscssj; /** - * 教研室查收人编号。 + * 教研室查收人编号,与审批人为同一人。 */ private String jyscsrbh; /** - * 机关审批列表,记录所有机关审批结果。 + * 发回意见。 */ - private List auditList; + private String fhyj; /** * 新教室列表。 diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/courserunning/ScheduleAdjustStrategyVO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/courserunning/ScheduleAdjustStrategyVO.java deleted file mode 100644 index d035090d1..000000000 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/courserunning/ScheduleAdjustStrategyVO.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.roomroot.jwgl.vo.courserunning; - -import lombok.Data; - -import java.time.LocalDateTime; - -/** - * 调课策略展示VO。 - */ -@Data -public class ScheduleAdjustStrategyVO { - - /** 策略编号 */ - private String clbh; - - /** 策略名称 */ - private String clmc; - - /** 策略类型:TIME_LIMIT=时间段限制,AUTO_APPROVE=免审批 */ - private String cllx; - - /** 策略类型描述 */ - private String cllxDesc; - - /** 是否启用:0=停用,1=启用 */ - private Integer sfqy; - - /** 是否启用描述 */ - private String sfqyDesc; - - /** 截止星期:0-6 */ - private Integer jzxq; - - /** 截止星期描述 */ - private String jzxqDesc; - - /** 截止节次 */ - private Integer jzjc; - - /** 生效开始时间 */ - private LocalDateTime sxkssj; - - /** 生效结束时间 */ - private LocalDateTime sxjssj; - - /** 备注 */ - private String bz; - - /** 创建时间 */ - private LocalDateTime cjsj; - - /** 更新时间 */ - private LocalDateTime gxsj; -} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jwtest/PkConflictCheckVO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jwtest/PkConflictCheckVO.java new file mode 100644 index 000000000..e6eb7da85 --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jwtest/PkConflictCheckVO.java @@ -0,0 +1,24 @@ +package com.roomroot.jwgl.vo.jwtest; + +import lombok.Data; + +import java.util.List; + +/** + * 一类冲突检查结果。 + */ +@Data +public class PkConflictCheckVO { + + /** 冲突类型 */ + private String ctlx; + + /** 检查说明 */ + private String jcsm; + + /** 冲突条数 */ + private Integer ts; + + /** 成对冲突明细 */ + private List mx; +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jwtest/PkConflictVO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jwtest/PkConflictVO.java new file mode 100644 index 000000000..4031a6c68 --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jwtest/PkConflictVO.java @@ -0,0 +1,73 @@ +package com.roomroot.jwgl.vo.jwtest; + +import lombok.Data; + +/** + * 排课冲突成对明细:一条记录表示两门课在同一时间资源上互相冲突。 + */ +@Data +public class PkConflictVO { + + /** 冲突类型 */ + private String ctlx; + + /** 冲突资源(班次 / 教员 / 教室) */ + private String ctzy; + + /** 上课日期 */ + private String skrq; + + /** 节次 */ + private Integer jc; + + /** 开始时间 */ + private String kssj; + + /** 结束时间 */ + private String jssj; + + /** 冲突说明 */ + private String sm; + + /** 课次A编号 */ + private String aKcBh; + + /** 课次A课堂名称 */ + private String aKtmc; + + /** 课次A课程名称 */ + private String aKcmc; + + /** 课次A课程类型 */ + private String aKclx; + + /** 课次A教员名称 */ + private String aJymc; + + /** 课次A班级名称 */ + private String aBjmc; + + /** 课次A教室名称 */ + private String aJsmc; + + /** 课次B编号 */ + private String bKcBh; + + /** 课次B课堂名称 */ + private String bKtmc; + + /** 课次B课程名称 */ + private String bKcmc; + + /** 课次B课程类型 */ + private String bKclx; + + /** 课次B教员名称 */ + private String bJymc; + + /** 课次B班级名称 */ + private String bBjmc; + + /** 课次B教室名称 */ + private String bJsmc; +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jwtest/PkLessonVO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jwtest/PkLessonVO.java new file mode 100644 index 000000000..de900ccca --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jwtest/PkLessonVO.java @@ -0,0 +1,45 @@ +package com.roomroot.jwgl.vo.jwtest; + +import lombok.Data; + +/** + * 排课全查明细(课堂、课程、教师、班级、教室及上课时间)。 + */ +@Data +public class PkLessonVO { + + /** 课堂名称 */ + private String ktmc; + + /** 课程名称 */ + private String kcmc; + /** 教学楼名称 */ + private String jxlmc; + + /** 教师名称 */ + private String jymc; + + /** 班级名称 */ + private String bjmc; + + /** 教室名称 */ + private String jsmc; + + /** 上课日期 */ + private String skrq; + + /** 开始时间 */ + private String kssj; + + /** 结束时间 */ + private String jssj; + + /** 学年学期 */ + private String xnxq; + + /** 周次 */ + private Integer zc; + + /** 应到人数 */ + private Integer ydrs; +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jys/ElectiveCourseStudentVO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jys/ElectiveCourseStudentVO.java new file mode 100644 index 000000000..4dc55eabd --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jys/ElectiveCourseStudentVO.java @@ -0,0 +1,32 @@ +package com.roomroot.jwgl.vo.jys; + +import com.roomroot.common.annotation.Excel; +import lombok.Data; + +/** + * 选修班学员名单行。 + */ +@Data +public class ElectiveCourseStudentVO { + + @Excel(name = "序号", sort = 1) + private Integer xh; + + @Excel(name = "选修班名称", sort = 2) + private String xxbmc; + + @Excel(name = "课程", sort = 3) + private String kmc; + + @Excel(name = "学号", sort = 4) + private String xhNo; + + @Excel(name = "姓名", sort = 5) + private String xm; + + @Excel(name = "性别", sort = 6) + private String xb; + + @Excel(name = "联系电话", sort = 7) + private String lxdh; +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jys/ElectiveCourseVO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jys/ElectiveCourseVO.java new file mode 100644 index 000000000..e477ade43 --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jys/ElectiveCourseVO.java @@ -0,0 +1,80 @@ +package com.roomroot.jwgl.vo.jys; + +import com.roomroot.common.annotation.Excel; +import lombok.Data; + +/** + * 选修课管理列表行。 + */ +@Data +public class ElectiveCourseVO { + + /** 学员队任务编号 */ + private String bh; + + /** 年度 */ + private Integer nd; + + /** 学员队编号 */ + private String xydbh; + + /** 课编号 */ + private String kbh; + + /** 教员编号 */ + private String jybh; + + /** 教室编号 */ + private String jsbh; + + @Excel(name = "序号", sort = 1) + private Integer xh; + + @Excel(name = "课程", sort = 2) + private String kmc; + + @Excel(name = "教材", sort = 3) + private String jcmc; + + @Excel(name = "实施教员", sort = 4) + private String jyxm; + + @Excel(name = "教学场地", sort = 5) + private String jsmc; + + @Excel(name = "显示可选队列班次", sort = 6, width = 28) + private String kxdlbc; + + /** 计划学时 */ + private Integer jhxs; + + /** 运行学时 */ + private Integer yxxs; + + /** 学分 */ + private Float xf; + + @Excel(name = "计划学时/运行学时/学分", sort = 7, width = 24) + private String jhyxxsxf; + + @Excel(name = "开课结课日期", sort = 8, width = 24) + private String kkjkrq; + + @Excel(name = "报名日期", sort = 9, width = 24) + private String bmrq; + + @Excel(name = "计划人数", sort = 10) + private Integer jhrs; + + @Excel(name = "要求说明", sort = 11, width = 24) + private String yqsm; + + @Excel(name = "选修班名称", sort = 12) + private String xxbmc; + + @Excel(name = "选择课状态", sort = 13) + private String xkzt; + + @Excel(name = "培训层次", sort = 14) + private String pxcc; +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jys/TeachingOfficeBookCourseVO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jys/TeachingOfficeBookCourseVO.java new file mode 100644 index 000000000..6b916bb4f --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jys/TeachingOfficeBookCourseVO.java @@ -0,0 +1,28 @@ +package com.roomroot.jwgl.vo.jys; + +import lombok.Data; + +/** + * 教研室任务书课程明细。 + */ +@Data +public class TeachingOfficeBookCourseVO { + + private String rwbh; + + private String kbh; + + private String kmc; + + private String klx; + + private Integer xs; + + private String xydbh; + + private String xydmc; + + private String jysjhjybh; + + private String jysjhjyxm; +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jys/TeachingOfficeBookVO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jys/TeachingOfficeBookVO.java new file mode 100644 index 000000000..f27211276 --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jys/TeachingOfficeBookVO.java @@ -0,0 +1,32 @@ +package com.roomroot.jwgl.vo.jys; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 教研室任务书列表行。 + */ +@Data +public class TeachingOfficeBookVO { + + private String bh; + + private String jxrwbh; + + private String jysdh; + + private String jysmc; + + private String zt; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime sbsj; + + /** 学员队课程任务数 */ + private Integer xydkcrws; + + /** 完成指定数(已指定计划教员的课程任务数) */ + private Integer wczds; +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jys/TeachingTaskDetailVO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jys/TeachingTaskDetailVO.java new file mode 100644 index 000000000..396140306 --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jys/TeachingTaskDetailVO.java @@ -0,0 +1,19 @@ +package com.roomroot.jwgl.vo.jys; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * 教学任务详情(含教研室任务书、学员队两个页签数据)。 + */ +@Data +public class TeachingTaskDetailVO { + + private TeachingTaskVO task; + + private List officeBooks = new ArrayList<>(); + + private List squads = new ArrayList<>(); +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jys/TeachingTaskSquadVO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jys/TeachingTaskSquadVO.java new file mode 100644 index 000000000..142fc3446 --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jys/TeachingTaskSquadVO.java @@ -0,0 +1,41 @@ +package com.roomroot.jwgl.vo.jys; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.time.LocalDate; + +/** + * 教学任务关联的学员队(班次)行。 + */ +@Data +public class TeachingTaskSquadVO { + + /** 学员队年度学期基本信息编号 */ + private String xydxqbh; + + private String xydbh; + + private String xydmc; + + private String nj; + + private String zydh; + + private String zymc; + + private Integer xydrs; + + private Integer nd; + + private Integer xqdc; + + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + private LocalDate kxrq; + + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + private LocalDate jsrq; + + /** 是否已被其他教学任务占用 */ + private Integer occupied; +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jys/TeachingTaskVO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jys/TeachingTaskVO.java new file mode 100644 index 000000000..3016244d2 --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/jys/TeachingTaskVO.java @@ -0,0 +1,53 @@ +package com.roomroot.jwgl.vo.jys; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 教学任务列表行。 + */ +@Data +public class TeachingTaskVO { + + private String bh; + + private String rwmc; + + private Integer nd; + + private Integer xqdc; + + /** 学期名称,如 2026年春季学期 */ + private String xqmc; + + private String zt; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime fbsj; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime cjsj; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime jssj; + + /** 教研室数 */ + private Integer jyss; + + /** 学员队数 */ + private Integer xyds; + + /** 合班前课程任务数 */ + private Integer hbqkcrws; + + /** 合班前总学时数 */ + private Integer hbqzxs; + + /** 合班后课程任务数 */ + private Integer hbhkcrws; + + /** 合班后总学时数 */ + private Integer hbhzxs; +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/kcb/ClassTimetableVO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/kcb/ClassTimetableVO.java new file mode 100644 index 000000000..addd3a3fe --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/kcb/ClassTimetableVO.java @@ -0,0 +1,38 @@ +package com.roomroot.jwgl.vo.kcb; + +import com.roomroot.common.annotation.Excel; +import lombok.Data; + +/** + * 班次课表行。 + */ +@Data +public class ClassTimetableVO { + + /** 实施_课程编号 */ + private String sskcbh; + + @Excel(name = "课程名称/课时系数", sort = 1, width = 28) + private String kcmcksxs; + + @Excel(name = "责任教员/课次", sort = 2, width = 20) + private String zrjykc; + + @Excel(name = "计划学时", sort = 3) + private Integer jhxs; + + @Excel(name = "运行学时", sort = 4) + private Integer yxxs; + + @Excel(name = "考核类型方式", sort = 5, width = 16) + private String khlxfs; + + @Excel(name = "实施教员", sort = 6, width = 16) + private String ssjy; + + @Excel(name = "人数/场地", sort = 7, width = 22) + private String rscd; + + @Excel(name = "实施计划变更", sort = 8, width = 28) + private String ssjhbg; +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/kcb/DailyWeeklyTimetableVO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/kcb/DailyWeeklyTimetableVO.java new file mode 100644 index 000000000..f270dfc96 --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/kcb/DailyWeeklyTimetableVO.java @@ -0,0 +1,38 @@ +package com.roomroot.jwgl.vo.kcb; + +import com.roomroot.common.annotation.Excel; +import lombok.Data; + +/** + * 今日课表、本周课表、学期教学实施计划行。 + */ +@Data +public class DailyWeeklyTimetableVO { + + /** 实施_课程表编号 */ + private String bh; + + @Excel(name = "上课时间", sort = 1, width = 22) + private String sksj; + + @Excel(name = "课程", sort = 2, width = 20) + private String kc; + + @Excel(name = "责任单位", sort = 3, width = 18) + private String zrdw; + + @Excel(name = "班次", sort = 4, width = 24) + private String bc; + + @Excel(name = "教员", sort = 5, width = 16) + private String jy; + + @Excel(name = "场地", sort = 6, width = 18) + private String cd; + + @Excel(name = "教学内容方法", sort = 7, width = 28) + private String jxnrxff; + + @Excel(name = "备注", sort = 8, width = 20) + private String bz; +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/kcb/SemesterGradeExportVO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/kcb/SemesterGradeExportVO.java new file mode 100644 index 000000000..17b137cb7 --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/kcb/SemesterGradeExportVO.java @@ -0,0 +1,35 @@ +package com.roomroot.jwgl.vo.kcb; + +import com.roomroot.common.annotation.Excel; +import lombok.Data; + +/** + * 学期成绩表导出行。 + */ +@Data +public class SemesterGradeExportVO { + + @Excel(name = "学号", sort = 1) + private String xh; + + @Excel(name = "姓名", sort = 2) + private String xm; + + @Excel(name = "课程", sort = 3, width = 20) + private String kcmc; + + @Excel(name = "平时成绩", sort = 4) + private Float pscj; + + @Excel(name = "考试成绩", sort = 5) + private Float kscj; + + @Excel(name = "最终成绩", sort = 6) + private Float zzcj; + + @Excel(name = "考试情况", sort = 7) + private String ksqk; + + @Excel(name = "年度", sort = 8) + private Integer nd; +} diff --git a/frontend/.editorconfig b/frontend/.editorconfig deleted file mode 100644 index 7034f9bf3..000000000 --- a/frontend/.editorconfig +++ /dev/null @@ -1,22 +0,0 @@ -# 告诉EditorConfig插件,这是根文件,不用继续往上查找 -root = true - -# 匹配全部文件 -[*] -# 设置字符集 -charset = utf-8 -# 缩进风格,可选space、tab -indent_style = space -# 缩进的空格数 -indent_size = 2 -# 结尾换行符,可选lf、cr、crlf -end_of_line = lf -# 在文件结尾插入新行 -insert_final_newline = true -# 删除一行中的前后空格 -trim_trailing_whitespace = true - -# 匹配md结尾的文件 -[*.md] -insert_final_newline = false -trim_trailing_whitespace = false diff --git a/frontend/.env.development b/frontend/.env.development deleted file mode 100644 index fb464bb0f..000000000 --- a/frontend/.env.development +++ /dev/null @@ -1,11 +0,0 @@ -# 页面标题 -VUE_APP_TITLE = 教学管理信息系统 - -# 开发环境配置 -ENV = 'development' - -# 智慧教学管理系统/开发环境 -VUE_APP_BASE_API = '/api' - -# 路由懒加载 -VUE_CLI_BABEL_TRANSPILE_MODULES = true diff --git a/frontend/.env.production b/frontend/.env.production deleted file mode 100644 index 7c56c11b2..000000000 --- a/frontend/.env.production +++ /dev/null @@ -1,8 +0,0 @@ -# 页面标题 -VUE_APP_TITLE = 教学管理信息系统 - -# 生产环境配置 -ENV = 'production' - -# 智慧教学管理系统/生产环境 -VUE_APP_BASE_API = '/prod-api' diff --git a/frontend/.env.staging b/frontend/.env.staging deleted file mode 100644 index 4ee3bc134..000000000 --- a/frontend/.env.staging +++ /dev/null @@ -1,12 +0,0 @@ -# 页面标题 -VUE_APP_TITLE = 教学管理信息系统 - -BABEL_ENV = production - -NODE_ENV = production - -# 测试环境配置 -ENV = 'staging' - -# 智慧教学管理系统/测试环境 -VUE_APP_BASE_API = '/stage-api' diff --git a/frontend/.gitignore b/frontend/.gitignore deleted file mode 100644 index 78a752d87..000000000 --- a/frontend/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -.DS_Store -node_modules/ -dist/ -npm-debug.log* -yarn-debug.log* -yarn-error.log* -**/*.log - -tests/**/coverage/ -tests/e2e/reports -selenium-debug.log - -# Editor directories and files -.idea -.vscode -*.suo -*.ntvs* -*.njsproj -*.sln -*.local - -package-lock.json -yarn.lock diff --git a/frontend/README.md b/frontend/README.md deleted file mode 100644 index 00c0ab84f..000000000 --- a/frontend/README.md +++ /dev/null @@ -1,30 +0,0 @@ -## 开发 - -```bash -# 克隆项目 -git clone https://gitee.com/y_project/RuoYi-Vue - -# 进入项目目录 -cd ruoyi-ui - -# 安装依赖 -npm install - -# 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题 -npm install --registry=https://registry.npmmirror.com - -# 启动服务 -npm run dev -``` - -浏览器访问 http://localhost:80 - -## 发布 - -```bash -# 构建测试环境 -npm run build:stage - -# 构建生产环境 -npm run build:prod -``` \ No newline at end of file diff --git a/frontend/babel.config.js b/frontend/babel.config.js deleted file mode 100644 index 5aa05ebbe..000000000 --- a/frontend/babel.config.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - presets: [ - // https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app - '@vue/cli-plugin-babel/preset' - ], - 'env': { - 'development': { - // babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require(). - // This plugin can significantly increase the speed of hot updates, when you have a large number of pages. - 'plugins': ['dynamic-import-node'] - } - } -} \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json deleted file mode 100644 index 480910541..000000000 --- a/frontend/package.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "name": "roomroot", - "version": "3.9.2", - "description": "教学管理信息系统", - "author": "教务", - "license": "MIT", - "scripts": { - "dev": "vue-cli-service serve", - "build:prod": "vue-cli-service build", - "build:stage": "vue-cli-service build --mode staging", - "preview": "node build/index.js --preview", - "dict:init-course-type": "node scripts/init-course-type-dict.js" - }, - "keywords": [ - "vue", - "admin", - "dashboard", - "element-ui", - "boilerplate", - "admin-template", - "management-system" - ], - "repository": { - "type": "git", - "url": "https://gitee.com/y_project/roomroot-Vue.git" - }, - "dependencies": { - "@riophae/vue-treeselect": "0.4.0", - "axios": "0.30.3", - "clipboard": "2.0.8", - "core-js": "3.37.1", - "echarts": "5.4.0", - "element-ui": "2.15.14", - "file-saver": "2.0.5", - "fuse.js": "6.4.3", - "highlight.js": "9.18.5", - "js-beautify": "1.13.0", - "js-cookie": "3.0.1", - "jsencrypt": "3.0.0-rc.1", - "nprogress": "0.2.0", - "quill": "2.0.2", - "screenfull": "5.0.2", - "sortablejs": "1.10.2", - "vue": "2.6.12", - "vue-count-to": "1.0.13", - "vue-cropper": "0.5.5", - "vue-router": "3.4.9", - "vuedraggable": "2.24.3", - "vuex": "3.6.0" - }, - "devDependencies": { - "@vue/cli-plugin-babel": "4.4.6", - "@vue/cli-service": "4.4.6", - "babel-plugin-dynamic-import-node": "2.3.3", - "chalk": "4.1.0", - "compression-webpack-plugin": "6.1.2", - "connect": "3.6.6", - "sass": "1.32.13", - "sass-loader": "10.1.1", - "script-ext-html-webpack-plugin": "2.1.5", - "svg-sprite-loader": "5.1.1", - "vue-template-compiler": "2.6.12" - }, - "engines": { - "node": ">=8.9", - "npm": ">= 3.0.0" - }, - "browserslist": [ - "> 1%", - "last 2 versions" - ] -} diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico deleted file mode 100644 index ea4750d0c..000000000 Binary files a/frontend/public/favicon.ico and /dev/null differ diff --git a/frontend/public/html/ie.html b/frontend/public/html/ie.html deleted file mode 100644 index b6634d12e..000000000 --- a/frontend/public/html/ie.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - 请升级您的浏览器 - - - - - - -

请升级您的浏览器,以便我们更好的为您提供服务!

-

您正在使用 Internet Explorer 的早期版本(IE11以下版本或使用该内核的浏览器)。这意味着在升级浏览器前,您将无法访问此网站。

-
-

请注意:微软公司对Windows XP 及 Internet Explorer 早期版本的支持已经结束

-

自 2016 年 1 月 12 日起,Microsoft 不再为 IE 11 以下版本提供相应支持和更新。没有关键的浏览器安全更新,您的电脑可能易受有害病毒、间谍软件和其他恶意软件的攻击,它们可以窃取或损害您的业务数据和信息。请参阅 微软对 Internet Explorer 早期版本的支持将于 2016 年 1 月 12 日结束的说明 。

-
-

您可以选择更先进的浏览器

-

推荐使用以下浏览器的最新版本。如果您的电脑已有以下浏览器的最新版本则直接使用该浏览器访问即可。

- -
- - \ No newline at end of file diff --git a/frontend/public/index.html b/frontend/public/index.html deleted file mode 100644 index 709bfe0e5..000000000 --- a/frontend/public/index.html +++ /dev/null @@ -1,208 +0,0 @@ - - - - - - - - - <%= webpackConfig.name %> - - - - -
-
-
-
-
-
正在加载系统资源,请耐心等待
-
-
- - diff --git a/frontend/public/robots.txt b/frontend/public/robots.txt deleted file mode 100644 index f870a67b1..000000000 --- a/frontend/public/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Disallow: / \ No newline at end of file diff --git a/frontend/public/styles/theme-chalk/index.css b/frontend/public/styles/theme-chalk/index.css deleted file mode 100644 index 6a6ac1da1..000000000 --- a/frontend/public/styles/theme-chalk/index.css +++ /dev/null @@ -1 +0,0 @@ -@charset "UTF-8";[class*=" el-icon-"],[class^=el-icon-]{font-family:element-icons!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;vertical-align:baseline;display:inline-block;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-icon-ice-cream-round:before{content:"\e6a0"}.el-icon-ice-cream-square:before{content:"\e6a3"}.el-icon-lollipop:before{content:"\e6a4"}.el-icon-potato-strips:before{content:"\e6a5"}.el-icon-milk-tea:before{content:"\e6a6"}.el-icon-ice-drink:before{content:"\e6a7"}.el-icon-ice-tea:before{content:"\e6a9"}.el-icon-coffee:before{content:"\e6aa"}.el-icon-orange:before{content:"\e6ab"}.el-icon-pear:before{content:"\e6ac"}.el-icon-apple:before{content:"\e6ad"}.el-icon-cherry:before{content:"\e6ae"}.el-icon-watermelon:before{content:"\e6af"}.el-icon-grape:before{content:"\e6b0"}.el-icon-refrigerator:before{content:"\e6b1"}.el-icon-goblet-square-full:before{content:"\e6b2"}.el-icon-goblet-square:before{content:"\e6b3"}.el-icon-goblet-full:before{content:"\e6b4"}.el-icon-goblet:before{content:"\e6b5"}.el-icon-cold-drink:before{content:"\e6b6"}.el-icon-coffee-cup:before{content:"\e6b8"}.el-icon-water-cup:before{content:"\e6b9"}.el-icon-hot-water:before{content:"\e6ba"}.el-icon-ice-cream:before{content:"\e6bb"}.el-icon-dessert:before{content:"\e6bc"}.el-icon-sugar:before{content:"\e6bd"}.el-icon-tableware:before{content:"\e6be"}.el-icon-burger:before{content:"\e6bf"}.el-icon-knife-fork:before{content:"\e6c1"}.el-icon-fork-spoon:before{content:"\e6c2"}.el-icon-chicken:before{content:"\e6c3"}.el-icon-food:before{content:"\e6c4"}.el-icon-dish-1:before{content:"\e6c5"}.el-icon-dish:before{content:"\e6c6"}.el-icon-moon-night:before{content:"\e6ee"}.el-icon-moon:before{content:"\e6f0"}.el-icon-cloudy-and-sunny:before{content:"\e6f1"}.el-icon-partly-cloudy:before{content:"\e6f2"}.el-icon-cloudy:before{content:"\e6f3"}.el-icon-sunny:before{content:"\e6f6"}.el-icon-sunset:before{content:"\e6f7"}.el-icon-sunrise-1:before{content:"\e6f8"}.el-icon-sunrise:before{content:"\e6f9"}.el-icon-heavy-rain:before{content:"\e6fa"}.el-icon-lightning:before{content:"\e6fb"}.el-icon-light-rain:before{content:"\e6fc"}.el-icon-wind-power:before{content:"\e6fd"}.el-icon-baseball:before{content:"\e712"}.el-icon-soccer:before{content:"\e713"}.el-icon-football:before{content:"\e715"}.el-icon-basketball:before{content:"\e716"}.el-icon-ship:before{content:"\e73f"}.el-icon-truck:before{content:"\e740"}.el-icon-bicycle:before{content:"\e741"}.el-icon-mobile-phone:before{content:"\e6d3"}.el-icon-service:before{content:"\e6d4"}.el-icon-key:before{content:"\e6e2"}.el-icon-unlock:before{content:"\e6e4"}.el-icon-lock:before{content:"\e6e5"}.el-icon-watch:before{content:"\e6fe"}.el-icon-watch-1:before{content:"\e6ff"}.el-icon-timer:before{content:"\e702"}.el-icon-alarm-clock:before{content:"\e703"}.el-icon-map-location:before{content:"\e704"}.el-icon-delete-location:before{content:"\e705"}.el-icon-add-location:before{content:"\e706"}.el-icon-location-information:before{content:"\e707"}.el-icon-location-outline:before{content:"\e708"}.el-icon-location:before{content:"\e79e"}.el-icon-place:before{content:"\e709"}.el-icon-discover:before{content:"\e70a"}.el-icon-first-aid-kit:before{content:"\e70b"}.el-icon-trophy-1:before{content:"\e70c"}.el-icon-trophy:before{content:"\e70d"}.el-icon-medal:before{content:"\e70e"}.el-icon-medal-1:before{content:"\e70f"}.el-icon-stopwatch:before{content:"\e710"}.el-icon-mic:before{content:"\e711"}.el-icon-copy-document:before{content:"\e718"}.el-icon-full-screen:before{content:"\e719"}.el-icon-switch-button:before{content:"\e71b"}.el-icon-aim:before{content:"\e71c"}.el-icon-crop:before{content:"\e71d"}.el-icon-odometer:before{content:"\e71e"}.el-icon-time:before{content:"\e71f"}.el-icon-bangzhu:before{content:"\e724"}.el-icon-close-notification:before{content:"\e726"}.el-icon-microphone:before{content:"\e727"}.el-icon-turn-off-microphone:before{content:"\e728"}.el-icon-position:before{content:"\e729"}.el-icon-postcard:before{content:"\e72a"}.el-icon-message:before{content:"\e72b"}.el-icon-chat-line-square:before{content:"\e72d"}.el-icon-chat-dot-square:before{content:"\e72e"}.el-icon-chat-dot-round:before{content:"\e72f"}.el-icon-chat-square:before{content:"\e730"}.el-icon-chat-line-round:before{content:"\e731"}.el-icon-chat-round:before{content:"\e732"}.el-icon-set-up:before{content:"\e733"}.el-icon-turn-off:before{content:"\e734"}.el-icon-open:before{content:"\e735"}.el-icon-connection:before{content:"\e736"}.el-icon-link:before{content:"\e737"}.el-icon-cpu:before{content:"\e738"}.el-icon-thumb:before{content:"\e739"}.el-icon-female:before{content:"\e73a"}.el-icon-male:before{content:"\e73b"}.el-icon-guide:before{content:"\e73c"}.el-icon-news:before{content:"\e73e"}.el-icon-price-tag:before{content:"\e744"}.el-icon-discount:before{content:"\e745"}.el-icon-wallet:before{content:"\e747"}.el-icon-coin:before{content:"\e748"}.el-icon-money:before{content:"\e749"}.el-icon-bank-card:before{content:"\e74a"}.el-icon-box:before{content:"\e74b"}.el-icon-present:before{content:"\e74c"}.el-icon-sell:before{content:"\e6d5"}.el-icon-sold-out:before{content:"\e6d6"}.el-icon-shopping-bag-2:before{content:"\e74d"}.el-icon-shopping-bag-1:before{content:"\e74e"}.el-icon-shopping-cart-2:before{content:"\e74f"}.el-icon-shopping-cart-1:before{content:"\e750"}.el-icon-shopping-cart-full:before{content:"\e751"}.el-icon-smoking:before{content:"\e752"}.el-icon-no-smoking:before{content:"\e753"}.el-icon-house:before{content:"\e754"}.el-icon-table-lamp:before{content:"\e755"}.el-icon-school:before{content:"\e756"}.el-icon-office-building:before{content:"\e757"}.el-icon-toilet-paper:before{content:"\e758"}.el-icon-notebook-2:before{content:"\e759"}.el-icon-notebook-1:before{content:"\e75a"}.el-icon-files:before{content:"\e75b"}.el-icon-collection:before{content:"\e75c"}.el-icon-receiving:before{content:"\e75d"}.el-icon-suitcase-1:before{content:"\e760"}.el-icon-suitcase:before{content:"\e761"}.el-icon-film:before{content:"\e763"}.el-icon-collection-tag:before{content:"\e765"}.el-icon-data-analysis:before{content:"\e766"}.el-icon-pie-chart:before{content:"\e767"}.el-icon-data-board:before{content:"\e768"}.el-icon-data-line:before{content:"\e76d"}.el-icon-reading:before{content:"\e769"}.el-icon-magic-stick:before{content:"\e76a"}.el-icon-coordinate:before{content:"\e76b"}.el-icon-mouse:before{content:"\e76c"}.el-icon-brush:before{content:"\e76e"}.el-icon-headset:before{content:"\e76f"}.el-icon-umbrella:before{content:"\e770"}.el-icon-scissors:before{content:"\e771"}.el-icon-mobile:before{content:"\e773"}.el-icon-attract:before{content:"\e774"}.el-icon-monitor:before{content:"\e775"}.el-icon-search:before{content:"\e778"}.el-icon-takeaway-box:before{content:"\e77a"}.el-icon-paperclip:before{content:"\e77d"}.el-icon-printer:before{content:"\e77e"}.el-icon-document-add:before{content:"\e782"}.el-icon-document:before{content:"\e785"}.el-icon-document-checked:before{content:"\e786"}.el-icon-document-copy:before{content:"\e787"}.el-icon-document-delete:before{content:"\e788"}.el-icon-document-remove:before{content:"\e789"}.el-icon-tickets:before{content:"\e78b"}.el-icon-folder-checked:before{content:"\e77f"}.el-icon-folder-delete:before{content:"\e780"}.el-icon-folder-remove:before{content:"\e781"}.el-icon-folder-add:before{content:"\e783"}.el-icon-folder-opened:before{content:"\e784"}.el-icon-folder:before{content:"\e78a"}.el-icon-edit-outline:before{content:"\e764"}.el-icon-edit:before{content:"\e78c"}.el-icon-date:before{content:"\e78e"}.el-icon-c-scale-to-original:before{content:"\e7c6"}.el-icon-view:before{content:"\e6ce"}.el-icon-loading:before{content:"\e6cf"}.el-icon-rank:before{content:"\e6d1"}.el-icon-sort-down:before{content:"\e7c4"}.el-icon-sort-up:before{content:"\e7c5"}.el-icon-sort:before{content:"\e6d2"}.el-icon-finished:before{content:"\e6cd"}.el-icon-refresh-left:before{content:"\e6c7"}.el-icon-refresh-right:before{content:"\e6c8"}.el-icon-refresh:before{content:"\e6d0"}.el-icon-video-play:before{content:"\e7c0"}.el-icon-video-pause:before{content:"\e7c1"}.el-icon-d-arrow-right:before{content:"\e6dc"}.el-icon-d-arrow-left:before{content:"\e6dd"}.el-icon-arrow-up:before{content:"\e6e1"}.el-icon-arrow-down:before{content:"\e6df"}.el-icon-arrow-right:before{content:"\e6e0"}.el-icon-arrow-left:before{content:"\e6de"}.el-icon-top-right:before{content:"\e6e7"}.el-icon-top-left:before{content:"\e6e8"}.el-icon-top:before{content:"\e6e6"}.el-icon-bottom:before{content:"\e6eb"}.el-icon-right:before{content:"\e6e9"}.el-icon-back:before{content:"\e6ea"}.el-icon-bottom-right:before{content:"\e6ec"}.el-icon-bottom-left:before{content:"\e6ed"}.el-icon-caret-top:before{content:"\e78f"}.el-icon-caret-bottom:before{content:"\e790"}.el-icon-caret-right:before{content:"\e791"}.el-icon-caret-left:before{content:"\e792"}.el-icon-d-caret:before{content:"\e79a"}.el-icon-share:before{content:"\e793"}.el-icon-menu:before{content:"\e798"}.el-icon-s-grid:before{content:"\e7a6"}.el-icon-s-check:before{content:"\e7a7"}.el-icon-s-data:before{content:"\e7a8"}.el-icon-s-opportunity:before{content:"\e7aa"}.el-icon-s-custom:before{content:"\e7ab"}.el-icon-s-claim:before{content:"\e7ad"}.el-icon-s-finance:before{content:"\e7ae"}.el-icon-s-comment:before{content:"\e7af"}.el-icon-s-flag:before{content:"\e7b0"}.el-icon-s-marketing:before{content:"\e7b1"}.el-icon-s-shop:before{content:"\e7b4"}.el-icon-s-open:before{content:"\e7b5"}.el-icon-s-management:before{content:"\e7b6"}.el-icon-s-ticket:before{content:"\e7b7"}.el-icon-s-release:before{content:"\e7b8"}.el-icon-s-home:before{content:"\e7b9"}.el-icon-s-promotion:before{content:"\e7ba"}.el-icon-s-operation:before{content:"\e7bb"}.el-icon-s-unfold:before{content:"\e7bc"}.el-icon-s-fold:before{content:"\e7a9"}.el-icon-s-platform:before{content:"\e7bd"}.el-icon-s-order:before{content:"\e7be"}.el-icon-s-cooperation:before{content:"\e7bf"}.el-icon-bell:before{content:"\e725"}.el-icon-message-solid:before{content:"\e799"}.el-icon-video-camera:before{content:"\e772"}.el-icon-video-camera-solid:before{content:"\e796"}.el-icon-camera:before{content:"\e779"}.el-icon-camera-solid:before{content:"\e79b"}.el-icon-download:before{content:"\e77c"}.el-icon-upload2:before{content:"\e77b"}.el-icon-upload:before{content:"\e7c3"}.el-icon-picture-outline-round:before{content:"\e75f"}.el-icon-picture-outline:before{content:"\e75e"}.el-icon-picture:before{content:"\e79f"}.el-icon-close:before{content:"\e6db"}.el-icon-check:before{content:"\e6da"}.el-icon-plus:before{content:"\e6d9"}.el-icon-minus:before{content:"\e6d8"}.el-icon-help:before{content:"\e73d"}.el-icon-s-help:before{content:"\e7b3"}.el-icon-circle-close:before{content:"\e78d"}.el-icon-circle-check:before{content:"\e720"}.el-icon-circle-plus-outline:before{content:"\e723"}.el-icon-remove-outline:before{content:"\e722"}.el-icon-zoom-out:before{content:"\e776"}.el-icon-zoom-in:before{content:"\e777"}.el-icon-error:before{content:"\e79d"}.el-icon-success:before{content:"\e79c"}.el-icon-circle-plus:before{content:"\e7a0"}.el-icon-remove:before{content:"\e7a2"}.el-icon-info:before{content:"\e7a1"}.el-icon-question:before{content:"\e7a4"}.el-icon-warning-outline:before{content:"\e6c9"}.el-icon-warning:before{content:"\e7a3"}.el-icon-goods:before{content:"\e7c2"}.el-icon-s-goods:before{content:"\e7b2"}.el-icon-star-off:before{content:"\e717"}.el-icon-star-on:before{content:"\e797"}.el-icon-more-outline:before{content:"\e6cc"}.el-icon-more:before{content:"\e794"}.el-icon-phone-outline:before{content:"\e6cb"}.el-icon-phone:before{content:"\e795"}.el-icon-user:before{content:"\e6e3"}.el-icon-user-solid:before{content:"\e7a5"}.el-icon-setting:before{content:"\e6ca"}.el-icon-s-tools:before{content:"\e7ac"}.el-icon-delete:before{content:"\e6d7"}.el-icon-delete-solid:before{content:"\e7c9"}.el-icon-eleme:before{content:"\e7c7"}.el-icon-platform-eleme:before{content:"\e7ca"}.el-icon-loading{-webkit-animation:rotating 2s linear infinite;animation:rotating 2s linear infinite}.el-icon--right{margin-left:5px}.el-icon--left{margin-right:5px}@-webkit-keyframes rotating{0%{-webkit-transform:rotateZ(0);transform:rotateZ(0)}100%{-webkit-transform:rotateZ(360deg);transform:rotateZ(360deg)}}@keyframes rotating{0%{-webkit-transform:rotateZ(0);transform:rotateZ(0)}100%{-webkit-transform:rotateZ(360deg);transform:rotateZ(360deg)}}.el-pagination{white-space:nowrap;padding:2px 5px;color:#303133;font-weight:700}.el-pagination::after,.el-pagination::before{display:table;content:""}.el-pagination::after{clear:both}.el-pagination button,.el-pagination span:not([class*=suffix]){display:inline-block;font-size:13px;min-width:35.5px;height:28px;line-height:28px;vertical-align:top;-webkit-box-sizing:border-box;box-sizing:border-box}.el-pagination .el-input__inner{text-align:center;-moz-appearance:textfield;line-height:normal}.el-pagination .el-input__suffix{right:0;-webkit-transform:scale(.8);transform:scale(.8)}.el-pagination .el-select .el-input{width:100px;margin:0 5px}.el-pagination .el-select .el-input .el-input__inner{padding-right:25px;border-radius:3px}.el-pagination button{border:none;padding:0 6px;background:0 0}.el-pagination button:focus{outline:0}.el-pagination button:hover{color:#409EFF}.el-pagination button:disabled{color:#C0C4CC;background-color:#FFF;cursor:not-allowed}.el-pagination .btn-next,.el-pagination .btn-prev{background:center center no-repeat #FFF;background-size:16px;cursor:pointer;margin:0;color:#303133}.el-pagination .btn-next .el-icon,.el-pagination .btn-prev .el-icon{display:block;font-size:12px;font-weight:700}.el-pagination .btn-prev{padding-right:12px}.el-pagination .btn-next{padding-left:12px}.el-pagination .el-pager li.disabled{color:#C0C4CC;cursor:not-allowed}.el-pager li,.el-pager li.btn-quicknext:hover,.el-pager li.btn-quickprev:hover{cursor:pointer}.el-pagination--small .btn-next,.el-pagination--small .btn-prev,.el-pagination--small .el-pager li,.el-pagination--small .el-pager li.btn-quicknext,.el-pagination--small .el-pager li.btn-quickprev,.el-pagination--small .el-pager li:last-child{border-color:transparent;font-size:12px;line-height:22px;height:22px;min-width:22px}.el-pagination--small .arrow.disabled{visibility:hidden}.el-pagination--small .more::before,.el-pagination--small li.more::before{line-height:24px}.el-pagination--small button,.el-pagination--small span:not([class*=suffix]){height:22px;line-height:22px}.el-pagination--small .el-pagination__editor,.el-pagination--small .el-pagination__editor.el-input .el-input__inner{height:22px}.el-pagination__sizes{margin:0 10px 0 0;font-weight:400;color:#606266}.el-pagination__sizes .el-input .el-input__inner{font-size:13px;padding-left:8px}.el-pagination__sizes .el-input .el-input__inner:hover{border-color:#409EFF}.el-pagination__total{margin-right:10px;font-weight:400;color:#606266}.el-pagination__jump{margin-left:24px;font-weight:400;color:#606266}.el-pagination__jump .el-input__inner{padding:0 3px}.el-pagination__rightwrapper{float:right}.el-pagination__editor{line-height:18px;padding:0 2px;height:28px;text-align:center;margin:0 2px;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:3px}.el-pager,.el-pagination.is-background .btn-next,.el-pagination.is-background .btn-prev{padding:0}.el-dialog,.el-pager li{-webkit-box-sizing:border-box}.el-pagination__editor.el-input{width:50px}.el-pagination__editor.el-input .el-input__inner{height:28px}.el-pagination__editor .el-input__inner::-webkit-inner-spin-button,.el-pagination__editor .el-input__inner::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.el-pagination.is-background .btn-next,.el-pagination.is-background .btn-prev,.el-pagination.is-background .el-pager li{margin:0 5px;background-color:#f4f4f5;color:#606266;min-width:30px;border-radius:2px}.el-pagination.is-background .btn-next.disabled,.el-pagination.is-background .btn-next:disabled,.el-pagination.is-background .btn-prev.disabled,.el-pagination.is-background .btn-prev:disabled,.el-pagination.is-background .el-pager li.disabled{color:#C0C4CC}.el-pagination.is-background .el-pager li:not(.disabled):hover{color:#409EFF}.el-pagination.is-background .el-pager li:not(.disabled).active{background-color:#409EFF;color:#FFF}.el-pagination.is-background.el-pagination--small .btn-next,.el-pagination.is-background.el-pagination--small .btn-prev,.el-pagination.is-background.el-pagination--small .el-pager li{margin:0 3px;min-width:22px}.el-pager,.el-pager li{vertical-align:top;margin:0;display:inline-block}.el-pager{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;list-style:none;font-size:0}.el-pager .more::before{line-height:30px}.el-pager li{padding:0 4px;background:#FFF;font-size:13px;min-width:35.5px;height:28px;line-height:28px;box-sizing:border-box;text-align:center}.el-pager li.btn-quicknext,.el-pager li.btn-quickprev{line-height:28px;color:#303133}.el-pager li.btn-quicknext.disabled,.el-pager li.btn-quickprev.disabled{color:#C0C4CC}.el-pager li.active+li{border-left:0}.el-pager li:hover{color:#409EFF}.el-pager li.active{color:#409EFF;cursor:default}@-webkit-keyframes v-modal-in{0%{opacity:0}}@-webkit-keyframes v-modal-out{100%{opacity:0}}.el-dialog{position:relative;margin:0 auto 50px;background:#FFF;border-radius:2px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,.3);box-shadow:0 1px 3px rgba(0,0,0,.3);box-sizing:border-box;width:50%}.el-dialog.is-fullscreen{width:100%;margin-top:0;margin-bottom:0;height:100%;overflow:auto}.el-dialog__wrapper{position:fixed;top:0;right:0;bottom:0;left:0;overflow:auto;margin:0}.el-dialog__header{padding:20px 20px 10px}.el-dialog__headerbtn{position:absolute;top:20px;right:20px;padding:0;background:0 0;border:none;outline:0;cursor:pointer;font-size:16px}.el-dialog__headerbtn .el-dialog__close{color:#909399}.el-dialog__headerbtn:focus .el-dialog__close,.el-dialog__headerbtn:hover .el-dialog__close{color:#409EFF}.el-dialog__title{line-height:24px;font-size:18px;color:#303133}.el-dialog__body{padding:30px 20px;color:#606266;font-size:14px;word-break:break-all}.el-dialog__footer{padding:10px 20px 20px;text-align:right;-webkit-box-sizing:border-box;box-sizing:border-box}.el-dialog--center{text-align:center}.el-dialog--center .el-dialog__body{text-align:initial;padding:25px 25px 30px}.el-dialog--center .el-dialog__footer{text-align:inherit}.dialog-fade-enter-active{-webkit-animation:dialog-fade-in .3s;animation:dialog-fade-in .3s}.dialog-fade-leave-active{-webkit-animation:dialog-fade-out .3s;animation:dialog-fade-out .3s}@-webkit-keyframes dialog-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes dialog-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes dialog-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes dialog-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-autocomplete{position:relative;display:inline-block}.el-autocomplete-suggestion{margin:5px 0;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);border-radius:4px;border:1px solid #E4E7ED;-webkit-box-sizing:border-box;box-sizing:border-box;background-color:#FFF}.el-autocomplete-suggestion__wrap{max-height:280px;padding:10px 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-autocomplete-suggestion__list{margin:0;padding:0}.el-autocomplete-suggestion li{padding:0 20px;margin:0;line-height:34px;cursor:pointer;color:#606266;font-size:14px;list-style:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.el-autocomplete-suggestion li.highlighted,.el-autocomplete-suggestion li:hover{background-color:#F5F7FA}.el-autocomplete-suggestion li.divider{margin-top:6px;border-top:1px solid #000}.el-autocomplete-suggestion li.divider:last-child{margin-bottom:-6px}.el-autocomplete-suggestion.is-loading li{text-align:center;height:100px;line-height:100px;font-size:20px;color:#999}.el-autocomplete-suggestion.is-loading li::after{display:inline-block;content:"";height:100%;vertical-align:middle}.el-autocomplete-suggestion.is-loading li:hover{background-color:#FFF}.el-autocomplete-suggestion.is-loading .el-icon-loading{vertical-align:middle}.el-dropdown{display:inline-block;position:relative;color:#606266;font-size:14px}.el-dropdown .el-button-group{display:block}.el-dropdown .el-button-group .el-button{float:none}.el-dropdown .el-dropdown__caret-button{padding-left:5px;padding-right:5px;position:relative;border-left:none}.el-dropdown .el-dropdown__caret-button::before{content:'';position:absolute;display:block;width:1px;top:5px;bottom:5px;left:0;background:rgba(255,255,255,.5)}.el-dropdown .el-dropdown__caret-button.el-button--default::before{background:rgba(220,223,230,.5)}.el-dropdown .el-dropdown__caret-button:hover:not(.is-disabled)::before{top:0;bottom:0}.el-dropdown .el-dropdown__caret-button .el-dropdown__icon{padding-left:0}.el-dropdown__icon{font-size:12px;margin:0 3px}.el-dropdown .el-dropdown-selfdefine:focus:active,.el-dropdown .el-dropdown-selfdefine:focus:not(.focusing){outline-width:0}.el-dropdown [disabled]{cursor:not-allowed;color:#bbb}.el-dropdown-menu{position:absolute;top:0;left:0;z-index:10;padding:10px 0;margin:5px 0;background-color:#FFF;border:1px solid #EBEEF5;border-radius:4px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-dropdown-menu__item,.el-menu-item{font-size:14px;padding:0 20px;cursor:pointer}.el-dropdown-menu__item{list-style:none;line-height:36px;margin:0;color:#606266;outline:0}.el-dropdown-menu__item:focus,.el-dropdown-menu__item:not(.is-disabled):hover{background-color:#ecf5ff;color:#66b1ff}.el-dropdown-menu__item i{margin-right:5px}.el-dropdown-menu__item--divided{position:relative;margin-top:6px;border-top:1px solid #EBEEF5}.el-dropdown-menu__item--divided:before{content:'';height:6px;display:block;margin:0 -20px;background-color:#FFF}.el-dropdown-menu__item.is-disabled{cursor:default;color:#bbb;pointer-events:none}.el-dropdown-menu--medium{padding:6px 0}.el-dropdown-menu--medium .el-dropdown-menu__item{line-height:30px;padding:0 17px;font-size:14px}.el-dropdown-menu--medium .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:6px}.el-dropdown-menu--medium .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:6px;margin:0 -17px}.el-dropdown-menu--small{padding:6px 0}.el-dropdown-menu--small .el-dropdown-menu__item{line-height:27px;padding:0 15px;font-size:13px}.el-dropdown-menu--small .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:4px}.el-dropdown-menu--small .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:4px;margin:0 -15px}.el-dropdown-menu--mini{padding:3px 0}.el-dropdown-menu--mini .el-dropdown-menu__item{line-height:24px;padding:0 10px;font-size:12px}.el-dropdown-menu--mini .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:3px}.el-dropdown-menu--mini .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:3px;margin:0 -10px}.el-menu{border-right:solid 1px #e6e6e6;list-style:none;position:relative;margin:0;padding-left:0;background-color:#FFF}.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus,.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover,.el-menu--horizontal>.el-submenu .el-submenu__title:hover{background-color:#fff}.el-menu::after,.el-menu::before{display:table;content:""}.el-breadcrumb__item:last-child .el-breadcrumb__separator,.el-menu--collapse>.el-menu-item .el-submenu__icon-arrow,.el-menu--collapse>.el-submenu>.el-submenu__title .el-submenu__icon-arrow{display:none}.el-menu::after{clear:both}.el-menu.el-menu--horizontal{border-bottom:solid 1px #e6e6e6}.el-menu--horizontal{border-right:none}.el-menu--horizontal>.el-menu-item{float:left;height:60px;line-height:60px;margin:0;border-bottom:2px solid transparent;color:#909399}.el-menu--horizontal>.el-menu-item a,.el-menu--horizontal>.el-menu-item a:hover{color:inherit}.el-menu--horizontal>.el-submenu{float:left}.el-menu--horizontal>.el-submenu:focus,.el-menu--horizontal>.el-submenu:hover{outline:0}.el-menu--horizontal>.el-submenu:focus .el-submenu__title,.el-menu--horizontal>.el-submenu:hover .el-submenu__title{color:#303133}.el-menu--horizontal>.el-submenu.is-active .el-submenu__title{border-bottom:2px solid #409EFF;color:#303133}.el-menu--horizontal>.el-submenu .el-submenu__title{height:60px;line-height:60px;border-bottom:2px solid transparent;color:#909399}.el-menu--horizontal>.el-submenu .el-submenu__icon-arrow{position:static;vertical-align:middle;margin-left:8px;margin-top:-3px}.el-menu--collapse .el-submenu,.el-menu-item{position:relative}.el-menu--horizontal .el-menu .el-menu-item,.el-menu--horizontal .el-menu .el-submenu__title{background-color:#FFF;float:none;height:36px;line-height:36px;padding:0 10px;color:#909399}.el-menu--horizontal .el-menu .el-menu-item.is-active,.el-menu--horizontal .el-menu .el-submenu.is-active>.el-submenu__title{color:#303133}.el-menu--horizontal .el-menu-item:not(.is-disabled):focus,.el-menu--horizontal .el-menu-item:not(.is-disabled):hover{outline:0;color:#303133}.el-menu--horizontal>.el-menu-item.is-active{border-bottom:2px solid #409EFF;color:#303133}.el-menu--collapse{width:64px}.el-menu--collapse>.el-menu-item [class^=el-icon-],.el-menu--collapse>.el-submenu>.el-submenu__title [class^=el-icon-]{margin:0;vertical-align:middle;width:24px;text-align:center}.el-menu--collapse>.el-menu-item span,.el-menu--collapse>.el-submenu>.el-submenu__title span{height:0;width:0;overflow:hidden;visibility:hidden;display:inline-block}.el-menu-item,.el-submenu__title{height:56px;line-height:56px;list-style:none}.el-menu--collapse>.el-menu-item.is-active i{color:inherit}.el-menu--collapse .el-menu .el-submenu{min-width:200px}.el-menu--collapse .el-submenu .el-menu{position:absolute;margin-left:5px;top:0;left:100%;z-index:10;border:1px solid #E4E7ED;border-radius:2px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-menu--collapse .el-submenu.is-opened>.el-submenu__title .el-submenu__icon-arrow{-webkit-transform:none;transform:none}.el-menu--popup{z-index:100;min-width:200px;border:none;padding:5px 0;border-radius:2px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-menu--popup-bottom-start{margin-top:5px}.el-menu--popup-right-start{margin-left:5px;margin-right:5px}.el-menu-item{color:#303133;-webkit-transition:border-color .3s,background-color .3s,color .3s;transition:border-color .3s,background-color .3s,color .3s;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap}.el-radio-button__inner,.el-submenu__title{-webkit-box-sizing:border-box;position:relative;white-space:nowrap}.el-menu-item *{vertical-align:middle}.el-menu-item i{color:#909399}.el-menu-item:focus,.el-menu-item:hover{outline:0;background-color:#ecf5ff}.el-menu-item.is-disabled{opacity:.25;cursor:not-allowed;background:0 0!important}.el-menu-item [class^=el-icon-]{margin-right:5px;width:24px;text-align:center;font-size:18px;vertical-align:middle}.el-menu-item.is-active{color:#409EFF}.el-menu-item.is-active i{color:inherit}.el-submenu{list-style:none;margin:0;padding-left:0}.el-submenu__title{font-size:14px;color:#303133;padding:0 20px;cursor:pointer;-webkit-transition:border-color .3s,background-color .3s,color .3s;transition:border-color .3s,background-color .3s,color .3s;box-sizing:border-box}.el-submenu__title *{vertical-align:middle}.el-submenu__title i{color:#909399}.el-submenu__title:focus,.el-submenu__title:hover{outline:0;background-color:#ecf5ff}.el-submenu__title.is-disabled{opacity:.25;cursor:not-allowed;background:0 0!important}.el-submenu__title:hover{background-color:#ecf5ff}.el-submenu .el-menu{border:none}.el-submenu .el-menu-item{height:50px;line-height:50px;padding:0 45px;min-width:200px}.el-submenu__icon-arrow{position:absolute;top:50%;right:20px;margin-top:-7px;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-size:12px}.el-submenu.is-active .el-submenu__title{border-bottom-color:#409EFF}.el-submenu.is-opened>.el-submenu__title .el-submenu__icon-arrow{-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg)}.el-submenu.is-disabled .el-menu-item,.el-submenu.is-disabled .el-submenu__title{opacity:.25;cursor:not-allowed;background:0 0!important}.el-submenu [class^=el-icon-]{vertical-align:middle;margin-right:5px;width:24px;text-align:center;font-size:18px}.el-menu-item-group>ul{padding:0}.el-menu-item-group__title{padding:7px 0 7px 20px;line-height:normal;font-size:12px;color:#909399}.el-radio-button__inner,.el-radio-group{display:inline-block;line-height:1;vertical-align:middle}.horizontal-collapse-transition .el-submenu__title .el-submenu__icon-arrow{-webkit-transition:.2s;transition:.2s;opacity:0}.el-radio-group{font-size:0}.el-radio-button{position:relative;display:inline-block;outline:0}.el-radio-button__inner{background:#FFF;border:1px solid #DCDFE6;font-weight:500;border-left:0;color:#606266;-webkit-appearance:none;text-align:center;box-sizing:border-box;outline:0;margin:0;cursor:pointer;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);padding:12px 20px;font-size:14px;border-radius:0}.el-radio-button__inner.is-round{padding:12px 20px}.el-radio-button__inner:hover{color:#409EFF}.el-radio-button__inner [class*=el-icon-]{line-height:.9}.el-radio-button__inner [class*=el-icon-]+span{margin-left:5px}.el-radio-button:first-child .el-radio-button__inner{border-left:1px solid #DCDFE6;border-radius:4px 0 0 4px;-webkit-box-shadow:none!important;box-shadow:none!important}.el-radio-button__orig-radio{opacity:0;outline:0;position:absolute;z-index:-1}.el-radio-button__orig-radio:checked+.el-radio-button__inner{color:#FFF;background-color:#409EFF;border-color:#409EFF;-webkit-box-shadow:-1px 0 0 0 #409EFF;box-shadow:-1px 0 0 0 #409EFF}.el-radio-button__orig-radio:disabled+.el-radio-button__inner{color:#C0C4CC;cursor:not-allowed;background-image:none;background-color:#FFF;border-color:#EBEEF5;-webkit-box-shadow:none;box-shadow:none}.el-radio-button__orig-radio:disabled:checked+.el-radio-button__inner{background-color:#F2F6FC}.el-radio-button:last-child .el-radio-button__inner{border-radius:0 4px 4px 0}.el-radio-button:first-child:last-child .el-radio-button__inner{border-radius:4px}.el-radio-button--medium .el-radio-button__inner{padding:10px 20px;font-size:14px;border-radius:0}.el-radio-button--medium .el-radio-button__inner.is-round{padding:10px 20px}.el-radio-button--small .el-radio-button__inner{padding:9px 15px;font-size:12px;border-radius:0}.el-radio-button--small .el-radio-button__inner.is-round{padding:9px 15px}.el-radio-button--mini .el-radio-button__inner{padding:7px 15px;font-size:12px;border-radius:0}.el-radio-button--mini .el-radio-button__inner.is-round{padding:7px 15px}.el-radio-button:focus:not(.is-focus):not(:active):not(.is-disabled){-webkit-box-shadow:0 0 2px 2px #409EFF;box-shadow:0 0 2px 2px #409EFF}.el-picker-panel,.el-popover,.el-select-dropdown,.el-table-filter,.el-time-panel{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-switch{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;position:relative;font-size:14px;line-height:20px;height:20px;vertical-align:middle}.el-switch__core,.el-switch__label{display:inline-block;cursor:pointer}.el-switch.is-disabled .el-switch__core,.el-switch.is-disabled .el-switch__label{cursor:not-allowed}.el-switch__label{-webkit-transition:.2s;transition:.2s;height:20px;font-size:14px;font-weight:500;vertical-align:middle;color:#303133}.el-switch__label.is-active{color:#409EFF}.el-switch__label--left{margin-right:10px}.el-switch__label--right{margin-left:10px}.el-switch__label *{line-height:1;font-size:14px;display:inline-block}.el-switch__input{position:absolute;width:0;height:0;opacity:0;margin:0}.el-switch__core{margin:0;position:relative;width:40px;height:20px;border:1px solid #DCDFE6;outline:0;border-radius:10px;-webkit-box-sizing:border-box;box-sizing:border-box;background:#DCDFE6;-webkit-transition:border-color .3s,background-color .3s;transition:border-color .3s,background-color .3s;vertical-align:middle}.el-input__prefix,.el-input__suffix{-webkit-transition:all .3s;color:#C0C4CC}.el-switch__core:after{content:"";position:absolute;top:1px;left:1px;border-radius:100%;-webkit-transition:all .3s;transition:all .3s;width:16px;height:16px;background-color:#FFF}.el-switch.is-checked .el-switch__core{border-color:#409EFF;background-color:#409EFF}.el-switch.is-checked .el-switch__core::after{left:100%;margin-left:-17px}.el-switch.is-disabled{opacity:.6}.el-switch--wide .el-switch__label.el-switch__label--left span{left:10px}.el-switch--wide .el-switch__label.el-switch__label--right span{right:10px}.el-switch .label-fade-enter,.el-switch .label-fade-leave-active{opacity:0}.el-select-dropdown{position:absolute;z-index:1001;border:1px solid #E4E7ED;border-radius:4px;background-color:#FFF;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-box-sizing:border-box;box-sizing:border-box;margin:5px 0}.el-select-dropdown.is-multiple .el-select-dropdown__item{padding-right:40px}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected{color:#409EFF;background-color:#FFF}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected.hover{background-color:#F5F7FA}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected::after{position:absolute;right:20px;font-family:element-icons;content:"\e6da";font-size:12px;font-weight:700;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-select-dropdown .el-scrollbar.is-empty .el-select-dropdown__list{padding:0}.el-select-dropdown__empty{padding:10px 0;margin:0;text-align:center;color:#999;font-size:14px}.el-select-dropdown__wrap{max-height:274px}.el-select-dropdown__list{list-style:none;padding:6px 0;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-select-dropdown__item{font-size:14px;padding:0 20px;position:relative;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#606266;height:34px;line-height:34px;-webkit-box-sizing:border-box;box-sizing:border-box;cursor:pointer}.el-select-dropdown__item.is-disabled{color:#C0C4CC;cursor:not-allowed}.el-select-dropdown__item.is-disabled:hover{background-color:#FFF}.el-select-dropdown__item.hover,.el-select-dropdown__item:hover{background-color:#F5F7FA}.el-select-dropdown__item.selected{color:#409EFF;font-weight:700}.el-select-group{margin:0;padding:0}.el-select-group__wrap{position:relative;list-style:none;margin:0;padding:0}.el-select-group__wrap:not(:last-of-type){padding-bottom:24px}.el-select-group__wrap:not(:last-of-type)::after{content:'';position:absolute;display:block;left:20px;right:20px;bottom:12px;height:1px;background:#E4E7ED}.el-select-group__title{padding-left:20px;font-size:12px;color:#909399;line-height:30px}.el-select-group .el-select-dropdown__item{padding-left:20px}.el-select{display:inline-block;position:relative}.el-select .el-select__tags>span{display:contents}.el-select:hover .el-input__inner{border-color:#C0C4CC}.el-select .el-input__inner{cursor:pointer;padding-right:35px}.el-select .el-input__inner:focus{border-color:#409EFF}.el-select .el-input .el-select__caret{color:#C0C4CC;font-size:14px;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg);cursor:pointer}.el-select .el-input .el-select__caret.is-reverse{-webkit-transform:rotateZ(0);transform:rotateZ(0)}.el-select .el-input .el-select__caret.is-show-close{font-size:14px;text-align:center;-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg);border-radius:100%;color:#C0C4CC;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-select .el-input .el-select__caret.is-show-close:hover{color:#909399}.el-select .el-input.is-disabled .el-input__inner{cursor:not-allowed}.el-select .el-input.is-disabled .el-input__inner:hover{border-color:#E4E7ED}.el-range-editor.is-active,.el-range-editor.is-active:hover,.el-select .el-input.is-focus .el-input__inner{border-color:#409EFF}.el-select>.el-input{display:block}.el-select__input{border:none;outline:0;padding:0;margin-left:15px;color:#666;font-size:14px;-webkit-appearance:none;-moz-appearance:none;appearance:none;height:28px;background-color:transparent}.el-select__input.is-mini{height:14px}.el-select__close{cursor:pointer;position:absolute;top:8px;z-index:1000;right:25px;color:#C0C4CC;line-height:18px;font-size:14px}.el-select__close:hover{color:#909399}.el-select__tags{position:absolute;line-height:normal;white-space:normal;z-index:1;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-wrap:wrap;flex-wrap:wrap}.el-select__tags-text{overflow:hidden;text-overflow:ellipsis}.el-select .el-tag{-webkit-box-sizing:border-box;box-sizing:border-box;border-color:transparent;margin:2px 0 2px 6px;background-color:#f0f2f5;display:-webkit-box;display:-ms-flexbox;display:flex;max-width:100%;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-select .el-tag__close.el-icon-close{background-color:#C0C4CC;top:0;color:#FFF;-ms-flex-negative:0;flex-shrink:0}.el-select .el-tag__close.el-icon-close:hover{background-color:#909399}.el-table,.el-table__expanded-cell{background-color:#FFF}.el-select .el-tag__close.el-icon-close::before{display:block;-webkit-transform:translate(0,.5px);transform:translate(0,.5px)}.el-table{position:relative;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-box-flex:1;-ms-flex:1;flex:1;width:100%;max-width:100%;font-size:14px;color:#606266}.el-table__empty-block{min-height:60px;text-align:center;width:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-table__empty-text{line-height:60px;width:50%;color:#909399}.el-table__expand-column .cell{padding:0;text-align:center}.el-table__expand-icon{position:relative;cursor:pointer;color:#666;font-size:12px;-webkit-transition:-webkit-transform .2s ease-in-out;transition:-webkit-transform .2s ease-in-out;transition:transform .2s ease-in-out;transition:transform .2s ease-in-out,-webkit-transform .2s ease-in-out;height:20px}.el-table__expand-icon--expanded{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-table__expand-icon>.el-icon{position:absolute;left:50%;top:50%;margin-left:-5px;margin-top:-5px}.el-table__expanded-cell[class*=cell]{padding:20px 50px}.el-table__expanded-cell:hover{background-color:transparent!important}.el-table__placeholder{display:inline-block;width:20px}.el-table__append-wrapper{overflow:hidden}.el-table--fit{border-right:0;border-bottom:0}.el-table--fit .el-table__cell.gutter{border-right-width:1px}.el-table--scrollable-x .el-table__body-wrapper{overflow-x:auto}.el-table--scrollable-y .el-table__body-wrapper{overflow-y:auto}.el-table thead{color:#909399;font-weight:500}.el-table thead.is-group th.el-table__cell{background:#F5F7FA}.el-table .el-table__cell{padding:12px 0;min-width:0;-webkit-box-sizing:border-box;box-sizing:border-box;text-overflow:ellipsis;vertical-align:middle;position:relative;text-align:left}.el-table .el-table__cell.is-center{text-align:center}.el-table .el-table__cell.is-right{text-align:right}.el-table .el-table__cell.gutter{width:15px;border-right-width:0;border-bottom-width:0;padding:0}.el-table .el-table__cell.is-hidden>*{visibility:hidden}.el-table--medium .el-table__cell{padding:10px 0}.el-table--small{font-size:12px}.el-table--small .el-table__cell{padding:8px 0}.el-table--mini{font-size:12px}.el-table--mini .el-table__cell{padding:6px 0}.el-table tr{background-color:#FFF}.el-table tr input[type=checkbox]{margin:0}.el-table td.el-table__cell,.el-table th.el-table__cell.is-leaf{border-bottom:1px solid #EBEEF5}.el-table th.el-table__cell.is-sortable{cursor:pointer}.el-table th.el-table__cell{overflow:hidden;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#FFF}.el-table th.el-table__cell>.cell{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;vertical-align:middle;padding-left:10px;padding-right:10px;width:100%}.el-table th.el-table__cell>.cell.highlight{color:#409EFF}.el-table th.el-table__cell.required>div::before{display:inline-block;content:"";width:8px;height:8px;border-radius:50%;background:#ff4d51;margin-right:5px;vertical-align:middle}.el-table td.el-table__cell div{-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-table td,.el-table .cell,.el-table-filter{-webkit-box-sizing:border-box}.el-table td.el-table__cell.gutter{width:0}.el-table .cell{box-sizing:border-box;overflow:hidden;text-overflow:ellipsis;white-space:normal;word-break:break-all;line-height:23px;padding-left:10px;padding-right:10px}.el-table .cell.el-tooltip{white-space:nowrap;min-width:50px}.el-table--border,.el-table--group{border:1px solid #EBEEF5}.el-table--border::after,.el-table--group::after,.el-table::before{content:'';position:absolute;background-color:#EBEEF5;z-index:1}.el-table--border::after,.el-table--group::after{top:0;right:0;width:1px;height:100%}.el-table::before{left:0;bottom:0;width:100%;height:1px}.el-table--border{border-right:none;border-bottom:none}.el-table--border.el-loading-parent--relative{border-color:transparent}.el-table--border .el-table__cell,.el-table__body-wrapper .el-table--border.is-scrolling-left~.el-table__fixed{border-right:1px solid #EBEEF5}.el-table--border .el-table__cell:first-child .cell{padding-left:10px}.el-table--border th.el-table__cell.gutter:last-of-type{border-bottom:1px solid #EBEEF5;border-bottom-width:1px}.el-table--border th.el-table__cell,.el-table__fixed-right-patch{border-bottom:1px solid #EBEEF5}.el-table--hidden{visibility:hidden}.el-table__fixed,.el-table__fixed-right{position:absolute;top:0;left:0;overflow-x:hidden;overflow-y:hidden;-webkit-box-shadow:0 0 10px rgba(0,0,0,.12);box-shadow:0 0 10px rgba(0,0,0,.12)}.el-table__fixed-right::before,.el-table__fixed::before{content:'';position:absolute;left:0;bottom:0;width:100%;height:1px;background-color:#EBEEF5;z-index:4}.el-table__fixed-right-patch{position:absolute;top:-1px;right:0;background-color:#FFF}.el-table__fixed-right{top:0;left:auto;right:0}.el-table__fixed-right .el-table__fixed-body-wrapper,.el-table__fixed-right .el-table__fixed-footer-wrapper,.el-table__fixed-right .el-table__fixed-header-wrapper{left:auto;right:0}.el-table__fixed-header-wrapper{position:absolute;left:0;top:0;z-index:3}.el-table__fixed-footer-wrapper{position:absolute;left:0;bottom:0;z-index:3}.el-table__fixed-footer-wrapper tbody td.el-table__cell{border-top:1px solid #EBEEF5;background-color:#F5F7FA;color:#606266}.el-table__fixed-body-wrapper{position:absolute;left:0;top:37px;overflow:hidden;z-index:3}.el-table__body-wrapper,.el-table__footer-wrapper,.el-table__header-wrapper{width:100%}.el-table__footer-wrapper{margin-top:-1px}.el-table__footer-wrapper td.el-table__cell{border-top:1px solid #EBEEF5}.el-table__body,.el-table__footer,.el-table__header{table-layout:fixed;border-collapse:separate}.el-table__footer-wrapper,.el-table__header-wrapper{overflow:hidden}.el-table__footer-wrapper tbody td.el-table__cell,.el-table__header-wrapper tbody td.el-table__cell{background-color:#F5F7FA;color:#606266}.el-table__body-wrapper{overflow:hidden;position:relative}.el-table__body-wrapper.is-scrolling-left~.el-table__fixed,.el-table__body-wrapper.is-scrolling-none~.el-table__fixed,.el-table__body-wrapper.is-scrolling-none~.el-table__fixed-right,.el-table__body-wrapper.is-scrolling-right~.el-table__fixed-right{-webkit-box-shadow:none;box-shadow:none}.el-table__body-wrapper .el-table--border.is-scrolling-right~.el-table__fixed-right{border-left:1px solid #EBEEF5}.el-table .caret-wrapper{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:34px;width:24px;vertical-align:middle;cursor:pointer;overflow:initial;position:relative}.el-table .sort-caret{width:0;height:0;border:5px solid transparent;position:absolute;left:7px}.el-table .sort-caret.ascending{border-bottom-color:#C0C4CC;top:5px}.el-table .sort-caret.descending{border-top-color:#C0C4CC;bottom:7px}.el-table .ascending .sort-caret.ascending{border-bottom-color:#409EFF}.el-table .descending .sort-caret.descending{border-top-color:#409EFF}.el-table .hidden-columns{visibility:hidden;position:absolute;z-index:-1}.el-table--striped .el-table__body tr.el-table__row--striped td.el-table__cell{background:#FAFAFA}.el-table--striped .el-table__body tr.el-table__row--striped.current-row td.el-table__cell,.el-table--striped .el-table__body tr.el-table__row--striped.selection-row td.el-table__cell{background-color:#ecf5ff}.el-table__body tr.hover-row.current-row>td.el-table__cell,.el-table__body tr.hover-row.el-table__row--striped.current-row>td.el-table__cell,.el-table__body tr.hover-row.el-table__row--striped.selection-row>td.el-table__cell,.el-table__body tr.hover-row.el-table__row--striped>td.el-table__cell,.el-table__body tr.hover-row.selection-row>td.el-table__cell,.el-table__body tr.hover-row>td.el-table__cell{background-color:#F5F7FA}.el-table__body tr.current-row>td.el-table__cell,.el-table__body tr.selection-row>td.el-table__cell{background-color:#ecf5ff}.el-table__column-resize-proxy{position:absolute;left:200px;top:0;bottom:0;width:0;border-left:1px solid #EBEEF5;z-index:10}.el-table__column-filter-trigger{display:inline-block;line-height:34px;cursor:pointer}.el-table__column-filter-trigger i{color:#909399;font-size:12px;-webkit-transform:scale(.75);transform:scale(.75)}.el-table--enable-row-transition .el-table__body td.el-table__cell{-webkit-transition:background-color .25s ease;transition:background-color .25s ease}.el-table--enable-row-hover .el-table__body tr:hover>td.el-table__cell{background-color:#F5F7FA}.el-table--fluid-height .el-table__fixed,.el-table--fluid-height .el-table__fixed-right{bottom:0;overflow:hidden}.el-table [class*=el-table__row--level] .el-table__expand-icon{display:inline-block;width:20px;line-height:20px;height:20px;text-align:center;margin-right:3px}.el-table-column--selection .cell{padding-left:14px;padding-right:14px}.el-table-filter{border:1px solid #EBEEF5;border-radius:2px;background-color:#FFF;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-sizing:border-box;margin:2px 0}.el-table-filter__list{padding:5px 0;margin:0;list-style:none;min-width:100px}.el-table-filter__list-item{line-height:36px;padding:0 10px;cursor:pointer;font-size:14px}.el-table-filter__list-item:hover{background-color:#ecf5ff;color:#66b1ff}.el-table-filter__list-item.is-active{background-color:#409EFF;color:#FFF}.el-table-filter__content{min-width:100px}.el-table-filter__bottom{border-top:1px solid #EBEEF5;padding:8px}.el-table-filter__bottom button{background:0 0;border:none;color:#606266;cursor:pointer;font-size:13px;padding:0 3px}.el-date-table td.in-range div,.el-date-table td.in-range div:hover,.el-date-table.is-week-mode .el-date-table__row.current div,.el-date-table.is-week-mode .el-date-table__row:hover div{background-color:#F2F6FC}.el-table-filter__bottom button:hover{color:#409EFF}.el-table-filter__bottom button:focus{outline:0}.el-table-filter__bottom button.is-disabled{color:#C0C4CC;cursor:not-allowed}.el-table-filter__wrap{max-height:280px}.el-table-filter__checkbox-group{padding:10px}.el-table-filter__checkbox-group label.el-checkbox{display:block;margin-right:5px;margin-bottom:8px;margin-left:5px}.el-table-filter__checkbox-group .el-checkbox:last-child{margin-bottom:0}.el-date-table{font-size:12px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.el-date-table.is-week-mode .el-date-table__row:hover td.available:hover{color:#606266}.el-date-table.is-week-mode .el-date-table__row:hover td:first-child div{margin-left:5px;border-top-left-radius:15px;border-bottom-left-radius:15px}.el-date-table.is-week-mode .el-date-table__row:hover td:last-child div{margin-right:5px;border-top-right-radius:15px;border-bottom-right-radius:15px}.el-date-table td{width:32px;height:30px;padding:4px 0;box-sizing:border-box;text-align:center;cursor:pointer;position:relative}.el-date-table td div{height:30px;padding:3px 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-table td span{width:24px;height:24px;display:block;margin:0 auto;line-height:24px;position:absolute;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);border-radius:50%}.el-date-table td.next-month,.el-date-table td.prev-month{color:#C0C4CC}.el-date-table td.today{position:relative}.el-date-table td.today span{color:#409EFF;font-weight:700}.el-date-table td.today.end-date span,.el-date-table td.today.start-date span{color:#FFF}.el-date-table td.available:hover{color:#409EFF}.el-date-table td.current:not(.disabled) span{color:#FFF;background-color:#409EFF}.el-date-table td.end-date div,.el-date-table td.start-date div{color:#FFF}.el-date-table td.end-date span,.el-date-table td.start-date span{background-color:#409EFF}.el-date-table td.start-date div{margin-left:5px;border-top-left-radius:15px;border-bottom-left-radius:15px}.el-date-table td.end-date div{margin-right:5px;border-top-right-radius:15px;border-bottom-right-radius:15px}.el-date-table td.disabled div{background-color:#F5F7FA;opacity:1;cursor:not-allowed;color:#C0C4CC}.el-date-table td.selected div{margin-left:5px;margin-right:5px;background-color:#F2F6FC;border-radius:15px}.el-date-table td.selected div:hover{background-color:#F2F6FC}.el-date-table td.selected span{background-color:#409EFF;color:#FFF;border-radius:15px}.el-date-table td.week{font-size:80%;color:#606266}.el-month-table,.el-year-table{font-size:12px;border-collapse:collapse}.el-date-table th{padding:5px;color:#606266;font-weight:400;border-bottom:solid 1px #EBEEF5}.el-month-table{margin:-1px}.el-month-table td{text-align:center;padding:8px 0;cursor:pointer}.el-month-table td div{height:48px;padding:6px 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-month-table td.today .cell{color:#409EFF;font-weight:700}.el-month-table td.today.end-date .cell,.el-month-table td.today.start-date .cell{color:#FFF}.el-month-table td.disabled .cell{background-color:#F5F7FA;cursor:not-allowed;color:#C0C4CC}.el-month-table td.disabled .cell:hover{color:#C0C4CC}.el-month-table td .cell{width:60px;height:36px;display:block;line-height:36px;color:#606266;margin:0 auto;border-radius:18px}.el-month-table td .cell:hover{color:#409EFF}.el-month-table td.in-range div,.el-month-table td.in-range div:hover{background-color:#F2F6FC}.el-month-table td.end-date div,.el-month-table td.start-date div{color:#FFF}.el-month-table td.end-date .cell,.el-month-table td.start-date .cell{color:#FFF;background-color:#409EFF}.el-month-table td.start-date div{border-top-left-radius:24px;border-bottom-left-radius:24px}.el-month-table td.end-date div{border-top-right-radius:24px;border-bottom-right-radius:24px}.el-month-table td.current:not(.disabled) .cell{color:#409EFF}.el-year-table{margin:-1px}.el-year-table .el-icon{color:#303133}.el-year-table td{text-align:center;padding:20px 3px;cursor:pointer}.el-year-table td.today .cell{color:#409EFF;font-weight:700}.el-year-table td.disabled .cell{background-color:#F5F7FA;cursor:not-allowed;color:#C0C4CC}.el-year-table td.disabled .cell:hover{color:#C0C4CC}.el-year-table td .cell{width:48px;height:32px;display:block;line-height:32px;color:#606266;margin:0 auto}.el-year-table td .cell:hover,.el-year-table td.current:not(.disabled) .cell{color:#409EFF}.el-date-range-picker{width:646px}.el-date-range-picker.has-sidebar{width:756px}.el-date-range-picker table{table-layout:fixed;width:100%}.el-date-range-picker .el-picker-panel__body{min-width:513px}.el-date-range-picker .el-picker-panel__content{margin:0}.el-date-range-picker__header{position:relative;text-align:center;height:28px}.el-date-range-picker__header [class*=arrow-left]{float:left}.el-date-range-picker__header [class*=arrow-right]{float:right}.el-date-range-picker__header div{font-size:16px;font-weight:500;margin-right:50px}.el-date-range-picker__content{float:left;width:50%;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:16px}.el-date-range-picker__content.is-left{border-right:1px solid #e4e4e4}.el-date-range-picker__content .el-date-range-picker__header div{margin-left:50px;margin-right:50px}.el-date-range-picker__editors-wrap{-webkit-box-sizing:border-box;box-sizing:border-box;display:table-cell}.el-date-range-picker__editors-wrap.is-right{text-align:right}.el-date-range-picker__time-header{position:relative;border-bottom:1px solid #e4e4e4;font-size:12px;padding:8px 5px 5px;display:table;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-range-picker__time-header>.el-icon-arrow-right{font-size:20px;vertical-align:middle;display:table-cell;color:#303133}.el-date-range-picker__time-picker-wrap{position:relative;display:table-cell;padding:0 5px}.el-date-range-picker__time-picker-wrap .el-picker-panel{position:absolute;top:13px;right:0;z-index:1;background:#FFF}.el-date-picker{width:322px}.el-date-picker.has-sidebar.has-time{width:434px}.el-date-picker.has-sidebar{width:438px}.el-date-picker.has-time .el-picker-panel__body-wrapper{position:relative}.el-date-picker .el-picker-panel__content{width:292px}.el-date-picker table{table-layout:fixed;width:100%}.el-date-picker__editor-wrap{position:relative;display:table-cell;padding:0 5px}.el-date-picker__time-header{position:relative;border-bottom:1px solid #e4e4e4;font-size:12px;padding:8px 5px 5px;display:table;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-picker__header{margin:12px;text-align:center}.el-date-picker__header--bordered{margin-bottom:0;padding-bottom:12px;border-bottom:solid 1px #EBEEF5}.el-date-picker__header--bordered+.el-picker-panel__content{margin-top:0}.el-date-picker__header-label{font-size:16px;font-weight:500;padding:0 5px;line-height:22px;text-align:center;cursor:pointer;color:#606266}.el-date-picker__header-label.active,.el-date-picker__header-label:hover{color:#409EFF}.el-date-picker__prev-btn{float:left}.el-date-picker__next-btn{float:right}.el-date-picker__time-wrap{padding:10px;text-align:center}.el-date-picker__time-label{float:left;cursor:pointer;line-height:30px;margin-left:10px}.time-select{margin:5px 0;min-width:0}.time-select .el-picker-panel__content{max-height:200px;margin:0}.time-select-item{padding:8px 10px;font-size:14px;line-height:20px}.time-select-item.selected:not(.disabled){color:#409EFF;font-weight:700}.time-select-item.disabled{color:#E4E7ED;cursor:not-allowed}.time-select-item:hover{background-color:#F5F7FA;font-weight:700;cursor:pointer}.el-date-editor{position:relative;display:inline-block;text-align:left}.el-date-editor.el-input,.el-date-editor.el-input__inner{width:220px}.el-date-editor--monthrange.el-input,.el-date-editor--monthrange.el-input__inner{width:300px}.el-date-editor--daterange.el-input,.el-date-editor--daterange.el-input__inner,.el-date-editor--timerange.el-input,.el-date-editor--timerange.el-input__inner{width:350px}.el-date-editor--datetimerange.el-input,.el-date-editor--datetimerange.el-input__inner{width:400px}.el-date-editor--dates .el-input__inner{text-overflow:ellipsis;white-space:nowrap}.el-date-editor .el-icon-circle-close{cursor:pointer}.el-date-editor .el-range__icon{font-size:14px;margin-left:-5px;color:#C0C4CC;float:left;line-height:32px}.el-date-editor .el-range-input{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:none;outline:0;display:inline-block;height:100%;margin:0;padding:0;width:39%;text-align:center;font-size:14px;color:#606266}.el-date-editor .el-range-input::-webkit-input-placeholder{color:#C0C4CC}.el-date-editor .el-range-input:-ms-input-placeholder{color:#C0C4CC}.el-date-editor .el-range-input::-ms-input-placeholder{color:#C0C4CC}.el-date-editor .el-range-input::placeholder{color:#C0C4CC}.el-date-editor .el-range-separator{display:inline-block;height:100%;padding:0 5px;margin:0;text-align:center;line-height:32px;font-size:14px;width:5%;color:#303133}.el-date-editor .el-range__close-icon{font-size:14px;color:#C0C4CC;width:25px;display:inline-block;float:right;line-height:32px}.el-range-editor.el-input__inner{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:3px 10px}.el-range-editor .el-range-input{line-height:1}.el-range-editor--medium.el-input__inner{height:36px}.el-range-editor--medium .el-range-separator{line-height:28px;font-size:14px}.el-range-editor--medium .el-range-input{font-size:14px}.el-range-editor--medium .el-range__close-icon,.el-range-editor--medium .el-range__icon{line-height:28px}.el-range-editor--small.el-input__inner{height:32px}.el-range-editor--small .el-range-separator{line-height:24px;font-size:13px}.el-range-editor--small .el-range-input{font-size:13px}.el-range-editor--small .el-range__close-icon,.el-range-editor--small .el-range__icon{line-height:24px}.el-range-editor--mini.el-input__inner{height:28px}.el-range-editor--mini .el-range-separator{line-height:20px;font-size:12px}.el-range-editor--mini .el-range-input{font-size:12px}.el-range-editor--mini .el-range__close-icon,.el-range-editor--mini .el-range__icon{line-height:20px}.el-range-editor.is-disabled{background-color:#F5F7FA;border-color:#E4E7ED;color:#C0C4CC;cursor:not-allowed}.el-range-editor.is-disabled:focus,.el-range-editor.is-disabled:hover{border-color:#E4E7ED}.el-range-editor.is-disabled input{background-color:#F5F7FA;color:#C0C4CC;cursor:not-allowed}.el-range-editor.is-disabled input::-webkit-input-placeholder{color:#C0C4CC}.el-range-editor.is-disabled input:-ms-input-placeholder{color:#C0C4CC}.el-range-editor.is-disabled input::-ms-input-placeholder{color:#C0C4CC}.el-range-editor.is-disabled input::placeholder{color:#C0C4CC}.el-range-editor.is-disabled .el-range-separator{color:#C0C4CC}.el-picker-panel{color:#606266;border:1px solid #E4E7ED;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);background:#FFF;border-radius:4px;line-height:30px;margin:5px 0}.el-picker-panel__body-wrapper::after,.el-picker-panel__body::after{content:"";display:table;clear:both}.el-picker-panel__content{position:relative;margin:15px}.el-picker-panel__footer{border-top:1px solid #e4e4e4;padding:4px;text-align:right;background-color:#FFF;position:relative;font-size:0}.el-picker-panel__shortcut{display:block;width:100%;border:0;background-color:transparent;line-height:28px;font-size:14px;color:#606266;padding-left:12px;text-align:left;outline:0;cursor:pointer}.el-picker-panel__shortcut:hover{color:#409EFF}.el-picker-panel__shortcut.active{background-color:#e6f1fe;color:#409EFF}.el-picker-panel__btn{border:1px solid #dcdcdc;color:#333;line-height:24px;border-radius:2px;padding:0 20px;cursor:pointer;background-color:transparent;outline:0;font-size:12px}.el-picker-panel__btn[disabled]{color:#ccc;cursor:not-allowed}.el-picker-panel__icon-btn{font-size:12px;color:#303133;border:0;background:0 0;cursor:pointer;outline:0;margin-top:8px}.el-picker-panel__icon-btn:hover{color:#409EFF}.el-picker-panel__icon-btn.is-disabled{color:#bbb}.el-picker-panel__icon-btn.is-disabled:hover{cursor:not-allowed}.el-picker-panel__link-btn{vertical-align:middle}.el-picker-panel [slot=sidebar],.el-picker-panel__sidebar{position:absolute;top:0;bottom:0;width:110px;border-right:1px solid #e4e4e4;-webkit-box-sizing:border-box;box-sizing:border-box;padding-top:6px;background-color:#FFF;overflow:auto}.el-picker-panel [slot=sidebar]+.el-picker-panel__body,.el-picker-panel__sidebar+.el-picker-panel__body{margin-left:110px}.el-time-spinner.has-seconds .el-time-spinner__wrapper{width:33.3%}.el-time-spinner__wrapper{max-height:190px;overflow:auto;display:inline-block;width:50%;vertical-align:top;position:relative}.el-time-spinner__wrapper .el-scrollbar__wrap:not(.el-scrollbar__wrap--hidden-default){padding-bottom:15px}.el-time-spinner__input.el-input .el-input__inner,.el-time-spinner__list{padding:0;text-align:center}.el-time-spinner__wrapper.is-arrow{-webkit-box-sizing:border-box;box-sizing:border-box;text-align:center;overflow:hidden}.el-time-spinner__wrapper.is-arrow .el-time-spinner__list{-webkit-transform:translateY(-32px);transform:translateY(-32px)}.el-time-spinner__wrapper.is-arrow .el-time-spinner__item:hover:not(.disabled):not(.active){background:#FFF;cursor:default}.el-time-spinner__arrow{font-size:12px;color:#909399;position:absolute;left:0;width:100%;z-index:1;text-align:center;height:30px;line-height:30px;cursor:pointer}.el-time-spinner__arrow:hover{color:#409EFF}.el-time-spinner__arrow.el-icon-arrow-up{top:10px}.el-time-spinner__arrow.el-icon-arrow-down{bottom:10px}.el-time-spinner__input.el-input{width:70%}.el-time-spinner__list{margin:0;list-style:none}.el-time-spinner__list::after,.el-time-spinner__list::before{content:'';display:block;width:100%;height:80px}.el-time-spinner__item{height:32px;line-height:32px;font-size:12px;color:#606266}.el-time-spinner__item:hover:not(.disabled):not(.active){background:#F5F7FA;cursor:pointer}.el-time-spinner__item.active:not(.disabled){color:#303133;font-weight:700}.el-time-spinner__item.disabled{color:#C0C4CC;cursor:not-allowed}.el-time-panel{margin:5px 0;border:1px solid #E4E7ED;background-color:#FFF;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);border-radius:2px;position:absolute;width:180px;left:0;z-index:1000;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-box-sizing:content-box;box-sizing:content-box}.el-time-panel__content{font-size:0;position:relative;overflow:hidden}.el-time-panel__content::after,.el-time-panel__content::before{content:"";top:50%;position:absolute;margin-top:-15px;height:32px;z-index:-1;left:0;right:0;-webkit-box-sizing:border-box;box-sizing:border-box;padding-top:6px;text-align:left;border-top:1px solid #E4E7ED;border-bottom:1px solid #E4E7ED}.el-time-panel__content::after{left:50%;margin-left:12%;margin-right:12%}.el-time-panel__content::before{padding-left:50%;margin-right:12%;margin-left:12%}.el-time-panel__content.has-seconds::after{left:calc(100% / 3 * 2)}.el-time-panel__content.has-seconds::before{padding-left:calc(100% / 3)}.el-time-panel__footer{border-top:1px solid #e4e4e4;padding:4px;height:36px;line-height:25px;text-align:right;-webkit-box-sizing:border-box;box-sizing:border-box}.el-time-panel__btn{border:none;line-height:28px;padding:0 5px;margin:0 5px;cursor:pointer;background-color:transparent;outline:0;font-size:12px;color:#303133}.el-time-panel__btn.confirm{font-weight:800;color:#409EFF}.el-time-range-picker{width:354px;overflow:visible}.el-time-range-picker__content{position:relative;text-align:center;padding:10px}.el-time-range-picker__cell{-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:4px 7px 7px;width:50%;display:inline-block}.el-time-range-picker__header{margin-bottom:5px;text-align:center;font-size:14px}.el-time-range-picker__body{border-radius:2px;border:1px solid #E4E7ED}.el-popover{position:absolute;background:#FFF;min-width:150px;border-radius:4px;border:1px solid #EBEEF5;padding:12px;z-index:2000;color:#606266;line-height:1.4;text-align:justify;font-size:14px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);word-break:break-all}.el-card.is-always-shadow,.el-card.is-hover-shadow:focus,.el-card.is-hover-shadow:hover,.el-cascader__dropdown,.el-color-picker__panel,.el-message-box,.el-notification{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-popover--plain{padding:18px 20px}.el-popover__title{color:#303133;font-size:16px;line-height:1;margin-bottom:12px}.el-popover:focus,.el-popover:focus:active,.el-popover__reference:focus:hover,.el-popover__reference:focus:not(.focusing){outline-width:0}.v-modal-enter{-webkit-animation:v-modal-in .2s ease;animation:v-modal-in .2s ease}.v-modal-leave{-webkit-animation:v-modal-out .2s ease forwards;animation:v-modal-out .2s ease forwards}@keyframes v-modal-in{0%{opacity:0}}@keyframes v-modal-out{100%{opacity:0}}.v-modal{position:fixed;left:0;top:0;width:100%;height:100%;opacity:.5;background:#000}.el-popup-parent--hidden{overflow:hidden}.el-message-box{display:inline-block;width:420px;padding-bottom:10px;vertical-align:middle;background-color:#FFF;border-radius:4px;border:1px solid #EBEEF5;font-size:18px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);text-align:left;overflow:hidden;-webkit-backface-visibility:hidden;backface-visibility:hidden}.el-message-box__wrapper{position:fixed;top:0;bottom:0;left:0;right:0;text-align:center}.el-message-box__wrapper::after{content:"";display:inline-block;height:100%;width:0;vertical-align:middle}.el-message-box__header{position:relative;padding:15px 15px 10px}.el-message-box__title{padding-left:0;margin-bottom:0;font-size:18px;line-height:1;color:#303133}.el-message-box__headerbtn{position:absolute;top:15px;right:15px;padding:0;border:none;outline:0;background:0 0;font-size:16px;cursor:pointer}.el-form-item.is-error .el-input__inner,.el-form-item.is-error .el-input__inner:focus,.el-form-item.is-error .el-textarea__inner,.el-form-item.is-error .el-textarea__inner:focus,.el-message-box__input input.invalid,.el-message-box__input input.invalid:focus{border-color:#F56C6C}.el-message-box__headerbtn .el-message-box__close{color:#909399}.el-message-box__headerbtn:focus .el-message-box__close,.el-message-box__headerbtn:hover .el-message-box__close{color:#409EFF}.el-message-box__content{padding:10px 15px;color:#606266;font-size:14px}.el-message-box__container{position:relative}.el-message-box__input{padding-top:15px}.el-message-box__status{position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);font-size:24px!important}.el-message-box__status::before{padding-left:1px}.el-message-box__status+.el-message-box__message{padding-left:36px;padding-right:12px}.el-message-box__status.el-icon-success{color:#67C23A}.el-message-box__status.el-icon-info{color:#909399}.el-message-box__status.el-icon-warning{color:#E6A23C}.el-message-box__status.el-icon-error{color:#F56C6C}.el-message-box__message{margin:0}.el-message-box__message p{margin:0;line-height:24px}.el-message-box__errormsg{color:#F56C6C;font-size:12px;min-height:18px;margin-top:2px}.el-message-box__btns{padding:5px 15px 0;text-align:right}.el-message-box__btns button:nth-child(2){margin-left:10px}.el-message-box__btns-reverse{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.el-message-box--center{padding-bottom:30px}.el-message-box--center .el-message-box__header{padding-top:30px}.el-message-box--center .el-message-box__title{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-message-box--center .el-message-box__status{position:relative;top:auto;padding-right:5px;text-align:center;-webkit-transform:translateY(-1px);transform:translateY(-1px)}.el-message-box--center .el-message-box__message{margin-left:0}.el-message-box--center .el-message-box__btns,.el-message-box--center .el-message-box__content{text-align:center}.el-message-box--center .el-message-box__content{padding-left:27px;padding-right:27px}.msgbox-fade-enter-active{-webkit-animation:msgbox-fade-in .3s;animation:msgbox-fade-in .3s}.msgbox-fade-leave-active{-webkit-animation:msgbox-fade-out .3s;animation:msgbox-fade-out .3s}@-webkit-keyframes msgbox-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes msgbox-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes msgbox-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes msgbox-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-breadcrumb{font-size:14px;line-height:1}.el-breadcrumb::after,.el-breadcrumb::before{display:table;content:""}.el-breadcrumb::after{clear:both}.el-breadcrumb__separator{margin:0 9px;font-weight:700;color:#C0C4CC}.el-breadcrumb__separator[class*=icon]{margin:0 6px;font-weight:400}.el-breadcrumb__item{float:left}.el-breadcrumb__inner{color:#606266}.el-breadcrumb__inner a,.el-breadcrumb__inner.is-link{font-weight:700;text-decoration:none;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1);color:#303133}.el-breadcrumb__inner a:hover,.el-breadcrumb__inner.is-link:hover{color:#409EFF;cursor:pointer}.el-breadcrumb__item:last-child .el-breadcrumb__inner,.el-breadcrumb__item:last-child .el-breadcrumb__inner a,.el-breadcrumb__item:last-child .el-breadcrumb__inner a:hover,.el-breadcrumb__item:last-child .el-breadcrumb__inner:hover{font-weight:400;color:#606266;cursor:text}.el-form--label-left .el-form-item__label{text-align:left}.el-form--label-top .el-form-item__label{float:none;display:inline-block;text-align:left;padding:0 0 10px}.el-form--inline .el-form-item{display:inline-block;margin-right:10px;vertical-align:top}.el-form--inline .el-form-item__label{float:none;display:inline-block}.el-form--inline .el-form-item__content{display:inline-block;vertical-align:top}.el-form--inline.el-form--label-top .el-form-item__content{display:block}.el-form-item{margin-bottom:22px}.el-form-item::after,.el-form-item::before{display:table;content:""}.el-form-item::after{clear:both}.el-form-item .el-form-item{margin-bottom:0}.el-form-item--mini.el-form-item,.el-form-item--small.el-form-item{margin-bottom:18px}.el-form-item .el-input__validateIcon{display:none}.el-form-item--medium .el-form-item__content,.el-form-item--medium .el-form-item__label{line-height:36px}.el-form-item--small .el-form-item__content,.el-form-item--small .el-form-item__label{line-height:32px}.el-form-item--small .el-form-item__error{padding-top:2px}.el-form-item--mini .el-form-item__content,.el-form-item--mini .el-form-item__label{line-height:28px}.el-form-item--mini .el-form-item__error{padding-top:1px}.el-form-item__label-wrap{float:left}.el-form-item__label-wrap .el-form-item__label{display:inline-block;float:none}.el-form-item__label{text-align:right;vertical-align:middle;float:left;font-size:14px;color:#606266;line-height:40px;padding:0 12px 0 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-form-item__content{line-height:40px;position:relative;font-size:14px}.el-form-item__content::after,.el-form-item__content::before{display:table;content:""}.el-form-item__content::after{clear:both}.el-form-item__content .el-input-group{vertical-align:top}.el-form-item__error{color:#F56C6C;font-size:12px;line-height:1;padding-top:4px;position:absolute;top:100%;left:0}.el-form-item__error--inline{position:relative;top:auto;left:auto;display:inline-block;margin-left:10px}.el-form-item.is-required:not(.is-no-asterisk) .el-form-item__label-wrap>.el-form-item__label:before,.el-form-item.is-required:not(.is-no-asterisk)>.el-form-item__label:before{content:'*';color:#F56C6C;margin-right:4px}.el-form-item.is-error .el-input-group__append .el-input__inner,.el-form-item.is-error .el-input-group__prepend .el-input__inner{border-color:transparent}.el-form-item.is-error .el-input__validateIcon{color:#F56C6C}.el-form-item--feedback .el-input__validateIcon{display:inline-block}.el-tabs__header{padding:0;position:relative;margin:0 0 15px}.el-tabs__active-bar{position:absolute;bottom:0;left:0;height:2px;background-color:#409EFF;z-index:1;-webkit-transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1),-webkit-transform .3s cubic-bezier(.645,.045,.355,1);list-style:none}.el-tabs__new-tab{float:right;border:1px solid #d3dce6;height:18px;width:18px;line-height:18px;margin:12px 0 9px 10px;border-radius:3px;text-align:center;font-size:12px;color:#d3dce6;cursor:pointer;-webkit-transition:all .15s;transition:all .15s}.el-tabs__new-tab .el-icon-plus{-webkit-transform:scale(.8,.8);transform:scale(.8,.8)}.el-tabs__new-tab:hover{color:#409EFF}.el-tabs__nav-wrap{overflow:hidden;margin-bottom:-1px;position:relative}.el-tabs__nav-wrap::after{content:"";position:absolute;left:0;bottom:0;width:100%;height:2px;background-color:#E4E7ED;z-index:1}.el-tabs__nav-wrap.is-scrollable{padding:0 20px;-webkit-box-sizing:border-box;box-sizing:border-box}.el-tabs__nav-scroll{overflow:hidden}.el-tabs__nav-next,.el-tabs__nav-prev{position:absolute;cursor:pointer;line-height:44px;font-size:12px;color:#909399}.el-tabs__nav-next{right:0}.el-tabs__nav-prev{left:0}.el-tabs__nav{white-space:nowrap;position:relative;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;float:left;z-index:2}.el-tabs__nav.is-stretch{min-width:100%;display:-webkit-box;display:-ms-flexbox;display:flex}.el-tabs__nav.is-stretch>*{-webkit-box-flex:1;-ms-flex:1;flex:1;text-align:center}.el-tabs__item{padding:0 20px;height:40px;-webkit-box-sizing:border-box;box-sizing:border-box;line-height:40px;display:inline-block;list-style:none;font-size:14px;font-weight:500;color:#303133;position:relative}.el-tabs__item:focus,.el-tabs__item:focus:active{outline:0}.el-tabs__item:focus.is-active.is-focus:not(:active){-webkit-box-shadow:0 0 2px 2px #409EFF inset;box-shadow:0 0 2px 2px #409EFF inset;border-radius:3px}.el-tabs__item .el-icon-close{border-radius:50%;text-align:center;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);margin-left:5px}.el-tabs__item .el-icon-close:before{-webkit-transform:scale(.9);transform:scale(.9);display:inline-block}.el-tabs--card>.el-tabs__header .el-tabs__active-bar,.el-tabs--left.el-tabs--card .el-tabs__active-bar.is-left,.el-tabs--right.el-tabs--card .el-tabs__active-bar.is-right{display:none}.el-tabs__item .el-icon-close:hover{background-color:#C0C4CC;color:#FFF}.el-tabs__item.is-active{color:#409EFF}.el-tabs__item:hover{color:#409EFF;cursor:pointer}.el-tabs__item.is-disabled{color:#C0C4CC;cursor:default}.el-tabs__content{overflow:hidden;position:relative}.el-tabs--card>.el-tabs__header{border-bottom:1px solid #E4E7ED}.el-tabs--card>.el-tabs__header .el-tabs__nav-wrap::after{content:none}.el-tabs--card>.el-tabs__header .el-tabs__nav{border:1px solid #E4E7ED;border-bottom:none;border-radius:4px 4px 0 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-tabs--card>.el-tabs__header .el-tabs__item .el-icon-close{position:relative;font-size:12px;width:0;height:14px;vertical-align:middle;line-height:15px;overflow:hidden;top:-1px;right:-2px;-webkit-transform-origin:100% 50%;transform-origin:100% 50%}.el-tabs--card>.el-tabs__header .el-tabs__item{border-bottom:1px solid transparent;border-left:1px solid #E4E7ED;-webkit-transition:color .3s cubic-bezier(.645,.045,.355,1),padding .3s cubic-bezier(.645,.045,.355,1);transition:color .3s cubic-bezier(.645,.045,.355,1),padding .3s cubic-bezier(.645,.045,.355,1)}.el-tabs--card>.el-tabs__header .el-tabs__item:first-child{border-left:none}.el-tabs--card>.el-tabs__header .el-tabs__item.is-closable:hover{padding-left:13px;padding-right:13px}.el-tabs--card>.el-tabs__header .el-tabs__item.is-closable:hover .el-icon-close{width:14px}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active{border-bottom-color:#FFF}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active.is-closable{padding-left:20px;padding-right:20px}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active.is-closable .el-icon-close{width:14px}.el-tabs--border-card{background:#FFF;border:1px solid #DCDFE6;-webkit-box-shadow:0 2px 4px 0 rgba(0,0,0,.12),0 0 6px 0 rgba(0,0,0,.04);box-shadow:0 2px 4px 0 rgba(0,0,0,.12),0 0 6px 0 rgba(0,0,0,.04)}.el-tabs--border-card>.el-tabs__content{padding:15px}.el-tabs--border-card>.el-tabs__header{background-color:#F5F7FA;border-bottom:1px solid #E4E7ED;margin:0}.el-tabs--border-card>.el-tabs__header .el-tabs__nav-wrap::after{content:none}.el-tabs--border-card>.el-tabs__header .el-tabs__item{-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);border:1px solid transparent;margin-top:-1px;color:#909399}.el-tabs--border-card>.el-tabs__header .el-tabs__item+.el-tabs__item,.el-tabs--border-card>.el-tabs__header .el-tabs__item:first-child{margin-left:-1px}.el-col-offset-0,.el-tabs--border-card>.el-tabs__header .is-scrollable .el-tabs__item:first-child{margin-left:0}.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-active{color:#409EFF;background-color:#FFF;border-right-color:#DCDFE6;border-left-color:#DCDFE6}.el-tabs--border-card>.el-tabs__header .el-tabs__item:not(.is-disabled):hover{color:#409EFF}.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-disabled{color:#C0C4CC}.el-tabs--bottom .el-tabs__item.is-bottom:nth-child(2),.el-tabs--bottom .el-tabs__item.is-top:nth-child(2),.el-tabs--top .el-tabs__item.is-bottom:nth-child(2),.el-tabs--top .el-tabs__item.is-top:nth-child(2){padding-left:0}.el-tabs--bottom .el-tabs__item.is-bottom:last-child,.el-tabs--bottom .el-tabs__item.is-top:last-child,.el-tabs--top .el-tabs__item.is-bottom:last-child,.el-tabs--top .el-tabs__item.is-top:last-child{padding-right:0}.el-cascader-menu:last-child .el-cascader-node,.el-tabs--bottom .el-tabs--left>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom .el-tabs--right>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom.el-tabs--border-card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom.el-tabs--card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top .el-tabs--left>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top .el-tabs--right>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top.el-tabs--border-card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top.el-tabs--card>.el-tabs__header .el-tabs__item:last-child{padding-right:20px}.el-tabs--bottom .el-tabs--left>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom .el-tabs--right>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom.el-tabs--border-card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom.el-tabs--card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top .el-tabs--left>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top .el-tabs--right>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top.el-tabs--border-card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top.el-tabs--card>.el-tabs__header .el-tabs__item:nth-child(2){padding-left:20px}.el-tabs--bottom .el-tabs__header.is-bottom{margin-bottom:0;margin-top:10px}.el-tabs--bottom.el-tabs--border-card .el-tabs__header.is-bottom{border-bottom:0;border-top:1px solid #DCDFE6}.el-tabs--bottom.el-tabs--border-card .el-tabs__nav-wrap.is-bottom{margin-top:-1px;margin-bottom:0}.el-tabs--bottom.el-tabs--border-card .el-tabs__item.is-bottom:not(.is-active){border:1px solid transparent}.el-tabs--bottom.el-tabs--border-card .el-tabs__item.is-bottom{margin:0 -1px -1px}.el-tabs--left,.el-tabs--right{overflow:hidden}.el-tabs--left .el-tabs__header.is-left,.el-tabs--left .el-tabs__header.is-right,.el-tabs--left .el-tabs__nav-scroll,.el-tabs--left .el-tabs__nav-wrap.is-left,.el-tabs--left .el-tabs__nav-wrap.is-right,.el-tabs--right .el-tabs__header.is-left,.el-tabs--right .el-tabs__header.is-right,.el-tabs--right .el-tabs__nav-scroll,.el-tabs--right .el-tabs__nav-wrap.is-left,.el-tabs--right .el-tabs__nav-wrap.is-right{height:100%}.el-tabs--left .el-tabs__active-bar.is-left,.el-tabs--left .el-tabs__active-bar.is-right,.el-tabs--right .el-tabs__active-bar.is-left,.el-tabs--right .el-tabs__active-bar.is-right{top:0;bottom:auto;width:2px;height:auto}.el-tabs--left .el-tabs__nav-wrap.is-left,.el-tabs--left .el-tabs__nav-wrap.is-right,.el-tabs--right .el-tabs__nav-wrap.is-left,.el-tabs--right .el-tabs__nav-wrap.is-right{margin-bottom:0}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev{height:30px;line-height:30px;width:100%;text-align:center;cursor:pointer}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next i,.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev i,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next i,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev i,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next i,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev i,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next i,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev i{-webkit-transform:rotateZ(90deg);transform:rotateZ(90deg)}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev{left:auto;top:0}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next{right:auto;bottom:0}.el-tabs--left .el-tabs__active-bar.is-left,.el-tabs--left .el-tabs__nav-wrap.is-left::after{right:0;left:auto}.el-tabs--left .el-tabs__nav-wrap.is-left.is-scrollable,.el-tabs--left .el-tabs__nav-wrap.is-right.is-scrollable,.el-tabs--right .el-tabs__nav-wrap.is-left.is-scrollable,.el-tabs--right .el-tabs__nav-wrap.is-right.is-scrollable{padding:30px 0}.el-tabs--left .el-tabs__nav-wrap.is-left::after,.el-tabs--left .el-tabs__nav-wrap.is-right::after,.el-tabs--right .el-tabs__nav-wrap.is-left::after,.el-tabs--right .el-tabs__nav-wrap.is-right::after{height:100%;width:2px;bottom:auto;top:0}.el-tabs--left .el-tabs__nav.is-left,.el-tabs--left .el-tabs__nav.is-right,.el-tabs--right .el-tabs__nav.is-left,.el-tabs--right .el-tabs__nav.is-right{float:none}.el-tabs--left .el-tabs__item.is-left,.el-tabs--left .el-tabs__item.is-right,.el-tabs--right .el-tabs__item.is-left,.el-tabs--right .el-tabs__item.is-right{display:block}.el-tabs--left .el-tabs__header.is-left{float:left;margin-bottom:0;margin-right:10px}.el-button-group>.el-button:not(:last-child),.el-tabs--left .el-tabs__nav-wrap.is-left{margin-right:-1px}.el-tabs--left .el-tabs__item.is-left{text-align:right}.el-tabs--left.el-tabs--card .el-tabs__item.is-left{border-left:none;border-right:1px solid #E4E7ED;border-bottom:none;border-top:1px solid #E4E7ED;text-align:left}.el-tabs--left.el-tabs--card .el-tabs__item.is-left:first-child{border-right:1px solid #E4E7ED;border-top:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active{border:1px solid #E4E7ED;border-right-color:#fff;border-left:none;border-bottom:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active:first-child{border-top:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active:last-child{border-bottom:none}.el-tabs--left.el-tabs--card .el-tabs__nav{border-radius:4px 0 0 4px;border-bottom:1px solid #E4E7ED;border-right:none}.el-tabs--left.el-tabs--card .el-tabs__new-tab{float:none}.el-tabs--left.el-tabs--border-card .el-tabs__header.is-left{border-right:1px solid #dfe4ed}.el-tabs--left.el-tabs--border-card .el-tabs__item.is-left{border:1px solid transparent;margin:-1px 0 -1px -1px}.el-tabs--left.el-tabs--border-card .el-tabs__item.is-left.is-active{border-color:#d1dbe5 transparent}.el-tabs--right .el-tabs__header.is-right{float:right;margin-bottom:0;margin-left:10px}.el-tabs--right .el-tabs__nav-wrap.is-right{margin-left:-1px}.el-tabs--right .el-tabs__nav-wrap.is-right::after{left:0;right:auto}.el-tabs--right .el-tabs__active-bar.is-right{left:0}.el-tabs--right.el-tabs--card .el-tabs__item.is-right{border-bottom:none;border-top:1px solid #E4E7ED}.el-tabs--right.el-tabs--card .el-tabs__item.is-right:first-child{border-left:1px solid #E4E7ED;border-top:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active{border:1px solid #E4E7ED;border-left-color:#fff;border-right:none;border-bottom:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active:first-child{border-top:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active:last-child{border-bottom:none}.el-tabs--right.el-tabs--card .el-tabs__nav{border-radius:0 4px 4px 0;border-bottom:1px solid #E4E7ED;border-left:none}.el-tabs--right.el-tabs--border-card .el-tabs__header.is-right{border-left:1px solid #dfe4ed}.el-tabs--right.el-tabs--border-card .el-tabs__item.is-right{border:1px solid transparent;margin:-1px -1px -1px 0}.el-tabs--right.el-tabs--border-card .el-tabs__item.is-right.is-active{border-color:#d1dbe5 transparent}.slideInLeft-transition,.slideInRight-transition{display:inline-block}.slideInRight-enter{-webkit-animation:slideInRight-enter .3s;animation:slideInRight-enter .3s}.slideInRight-leave{position:absolute;left:0;right:0;-webkit-animation:slideInRight-leave .3s;animation:slideInRight-leave .3s}.slideInLeft-enter{-webkit-animation:slideInLeft-enter .3s;animation:slideInLeft-enter .3s}.slideInLeft-leave{position:absolute;left:0;right:0;-webkit-animation:slideInLeft-leave .3s;animation:slideInLeft-leave .3s}@-webkit-keyframes slideInRight-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideInRight-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes slideInRight-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);opacity:0}}@keyframes slideInRight-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);opacity:0}}@-webkit-keyframes slideInLeft-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideInLeft-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes slideInLeft-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%);opacity:0}}@keyframes slideInLeft-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%);opacity:0}}.el-tree{position:relative;cursor:default;background:#FFF;color:#606266}.el-tree__empty-block{position:relative;min-height:60px;text-align:center;width:100%;height:100%}.el-tree__empty-text{position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);color:#909399;font-size:14px}.el-tree__drop-indicator{position:absolute;left:0;right:0;height:1px;background-color:#409EFF}.el-tree-node{white-space:nowrap;outline:0}.el-tree-node:focus>.el-tree-node__content{background-color:#F5F7FA}.el-tree-node.is-drop-inner>.el-tree-node__content .el-tree-node__label{background-color:#409EFF;color:#fff}.el-tree-node__content:hover,.el-upload-list__item:hover{background-color:#F5F7FA}.el-tree-node__content{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:26px;cursor:pointer}.el-tree-node__content>.el-tree-node__expand-icon{padding:6px}.el-tree-node__content>label.el-checkbox{margin-right:8px}.el-tree.is-dragging .el-tree-node__content{cursor:move}.el-tree.is-dragging .el-tree-node__content *{pointer-events:none}.el-tree.is-dragging.is-drop-not-allow .el-tree-node__content{cursor:not-allowed}.el-tree-node__expand-icon{cursor:pointer;color:#C0C4CC;font-size:12px;-webkit-transform:rotate(0);transform:rotate(0);-webkit-transition:-webkit-transform .3s ease-in-out;transition:-webkit-transform .3s ease-in-out;transition:transform .3s ease-in-out;transition:transform .3s ease-in-out,-webkit-transform .3s ease-in-out}.el-tree-node__expand-icon.expanded{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-tree-node__expand-icon.is-leaf{color:transparent;cursor:default}.el-tree-node__label{font-size:14px}.el-tree-node__loading-icon{margin-right:8px;font-size:14px;color:#C0C4CC}.el-tree-node>.el-tree-node__children{overflow:hidden;background-color:transparent}.el-tree-node.is-expanded>.el-tree-node__children{display:block}.el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content{background-color:#f0f7ff}.el-alert{width:100%;padding:8px 16px;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;position:relative;background-color:#FFF;overflow:hidden;opacity:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:opacity .2s;transition:opacity .2s}.el-alert.is-light .el-alert__closebtn{color:#C0C4CC}.el-alert.is-dark .el-alert__closebtn,.el-alert.is-dark .el-alert__description{color:#FFF}.el-alert.is-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-alert--success.is-light{background-color:#f0f9eb;color:#67C23A}.el-alert--success.is-light .el-alert__description{color:#67C23A}.el-alert--success.is-dark{background-color:#67C23A;color:#FFF}.el-alert--info.is-light{background-color:#f4f4f5;color:#909399}.el-alert--info.is-dark{background-color:#909399;color:#FFF}.el-alert--info .el-alert__description{color:#909399}.el-alert--warning.is-light{background-color:#fdf6ec;color:#E6A23C}.el-alert--warning.is-light .el-alert__description{color:#E6A23C}.el-alert--warning.is-dark{background-color:#E6A23C;color:#FFF}.el-alert--error.is-light{background-color:#fef0f0;color:#F56C6C}.el-alert--error.is-light .el-alert__description{color:#F56C6C}.el-alert--error.is-dark{background-color:#F56C6C;color:#FFF}.el-alert__content{display:table-cell;padding:0 8px}.el-alert__icon{font-size:16px;width:16px}.el-alert__icon.is-big{font-size:28px;width:28px}.el-alert__title{font-size:13px;line-height:18px}.el-alert__title.is-bold{font-weight:700}.el-alert .el-alert__description{font-size:12px;margin:5px 0 0}.el-alert__closebtn{font-size:12px;opacity:1;position:absolute;top:12px;right:15px;cursor:pointer}.el-alert-fade-enter,.el-alert-fade-leave-active,.el-loading-fade-enter,.el-loading-fade-leave-active,.el-notification-fade-leave-active,.el-upload iframe{opacity:0}.el-carousel__arrow--right,.el-notification.right{right:16px}.el-alert__closebtn.is-customed{font-style:normal;font-size:13px;top:9px}.el-notification{display:-webkit-box;display:-ms-flexbox;display:flex;width:330px;padding:14px 26px 14px 13px;border-radius:8px;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid #EBEEF5;position:fixed;background-color:#FFF;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-transition:opacity .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;transition:opacity .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;transition:opacity .3s,transform .3s,left .3s,right .3s,top .4s,bottom .3s;transition:opacity .3s,transform .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;overflow:hidden}.el-notification.left{left:16px}.el-notification__group{margin-left:13px;margin-right:8px}.el-notification__title{font-weight:700;font-size:16px;color:#303133;margin:0}.el-notification__content{font-size:14px;line-height:21px;margin:6px 0 0;color:#606266;text-align:justify}.el-notification__content p{margin:0}.el-notification__icon{height:24px;width:24px;font-size:24px}.el-notification__closeBtn{position:absolute;top:18px;right:15px;cursor:pointer;color:#909399;font-size:16px}.el-notification__closeBtn:hover{color:#606266}.el-notification .el-icon-success{color:#67C23A}.el-notification .el-icon-error{color:#F56C6C}.el-notification .el-icon-info{color:#909399}.el-notification .el-icon-warning{color:#E6A23C}.el-notification-fade-enter.right{right:0;-webkit-transform:translateX(100%);transform:translateX(100%)}.el-notification-fade-enter.left{left:0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}.el-input-number{position:relative;display:inline-block;width:180px;line-height:38px}.el-input-number .el-input{display:block}.el-input-number .el-input__inner{-webkit-appearance:none;padding-left:50px;padding-right:50px;text-align:center}.el-input-number__decrease,.el-input-number__increase{position:absolute;z-index:1;top:1px;width:40px;height:auto;text-align:center;background:#F5F7FA;color:#606266;cursor:pointer;font-size:13px}.el-input-number__decrease:hover,.el-input-number__increase:hover{color:#409EFF}.el-input-number__decrease:hover:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled),.el-input-number__increase:hover:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled){border-color:#409EFF}.el-input-number__decrease.is-disabled,.el-input-number__increase.is-disabled{color:#C0C4CC;cursor:not-allowed}.el-input-number__increase{right:1px;border-radius:0 4px 4px 0;border-left:1px solid #DCDFE6}.el-input-number__decrease{left:1px;border-radius:4px 0 0 4px;border-right:1px solid #DCDFE6}.el-input-number.is-disabled .el-input-number__decrease,.el-input-number.is-disabled .el-input-number__increase{border-color:#E4E7ED;color:#E4E7ED}.el-input-number.is-disabled .el-input-number__decrease:hover,.el-input-number.is-disabled .el-input-number__increase:hover{color:#E4E7ED;cursor:not-allowed}.el-input-number--medium{width:200px;line-height:34px}.el-input-number--medium .el-input-number__decrease,.el-input-number--medium .el-input-number__increase{width:36px;font-size:14px}.el-input-number--medium .el-input__inner{padding-left:43px;padding-right:43px}.el-input-number--small{width:130px;line-height:30px}.el-input-number--small .el-input-number__decrease,.el-input-number--small .el-input-number__increase{width:32px;font-size:13px}.el-input-number--small .el-input-number__decrease [class*=el-icon],.el-input-number--small .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.9);transform:scale(.9)}.el-input-number--small .el-input__inner{padding-left:39px;padding-right:39px}.el-input-number--mini{width:130px;line-height:26px}.el-input-number--mini .el-input-number__decrease,.el-input-number--mini .el-input-number__increase{width:28px;font-size:12px}.el-input-number--mini .el-input-number__decrease [class*=el-icon],.el-input-number--mini .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.8);transform:scale(.8)}.el-input-number--mini .el-input__inner{padding-left:35px;padding-right:35px}.el-input-number.is-without-controls .el-input__inner{padding-left:15px;padding-right:15px}.el-input-number.is-controls-right .el-input__inner{padding-left:15px;padding-right:50px}.el-input-number.is-controls-right .el-input-number__decrease,.el-input-number.is-controls-right .el-input-number__increase{height:auto;line-height:19px}.el-input-number.is-controls-right .el-input-number__decrease [class*=el-icon],.el-input-number.is-controls-right .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.8);transform:scale(.8)}.el-input-number.is-controls-right .el-input-number__increase{border-radius:0 4px 0 0;border-bottom:1px solid #DCDFE6}.el-input-number.is-controls-right .el-input-number__decrease{right:1px;bottom:1px;top:auto;left:auto;border-right:none;border-left:1px solid #DCDFE6;border-radius:0 0 4px}.el-input-number.is-controls-right[class*=medium] [class*=decrease],.el-input-number.is-controls-right[class*=medium] [class*=increase]{line-height:17px}.el-input-number.is-controls-right[class*=small] [class*=decrease],.el-input-number.is-controls-right[class*=small] [class*=increase]{line-height:15px}.el-input-number.is-controls-right[class*=mini] [class*=decrease],.el-input-number.is-controls-right[class*=mini] [class*=increase]{line-height:13px}.el-tooltip:focus:hover,.el-tooltip:focus:not(.focusing){outline-width:0}.el-tooltip__popper{position:absolute;border-radius:4px;padding:10px;z-index:2000;font-size:12px;line-height:1.2;min-width:10px;word-wrap:break-word}.el-tooltip__popper .popper__arrow,.el-tooltip__popper .popper__arrow::after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-tooltip__popper .popper__arrow{border-width:6px}.el-tooltip__popper .popper__arrow::after{content:" ";border-width:5px}.el-button-group::after,.el-button-group::before,.el-color-dropdown__main-wrapper::after,.el-link.is-underline:hover:after,.el-page-header__left::after,.el-progress-bar__inner::after,.el-row::after,.el-row::before,.el-slider::after,.el-slider::before,.el-slider__button-wrapper::after,.el-transfer-panel .el-transfer-panel__footer::after,.el-upload-cover::after,.el-upload-list--picture-card .el-upload-list__item-actions::after{content:""}.el-tooltip__popper[x-placement^=top]{margin-bottom:12px}.el-tooltip__popper[x-placement^=top] .popper__arrow{bottom:-6px;border-top-color:#303133;border-bottom-width:0}.el-tooltip__popper[x-placement^=top] .popper__arrow::after{bottom:1px;margin-left:-5px;border-top-color:#303133;border-bottom-width:0}.el-tooltip__popper[x-placement^=bottom]{margin-top:12px}.el-tooltip__popper[x-placement^=bottom] .popper__arrow{top:-6px;border-top-width:0;border-bottom-color:#303133}.el-tooltip__popper[x-placement^=bottom] .popper__arrow::after{top:1px;margin-left:-5px;border-top-width:0;border-bottom-color:#303133}.el-tooltip__popper[x-placement^=right]{margin-left:12px}.el-tooltip__popper[x-placement^=right] .popper__arrow{left:-6px;border-right-color:#303133;border-left-width:0}.el-tooltip__popper[x-placement^=right] .popper__arrow::after{bottom:-5px;left:1px;border-right-color:#303133;border-left-width:0}.el-tooltip__popper[x-placement^=left]{margin-right:12px}.el-tooltip__popper[x-placement^=left] .popper__arrow{right:-6px;border-right-width:0;border-left-color:#303133}.el-tooltip__popper[x-placement^=left] .popper__arrow::after{right:1px;bottom:-5px;margin-left:-5px;border-right-width:0;border-left-color:#303133}.el-tooltip__popper.is-dark{background:#303133;color:#FFF}.el-tooltip__popper.is-light{background:#FFF;border:1px solid #303133}.el-tooltip__popper.is-light[x-placement^=top] .popper__arrow{border-top-color:#303133}.el-tooltip__popper.is-light[x-placement^=top] .popper__arrow::after{border-top-color:#FFF}.el-tooltip__popper.is-light[x-placement^=bottom] .popper__arrow{border-bottom-color:#303133}.el-tooltip__popper.is-light[x-placement^=bottom] .popper__arrow::after{border-bottom-color:#FFF}.el-tooltip__popper.is-light[x-placement^=left] .popper__arrow{border-left-color:#303133}.el-tooltip__popper.is-light[x-placement^=left] .popper__arrow::after{border-left-color:#FFF}.el-tooltip__popper.is-light[x-placement^=right] .popper__arrow{border-right-color:#303133}.el-tooltip__popper.is-light[x-placement^=right] .popper__arrow::after{border-right-color:#FFF}.el-slider::after,.el-slider::before{display:table}.el-slider__button-wrapper .el-tooltip,.el-slider__button-wrapper::after{display:inline-block;vertical-align:middle}.el-slider::after{clear:both}.el-slider__runway{width:100%;height:6px;margin:16px 0;background-color:#E4E7ED;border-radius:3px;position:relative;cursor:pointer;vertical-align:middle}.el-slider__runway.show-input{margin-right:160px;width:auto}.el-slider__runway.disabled{cursor:default}.el-slider__runway.disabled .el-slider__bar{background-color:#C0C4CC}.el-slider__runway.disabled .el-slider__button{border-color:#C0C4CC}.el-slider__runway.disabled .el-slider__button-wrapper.dragging,.el-slider__runway.disabled .el-slider__button-wrapper.hover,.el-slider__runway.disabled .el-slider__button-wrapper:hover{cursor:not-allowed}.el-slider__runway.disabled .el-slider__button.dragging,.el-slider__runway.disabled .el-slider__button.hover,.el-slider__runway.disabled .el-slider__button:hover{-webkit-transform:scale(1);transform:scale(1);cursor:not-allowed}.el-slider__button-wrapper,.el-slider__stop{-webkit-transform:translateX(-50%);position:absolute}.el-slider__input{float:right;margin-top:3px;width:130px}.el-slider__input.el-input-number--mini{margin-top:5px}.el-slider__input.el-input-number--medium{margin-top:0}.el-slider__input.el-input-number--large{margin-top:-2px}.el-slider__bar{height:6px;background-color:#409EFF;border-top-left-radius:3px;border-bottom-left-radius:3px;position:absolute}.el-slider__button-wrapper{height:36px;width:36px;z-index:1001;top:-15px;transform:translateX(-50%);background-color:transparent;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;line-height:normal}.el-image-viewer__btn,.el-slider__button,.el-step__icon-inner{-moz-user-select:none;-ms-user-select:none}.el-slider__button-wrapper::after{height:100%}.el-slider__button-wrapper.hover,.el-slider__button-wrapper:hover{cursor:-webkit-grab;cursor:grab}.el-slider__button-wrapper.dragging{cursor:-webkit-grabbing;cursor:grabbing}.el-slider__button{width:16px;height:16px;border:2px solid #409EFF;background-color:#FFF;border-radius:50%;-webkit-transition:.2s;transition:.2s;-webkit-user-select:none;user-select:none}.el-slider__button.dragging,.el-slider__button.hover,.el-slider__button:hover{-webkit-transform:scale(1.2);transform:scale(1.2)}.el-slider__button.hover,.el-slider__button:hover{cursor:-webkit-grab;cursor:grab}.el-slider__button.dragging{cursor:-webkit-grabbing;cursor:grabbing}.el-slider__stop{height:6px;width:6px;border-radius:100%;background-color:#FFF;transform:translateX(-50%)}.el-slider__marks{top:0;left:12px;width:18px;height:100%}.el-slider__marks-text{position:absolute;-webkit-transform:translateX(-50%);transform:translateX(-50%);font-size:14px;color:#909399;margin-top:15px}.el-slider.is-vertical{position:relative}.el-slider.is-vertical .el-slider__runway{width:6px;height:100%;margin:0 16px}.el-slider.is-vertical .el-slider__bar{width:6px;height:auto;border-radius:0 0 3px 3px}.el-slider.is-vertical .el-slider__button-wrapper{top:auto;left:-15px;-webkit-transform:translateY(50%);transform:translateY(50%)}.el-slider.is-vertical .el-slider__stop{-webkit-transform:translateY(50%);transform:translateY(50%)}.el-slider.is-vertical.el-slider--with-input{padding-bottom:58px}.el-slider.is-vertical.el-slider--with-input .el-slider__input{overflow:visible;float:none;position:absolute;bottom:22px;width:36px;margin-top:15px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input__inner{text-align:center;padding-left:5px;padding-right:5px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase{top:32px;margin-top:-1px;border:1px solid #DCDFE6;line-height:20px;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__decrease{width:18px;right:18px;border-bottom-left-radius:4px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase{width:19px;border-bottom-right-radius:4px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase~.el-input .el-input__inner{border-bottom-left-radius:0;border-bottom-right-radius:0}.el-slider.is-vertical.el-slider--with-input .el-slider__input:hover .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input:hover .el-input-number__increase{border-color:#C0C4CC}.el-slider.is-vertical.el-slider--with-input .el-slider__input:active .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input:active .el-input-number__increase{border-color:#409EFF}.el-slider.is-vertical .el-slider__marks-text{margin-top:0;left:15px;-webkit-transform:translateY(50%);transform:translateY(50%)}.el-loading-parent--relative{position:relative!important}.el-loading-parent--hidden{overflow:hidden!important}.el-loading-mask{position:absolute;z-index:2000;background-color:rgba(255,255,255,.9);margin:0;top:0;right:0;bottom:0;left:0;-webkit-transition:opacity .3s;transition:opacity .3s}.el-loading-mask.is-fullscreen{position:fixed}.el-loading-mask.is-fullscreen .el-loading-spinner{margin-top:-25px}.el-loading-mask.is-fullscreen .el-loading-spinner .circular{height:50px;width:50px}.el-loading-spinner{top:50%;margin-top:-21px;width:100%;text-align:center;position:absolute}.el-col-pull-0,.el-col-pull-1,.el-col-pull-10,.el-col-pull-11,.el-col-pull-12,.el-col-pull-13,.el-col-pull-14,.el-col-pull-15,.el-col-pull-16,.el-col-pull-17,.el-col-pull-18,.el-col-pull-19,.el-col-pull-2,.el-col-pull-20,.el-col-pull-21,.el-col-pull-22,.el-col-pull-23,.el-col-pull-24,.el-col-pull-3,.el-col-pull-4,.el-col-pull-5,.el-col-pull-6,.el-col-pull-7,.el-col-pull-8,.el-col-pull-9,.el-col-push-0,.el-col-push-1,.el-col-push-10,.el-col-push-11,.el-col-push-12,.el-col-push-13,.el-col-push-14,.el-col-push-15,.el-col-push-16,.el-col-push-17,.el-col-push-18,.el-col-push-19,.el-col-push-2,.el-col-push-20,.el-col-push-21,.el-col-push-22,.el-col-push-23,.el-col-push-24,.el-col-push-3,.el-col-push-4,.el-col-push-5,.el-col-push-6,.el-col-push-7,.el-col-push-8,.el-col-push-9,.el-row,.el-upload-dragger,.el-upload-list__item{position:relative}.el-loading-spinner .el-loading-text{color:#409EFF;margin:3px 0;font-size:14px}.el-loading-spinner .circular{height:42px;width:42px;-webkit-animation:loading-rotate 2s linear infinite;animation:loading-rotate 2s linear infinite}.el-loading-spinner .path{-webkit-animation:loading-dash 1.5s ease-in-out infinite;animation:loading-dash 1.5s ease-in-out infinite;stroke-dasharray:90,150;stroke-dashoffset:0;stroke-width:2;stroke:#409EFF;stroke-linecap:round}.el-loading-spinner i{color:#409EFF}@-webkit-keyframes loading-rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes loading-rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}100%{stroke-dasharray:90,150;stroke-dashoffset:-120px}}@keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}100%{stroke-dasharray:90,150;stroke-dashoffset:-120px}}.el-row{-webkit-box-sizing:border-box;box-sizing:border-box}.el-row::after,.el-row::before{display:table}.el-row::after{clear:both}.el-row--flex{display:-webkit-box;display:-ms-flexbox;display:flex}.el-col-0,.el-row--flex:after,.el-row--flex:before{display:none}.el-row--flex.is-justify-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-row--flex.is-justify-end{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.el-row--flex.is-justify-space-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.el-row--flex.is-justify-space-around{-ms-flex-pack:distribute;justify-content:space-around}.el-row--flex.is-align-top{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.el-row--flex.is-align-middle{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-row--flex.is-align-bottom{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}[class*=el-col-]{float:left;-webkit-box-sizing:border-box;box-sizing:border-box}.el-col-0{width:0%}.el-col-pull-0{right:0}.el-col-push-0{left:0}.el-col-1{width:4.16667%}.el-col-offset-1{margin-left:4.16667%}.el-col-pull-1{right:4.16667%}.el-col-push-1{left:4.16667%}.el-col-2{width:8.33333%}.el-col-offset-2{margin-left:8.33333%}.el-col-pull-2{right:8.33333%}.el-col-push-2{left:8.33333%}.el-col-3{width:12.5%}.el-col-offset-3{margin-left:12.5%}.el-col-pull-3{right:12.5%}.el-col-push-3{left:12.5%}.el-col-4{width:16.66667%}.el-col-offset-4{margin-left:16.66667%}.el-col-pull-4{right:16.66667%}.el-col-push-4{left:16.66667%}.el-col-5{width:20.83333%}.el-col-offset-5{margin-left:20.83333%}.el-col-pull-5{right:20.83333%}.el-col-push-5{left:20.83333%}.el-col-6{width:25%}.el-col-offset-6{margin-left:25%}.el-col-pull-6{right:25%}.el-col-push-6{left:25%}.el-col-7{width:29.16667%}.el-col-offset-7{margin-left:29.16667%}.el-col-pull-7{right:29.16667%}.el-col-push-7{left:29.16667%}.el-col-8{width:33.33333%}.el-col-offset-8{margin-left:33.33333%}.el-col-pull-8{right:33.33333%}.el-col-push-8{left:33.33333%}.el-col-9{width:37.5%}.el-col-offset-9{margin-left:37.5%}.el-col-pull-9{right:37.5%}.el-col-push-9{left:37.5%}.el-col-10{width:41.66667%}.el-col-offset-10{margin-left:41.66667%}.el-col-pull-10{right:41.66667%}.el-col-push-10{left:41.66667%}.el-col-11{width:45.83333%}.el-col-offset-11{margin-left:45.83333%}.el-col-pull-11{right:45.83333%}.el-col-push-11{left:45.83333%}.el-col-12{width:50%}.el-col-offset-12{margin-left:50%}.el-col-pull-12{right:50%}.el-col-push-12{left:50%}.el-col-13{width:54.16667%}.el-col-offset-13{margin-left:54.16667%}.el-col-pull-13{right:54.16667%}.el-col-push-13{left:54.16667%}.el-col-14{width:58.33333%}.el-col-offset-14{margin-left:58.33333%}.el-col-pull-14{right:58.33333%}.el-col-push-14{left:58.33333%}.el-col-15{width:62.5%}.el-col-offset-15{margin-left:62.5%}.el-col-pull-15{right:62.5%}.el-col-push-15{left:62.5%}.el-col-16{width:66.66667%}.el-col-offset-16{margin-left:66.66667%}.el-col-pull-16{right:66.66667%}.el-col-push-16{left:66.66667%}.el-col-17{width:70.83333%}.el-col-offset-17{margin-left:70.83333%}.el-col-pull-17{right:70.83333%}.el-col-push-17{left:70.83333%}.el-col-18{width:75%}.el-col-offset-18{margin-left:75%}.el-col-pull-18{right:75%}.el-col-push-18{left:75%}.el-col-19{width:79.16667%}.el-col-offset-19{margin-left:79.16667%}.el-col-pull-19{right:79.16667%}.el-col-push-19{left:79.16667%}.el-col-20{width:83.33333%}.el-col-offset-20{margin-left:83.33333%}.el-col-pull-20{right:83.33333%}.el-col-push-20{left:83.33333%}.el-col-21{width:87.5%}.el-col-offset-21{margin-left:87.5%}.el-col-pull-21{right:87.5%}.el-col-push-21{left:87.5%}.el-col-22{width:91.66667%}.el-col-offset-22{margin-left:91.66667%}.el-col-pull-22{right:91.66667%}.el-col-push-22{left:91.66667%}.el-col-23{width:95.83333%}.el-col-offset-23{margin-left:95.83333%}.el-col-pull-23{right:95.83333%}.el-col-push-23{left:95.83333%}.el-col-24{width:100%}.el-col-offset-24{margin-left:100%}.el-col-pull-24{right:100%}.el-col-push-24{left:100%}@media only screen and (max-width:767px){.el-col-xs-0{display:none;width:0%}.el-col-xs-offset-0{margin-left:0}.el-col-xs-pull-0{position:relative;right:0}.el-col-xs-push-0{position:relative;left:0}.el-col-xs-1{width:4.16667%}.el-col-xs-offset-1{margin-left:4.16667%}.el-col-xs-pull-1{position:relative;right:4.16667%}.el-col-xs-push-1{position:relative;left:4.16667%}.el-col-xs-2{width:8.33333%}.el-col-xs-offset-2{margin-left:8.33333%}.el-col-xs-pull-2{position:relative;right:8.33333%}.el-col-xs-push-2{position:relative;left:8.33333%}.el-col-xs-3{width:12.5%}.el-col-xs-offset-3{margin-left:12.5%}.el-col-xs-pull-3{position:relative;right:12.5%}.el-col-xs-push-3{position:relative;left:12.5%}.el-col-xs-4{width:16.66667%}.el-col-xs-offset-4{margin-left:16.66667%}.el-col-xs-pull-4{position:relative;right:16.66667%}.el-col-xs-push-4{position:relative;left:16.66667%}.el-col-xs-5{width:20.83333%}.el-col-xs-offset-5{margin-left:20.83333%}.el-col-xs-pull-5{position:relative;right:20.83333%}.el-col-xs-push-5{position:relative;left:20.83333%}.el-col-xs-6{width:25%}.el-col-xs-offset-6{margin-left:25%}.el-col-xs-pull-6{position:relative;right:25%}.el-col-xs-push-6{position:relative;left:25%}.el-col-xs-7{width:29.16667%}.el-col-xs-offset-7{margin-left:29.16667%}.el-col-xs-pull-7{position:relative;right:29.16667%}.el-col-xs-push-7{position:relative;left:29.16667%}.el-col-xs-8{width:33.33333%}.el-col-xs-offset-8{margin-left:33.33333%}.el-col-xs-pull-8{position:relative;right:33.33333%}.el-col-xs-push-8{position:relative;left:33.33333%}.el-col-xs-9{width:37.5%}.el-col-xs-offset-9{margin-left:37.5%}.el-col-xs-pull-9{position:relative;right:37.5%}.el-col-xs-push-9{position:relative;left:37.5%}.el-col-xs-10{width:41.66667%}.el-col-xs-offset-10{margin-left:41.66667%}.el-col-xs-pull-10{position:relative;right:41.66667%}.el-col-xs-push-10{position:relative;left:41.66667%}.el-col-xs-11{width:45.83333%}.el-col-xs-offset-11{margin-left:45.83333%}.el-col-xs-pull-11{position:relative;right:45.83333%}.el-col-xs-push-11{position:relative;left:45.83333%}.el-col-xs-12{width:50%}.el-col-xs-offset-12{margin-left:50%}.el-col-xs-pull-12{position:relative;right:50%}.el-col-xs-push-12{position:relative;left:50%}.el-col-xs-13{width:54.16667%}.el-col-xs-offset-13{margin-left:54.16667%}.el-col-xs-pull-13{position:relative;right:54.16667%}.el-col-xs-push-13{position:relative;left:54.16667%}.el-col-xs-14{width:58.33333%}.el-col-xs-offset-14{margin-left:58.33333%}.el-col-xs-pull-14{position:relative;right:58.33333%}.el-col-xs-push-14{position:relative;left:58.33333%}.el-col-xs-15{width:62.5%}.el-col-xs-offset-15{margin-left:62.5%}.el-col-xs-pull-15{position:relative;right:62.5%}.el-col-xs-push-15{position:relative;left:62.5%}.el-col-xs-16{width:66.66667%}.el-col-xs-offset-16{margin-left:66.66667%}.el-col-xs-pull-16{position:relative;right:66.66667%}.el-col-xs-push-16{position:relative;left:66.66667%}.el-col-xs-17{width:70.83333%}.el-col-xs-offset-17{margin-left:70.83333%}.el-col-xs-pull-17{position:relative;right:70.83333%}.el-col-xs-push-17{position:relative;left:70.83333%}.el-col-xs-18{width:75%}.el-col-xs-offset-18{margin-left:75%}.el-col-xs-pull-18{position:relative;right:75%}.el-col-xs-push-18{position:relative;left:75%}.el-col-xs-19{width:79.16667%}.el-col-xs-offset-19{margin-left:79.16667%}.el-col-xs-pull-19{position:relative;right:79.16667%}.el-col-xs-push-19{position:relative;left:79.16667%}.el-col-xs-20{width:83.33333%}.el-col-xs-offset-20{margin-left:83.33333%}.el-col-xs-pull-20{position:relative;right:83.33333%}.el-col-xs-push-20{position:relative;left:83.33333%}.el-col-xs-21{width:87.5%}.el-col-xs-offset-21{margin-left:87.5%}.el-col-xs-pull-21{position:relative;right:87.5%}.el-col-xs-push-21{position:relative;left:87.5%}.el-col-xs-22{width:91.66667%}.el-col-xs-offset-22{margin-left:91.66667%}.el-col-xs-pull-22{position:relative;right:91.66667%}.el-col-xs-push-22{position:relative;left:91.66667%}.el-col-xs-23{width:95.83333%}.el-col-xs-offset-23{margin-left:95.83333%}.el-col-xs-pull-23{position:relative;right:95.83333%}.el-col-xs-push-23{position:relative;left:95.83333%}.el-col-xs-24{width:100%}.el-col-xs-offset-24{margin-left:100%}.el-col-xs-pull-24{position:relative;right:100%}.el-col-xs-push-24{position:relative;left:100%}}@media only screen and (min-width:768px){.el-col-sm-0{display:none;width:0%}.el-col-sm-offset-0{margin-left:0}.el-col-sm-pull-0{position:relative;right:0}.el-col-sm-push-0{position:relative;left:0}.el-col-sm-1{width:4.16667%}.el-col-sm-offset-1{margin-left:4.16667%}.el-col-sm-pull-1{position:relative;right:4.16667%}.el-col-sm-push-1{position:relative;left:4.16667%}.el-col-sm-2{width:8.33333%}.el-col-sm-offset-2{margin-left:8.33333%}.el-col-sm-pull-2{position:relative;right:8.33333%}.el-col-sm-push-2{position:relative;left:8.33333%}.el-col-sm-3{width:12.5%}.el-col-sm-offset-3{margin-left:12.5%}.el-col-sm-pull-3{position:relative;right:12.5%}.el-col-sm-push-3{position:relative;left:12.5%}.el-col-sm-4{width:16.66667%}.el-col-sm-offset-4{margin-left:16.66667%}.el-col-sm-pull-4{position:relative;right:16.66667%}.el-col-sm-push-4{position:relative;left:16.66667%}.el-col-sm-5{width:20.83333%}.el-col-sm-offset-5{margin-left:20.83333%}.el-col-sm-pull-5{position:relative;right:20.83333%}.el-col-sm-push-5{position:relative;left:20.83333%}.el-col-sm-6{width:25%}.el-col-sm-offset-6{margin-left:25%}.el-col-sm-pull-6{position:relative;right:25%}.el-col-sm-push-6{position:relative;left:25%}.el-col-sm-7{width:29.16667%}.el-col-sm-offset-7{margin-left:29.16667%}.el-col-sm-pull-7{position:relative;right:29.16667%}.el-col-sm-push-7{position:relative;left:29.16667%}.el-col-sm-8{width:33.33333%}.el-col-sm-offset-8{margin-left:33.33333%}.el-col-sm-pull-8{position:relative;right:33.33333%}.el-col-sm-push-8{position:relative;left:33.33333%}.el-col-sm-9{width:37.5%}.el-col-sm-offset-9{margin-left:37.5%}.el-col-sm-pull-9{position:relative;right:37.5%}.el-col-sm-push-9{position:relative;left:37.5%}.el-col-sm-10{width:41.66667%}.el-col-sm-offset-10{margin-left:41.66667%}.el-col-sm-pull-10{position:relative;right:41.66667%}.el-col-sm-push-10{position:relative;left:41.66667%}.el-col-sm-11{width:45.83333%}.el-col-sm-offset-11{margin-left:45.83333%}.el-col-sm-pull-11{position:relative;right:45.83333%}.el-col-sm-push-11{position:relative;left:45.83333%}.el-col-sm-12{width:50%}.el-col-sm-offset-12{margin-left:50%}.el-col-sm-pull-12{position:relative;right:50%}.el-col-sm-push-12{position:relative;left:50%}.el-col-sm-13{width:54.16667%}.el-col-sm-offset-13{margin-left:54.16667%}.el-col-sm-pull-13{position:relative;right:54.16667%}.el-col-sm-push-13{position:relative;left:54.16667%}.el-col-sm-14{width:58.33333%}.el-col-sm-offset-14{margin-left:58.33333%}.el-col-sm-pull-14{position:relative;right:58.33333%}.el-col-sm-push-14{position:relative;left:58.33333%}.el-col-sm-15{width:62.5%}.el-col-sm-offset-15{margin-left:62.5%}.el-col-sm-pull-15{position:relative;right:62.5%}.el-col-sm-push-15{position:relative;left:62.5%}.el-col-sm-16{width:66.66667%}.el-col-sm-offset-16{margin-left:66.66667%}.el-col-sm-pull-16{position:relative;right:66.66667%}.el-col-sm-push-16{position:relative;left:66.66667%}.el-col-sm-17{width:70.83333%}.el-col-sm-offset-17{margin-left:70.83333%}.el-col-sm-pull-17{position:relative;right:70.83333%}.el-col-sm-push-17{position:relative;left:70.83333%}.el-col-sm-18{width:75%}.el-col-sm-offset-18{margin-left:75%}.el-col-sm-pull-18{position:relative;right:75%}.el-col-sm-push-18{position:relative;left:75%}.el-col-sm-19{width:79.16667%}.el-col-sm-offset-19{margin-left:79.16667%}.el-col-sm-pull-19{position:relative;right:79.16667%}.el-col-sm-push-19{position:relative;left:79.16667%}.el-col-sm-20{width:83.33333%}.el-col-sm-offset-20{margin-left:83.33333%}.el-col-sm-pull-20{position:relative;right:83.33333%}.el-col-sm-push-20{position:relative;left:83.33333%}.el-col-sm-21{width:87.5%}.el-col-sm-offset-21{margin-left:87.5%}.el-col-sm-pull-21{position:relative;right:87.5%}.el-col-sm-push-21{position:relative;left:87.5%}.el-col-sm-22{width:91.66667%}.el-col-sm-offset-22{margin-left:91.66667%}.el-col-sm-pull-22{position:relative;right:91.66667%}.el-col-sm-push-22{position:relative;left:91.66667%}.el-col-sm-23{width:95.83333%}.el-col-sm-offset-23{margin-left:95.83333%}.el-col-sm-pull-23{position:relative;right:95.83333%}.el-col-sm-push-23{position:relative;left:95.83333%}.el-col-sm-24{width:100%}.el-col-sm-offset-24{margin-left:100%}.el-col-sm-pull-24{position:relative;right:100%}.el-col-sm-push-24{position:relative;left:100%}}@media only screen and (min-width:992px){.el-col-md-0{display:none;width:0%}.el-col-md-offset-0{margin-left:0}.el-col-md-pull-0{position:relative;right:0}.el-col-md-push-0{position:relative;left:0}.el-col-md-1{width:4.16667%}.el-col-md-offset-1{margin-left:4.16667%}.el-col-md-pull-1{position:relative;right:4.16667%}.el-col-md-push-1{position:relative;left:4.16667%}.el-col-md-2{width:8.33333%}.el-col-md-offset-2{margin-left:8.33333%}.el-col-md-pull-2{position:relative;right:8.33333%}.el-col-md-push-2{position:relative;left:8.33333%}.el-col-md-3{width:12.5%}.el-col-md-offset-3{margin-left:12.5%}.el-col-md-pull-3{position:relative;right:12.5%}.el-col-md-push-3{position:relative;left:12.5%}.el-col-md-4{width:16.66667%}.el-col-md-offset-4{margin-left:16.66667%}.el-col-md-pull-4{position:relative;right:16.66667%}.el-col-md-push-4{position:relative;left:16.66667%}.el-col-md-5{width:20.83333%}.el-col-md-offset-5{margin-left:20.83333%}.el-col-md-pull-5{position:relative;right:20.83333%}.el-col-md-push-5{position:relative;left:20.83333%}.el-col-md-6{width:25%}.el-col-md-offset-6{margin-left:25%}.el-col-md-pull-6{position:relative;right:25%}.el-col-md-push-6{position:relative;left:25%}.el-col-md-7{width:29.16667%}.el-col-md-offset-7{margin-left:29.16667%}.el-col-md-pull-7{position:relative;right:29.16667%}.el-col-md-push-7{position:relative;left:29.16667%}.el-col-md-8{width:33.33333%}.el-col-md-offset-8{margin-left:33.33333%}.el-col-md-pull-8{position:relative;right:33.33333%}.el-col-md-push-8{position:relative;left:33.33333%}.el-col-md-9{width:37.5%}.el-col-md-offset-9{margin-left:37.5%}.el-col-md-pull-9{position:relative;right:37.5%}.el-col-md-push-9{position:relative;left:37.5%}.el-col-md-10{width:41.66667%}.el-col-md-offset-10{margin-left:41.66667%}.el-col-md-pull-10{position:relative;right:41.66667%}.el-col-md-push-10{position:relative;left:41.66667%}.el-col-md-11{width:45.83333%}.el-col-md-offset-11{margin-left:45.83333%}.el-col-md-pull-11{position:relative;right:45.83333%}.el-col-md-push-11{position:relative;left:45.83333%}.el-col-md-12{width:50%}.el-col-md-offset-12{margin-left:50%}.el-col-md-pull-12{position:relative;right:50%}.el-col-md-push-12{position:relative;left:50%}.el-col-md-13{width:54.16667%}.el-col-md-offset-13{margin-left:54.16667%}.el-col-md-pull-13{position:relative;right:54.16667%}.el-col-md-push-13{position:relative;left:54.16667%}.el-col-md-14{width:58.33333%}.el-col-md-offset-14{margin-left:58.33333%}.el-col-md-pull-14{position:relative;right:58.33333%}.el-col-md-push-14{position:relative;left:58.33333%}.el-col-md-15{width:62.5%}.el-col-md-offset-15{margin-left:62.5%}.el-col-md-pull-15{position:relative;right:62.5%}.el-col-md-push-15{position:relative;left:62.5%}.el-col-md-16{width:66.66667%}.el-col-md-offset-16{margin-left:66.66667%}.el-col-md-pull-16{position:relative;right:66.66667%}.el-col-md-push-16{position:relative;left:66.66667%}.el-col-md-17{width:70.83333%}.el-col-md-offset-17{margin-left:70.83333%}.el-col-md-pull-17{position:relative;right:70.83333%}.el-col-md-push-17{position:relative;left:70.83333%}.el-col-md-18{width:75%}.el-col-md-offset-18{margin-left:75%}.el-col-md-pull-18{position:relative;right:75%}.el-col-md-push-18{position:relative;left:75%}.el-col-md-19{width:79.16667%}.el-col-md-offset-19{margin-left:79.16667%}.el-col-md-pull-19{position:relative;right:79.16667%}.el-col-md-push-19{position:relative;left:79.16667%}.el-col-md-20{width:83.33333%}.el-col-md-offset-20{margin-left:83.33333%}.el-col-md-pull-20{position:relative;right:83.33333%}.el-col-md-push-20{position:relative;left:83.33333%}.el-col-md-21{width:87.5%}.el-col-md-offset-21{margin-left:87.5%}.el-col-md-pull-21{position:relative;right:87.5%}.el-col-md-push-21{position:relative;left:87.5%}.el-col-md-22{width:91.66667%}.el-col-md-offset-22{margin-left:91.66667%}.el-col-md-pull-22{position:relative;right:91.66667%}.el-col-md-push-22{position:relative;left:91.66667%}.el-col-md-23{width:95.83333%}.el-col-md-offset-23{margin-left:95.83333%}.el-col-md-pull-23{position:relative;right:95.83333%}.el-col-md-push-23{position:relative;left:95.83333%}.el-col-md-24{width:100%}.el-col-md-offset-24{margin-left:100%}.el-col-md-pull-24{position:relative;right:100%}.el-col-md-push-24{position:relative;left:100%}}@media only screen and (min-width:1200px){.el-col-lg-0{display:none;width:0%}.el-col-lg-offset-0{margin-left:0}.el-col-lg-pull-0{position:relative;right:0}.el-col-lg-push-0{position:relative;left:0}.el-col-lg-1{width:4.16667%}.el-col-lg-offset-1{margin-left:4.16667%}.el-col-lg-pull-1{position:relative;right:4.16667%}.el-col-lg-push-1{position:relative;left:4.16667%}.el-col-lg-2{width:8.33333%}.el-col-lg-offset-2{margin-left:8.33333%}.el-col-lg-pull-2{position:relative;right:8.33333%}.el-col-lg-push-2{position:relative;left:8.33333%}.el-col-lg-3{width:12.5%}.el-col-lg-offset-3{margin-left:12.5%}.el-col-lg-pull-3{position:relative;right:12.5%}.el-col-lg-push-3{position:relative;left:12.5%}.el-col-lg-4{width:16.66667%}.el-col-lg-offset-4{margin-left:16.66667%}.el-col-lg-pull-4{position:relative;right:16.66667%}.el-col-lg-push-4{position:relative;left:16.66667%}.el-col-lg-5{width:20.83333%}.el-col-lg-offset-5{margin-left:20.83333%}.el-col-lg-pull-5{position:relative;right:20.83333%}.el-col-lg-push-5{position:relative;left:20.83333%}.el-col-lg-6{width:25%}.el-col-lg-offset-6{margin-left:25%}.el-col-lg-pull-6{position:relative;right:25%}.el-col-lg-push-6{position:relative;left:25%}.el-col-lg-7{width:29.16667%}.el-col-lg-offset-7{margin-left:29.16667%}.el-col-lg-pull-7{position:relative;right:29.16667%}.el-col-lg-push-7{position:relative;left:29.16667%}.el-col-lg-8{width:33.33333%}.el-col-lg-offset-8{margin-left:33.33333%}.el-col-lg-pull-8{position:relative;right:33.33333%}.el-col-lg-push-8{position:relative;left:33.33333%}.el-col-lg-9{width:37.5%}.el-col-lg-offset-9{margin-left:37.5%}.el-col-lg-pull-9{position:relative;right:37.5%}.el-col-lg-push-9{position:relative;left:37.5%}.el-col-lg-10{width:41.66667%}.el-col-lg-offset-10{margin-left:41.66667%}.el-col-lg-pull-10{position:relative;right:41.66667%}.el-col-lg-push-10{position:relative;left:41.66667%}.el-col-lg-11{width:45.83333%}.el-col-lg-offset-11{margin-left:45.83333%}.el-col-lg-pull-11{position:relative;right:45.83333%}.el-col-lg-push-11{position:relative;left:45.83333%}.el-col-lg-12{width:50%}.el-col-lg-offset-12{margin-left:50%}.el-col-lg-pull-12{position:relative;right:50%}.el-col-lg-push-12{position:relative;left:50%}.el-col-lg-13{width:54.16667%}.el-col-lg-offset-13{margin-left:54.16667%}.el-col-lg-pull-13{position:relative;right:54.16667%}.el-col-lg-push-13{position:relative;left:54.16667%}.el-col-lg-14{width:58.33333%}.el-col-lg-offset-14{margin-left:58.33333%}.el-col-lg-pull-14{position:relative;right:58.33333%}.el-col-lg-push-14{position:relative;left:58.33333%}.el-col-lg-15{width:62.5%}.el-col-lg-offset-15{margin-left:62.5%}.el-col-lg-pull-15{position:relative;right:62.5%}.el-col-lg-push-15{position:relative;left:62.5%}.el-col-lg-16{width:66.66667%}.el-col-lg-offset-16{margin-left:66.66667%}.el-col-lg-pull-16{position:relative;right:66.66667%}.el-col-lg-push-16{position:relative;left:66.66667%}.el-col-lg-17{width:70.83333%}.el-col-lg-offset-17{margin-left:70.83333%}.el-col-lg-pull-17{position:relative;right:70.83333%}.el-col-lg-push-17{position:relative;left:70.83333%}.el-col-lg-18{width:75%}.el-col-lg-offset-18{margin-left:75%}.el-col-lg-pull-18{position:relative;right:75%}.el-col-lg-push-18{position:relative;left:75%}.el-col-lg-19{width:79.16667%}.el-col-lg-offset-19{margin-left:79.16667%}.el-col-lg-pull-19{position:relative;right:79.16667%}.el-col-lg-push-19{position:relative;left:79.16667%}.el-col-lg-20{width:83.33333%}.el-col-lg-offset-20{margin-left:83.33333%}.el-col-lg-pull-20{position:relative;right:83.33333%}.el-col-lg-push-20{position:relative;left:83.33333%}.el-col-lg-21{width:87.5%}.el-col-lg-offset-21{margin-left:87.5%}.el-col-lg-pull-21{position:relative;right:87.5%}.el-col-lg-push-21{position:relative;left:87.5%}.el-col-lg-22{width:91.66667%}.el-col-lg-offset-22{margin-left:91.66667%}.el-col-lg-pull-22{position:relative;right:91.66667%}.el-col-lg-push-22{position:relative;left:91.66667%}.el-col-lg-23{width:95.83333%}.el-col-lg-offset-23{margin-left:95.83333%}.el-col-lg-pull-23{position:relative;right:95.83333%}.el-col-lg-push-23{position:relative;left:95.83333%}.el-col-lg-24{width:100%}.el-col-lg-offset-24{margin-left:100%}.el-col-lg-pull-24{position:relative;right:100%}.el-col-lg-push-24{position:relative;left:100%}}@media only screen and (min-width:1920px){.el-col-xl-0{display:none;width:0%}.el-col-xl-offset-0{margin-left:0}.el-col-xl-pull-0{position:relative;right:0}.el-col-xl-push-0{position:relative;left:0}.el-col-xl-1{width:4.16667%}.el-col-xl-offset-1{margin-left:4.16667%}.el-col-xl-pull-1{position:relative;right:4.16667%}.el-col-xl-push-1{position:relative;left:4.16667%}.el-col-xl-2{width:8.33333%}.el-col-xl-offset-2{margin-left:8.33333%}.el-col-xl-pull-2{position:relative;right:8.33333%}.el-col-xl-push-2{position:relative;left:8.33333%}.el-col-xl-3{width:12.5%}.el-col-xl-offset-3{margin-left:12.5%}.el-col-xl-pull-3{position:relative;right:12.5%}.el-col-xl-push-3{position:relative;left:12.5%}.el-col-xl-4{width:16.66667%}.el-col-xl-offset-4{margin-left:16.66667%}.el-col-xl-pull-4{position:relative;right:16.66667%}.el-col-xl-push-4{position:relative;left:16.66667%}.el-col-xl-5{width:20.83333%}.el-col-xl-offset-5{margin-left:20.83333%}.el-col-xl-pull-5{position:relative;right:20.83333%}.el-col-xl-push-5{position:relative;left:20.83333%}.el-col-xl-6{width:25%}.el-col-xl-offset-6{margin-left:25%}.el-col-xl-pull-6{position:relative;right:25%}.el-col-xl-push-6{position:relative;left:25%}.el-col-xl-7{width:29.16667%}.el-col-xl-offset-7{margin-left:29.16667%}.el-col-xl-pull-7{position:relative;right:29.16667%}.el-col-xl-push-7{position:relative;left:29.16667%}.el-col-xl-8{width:33.33333%}.el-col-xl-offset-8{margin-left:33.33333%}.el-col-xl-pull-8{position:relative;right:33.33333%}.el-col-xl-push-8{position:relative;left:33.33333%}.el-col-xl-9{width:37.5%}.el-col-xl-offset-9{margin-left:37.5%}.el-col-xl-pull-9{position:relative;right:37.5%}.el-col-xl-push-9{position:relative;left:37.5%}.el-col-xl-10{width:41.66667%}.el-col-xl-offset-10{margin-left:41.66667%}.el-col-xl-pull-10{position:relative;right:41.66667%}.el-col-xl-push-10{position:relative;left:41.66667%}.el-col-xl-11{width:45.83333%}.el-col-xl-offset-11{margin-left:45.83333%}.el-col-xl-pull-11{position:relative;right:45.83333%}.el-col-xl-push-11{position:relative;left:45.83333%}.el-col-xl-12{width:50%}.el-col-xl-offset-12{margin-left:50%}.el-col-xl-pull-12{position:relative;right:50%}.el-col-xl-push-12{position:relative;left:50%}.el-col-xl-13{width:54.16667%}.el-col-xl-offset-13{margin-left:54.16667%}.el-col-xl-pull-13{position:relative;right:54.16667%}.el-col-xl-push-13{position:relative;left:54.16667%}.el-col-xl-14{width:58.33333%}.el-col-xl-offset-14{margin-left:58.33333%}.el-col-xl-pull-14{position:relative;right:58.33333%}.el-col-xl-push-14{position:relative;left:58.33333%}.el-col-xl-15{width:62.5%}.el-col-xl-offset-15{margin-left:62.5%}.el-col-xl-pull-15{position:relative;right:62.5%}.el-col-xl-push-15{position:relative;left:62.5%}.el-col-xl-16{width:66.66667%}.el-col-xl-offset-16{margin-left:66.66667%}.el-col-xl-pull-16{position:relative;right:66.66667%}.el-col-xl-push-16{position:relative;left:66.66667%}.el-col-xl-17{width:70.83333%}.el-col-xl-offset-17{margin-left:70.83333%}.el-col-xl-pull-17{position:relative;right:70.83333%}.el-col-xl-push-17{position:relative;left:70.83333%}.el-col-xl-18{width:75%}.el-col-xl-offset-18{margin-left:75%}.el-col-xl-pull-18{position:relative;right:75%}.el-col-xl-push-18{position:relative;left:75%}.el-col-xl-19{width:79.16667%}.el-col-xl-offset-19{margin-left:79.16667%}.el-col-xl-pull-19{position:relative;right:79.16667%}.el-col-xl-push-19{position:relative;left:79.16667%}.el-col-xl-20{width:83.33333%}.el-col-xl-offset-20{margin-left:83.33333%}.el-col-xl-pull-20{position:relative;right:83.33333%}.el-col-xl-push-20{position:relative;left:83.33333%}.el-col-xl-21{width:87.5%}.el-col-xl-offset-21{margin-left:87.5%}.el-col-xl-pull-21{position:relative;right:87.5%}.el-col-xl-push-21{position:relative;left:87.5%}.el-col-xl-22{width:91.66667%}.el-col-xl-offset-22{margin-left:91.66667%}.el-col-xl-pull-22{position:relative;right:91.66667%}.el-col-xl-push-22{position:relative;left:91.66667%}.el-col-xl-23{width:95.83333%}.el-col-xl-offset-23{margin-left:95.83333%}.el-col-xl-pull-23{position:relative;right:95.83333%}.el-col-xl-push-23{position:relative;left:95.83333%}.el-col-xl-24{width:100%}.el-col-xl-offset-24{margin-left:100%}.el-col-xl-pull-24{position:relative;right:100%}.el-col-xl-push-24{position:relative;left:100%}}@-webkit-keyframes progress{0%{background-position:0 0}100%{background-position:32px 0}}.el-upload{display:inline-block;text-align:center;cursor:pointer;outline:0}.el-upload__input{display:none}.el-upload__tip{font-size:12px;color:#606266;margin-top:7px}.el-upload iframe{position:absolute;z-index:-1;top:0;left:0;filter:alpha(opacity=0)}.el-upload--picture-card{background-color:#fbfdff;border:1px dashed #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;width:148px;height:148px;cursor:pointer;line-height:146px;vertical-align:top}.el-upload--picture-card i{font-size:28px;color:#8c939d}.el-upload--picture-card:hover,.el-upload:focus{border-color:#409EFF;color:#409EFF}.el-upload:focus .el-upload-dragger{border-color:#409EFF}.el-upload-dragger{background-color:#fff;border:1px dashed #d9d9d9;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;width:360px;height:180px;text-align:center;cursor:pointer;overflow:hidden}.el-upload-dragger .el-icon-upload{font-size:67px;color:#C0C4CC;margin:40px 0 16px;line-height:50px}.el-upload-dragger+.el-upload__tip{text-align:center}.el-upload-dragger~.el-upload__files{border-top:1px solid #DCDFE6;margin-top:7px;padding-top:5px}.el-upload-dragger .el-upload__text{color:#606266;font-size:14px;text-align:center}.el-upload-dragger .el-upload__text em{color:#409EFF;font-style:normal}.el-upload-dragger:hover{border-color:#409EFF}.el-upload-dragger.is-dragover{background-color:rgba(32,159,255,.06);border:2px dashed #409EFF}.el-upload-list{margin:0;padding:0;list-style:none}.el-upload-list__item{-webkit-transition:all .5s cubic-bezier(.55,0,.1,1);transition:all .5s cubic-bezier(.55,0,.1,1);font-size:14px;color:#606266;line-height:1.8;margin-top:5px;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;width:100%}.el-upload-list__item .el-progress{position:absolute;top:20px;width:100%}.el-upload-list__item .el-progress__text{position:absolute;right:0;top:-13px}.el-upload-list__item .el-progress-bar{margin-right:0;padding-right:0}.el-upload-list__item:first-child{margin-top:10px}.el-upload-list__item .el-icon-upload-success{color:#67C23A}.el-upload-list__item .el-icon-close{display:none;position:absolute;top:5px;right:5px;cursor:pointer;opacity:.75;color:#606266}.el-upload-list__item .el-icon-close:hover{opacity:1}.el-upload-list__item .el-icon-close-tip{display:none;position:absolute;top:5px;right:5px;font-size:12px;cursor:pointer;opacity:1;color:#409EFF}.el-upload-list__item:hover .el-icon-close{display:inline-block}.el-upload-list__item:hover .el-progress__text{display:none}.el-upload-list__item.is-success .el-upload-list__item-status-label{display:block}.el-upload-list__item.is-success .el-upload-list__item-name:focus,.el-upload-list__item.is-success .el-upload-list__item-name:hover{color:#409EFF;cursor:pointer}.el-upload-list__item.is-success:focus:not(:hover) .el-icon-close-tip{display:inline-block}.el-upload-list__item.is-success:active,.el-upload-list__item.is-success:not(.focusing):focus{outline-width:0}.el-upload-list__item.is-success:active .el-icon-close-tip,.el-upload-list__item.is-success:focus .el-upload-list__item-status-label,.el-upload-list__item.is-success:hover .el-upload-list__item-status-label,.el-upload-list__item.is-success:not(.focusing):focus .el-icon-close-tip{display:none}.el-upload-list.is-disabled .el-upload-list__item:hover .el-upload-list__item-status-label{display:block}.el-upload-list__item-name{color:#606266;display:block;margin-right:40px;overflow:hidden;padding-left:4px;text-overflow:ellipsis;-webkit-transition:color .3s;transition:color .3s;white-space:nowrap}.el-upload-list__item-name [class^=el-icon]{height:100%;margin-right:7px;color:#909399;line-height:inherit}.el-upload-list__item-status-label{position:absolute;right:5px;top:0;line-height:inherit;display:none}.el-upload-list__item-delete{position:absolute;right:10px;top:0;font-size:12px;color:#606266;display:none}.el-upload-list__item-delete:hover{color:#409EFF}.el-upload-list--picture-card{margin:0;display:inline;vertical-align:top}.el-upload-list--picture-card .el-upload-list__item{overflow:hidden;background-color:#fff;border:1px solid #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;width:148px;height:148px;margin:0 8px 8px 0;display:inline-block}.el-upload-list--picture-card .el-upload-list__item .el-icon-check,.el-upload-list--picture-card .el-upload-list__item .el-icon-circle-check{color:#FFF}.el-upload-list--picture-card .el-upload-list__item .el-icon-close,.el-upload-list--picture-card .el-upload-list__item:hover .el-upload-list__item-status-label{display:none}.el-upload-list--picture-card .el-upload-list__item:hover .el-progress__text{display:block}.el-upload-list--picture-card .el-upload-list__item-name{display:none}.el-upload-list--picture-card .el-upload-list__item-thumbnail{width:100%;height:100%}.el-upload-list--picture-card .el-upload-list__item-status-label{position:absolute;right:-15px;top:-6px;width:40px;height:24px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 0 1pc 1px rgba(0,0,0,.2);box-shadow:0 0 1pc 1px rgba(0,0,0,.2)}.el-upload-list--picture-card .el-upload-list__item-status-label i{font-size:12px;margin-top:11px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.el-upload-list--picture-card .el-upload-list__item-actions{position:absolute;width:100%;height:100%;left:0;top:0;cursor:default;text-align:center;color:#fff;opacity:0;font-size:20px;background-color:rgba(0,0,0,.5);-webkit-transition:opacity .3s;transition:opacity .3s}.el-upload-list--picture-card .el-upload-list__item-actions::after{display:inline-block;height:100%;vertical-align:middle}.el-upload-list--picture-card .el-upload-list__item-actions span{display:none;cursor:pointer}.el-upload-list--picture-card .el-upload-list__item-actions span+span{margin-left:15px}.el-upload-list--picture-card .el-upload-list__item-actions .el-upload-list__item-delete{position:static;font-size:inherit;color:inherit}.el-upload-list--picture-card .el-upload-list__item-actions:hover{opacity:1}.el-upload-list--picture-card .el-upload-list__item-actions:hover span{display:inline-block}.el-upload-list--picture-card .el-progress{top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);bottom:auto;width:126px}.el-upload-list--picture-card .el-progress .el-progress__text{top:50%}.el-upload-list--picture .el-upload-list__item{overflow:hidden;z-index:0;background-color:#fff;border:1px solid #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;margin-top:10px;padding:10px 10px 10px 90px;height:92px}.el-upload-list--picture .el-upload-list__item .el-icon-check,.el-upload-list--picture .el-upload-list__item .el-icon-circle-check{color:#FFF}.el-upload-list--picture .el-upload-list__item:hover .el-upload-list__item-status-label{background:0 0;-webkit-box-shadow:none;box-shadow:none;top:-2px;right:-12px}.el-upload-list--picture .el-upload-list__item:hover .el-progress__text{display:block}.el-upload-list--picture .el-upload-list__item.is-success .el-upload-list__item-name{line-height:70px;margin-top:0}.el-upload-list--picture .el-upload-list__item.is-success .el-upload-list__item-name i{display:none}.el-upload-list--picture .el-upload-list__item-thumbnail{vertical-align:middle;display:inline-block;width:70px;height:70px;float:left;position:relative;z-index:1;margin-left:-80px;background-color:#FFF}.el-upload-list--picture .el-upload-list__item-name{display:block;margin-top:20px}.el-upload-list--picture .el-upload-list__item-name i{font-size:70px;line-height:1;position:absolute;left:9px;top:10px}.el-upload-list--picture .el-upload-list__item-status-label{position:absolute;right:-17px;top:-7px;width:46px;height:26px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 1px 1px #ccc;box-shadow:0 1px 1px #ccc}.el-upload-list--picture .el-upload-list__item-status-label i{font-size:12px;margin-top:12px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.el-upload-list--picture .el-progress{position:relative;top:-7px}.el-upload-cover{position:absolute;left:0;top:0;width:100%;height:100%;overflow:hidden;z-index:10;cursor:default}.el-upload-cover::after{display:inline-block;height:100%;vertical-align:middle}.el-upload-cover img{display:block;width:100%;height:100%}.el-upload-cover__label{position:absolute;right:-15px;top:-6px;width:40px;height:24px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 0 1pc 1px rgba(0,0,0,.2);box-shadow:0 0 1pc 1px rgba(0,0,0,.2)}.el-upload-cover__label i{font-size:12px;margin-top:11px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);color:#fff}.el-upload-cover__progress{display:inline-block;vertical-align:middle;position:static;width:243px}.el-upload-cover__progress+.el-upload__inner{opacity:0}.el-upload-cover__content{position:absolute;top:0;left:0;width:100%;height:100%}.el-upload-cover__interact{position:absolute;bottom:0;left:0;width:100%;height:100%;background-color:rgba(0,0,0,.72);text-align:center}.el-upload-cover__interact .btn{display:inline-block;color:#FFF;font-size:14px;cursor:pointer;vertical-align:middle;-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);margin-top:60px}.el-upload-cover__interact .btn span{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.el-upload-cover__interact .btn:not(:first-child){margin-left:35px}.el-upload-cover__interact .btn:hover{-webkit-transform:translateY(-13px);transform:translateY(-13px)}.el-upload-cover__interact .btn:hover span{opacity:1}.el-upload-cover__interact .btn i{color:#FFF;display:block;font-size:24px;line-height:inherit;margin:0 auto 5px}.el-upload-cover__title{position:absolute;bottom:0;left:0;background-color:#FFF;height:36px;width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:400;text-align:left;padding:0 10px;margin:0;line-height:36px;font-size:14px;color:#303133}.el-upload-cover+.el-upload__inner{opacity:0;position:relative;z-index:1}.el-progress{position:relative;line-height:1}.el-progress__text{font-size:14px;color:#606266;display:inline-block;vertical-align:middle;margin-left:10px;line-height:1}.el-progress__text i{vertical-align:middle;display:block}.el-progress--circle,.el-progress--dashboard{display:inline-block}.el-progress--circle .el-progress__text,.el-progress--dashboard .el-progress__text{position:absolute;top:50%;left:0;width:100%;text-align:center;margin:0;-webkit-transform:translate(0,-50%);transform:translate(0,-50%)}.el-progress--circle .el-progress__text i,.el-progress--dashboard .el-progress__text i{vertical-align:middle;display:inline-block}.el-progress--without-text .el-progress__text{display:none}.el-progress--without-text .el-progress-bar{padding-right:0;margin-right:0;display:block}.el-progress--text-inside .el-progress-bar{padding-right:0;margin-right:0}.el-progress.is-success .el-progress-bar__inner{background-color:#67C23A}.el-progress.is-success .el-progress__text{color:#67C23A}.el-progress.is-warning .el-progress-bar__inner{background-color:#E6A23C}.el-badge__content,.el-progress.is-exception .el-progress-bar__inner{background-color:#F56C6C}.el-progress.is-warning .el-progress__text{color:#E6A23C}.el-progress.is-exception .el-progress__text{color:#F56C6C}.el-progress-bar{padding-right:50px;display:inline-block;vertical-align:middle;width:100%;margin-right:-55px;-webkit-box-sizing:border-box;box-sizing:border-box}.el-card__header,.el-message,.el-step__icon{-webkit-box-sizing:border-box}.el-progress-bar__outer{height:6px;border-radius:100px;background-color:#EBEEF5;overflow:hidden;position:relative;vertical-align:middle}.el-progress-bar__inner{position:absolute;left:0;top:0;height:100%;background-color:#409EFF;text-align:right;border-radius:100px;line-height:1;white-space:nowrap;-webkit-transition:width .6s ease;transition:width .6s ease}.el-progress-bar__inner::after{display:inline-block;height:100%;vertical-align:middle}.el-progress-bar__innerText{display:inline-block;vertical-align:middle;color:#FFF;font-size:12px;margin:0 5px}@keyframes progress{0%{background-position:0 0}100%{background-position:32px 0}}.el-time-spinner{width:100%;white-space:nowrap}.el-spinner{display:inline-block;vertical-align:middle}.el-spinner-inner{-webkit-animation:rotate 2s linear infinite;animation:rotate 2s linear infinite;width:50px;height:50px}.el-spinner-inner .path{stroke:#ececec;stroke-linecap:round;-webkit-animation:dash 1.5s ease-in-out infinite;animation:dash 1.5s ease-in-out infinite}@-webkit-keyframes rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}100%{stroke-dasharray:90,150;stroke-dashoffset:-124}}@keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}100%{stroke-dasharray:90,150;stroke-dashoffset:-124}}.el-message{min-width:380px;box-sizing:border-box;border-radius:4px;border-width:1px;border-style:solid;border-color:#EBEEF5;position:fixed;left:50%;top:20px;-webkit-transform:translateX(-50%);transform:translateX(-50%);background-color:#edf2fc;-webkit-transition:opacity .3s,top .4s,-webkit-transform .4s;transition:opacity .3s,top .4s,-webkit-transform .4s;transition:opacity .3s,transform .4s,top .4s;transition:opacity .3s,transform .4s,top .4s,-webkit-transform .4s;overflow:hidden;padding:15px 15px 15px 20px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-message.is-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-message.is-closable .el-message__content{padding-right:16px}.el-message p{margin:0}.el-message--info .el-message__content{color:#909399}.el-message--success{background-color:#f0f9eb;border-color:#e1f3d8}.el-message--success .el-message__content{color:#67C23A}.el-message--warning{background-color:#fdf6ec;border-color:#faecd8}.el-message--warning .el-message__content{color:#E6A23C}.el-message--error{background-color:#fef0f0;border-color:#fde2e2}.el-message--error .el-message__content{color:#F56C6C}.el-message__icon{margin-right:10px}.el-message__content{padding:0;font-size:14px;line-height:1}.el-message__content:focus{outline-width:0}.el-message__closeBtn{position:absolute;top:50%;right:15px;-webkit-transform:translateY(-50%);transform:translateY(-50%);cursor:pointer;color:#C0C4CC;font-size:16px}.el-message__closeBtn:focus{outline-width:0}.el-message__closeBtn:hover{color:#909399}.el-message .el-icon-success{color:#67C23A}.el-message .el-icon-error{color:#F56C6C}.el-message .el-icon-info{color:#909399}.el-message .el-icon-warning{color:#E6A23C}.el-message-fade-enter,.el-message-fade-leave-active{opacity:0;-webkit-transform:translate(-50%,-100%);transform:translate(-50%,-100%)}.el-badge{position:relative;vertical-align:middle;display:inline-block}.el-badge__content{border-radius:10px;color:#FFF;display:inline-block;font-size:12px;height:18px;line-height:18px;padding:0 6px;text-align:center;white-space:nowrap;border:1px solid #FFF}.el-badge__content.is-fixed{position:absolute;top:0;right:10px;-webkit-transform:translateY(-50%) translateX(100%);transform:translateY(-50%) translateX(100%)}.el-rate__icon,.el-rate__item{position:relative;display:inline-block}.el-badge__content.is-fixed.is-dot{right:5px}.el-badge__content.is-dot{height:8px;width:8px;padding:0;right:0;border-radius:50%}.el-badge__content--primary{background-color:#409EFF}.el-badge__content--success{background-color:#67C23A}.el-badge__content--warning{background-color:#E6A23C}.el-badge__content--info{background-color:#909399}.el-badge__content--danger{background-color:#F56C6C}.el-card{border-radius:4px;border:1px solid #EBEEF5;background-color:#FFF;overflow:hidden;color:#303133;-webkit-transition:.3s;transition:.3s}.el-card.is-always-shadow,.el-card.is-hover-shadow:focus,.el-card.is-hover-shadow:hover{box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-card__header{padding:18px 20px;border-bottom:1px solid #EBEEF5;box-sizing:border-box}.el-card__body,.el-main{padding:20px}.el-rate{height:20px;line-height:1}.el-rate:active,.el-rate:focus{outline-width:0}.el-rate__item{font-size:0;vertical-align:middle}.el-rate__icon{font-size:18px;margin-right:6px;color:#C0C4CC;-webkit-transition:.3s;transition:.3s}.el-rate__decimal,.el-rate__icon .path2{position:absolute;top:0;left:0}.el-rate__icon.hover{-webkit-transform:scale(1.15);transform:scale(1.15)}.el-rate__decimal{display:inline-block;overflow:hidden}.el-step.is-vertical,.el-steps{display:-webkit-box;display:-ms-flexbox}.el-rate__text{font-size:14px;vertical-align:middle}.el-steps{display:flex}.el-steps--simple{padding:13px 8%;border-radius:4px;background:#F5F7FA}.el-steps--horizontal{white-space:nowrap}.el-steps--vertical{height:100%;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-flow:column;flex-flow:column}.el-step{position:relative;-ms-flex-negative:1;flex-shrink:1}.el-step:last-of-type .el-step__line{display:none}.el-step:last-of-type.is-flex{-ms-flex-preferred-size:auto!important;flex-basis:auto!important;-ms-flex-negative:0;flex-shrink:0;-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0}.el-step:last-of-type .el-step__description,.el-step:last-of-type .el-step__main{padding-right:0}.el-step__head{position:relative;width:100%}.el-step__head.is-process{color:#303133;border-color:#303133}.el-step__head.is-wait{color:#C0C4CC;border-color:#C0C4CC}.el-step__head.is-success{color:#67C23A;border-color:#67C23A}.el-step__head.is-error{color:#F56C6C;border-color:#F56C6C}.el-step__head.is-finish{color:#409EFF;border-color:#409EFF}.el-step__icon{position:relative;z-index:1;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:24px;height:24px;font-size:14px;box-sizing:border-box;background:#FFF;-webkit-transition:.15s ease-out;transition:.15s ease-out}.el-step.is-horizontal,.el-step__icon-inner{display:inline-block}.el-step__icon.is-text{border-radius:50%;border:2px solid;border-color:inherit}.el-step__icon.is-icon{width:40px}.el-step__icon-inner{-webkit-user-select:none;user-select:none;text-align:center;font-weight:700;line-height:1;color:inherit}.el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:25px;font-weight:400}.el-step__icon-inner.is-status{-webkit-transform:translateY(1px);transform:translateY(1px)}.el-step__line{position:absolute;border-color:inherit;background-color:#C0C4CC}.el-step__line-inner{display:block;border-width:1px;border-style:solid;border-color:inherit;-webkit-transition:.15s ease-out;transition:.15s ease-out;-webkit-box-sizing:border-box;box-sizing:border-box;width:0;height:0}.el-step__main{white-space:normal;text-align:left}.el-step__title{font-size:16px;line-height:38px}.el-step__title.is-process{font-weight:700;color:#303133}.el-step__title.is-wait{color:#C0C4CC}.el-step__title.is-success{color:#67C23A}.el-step__title.is-error{color:#F56C6C}.el-step__title.is-finish{color:#409EFF}.el-step__description{padding-right:10%;margin-top:-5px;font-size:12px;line-height:20px;font-weight:400}.el-step__description.is-process{color:#303133}.el-step__description.is-wait{color:#C0C4CC}.el-step__description.is-success{color:#67C23A}.el-step__description.is-error{color:#F56C6C}.el-step__description.is-finish{color:#409EFF}.el-step.is-horizontal .el-step__line{height:2px;top:11px;left:0;right:0}.el-step.is-vertical{display:flex}.el-step.is-vertical .el-step__head{-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;width:24px}.el-step.is-vertical .el-step__main{padding-left:10px;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.el-step.is-vertical .el-step__title{line-height:24px;padding-bottom:8px}.el-step.is-vertical .el-step__line{width:2px;top:0;bottom:0;left:11px}.el-step.is-vertical .el-step__icon.is-icon{width:24px}.el-step.is-center .el-step__head,.el-step.is-center .el-step__main{text-align:center}.el-step.is-center .el-step__description{padding-left:20%;padding-right:20%}.el-step.is-center .el-step__line{left:50%;right:-50%}.el-step.is-simple{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-step.is-simple .el-step__head{width:auto;font-size:0;padding-right:10px}.el-step.is-simple .el-step__icon{background:0 0;width:16px;height:16px;font-size:12px}.el-step.is-simple .el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:18px}.el-step.is-simple .el-step__icon-inner.is-status{-webkit-transform:scale(.8) translateY(1px);transform:scale(.8) translateY(1px)}.el-step.is-simple .el-step__main{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.el-step.is-simple .el-step__title{font-size:16px;line-height:20px}.el-step.is-simple:not(:last-of-type) .el-step__title{max-width:50%;word-break:break-all}.el-step.is-simple .el-step__arrow{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-step.is-simple .el-step__arrow::after,.el-step.is-simple .el-step__arrow::before{content:'';display:inline-block;position:absolute;height:15px;width:1px;background:#C0C4CC}.el-step.is-simple .el-step__arrow::before{-webkit-transform:rotate(-45deg) translateY(-4px);transform:rotate(-45deg) translateY(-4px);-webkit-transform-origin:0 0;transform-origin:0 0}.el-step.is-simple .el-step__arrow::after{-webkit-transform:rotate(45deg) translateY(4px);transform:rotate(45deg) translateY(4px);-webkit-transform-origin:100% 100%;transform-origin:100% 100%}.el-step.is-simple:last-of-type .el-step__arrow{display:none}.el-carousel{position:relative}.el-carousel--horizontal{overflow-x:hidden}.el-carousel--vertical{overflow-y:hidden}.el-carousel__container{position:relative;height:300px}.el-carousel__arrow{border:none;outline:0;padding:0;margin:0;height:36px;width:36px;cursor:pointer;-webkit-transition:.3s;transition:.3s;border-radius:50%;background-color:rgba(31,45,61,.11);color:#FFF;position:absolute;top:50%;z-index:10;-webkit-transform:translateY(-50%);transform:translateY(-50%);text-align:center;font-size:12px}.el-carousel__arrow--left{left:16px}.el-carousel__arrow:hover{background-color:rgba(31,45,61,.23)}.el-carousel__arrow i{cursor:pointer}.el-carousel__indicators{position:absolute;list-style:none;margin:0;padding:0;z-index:2}.el-carousel__indicators--horizontal{bottom:0;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.el-carousel__indicators--vertical{right:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-carousel__indicators--outside{bottom:26px;text-align:center;position:static;-webkit-transform:none;transform:none}.el-carousel__indicators--outside .el-carousel__indicator:hover button{opacity:.64}.el-carousel__indicators--outside button{background-color:#C0C4CC;opacity:.24}.el-carousel__indicators--labels{left:0;right:0;-webkit-transform:none;transform:none;text-align:center}.el-carousel__indicators--labels .el-carousel__button{height:auto;width:auto;padding:2px 18px;font-size:12px}.el-carousel__indicators--labels .el-carousel__indicator{padding:6px 4px}.el-carousel__indicator{background-color:transparent;cursor:pointer}.el-carousel__indicator:hover button{opacity:.72}.el-carousel__indicator--horizontal{display:inline-block;padding:12px 4px}.el-carousel__indicator--vertical{padding:4px 12px}.el-carousel__indicator--vertical .el-carousel__button{width:2px;height:15px}.el-carousel__indicator.is-active button{opacity:1}.el-carousel__button{display:block;opacity:.48;width:30px;height:2px;background-color:#FFF;border:none;outline:0;padding:0;margin:0;cursor:pointer;-webkit-transition:.3s;transition:.3s}.el-carousel__item,.el-carousel__mask{height:100%;position:absolute;top:0;left:0}.carousel-arrow-left-enter,.carousel-arrow-left-leave-active{-webkit-transform:translateY(-50%) translateX(-10px);transform:translateY(-50%) translateX(-10px);opacity:0}.carousel-arrow-right-enter,.carousel-arrow-right-leave-active{-webkit-transform:translateY(-50%) translateX(10px);transform:translateY(-50%) translateX(10px);opacity:0}.el-carousel__item{width:100%;display:inline-block;overflow:hidden;z-index:0}.el-carousel__item.is-active{z-index:2}.el-carousel__item.is-animating{-webkit-transition:-webkit-transform .4s ease-in-out;transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.el-carousel__item--card{width:50%;-webkit-transition:-webkit-transform .4s ease-in-out;transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.el-carousel__item--card.is-in-stage{cursor:pointer;z-index:1}.el-carousel__item--card.is-in-stage.is-hover .el-carousel__mask,.el-carousel__item--card.is-in-stage:hover .el-carousel__mask{opacity:.12}.el-carousel__item--card.is-active{z-index:2}.el-carousel__mask{width:100%;background-color:#FFF;opacity:.24;-webkit-transition:.2s;transition:.2s}.fade-in-linear-enter-active,.fade-in-linear-leave-active{-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.fade-in-linear-enter,.fade-in-linear-leave,.fade-in-linear-leave-active{opacity:0}.el-fade-in-linear-enter-active,.el-fade-in-linear-leave-active{-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.el-fade-in-linear-enter,.el-fade-in-linear-leave,.el-fade-in-linear-leave-active{opacity:0}.el-fade-in-enter-active,.el-fade-in-leave-active{-webkit-transition:all .3s cubic-bezier(.55,0,.1,1);transition:all .3s cubic-bezier(.55,0,.1,1)}.el-fade-in-enter,.el-fade-in-leave-active{opacity:0}.el-zoom-in-center-enter-active,.el-zoom-in-center-leave-active{-webkit-transition:all .3s cubic-bezier(.55,0,.1,1);transition:all .3s cubic-bezier(.55,0,.1,1)}.el-zoom-in-center-enter,.el-zoom-in-center-leave-active{opacity:0;-webkit-transform:scaleX(0);transform:scaleX(0)}.el-zoom-in-top-enter-active,.el-zoom-in-top-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center top;transform-origin:center top}.el-zoom-in-top-enter,.el-zoom-in-top-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.el-zoom-in-bottom-enter-active,.el-zoom-in-bottom-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center bottom;transform-origin:center bottom}.el-zoom-in-bottom-enter,.el-zoom-in-bottom-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.el-zoom-in-left-enter-active,.el-zoom-in-left-leave-active{opacity:1;-webkit-transform:scale(1,1);transform:scale(1,1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:top left;transform-origin:top left}.el-zoom-in-left-enter,.el-zoom-in-left-leave-active{opacity:0;-webkit-transform:scale(.45,.45);transform:scale(.45,.45)}.collapse-transition{-webkit-transition:.3s height ease-in-out,.3s padding-top ease-in-out,.3s padding-bottom ease-in-out;transition:.3s height ease-in-out,.3s padding-top ease-in-out,.3s padding-bottom ease-in-out}.horizontal-collapse-transition{-webkit-transition:.3s width ease-in-out,.3s padding-left ease-in-out,.3s padding-right ease-in-out;transition:.3s width ease-in-out,.3s padding-left ease-in-out,.3s padding-right ease-in-out}.el-list-enter-active,.el-list-leave-active{-webkit-transition:all 1s;transition:all 1s}.el-list-enter,.el-list-leave-active{opacity:0;-webkit-transform:translateY(-30px);transform:translateY(-30px)}.el-opacity-transition{-webkit-transition:opacity .3s cubic-bezier(.55,0,.1,1);transition:opacity .3s cubic-bezier(.55,0,.1,1)}.el-collapse{border-top:1px solid #EBEEF5;border-bottom:1px solid #EBEEF5}.el-collapse-item.is-disabled .el-collapse-item__header{color:#bbb;cursor:not-allowed}.el-collapse-item__header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:48px;line-height:48px;background-color:#FFF;color:#303133;cursor:pointer;border-bottom:1px solid #EBEEF5;font-size:13px;font-weight:500;-webkit-transition:border-bottom-color .3s;transition:border-bottom-color .3s;outline:0}.el-collapse-item__arrow{margin:0 8px 0 auto;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-weight:300}.el-collapse-item__arrow.is-active{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-collapse-item__header.focusing:focus:not(:hover){color:#409EFF}.el-collapse-item__header.is-active{border-bottom-color:transparent}.el-collapse-item__wrap{will-change:height;background-color:#FFF;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;border-bottom:1px solid #EBEEF5}.el-cascader__search-input,.el-cascader__tags,.el-tag{-webkit-box-sizing:border-box}.el-collapse-item__content{padding-bottom:25px;font-size:13px;color:#303133;line-height:1.769230769230769}.el-collapse-item:last-child{margin-bottom:-1px}.el-popper .popper__arrow,.el-popper .popper__arrow::after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-cascader,.el-tag{display:inline-block}.el-popper .popper__arrow{border-width:6px;-webkit-filter:drop-shadow(0 2px 12px rgba(0, 0, 0, .03));filter:drop-shadow(0 2px 12px rgba(0, 0, 0, .03))}.el-popper .popper__arrow::after{content:" ";border-width:6px}.el-popper[x-placement^=top]{margin-bottom:12px}.el-popper[x-placement^=top] .popper__arrow{bottom:-6px;left:50%;margin-right:3px;border-top-color:#EBEEF5;border-bottom-width:0}.el-popper[x-placement^=top] .popper__arrow::after{bottom:1px;margin-left:-6px;border-top-color:#FFF;border-bottom-width:0}.el-popper[x-placement^=bottom]{margin-top:12px}.el-popper[x-placement^=bottom] .popper__arrow{top:-6px;left:50%;margin-right:3px;border-top-width:0;border-bottom-color:#EBEEF5}.el-popper[x-placement^=bottom] .popper__arrow::after{top:1px;margin-left:-6px;border-top-width:0;border-bottom-color:#FFF}.el-popper[x-placement^=right]{margin-left:12px}.el-popper[x-placement^=right] .popper__arrow{top:50%;left:-6px;margin-bottom:3px;border-right-color:#EBEEF5;border-left-width:0}.el-popper[x-placement^=right] .popper__arrow::after{bottom:-6px;left:1px;border-right-color:#FFF;border-left-width:0}.el-popper[x-placement^=left]{margin-right:12px}.el-popper[x-placement^=left] .popper__arrow{top:50%;right:-6px;margin-bottom:3px;border-right-width:0;border-left-color:#EBEEF5}.el-popper[x-placement^=left] .popper__arrow::after{right:1px;bottom:-6px;margin-left:-6px;border-right-width:0;border-left-color:#FFF}.el-tag{background-color:#ecf5ff;border-color:#d9ecff;height:32px;padding:0 10px;line-height:30px;font-size:12px;color:#409EFF;border-width:1px;border-style:solid;border-radius:4px;box-sizing:border-box;white-space:nowrap}.el-tag.is-hit{border-color:#409EFF}.el-tag .el-tag__close{color:#409eff}.el-tag .el-tag__close:hover{color:#FFF;background-color:#409eff}.el-tag.el-tag--info{background-color:#f4f4f5;border-color:#e9e9eb;color:#909399}.el-tag.el-tag--info.is-hit{border-color:#909399}.el-tag.el-tag--info .el-tag__close{color:#909399}.el-tag.el-tag--info .el-tag__close:hover{color:#FFF;background-color:#909399}.el-tag.el-tag--success{background-color:#f0f9eb;border-color:#e1f3d8;color:#67c23a}.el-tag.el-tag--success.is-hit{border-color:#67C23A}.el-tag.el-tag--success .el-tag__close{color:#67c23a}.el-tag.el-tag--success .el-tag__close:hover{color:#FFF;background-color:#67c23a}.el-tag.el-tag--warning{background-color:#fdf6ec;border-color:#faecd8;color:#e6a23c}.el-tag.el-tag--warning.is-hit{border-color:#E6A23C}.el-tag.el-tag--warning .el-tag__close{color:#e6a23c}.el-tag.el-tag--warning .el-tag__close:hover{color:#FFF;background-color:#e6a23c}.el-tag.el-tag--danger{background-color:#fef0f0;border-color:#fde2e2;color:#f56c6c}.el-tag.el-tag--danger.is-hit{border-color:#F56C6C}.el-tag.el-tag--danger .el-tag__close{color:#f56c6c}.el-tag.el-tag--danger .el-tag__close:hover{color:#FFF;background-color:#f56c6c}.el-tag .el-icon-close{border-radius:50%;text-align:center;position:relative;cursor:pointer;font-size:12px;height:16px;width:16px;line-height:16px;vertical-align:middle;top:-1px;right:-5px}.el-tag .el-icon-close::before{display:block}.el-tag--dark{background-color:#409eff;border-color:#409eff;color:#fff}.el-tag--dark.is-hit{border-color:#409EFF}.el-tag--dark .el-tag__close{color:#fff}.el-tag--dark .el-tag__close:hover{color:#FFF;background-color:#66b1ff}.el-tag--dark.el-tag--info{background-color:#909399;border-color:#909399;color:#fff}.el-tag--dark.el-tag--info.is-hit{border-color:#909399}.el-tag--dark.el-tag--info .el-tag__close{color:#fff}.el-tag--dark.el-tag--info .el-tag__close:hover{color:#FFF;background-color:#a6a9ad}.el-tag--dark.el-tag--success{background-color:#67c23a;border-color:#67c23a;color:#fff}.el-tag--dark.el-tag--success.is-hit{border-color:#67C23A}.el-tag--dark.el-tag--success .el-tag__close{color:#fff}.el-tag--dark.el-tag--success .el-tag__close:hover{color:#FFF;background-color:#85ce61}.el-tag--dark.el-tag--warning{background-color:#e6a23c;border-color:#e6a23c;color:#fff}.el-tag--dark.el-tag--warning.is-hit{border-color:#E6A23C}.el-tag--dark.el-tag--warning .el-tag__close{color:#fff}.el-tag--dark.el-tag--warning .el-tag__close:hover{color:#FFF;background-color:#ebb563}.el-tag--dark.el-tag--danger{background-color:#f56c6c;border-color:#f56c6c;color:#fff}.el-tag--dark.el-tag--danger.is-hit{border-color:#F56C6C}.el-tag--dark.el-tag--danger .el-tag__close{color:#fff}.el-tag--dark.el-tag--danger .el-tag__close:hover{color:#FFF;background-color:#f78989}.el-tag--plain{background-color:#fff;border-color:#b3d8ff;color:#409eff}.el-tag--plain.is-hit{border-color:#409EFF}.el-tag--plain .el-tag__close{color:#409eff}.el-tag--plain .el-tag__close:hover{color:#FFF;background-color:#409eff}.el-tag--plain.el-tag--info{background-color:#fff;border-color:#d3d4d6;color:#909399}.el-tag--plain.el-tag--info.is-hit{border-color:#909399}.el-tag--plain.el-tag--info .el-tag__close{color:#909399}.el-tag--plain.el-tag--info .el-tag__close:hover{color:#FFF;background-color:#909399}.el-tag--plain.el-tag--success{background-color:#fff;border-color:#c2e7b0;color:#67c23a}.el-tag--plain.el-tag--success.is-hit{border-color:#67C23A}.el-tag--plain.el-tag--success .el-tag__close{color:#67c23a}.el-tag--plain.el-tag--success .el-tag__close:hover{color:#FFF;background-color:#67c23a}.el-tag--plain.el-tag--warning{background-color:#fff;border-color:#f5dab1;color:#e6a23c}.el-tag--plain.el-tag--warning.is-hit{border-color:#E6A23C}.el-tag--plain.el-tag--warning .el-tag__close{color:#e6a23c}.el-tag--plain.el-tag--warning .el-tag__close:hover{color:#FFF;background-color:#e6a23c}.el-tag--plain.el-tag--danger{background-color:#fff;border-color:#fbc4c4;color:#f56c6c}.el-tag--plain.el-tag--danger.is-hit{border-color:#F56C6C}.el-tag--plain.el-tag--danger .el-tag__close{color:#f56c6c}.el-tag--plain.el-tag--danger .el-tag__close:hover{color:#FFF;background-color:#f56c6c}.el-tag--medium{height:28px;line-height:26px}.el-tag--medium .el-icon-close{-webkit-transform:scale(.8);transform:scale(.8)}.el-tag--small{height:24px;padding:0 8px;line-height:22px}.el-tag--small .el-icon-close{-webkit-transform:scale(.8);transform:scale(.8)}.el-tag--mini{height:20px;padding:0 5px;line-height:19px}.el-tag--mini .el-icon-close{margin-left:-3px;-webkit-transform:scale(.7);transform:scale(.7)}.el-cascader{position:relative;font-size:14px;line-height:40px}.el-cascader:not(.is-disabled):hover .el-input__inner{cursor:pointer;border-color:#C0C4CC}.el-cascader .el-input .el-input__inner:focus,.el-cascader .el-input.is-focus .el-input__inner{border-color:#409EFF}.el-cascader .el-input{cursor:pointer}.el-cascader .el-input .el-input__inner{text-overflow:ellipsis}.el-cascader .el-input .el-icon-arrow-down{-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-size:14px}.el-cascader .el-input .el-icon-arrow-down.is-reverse{-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg)}.el-cascader .el-input .el-icon-circle-close:hover{color:#909399}.el-cascader--medium{font-size:14px;line-height:36px}.el-cascader--small{font-size:13px;line-height:32px}.el-cascader--mini{font-size:12px;line-height:28px}.el-cascader.is-disabled .el-cascader__label{z-index:2;color:#C0C4CC}.el-cascader__dropdown{margin:5px 0;font-size:14px;background:#FFF;border:1px solid #E4E7ED;border-radius:4px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-cascader__tags{position:absolute;left:0;right:30px;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;line-height:normal;text-align:left;box-sizing:border-box}.el-cascader__tags .el-tag{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;max-width:100%;margin:2px 0 2px 6px;text-overflow:ellipsis;background:#f0f2f5}.el-cascader__tags .el-tag:not(.is-hit){border-color:transparent}.el-cascader__tags .el-tag>span{-webkit-box-flex:1;-ms-flex:1;flex:1;overflow:hidden;text-overflow:ellipsis}.el-cascader__tags .el-tag .el-icon-close{-webkit-box-flex:0;-ms-flex:none;flex:none;background-color:#C0C4CC;color:#FFF}.el-cascader__tags .el-tag .el-icon-close:hover{background-color:#909399}.el-cascader__suggestion-panel{border-radius:4px}.el-cascader__suggestion-list{max-height:204px;margin:0;padding:6px 0;font-size:14px;color:#606266;text-align:center}.el-cascader__suggestion-item{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:34px;padding:0 15px;text-align:left;outline:0;cursor:pointer}.el-cascader__suggestion-item:focus,.el-cascader__suggestion-item:hover{background:#F5F7FA}.el-cascader__suggestion-item.is-checked{color:#409EFF;font-weight:700}.el-cascader__suggestion-item>span{margin-right:10px}.el-cascader__empty-text{margin:10px 0;color:#C0C4CC}.el-cascader__search-input{-webkit-box-flex:1;-ms-flex:1;flex:1;height:24px;min-width:60px;margin:2px 0 2px 15px;padding:0;color:#606266;border:none;outline:0;box-sizing:border-box}.el-cascader__search-input::-webkit-input-placeholder{color:#C0C4CC}.el-cascader__search-input:-ms-input-placeholder{color:#C0C4CC}.el-cascader__search-input::-ms-input-placeholder{color:#C0C4CC}.el-cascader__search-input::placeholder{color:#C0C4CC}.el-color-predefine{display:-webkit-box;display:-ms-flexbox;display:flex;font-size:12px;margin-top:8px;width:280px}.el-color-predefine__colors{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-wrap:wrap;flex-wrap:wrap}.el-color-predefine__color-selector{margin:0 0 8px 8px;width:20px;height:20px;border-radius:4px;cursor:pointer}.el-color-predefine__color-selector:nth-child(10n+1){margin-left:0}.el-color-predefine__color-selector.selected{-webkit-box-shadow:0 0 3px 2px #409EFF;box-shadow:0 0 3px 2px #409EFF}.el-color-predefine__color-selector>div{display:-webkit-box;display:-ms-flexbox;display:flex;height:100%;border-radius:3px}.el-color-predefine__color-selector.is-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-hue-slider{position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;width:280px;height:12px;background-color:red;padding:0 2px}.el-color-hue-slider__bar{position:relative;background:-webkit-gradient(linear,left top,right top,from(red),color-stop(17%,#ff0),color-stop(33%,#0f0),color-stop(50%,#0ff),color-stop(67%,#00f),color-stop(83%,#f0f),to(red));background:linear-gradient(to right,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%);height:100%}.el-color-hue-slider__thumb{position:absolute;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;left:0;top:0;width:4px;height:100%;border-radius:1px;background:#fff;border:1px solid #f0f0f0;-webkit-box-shadow:0 0 2px rgba(0,0,0,.6);box-shadow:0 0 2px rgba(0,0,0,.6);z-index:1}.el-color-hue-slider.is-vertical{width:12px;height:180px;padding:2px 0}.el-color-hue-slider.is-vertical .el-color-hue-slider__bar{background:-webkit-gradient(linear,left top,left bottom,from(red),color-stop(17%,#ff0),color-stop(33%,#0f0),color-stop(50%,#0ff),color-stop(67%,#00f),color-stop(83%,#f0f),to(red));background:linear-gradient(to bottom,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%)}.el-color-hue-slider.is-vertical .el-color-hue-slider__thumb{left:0;top:0;width:100%;height:4px}.el-color-svpanel{position:relative;width:280px;height:180px}.el-color-svpanel__black,.el-color-svpanel__white{position:absolute;top:0;left:0;right:0;bottom:0}.el-color-svpanel__white{background:-webkit-gradient(linear,left top,right top,from(#fff),to(rgba(255,255,255,0)));background:linear-gradient(to right,#fff,rgba(255,255,255,0))}.el-color-svpanel__black{background:-webkit-gradient(linear,left bottom,left top,from(#000),to(rgba(0,0,0,0)));background:linear-gradient(to top,#000,rgba(0,0,0,0))}.el-color-svpanel__cursor{position:absolute}.el-color-svpanel__cursor>div{cursor:head;width:4px;height:4px;-webkit-box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);border-radius:50%;-webkit-transform:translate(-2px,-2px);transform:translate(-2px,-2px)}.el-color-alpha-slider{position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;width:280px;height:12px;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-alpha-slider__bar{position:relative;background:-webkit-gradient(linear,left top,right top,from(rgba(255,255,255,0)),to(white));background:linear-gradient(to right,rgba(255,255,255,0) 0,#fff 100%);height:100%}.el-color-alpha-slider__thumb{position:absolute;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;left:0;top:0;width:4px;height:100%;border-radius:1px;background:#fff;border:1px solid #f0f0f0;-webkit-box-shadow:0 0 2px rgba(0,0,0,.6);box-shadow:0 0 2px rgba(0,0,0,.6);z-index:1}.el-color-alpha-slider.is-vertical{width:20px;height:180px}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__bar{background:-webkit-gradient(linear,left top,left bottom,from(rgba(255,255,255,0)),to(white));background:linear-gradient(to bottom,rgba(255,255,255,0) 0,#fff 100%)}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__thumb{left:0;top:0;width:100%;height:4px}.el-color-dropdown{width:300px}.el-color-dropdown__main-wrapper{margin-bottom:6px}.el-color-dropdown__main-wrapper::after{display:table;clear:both}.el-color-dropdown__btns{margin-top:6px;text-align:right}.el-color-dropdown__value{float:left;line-height:26px;font-size:12px;color:#000;width:160px}.el-color-dropdown__btn{border:1px solid #dcdcdc;color:#333;line-height:24px;border-radius:2px;padding:0 20px;cursor:pointer;background-color:transparent;outline:0;font-size:12px}.el-color-dropdown__btn[disabled]{color:#ccc;cursor:not-allowed}.el-color-dropdown__btn:hover{color:#409EFF;border-color:#409EFF}.el-color-dropdown__link-btn{cursor:pointer;color:#409EFF;text-decoration:none;padding:15px;font-size:12px}.el-color-dropdown__link-btn:hover{color:tint(#409EFF,20%)}.el-color-picker{display:inline-block;position:relative;line-height:normal;height:40px}.el-color-picker.is-disabled .el-color-picker__trigger{cursor:not-allowed}.el-color-picker--medium{height:36px}.el-color-picker--medium .el-color-picker__trigger{height:36px;width:36px}.el-color-picker--medium .el-color-picker__mask{height:34px;width:34px}.el-color-picker--small{height:32px}.el-color-picker--small .el-color-picker__trigger{height:32px;width:32px}.el-color-picker--small .el-color-picker__mask{height:30px;width:30px}.el-color-picker--small .el-color-picker__empty,.el-color-picker--small .el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0) scale(.8);transform:translate3d(-50%,-50%,0) scale(.8)}.el-color-picker--mini{height:28px}.el-color-picker--mini .el-color-picker__trigger{height:28px;width:28px}.el-color-picker--mini .el-color-picker__mask{height:26px;width:26px}.el-color-picker--mini .el-color-picker__empty,.el-color-picker--mini .el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0) scale(.8);transform:translate3d(-50%,-50%,0) scale(.8)}.el-color-picker__mask{height:38px;width:38px;border-radius:4px;position:absolute;top:1px;left:1px;z-index:1;cursor:not-allowed;background-color:rgba(255,255,255,.7)}.el-color-picker__trigger{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;height:40px;width:40px;padding:4px;border:1px solid #e6e6e6;border-radius:4px;font-size:0;position:relative;cursor:pointer}.el-color-picker__color{position:relative;display:block;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid #999;border-radius:2px;width:100%;height:100%;text-align:center}.el-color-picker__icon,.el-input,.el-textarea{display:inline-block;width:100%}.el-color-picker__color.is-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-picker__color-inner{position:absolute;left:0;top:0;right:0;bottom:0}.el-color-picker__empty{font-size:12px;color:#999;position:absolute;top:50%;left:50%;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0)}.el-color-picker__icon{position:absolute;top:50%;left:50%;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0);color:#FFF;text-align:center;font-size:12px}.el-input__prefix,.el-input__suffix{position:absolute;top:0;text-align:center}.el-color-picker__panel{position:absolute;z-index:10;padding:6px;-webkit-box-sizing:content-box;box-sizing:content-box;background-color:#FFF;border:1px solid #EBEEF5;border-radius:4px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-input__inner,.el-textarea__inner,.el-transfer-panel{-webkit-box-sizing:border-box}.el-textarea{position:relative;vertical-align:bottom;font-size:14px}.el-textarea__inner{display:block;resize:vertical;padding:5px 15px;line-height:1.5;box-sizing:border-box;width:100%;font-size:inherit;color:#606266;background-color:#FFF;background-image:none;border:1px solid #DCDFE6;border-radius:4px;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-textarea__inner::-webkit-input-placeholder{color:#C0C4CC}.el-textarea__inner:-ms-input-placeholder{color:#C0C4CC}.el-textarea__inner::-ms-input-placeholder{color:#C0C4CC}.el-textarea__inner::placeholder{color:#C0C4CC}.el-textarea__inner:hover{border-color:#C0C4CC}.el-textarea__inner:focus{outline:0;border-color:#409EFF}.el-textarea .el-input__count{color:#909399;background:#FFF;position:absolute;font-size:12px;bottom:5px;right:10px}.el-textarea.is-disabled .el-textarea__inner{background-color:#F5F7FA;border-color:#E4E7ED;color:#C0C4CC;cursor:not-allowed}.el-textarea.is-disabled .el-textarea__inner::-webkit-input-placeholder{color:#C0C4CC}.el-textarea.is-disabled .el-textarea__inner:-ms-input-placeholder{color:#C0C4CC}.el-textarea.is-disabled .el-textarea__inner::-ms-input-placeholder{color:#C0C4CC}.el-textarea.is-disabled .el-textarea__inner::placeholder{color:#C0C4CC}.el-textarea.is-exceed .el-textarea__inner{border-color:#F56C6C}.el-textarea.is-exceed .el-input__count{color:#F56C6C}.el-input{position:relative;font-size:14px}.el-input::-webkit-scrollbar{z-index:11;width:6px}.el-input::-webkit-scrollbar:horizontal{height:6px}.el-input::-webkit-scrollbar-thumb{border-radius:5px;width:6px;background:#b4bccc}.el-input::-webkit-scrollbar-corner{background:#fff}.el-input::-webkit-scrollbar-track{background:#fff}.el-input::-webkit-scrollbar-track-piece{background:#fff;width:6px}.el-input .el-input__clear{color:#C0C4CC;font-size:14px;cursor:pointer;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-input .el-input__clear:hover{color:#909399}.el-input .el-input__count{height:100%;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#909399;font-size:12px}.el-input-group__append .el-button,.el-input-group__append .el-input,.el-input-group__prepend .el-button,.el-input-group__prepend .el-input,.el-input__inner{font-size:inherit}.el-input .el-input__count .el-input__count-inner{background:#FFF;line-height:initial;display:inline-block;padding:0 5px}.el-input__inner{-webkit-appearance:none;background-color:#FFF;background-image:none;border-radius:4px;border:1px solid #DCDFE6;box-sizing:border-box;color:#606266;display:inline-block;height:40px;line-height:40px;outline:0;padding:0 15px;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1);width:100%}.el-input__inner::-ms-reveal{display:none}.el-input__inner::-webkit-input-placeholder{color:#C0C4CC}.el-input__inner:-ms-input-placeholder{color:#C0C4CC}.el-input__inner::-ms-input-placeholder{color:#C0C4CC}.el-input__inner::placeholder{color:#C0C4CC}.el-input__inner:hover{border-color:#C0C4CC}.el-input.is-active .el-input__inner,.el-input__inner:focus{border-color:#409EFF;outline:0}.el-input__suffix{height:100%;right:5px;transition:all .3s;pointer-events:none}.el-input__suffix-inner{pointer-events:all}.el-input__prefix{height:100%;left:5px;transition:all .3s}.el-input__icon{height:100%;width:25px;text-align:center;-webkit-transition:all .3s;transition:all .3s;line-height:40px}.el-input__icon:after{content:'';height:100%;width:0;display:inline-block;vertical-align:middle}.el-input__validateIcon{pointer-events:none}.el-input.is-disabled .el-input__inner{background-color:#F5F7FA;border-color:#E4E7ED;color:#C0C4CC;cursor:not-allowed}.el-input.is-disabled .el-input__inner::-webkit-input-placeholder{color:#C0C4CC}.el-input.is-disabled .el-input__inner:-ms-input-placeholder{color:#C0C4CC}.el-input.is-disabled .el-input__inner::-ms-input-placeholder{color:#C0C4CC}.el-input.is-disabled .el-input__inner::placeholder{color:#C0C4CC}.el-input.is-disabled .el-input__icon{cursor:not-allowed}.el-image-viewer__btn,.el-image__preview,.el-link,.el-transfer-panel__filter .el-icon-circle-close{cursor:pointer}.el-input.is-exceed .el-input__inner{border-color:#F56C6C}.el-input.is-exceed .el-input__suffix .el-input__count{color:#F56C6C}.el-input--suffix .el-input__inner{padding-right:30px}.el-input--prefix .el-input__inner{padding-left:30px}.el-input--medium{font-size:14px}.el-input--medium .el-input__inner{height:36px;line-height:36px}.el-input--medium .el-input__icon{line-height:36px}.el-input--small{font-size:13px}.el-input--small .el-input__inner{height:32px;line-height:32px}.el-input--small .el-input__icon{line-height:32px}.el-input--mini{font-size:12px}.el-input--mini .el-input__inner{height:28px;line-height:28px}.el-input--mini .el-input__icon{line-height:28px}.el-input-group{line-height:normal;display:inline-table;width:100%;border-collapse:separate;border-spacing:0}.el-input-group>.el-input__inner{vertical-align:middle;display:table-cell}.el-input-group__append,.el-input-group__prepend{background-color:#F5F7FA;color:#909399;vertical-align:middle;display:table-cell;position:relative;border:1px solid #DCDFE6;border-radius:4px;padding:0 20px;width:1px;white-space:nowrap}.el-input-group--append .el-input__inner,.el-input-group__prepend{border-top-right-radius:0;border-bottom-right-radius:0}.el-input-group__append:focus,.el-input-group__prepend:focus{outline:0}.el-input-group__append .el-button,.el-input-group__append .el-select,.el-input-group__prepend .el-button,.el-input-group__prepend .el-select{display:inline-block;margin:-10px -20px}.el-input-group__append button.el-button,.el-input-group__append div.el-select .el-input__inner,.el-input-group__append div.el-select:hover .el-input__inner,.el-input-group__prepend button.el-button,.el-input-group__prepend div.el-select .el-input__inner,.el-input-group__prepend div.el-select:hover .el-input__inner{border-color:transparent;background-color:transparent;color:inherit;border-top:0;border-bottom:0}.el-input-group__prepend{border-right:0}.el-input-group__append{border-left:0;border-top-left-radius:0;border-bottom-left-radius:0}.el-input-group--append .el-select .el-input.is-focus .el-input__inner,.el-input-group--prepend .el-select .el-input.is-focus .el-input__inner{border-color:transparent}.el-input-group--prepend .el-input__inner{border-top-left-radius:0;border-bottom-left-radius:0}.el-input__inner::-ms-clear{display:none;width:0;height:0}.el-transfer{font-size:14px}.el-transfer__buttons{display:inline-block;vertical-align:middle;padding:0 30px}.el-transfer__button{display:block;margin:0 auto;padding:10px;border-radius:50%;color:#FFF;background-color:#409EFF;font-size:0}.el-button-group>.el-button+.el-button,.el-transfer-panel__item+.el-transfer-panel__item,.el-transfer__button [class*=el-icon-]+span{margin-left:0}.el-divider__text,.el-image__error,.el-link,.el-timeline,.el-transfer__button i,.el-transfer__button span{font-size:14px}.el-transfer__button.is-with-texts{border-radius:4px}.el-transfer__button.is-disabled,.el-transfer__button.is-disabled:hover{border:1px solid #DCDFE6;background-color:#F5F7FA;color:#C0C4CC}.el-transfer__button:first-child{margin-bottom:10px}.el-transfer__button:nth-child(2){margin:0}.el-transfer-panel{border:1px solid #EBEEF5;border-radius:4px;overflow:hidden;background:#FFF;display:inline-block;vertical-align:middle;width:200px;max-height:100%;box-sizing:border-box;position:relative}.el-transfer-panel__body{height:246px}.el-transfer-panel__body.is-with-footer{padding-bottom:40px}.el-transfer-panel__list{margin:0;padding:6px 0;list-style:none;height:246px;overflow:auto;-webkit-box-sizing:border-box;box-sizing:border-box}.el-transfer-panel__list.is-filterable{height:194px;padding-top:0}.el-transfer-panel__item{height:30px;line-height:30px;padding-left:15px;display:block!important}.el-transfer-panel__item.el-checkbox{color:#606266}.el-transfer-panel__item:hover{color:#409EFF}.el-transfer-panel__item.el-checkbox .el-checkbox__label{width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;-webkit-box-sizing:border-box;box-sizing:border-box;padding-left:24px;line-height:30px}.el-transfer-panel__item .el-checkbox__input{position:absolute;top:8px}.el-transfer-panel__filter{text-align:center;margin:15px;-webkit-box-sizing:border-box;box-sizing:border-box;display:block;width:auto}.el-transfer-panel__filter .el-input__inner{height:32px;width:100%;font-size:12px;display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:16px;padding-right:10px;padding-left:30px}.el-transfer-panel__filter .el-input__icon{margin-left:5px}.el-transfer-panel .el-transfer-panel__header{height:40px;line-height:40px;background:#F5F7FA;margin:0;padding-left:15px;border-bottom:1px solid #EBEEF5;-webkit-box-sizing:border-box;box-sizing:border-box;color:#000}.el-container,.el-header{-webkit-box-sizing:border-box}.el-transfer-panel .el-transfer-panel__header .el-checkbox{display:block;line-height:40px}.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label{font-size:16px;color:#303133;font-weight:400}.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label span{position:absolute;right:15px;color:#909399;font-size:12px;font-weight:400}.el-transfer-panel .el-transfer-panel__footer{height:40px;background:#FFF;margin:0;padding:0;border-top:1px solid #EBEEF5;position:absolute;bottom:0;left:0;width:100%;z-index:1}.el-transfer-panel .el-transfer-panel__footer::after{display:inline-block;height:100%;vertical-align:middle}.el-container,.el-timeline-item__node{display:-webkit-box;display:-ms-flexbox}.el-transfer-panel .el-transfer-panel__footer .el-checkbox{padding-left:20px;color:#606266}.el-transfer-panel .el-transfer-panel__empty{margin:0;height:30px;line-height:30px;padding:6px 15px 0;color:#909399;text-align:center}.el-transfer-panel .el-checkbox__label{padding-left:8px}.el-transfer-panel .el-checkbox__inner{height:14px;width:14px;border-radius:3px}.el-transfer-panel .el-checkbox__inner::after{height:6px;width:3px;left:4px}.el-container{display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-preferred-size:auto;flex-basis:auto;box-sizing:border-box;min-width:0}.el-container.is-vertical,.el-drawer,.el-empty,.el-result{-webkit-box-orient:vertical;-webkit-box-direction:normal}.el-container.is-vertical{-ms-flex-direction:column;flex-direction:column}.el-header{padding:0 20px;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-aside{overflow:auto;-webkit-box-sizing:border-box;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-main{display:block;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-preferred-size:auto;flex-basis:auto;overflow:auto;-webkit-box-sizing:border-box;box-sizing:border-box}.el-footer{padding:0 20px;-webkit-box-sizing:border-box;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-timeline{margin:0;list-style:none}.el-timeline .el-timeline-item:last-child .el-timeline-item__tail{display:none}.el-timeline-item{position:relative;padding-bottom:20px}.el-timeline-item__wrapper{position:relative;padding-left:28px;top:-3px}.el-timeline-item__tail{position:absolute;left:4px;height:100%;border-left:2px solid #E4E7ED}.el-timeline-item__icon{color:#FFF;font-size:13px}.el-timeline-item__node{position:absolute;background-color:#E4E7ED;border-radius:50%;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-image__error,.el-timeline-item__dot{display:-webkit-box;display:-ms-flexbox}.el-timeline-item__node--normal{left:-1px;width:12px;height:12px}.el-timeline-item__node--large{left:-2px;width:14px;height:14px}.el-timeline-item__node--primary{background-color:#409EFF}.el-timeline-item__node--success{background-color:#67C23A}.el-timeline-item__node--warning{background-color:#E6A23C}.el-timeline-item__node--danger{background-color:#F56C6C}.el-timeline-item__node--info{background-color:#909399}.el-timeline-item__dot{position:absolute;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-timeline-item__content{color:#303133}.el-timeline-item__timestamp{color:#909399;line-height:1;font-size:13px}.el-timeline-item__timestamp.is-top{margin-bottom:8px;padding-top:4px}.el-timeline-item__timestamp.is-bottom{margin-top:8px}.el-link{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;vertical-align:middle;position:relative;text-decoration:none;outline:0;padding:0;font-weight:500}.el-link.is-underline:hover:after{position:absolute;left:0;right:0;height:0;bottom:0;border-bottom:1px solid #409EFF}.el-link.el-link--default:after,.el-link.el-link--primary.is-underline:hover:after,.el-link.el-link--primary:after{border-color:#409EFF}.el-link.is-disabled{cursor:not-allowed}.el-link [class*=el-icon-]+span{margin-left:5px}.el-link.el-link--default{color:#606266}.el-link.el-link--default:hover{color:#409EFF}.el-link.el-link--default.is-disabled{color:#C0C4CC}.el-link.el-link--primary{color:#409EFF}.el-link.el-link--primary:hover{color:#66b1ff}.el-link.el-link--primary.is-disabled{color:#a0cfff}.el-link.el-link--danger.is-underline:hover:after,.el-link.el-link--danger:after{border-color:#F56C6C}.el-link.el-link--danger{color:#F56C6C}.el-link.el-link--danger:hover{color:#f78989}.el-link.el-link--danger.is-disabled{color:#fab6b6}.el-link.el-link--success.is-underline:hover:after,.el-link.el-link--success:after{border-color:#67C23A}.el-link.el-link--success{color:#67C23A}.el-link.el-link--success:hover{color:#85ce61}.el-link.el-link--success.is-disabled{color:#b3e19d}.el-link.el-link--warning.is-underline:hover:after,.el-link.el-link--warning:after{border-color:#E6A23C}.el-link.el-link--warning{color:#E6A23C}.el-link.el-link--warning:hover{color:#ebb563}.el-link.el-link--warning.is-disabled{color:#f3d19e}.el-link.el-link--info.is-underline:hover:after,.el-link.el-link--info:after{border-color:#909399}.el-link.el-link--info{color:#909399}.el-link.el-link--info:hover{color:#a6a9ad}.el-link.el-link--info.is-disabled{color:#c8c9cc}.el-divider{background-color:#DCDFE6;position:relative}.el-divider--horizontal{display:block;height:1px;width:100%;margin:24px 0}.el-divider--vertical{display:inline-block;width:1px;height:1em;margin:0 8px;vertical-align:middle;position:relative}.el-divider__text{position:absolute;background-color:#FFF;padding:0 20px;font-weight:500;color:#303133}.el-image__error,.el-image__placeholder{background:#F5F7FA}.el-divider__text.is-left{left:20px;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-divider__text.is-center{left:50%;-webkit-transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%)}.el-divider__text.is-right{right:20px;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-image__error,.el-image__inner,.el-image__placeholder{width:100%;height:100%}.el-image{position:relative;display:inline-block;overflow:hidden}.el-image__inner{vertical-align:top}.el-image__inner--center{position:relative;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);display:block}.el-image__error{display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#C0C4CC;vertical-align:middle}.el-image-viewer__wrapper{position:fixed;top:0;right:0;bottom:0;left:0}.el-image-viewer__btn{position:absolute;z-index:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;border-radius:50%;opacity:.8;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-user-select:none;user-select:none}.el-button,.el-checkbox,.el-checkbox-button__inner,.el-empty__image img,.el-radio{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.el-image-viewer__close{top:40px;right:40px;width:40px;height:40px;font-size:24px;color:#fff;background-color:#606266}.el-image-viewer__canvas{width:100%;height:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-image-viewer__actions{left:50%;bottom:30px;-webkit-transform:translateX(-50%);transform:translateX(-50%);width:282px;height:44px;padding:0 23px;background-color:#606266;border-color:#fff;border-radius:22px}.el-image-viewer__actions__inner{width:100%;height:100%;text-align:justify;cursor:default;font-size:23px;color:#fff;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-pack:distribute;justify-content:space-around}.el-image-viewer__next,.el-image-viewer__prev{width:44px;height:44px;font-size:24px;color:#fff;background-color:#606266;border-color:#fff;top:50%}.el-image-viewer__prev{-webkit-transform:translateY(-50%);transform:translateY(-50%);left:40px}.el-image-viewer__next{-webkit-transform:translateY(-50%);transform:translateY(-50%);right:40px;text-indent:2px}.el-image-viewer__mask{position:absolute;width:100%;height:100%;top:0;left:0;opacity:.5;background:#000}.viewer-fade-enter-active{-webkit-animation:viewer-fade-in .3s;animation:viewer-fade-in .3s}.viewer-fade-leave-active{-webkit-animation:viewer-fade-out .3s;animation:viewer-fade-out .3s}@-webkit-keyframes viewer-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes viewer-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes viewer-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes viewer-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-button{display:inline-block;line-height:1;white-space:nowrap;cursor:pointer;background:#FFF;border:1px solid #DCDFE6;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;-webkit-transition:.1s;transition:.1s;font-weight:500;padding:12px 20px;font-size:14px;border-radius:4px}.el-button+.el-button,.el-checkbox.is-bordered+.el-checkbox.is-bordered{margin-left:10px}.el-button:focus,.el-button:hover{color:#409EFF;border-color:#c6e2ff;background-color:#ecf5ff}.el-button:active{color:#3a8ee6;border-color:#3a8ee6;outline:0}.el-button::-moz-focus-inner{border:0}.el-button [class*=el-icon-]+span{margin-left:5px}.el-button.is-plain:focus,.el-button.is-plain:hover{background:#FFF;border-color:#409EFF;color:#409EFF}.el-button.is-active,.el-button.is-plain:active{color:#3a8ee6;border-color:#3a8ee6}.el-button.is-plain:active{background:#FFF;outline:0}.el-button.is-disabled,.el-button.is-disabled:focus,.el-button.is-disabled:hover{color:#C0C4CC;cursor:not-allowed;background-image:none;background-color:#FFF;border-color:#EBEEF5}.el-button.is-disabled.el-button--text{background-color:transparent}.el-button.is-disabled.is-plain,.el-button.is-disabled.is-plain:focus,.el-button.is-disabled.is-plain:hover{background-color:#FFF;border-color:#EBEEF5;color:#C0C4CC}.el-button.is-loading{position:relative;pointer-events:none}.el-button.is-loading:before{pointer-events:none;content:'';position:absolute;left:-1px;top:-1px;right:-1px;bottom:-1px;border-radius:inherit;background-color:rgba(255,255,255,.35)}.el-button.is-round{border-radius:20px;padding:12px 23px}.el-button.is-circle{border-radius:50%;padding:12px}.el-button--primary{color:#FFF;background-color:#409EFF;border-color:#409EFF}.el-button--primary:focus,.el-button--primary:hover{background:#66b1ff;border-color:#66b1ff;color:#FFF}.el-button--primary.is-active,.el-button--primary:active{background:#3a8ee6;border-color:#3a8ee6;color:#FFF}.el-button--primary:active{outline:0}.el-button--primary.is-disabled,.el-button--primary.is-disabled:active,.el-button--primary.is-disabled:focus,.el-button--primary.is-disabled:hover{color:#FFF;background-color:#a0cfff;border-color:#a0cfff}.el-button--primary.is-plain{color:#409EFF;background:#ecf5ff;border-color:#b3d8ff}.el-button--primary.is-plain:focus,.el-button--primary.is-plain:hover{background:#409EFF;border-color:#409EFF;color:#FFF}.el-button--primary.is-plain:active{background:#3a8ee6;border-color:#3a8ee6;color:#FFF;outline:0}.el-button--primary.is-plain.is-disabled,.el-button--primary.is-plain.is-disabled:active,.el-button--primary.is-plain.is-disabled:focus,.el-button--primary.is-plain.is-disabled:hover{color:#8cc5ff;background-color:#ecf5ff;border-color:#d9ecff}.el-button--success{color:#FFF;background-color:#67C23A;border-color:#67C23A}.el-button--success:focus,.el-button--success:hover{background:#85ce61;border-color:#85ce61;color:#FFF}.el-button--success.is-active,.el-button--success:active{background:#5daf34;border-color:#5daf34;color:#FFF}.el-button--success:active{outline:0}.el-button--success.is-disabled,.el-button--success.is-disabled:active,.el-button--success.is-disabled:focus,.el-button--success.is-disabled:hover{color:#FFF;background-color:#b3e19d;border-color:#b3e19d}.el-button--success.is-plain{color:#67C23A;background:#f0f9eb;border-color:#c2e7b0}.el-button--success.is-plain:focus,.el-button--success.is-plain:hover{background:#67C23A;border-color:#67C23A;color:#FFF}.el-button--success.is-plain:active{background:#5daf34;border-color:#5daf34;color:#FFF;outline:0}.el-button--success.is-plain.is-disabled,.el-button--success.is-plain.is-disabled:active,.el-button--success.is-plain.is-disabled:focus,.el-button--success.is-plain.is-disabled:hover{color:#a4da89;background-color:#f0f9eb;border-color:#e1f3d8}.el-button--warning{color:#FFF;background-color:#E6A23C;border-color:#E6A23C}.el-button--warning:focus,.el-button--warning:hover{background:#ebb563;border-color:#ebb563;color:#FFF}.el-button--warning.is-active,.el-button--warning:active{background:#cf9236;border-color:#cf9236;color:#FFF}.el-button--warning:active{outline:0}.el-button--warning.is-disabled,.el-button--warning.is-disabled:active,.el-button--warning.is-disabled:focus,.el-button--warning.is-disabled:hover{color:#FFF;background-color:#f3d19e;border-color:#f3d19e}.el-button--warning.is-plain{color:#E6A23C;background:#fdf6ec;border-color:#f5dab1}.el-button--warning.is-plain:focus,.el-button--warning.is-plain:hover{background:#E6A23C;border-color:#E6A23C;color:#FFF}.el-button--warning.is-plain:active{background:#cf9236;border-color:#cf9236;color:#FFF;outline:0}.el-button--warning.is-plain.is-disabled,.el-button--warning.is-plain.is-disabled:active,.el-button--warning.is-plain.is-disabled:focus,.el-button--warning.is-plain.is-disabled:hover{color:#f0c78a;background-color:#fdf6ec;border-color:#faecd8}.el-button--danger{color:#FFF;background-color:#F56C6C;border-color:#F56C6C}.el-button--danger:focus,.el-button--danger:hover{background:#f78989;border-color:#f78989;color:#FFF}.el-button--danger.is-active,.el-button--danger:active{background:#dd6161;border-color:#dd6161;color:#FFF}.el-button--danger:active{outline:0}.el-button--danger.is-disabled,.el-button--danger.is-disabled:active,.el-button--danger.is-disabled:focus,.el-button--danger.is-disabled:hover{color:#FFF;background-color:#fab6b6;border-color:#fab6b6}.el-button--danger.is-plain{color:#F56C6C;background:#fef0f0;border-color:#fbc4c4}.el-button--danger.is-plain:focus,.el-button--danger.is-plain:hover{background:#F56C6C;border-color:#F56C6C;color:#FFF}.el-button--danger.is-plain:active{background:#dd6161;border-color:#dd6161;color:#FFF;outline:0}.el-button--danger.is-plain.is-disabled,.el-button--danger.is-plain.is-disabled:active,.el-button--danger.is-plain.is-disabled:focus,.el-button--danger.is-plain.is-disabled:hover{color:#f9a7a7;background-color:#fef0f0;border-color:#fde2e2}.el-button--info{color:#FFF;background-color:#909399;border-color:#909399}.el-button--info:focus,.el-button--info:hover{background:#a6a9ad;border-color:#a6a9ad;color:#FFF}.el-button--info.is-active,.el-button--info:active{background:#82848a;border-color:#82848a;color:#FFF}.el-button--info:active{outline:0}.el-button--info.is-disabled,.el-button--info.is-disabled:active,.el-button--info.is-disabled:focus,.el-button--info.is-disabled:hover{color:#FFF;background-color:#c8c9cc;border-color:#c8c9cc}.el-button--info.is-plain{color:#909399;background:#f4f4f5;border-color:#d3d4d6}.el-button--info.is-plain:focus,.el-button--info.is-plain:hover{background:#909399;border-color:#909399;color:#FFF}.el-button--info.is-plain:active{background:#82848a;border-color:#82848a;color:#FFF;outline:0}.el-button--info.is-plain.is-disabled,.el-button--info.is-plain.is-disabled:active,.el-button--info.is-plain.is-disabled:focus,.el-button--info.is-plain.is-disabled:hover{color:#bcbec2;background-color:#f4f4f5;border-color:#e9e9eb}.el-button--medium{padding:10px 20px;font-size:14px;border-radius:4px}.el-button--medium.is-round{padding:10px 20px}.el-button--medium.is-circle{padding:10px}.el-button--small{padding:9px 15px;font-size:12px;border-radius:3px}.el-button--small.is-round{padding:9px 15px}.el-button--small.is-circle{padding:9px}.el-button--mini,.el-button--mini.is-round{padding:7px 15px}.el-button--mini{font-size:12px;border-radius:3px}.el-button--mini.is-circle{padding:7px}.el-button--text{border-color:transparent;color:#409EFF;background:0 0;padding-left:0;padding-right:0}.el-button--text:focus,.el-button--text:hover{color:#66b1ff;border-color:transparent;background-color:transparent}.el-button--text:active{color:#3a8ee6;border-color:transparent;background-color:transparent}.el-button--text.is-disabled,.el-button--text.is-disabled:focus,.el-button--text.is-disabled:hover{border-color:transparent}.el-button-group .el-button--danger:last-child,.el-button-group .el-button--danger:not(:first-child):not(:last-child),.el-button-group .el-button--info:last-child,.el-button-group .el-button--info:not(:first-child):not(:last-child),.el-button-group .el-button--primary:last-child,.el-button-group .el-button--primary:not(:first-child):not(:last-child),.el-button-group .el-button--success:last-child,.el-button-group .el-button--success:not(:first-child):not(:last-child),.el-button-group .el-button--warning:last-child,.el-button-group .el-button--warning:not(:first-child):not(:last-child),.el-button-group>.el-dropdown>.el-button{border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--danger:first-child,.el-button-group .el-button--danger:not(:first-child):not(:last-child),.el-button-group .el-button--info:first-child,.el-button-group .el-button--info:not(:first-child):not(:last-child),.el-button-group .el-button--primary:first-child,.el-button-group .el-button--primary:not(:first-child):not(:last-child),.el-button-group .el-button--success:first-child,.el-button-group .el-button--success:not(:first-child):not(:last-child),.el-button-group .el-button--warning:first-child,.el-button-group .el-button--warning:not(:first-child):not(:last-child){border-right-color:rgba(255,255,255,.5)}.el-button-group{display:inline-block;vertical-align:middle}.el-button-group::after,.el-button-group::before{display:table}.el-button-group::after{clear:both}.el-button-group>.el-button{float:left;position:relative}.el-button-group>.el-button.is-disabled{z-index:1}.el-button-group>.el-button:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.el-button-group>.el-button:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.el-button-group>.el-button:first-child:last-child{border-radius:4px}.el-button-group>.el-button:first-child:last-child.is-round{border-radius:20px}.el-button-group>.el-button:first-child:last-child.is-circle{border-radius:50%}.el-button-group>.el-button:not(:first-child):not(:last-child){border-radius:0}.el-button-group>.el-button.is-active,.el-button-group>.el-button:not(.is-disabled):active,.el-button-group>.el-button:not(.is-disabled):focus,.el-button-group>.el-button:not(.is-disabled):hover{z-index:1}.el-button-group>.el-dropdown>.el-button{border-top-left-radius:0;border-bottom-left-radius:0}.el-calendar{background-color:#fff}.el-calendar__header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding:12px 20px;border-bottom:1px solid #EBEEF5}.el-backtop,.el-page-header{display:-webkit-box;display:-ms-flexbox}.el-calendar__title{color:#000;-ms-flex-item-align:center;align-self:center}.el-calendar__body{padding:12px 20px 35px}.el-calendar-table{table-layout:fixed;width:100%}.el-calendar-table thead th{padding:12px 0;color:#606266;font-weight:400}.el-calendar-table:not(.is-range) td.next,.el-calendar-table:not(.is-range) td.prev{color:#C0C4CC}.el-backtop,.el-calendar-table td.is-today{color:#409EFF}.el-calendar-table td{border-bottom:1px solid #EBEEF5;border-right:1px solid #EBEEF5;vertical-align:top;-webkit-transition:background-color .2s ease;transition:background-color .2s ease}.el-calendar-table td.is-selected{background-color:#F2F8FE}.el-calendar-table tr:first-child td{border-top:1px solid #EBEEF5}.el-calendar-table tr td:first-child{border-left:1px solid #EBEEF5}.el-calendar-table tr.el-calendar-table__row--hide-border td{border-top:none}.el-calendar-table .el-calendar-day{-webkit-box-sizing:border-box;box-sizing:border-box;padding:8px;height:85px}.el-calendar-table .el-calendar-day:hover{cursor:pointer;background-color:#F2F8FE}.el-backtop{position:fixed;background-color:#FFF;width:40px;height:40px;border-radius:50%;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;font-size:20px;-webkit-box-shadow:0 0 6px rgba(0,0,0,.12);box-shadow:0 0 6px rgba(0,0,0,.12);cursor:pointer;z-index:5}.el-backtop:hover{background-color:#F2F6FC}.el-page-header{display:flex;line-height:24px}.el-page-header__left{display:-webkit-box;display:-ms-flexbox;display:flex;cursor:pointer;margin-right:40px;position:relative}.el-page-header__left::after{position:absolute;width:1px;height:16px;right:-20px;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);background-color:#DCDFE6}.el-checkbox,.el-checkbox__input{display:inline-block;position:relative;white-space:nowrap}.el-page-header__left .el-icon-back{font-size:18px;margin-right:6px;-ms-flex-item-align:center;align-self:center}.el-page-header__title{font-size:14px;font-weight:500}.el-page-header__content{font-size:18px;color:#303133}.el-checkbox{color:#606266;font-weight:500;font-size:14px;cursor:pointer;user-select:none;margin-right:30px}.el-checkbox.is-bordered{padding:9px 20px 9px 10px;border-radius:4px;border:1px solid #DCDFE6;-webkit-box-sizing:border-box;box-sizing:border-box;line-height:normal;height:40px}.el-checkbox.is-bordered.is-checked{border-color:#409EFF}.el-checkbox.is-bordered.is-disabled{border-color:#EBEEF5;cursor:not-allowed}.el-checkbox.is-bordered.el-checkbox--medium{padding:7px 20px 7px 10px;border-radius:4px;height:36px}.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__label{line-height:17px;font-size:14px}.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__inner{height:14px;width:14px}.el-checkbox.is-bordered.el-checkbox--small{padding:5px 15px 5px 10px;border-radius:3px;height:32px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__label{line-height:15px;font-size:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner::after{height:6px;width:2px}.el-checkbox.is-bordered.el-checkbox--mini{padding:3px 15px 3px 10px;border-radius:3px;height:28px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__label{line-height:12px;font-size:12px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner::after{height:6px;width:2px}.el-checkbox__input{cursor:pointer;outline:0;line-height:1;vertical-align:middle}.el-checkbox__input.is-disabled .el-checkbox__inner{background-color:#edf2fc;border-color:#DCDFE6;cursor:not-allowed}.el-checkbox__input.is-disabled .el-checkbox__inner::after{cursor:not-allowed;border-color:#C0C4CC}.el-checkbox__input.is-disabled .el-checkbox__inner+.el-checkbox__label{cursor:not-allowed}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner{background-color:#F2F6FC;border-color:#DCDFE6}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner::after{border-color:#C0C4CC}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner{background-color:#F2F6FC;border-color:#DCDFE6}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner::before{background-color:#C0C4CC;border-color:#C0C4CC}.el-checkbox__input.is-checked .el-checkbox__inner,.el-checkbox__input.is-indeterminate .el-checkbox__inner{background-color:#409EFF;border-color:#409EFF}.el-checkbox__input.is-disabled+span.el-checkbox__label{color:#C0C4CC;cursor:not-allowed}.el-checkbox__input.is-checked .el-checkbox__inner::after{-webkit-transform:rotate(45deg) scaleY(1);transform:rotate(45deg) scaleY(1)}.el-checkbox__input.is-checked+.el-checkbox__label{color:#409EFF}.el-checkbox__input.is-focus .el-checkbox__inner{border-color:#409EFF}.el-checkbox__input.is-indeterminate .el-checkbox__inner::before{content:'';position:absolute;display:block;background-color:#FFF;height:2px;-webkit-transform:scale(.5);transform:scale(.5);left:0;right:0;top:5px}.el-checkbox__input.is-indeterminate .el-checkbox__inner::after{display:none}.el-checkbox__inner{display:inline-block;position:relative;border:1px solid #DCDFE6;border-radius:2px;-webkit-box-sizing:border-box;box-sizing:border-box;width:14px;height:14px;background-color:#FFF;z-index:1;-webkit-transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46);transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46)}.el-checkbox__inner:hover{border-color:#409EFF}.el-checkbox__inner::after{-webkit-box-sizing:content-box;box-sizing:content-box;content:"";border:1px solid #FFF;border-left:0;border-top:0;height:7px;left:4px;position:absolute;top:1px;-webkit-transform:rotate(45deg) scaleY(0);transform:rotate(45deg) scaleY(0);width:3px;-webkit-transition:-webkit-transform .15s ease-in .05s;transition:-webkit-transform .15s ease-in .05s;transition:transform .15s ease-in .05s;transition:transform .15s ease-in .05s,-webkit-transform .15s ease-in .05s;-webkit-transform-origin:center;transform-origin:center}.el-checkbox__original{opacity:0;outline:0;position:absolute;margin:0;width:0;height:0;z-index:-1}.el-checkbox-button,.el-checkbox-button__inner{display:inline-block;position:relative}.el-checkbox__label{display:inline-block;padding-left:10px;line-height:19px;font-size:14px}.el-checkbox:last-of-type{margin-right:0}.el-checkbox-button__inner{line-height:1;font-weight:500;white-space:nowrap;vertical-align:middle;cursor:pointer;background:#FFF;border:1px solid #DCDFE6;border-left:0;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);padding:12px 20px;font-size:14px;border-radius:0}.el-checkbox-button__inner.is-round{padding:12px 20px}.el-checkbox-button__inner:hover{color:#409EFF}.el-checkbox-button__inner [class*=el-icon-]{line-height:.9}.el-checkbox-button__inner [class*=el-icon-]+span{margin-left:5px}.el-checkbox-button__original{opacity:0;outline:0;position:absolute;margin:0;z-index:-1}.el-radio,.el-radio__inner,.el-radio__input{position:relative;display:inline-block}.el-checkbox-button.is-checked .el-checkbox-button__inner{color:#FFF;background-color:#409EFF;border-color:#409EFF;-webkit-box-shadow:-1px 0 0 0 #8cc5ff;box-shadow:-1px 0 0 0 #8cc5ff}.el-checkbox-button.is-checked:first-child .el-checkbox-button__inner{border-left-color:#409EFF}.el-checkbox-button.is-disabled .el-checkbox-button__inner{color:#C0C4CC;cursor:not-allowed;background-image:none;background-color:#FFF;border-color:#EBEEF5;-webkit-box-shadow:none;box-shadow:none}.el-checkbox-button.is-disabled:first-child .el-checkbox-button__inner{border-left-color:#EBEEF5}.el-checkbox-button:first-child .el-checkbox-button__inner{border-left:1px solid #DCDFE6;border-radius:4px 0 0 4px;-webkit-box-shadow:none!important;box-shadow:none!important}.el-checkbox-button.is-focus .el-checkbox-button__inner{border-color:#409EFF}.el-checkbox-button:last-child .el-checkbox-button__inner{border-radius:0 4px 4px 0}.el-checkbox-button--medium .el-checkbox-button__inner{padding:10px 20px;font-size:14px;border-radius:0}.el-checkbox-button--medium .el-checkbox-button__inner.is-round{padding:10px 20px}.el-checkbox-button--small .el-checkbox-button__inner{padding:9px 15px;font-size:12px;border-radius:0}.el-checkbox-button--small .el-checkbox-button__inner.is-round{padding:9px 15px}.el-checkbox-button--mini .el-checkbox-button__inner{padding:7px 15px;font-size:12px;border-radius:0}.el-checkbox-button--mini .el-checkbox-button__inner.is-round{padding:7px 15px}.el-checkbox-group{font-size:0}.el-avatar,.el-cascader-panel,.el-radio,.el-radio--medium.is-bordered .el-radio__label,.el-radio__label{font-size:14px}.el-radio{color:#606266;font-weight:500;line-height:1;cursor:pointer;white-space:nowrap;outline:0;margin-right:30px}.el-cascader-node>.el-radio,.el-radio:last-child{margin-right:0}.el-radio.is-bordered{padding:12px 20px 0 10px;border-radius:4px;border:1px solid #DCDFE6;-webkit-box-sizing:border-box;box-sizing:border-box;height:40px}.el-cascader-menu,.el-cascader-menu__list,.el-radio__inner{-webkit-box-sizing:border-box}.el-radio.is-bordered.is-checked{border-color:#409EFF}.el-radio.is-bordered.is-disabled{cursor:not-allowed;border-color:#EBEEF5}.el-radio__input.is-disabled .el-radio__inner,.el-radio__input.is-disabled.is-checked .el-radio__inner{background-color:#F5F7FA;border-color:#E4E7ED}.el-radio.is-bordered+.el-radio.is-bordered{margin-left:10px}.el-radio--medium.is-bordered{padding:10px 20px 0 10px;border-radius:4px;height:36px}.el-radio--mini.is-bordered .el-radio__label,.el-radio--small.is-bordered .el-radio__label{font-size:12px}.el-radio--medium.is-bordered .el-radio__inner{height:14px;width:14px}.el-radio--small.is-bordered{padding:8px 15px 0 10px;border-radius:3px;height:32px}.el-radio--small.is-bordered .el-radio__inner{height:12px;width:12px}.el-radio--mini.is-bordered{padding:6px 15px 0 10px;border-radius:3px;height:28px}.el-radio--mini.is-bordered .el-radio__inner{height:12px;width:12px}.el-radio__input{white-space:nowrap;cursor:pointer;outline:0;line-height:1;vertical-align:middle}.el-radio__input.is-disabled .el-radio__inner{cursor:not-allowed}.el-radio__input.is-disabled .el-radio__inner::after{cursor:not-allowed;background-color:#F5F7FA}.el-radio__input.is-disabled .el-radio__inner+.el-radio__label{cursor:not-allowed}.el-radio__input.is-disabled.is-checked .el-radio__inner::after{background-color:#C0C4CC}.el-radio__input.is-disabled+span.el-radio__label{color:#C0C4CC;cursor:not-allowed}.el-radio__input.is-checked .el-radio__inner{border-color:#409EFF;background:#409EFF}.el-radio__input.is-checked .el-radio__inner::after{-webkit-transform:translate(-50%,-50%) scale(1);transform:translate(-50%,-50%) scale(1)}.el-radio__input.is-checked+.el-radio__label{color:#409EFF}.el-radio__input.is-focus .el-radio__inner{border-color:#409EFF}.el-radio__inner{border:1px solid #DCDFE6;border-radius:100%;width:14px;height:14px;background-color:#FFF;cursor:pointer;box-sizing:border-box}.el-radio__inner:hover{border-color:#409EFF}.el-radio__inner::after{width:4px;height:4px;border-radius:100%;background-color:#FFF;content:"";position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%) scale(0);transform:translate(-50%,-50%) scale(0);-webkit-transition:-webkit-transform .15s ease-in;transition:-webkit-transform .15s ease-in;transition:transform .15s ease-in;transition:transform .15s ease-in,-webkit-transform .15s ease-in}.el-radio__original{opacity:0;outline:0;position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;margin:0}.el-radio:focus:not(.is-focus):not(:active):not(.is-disabled) .el-radio__inner{-webkit-box-shadow:0 0 2px 2px #409EFF;box-shadow:0 0 2px 2px #409EFF}.el-radio__label{padding-left:10px}.el-scrollbar{overflow:hidden;position:relative}.el-scrollbar:active>.el-scrollbar__bar,.el-scrollbar:focus>.el-scrollbar__bar,.el-scrollbar:hover>.el-scrollbar__bar{opacity:1;-webkit-transition:opacity 340ms ease-out;transition:opacity 340ms ease-out}.el-scrollbar__wrap{overflow:scroll;height:100%}.el-scrollbar__wrap--hidden-default{scrollbar-width:none}.el-scrollbar__wrap--hidden-default::-webkit-scrollbar{width:0;height:0}.el-scrollbar__thumb{position:relative;display:block;width:0;height:0;cursor:pointer;border-radius:inherit;background-color:rgba(144,147,153,.3);-webkit-transition:.3s background-color;transition:.3s background-color}.el-scrollbar__thumb:hover{background-color:rgba(144,147,153,.5)}.el-scrollbar__bar{position:absolute;right:2px;bottom:2px;z-index:1;border-radius:4px;opacity:0;-webkit-transition:opacity 120ms ease-out;transition:opacity 120ms ease-out}.el-scrollbar__bar.is-vertical{width:6px;top:2px}.el-scrollbar__bar.is-vertical>div{width:100%}.el-scrollbar__bar.is-horizontal{height:6px;left:2px}.el-scrollbar__bar.is-horizontal>div{height:100%}.el-cascader-panel{display:-webkit-box;display:-ms-flexbox;display:flex;border-radius:4px}.el-cascader-panel.is-bordered{border:1px solid #E4E7ED;border-radius:4px}.el-cascader-menu{min-width:180px;box-sizing:border-box;color:#606266;border-right:solid 1px #E4E7ED}.el-cascader-menu:last-child{border-right:none}.el-cascader-menu__wrap{height:204px}.el-cascader-menu__list{position:relative;min-height:100%;margin:0;padding:6px 0;list-style:none;box-sizing:border-box}.el-cascader-menu__hover-zone{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.el-cascader-menu__empty-text{position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);text-align:center;color:#C0C4CC}.el-cascader-node{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:0 30px 0 20px;height:34px;line-height:34px;outline:0}.el-cascader-node.is-selectable.in-active-path{color:#606266}.el-cascader-node.in-active-path,.el-cascader-node.is-active,.el-cascader-node.is-selectable.in-checked-path{color:#409EFF;font-weight:700}.el-cascader-node:not(.is-disabled){cursor:pointer}.el-cascader-node:not(.is-disabled):focus,.el-cascader-node:not(.is-disabled):hover{background:#F5F7FA}.el-cascader-node.is-disabled{color:#C0C4CC;cursor:not-allowed}.el-cascader-node__prefix{position:absolute;left:10px}.el-cascader-node__postfix{position:absolute;right:10px}.el-cascader-node__label{-webkit-box-flex:1;-ms-flex:1;flex:1;padding:0 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.el-cascader-node>.el-radio .el-radio__label{padding-left:0}.el-avatar{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;text-align:center;overflow:hidden;color:#fff;background:#C0C4CC;width:40px;height:40px;line-height:40px}.el-drawer,.el-drawer__body>*{-webkit-box-sizing:border-box}.el-avatar>img{display:block;height:100%;vertical-align:middle}.el-empty__image img,.el-empty__image svg{vertical-align:top;height:100%;width:100%}.el-avatar--circle{border-radius:50%}.el-avatar--square{border-radius:4px}.el-avatar--icon{font-size:18px}.el-avatar--large{width:40px;height:40px;line-height:40px}.el-avatar--medium{width:36px;height:36px;line-height:36px}.el-avatar--small{width:28px;height:28px;line-height:28px}@-webkit-keyframes el-drawer-fade-in{0%{opacity:0}100%{opacity:1}}@keyframes el-drawer-fade-in{0%{opacity:0}100%{opacity:1}}@-webkit-keyframes rtl-drawer-in{0%{-webkit-transform:translate(100%,0);transform:translate(100%,0)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes rtl-drawer-in{0%{-webkit-transform:translate(100%,0);transform:translate(100%,0)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@-webkit-keyframes rtl-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(100%,0);transform:translate(100%,0)}}@keyframes rtl-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(100%,0);transform:translate(100%,0)}}@-webkit-keyframes ltr-drawer-in{0%{-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes ltr-drawer-in{0%{-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@-webkit-keyframes ltr-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}}@keyframes ltr-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}}@-webkit-keyframes ttb-drawer-in{0%{-webkit-transform:translate(0,-100%);transform:translate(0,-100%)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes ttb-drawer-in{0%{-webkit-transform:translate(0,-100%);transform:translate(0,-100%)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@-webkit-keyframes ttb-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(0,-100%);transform:translate(0,-100%)}}@keyframes ttb-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(0,-100%);transform:translate(0,-100%)}}@-webkit-keyframes btt-drawer-in{0%{-webkit-transform:translate(0,100%);transform:translate(0,100%)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes btt-drawer-in{0%{-webkit-transform:translate(0,100%);transform:translate(0,100%)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@-webkit-keyframes btt-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(0,100%);transform:translate(0,100%)}}@keyframes btt-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(0,100%);transform:translate(0,100%)}}.el-drawer{position:absolute;box-sizing:border-box;background-color:#FFF;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-webkit-box-shadow:0 8px 10px -5px rgba(0,0,0,.2),0 16px 24px 2px rgba(0,0,0,.14),0 6px 30px 5px rgba(0,0,0,.12);box-shadow:0 8px 10px -5px rgba(0,0,0,.2),0 16px 24px 2px rgba(0,0,0,.14),0 6px 30px 5px rgba(0,0,0,.12);overflow:hidden;outline:0}.el-drawer.rtl{-webkit-animation:rtl-drawer-out .3s;animation:rtl-drawer-out .3s;right:0}.el-drawer__open .el-drawer.rtl{-webkit-animation:rtl-drawer-in .3s 1ms;animation:rtl-drawer-in .3s 1ms}.el-drawer.ltr{-webkit-animation:ltr-drawer-out .3s;animation:ltr-drawer-out .3s;left:0}.el-drawer__open .el-drawer.ltr{-webkit-animation:ltr-drawer-in .3s 1ms;animation:ltr-drawer-in .3s 1ms}.el-drawer.ttb{-webkit-animation:ttb-drawer-out .3s;animation:ttb-drawer-out .3s;top:0}.el-drawer__open .el-drawer.ttb{-webkit-animation:ttb-drawer-in .3s 1ms;animation:ttb-drawer-in .3s 1ms}.el-drawer.btt{-webkit-animation:btt-drawer-out .3s;animation:btt-drawer-out .3s;bottom:0}.el-drawer__open .el-drawer.btt{-webkit-animation:btt-drawer-in .3s 1ms;animation:btt-drawer-in .3s 1ms}.el-drawer__wrapper{position:fixed;top:0;right:0;bottom:0;left:0;overflow:hidden;margin:0}.el-drawer__header{-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#72767b;display:-webkit-box;display:-ms-flexbox;display:flex;margin-bottom:32px;padding:20px 20px 0}.el-drawer__header>:first-child{-webkit-box-flex:1;-ms-flex:1;flex:1}.el-drawer__title{margin:0;-webkit-box-flex:1;-ms-flex:1;flex:1;line-height:inherit;font-size:1rem}.el-drawer__close-btn{border:none;cursor:pointer;font-size:20px;color:inherit;background-color:transparent}.el-drawer__body{-webkit-box-flex:1;-ms-flex:1;flex:1;overflow:auto}.el-drawer__body>*{box-sizing:border-box}.el-drawer.ltr,.el-drawer.rtl{height:100%;top:0;bottom:0}.el-drawer.btt,.el-drawer.ttb{width:100%;left:0;right:0}.el-drawer__container{position:relative;left:0;right:0;top:0;bottom:0;height:100%;width:100%}.el-drawer-fade-enter-active{-webkit-animation:el-drawer-fade-in .3s;animation:el-drawer-fade-in .3s}.el-drawer-fade-leave-active{animation:el-drawer-fade-in .3s reverse}.el-statistic{width:100%;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:0;color:#000;font-variant:tabular-nums;list-style:none;-webkit-font-feature-settings:"tnum";font-feature-settings:"tnum";text-align:center}.el-statistic .head{margin-bottom:4px;color:#606266;font-size:13px}.el-statistic .con{font-family:Sans-serif;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#303133}.el-statistic .con .number{font-size:20px;padding:0 4px}.el-statistic .con span{display:inline-block;margin:0;line-height:100%}.el-popconfirm__main,.el-skeleton__image{display:-ms-flexbox;-webkit-box-align:center;display:-webkit-box}.el-popconfirm__main{display:flex;-ms-flex-align:center;align-items:center}.el-popconfirm__icon{margin-right:5px}.el-popconfirm__action{text-align:right;margin:0}@-webkit-keyframes el-skeleton-loading{0%{background-position:100% 50%}100%{background-position:0 50%}}@keyframes el-skeleton-loading{0%{background-position:100% 50%}100%{background-position:0 50%}}.el-skeleton{width:100%}.el-skeleton__first-line,.el-skeleton__paragraph{height:16px;margin-top:16px;background:#f2f2f2}.el-skeleton.is-animated .el-skeleton__item{background:-webkit-gradient(linear,left top,right top,color-stop(25%,#f2f2f2),color-stop(37%,#e6e6e6),color-stop(63%,#f2f2f2));background:linear-gradient(90deg,#f2f2f2 25%,#e6e6e6 37%,#f2f2f2 63%);background-size:400% 100%;-webkit-animation:el-skeleton-loading 1.4s ease infinite;animation:el-skeleton-loading 1.4s ease infinite}.el-skeleton__item{background:#f2f2f2;display:inline-block;height:16px;border-radius:4px;width:100%}.el-skeleton__circle{border-radius:50%;width:36px;height:36px;line-height:36px}.el-skeleton__circle--lg{width:40px;height:40px;line-height:40px}.el-skeleton__circle--md{width:28px;height:28px;line-height:28px}.el-skeleton__button{height:40px;width:64px;border-radius:4px}.el-skeleton__p{width:100%}.el-skeleton__p.is-last{width:61%}.el-skeleton__p.is-first{width:33%}.el-skeleton__text{width:100%;height:13px}.el-skeleton__caption{height:12px}.el-skeleton__h1{height:20px}.el-skeleton__h3{height:18px}.el-skeleton__h5{height:16px}.el-skeleton__image{width:unset;display:flex;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;border-radius:0}.el-skeleton__image svg{fill:#DCDDE0;width:22%;height:22%}.el-empty{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-direction:column;flex-direction:column;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;padding:40px 0}.el-empty__image{width:160px}.el-empty__image img{user-select:none;-o-object-fit:contain;object-fit:contain}.el-empty__image svg{fill:#DCDDE0}.el-empty__description{margin-top:20px}.el-empty__description p{margin:0;font-size:14px;color:#909399}.el-empty__bottom,.el-result__title{margin-top:20px}.el-descriptions{-webkit-box-sizing:border-box;box-sizing:border-box;font-size:14px;color:#303133}.el-descriptions__header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin-bottom:20px}.el-descriptions__title{font-size:16px;font-weight:700}.el-descriptions--mini,.el-descriptions--small{font-size:12px}.el-descriptions__body{color:#606266;background-color:#FFF}.el-descriptions__body .el-descriptions__table{border-collapse:collapse;width:100%;table-layout:fixed}.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell{-webkit-box-sizing:border-box;box-sizing:border-box;text-align:left;font-weight:400;line-height:1.5}.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell.is-left{text-align:left}.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell.is-center{text-align:center}.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell.is-right{text-align:right}.el-descriptions .is-bordered{table-layout:auto}.el-descriptions .is-bordered .el-descriptions-item__cell{border:1px solid #EBEEF5;padding:12px 10px}.el-descriptions :not(.is-bordered) .el-descriptions-item__cell{padding-bottom:12px}.el-descriptions--medium.is-bordered .el-descriptions-item__cell{padding:10px}.el-descriptions--medium:not(.is-bordered) .el-descriptions-item__cell{padding-bottom:10px}.el-descriptions--small.is-bordered .el-descriptions-item__cell{padding:8px 10px}.el-descriptions--small:not(.is-bordered) .el-descriptions-item__cell{padding-bottom:8px}.el-descriptions--mini.is-bordered .el-descriptions-item__cell{padding:6px 10px}.el-descriptions--mini:not(.is-bordered) .el-descriptions-item__cell{padding-bottom:6px}.el-descriptions-item{vertical-align:top}.el-descriptions-item__container{display:-webkit-box;display:-ms-flexbox;display:flex}.el-descriptions-item__container .el-descriptions-item__content,.el-descriptions-item__container .el-descriptions-item__label{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline}.el-descriptions-item__container .el-descriptions-item__content{-webkit-box-flex:1;-ms-flex:1;flex:1}.el-descriptions-item__label.has-colon::after{content:':';position:relative;top:-.5px}.el-descriptions-item__label.is-bordered-label{font-weight:700;color:#909399;background:#fafafa}.el-descriptions-item__label:not(.is-bordered-label){margin-right:10px}.el-descriptions-item__content{word-break:break-word;overflow-wrap:break-word}.el-result{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-direction:column;flex-direction:column;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;padding:40px 30px}.el-result__icon svg{width:64px;height:64px}.el-result__title p{margin:0;font-size:20px;color:#303133;line-height:1.3}.el-result__subtitle{margin-top:10px}.el-result__subtitle p{margin:0;font-size:14px;color:#606266;line-height:1.3}.el-result__extra{margin-top:30px }.el-result .icon-success{fill:#67C23A}.el-result .icon-error{fill:#F56C6C}.el-result .icon-info{fill:#909399}.el-result .icon-warning{fill:#E6A23C} \ No newline at end of file diff --git a/frontend/src/App.vue b/frontend/src/App.vue deleted file mode 100644 index 9e13b7407..000000000 --- a/frontend/src/App.vue +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/frontend/src/api/classHour/hourStat.js b/frontend/src/api/classHour/hourStat.js deleted file mode 100644 index 3075223c1..000000000 --- a/frontend/src/api/classHour/hourStat.js +++ /dev/null @@ -1,42 +0,0 @@ -import request from '@/utils/request' - -// ======================== 课时补助核算:课时统计 / 课时费统计 ======================== -// 接口前缀 /ks,经 vue.config.js 代理转发为 /api/ks;返回行为 HourStatisticsVO。 - -// 分页查询课时统计(支持 nd 年度、xq 学期序号、jyxm 教员姓名) -export function listHourStatistics(query) { - return request({ - url: '/ks/hour-stat/list', - method: 'get', - params: query - }) -} - -// 导出课时统计 Excel(返回 Blob,文件名 课时统计.xlsx) -export function exportHourStatistics(query) { - return request({ - url: '/ks/hour-stat/export', - method: 'get', - params: query, - responseType: 'blob' - }) -} - -// 分页查询课时费统计(支持 nd、xq、jyxm、ksfbzbh 课时费标准编号) -export function listFeeStatistics(query) { - return request({ - url: '/ks/fee-stat/list', - method: 'get', - params: query - }) -} - -// 导出课时费统计 Excel(返回 Blob,文件名 课时费统计.xlsx) -export function exportFeeStatistics(query) { - return request({ - url: '/ks/fee-stat/export', - method: 'get', - params: query, - responseType: 'blob' - }) -} diff --git a/frontend/src/api/classHour/jointTraining.js b/frontend/src/api/classHour/jointTraining.js deleted file mode 100644 index 2422e153f..000000000 --- a/frontend/src/api/classHour/jointTraining.js +++ /dev/null @@ -1,69 +0,0 @@ -import request from '@/utils/request' - -// ======================== 联教联训管理(课时补助项目) ======================== -// 接口前缀 /ks,经 vue.config.js 代理转发为 /api/ks;后端实体为 KSBZXM。 - -// 新增联教联训(编号为空时后端自动生成 UUID) -export function addJointTraining(data) { - return request({ - url: '/ks/yjlx/add', - method: 'post', - data: data - }) -} - -// 删除联教联训 -export function deleteJointTraining(bh) { - return request({ - url: '/ks/yjlx/delete', - method: 'post', - params: { bh: bh } - }) -} - -// 修改联教联训 -export function updateJointTraining(data) { - return request({ - url: '/ks/yjlx/update', - method: 'post', - data: data - }) -} - -// 按编号查询联教联训详情 -export function getJointTraining(bh) { - return request({ - url: '/ks/yjlx/get', - method: 'get', - params: { bh: bh } - }) -} - -// 分页查询联教联训列表(支持名称模糊) -export function listJointTraining(query) { - return request({ - url: '/ks/yjlx/list', - method: 'get', - params: query - }) -} - -// 导入联教联训 Excel(multipart,字段名 file) -export function importJointTraining(file) { - const formData = new FormData() - formData.append('file', file) - return request({ - url: '/ks/yjlx/import', - method: 'post', - data: formData - }) -} - -// 导出联教联训到 Excel(返回 Blob) -export function exportJointTraining() { - return request({ - url: '/ks/yjlx/export', - method: 'get', - responseType: 'blob' - }) -} diff --git a/frontend/src/api/classHour/plan.js b/frontend/src/api/classHour/plan.js deleted file mode 100644 index d00363322..000000000 --- a/frontend/src/api/classHour/plan.js +++ /dev/null @@ -1,87 +0,0 @@ -import request from '@/utils/request' - -// ======================== 方案管理:课时费方案 / 课时方案 ======================== -// 接口前缀 /ks,经 vue.config.js 代理转发为 /api/ks。 - -// ---------- 课时费方案(KSFBZ) ---------- -// 分页列表(名称模糊) -export function listFeeStandard(query) { - return request({ - url: '/ks/fee-standard/list', - method: 'get', - params: query - }) -} - -// 详情 -export function getFeeStandard(bh) { - return request({ - url: '/ks/fee-standard/get', - method: 'get', - params: { bh: bh } - }) -} - -// 新增(编号为空时后端自动生成 UUID) -export function addFeeStandard(data) { - return request({ - url: '/ks/fee-standard/add', - method: 'post', - data: data - }) -} - -// 编辑(编号必传) -export function updateFeeStandard(data) { - return request({ - url: '/ks/fee-standard/update', - method: 'post', - data: data - }) -} - -// 删除 -export function deleteFeeStandard(bh) { - return request({ - url: '/ks/fee-standard/delete', - method: 'post', - params: { bh: bh } - }) -} - -// ---------- 课时方案(KSXSFA) ---------- -// 分页列表(名称模糊) -export function listCoefficientPlan(query) { - return request({ - url: '/ks/coefficient-plan/list', - method: 'get', - params: query - }) -} - -// 详情 -export function getCoefficientPlan(bh) { - return request({ - url: '/ks/coefficient-plan/get', - method: 'get', - params: { bh: bh } - }) -} - -// 新增(编号为空时后端自动生成 UUID) -export function addCoefficientPlan(data) { - return request({ - url: '/ks/coefficient-plan/add', - method: 'post', - data: data - }) -} - -// 编辑(编号必传) -export function updateCoefficientPlan(data) { - return request({ - url: '/ks/coefficient-plan/update', - method: 'post', - data: data - }) -} diff --git a/frontend/src/api/log.js b/frontend/src/api/log.js deleted file mode 100644 index c3114b47e..000000000 --- a/frontend/src/api/log.js +++ /dev/null @@ -1,125 +0,0 @@ -import request from '@/utils/request' - -// ======================== 教学日志核心(以 api.txt 为准) ======================== -// 接口前缀 /log,经 vue.config.js 代理转发为 /api/log(axios baseURL 为 /api)。 - -// 分页条件查询教学日志列表(待上报视图) -// 支持参数:pageNum pageSize ksrq jsrq kcmc jys jxff skjy rzzt pxqb gdqk gdxxqk rwlb -export function getTeachingLogList(query) { - return request({ - url: '/log/teaching-log/list', - method: 'get', - params: query - }) -} - -// 分页条件查询已上报的教学日志列表(状态固定为「已上报」) -export function getReportedTeachingLogList(query) { - return request({ - url: '/log/teaching-log/reported/list', - method: 'get', - params: query - }) -} - -// 分页条件查询已审核的教学日志列表(状态固定为「已审核」) -export function getAuditedTeachingLogList(query) { - return request({ - url: '/log/teaching-log/audited/list', - method: 'get', - params: query - }) -} - -// 新增教学日志(请求体为 SSKCB_RZ 实体) -export function addTeachingLog(data) { - return request({ - url: '/log/teaching-log/add', - method: 'post', - data: data - }) -} - -// 编辑教学日志(请求体为 SSKCB_RZ 实体,bh 必传) -export function updateTeachingLog(data) { - return request({ - url: '/log/teaching-log/update', - method: 'post', - data: data - }) -} - -// 根据编号查询教学日志详情 -export function getTeachingLogByBh(bh) { - return request({ - url: '/log/teaching-log/get', - method: 'get', - params: { bh: bh } - }) -} - -// 提交教学日志审核,接口形态:POST /log/teaching-log/submit?bh=&targetStatus= -export function submitTeachingLog(bh, targetStatus) { - return request({ - url: '/log/teaching-log/submit', - method: 'post', - params: { bh: bh, targetStatus: targetStatus } - }) -} - -// 审核通过教学日志,接口形态:GET /log/teaching-log/approve?bh=&feedback= -export function approveTeachingLog(bh, feedback) { - return request({ - url: '/log/teaching-log/approve', - method: 'get', - params: { bh: bh, feedback: feedback } - }) -} - -// 退回教学日志(撤回重填),接口形态:POST /log/teaching-log/reject?bh=&thyj= -export function rejectTeachingLog(bh, thyj) { - return request({ - url: '/log/teaching-log/reject', - method: 'post', - params: { bh: bh, thyj: thyj } - }) -} - -// 根据课表自动创建教学日志,接口形态:POST /log/teaching-log/auto-create?tybh= -export function autoCreateTeachingLog(tybh) { - return request({ - url: '/log/teaching-log/auto-create', - method: 'post', - params: { tybh: tybh } - }) -} - -// 批量导入教学日志 Excel,接口形态:POST /log/teaching-log/import-excel(multipart,字段名 file) -export function importTeachingLogExcel(file) { - const formData = new FormData() - formData.append('file', file) - return request({ - url: '/log/teaching-log/import-excel', - method: 'post', - data: formData - }) -} - -// 导出教学日志 Excel(返回 Blob),接口形态:GET /log/teaching-log/export -export function exportTeachingLog(query) { - return request({ - url: '/log/teaching-log/export', - method: 'get', - params: query, - responseType: 'blob' - }) -} - -// 下载导入模板(返回 Blob),接口形态:GET /log/teaching-log/download-template -export function downloadTeachingLogTemplate() { - return request({ - url: '/log/teaching-log/download-template', - method: 'get', - responseType: 'blob' - }) -} diff --git a/frontend/src/api/login.js b/frontend/src/api/login.js deleted file mode 100644 index 0405b25fe..000000000 --- a/frontend/src/api/login.js +++ /dev/null @@ -1,58 +0,0 @@ -import request from '@/utils/request' - -// 登录方法 -export function login(username, password, code, uuid) { - const data = { - username, - password, - code, - uuid - } - return request({ - url: '/login', - headers: { - isToken: false, - repeatSubmit: false - }, - method: 'post', - data: data - }) -} - -// 注册方法 -export function register(data) { - return request({ - url: '/register', - headers: { - isToken: false - }, - method: 'post', - data: data - }) -} - -// 获取用户详细信息 -export function getInfo() { - return request({ - url: '/getInfo', - method: 'get' - }) -} - -// 解锁屏幕 -export function unlockScreen(password) { - return request({ - url: '/unlockscreen', - method: 'post', - data: { password } - }) -} - -// 退出方法 -export function logout() { - return request({ - url: '/logout', - method: 'post' - }) -} - diff --git a/frontend/src/api/menu.js b/frontend/src/api/menu.js deleted file mode 100644 index ee2913594..000000000 --- a/frontend/src/api/menu.js +++ /dev/null @@ -1,9 +0,0 @@ -import request from '@/utils/request' - -// 获取路由 -export const getRouters = () => { - return request({ - url: '/getRouters', - method: 'get' - }) -} \ No newline at end of file diff --git a/frontend/src/api/monitor/cache.js b/frontend/src/api/monitor/cache.js deleted file mode 100644 index 257805c79..000000000 --- a/frontend/src/api/monitor/cache.js +++ /dev/null @@ -1,57 +0,0 @@ -import request from '@/utils/request' - -// 查询缓存详细 -export function getCache() { - return request({ - url: '/monitor/cache', - method: 'get' - }) -} - -// 查询缓存名称列表 -export function listCacheName() { - return request({ - url: '/monitor/cache/getNames', - method: 'get' - }) -} - -// 查询缓存键名列表 -export function listCacheKey(cacheName) { - return request({ - url: '/monitor/cache/getKeys/' + cacheName, - method: 'get' - }) -} - -// 查询缓存内容 -export function getCacheValue(cacheName, cacheKey) { - return request({ - url: '/monitor/cache/getValue/' + cacheName + '/' + cacheKey, - method: 'get' - }) -} - -// 清理指定名称缓存 -export function clearCacheName(cacheName) { - return request({ - url: '/monitor/cache/clearCacheName/' + cacheName, - method: 'delete' - }) -} - -// 清理指定键名缓存 -export function clearCacheKey(cacheKey) { - return request({ - url: '/monitor/cache/clearCacheKey/' + cacheKey, - method: 'delete' - }) -} - -// 清理全部缓存 -export function clearCacheAll() { - return request({ - url: '/monitor/cache/clearCacheAll', - method: 'delete' - }) -} diff --git a/frontend/src/api/monitor/job.js b/frontend/src/api/monitor/job.js deleted file mode 100644 index 82ff2fb50..000000000 --- a/frontend/src/api/monitor/job.js +++ /dev/null @@ -1,71 +0,0 @@ -import request from '@/utils/request' - -// 查询定时任务调度列表 -export function listJob(query) { - return request({ - url: '/monitor/job/list', - method: 'get', - params: query - }) -} - -// 查询定时任务调度详细 -export function getJob(jobId) { - return request({ - url: '/monitor/job/' + jobId, - method: 'get' - }) -} - -// 新增定时任务调度 -export function addJob(data) { - return request({ - url: '/monitor/job', - method: 'post', - data: data - }) -} - -// 修改定时任务调度 -export function updateJob(data) { - return request({ - url: '/monitor/job', - method: 'put', - data: data - }) -} - -// 删除定时任务调度 -export function delJob(jobId) { - return request({ - url: '/monitor/job/' + jobId, - method: 'delete' - }) -} - -// 任务状态修改 -export function changeJobStatus(jobId, status) { - const data = { - jobId, - status - } - return request({ - url: '/monitor/job/changeStatus', - method: 'put', - data: data - }) -} - - -// 定时任务立即执行一次 -export function runJob(jobId, jobGroup) { - const data = { - jobId, - jobGroup - } - return request({ - url: '/monitor/job/run', - method: 'put', - data: data - }) -} \ No newline at end of file diff --git a/frontend/src/api/monitor/jobLog.js b/frontend/src/api/monitor/jobLog.js deleted file mode 100644 index b05fed45d..000000000 --- a/frontend/src/api/monitor/jobLog.js +++ /dev/null @@ -1,26 +0,0 @@ -import request from '@/utils/request' - -// 查询调度日志列表 -export function listJobLog(query) { - return request({ - url: '/monitor/jobLog/list', - method: 'get', - params: query - }) -} - -// 删除调度日志 -export function delJobLog(jobLogId) { - return request({ - url: '/monitor/jobLog/' + jobLogId, - method: 'delete' - }) -} - -// 清空调度日志 -export function cleanJobLog() { - return request({ - url: '/monitor/jobLog/clean', - method: 'delete' - }) -} diff --git a/frontend/src/api/monitor/logininfor.js b/frontend/src/api/monitor/logininfor.js deleted file mode 100644 index e2193196c..000000000 --- a/frontend/src/api/monitor/logininfor.js +++ /dev/null @@ -1,43 +0,0 @@ -import request from '@/utils/request' - -// 查询登录日志列表 -export function list(query) { - return request({ - url: '/monitor/logininfor/list', - method: 'get', - params: query - }) -} - -// 查询首页登录日志列表 -export function homeList(query) { - return request({ - url: '/monitor/logininfor/homeList', - method: 'get', - params: query - }) -} - -// 删除登录日志 -export function delLogininfor(infoId) { - return request({ - url: '/monitor/logininfor/' + infoId, - method: 'delete' - }) -} - -// 解锁用户登录状态 -export function unlockLogininfor(userName) { - return request({ - url: '/monitor/logininfor/unlock/' + userName, - method: 'get' - }) -} - -// 清空登录日志 -export function cleanLogininfor() { - return request({ - url: '/monitor/logininfor/clean', - method: 'delete' - }) -} diff --git a/frontend/src/api/monitor/online.js b/frontend/src/api/monitor/online.js deleted file mode 100644 index 27fd96199..000000000 --- a/frontend/src/api/monitor/online.js +++ /dev/null @@ -1,18 +0,0 @@ -import request from '@/utils/request' - -// 查询在线用户列表 -export function list(query) { - return request({ - url: '/monitor/online/list', - method: 'get', - params: query - }) -} - -// 强退用户 -export function forceLogout(tokenId) { - return request({ - url: '/monitor/online/' + tokenId, - method: 'delete' - }) -} diff --git a/frontend/src/api/monitor/operlog.js b/frontend/src/api/monitor/operlog.js deleted file mode 100644 index fd86768a5..000000000 --- a/frontend/src/api/monitor/operlog.js +++ /dev/null @@ -1,26 +0,0 @@ -import request from '@/utils/request' - -// 查询操作日志列表 -export function list(query) { - return request({ - url: '/monitor/operlog/list', - method: 'get', - params: query - }) -} - -// 删除操作日志 -export function delOperlog(operId) { - return request({ - url: '/monitor/operlog/' + operId, - method: 'delete' - }) -} - -// 清空操作日志 -export function cleanOperlog() { - return request({ - url: '/monitor/operlog/clean', - method: 'delete' - }) -} diff --git a/frontend/src/api/monitor/server.js b/frontend/src/api/monitor/server.js deleted file mode 100644 index 092901696..000000000 --- a/frontend/src/api/monitor/server.js +++ /dev/null @@ -1,9 +0,0 @@ -import request from '@/utils/request' - -// 获取服务信息 -export function getServer() { - return request({ - url: '/monitor/server', - method: 'get' - }) -} \ No newline at end of file diff --git a/frontend/src/api/schedule/teachingPlan.js b/frontend/src/api/schedule/teachingPlan.js deleted file mode 100644 index ca90ff233..000000000 --- a/frontend/src/api/schedule/teachingPlan.js +++ /dev/null @@ -1,34 +0,0 @@ -import request from '@/utils/request' - -// ======================== 教学实施计划导入 ======================== -// 接口前缀 /teachingPlan,经 vue.config.js 代理转发为 /api/teachingPlan。 - -// 分页查询教学实施计划列表 -// 支持参数:pageNum pageSize nd kcmc bc zrdw skjy ytgjc ybdr(与后端 Mapper 一致) -export function listTeachingPlan(query) { - return request({ - url: '/teachingPlan/list', - method: 'get', - params: query - }) -} - -// 导入教学实施计划 Excel(multipart,字段名 file),返回导入条数 -export function importTeachingPlan(file) { - const formData = new FormData() - formData.append('file', file) - return request({ - url: '/teachingPlan/import', - method: 'post', - data: formData - }) -} - -// 下载教学实施计划导入模板(返回 Blob) -export function downloadTeachingPlanTemplate() { - return request({ - url: '/teachingPlan/template', - method: 'get', - responseType: 'blob' - }) -} diff --git a/frontend/src/api/studentRecords/application.js b/frontend/src/api/studentRecords/application.js deleted file mode 100644 index 33e5250dc..000000000 --- a/frontend/src/api/studentRecords/application.js +++ /dev/null @@ -1,49 +0,0 @@ -import request from '@/utils/request' - -// ======================== 学员学籍异动申请(实体 XYXJYDSQB) ======================== -// 列表查询仅支持 bh / xybh / sqlx / zt 四个等值筛选。 - -// 分页查询学籍异动申请列表 -export function listApplication(query) { - return request({ - url: '/student-records/application/list', - method: 'get', - params: query - }) -} - -// 查询学籍异动申请详情(bh 异动申请编号) -export function getApplication(bh) { - return request({ - url: '/student-records/application/get', - method: 'get', - params: { bh: bh } - }) -} - -// 新增学籍异动申请(请求体 XYXJYDSQB 实体;bh 需前端传入,创建/修改时间后端自动维护) -export function addApplication(data) { - return request({ - url: '/student-records/application/add', - method: 'post', - data: data - }) -} - -// 编辑学籍异动申请(bh 异动申请编号必传,请求体 XYXJYDSQB 实体) -export function updateApplication(data) { - return request({ - url: '/student-records/application/update', - method: 'post', - data: data - }) -} - -// 删除学籍异动申请(bh 异动申请编号) -export function delApplication(bh) { - return request({ - url: '/student-records/application/delete', - method: 'post', - params: { bh: bh } - }) -} diff --git a/frontend/src/api/studentRecords/classCalendar.js b/frontend/src/api/studentRecords/classCalendar.js deleted file mode 100644 index 96604c5d4..000000000 --- a/frontend/src/api/studentRecords/classCalendar.js +++ /dev/null @@ -1,105 +0,0 @@ -import request from '@/utils/request' - -// ======================== 班历管理(实体 XYDRWB 学员队任务表) ======================== -// 接口依据:api2.txt「班次学期日历(班历)」分组 + StudentTeamTaskController -// 每个班次学期(xydxqbh)下挂若干条课程任务记录: -// bh 编号、nd 年度、xydbh 学员队编号、kbh 课编号、xqdc 学期第次、jybh 教员编号、kcxh 课次序号、 -// jsbh 教室编号、rs 人数、zks 周课时、xs 学时、klx 课类型、jc 简称、ksdd 考试地点、ksbh 考试编号、 -// jysdh 教研室代号、jysjhjybh 教研室计划教员编号、jysjhbz 教研室计划备注、jhkcxh 计划课次序号、 -// xhbs 序号标识、xydxqbh 学员队学期编号、bz 备注、xf 学分、cjsj/bdsj/kbbdsj 时间、 -// ksks 考试课时、bz2 编组、cjfz 成绩分制、bjrxypjf 不计入学员平均分、llxs 理论学时、sjxs 实践学时、 -// ksksbxs 考试课时不显示、pdxh 配档序号、pdqsz 配档起始周、pdaz 配档按周、pdzzksj 配档占正课时间、 -// pdbz 配档编组、pdtbykxxbz 配当同班异课选修编组、pdzdyxsfbsj 配档自定义学时分布数据、 -// pdqyzdyxs 配档启用自定义学时 - -// 查询某班次学期下的全部班历记录(xydxqbh 学员队学期编号) -export function listClassCalendar(xydxqbh) { - return request({ - url: '/classCalendar/all', - method: 'get', - params: { xydxqbh: xydxqbh } - }) -} - -// 根据主键查询班历记录 -export function getClassCalendar(bh) { - return request({ - url: '/classCalendar/get', - method: 'get', - params: { bh: bh } - }) -} - -// 更新班历记录(请求体 XYDRWB,bh 必传) -export function updateClassCalendar(data) { - return request({ - url: '/classCalendar/update', - method: 'post', - data: data - }) -} - -// 选定区域设置应用于其它班次(请求体 { sourceBhList: 源记录编号, targetBhList: 目标班次学期编号 }) -export function batchCopyCalendar(data) { - return request({ - url: '/classCalendar/batchCopy', - method: 'post', - data: data - }) -} - -// 整个班历应用于其它班次(请求体 { sourceXydxqbh: 源班次学期编号, targetBhList: 目标班次学期编号 }) -export function batchCopyCalendarBySemester(data) { - return request({ - url: '/classCalendar/batchCopyBySemester', - method: 'post', - data: data - }) -} - -// ======================== 学员队任务表操作(/studentTeamTask) ======================== - -// 新增班历记录(请求体 XYDRWB;bh 留空后端生成 UUID) -export function addTeamTask(data) { - return request({ - url: '/studentTeamTask/add', - method: 'post', - data: data - }) -} - -// 删除班历记录(bh 编号) -export function delTeamTask(bh) { - return request({ - url: '/studentTeamTask/delete', - method: 'post', - params: { bh: bh } - }) -} - -// 批量预设合班(请求体 { bhList },按年度排序生成统一课次序号) -export function batchPresetMerge(bhList) { - return request({ - url: '/studentTeamTask/batchPresetMerge', - method: 'post', - data: { bhList: bhList } - }) -} - -// 批量预设拆班(请求体 { bhList },清空课次序号) -export function batchPresetSplit(bhList) { - return request({ - url: '/studentTeamTask/batchPresetSplit', - method: 'post', - data: { bhList: bhList } - }) -} - -// 自动生成必修课程(按学员队+学期第次从专业教学计划生成班历记录) -export function autoGenerateRequiredCourses(xydbh, xqdc) { - return request({ - url: '/studentTeamTask/autoGenerateRequiredCourses', - method: 'post', - params: { xydbh: xydbh, xqdc: xqdc } - }) -} diff --git a/frontend/src/api/studentRecords/semester.js b/frontend/src/api/studentRecords/semester.js deleted file mode 100644 index d60be6e35..000000000 --- a/frontend/src/api/studentRecords/semester.js +++ /dev/null @@ -1,117 +0,0 @@ -import request from '@/utils/request' - -// ======================== 班次学期管理(实体 XYDNDXQJBXXB 学员队年度学期基本信息表) ======================== -// 接口依据:api1.txt「班次学期」分组,实际后端位于 StudentRecordsController (/student-records/semester/*) -// 列表仅支持 xydbh(学员队编号)模糊筛选,无年度筛选,前端需本地过滤 -// 新增 bh 留空由后端生成 UUID;字段 nd 年度、xydbh 学员队编号、kxrq 开学日期、jsrq 结束日期、 -// xqdc 学期第次、zyjsbh 专用教室编号、jxrwbh 教学任务编号、bdsj 变动时间、bz 备注、 -// xhbs 序号标识、ysbbh 预设编班号、jclb 节次类别、xtms 系统模式、kfjypk 开放教员排课(0/1)、 -// jsonzd、fxbgscsj 分析报告生成时间、fxbgwd1bh/fxbgwd2bh/fxbgwd3bh 分析报告文档编号 - -// 分页查询班次学期列表(支持 xydbh 模糊) -export function listSemester(query) { - return request({ - url: '/student-records/semester/list', - method: 'get', - params: query - }) -} - -// 查询所有有效班次学期(DEL_FLAG = 0) -export function allSemester() { - return request({ - url: '/student-records/semester/all', - method: 'get' - }) -} - -// 查询班次学期详情(bh 编号) -export function getSemester(bh) { - return request({ - url: '/student-records/semester/get', - method: 'get', - params: { bh: bh } - }) -} - -// 新增班次学期(请求体 XYDNDXQJBXXB;bh 留空后端生成 UUID,delFlag 后端置 0) -export function addSemester(data) { - return request({ - url: '/student-records/semester/add', - method: 'post', - data: data - }) -} - -// 编辑班次学期(bh 编号必传,请求体 XYDNDXQJBXXB) -export function updateSemester(data) { - return request({ - url: '/student-records/semester/update', - method: 'post', - data: data - }) -} - -// 删除班次学期(逻辑删除并级联删除其班历记录) -export function delSemester(bh) { - return request({ - url: '/student-records/semester/delete', - method: 'post', - params: { bh: bh } - }) -} - -// 批量删除班次学期(请求体为编号数组) -export function batchDeleteSemester(bhList) { - return request({ - url: '/student-records/semester/batchDelete', - method: 'post', - data: bhList - }) -} - -// 批量设定学期日期(请求体 { bhList, xqkssj, xqjssj }) -export function batchUpdateDateRange(data) { - return request({ - url: '/student-records/semester/batchUpdateDateRange', - method: 'post', - data: data - }) -} - -// 批量修改开放教员排课状态(请求体 { bhList, kfjypk },0-否 1-是) -export function batchUpdateKfjypk(data) { - return request({ - url: '/student-records/semester/batchUpdateKfjypk', - method: 'post', - data: data - }) -} - -// 批量修改学期第次(请求体 { bhList, xqdc }) -export function batchUpdateXqdc(data) { - return request({ - url: '/student-records/semester/batchUpdateXqdc', - method: 'post', - data: data - }) -} - -// 批量设置教学任务(请求体 { bhList, jxrwbh }) -export function batchUpdateJxrwbh(data) { - return request({ - url: '/student-records/semester/batchUpdateJxrwbh', - method: 'post', - data: data - }) -} - -// 批量创建班次学期(按时间范围筛选可建班的学员队;xqdc 传 春季学期/夏季学期/秋季学期) -// 参数:startTime 起始日、endTime 截止日、nd 年度、xqdc 学期 -export function batchAddFromElective(params) { - return request({ - url: '/student-records/semester/batchAddFromElective', - method: 'post', - params: params - }) -} diff --git a/frontend/src/api/studentRecords/studentRecords.js b/frontend/src/api/studentRecords/studentRecords.js deleted file mode 100644 index 1a19eceae..000000000 --- a/frontend/src/api/studentRecords/studentRecords.js +++ /dev/null @@ -1,84 +0,0 @@ -import request from '@/utils/request' - -// 分页查询学员信息列表(姓名/联系电话/通信地址支持模糊查询,其余实体字段可作为查询条件) -export function listStudentRecord(query) { - return request({ - url: '/student-records/list', - method: 'get', - params: query - }) -} - -// 查询学员信息详情(bh 编号必传) -export function getStudentRecord(bh) { - return request({ - url: '/student-records/get', - method: 'get', - params: { bh: bh } - }) -} - -// 新增学员信息 -export function addStudentRecord(data) { - return request({ - url: '/student-records/add', - method: 'post', - data: data - }) -} - -// 修改学员信息(bh 编号必传) -export function updateStudentRecord(data) { - return request({ - url: '/student-records/update', - method: 'post', - data: data - }) -} - -// 删除学员信息(bh 编号) -export function delStudentRecord(bh) { - return request({ - url: '/student-records/delete', - method: 'post', - params: { bh: bh } - }) -} - -// 分页查询学员课程成绩(xybh 学员编号必传;nd 年度可选) -export function listStudentGrades(query) { - return request({ - url: '/student-records/grades', - method: 'get', - params: query - }) -} - -// 分页查询学员课程过程成绩(xybh 学员编号必传;nd 年度可选) -export function listStudentProcessGrades(query) { - return request({ - url: '/student-records/process-grades', - method: 'get', - params: query - }) -} - -// 导出学员课程成绩 Excel(xybh 学员编号必传) -export function exportStudentGrades(xybh) { - return request({ - url: '/student-records/export-grades', - method: 'get', - params: { xybh: xybh }, - responseType: 'blob' - }) -} - -// 导出学员课程过程成绩 Excel(xybh 学员编号必传) -export function exportStudentProcessGrades(xybh) { - return request({ - url: '/student-records/export-process-grades', - method: 'get', - params: { xybh: xybh }, - responseType: 'blob' - }) -} \ No newline at end of file diff --git a/frontend/src/api/studentRecords/team.js b/frontend/src/api/studentRecords/team.js deleted file mode 100644 index 54f389c3a..000000000 --- a/frontend/src/api/studentRecords/team.js +++ /dev/null @@ -1,70 +0,0 @@ -import request from '@/utils/request' - -// ======================== 班次(学员队)管理(实体 XYDB) ======================== -// 分页列表查询条件为 XYDB 实体字段。 - -// 分页查询学员队列表 -export function listTeam(query) { - return request({ - url: '/student-records/team/list', - method: 'get', - params: query - }) -} - -// 查询学员队详情(xydbh 学员队编号) -export function getTeam(xydbh) { - return request({ - url: '/student-records/team/get', - method: 'get', - params: { xydbh: xydbh } - }) -} - -// 新增学员队(请求体 XYDB) -export function addTeam(data) { - return request({ - url: '/student-records/team/add', - method: 'post', - data: data - }) -} - -// 编辑学员队(xydbh 学员队编号必传,请求体 XYDB) -export function updateTeam(data) { - return request({ - url: '/student-records/team/update', - method: 'post', - data: data - }) -} - -// 删除学员队(xydbh 学员队编号) -export function delTeam(xydbh) { - return request({ - url: '/student-records/team/delete', - method: 'post', - params: { xydbh: xydbh } - }) -} - -// 导入学员队 Excel(multipart,字段名 file) -export function importTeam(file) { - const formData = new FormData() - formData.append('file', file) - return request({ - url: '/student-records/team/import', - method: 'post', - data: formData - }) -} - -// 导出学员队 Excel(查询条件为 XYDB 实体) -export function exportTeam(query) { - return request({ - url: '/student-records/team/export', - method: 'get', - params: query, - responseType: 'blob' - }) -} diff --git a/frontend/src/api/studentRecords/warningCondition.js b/frontend/src/api/studentRecords/warningCondition.js deleted file mode 100644 index 25deb0d87..000000000 --- a/frontend/src/api/studentRecords/warningCondition.js +++ /dev/null @@ -1,37 +0,0 @@ -import request from '@/utils/request' - -// 分页查询预警条件列表 -export function listWarningCondition(query) { - return request({ - url: '/student-records/warning-condition/list', - method: 'get', - params: query - }) -} - -// 查询预警条件详情 -export function getWarningCondition(bh) { - return request({ - url: '/student-records/warning-condition/get', - method: 'get', - params: { bh: bh } - }) -} - -// 新增预警条件 -export function addWarningCondition(data) { - return request({ - url: '/student-records/warning-condition/add', - method: 'post', - data: data - }) -} - -// 修改预警条件 -export function updateWarningCondition(data) { - return request({ - url: '/student-records/warning-condition/update', - method: 'post', - data: data - }) -} \ No newline at end of file diff --git a/frontend/src/api/studentRecords/warningResult.js b/frontend/src/api/studentRecords/warningResult.js deleted file mode 100644 index 18fe36606..000000000 --- a/frontend/src/api/studentRecords/warningResult.js +++ /dev/null @@ -1,21 +0,0 @@ -import request from '@/utils/request' - -// ======================== 学员学籍预警结果(实体 XYXJYJGJG,查询:实体类) ======================== - -// 分页查询预警结果列表 -export function listWarningResult(query) { - return request({ - url: '/student-records/warning-result/list', - method: 'get', - params: query - }) -} - -// 查询预警结果详情(bh 预警结果编号) -export function getWarningResult(bh) { - return request({ - url: '/student-records/warning-result/get', - method: 'get', - params: { bh: bh } - }) -} diff --git a/frontend/src/api/subjectMajor/discipline.js b/frontend/src/api/subjectMajor/discipline.js deleted file mode 100644 index e62cbc52b..000000000 --- a/frontend/src/api/subjectMajor/discipline.js +++ /dev/null @@ -1,46 +0,0 @@ -import request from '@/utils/request' - -// 分页查询学科专业列表 -export function listDiscipline(query) { - return request({ - url: '/discipline/list', - method: 'get', - params: query - }) -} - -// 查询学科专业详情 -export function getDiscipline(bsh) { - return request({ - url: '/discipline/get', - method: 'get', - params: { bsh: bsh } - }) -} - -// 新增学科专业 -export function addDiscipline(data) { - return request({ - url: '/discipline/add', - method: 'post', - data: data - }) -} - -// 编辑学科专业 -export function updateDiscipline(data) { - return request({ - url: '/discipline/update', - method: 'post', - data: data - }) -} - -// 停用学科专业 -export function disableDiscipline(bsh) { - return request({ - url: '/discipline/disable', - method: 'post', - params: { bsh: bsh } - }) -} diff --git a/frontend/src/api/subjectMajor/major.js b/frontend/src/api/subjectMajor/major.js deleted file mode 100644 index 85ad40f08..000000000 --- a/frontend/src/api/subjectMajor/major.js +++ /dev/null @@ -1,56 +0,0 @@ -import request from '@/utils/request' - -// 分页查询专业列表 -export function listMajor(query) { - return request({ - url: '/discipline/major/list', - method: 'get', - params: query - }) -} - -// 查询专业详情 -export function getMajor(zydh) { - return request({ - url: '/discipline/major/get', - method: 'get', - params: { zydh: zydh } - }) -} - -// 新增专业 -export function addMajor(data) { - return request({ - url: '/discipline/major/add', - method: 'post', - data: data - }) -} - -// 修改专业 -export function updateMajor(data) { - return request({ - url: '/discipline/major/update', - method: 'post', - data: data - }) -} - -// 删除专业 -export function delMajor(zydh) { - return request({ - url: '/discipline/major/delete', - method: 'post', - params: { zydh: zydh } - }) -} - -// 下载人才培养方案课程数据文件模板 -export function downloadMajorTemplate() { - return request({ - url: '/download/training-program', - method: 'get', - responseType: 'blob', - timeout: 30000 - }) -} \ No newline at end of file diff --git a/frontend/src/api/system/config.js b/frontend/src/api/system/config.js deleted file mode 100644 index 957b89c2d..000000000 --- a/frontend/src/api/system/config.js +++ /dev/null @@ -1,60 +0,0 @@ -import request from '@/utils/request' - -// 查询参数列表 -export function listConfig(query) { - return request({ - url: '/system/config/list', - method: 'get', - params: query - }) -} - -// 查询参数详细 -export function getConfig(configId) { - return request({ - url: '/system/config/' + configId, - method: 'get' - }) -} - -// 根据参数键名查询参数值 -export function getConfigKey(configKey) { - return request({ - url: '/system/config/configKey/' + configKey, - method: 'get' - }) -} - -// 新增参数配置 -export function addConfig(data) { - return request({ - url: '/system/config', - method: 'post', - data: data - }) -} - -// 修改参数配置 -export function updateConfig(data) { - return request({ - url: '/system/config', - method: 'put', - data: data - }) -} - -// 删除参数配置 -export function delConfig(configId) { - return request({ - url: '/system/config/' + configId, - method: 'delete' - }) -} - -// 刷新参数缓存 -export function refreshCache() { - return request({ - url: '/system/config/refreshCache', - method: 'delete' - }) -} diff --git a/frontend/src/api/system/dept.js b/frontend/src/api/system/dept.js deleted file mode 100644 index af67f82b2..000000000 --- a/frontend/src/api/system/dept.js +++ /dev/null @@ -1,61 +0,0 @@ -import request from '@/utils/request' - -// 查询部门列表 -export function listDept(query) { - return request({ - url: '/system/dept/list', - method: 'get', - params: query - }) -} - -// 查询部门列表(排除节点) -export function listDeptExcludeChild(deptId) { - return request({ - url: '/system/dept/list/exclude/' + deptId, - method: 'get' - }) -} - -// 查询部门详细 -export function getDept(deptId) { - return request({ - url: '/system/dept/' + deptId, - method: 'get' - }) -} - -// 新增部门 -export function addDept(data) { - return request({ - url: '/system/dept', - method: 'post', - data: data - }) -} - -// 修改部门 -export function updateDept(data) { - return request({ - url: '/system/dept', - method: 'put', - data: data - }) -} - -// 保存部门排序 -export function updateDeptSort(data) { - return request({ - url: '/system/dept/updateSort', - method: 'put', - data: data - }) -} - -// 删除部门 -export function delDept(deptId) { - return request({ - url: '/system/dept/' + deptId, - method: 'delete' - }) -} \ No newline at end of file diff --git a/frontend/src/api/system/dict/data.js b/frontend/src/api/system/dict/data.js deleted file mode 100644 index 50ec3c28f..000000000 --- a/frontend/src/api/system/dict/data.js +++ /dev/null @@ -1,52 +0,0 @@ -import request from '@/utils/request' - -// 查询字典数据列表 -export function listData(query) { - return request({ - url: '/system/dict/data/list', - method: 'get', - params: query - }) -} - -// 查询字典数据详细 -export function getData(dictCode) { - return request({ - url: '/system/dict/data/' + dictCode, - method: 'get' - }) -} - -// 根据字典类型查询字典数据信息 -export function getDicts(dictType) { - return request({ - url: '/system/dict/data/type/' + dictType, - method: 'get' - }) -} - -// 新增字典数据 -export function addData(data) { - return request({ - url: '/system/dict/data', - method: 'post', - data: data - }) -} - -// 修改字典数据 -export function updateData(data) { - return request({ - url: '/system/dict/data', - method: 'put', - data: data - }) -} - -// 删除字典数据 -export function delData(dictCode) { - return request({ - url: '/system/dict/data/' + dictCode, - method: 'delete' - }) -} diff --git a/frontend/src/api/system/dict/type.js b/frontend/src/api/system/dict/type.js deleted file mode 100644 index 19ec1193e..000000000 --- a/frontend/src/api/system/dict/type.js +++ /dev/null @@ -1,60 +0,0 @@ -import request from '@/utils/request' - -// 查询字典类型列表 -export function listType(query) { - return request({ - url: '/system/dict/type/list', - method: 'get', - params: query - }) -} - -// 查询字典类型详细 -export function getType(dictId) { - return request({ - url: '/system/dict/type/' + dictId, - method: 'get' - }) -} - -// 新增字典类型 -export function addType(data) { - return request({ - url: '/system/dict/type', - method: 'post', - data: data - }) -} - -// 修改字典类型 -export function updateType(data) { - return request({ - url: '/system/dict/type', - method: 'put', - data: data - }) -} - -// 删除字典类型 -export function delType(dictId) { - return request({ - url: '/system/dict/type/' + dictId, - method: 'delete' - }) -} - -// 刷新字典缓存 -export function refreshCache() { - return request({ - url: '/system/dict/type/refreshCache', - method: 'delete' - }) -} - -// 获取字典选择框列表 -export function optionselect() { - return request({ - url: '/system/dict/type/optionselect', - method: 'get' - }) -} \ No newline at end of file diff --git a/frontend/src/api/system/menu.js b/frontend/src/api/system/menu.js deleted file mode 100644 index 24b58dd24..000000000 --- a/frontend/src/api/system/menu.js +++ /dev/null @@ -1,69 +0,0 @@ -import request from '@/utils/request' - -// 查询菜单列表 -export function listMenu(query) { - return request({ - url: '/system/menu/list', - method: 'get', - params: query - }) -} - -// 查询菜单详细 -export function getMenu(menuId) { - return request({ - url: '/system/menu/' + menuId, - method: 'get' - }) -} - -// 查询菜单下拉树结构 -export function treeselect() { - return request({ - url: '/system/menu/treeselect', - method: 'get' - }) -} - -// 根据角色ID查询菜单下拉树结构 -export function roleMenuTreeselect(roleId) { - return request({ - url: '/system/menu/roleMenuTreeselect/' + roleId, - method: 'get' - }) -} - -// 新增菜单 -export function addMenu(data) { - return request({ - url: '/system/menu', - method: 'post', - data: data - }) -} - -// 修改菜单 -export function updateMenu(data) { - return request({ - url: '/system/menu', - method: 'put', - data: data - }) -} - -// 保存菜单排序 -export function updateMenuSort(data) { - return request({ - url: '/system/menu/updateSort', - method: 'put', - data: data - }) -} - -// 删除菜单 -export function delMenu(menuId) { - return request({ - url: '/system/menu/' + menuId, - method: 'delete' - }) -} \ No newline at end of file diff --git a/frontend/src/api/system/notice.js b/frontend/src/api/system/notice.js deleted file mode 100644 index c240e071b..000000000 --- a/frontend/src/api/system/notice.js +++ /dev/null @@ -1,79 +0,0 @@ -import request from '@/utils/request' - -// 查询公告列表 -export function listNotice(query) { - return request({ - url: '/system/notice/list', - method: 'get', - params: query - }) -} - -// 查询公告详细 -export function getNotice(noticeId) { - return request({ - url: '/system/notice/' + noticeId, - method: 'get' - }) -} - -// 新增公告 -export function addNotice(data) { - return request({ - url: '/system/notice', - method: 'post', - data: data - }) -} - -// 修改公告 -export function updateNotice(data) { - return request({ - url: '/system/notice', - method: 'put', - data: data - }) -} - -// 删除公告 -export function delNotice(noticeId) { - return request({ - url: '/system/notice/' + noticeId, - method: 'delete' - }) -} - -// 首页顶部公告列表(带已读状态) -export function listNoticeTop() { - return request({ - url: '/system/notice/listTop', - method: 'get' - }) -} - -// 标记公告已读 -export function markNoticeRead(noticeId) { - return request({ - url: '/system/notice/markRead', - method: 'post', - params: { noticeId } - }) -} - -// 批量标记已读 -export function markNoticeReadAll(ids) { - return request({ - url: '/system/notice/markReadAll', - method: 'post', - params: { ids } - }) -} - -// 查询公告已读用户列表 -export function listNoticeReadUsers(query) { - return request({ - url: '/system/notice/readUsers/list', - method: 'get', - params: query - }) -} diff --git a/frontend/src/api/system/post.js b/frontend/src/api/system/post.js deleted file mode 100644 index 6b491f7bd..000000000 --- a/frontend/src/api/system/post.js +++ /dev/null @@ -1,44 +0,0 @@ -import request from '@/utils/request' - -// 查询岗位列表 -export function listPost(query) { - return request({ - url: '/system/post/list', - method: 'get', - params: query - }) -} - -// 查询岗位详细 -export function getPost(postId) { - return request({ - url: '/system/post/' + postId, - method: 'get' - }) -} - -// 新增岗位 -export function addPost(data) { - return request({ - url: '/system/post', - method: 'post', - data: data - }) -} - -// 修改岗位 -export function updatePost(data) { - return request({ - url: '/system/post', - method: 'put', - data: data - }) -} - -// 删除岗位 -export function delPost(postId) { - return request({ - url: '/system/post/' + postId, - method: 'delete' - }) -} diff --git a/frontend/src/api/system/role.js b/frontend/src/api/system/role.js deleted file mode 100644 index 816fb7eaa..000000000 --- a/frontend/src/api/system/role.js +++ /dev/null @@ -1,119 +0,0 @@ -import request from '@/utils/request' - -// 查询角色列表 -export function listRole(query) { - return request({ - url: '/system/role/list', - method: 'get', - params: query - }) -} - -// 查询角色详细 -export function getRole(roleId) { - return request({ - url: '/system/role/' + roleId, - method: 'get' - }) -} - -// 新增角色 -export function addRole(data) { - return request({ - url: '/system/role', - method: 'post', - data: data - }) -} - -// 修改角色 -export function updateRole(data) { - return request({ - url: '/system/role', - method: 'put', - data: data - }) -} - -// 角色数据权限 -export function dataScope(data) { - return request({ - url: '/system/role/dataScope', - method: 'put', - data: data - }) -} - -// 角色状态修改 -export function changeRoleStatus(roleId, status) { - const data = { - roleId, - status - } - return request({ - url: '/system/role/changeStatus', - method: 'put', - data: data - }) -} - -// 删除角色 -export function delRole(roleId) { - return request({ - url: '/system/role/' + roleId, - method: 'delete' - }) -} - -// 查询角色已授权用户列表 -export function allocatedUserList(query) { - return request({ - url: '/system/role/authUser/allocatedList', - method: 'get', - params: query - }) -} - -// 查询角色未授权用户列表 -export function unallocatedUserList(query) { - return request({ - url: '/system/role/authUser/unallocatedList', - method: 'get', - params: query - }) -} - -// 取消用户授权角色 -export function authUserCancel(data) { - return request({ - url: '/system/role/authUser/cancel', - method: 'put', - data: data - }) -} - -// 批量取消用户授权角色 -export function authUserCancelAll(data) { - return request({ - url: '/system/role/authUser/cancelAll', - method: 'put', - params: data - }) -} - -// 授权用户选择 -export function authUserSelectAll(data) { - return request({ - url: '/system/role/authUser/selectAll', - method: 'put', - params: data - }) -} - -// 根据角色ID查询部门树结构 -export function deptTreeSelect(roleId) { - return request({ - url: '/system/role/deptTree/' + roleId, - method: 'get' - }) -} diff --git a/frontend/src/api/system/user.js b/frontend/src/api/system/user.js deleted file mode 100644 index 612581416..000000000 --- a/frontend/src/api/system/user.js +++ /dev/null @@ -1,136 +0,0 @@ -import request from '@/utils/request' -import { parseStrEmpty } from "@/utils/roomroot" - -// 查询用户列表 -export function listUser(query) { - return request({ - url: '/system/user/list', - method: 'get', - params: query - }) -} - -// 查询用户详细 -export function getUser(userId) { - return request({ - url: '/system/user/' + parseStrEmpty(userId), - method: 'get' - }) -} - -// 新增用户 -export function addUser(data) { - return request({ - url: '/system/user', - method: 'post', - data: data - }) -} - -// 修改用户 -export function updateUser(data) { - return request({ - url: '/system/user', - method: 'put', - data: data - }) -} - -// 删除用户 -export function delUser(userId) { - return request({ - url: '/system/user/' + userId, - method: 'delete' - }) -} - -// 用户密码重置 -export function resetUserPwd(userId, password) { - const data = { - userId, - password - } - return request({ - url: '/system/user/resetPwd', - method: 'put', - data: data - }) -} - -// 用户状态修改 -export function changeUserStatus(userId, status) { - const data = { - userId, - status - } - return request({ - url: '/system/user/changeStatus', - method: 'put', - data: data - }) -} - -// 查询用户个人信息 -export function getUserProfile() { - return request({ - url: '/system/user/profile', - method: 'get' - }) -} - -// 修改用户个人信息 -export function updateUserProfile(data) { - return request({ - url: '/system/user/profile', - method: 'put', - data: data - }) -} - -// 用户密码重置 -export function updateUserPwd(oldPassword, newPassword) { - const data = { - oldPassword, - newPassword - } - return request({ - url: '/system/user/profile/updatePwd', - method: 'put', - data: data - }) -} - -// 用户头像上传 -export function uploadAvatar(data) { - return request({ - url: '/system/user/profile/avatar', - method: 'post', - headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, - data: data - }) -} - -// 查询授权角色 -export function getAuthRole(userId) { - return request({ - url: '/system/user/authRole/' + userId, - method: 'get' - }) -} - -// 保存授权角色 -export function updateAuthRole(data) { - return request({ - url: '/system/user/authRole', - method: 'put', - params: data - }) -} - -// 查询部门下拉树结构 -export function deptTreeSelect() { - return request({ - url: '/system/user/deptTree', - method: 'get' - }) -} diff --git a/frontend/src/api/teachBusiness/classroom.js b/frontend/src/api/teachBusiness/classroom.js deleted file mode 100644 index 7c36aed69..000000000 --- a/frontend/src/api/teachBusiness/classroom.js +++ /dev/null @@ -1,95 +0,0 @@ -import request from '@/utils/request' - -// 教学场地/教室管理(JSB 教室表 /classroom) -// 接口依据:classroom 控制器(前端 baseURL 为 /api,此处不重复 /api 前缀) - -/** - * 新增教室 - * POST /classroom/add - * 请求体(JSB):id/jsbh/jsmc 必填,其余字段可空;ty/xslx 为 Boolean - */ -export function addClassroom(data) { - return request({ - url: '/classroom/add', - method: 'post', - data - }) -} - -/** - * 删除教室(不提供批量删除接口) - * POST /classroom/delete - * @param id 教室编号(主键,必填) - */ -export function deleteClassroom(id) { - return request({ - url: '/classroom/delete', - method: 'post', - params: { id } - }) -} - -/** - * 更新教室 - * POST /classroom/update - * 请求体(JSB):id 必传 - */ -export function updateClassroom(data) { - return request({ - url: '/classroom/update', - method: 'post', - data - }) -} - -/** - * 根据编号查询教室详情 - * GET /classroom/get - * @param id 教室编号 - */ -export function getClassroom(id) { - return request({ - url: '/classroom/get', - method: 'get', - params: { id } - }) -} - -/** - * 分页查询教室列表 - * GET /classroom/list - * 查询参数:jsbh(模糊)、jsmc(模糊)、jxldh(等值)、jxcdlx(等值)、ty(等值)、pageNum、pageSize - * 返回:PageResult(records/total) - */ -export function listClassroom(params) { - return request({ - url: '/classroom/list', - method: 'get', - params - }) -} - -/** - * 查询全部教室 - * GET /classroom/all - * 返回:List(无分页) - */ -export function listAllClassroom() { - return request({ - url: '/classroom/all', - method: 'get' - }) -} - -/** - * 根据教学楼代号查询教室 - * GET /classroom/listByJxldh - * @param jxldh 教学楼代号(必填) - */ -export function listClassroomByJxldh(jxldh) { - return request({ - url: '/classroom/listByJxldh', - method: 'get', - params: { jxldh } - }) -} diff --git a/frontend/src/api/teachBusiness/courseRunning.js b/frontend/src/api/teachBusiness/courseRunning.js deleted file mode 100644 index 04ecfd690..000000000 --- a/frontend/src/api/teachBusiness/courseRunning.js +++ /dev/null @@ -1,110 +0,0 @@ -import request from '@/utils/request' - -// 课程教学运行管理(CourseRunningController /course-running) -// 接口依据:course-running 控制器(前端 baseURL 为 /api,此处不重复 /api 前缀) - -/** - * 分页查询教学实施计划课次列表 - * GET /course-running/plan/list - * 查询参数(TeachingPlanQueryDTO): - * sskcbh 实施_课程编号、nd 年度、jxff 教学方法、 - * rqStart 日期范围开始、rqEnd 日期范围结束(均传 ISO 格式,如 2026-08-23T00:00:00)、 - * txzt 填写状态(0-未填写 1-已填写 2-已提交)、pageNum、pageSize - * 返回:PageResult(records/total) - */ -export function listTeachingPlan(params) { - return request({ - url: '/course-running/plan/list', - method: 'get', - params - }) -} - -// ==================== 调课申请管理 /course-running/adjust ==================== -// 接口依据:CourseRunningController(类上 @RequestMapping("/course-running"),前端 baseURL 为 /api,此处不重复 /api 前缀) - -/** - * 分页查询调课申请列表 - * GET /course-running/adjust/list - * 查询参数(ScheduleAdjustQueryDTO):sskcbbh 课次编号、sqjybh 申请教员编号、nd 年度、 - * jyspzzt 教研室审批状态、jyscszt 教研室查收状态、sczt 删除状态、 - * cjsjStart/cjsjEnd 申请日期范围(ISO 格式)、pageNum、pageSize - * 返回:PageResult(records/total) - */ -export function listScheduleAdjust(params) { - return request({ - url: '/course-running/adjust/list', - method: 'get', - params - }) -} - -/** - * 查询当前教员可供调课的课次 - * GET /course-running/adjust/lessons - * 查询参数:nd 年度(可选) - * 返回:List(kcmc/rq/jc/xydmc/kcxh/jsbh/sskcbbh 等) - */ -export function listAdjustableLessons(params) { - return request({ - url: '/course-running/adjust/lessons', - method: 'get', - params - }) -} - -/** - * 查询调课申请详情 - * GET /course-running/adjust/detail - * @param ssdksqbh 调课申请编号 - * 返回:ScheduleAdjustDetailVO - */ -export function getScheduleAdjustDetail(ssdksqbh) { - return request({ - url: '/course-running/adjust/detail', - method: 'get', - params: { ssdksqbh } - }) -} - -/** - * 提交调课申请 - * POST /course-running/adjust/submit - * 请求体(ScheduleAdjustApplyDTO)核心字段:sskcbbh 课次编号、sy 调课事由、rq 调课后新日期、 - * jc 调课后新节次、nd 年度、sqjybh 申请教员编号(可选 ydsjap 原日期节次描述、xydrwbh/kbh/ - * kcbbh/xydmc/jysdh/yjsbh/xjsbh/kcmc/sqjyxm 由课次自动带出) - */ -export function submitScheduleAdjust(data) { - return request({ - url: '/course-running/adjust/submit', - method: 'post', - data - }) -} - -/** - * 教研室审批调课申请 - * POST /course-running/adjust/audit/jys - * 请求体(ScheduleAdjustAuditDTO):ssdksqbh(必填)、spzt(1同意/2发回/3拒绝)、 - * fhyj(审批意见,发回时填写)、sprbh(审批人编号,不传时取当前登录人;点审批即已查收) - */ -export function auditByTeachingOffice(data) { - return request({ - url: '/course-running/adjust/audit/jys', - method: 'post', - data - }) -} - -/** - * 撤销调课申请 - * DELETE /course-running/adjust/cancel - * @param params { ssdksqbh, sqjybh } - */ -export function cancelScheduleAdjust(params) { - return request({ - url: '/course-running/adjust/cancel', - method: 'delete', - params - }) -} diff --git a/frontend/src/api/teachBusiness/semester.js b/frontend/src/api/teachBusiness/semester.js deleted file mode 100644 index d4e681698..000000000 --- a/frontend/src/api/teachBusiness/semester.js +++ /dev/null @@ -1,54 +0,0 @@ -import request from '@/utils/request' - -// 分页查询学期列表 -export function listSemester(query) { - return request({ - url: '/semester/list', - method: 'get', - params: query - }) -} - -// 查询所有学期列表(年度下拉数据源,返回全部学期含 nd/dqxq,按年度倒序) -export function listAllSemester() { - return request({ - url: '/semester/all', - method: 'get' - }) -} - -// 根据主键查询学期 -export function getSemester(nd) { - return request({ - url: '/semester/get', - method: 'get', - params: { nd: nd } - }) -} - -// 学期新增 -export function addSemester(data) { - return request({ - url: '/semester/add', - method: 'post', - data: data - }) -} - -// 根据主键修改 -export function updateSemester(data) { - return request({ - url: '/semester/update', - method: 'post', - data: data - }) -} - -// 根据主键删除 -export function delSemester(nd) { - return request({ - url: '/semester/delete', - method: 'post', - params: { nd: nd } - }) -} diff --git a/frontend/src/api/teachBusiness/studentTeamTask.js b/frontend/src/api/teachBusiness/studentTeamTask.js deleted file mode 100644 index fa0423cb8..000000000 --- a/frontend/src/api/teachBusiness/studentTeamTask.js +++ /dev/null @@ -1,18 +0,0 @@ -import request from '@/utils/request' - -// 学员队任务表(StudentTeamTaskController /studentTeamTask) -// 接口依据:studentTeamTask 控制器(前端 baseURL 为 /api,此处不重复 /api 前缀) - -/** - * 分页查询学员队任务表(按班次/年度) - * GET /studentTeamTask/list - * 查询参数(XYDRWB 实体字段):xydbh 学员队编号、nd 年度、kcxh 课次序号、jhkcxh 计划课次序号、xs 学时等 - * 返回:Page(records/total) - */ -export function listStudentTeamTask(params) { - return request({ - url: '/studentTeamTask/list', - method: 'get', - params - }) -} diff --git a/frontend/src/api/teachBusiness/syllabus.js b/frontend/src/api/teachBusiness/syllabus.js deleted file mode 100644 index 0b4c144f4..000000000 --- a/frontend/src/api/teachBusiness/syllabus.js +++ /dev/null @@ -1,66 +0,0 @@ -import request from '@/utils/request' - -// 专业教学计划(教学大纲 ZYJXJHB) -// 接口依据:/zyjxjhb/*(前端 baseURL 为 '/api',此处不再加前缀) - -// 新增(bh 留空后端自动生成 UUID,ty 默认 0,qysj 默认当前时间) -export function addSyllabus(data) { - return request({ - url: '/zyjxjhb/add', - method: 'post', - data - }) -} - -// 删除(软删:置 ty=1 并写 tysj) -export function deleteSyllabus(bh) { - return request({ - url: '/zyjxjhb/delete', - method: 'post', - params: { bh } - }) -} - -// 批量删除(软删) -export function batchDeleteSyllabus(bhList) { - return request({ - url: '/zyjxjhb/batchDelete', - method: 'post', - data: bhList - }) -} - -// 更新(bh 必传) -export function updateSyllabus(data) { - return request({ - url: '/zyjxjhb/update', - method: 'post', - data - }) -} - -// 根据编号查询 -export function getSyllabus(bh) { - return request({ - url: '/zyjxjhb/get', - method: 'get', - params: { bh } - }) -} - -// 查询所有(返回 List,无分页,前端本地分页) -export function listSyllabus() { - return request({ - url: '/zyjxjhb/list', - method: 'get' - }) -} - -// 根据专业代号和停用标识查询(zydh、ty 均必填,等值匹配) -export function listSyllabusByZydhAndTy(zydh, ty) { - return request({ - url: '/zyjxjhb/listByZydhAndTy', - method: 'get', - params: { zydh, ty } - }) -} diff --git a/frontend/src/api/teachBusiness/teachingTask.js b/frontend/src/api/teachBusiness/teachingTask.js deleted file mode 100644 index e83d276c1..000000000 --- a/frontend/src/api/teachBusiness/teachingTask.js +++ /dev/null @@ -1,90 +0,0 @@ -import request from '@/utils/request' - -// 教学任务管理(TeachingTaskController /teachingTask) -// 接口依据:api.txt「教学任务管理」分组(前端 baseURL 为 /api,此处不重复 /api 前缀) -// 实体:JXRW(bh 编号、rwmc 任务名称、nd 年度、zt 状态、 -// fbsj 发布时间、cjsj 创建时间、jssj 结束时间、jcxqscsj 教材需求生成时间) -// 新增时 bh 留空由后端生成(api.txt 新增示例未传 bh),编辑/更新时 bh 必传 - -/** - * 分页查询教学任务列表 - * GET /teachingTask/list - * 查询参数(JXRW):rwmc 任务名称(模糊)、nd 年度(等值)、zt 状态(等值)、 - * pageNum、pageSize - * 返回:PageResult(records/total) - */ -export function listTeachingTask(params) { - return request({ - url: '/teachingTask/list', - method: 'get', - params - }) -} - -/** - * 根据编号查询教学任务 - * GET /teachingTask/get?bh= - * @param bh 编号 - * 返回:JXRW - */ -export function getTeachingTask(bh) { - return request({ - url: '/teachingTask/get', - method: 'get', - params: { bh } - }) -} - -/** - * 新增教学任务 - * POST /teachingTask/add - * 请求体(JXRW):rwmc 任务名称(必填)、nd 年度(必填)、zt 状态、fbsj/jssj/jcxqscsj - * 说明:bh 不传由后端自动生成;cjsj 创建时间由后端自动维护 - */ -export function addTeachingTask(data) { - return request({ - url: '/teachingTask/add', - method: 'post', - data - }) -} - -/** - * 更新教学任务(根据主键) - * POST /teachingTask/update - * 请求体(JXRW):bh 编号(必填)、rwmc、nd、zt - */ -export function updateTeachingTask(data) { - return request({ - url: '/teachingTask/update', - method: 'post', - data - }) -} - -/** - * 级联删除教学任务和教研室任务书 - * POST /teachingTask/delete?bh= - * @param bh 编号 - */ -export function deleteTeachingTask(bh) { - return request({ - url: '/teachingTask/delete', - method: 'post', - params: { bh } - }) -} - -/** - * 教学任务发布(需要先填写教研室任务书) - * POST /teachingTask/batchPublish?bh= - * @param bh 教学任务编号 - * 返回:更新数量 - */ -export function publishTeachingTask(bh) { - return request({ - url: '/teachingTask/batchPublish', - method: 'post', - params: { bh } - }) -} diff --git a/frontend/src/api/teachBusiness/timetableConflict.js b/frontend/src/api/teachBusiness/timetableConflict.js deleted file mode 100644 index 8cb81d48a..000000000 --- a/frontend/src/api/teachBusiness/timetableConflict.js +++ /dev/null @@ -1,45 +0,0 @@ -import request from '@/utils/request' - -// 课表冲突检查:单维度检查(POST /timetable-conflict/check) -// body: { nd 年度(必填), dimensionCode 维度编码(必填), writeToDb?(落库), jcpch?(批次号) } -// 返回 TimetableConflictCardVO { dimensionCode, title, description, checked, conflictCount } -export function checkConflict(data) { - return request({ - url: '/timetable-conflict/check', - method: 'post', - data - }) -} - -// 课表冲突检查:执行全部维度检查(POST /timetable-conflict/check-all) -// body: { nd 年度(必填), writeToDb? } -// 返回 TimetableConflictSummaryVO { nd, cards[], totalConflictCount, fullyChecked } -export function checkAllConflict(data) { - return request({ - url: '/timetable-conflict/check-all', - method: 'post', - data - }) -} - -// 课表冲突检查:重置检查结果(POST /timetable-conflict/reset) -// body: { nd 年度(必填), clearDb? 是否同时清空落库表 } -// 返回 TimetableConflictSummaryVO(所有卡片未检查状态) -export function resetConflict(data) { - return request({ - url: '/timetable-conflict/reset', - method: 'post', - data - }) -} - -// 课表冲突检查:分页查询冲突明细(GET /timetable-conflict/details) -// params: { nd 年度(必填), dimensionCode? 维度编码, pageNum?, pageSize?, useDb?, jcpch? } -// 返回 PageResult -export function getConflictDetails(params) { - return request({ - url: '/timetable-conflict/details', - method: 'get', - params - }) -} diff --git a/frontend/src/api/teachBusiness/training.js b/frontend/src/api/teachBusiness/training.js deleted file mode 100644 index d64b39845..000000000 --- a/frontend/src/api/teachBusiness/training.js +++ /dev/null @@ -1,71 +0,0 @@ -import request from '@/utils/request' - -// 人才培养方案(专业表 ZYB /training) -// 接口依据:TrainingProgramController(前端 baseURL 为 /api,此处不重复 /api 前缀) - -/** - * 新增培养方案(专业) - * POST /training/add - * 请求体(ZYB):zydh/zymc/zydm/pxcc/pxlx 必填; - * 主键 zydh 需手动传入(留空时后端自动生成 UUID,后端同时置 ty=false、qysj=当前时间) - */ -export function addTraining(data) { - return request({ - url: '/training/add', - method: 'post', - data - }) -} - -/** - * 停用(逻辑删除)培养方案 - * POST /training/disable?zydh= - * @param zydh 专业代号(必填) - */ -export function disableTraining(zydh) { - return request({ - url: '/training/disable', - method: 'post', - params: { zydh } - }) -} - -/** - * 更新培养方案 - * POST /training/update - * 请求体(ZYB):zydh 必传 - */ -export function updateTraining(data) { - return request({ - url: '/training/update', - method: 'post', - data - }) -} - -/** - * 根据专业代号查询培养方案详情 - * GET /training/get?zydh= - * @param zydh 专业代号 - */ -export function getTraining(zydh) { - return request({ - url: '/training/get', - method: 'get', - params: { zydh } - }) -} - -/** - * 分页条件查询培养方案列表 - * GET /training/list - * 查询参数:zymc(模糊)、zydm(模糊)、pxlx(精确)、pxcc(精确)、pageNum、pageSize - * 返回:PageResult(records/total) - */ -export function listTraining(params) { - return request({ - url: '/training/list', - method: 'get', - params - }) -} diff --git a/frontend/src/api/teachBusiness/xqxlb.js b/frontend/src/api/teachBusiness/xqxlb.js deleted file mode 100644 index 5a2731142..000000000 --- a/frontend/src/api/teachBusiness/xqxlb.js +++ /dev/null @@ -1,28 +0,0 @@ -import request from '@/utils/request' - -// 按学期查询校历假期列表(nd 为学期代号,如 202601) -export function listXqxlb(query) { - return request({ - url: '/xqxlb/list', - method: 'get', - params: query - }) -} - -// 根据主键查询校历假期 -export function getXqxlb(bh) { - return request({ - url: '/xqxlb/get', - method: 'get', - params: { bh: bh } - }) -} - -// 新增 / 修改校历假期(无 bh 时为新增,带 bh 时为修改) -export function updateXqxlb(data) { - return request({ - url: '/xqxlb/update', - method: 'post', - data: data - }) -} diff --git a/frontend/src/api/teachNotice.js b/frontend/src/api/teachNotice.js deleted file mode 100644 index ff5c48005..000000000 --- a/frontend/src/api/teachNotice.js +++ /dev/null @@ -1,47 +0,0 @@ -import request from '@/utils/request' - -// 分页查询教学公告列表 -export function listTeachNotice(query) { - return request({ - url: '/notice-announcement/list', - method: 'get', - params: query - }) -} - -// 查询公告详情 -export function getTeachNotice(Id) { - return request({ - url: '/notice-announcement/get', - method: 'get', - params: { Id } - }) -} - -// 新增公告 -export function addTeachNotice(data) { - return request({ - url: '/notice-announcement/add', - method: 'post', - data: data - }) -} - -// 修改公告(含下架/上架:更新时附带 status) -export function updateTeachNotice(data) { - return request({ - url: '/notice-announcement/update', - method: 'post', - params: { Id: data.id }, - data: data - }) -} - -// 删除/下架(级联删除:先删通告用户信息表,再删通告表) -export function delTeachNotice(Id) { - return request({ - url: '/notice-announcement/delete', - method: 'post', - params: { Id } - }) -} \ No newline at end of file diff --git a/frontend/src/api/teachOffice/elective.js b/frontend/src/api/teachOffice/elective.js deleted file mode 100644 index d1b6cd228..000000000 --- a/frontend/src/api/teachOffice/elective.js +++ /dev/null @@ -1,68 +0,0 @@ -import request from '@/utils/request' - -// 分页查询选修班 -// pageNum/pageSize/jyxm(通信)/kmc(通信)/kxbcnj(通信)/xxbmc(通信)/xkzt(等值)/pxcc(等值) -export function listElective(query) { - return request({ - url: '/jys/elective/list', - method: 'get', - params: query - }) -} - -// 批量开放报名 -export function batchOpenElective(bhList) { - return request({ - url: '/jys/elective/batch-open', - method: 'post', - data: { bhList: bhList } - }) -} - -// 批量取消开放报名 -export function batchCancelOpenElective(bhList) { - return request({ - url: '/jys/elective/batch-cancel-open', - method: 'post', - data: { bhList: bhList } - }) -} - -// 批量停止报名 -export function batchStopElective(bhList) { - return request({ - url: '/jys/elective/batch-stop', - method: 'post', - data: { bhList: bhList } - }) -} - -// 下载选修班列表(Excel) -export function exportElectiveList(query) { - return request({ - url: '/jys/elective/export', - method: 'get', - params: query, - responseType: 'blob' - }) -} - -// 下载选修班学员名单(Excel) -export function exportElectiveStudentsExcel(bhList) { - return request({ - url: '/jys/elective/students/export-excel', - method: 'get', - params: { bhList: bhList }, - responseType: 'blob' - }) -} - -// 下载选修班学员名单(Word) -export function exportElectiveStudentsWord(bhList) { - return request({ - url: '/jys/elective/students/export-word', - method: 'get', - params: { bhList: bhList }, - responseType: 'blob' - }) -} \ No newline at end of file diff --git a/frontend/src/api/teachOffice/kb.js b/frontend/src/api/teachOffice/kb.js deleted file mode 100644 index fbc624cff..000000000 --- a/frontend/src/api/teachOffice/kb.js +++ /dev/null @@ -1,47 +0,0 @@ -import request from '@/utils/request' - -// 分页查询课程科目(课表 KB) -// kmc/kmdm/jc 模糊,jysdh/kclx/pxlx/pxcc 等值 -export function listKb(query) { - return request({ - url: '/jys/kb/list', - method: 'get', - params: query - }) -} - -// 课程科目详情(kbh 课编号) -export function getKb(kbh) { - return request({ - url: '/jys/kb/get', - method: 'get', - params: { kbh: kbh } - }) -} - -// 新增课程科目(kbh 留空后端生成 UUID) -export function addKb(data) { - return request({ - url: '/jys/kb/add', - method: 'post', - data: data - }) -} - -// 删除课程科目(kbh 课编号) -export function deleteKb(kbh) { - return request({ - url: '/jys/kb/delete', - method: 'post', - params: { kbh: kbh } - }) -} - -// 编辑课程科目(kbh 必传) -export function updateKb(data) { - return request({ - url: '/jys/kb/update', - method: 'post', - data: data - }) -} \ No newline at end of file diff --git a/frontend/src/api/teachOffice/office.js b/frontend/src/api/teachOffice/office.js deleted file mode 100644 index 7161b685b..000000000 --- a/frontend/src/api/teachOffice/office.js +++ /dev/null @@ -1,37 +0,0 @@ -import request from '@/utils/request' - -// 查询教研室列表 -export function listOffice(query) { - return request({ - url: '/jys/office/list', - method: 'get', - params: query - }) -} - -// 新增教研室 -export function addOffice(data) { - return request({ - url: '/jys/office/add', - method: 'post', - data: data - }) -} - -// 更新教研室 -export function updateOffice(data) { - return request({ - url: '/jys/office/update', - method: 'post', - data: data - }) -} - -// 停用教研室(jysdh 必传,query 参数) -export function disableOffice(jysdh) { - return request({ - url: '/jys/office/disable', - method: 'post', - params: { jysdh: jysdh } - }) -} diff --git a/frontend/src/api/teachOffice/teacher.js b/frontend/src/api/teachOffice/teacher.js deleted file mode 100644 index 5b1b62f1d..000000000 --- a/frontend/src/api/teachOffice/teacher.js +++ /dev/null @@ -1,75 +0,0 @@ -import request from '@/utils/request' - -// 教员管理:教员(JYB)+ 教员属性(JYSX) -// 接口依据:/jys/teacher/*(前端 baseURL 为 /api,此处不重复 /api 前缀) - -/** - * 分页查询教员列表 - * GET /jys/teacher/list - * 查询参数(JYBMapper.xml 支持):jyxm 模糊、jysdh 等值、zc 模糊、jylb 等值 - */ -export function listTeacher(params) { - return request({ - url: '/jys/teacher/list', - method: 'get', - params - }) -} - -/** 根据教员编号查询教员详情 GET /jys/teacher/get?jybh= */ -export function getTeacher(jybh) { - return request({ - url: '/jys/teacher/get', - method: 'get', - params: { jybh } - }) -} - -/** - * 新增教员 POST /jys/teacher/add - * body 为 AddTeacherDTO:{ teacher: JYB, attributes: JYSX } - * lzzt 前端不传,后端自动置 0 - */ -export function addTeacher(data) { - return request({ - url: '/jys/teacher/add', - method: 'post', - data - }) -} - -/** 更新教员基本信息 POST /jys/teacher/update(body 为 JYB,jybh 必传) */ -export function updateTeacher(data) { - return request({ - url: '/jys/teacher/update', - method: 'post', - data - }) -} - -/** 教员离职(逻辑删除)POST /jys/teacher/disable?jybh= */ -export function disableTeacher(jybh) { - return request({ - url: '/jys/teacher/disable', - method: 'post', - params: { jybh } - }) -} - -/** 查询教员属性 GET /jys/teacher/attribute/get?jybh= */ -export function getTeacherAttribute(jybh) { - return request({ - url: '/jys/teacher/attribute/get', - method: 'get', - params: { jybh } - }) -} - -/** 更新教员属性 POST /jys/teacher/attribute/update(body 为 JYSX,jybh 必传) */ -export function updateTeacherAttribute(data) { - return request({ - url: '/jys/teacher/attribute/update', - method: 'post', - data - }) -} diff --git a/frontend/src/api/textbook/teachingMaterial.js b/frontend/src/api/textbook/teachingMaterial.js deleted file mode 100644 index 0c94d4bf0..000000000 --- a/frontend/src/api/textbook/teachingMaterial.js +++ /dev/null @@ -1,83 +0,0 @@ -import request from '@/utils/request' - -// 教材管理:教材信息(JCXX 实体) -// 接口依据 api.txt:/teachingMaterial/*(前端 baseURL 为 /api,此处不重复 /api 前缀) - -/** - * 教材信息分页查询 - * GET /teachingMaterial/list - * 查询参数(TeachingMaterialMapper.xml 支持):bh/mc/isbn/cbs/zz 模糊,jcfl/jclx 等值,ty 等值 - */ -export function listTeachingMaterial(params) { - return request({ - url: '/teachingMaterial/list', - method: 'get', - params - }) -} - -/** 根据编号查询 GET /teachingMaterial/getByBh?bh= */ -export function getTeachingMaterialByBh(bh) { - return request({ - url: '/teachingMaterial/getByBh', - method: 'get', - params: { bh } - }) -} - -/** 根据ID查询 GET /teachingMaterial/getById?id= */ -export function getTeachingMaterialById(id) { - return request({ - url: '/teachingMaterial/getById', - method: 'get', - params: { id } - }) -} - -/** 新增教材信息 POST /teachingMaterial/add */ -export function addTeachingMaterial(data) { - return request({ - url: '/teachingMaterial/add', - method: 'post', - data - }) -} - -/** 根据ID修改 POST /teachingMaterial/update(body 需携带 id) */ -export function updateTeachingMaterial(data) { - return request({ - url: '/teachingMaterial/update', - method: 'post', - data - }) -} - -/** 删除 POST /teachingMaterial/delete?id= */ -export function deleteTeachingMaterial(id) { - return request({ - url: '/teachingMaterial/delete', - method: 'post', - params: { id } - }) -} - -/** 教材导入模板下载 GET /teachingMaterial/template */ -export function downloadTeachingMaterialTemplate() { - return request({ - url: '/teachingMaterial/template', - method: 'get', - responseType: 'blob' - }) -} - -/** 教材导入 POST /teachingMaterial/import(form-data,字段名 file) */ -export function importTeachingMaterial(file) { - const formData = new FormData() - formData.append('file', file) - return request({ - url: '/teachingMaterial/import', - method: 'post', - data: formData, - headers: { 'Content-Type': 'multipart/form-data' } - }) -} diff --git a/frontend/src/api/textbook/teachingStock.js b/frontend/src/api/textbook/teachingStock.js deleted file mode 100644 index 1b99fce6a..000000000 --- a/frontend/src/api/textbook/teachingStock.js +++ /dev/null @@ -1,106 +0,0 @@ -import request from '@/utils/request' - -// 教材库存:库存单(JCKCD)+ 库存明细项(JCKCMXX) -// 接口依据 api.txt:/teachingStock/*(前端 baseURL 为 /api,此处不重复 /api 前缀) - -// ==================== 教材库存单(JCKCD) ==================== - -/** - * 分页查询库存单 - * GET /teachingStock/list - * 查询参数(TeachingStockMapper.xml 支持):bh/mc 模糊,lb/zb/zt 等值 - */ -export function listTeachingStock(params) { - return request({ - url: '/teachingStock/list', - method: 'get', - params - }) -} - -/** 根据ID查询库存单 GET /teachingStock/get?id= */ -export function getTeachingStock(id) { - return request({ - url: '/teachingStock/get', - method: 'get', - params: { id } - }) -} - -/** 新增库存单 POST /teachingStock/add(bh 留空由后端自动生成) */ -export function addTeachingStock(data) { - return request({ - url: '/teachingStock/add', - method: 'post', - data - }) -} - -/** 修改库存单 POST /teachingStock/update(body 需携带 id) */ -export function updateTeachingStock(data) { - return request({ - url: '/teachingStock/update', - method: 'post', - data - }) -} - -/** 删除库存单 POST /teachingStock/delete?id= */ -export function deleteTeachingStock(id) { - return request({ - url: '/teachingStock/delete', - method: 'post', - params: { id } - }) -} - -// ==================== 教材库存明细项(JCKCMXX) ==================== - -/** - * 分页查询库存明细项 - * GET /teachingStock/detail/list - * 查询参数(TeachingStockDetailMapper.xml 支持):bh 模糊,jckcdbbh 等值,jcxxbh 模糊,hwbw 等值 - */ -export function listTeachingStockDetail(params) { - return request({ - url: '/teachingStock/detail/list', - method: 'get', - params - }) -} - -/** 根据ID查询库存明细项 GET /teachingStock/detail/get?id= */ -export function getTeachingStockDetail(id) { - return request({ - url: '/teachingStock/detail/get', - method: 'get', - params: { id } - }) -} - -/** 新增库存明细项 POST /teachingStock/detail/add(bh 留空由后端自动生成) */ -export function addTeachingStockDetail(data) { - return request({ - url: '/teachingStock/detail/add', - method: 'post', - data - }) -} - -/** 修改库存明细项 POST /teachingStock/detail/update(body 需携带 id) */ -export function updateTeachingStockDetail(data) { - return request({ - url: '/teachingStock/detail/update', - method: 'post', - data - }) -} - -/** 删除库存明细项 POST /teachingStock/detail/delete?id= */ -export function deleteTeachingStockDetail(id) { - return request({ - url: '/teachingStock/detail/delete', - method: 'post', - params: { id } - }) -} diff --git a/frontend/src/api/tool/gen.js b/frontend/src/api/tool/gen.js deleted file mode 100644 index 65757ac7d..000000000 --- a/frontend/src/api/tool/gen.js +++ /dev/null @@ -1,86 +0,0 @@ -import request from '@/utils/request' - -// 查询生成表数据 -export function listTable(query) { - return request({ - url: '/tool/gen/list', - method: 'get', - params: query - }) -} - -// 查询db数据库列表 -export function listDbTable(query) { - return request({ - url: '/tool/gen/db/list', - method: 'get', - params: query - }) -} - -// 查询表详细信息 -export function getGenTable(tableId) { - return request({ - url: '/tool/gen/' + tableId, - method: 'get' - }) -} - -// 修改代码生成信息 -export function updateGenTable(data) { - return request({ - url: '/tool/gen', - method: 'put', - data: data - }) -} - -// 导入表 -export function importTable(data) { - return request({ - url: '/tool/gen/importTable', - method: 'post', - params: data - }) -} - -// 创建表 -export function createTable(data) { - return request({ - url: '/tool/gen/createTable', - method: 'post', - params: data - }) -} - -// 预览生成代码 -export function previewTable(tableId) { - return request({ - url: '/tool/gen/preview/' + tableId, - method: 'get' - }) -} - -// 删除表数据 -export function delTable(tableId) { - return request({ - url: '/tool/gen/' + tableId, - method: 'delete' - }) -} - -// 生成代码(自定义路径) -export function genCode(tableName) { - return request({ - url: '/tool/gen/genCode/' + tableName, - method: 'get' - }) -} - -// 同步数据库 -export function synchDb(tableName) { - return request({ - url: '/tool/gen/synchDb/' + tableName, - method: 'get' - }) -} diff --git a/frontend/src/assets/401_images/401.gif b/frontend/src/assets/401_images/401.gif deleted file mode 100644 index cd6e0d943..000000000 Binary files a/frontend/src/assets/401_images/401.gif and /dev/null differ diff --git a/frontend/src/assets/404_images/404.png b/frontend/src/assets/404_images/404.png deleted file mode 100644 index 3d8e2305c..000000000 Binary files a/frontend/src/assets/404_images/404.png and /dev/null differ diff --git a/frontend/src/assets/404_images/404_cloud.png b/frontend/src/assets/404_images/404_cloud.png deleted file mode 100644 index c6281d090..000000000 Binary files a/frontend/src/assets/404_images/404_cloud.png and /dev/null differ diff --git a/frontend/src/assets/icons/index.js b/frontend/src/assets/icons/index.js deleted file mode 100644 index e1a28d7fc..000000000 --- a/frontend/src/assets/icons/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import Vue from 'vue' -import SvgIcon from '@/components/SvgIcon'// svg component - -// register globally -Vue.component('svg-icon', SvgIcon) - -const req = require.context('./svg', false, /\.svg$/) -const requireAll = requireContext => requireContext.keys().map(requireContext) -requireAll(req) diff --git a/frontend/src/assets/icons/svg/404.svg b/frontend/src/assets/icons/svg/404.svg deleted file mode 100644 index 6df50190a..000000000 --- a/frontend/src/assets/icons/svg/404.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/bell.svg b/frontend/src/assets/icons/svg/bell.svg deleted file mode 100644 index a7320a05b..000000000 --- a/frontend/src/assets/icons/svg/bell.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/bug.svg b/frontend/src/assets/icons/svg/bug.svg deleted file mode 100644 index 05a150dc3..000000000 --- a/frontend/src/assets/icons/svg/bug.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/build.svg b/frontend/src/assets/icons/svg/build.svg deleted file mode 100644 index 97c468863..000000000 --- a/frontend/src/assets/icons/svg/build.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/button.svg b/frontend/src/assets/icons/svg/button.svg deleted file mode 100644 index 904fddc85..000000000 --- a/frontend/src/assets/icons/svg/button.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/cascader.svg b/frontend/src/assets/icons/svg/cascader.svg deleted file mode 100644 index e256024f9..000000000 --- a/frontend/src/assets/icons/svg/cascader.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/chart.svg b/frontend/src/assets/icons/svg/chart.svg deleted file mode 100644 index 27728fb0b..000000000 --- a/frontend/src/assets/icons/svg/chart.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/checkbox.svg b/frontend/src/assets/icons/svg/checkbox.svg deleted file mode 100644 index 013fd3a27..000000000 --- a/frontend/src/assets/icons/svg/checkbox.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/clipboard.svg b/frontend/src/assets/icons/svg/clipboard.svg deleted file mode 100644 index 90923ff62..000000000 --- a/frontend/src/assets/icons/svg/clipboard.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/code.svg b/frontend/src/assets/icons/svg/code.svg deleted file mode 100644 index 5f9c5abd5..000000000 --- a/frontend/src/assets/icons/svg/code.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/color.svg b/frontend/src/assets/icons/svg/color.svg deleted file mode 100644 index 44a81aab1..000000000 --- a/frontend/src/assets/icons/svg/color.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/component.svg b/frontend/src/assets/icons/svg/component.svg deleted file mode 100644 index 29c345809..000000000 --- a/frontend/src/assets/icons/svg/component.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/dashboard.svg b/frontend/src/assets/icons/svg/dashboard.svg deleted file mode 100644 index 5317d3702..000000000 --- a/frontend/src/assets/icons/svg/dashboard.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/date-range.svg b/frontend/src/assets/icons/svg/date-range.svg deleted file mode 100644 index fda571e70..000000000 --- a/frontend/src/assets/icons/svg/date-range.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/date.svg b/frontend/src/assets/icons/svg/date.svg deleted file mode 100644 index 52dc73eec..000000000 --- a/frontend/src/assets/icons/svg/date.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/dict.svg b/frontend/src/assets/icons/svg/dict.svg deleted file mode 100644 index 484937730..000000000 --- a/frontend/src/assets/icons/svg/dict.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/documentation.svg b/frontend/src/assets/icons/svg/documentation.svg deleted file mode 100644 index 704312289..000000000 --- a/frontend/src/assets/icons/svg/documentation.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/download.svg b/frontend/src/assets/icons/svg/download.svg deleted file mode 100644 index c89695134..000000000 --- a/frontend/src/assets/icons/svg/download.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/drag.svg b/frontend/src/assets/icons/svg/drag.svg deleted file mode 100644 index 4185d3cee..000000000 --- a/frontend/src/assets/icons/svg/drag.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/druid.svg b/frontend/src/assets/icons/svg/druid.svg deleted file mode 100644 index a2b4b4ed2..000000000 --- a/frontend/src/assets/icons/svg/druid.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/edit.svg b/frontend/src/assets/icons/svg/edit.svg deleted file mode 100644 index d26101f29..000000000 --- a/frontend/src/assets/icons/svg/edit.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/education.svg b/frontend/src/assets/icons/svg/education.svg deleted file mode 100644 index 7bfb01d18..000000000 --- a/frontend/src/assets/icons/svg/education.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/email.svg b/frontend/src/assets/icons/svg/email.svg deleted file mode 100644 index 74d25e21a..000000000 --- a/frontend/src/assets/icons/svg/email.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/enter.svg b/frontend/src/assets/icons/svg/enter.svg deleted file mode 100644 index f7cabf29e..000000000 --- a/frontend/src/assets/icons/svg/enter.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/example.svg b/frontend/src/assets/icons/svg/example.svg deleted file mode 100644 index 46f42b532..000000000 --- a/frontend/src/assets/icons/svg/example.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/excel.svg b/frontend/src/assets/icons/svg/excel.svg deleted file mode 100644 index 74d97b802..000000000 --- a/frontend/src/assets/icons/svg/excel.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/exit-fullscreen.svg b/frontend/src/assets/icons/svg/exit-fullscreen.svg deleted file mode 100644 index 485c128b6..000000000 --- a/frontend/src/assets/icons/svg/exit-fullscreen.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/eye-open.svg b/frontend/src/assets/icons/svg/eye-open.svg deleted file mode 100644 index 88dcc98e6..000000000 --- a/frontend/src/assets/icons/svg/eye-open.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/eye.svg b/frontend/src/assets/icons/svg/eye.svg deleted file mode 100644 index 16ed2d872..000000000 --- a/frontend/src/assets/icons/svg/eye.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/form.svg b/frontend/src/assets/icons/svg/form.svg deleted file mode 100644 index dcbaa185a..000000000 --- a/frontend/src/assets/icons/svg/form.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/fullscreen.svg b/frontend/src/assets/icons/svg/fullscreen.svg deleted file mode 100644 index 0e86b6fa8..000000000 --- a/frontend/src/assets/icons/svg/fullscreen.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/github.svg b/frontend/src/assets/icons/svg/github.svg deleted file mode 100644 index db0a0d430..000000000 --- a/frontend/src/assets/icons/svg/github.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/guide.svg b/frontend/src/assets/icons/svg/guide.svg deleted file mode 100644 index b27100179..000000000 --- a/frontend/src/assets/icons/svg/guide.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/icon.svg b/frontend/src/assets/icons/svg/icon.svg deleted file mode 100644 index 82be8eeed..000000000 --- a/frontend/src/assets/icons/svg/icon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/input.svg b/frontend/src/assets/icons/svg/input.svg deleted file mode 100644 index ab91381e6..000000000 --- a/frontend/src/assets/icons/svg/input.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/international.svg b/frontend/src/assets/icons/svg/international.svg deleted file mode 100644 index e9b56eee2..000000000 --- a/frontend/src/assets/icons/svg/international.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/job.svg b/frontend/src/assets/icons/svg/job.svg deleted file mode 100644 index 2a93a2519..000000000 --- a/frontend/src/assets/icons/svg/job.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/language.svg b/frontend/src/assets/icons/svg/language.svg deleted file mode 100644 index 0082b577a..000000000 --- a/frontend/src/assets/icons/svg/language.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/link.svg b/frontend/src/assets/icons/svg/link.svg deleted file mode 100644 index 48197ba4d..000000000 --- a/frontend/src/assets/icons/svg/link.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/list.svg b/frontend/src/assets/icons/svg/list.svg deleted file mode 100644 index 20259eddb..000000000 --- a/frontend/src/assets/icons/svg/list.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/lock.svg b/frontend/src/assets/icons/svg/lock.svg deleted file mode 100644 index 74fee543d..000000000 --- a/frontend/src/assets/icons/svg/lock.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/log.svg b/frontend/src/assets/icons/svg/log.svg deleted file mode 100644 index d879d33b6..000000000 --- a/frontend/src/assets/icons/svg/log.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/logininfor.svg b/frontend/src/assets/icons/svg/logininfor.svg deleted file mode 100644 index 267f84474..000000000 --- a/frontend/src/assets/icons/svg/logininfor.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/message.svg b/frontend/src/assets/icons/svg/message.svg deleted file mode 100644 index 14ca81728..000000000 --- a/frontend/src/assets/icons/svg/message.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/money.svg b/frontend/src/assets/icons/svg/money.svg deleted file mode 100644 index c1580de10..000000000 --- a/frontend/src/assets/icons/svg/money.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/monitor.svg b/frontend/src/assets/icons/svg/monitor.svg deleted file mode 100644 index bc308cb0f..000000000 --- a/frontend/src/assets/icons/svg/monitor.svg +++ /dev/null @@ -1,2 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/more-up.svg b/frontend/src/assets/icons/svg/more-up.svg deleted file mode 100644 index d30ac11c1..000000000 --- a/frontend/src/assets/icons/svg/more-up.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/nested.svg b/frontend/src/assets/icons/svg/nested.svg deleted file mode 100644 index 06713a86c..000000000 --- a/frontend/src/assets/icons/svg/nested.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/number.svg b/frontend/src/assets/icons/svg/number.svg deleted file mode 100644 index ad5ce9af2..000000000 --- a/frontend/src/assets/icons/svg/number.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/online.svg b/frontend/src/assets/icons/svg/online.svg deleted file mode 100644 index 330a20293..000000000 --- a/frontend/src/assets/icons/svg/online.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/password.svg b/frontend/src/assets/icons/svg/password.svg deleted file mode 100644 index 6c64defe3..000000000 --- a/frontend/src/assets/icons/svg/password.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/pdf.svg b/frontend/src/assets/icons/svg/pdf.svg deleted file mode 100644 index 957aa0cc3..000000000 --- a/frontend/src/assets/icons/svg/pdf.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/people.svg b/frontend/src/assets/icons/svg/people.svg deleted file mode 100644 index 2bd54aeb7..000000000 --- a/frontend/src/assets/icons/svg/people.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/peoples.svg b/frontend/src/assets/icons/svg/peoples.svg deleted file mode 100644 index aab852e52..000000000 --- a/frontend/src/assets/icons/svg/peoples.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/phone.svg b/frontend/src/assets/icons/svg/phone.svg deleted file mode 100644 index ab8e8c4e5..000000000 --- a/frontend/src/assets/icons/svg/phone.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/post.svg b/frontend/src/assets/icons/svg/post.svg deleted file mode 100644 index 2922c613b..000000000 --- a/frontend/src/assets/icons/svg/post.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/qq.svg b/frontend/src/assets/icons/svg/qq.svg deleted file mode 100644 index ee13d4ec2..000000000 --- a/frontend/src/assets/icons/svg/qq.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/question.svg b/frontend/src/assets/icons/svg/question.svg deleted file mode 100644 index cf75bd4be..000000000 --- a/frontend/src/assets/icons/svg/question.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/radio.svg b/frontend/src/assets/icons/svg/radio.svg deleted file mode 100644 index 0cde34521..000000000 --- a/frontend/src/assets/icons/svg/radio.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/rate.svg b/frontend/src/assets/icons/svg/rate.svg deleted file mode 100644 index aa3b14d7d..000000000 --- a/frontend/src/assets/icons/svg/rate.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/redis-list.svg b/frontend/src/assets/icons/svg/redis-list.svg deleted file mode 100644 index 98a15b2a6..000000000 --- a/frontend/src/assets/icons/svg/redis-list.svg +++ /dev/null @@ -1,2 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/redis.svg b/frontend/src/assets/icons/svg/redis.svg deleted file mode 100644 index 2f1d62dfc..000000000 --- a/frontend/src/assets/icons/svg/redis.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/row.svg b/frontend/src/assets/icons/svg/row.svg deleted file mode 100644 index 078099222..000000000 --- a/frontend/src/assets/icons/svg/row.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/search.svg b/frontend/src/assets/icons/svg/search.svg deleted file mode 100644 index 84233ddaa..000000000 --- a/frontend/src/assets/icons/svg/search.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/select.svg b/frontend/src/assets/icons/svg/select.svg deleted file mode 100644 index d6283828b..000000000 --- a/frontend/src/assets/icons/svg/select.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/server.svg b/frontend/src/assets/icons/svg/server.svg deleted file mode 100644 index eb287e36c..000000000 --- a/frontend/src/assets/icons/svg/server.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/shopping.svg b/frontend/src/assets/icons/svg/shopping.svg deleted file mode 100644 index 87513e7c5..000000000 --- a/frontend/src/assets/icons/svg/shopping.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/size.svg b/frontend/src/assets/icons/svg/size.svg deleted file mode 100644 index ddb25b8d5..000000000 --- a/frontend/src/assets/icons/svg/size.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/skill.svg b/frontend/src/assets/icons/svg/skill.svg deleted file mode 100644 index a3b731218..000000000 --- a/frontend/src/assets/icons/svg/skill.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/slider.svg b/frontend/src/assets/icons/svg/slider.svg deleted file mode 100644 index fbe4f39f0..000000000 --- a/frontend/src/assets/icons/svg/slider.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/star.svg b/frontend/src/assets/icons/svg/star.svg deleted file mode 100644 index 6cf86e66a..000000000 --- a/frontend/src/assets/icons/svg/star.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/swagger.svg b/frontend/src/assets/icons/svg/swagger.svg deleted file mode 100644 index 05d4e7bce..000000000 --- a/frontend/src/assets/icons/svg/swagger.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/switch.svg b/frontend/src/assets/icons/svg/switch.svg deleted file mode 100644 index 0ba61e38d..000000000 --- a/frontend/src/assets/icons/svg/switch.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/system.svg b/frontend/src/assets/icons/svg/system.svg deleted file mode 100644 index 5992593e0..000000000 --- a/frontend/src/assets/icons/svg/system.svg +++ /dev/null @@ -1,2 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/tab.svg b/frontend/src/assets/icons/svg/tab.svg deleted file mode 100644 index b4b48e480..000000000 --- a/frontend/src/assets/icons/svg/tab.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/table.svg b/frontend/src/assets/icons/svg/table.svg deleted file mode 100644 index 0e3dc9dea..000000000 --- a/frontend/src/assets/icons/svg/table.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/textarea.svg b/frontend/src/assets/icons/svg/textarea.svg deleted file mode 100644 index 2709f292e..000000000 --- a/frontend/src/assets/icons/svg/textarea.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/theme.svg b/frontend/src/assets/icons/svg/theme.svg deleted file mode 100644 index 5982a2f78..000000000 --- a/frontend/src/assets/icons/svg/theme.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/time-range.svg b/frontend/src/assets/icons/svg/time-range.svg deleted file mode 100644 index 13c1202bd..000000000 --- a/frontend/src/assets/icons/svg/time-range.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/time.svg b/frontend/src/assets/icons/svg/time.svg deleted file mode 100644 index b376e32a6..000000000 --- a/frontend/src/assets/icons/svg/time.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/tool.svg b/frontend/src/assets/icons/svg/tool.svg deleted file mode 100644 index 48e0e3573..000000000 --- a/frontend/src/assets/icons/svg/tool.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/tree-table.svg b/frontend/src/assets/icons/svg/tree-table.svg deleted file mode 100644 index 8aafdb829..000000000 --- a/frontend/src/assets/icons/svg/tree-table.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/tree.svg b/frontend/src/assets/icons/svg/tree.svg deleted file mode 100644 index dd4b7dd22..000000000 --- a/frontend/src/assets/icons/svg/tree.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/upload.svg b/frontend/src/assets/icons/svg/upload.svg deleted file mode 100644 index bae49c0a5..000000000 --- a/frontend/src/assets/icons/svg/upload.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/user.svg b/frontend/src/assets/icons/svg/user.svg deleted file mode 100644 index 0ba0716a6..000000000 --- a/frontend/src/assets/icons/svg/user.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/validCode.svg b/frontend/src/assets/icons/svg/validCode.svg deleted file mode 100644 index cfb10214c..000000000 --- a/frontend/src/assets/icons/svg/validCode.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/wechat.svg b/frontend/src/assets/icons/svg/wechat.svg deleted file mode 100644 index c586e5511..000000000 --- a/frontend/src/assets/icons/svg/wechat.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svg/zip.svg b/frontend/src/assets/icons/svg/zip.svg deleted file mode 100644 index f806fc482..000000000 --- a/frontend/src/assets/icons/svg/zip.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/icons/svgo.yml b/frontend/src/assets/icons/svgo.yml deleted file mode 100644 index d11906aec..000000000 --- a/frontend/src/assets/icons/svgo.yml +++ /dev/null @@ -1,22 +0,0 @@ -# replace default config - -# multipass: true -# full: true - -plugins: - - # - name - # - # or: - # - name: false - # - name: true - # - # or: - # - name: - # param1: 1 - # param2: 2 - -- removeAttrs: - attrs: - - 'fill' - - 'fill-rule' diff --git a/frontend/src/assets/images/dark.svg b/frontend/src/assets/images/dark.svg deleted file mode 100644 index f646bd7ea..000000000 --- a/frontend/src/assets/images/dark.svg +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/frontend/src/assets/images/light.svg b/frontend/src/assets/images/light.svg deleted file mode 100644 index ab7cc088f..000000000 --- a/frontend/src/assets/images/light.svg +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/frontend/src/assets/images/login-background.jpg b/frontend/src/assets/images/login-background.jpg deleted file mode 100644 index 8a89eb829..000000000 Binary files a/frontend/src/assets/images/login-background.jpg and /dev/null differ diff --git a/frontend/src/assets/images/pay.png b/frontend/src/assets/images/pay.png deleted file mode 100644 index bb8b96723..000000000 Binary files a/frontend/src/assets/images/pay.png and /dev/null differ diff --git a/frontend/src/assets/images/profile.jpg b/frontend/src/assets/images/profile.jpg deleted file mode 100644 index b3a940b21..000000000 Binary files a/frontend/src/assets/images/profile.jpg and /dev/null differ diff --git a/frontend/src/assets/logo/logo.png b/frontend/src/assets/logo/logo.png deleted file mode 100644 index e26376026..000000000 Binary files a/frontend/src/assets/logo/logo.png and /dev/null differ diff --git a/frontend/src/assets/styles/btn.scss b/frontend/src/assets/styles/btn.scss deleted file mode 100644 index f2db674ec..000000000 --- a/frontend/src/assets/styles/btn.scss +++ /dev/null @@ -1,145 +0,0 @@ -@import './variables.scss'; - -@mixin colorBtn($color) { - background: $color; - - &:hover { - color: $color; - - &:before, - &:after { - background: $color; - } - } -} - -.blue-btn { - @include colorBtn($blue) -} - -.light-blue-btn { - @include colorBtn($light-blue) -} - -.red-btn { - @include colorBtn($red) -} - -.pink-btn { - @include colorBtn($pink) -} - -.green-btn { - @include colorBtn($green) -} - -.tiffany-btn { - @include colorBtn($tiffany) -} - -.yellow-btn { - @include colorBtn($yellow) -} - -.pan-btn { - font-size: 14px; - color: #fff; - padding: 14px 36px; - border-radius: 8px; - border: none; - outline: none; - transition: 600ms ease all; - position: relative; - display: inline-block; - - &:hover { - background: #fff; - - &:before, - &:after { - width: 100%; - transition: 600ms ease all; - } - } - - &:before, - &:after { - content: ''; - position: absolute; - top: 0; - right: 0; - height: 2px; - width: 0; - transition: 400ms ease all; - } - - &::after { - right: inherit; - top: inherit; - left: 0; - bottom: 0; - } -} - -.custom-button { - display: inline-block; - line-height: 1; - white-space: nowrap; - cursor: pointer; - background: #fff; - color: #fff; - -webkit-appearance: none; - text-align: center; - box-sizing: border-box; - outline: 0; - margin: 0; - padding: 10px 15px; - font-size: 14px; - border-radius: 4px; -} - -// ================= 教学任务模块操作按钮(灰 / 主色 / 蓝色) ================= -.gray-btn, -.primary-btn, -.blue-btn { - display: inline-block; - height: 30px; - line-height: 1; - padding: 0 15px; - font-size: 13px; - border-radius: 4px; - border: 1px solid transparent; - cursor: pointer; - vertical-align: middle; - white-space: nowrap; - transition: all 0.2s; -} - -.gray-btn { - background: #f5f7fa; - color: #333; - border-color: #dcdfe6; - - &:hover { - background: #e4e7ed; - } -} - -.primary-btn { - background: #00875a; - color: #fff; - - &:hover { - background: #006b47; - } -} - -.blue-btn { - background: #3a71a8; - color: #fff; - - &:hover { - background: #2f5e8c; - color: #fff; - } -} diff --git a/frontend/src/assets/styles/element-ui.scss b/frontend/src/assets/styles/element-ui.scss deleted file mode 100644 index 8e2301bf9..000000000 --- a/frontend/src/assets/styles/element-ui.scss +++ /dev/null @@ -1,92 +0,0 @@ -// cover some element-ui styles - -.el-breadcrumb__inner, -.el-breadcrumb__inner a { - font-weight: 400 !important; -} - -.el-upload { - input[type="file"] { - display: none !important; - } -} - -.el-upload__input { - display: none; -} - -.cell { - .el-tag { - margin-right: 0px; - } -} - -.small-padding { - .cell { - padding-left: 5px; - padding-right: 5px; - } -} - -.fixed-width { - .el-button--mini { - padding: 7px 10px; - width: 60px; - } -} - -.status-col { - .cell { - padding: 0 10px; - text-align: center; - - .el-tag { - margin-right: 0px; - } - } -} - -// to fixed https://github.com/ElemeFE/element/issues/2461 -.el-dialog { - transform: none; - left: 0; - position: relative; - margin: 0 auto; -} - -// refine element ui upload -.upload-container { - .el-upload { - width: 100%; - - .el-upload-dragger { - width: 100%; - height: 200px; - } - } -} - -// dropdown -.el-dropdown-menu { - a { - display: block - } -} - -// fix date-picker ui bug in filter-item -.el-range-editor.el-input__inner { - display: inline-flex !important; -} - -// to fix el-date-picker css style -.el-range-separator { - box-sizing: content-box; -} - -.el-menu--collapse - > div - > .el-submenu - > .el-submenu__title - .el-submenu__icon-arrow { - display: none; -} \ No newline at end of file diff --git a/frontend/src/assets/styles/element-variables.scss b/frontend/src/assets/styles/element-variables.scss deleted file mode 100644 index e7a9d4ac7..000000000 --- a/frontend/src/assets/styles/element-variables.scss +++ /dev/null @@ -1,31 +0,0 @@ -/** -* I think element-ui's default theme color is too light for long-term use. -* So I modified the default color and you can modify it to your liking. -**/ - -/* theme color */ -$--color-primary: #0b6b55; -$--color-success: #238b68; -$--color-warning: #c58a22; -$--color-danger: #c94b52; -// $--color-info: #1E1E1E; - -$--button-font-weight: 500; - -// $--color-text-regular: #1f2d3d; - -$--border-color-light: #dfe4ed; -$--border-color-lighter: #e6ebf5; - -$--table-border: 1px solid #dfe6ec; - -/* icon font path, required */ -$--font-path: '~element-ui/lib/theme-chalk/fonts'; - -@import "~element-ui/packages/theme-chalk/src/index"; - -// the :export directive is the magic sauce for webpack -// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass -:export { - theme: $--color-primary; -} diff --git a/frontend/src/assets/styles/index.scss b/frontend/src/assets/styles/index.scss deleted file mode 100644 index b2cce8aa8..000000000 --- a/frontend/src/assets/styles/index.scss +++ /dev/null @@ -1,248 +0,0 @@ -@import './variables.scss'; -@import './mixin.scss'; -@import './transition.scss'; -@import './element-ui.scss'; -@import './sidebar.scss'; -@import './btn.scss'; -@import './education-theme.scss'; - -/* ================= 系统主题色(教育绿) ================= */ -:root { - /* 基础绿 */ - --edu-green: #0b6b55; - --edu-green-hover: #085442; - --edu-green-bg: #e8f3ef; - - /* 主色:导航、按钮、主题色 */ - --edu-green-primary: #0b6b55; - /* hover 加深 */ - --edu-green-dark: #084c3f; - /* 浅色背景、标签底色 */ - --edu-green-light: #e8f3ef; -} - -body { - height: 100%; - -moz-osx-font-smoothing: grayscale; - -webkit-font-smoothing: antialiased; - text-rendering: optimizeLegibility; - font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; -} - -label { - font-weight: 700; -} - -html { - height: 100%; - box-sizing: border-box; -} - -#app { - height: 100%; -} - -/* ================= 全局自适应加固 ================= - 与 src/utils/adaptive.js 的视口等比缩放配合, - 兜底避免极端情况下出现页面级横向溢出与内容崩塌。 */ -html, -body { - width: 100%; -} - -body { - /* 禁止页面级横向滚动,防止因个别固定宽度元素把整页撑破; - 表格自身的横向滚动由 el-table 内部滚动容器承担,不受影响 */ - overflow-x: hidden; -} - -/* 弹性布局子项允许收缩,避免 flex 容器被子项固有宽度撑破 */ -#app, -.app-wrapper, -.main-container, -.lower-container { - min-width: 0; -} - -/* ===== Element 浮层逆缩放(配合 adaptive.js) ===== - 挂到 body 的浮层(下拉/气泡/日期/对话框/消息等)基于 getBoundingClientRect 定位, - 该值受 html 的 zoom 缩放影响;若浮层自身也继承同一 zoom,坐标会被“重复缩放”而错位。 - 这里用 adaptive.js 注入的 --adaptive-scale-inv(= 1/当前缩放倍数)把这些浮层还原为 1:1, - 使其与触发元素在视觉坐标上正确对齐。缩放=1 时该变量为 1,不产生任何影响。 */ -:root { - --adaptive-scale: 1; -} - -.el-popper, -.el-select-dropdown, -.el-dropdown-menu, -.el-picker-panel, -.el-cascader__dropdown, -.el-message-box__wrapper, -.el-dialog__wrapper, -.el-message, -.el-notification, -.el-loading-mask, -.v-modal { - zoom: var(--adaptive-scale-inv, 1); -} - -/* 通用长文本换行,避免 url/数字/英文长串将布局撑破 */ -a, -.el-button, -.el-table .cell, -.el-form-item__content, -.el-form-item__label { - word-break: break-word; -} - -*, -*:before, -*:after { - box-sizing: inherit; -} - -.no-padding { - padding: 0px !important; -} - -.padding-content { - padding: 4px 0; -} - -a:focus, -a:active { - outline: none; -} - -a, -a:focus, -a:hover { - cursor: pointer; - color: inherit; - text-decoration: none; -} - -div:focus { - outline: none; -} - -.fr { - float: right; -} - -.fl { - float: left; -} - -.pr-5 { - padding-right: 5px; -} - -.pl-5 { - padding-left: 5px; -} - -.block { - display: block; -} - -.pointer { - cursor: pointer; -} - -.inlineBlock { - display: block; -} - -.clearfix { - &:after { - visibility: hidden; - display: block; - font-size: 0; - content: " "; - clear: both; - height: 0; - } -} - -aside { - background: #eef1f6; - padding: 8px 24px; - margin-bottom: 20px; - border-radius: 2px; - display: block; - line-height: 32px; - font-size: 16px; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; - color: #2c3e50; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - - a { - color: var(--edu-green-primary); - cursor: pointer; - - &:hover { - color: var(--edu-green-dark); - } - } -} - -//main-container全局样式 -.app-container { - padding: 20px; -} - -.components-container { - margin: 30px 50px; - position: relative; -} - -.text-center { - text-align: center -} - -.sub-navbar { - height: 50px; - line-height: 50px; - position: relative; - width: 100%; - text-align: right; - padding-right: 20px; - transition: 600ms ease position; - background: linear-gradient(90deg, var(--edu-green-primary) 0%, var(--edu-green-primary) 0%, var(--edu-green-dark) 100%, var(--edu-green-dark) 100%); - - .subtitle { - font-size: 20px; - color: #fff; - } - - &.draft { - background: #d0d0d0; - } - - &.deleted { - background: #d0d0d0; - } -} - -.link-type, -.link-type:focus { - color: var(--edu-green-primary); - cursor: pointer; - - &:hover { - color: var(--edu-green-dark); - } -} - -.filter-container { - padding-bottom: 10px; - - .filter-item { - display: inline-block; - vertical-align: middle; - margin-bottom: 10px; - } -} diff --git a/frontend/src/assets/styles/mixin.scss b/frontend/src/assets/styles/mixin.scss deleted file mode 100644 index a9f3bc7ce..000000000 --- a/frontend/src/assets/styles/mixin.scss +++ /dev/null @@ -1,7 +0,0 @@ -@mixin clearfix { - &:after { - content: ""; - display: table; - clear: both; - } -} diff --git a/frontend/src/assets/styles/roomroot.scss b/frontend/src/assets/styles/roomroot.scss deleted file mode 100644 index de603b397..000000000 --- a/frontend/src/assets/styles/roomroot.scss +++ /dev/null @@ -1,521 +0,0 @@ -/** -* 通用css样式布局处理 -* Copyright (c) 2019 roomroot -*/ - -/** 基础通用 **/ -.pt5 { - padding-top: 5px; -} - -.pr5 { - padding-right: 5px; -} - -.pb5 { - padding-bottom: 5px; -} - -.mt5 { - margin-top: 5px; -} - -.mr5 { - margin-right: 5px; -} - -.mb5 { - margin-bottom: 5px; -} - -.mb8 { - margin-bottom: 8px; -} - -.ml5 { - margin-left: 5px; -} - -.mt10 { - margin-top: 10px; -} - -.mr10 { - margin-right: 10px; -} - -.mb10 { - margin-bottom: 10px; -} -.ml10 { - margin-left: 10px; -} - -.mt20 { - margin-top: 20px; -} - -.mr20 { - margin-right: 20px; -} - -.mb20 { - margin-bottom: 20px; -} -.ml20 { - margin-left: 20px; -} - -.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 { - font-family: inherit; - font-weight: 500; - line-height: 1.1; - color: inherit; -} - -.el-message-box__status + .el-message-box__message{ - word-break: break-word; -} - -.el-dialog:not(.is-fullscreen) { - margin-top: 6vh !important; -} - -.el-dialog__body { - padding: 8px 20px !important; -} - -.el-dialog__wrapper.scrollbar .el-dialog .el-dialog__body { - overflow: auto; - overflow-x: hidden; - max-height: 70vh; - padding: 10px 20px 0; -} - -.el-table { - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - - .el-table__header-wrapper, .el-table__fixed-header-wrapper { - th { - word-break: break-word; - background-color: #f8f8f9; - color: #515a6e; - height: 40px; - font-size: 13px; - } - } - - .el-table__body-wrapper { - // 宽表格统一通过内容区拖拽横向查看,隐藏重复的底部滚动条但保留滚动能力。 - -ms-overflow-style: none; - scrollbar-width: none; - - &::-webkit-scrollbar { - display: none; - width: 0; - height: 0; - } - - .el-button [class*="el-icon-"] + span { - margin-left: 1px; - } - } - - // 表格横向拖拽滚动:拖拽过程中光标保持默认箭头,不切换为“抓手” - .el-table__body-wrapper.is-dragging, - .el-table__fixed-body-wrapper.is-dragging { - cursor: default; - } -} - -/* 表格横拖期间锁定整页光标与文本选中: - 避免光标划过按钮/链接时闪变成手型、以及拖拽过程误选中文字 */ -body.el-table-dragging, -body.el-table-dragging * { - user-select: none !important; - cursor: default !important; -} - -/* 原生表格同样禁止选中文本,避免横向滑动/滚动时误触发复制前的文本选中 */ -table { - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -/** 表单布局 **/ -.form-header { - font-size: 15px; - color: #6379bb; - border-bottom: 1px solid #ddd; - margin: 8px 10px 25px 10px; - padding-bottom: 5px -} - -/** 表格布局 **/ -.pagination-container { - display: flex; - justify-content: flex-end; - margin-top: 20px; -} - -/* tree border */ -.tree-border { - margin-top: 5px; - border: 1px solid #e5e6e7; - background: #FFFFFF none; - border-radius: 4px; -} - -/* horizontal el menu */ -.el-menu--horizontal .el-menu-item .svg-icon + span, -.el-menu--horizontal .el-submenu__title .svg-icon + span { - margin-left: 3px; -} - -.el-menu--horizontal .el-menu--popup { - min-width: 120px !important; -} - -@media (max-width: 768px) { - .pagination-container .el-pagination > .el-pagination__jump { - display: none !important; - } - .pagination-container .el-pagination > .el-pagination__sizes { - display: none !important; - } -} - -.el-table .fixed-width .el-button--mini { - padding-left: 0; - padding-right: 0; - width: inherit; -} - -/** 表格更多操作下拉样式 */ -.el-table .el-dropdown-link,.el-table .el-dropdown-selfdefine { - cursor: pointer; - margin-left: 5px; -} - -.el-table .el-dropdown, .el-icon-arrow-down { - font-size: 12px; -} - -.el-tree-node__content > .el-checkbox { - margin-right: 8px; -} - -.list-group-striped > .list-group-item { - border-left: 0; - border-right: 0; - border-radius: 0; - padding-left: 0; - padding-right: 0; -} - -.list-group { - padding-left: 0px; - list-style: none; -} - -.list-group-item { - border-bottom: 1px solid #e7eaec; - border-top: 1px solid #e7eaec; - margin-bottom: -1px; - padding: 11px 0px; - font-size: 13px; -} - -.pull-right { - float: right !important; -} - -.el-card__header { - padding: 14px 15px 7px; - min-height: 40px; -} - -.el-card__body { - padding: 15px 20px 20px 20px; -} - -.card-box { - margin-bottom: 10px; -} - -/* button color */ -.el-button--cyan.is-active, -.el-button--cyan:active { - background: #20B2AA; - border-color: #20B2AA; - color: #FFFFFF; -} - -.el-button--cyan:focus, -.el-button--cyan:hover { - background: #48D1CC; - border-color: #48D1CC; - color: #FFFFFF; -} - -.el-button--cyan { - background-color: #20B2AA; - border-color: #20B2AA; - color: #FFFFFF; -} - -/** 详细卡片样式 */ -.detail-drawer { - .el-drawer__header { - margin-bottom: 6px; - padding: 8px 12px 6px; - font-size: 15px; - color: #303133; - background: #f8f8f8; - } - .section-header { - font-size: 15px; - color: #6379bb; - border-bottom: 1px solid #ddd; - margin: 12px 0 16px 0; - padding-bottom: 8px; - } - .drawer-content { - padding: 0 20px 20px 20px; - .info-item { - display: flex; - align-items: flex-start; - padding: 8px 0; - min-height: 40px; - } - .info-label { - flex-shrink: 0; - width: 200px; - color: #606266; - font-size: 13px; - line-height: 1.6; - padding-top: 4px; - text-align: right; - margin-right: 14px; - } - .info-value { - flex: 1; - color: #303133; - font-size: 13px; - font-weight: 500; - line-height: 1.6; - word-break: break-all; - padding-top: 4px; - min-height: 1.6em; - &.plaintext { - border-bottom: 1px dashed #dde1e6; - } - } - } -} - -.detail-wrap { padding: 0 4px; } - -.detail-card { - border: 1px solid #ebeef5; - border-radius: 6px; - margin-bottom: 14px; - overflow: hidden; -} - -.detail-card-title { - background: #f7f9fb; - padding: 8px 16px; - font-size: 13px; - font-weight: 600; - color: #333; - border-bottom: 1px solid #ebeef5; -} -.detail-card-title i { margin-right: 5px; color: #00875A; } - -.detail-row { padding: 0 8px; } - -.detail-item { - display: flex; - align-items: flex-start; - padding: 10px 8px; - font-size: 13px; - border-bottom: 1px solid #f5f7fa; -} -.detail-item:last-child { border-bottom: none; } - -.detail-label { - flex-shrink: 0; - width: 72px; - color: #909399; - margin-right: 12px; -} -.detail-value { color: #303133; flex: 1; word-break: break-all; } -.detail-location { color: #999; font-size: 12px; } - -.method-tag { - display: inline-block; - padding: 1px 7px; - border-radius: 3px; - font-size: 11px; - font-weight: 700; - margin-right: 6px; - vertical-align: middle; -} -.mono { font-family: Consolas, 'SFMono-Regular', monospace; font-size: 12px; } -.code-body { padding: 14px; } -.code-wrap { - background: #f7f9fb; - border: 1px solid #e8ecf0; - border-radius: 4px; - overflow: hidden; - max-height: 260px; - position: relative; -} -.code-action { - position: absolute; - top: 8px; - right: 8px; - z-index: 10; - margin: 0; - padding: 0; -} -.code-action .el-button { - height: 24px; - font-size: 12px; - padding: 4px 8px; - background: rgba(255, 255, 255, 0.9); - border: 1px solid #dcdcdc; -} -.code-action .el-button:hover { - background: #ffffff; - border-color: #00875A; -} -.code-pre { - margin: 0; - padding: 12px 14px; - font-size: 12px; - line-height: 1.6; - font-family: Consolas, 'SFMono-Regular', monospace; - color: #444; - white-space: pre-wrap; - word-break: break-all; - overflow: auto; - max-height: 240px; - display: block; -} - -/* tree-sidebar content */ -.tree-sidebar-manage-wrap { - display: flex; - gap: 0; - min-height: calc(100vh - 130px); - padding: 0 !important; - overflow: hidden; -} - -.tree-sidebar-content { - flex: 1; - min-width: 0; - overflow: hidden; - background: #fff; - - .content-inner { - padding: 12px 16px; - height: 100%; - overflow-y: auto; - } -} - -/* error */ -.error-title { color: #c0392b !important; } -.error-title i { color: #c0392b !important; } -.error-body { padding: 12px 16px; } -.error-msg { - background: #fff8f8; - border-left: 3px solid #e74c3c; - border-radius: 3px; - padding: 8px 12px; - color: #c0392b; - font-size: 12px; - line-height: 1.7; - word-break: break-all; - white-space: pre-wrap; -} - -/* http method */ -.method-GET { background: #e8f5e9; color: #27ae60; } -.method-POST { background: #e3f2fd; color: #1565c0; } -.method-PUT { background: #fff3e0; color: #e65100; } -.method-DELETE { background: #ffebee; color: #c62828; } - -/* text color */ -.text-navy { - color: #1ab394; -} - -.text-primary { - color: inherit; -} - -.text-success { - color: #1c84c6; -} - -.text-info { - color: #23c6c8; -} - -.text-warning { - color: #f8ac59; -} - -.text-danger { - color: #ed5565; -} - -.text-muted { - color: #888888; -} - -/* image */ -.img-circle { - border-radius: 50%; -} - -.img-lg { - width: 120px; - height: 120px; -} - -.avatar-upload-preview { - position: relative; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 200px; - height: 200px; - border-radius: 50%; - box-shadow: 0 0 4px #ccc; - overflow: hidden; -} - -/* 拖拽列样式 */ -.allowDrag { cursor: grab; } -.allowDrag:active { cursor: grabbing; } - -.sortable-ghost { - opacity: .8; - color: #fff !important; - background: #42b983 !important; -} - -.top-right-btn { - position: relative; - float: right; -} diff --git a/frontend/src/assets/styles/ruoyi.scss b/frontend/src/assets/styles/ruoyi.scss deleted file mode 100644 index c45e0575e..000000000 --- a/frontend/src/assets/styles/ruoyi.scss +++ /dev/null @@ -1,487 +0,0 @@ -/** -* 通用css样式布局处理 -* Copyright (c) 2019 roomroot -*/ - -/** 基础通用 **/ -.pt5 { - padding-top: 5px; -} - -.pr5 { - padding-right: 5px; -} - -.pb5 { - padding-bottom: 5px; -} - -.mt5 { - margin-top: 5px; -} - -.mr5 { - margin-right: 5px; -} - -.mb5 { - margin-bottom: 5px; -} - -.mb8 { - margin-bottom: 8px; -} - -.ml5 { - margin-left: 5px; -} - -.mt10 { - margin-top: 10px; -} - -.mr10 { - margin-right: 10px; -} - -.mb10 { - margin-bottom: 10px; -} -.ml10 { - margin-left: 10px; -} - -.mt20 { - margin-top: 20px; -} - -.mr20 { - margin-right: 20px; -} - -.mb20 { - margin-bottom: 20px; -} -.ml20 { - margin-left: 20px; -} - -.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 { - font-family: inherit; - font-weight: 500; - line-height: 1.1; - color: inherit; -} - -.el-message-box__status + .el-message-box__message{ - word-break: break-word; -} - -.el-dialog:not(.is-fullscreen) { - margin-top: 6vh !important; -} - -.el-dialog__body { - padding: 8px 20px !important; -} - -.el-dialog__wrapper.scrollbar .el-dialog .el-dialog__body { - overflow: auto; - overflow-x: hidden; - max-height: 70vh; - padding: 10px 20px 0; -} - -.el-table { - th { - word-break: break-word; - background-color: #f8f8f9; - color: #515a6e; - height: 40px; - font-size: 13px; - text-align: center; - - .cell { - text-align: center; - } - } - - .el-table__body-wrapper { - .el-button [class*="el-icon-"] + span { - margin-left: 1px; - } - } -} - -/** 表单布局 **/ -.form-header { - font-size: 15px; - color: #6379bb; - border-bottom: 1px solid #ddd; - margin: 8px 10px 25px 10px; - padding-bottom: 5px -} - -/** 表格布局 **/ -.pagination-container { - display: flex; - justify-content: flex-end; - margin-top: 20px; -} - -/* tree border */ -.tree-border { - margin-top: 5px; - border: 1px solid #e5e6e7; - background: #FFFFFF none; - border-radius: 4px; -} - -/* horizontal el menu */ -.el-menu--horizontal .el-menu-item .svg-icon + span, -.el-menu--horizontal .el-submenu__title .svg-icon + span { - margin-left: 3px; -} - -.el-menu--horizontal .el-menu--popup { - min-width: 120px !important; -} - -@media (max-width: 768px) { - .pagination-container .el-pagination > .el-pagination__jump { - display: none !important; - } - .pagination-container .el-pagination > .el-pagination__sizes { - display: none !important; - } -} - -.el-table .fixed-width .el-button--mini { - padding-left: 0; - padding-right: 0; - width: inherit; -} - -/** 表格更多操作下拉样式 */ -.el-table .el-dropdown-link,.el-table .el-dropdown-selfdefine { - cursor: pointer; - margin-left: 5px; -} - -.el-table .el-dropdown, .el-icon-arrow-down { - font-size: 12px; -} - -.el-tree-node__content > .el-checkbox { - margin-right: 8px; -} - -.list-group-striped > .list-group-item { - border-left: 0; - border-right: 0; - border-radius: 0; - padding-left: 0; - padding-right: 0; -} - -.list-group { - padding-left: 0px; - list-style: none; -} - -.list-group-item { - border-bottom: 1px solid #e7eaec; - border-top: 1px solid #e7eaec; - margin-bottom: -1px; - padding: 11px 0px; - font-size: 13px; -} - -.pull-right { - float: right !important; -} - -.el-card__header { - padding: 14px 15px 7px; - min-height: 40px; -} - -.el-card__body { - padding: 15px 20px 20px 20px; -} - -.card-box { - margin-bottom: 10px; -} - -/* button color */ -.el-button--cyan.is-active, -.el-button--cyan:active { - background: #20B2AA; - border-color: #20B2AA; - color: #FFFFFF; -} - -.el-button--cyan:focus, -.el-button--cyan:hover { - background: #48D1CC; - border-color: #48D1CC; - color: #FFFFFF; -} - -.el-button--cyan { - background-color: #20B2AA; - border-color: #20B2AA; - color: #FFFFFF; -} - -/** 详细卡片样式 */ -.detail-drawer { - .el-drawer__header { - margin-bottom: 6px; - padding: 8px 12px 6px; - font-size: 15px; - color: #303133; - background: #f8f8f8; - } - .section-header { - font-size: 15px; - color: #6379bb; - border-bottom: 1px solid #ddd; - margin: 12px 0 16px 0; - padding-bottom: 8px; - } - .drawer-content { - padding: 0 20px 20px 20px; - .info-item { - display: flex; - align-items: flex-start; - padding: 8px 0; - min-height: 40px; - } - .info-label { - flex-shrink: 0; - width: 200px; - color: #606266; - font-size: 13px; - line-height: 1.6; - padding-top: 4px; - text-align: right; - margin-right: 14px; - } - .info-value { - flex: 1; - color: #303133; - font-size: 13px; - font-weight: 500; - line-height: 1.6; - word-break: break-all; - padding-top: 4px; - min-height: 1.6em; - &.plaintext { - border-bottom: 1px dashed #dde1e6; - } - } - } -} - -.detail-wrap { padding: 0 4px; } - -.detail-card { - border: 1px solid #ebeef5; - border-radius: 6px; - margin-bottom: 14px; - overflow: hidden; -} - -.detail-card-title { - background: #f7f9fb; - padding: 8px 16px; - font-size: 13px; - font-weight: 600; - color: #333; - border-bottom: 1px solid #ebeef5; -} -.detail-card-title i { margin-right: 5px; color: #00875A; } - -.detail-row { padding: 0 8px; } - -.detail-item { - display: flex; - align-items: flex-start; - padding: 10px 8px; - font-size: 13px; - border-bottom: 1px solid #f5f7fa; -} -.detail-item:last-child { border-bottom: none; } - -.detail-label { - flex-shrink: 0; - width: 72px; - color: #909399; - margin-right: 12px; -} -.detail-value { color: #303133; flex: 1; word-break: break-all; } -.detail-location { color: #999; font-size: 12px; } - -.method-tag { - display: inline-block; - padding: 1px 7px; - border-radius: 3px; - font-size: 11px; - font-weight: 700; - margin-right: 6px; - vertical-align: middle; -} -.mono { font-family: Consolas, 'SFMono-Regular', monospace; font-size: 12px; } -.code-body { padding: 14px; } -.code-wrap { - background: #f7f9fb; - border: 1px solid #e8ecf0; - border-radius: 4px; - overflow: hidden; - max-height: 260px; - position: relative; -} -.code-action { - position: absolute; - top: 8px; - right: 8px; - z-index: 10; - margin: 0; - padding: 0; -} -.code-action .el-button { - height: 24px; - font-size: 12px; - padding: 4px 8px; - background: rgba(255, 255, 255, 0.9); - border: 1px solid #dcdcdc; -} -.code-action .el-button:hover { - background: #ffffff; - border-color: #00875A; -} -.code-pre { - margin: 0; - padding: 12px 14px; - font-size: 12px; - line-height: 1.6; - font-family: Consolas, 'SFMono-Regular', monospace; - color: #444; - white-space: pre-wrap; - word-break: break-all; - overflow: auto; - max-height: 240px; - display: block; -} - -/* tree-sidebar content */ -.tree-sidebar-manage-wrap { - display: flex; - gap: 0; - min-height: calc(100vh - 130px); - padding: 0 !important; - overflow: hidden; -} - -.tree-sidebar-content { - flex: 1; - min-width: 0; - overflow: hidden; - background: #fff; - - .content-inner { - padding: 12px 16px; - height: 100%; - overflow-y: auto; - } -} - -/* error */ -.error-title { color: #c0392b !important; } -.error-title i { color: #c0392b !important; } -.error-body { padding: 12px 16px; } -.error-msg { - background: #fff8f8; - border-left: 3px solid #e74c3c; - border-radius: 3px; - padding: 8px 12px; - color: #c0392b; - font-size: 12px; - line-height: 1.7; - word-break: break-all; - white-space: pre-wrap; -} - -/* http method */ -.method-GET { background: #e8f5e9; color: #27ae60; } -.method-POST { background: #e3f2fd; color: #1565c0; } -.method-PUT { background: #fff3e0; color: #e65100; } -.method-DELETE { background: #ffebee; color: #c62828; } - -/* text color */ -.text-navy { - color: #1ab394; -} - -.text-primary { - color: inherit; -} - -.text-success { - color: #1c84c6; -} - -.text-info { - color: #23c6c8; -} - -.text-warning { - color: #f8ac59; -} - -.text-danger { - color: #ed5565; -} - -.text-muted { - color: #888888; -} - -/* image */ -.img-circle { - border-radius: 50%; -} - -.img-lg { - width: 120px; - height: 120px; -} - -.avatar-upload-preview { - position: relative; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 200px; - height: 200px; - border-radius: 50%; - box-shadow: 0 0 4px #ccc; - overflow: hidden; -} - -/* 拖拽列样式 */ -.allowDrag { cursor: grab; } -.allowDrag:active { cursor: grabbing; } - -.sortable-ghost { - opacity: .8; - color: #fff !important; - background: #42b983 !important; -} - -.top-right-btn { - position: relative; - float: right; -} diff --git a/frontend/src/assets/styles/sidebar.scss b/frontend/src/assets/styles/sidebar.scss deleted file mode 100644 index 667fd54f5..000000000 --- a/frontend/src/assets/styles/sidebar.scss +++ /dev/null @@ -1,327 +0,0 @@ -#app { - - .sidebar-container { - -webkit-transition: width .28s; - transition: width 0.28s; - width: $base-sidebar-width !important; - background-color: $base-menu-background; - border-right: 1px solid rgba(3, 49, 40, 0.32); - box-shadow: 4px 0 14px rgba(8, 51, 42, 0.08); - height: 100%; - position: relative; - overflow: hidden; - - // reset element-ui css - .horizontal-collapse-transition { - transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out; - } - - .scrollbar-wrapper { - overflow-x: hidden !important; - } - - .el-scrollbar__bar.is-vertical { - right: 0px; - } - - .el-scrollbar { - height: 100%; - } - - .is-horizontal { - display: none; - } - - a { - display: inline-block; - width: 100%; - overflow: hidden; - } - - .svg-icon { - margin-right: 10px !important; - } - - .el-menu { - border: none; - height: 100%; - width: 100% !important; - } - - .el-menu-item, .el-submenu__title { - overflow: hidden !important; - text-overflow: ellipsis !important; - white-space: nowrap !important; - height: 44px !important; - line-height: 44px !important; - font-weight: 500; - letter-spacing: 0.2px; - } - - // menu hover - .submenu-title-noDropdown, - .el-submenu__title { - &:hover { - background-color: rgba(255, 255, 255, 0.08) !important; - } - } - - & .theme-dark .is-active > .el-submenu__title { - color: $base-menu-color-active !important; - } - - & .nest-menu .el-submenu>.el-submenu__title, - & .el-submenu .el-menu-item { - min-width: $base-sidebar-width !important; - - &:hover { - background-color: rgba(0, 0, 0, 0.06) !important; - } - } - - & .theme-dark .nest-menu .el-submenu>.el-submenu__title, - & .theme-dark .el-submenu .el-menu-item { - background-color: $base-sub-menu-background !important; - - &:hover { - background-color: $base-sub-menu-hover !important; - } - } - - // theme-dark 深色主题(绿色导航栏) - &.theme-dark { - border-right: none; - - // Element 会内联设置子菜单 ul 和 item 的背景色,强制用深色子菜单背景 - .el-submenu .el-menu--inline { - background-color: $base-sub-menu-background !important; - } - - .el-submenu .el-menu-item, - .nest-menu .el-submenu > .el-submenu__title { - background-color: $base-sub-menu-background !important; - - &:hover { - background-color: $base-sub-menu-hover !important; - } - } - - .el-menu-item.is-active { - position: relative; - font-weight: 600; - - &::before { - content: ''; - position: absolute; - inset: 0; - background-color: rgba(255, 255, 255, 0.13); - border-left: 3px solid #d7b45a; - pointer-events: none; - z-index: 1; - } - } - - .el-submenu.is-active > .el-submenu__title { - color: #ffffff !important; - font-weight: 600; - - &::before { - background-color: rgba(255, 255, 255, 0.10); - border-left: 3px solid #d7b45a; - } - - .el-submenu__icon-arrow { - color: #e2c36f !important; - } - } - - .el-submenu__title .el-submenu__icon-arrow { - color: rgba(255, 255, 255, 0.76); - font-size: 12px; - font-weight: 700; - transition: transform 0.2s; - } - - .el-menu-item:not(.is-active), - .submenu-title-noDropdown, - .el-submenu__title { - position: relative; - - &::before { - content: ''; - position: absolute; - inset: 0; - background-color: transparent; - pointer-events: none; - z-index: 1; - transition: background-color 0.2s; - } - - &:hover::before { - background-color: rgba(255, 255, 255, 0.1); - } - } - } - - // theme-light 浅色主题 - &.theme-light { - border-right: 1px solid #e8eaf0; - box-shadow: none; - - .el-menu-item, - .el-submenu__title { - color: rgba(0, 0, 0, 0.65); - } - - .el-menu-item.is-active { - color: var(--current-color, #00875A) !important; - position: relative; - - &::before { - content: ''; - position: absolute; - inset: 0; - background-color: var(--current-color-light, #E6F4EA); - border-right: 3px solid var(--current-color, #00875A); - pointer-events: none; - z-index: 1; - } - } - - .el-submenu.is-active > .el-submenu__title { - color: var(--current-color, #00875A) !important; - } - - .el-menu-item:not(.is-active):hover, - .submenu-title-noDropdown:hover, - .el-submenu__title:hover { - background-color: #f5f7fa !important; - color: rgba(0, 0, 0, 0.85) !important; - } - - .nest-menu .el-submenu > .el-submenu__title, - .el-submenu .el-menu-item { - background-color: #fafafa !important; - - &:hover { - background-color: #f0f5ff !important; - } - } - } - } - - .hideSidebar { - .sidebar-container { - width: 54px !important; - } - - .el-menu:not(.el-menu--horizontal) { - .submenu-title-noDropdown { - padding: 0 !important; - position: relative; - - .el-tooltip { - padding: 0 !important; - - .svg-icon { - margin-left: 20px; - } - } - } - } - - .el-submenu { - overflow: hidden; - - &>.el-submenu__title { - padding: 0 !important; - - .svg-icon { - margin-left: 20px; - } - - } - } - - .el-menu--collapse { - .el-submenu { - &>.el-submenu__title { - &>span { - height: 0; - width: 0; - overflow: hidden; - visibility: hidden; - display: inline-block; - } - } - } - } - } - - .el-menu--collapse .el-menu .el-submenu { - min-width: $base-sidebar-width !important; - } - - // mobile responsive - .mobile { - .sidebar-container { - position: fixed; - top: 0; - bottom: 0; - left: 0; - z-index: 1001; - transition: transform .28s; - width: $base-sidebar-width !important; - } - - &.hideSidebar { - .sidebar-container { - pointer-events: none; - transition-duration: 0.3s; - transform: translate3d(-$base-sidebar-width, 0, 0); - } - } - } -} - -// when menu collapsed -.el-menu--vertical { - box-shadow: none; - - >.el-menu--popup { - box-shadow: none !important; - } - - &>.el-menu { - .svg-icon { - margin-right: 16px; - } - } - - .nest-menu .el-submenu>.el-submenu__title, - .el-menu-item { - &:hover { - // you can use $subMenuHover - background-color: rgba(0, 0, 0, 0.06) !important; - } - } - - // the scroll bar appears when the subMenu is too long - >.el-menu--popup { - max-height: 100vh; - overflow-y: auto; - - &::-webkit-scrollbar-track-piece { - background: #d3dce6; - } - - &::-webkit-scrollbar { - width: 6px; - } - - &::-webkit-scrollbar-thumb { - background: #99a9bf; - border-radius: 20px; - } - } -} diff --git a/frontend/src/assets/styles/transition.scss b/frontend/src/assets/styles/transition.scss deleted file mode 100644 index a695208ad..000000000 --- a/frontend/src/assets/styles/transition.scss +++ /dev/null @@ -1,49 +0,0 @@ -// global transition css - -/* fade */ -.fade-enter-active, -.fade-leave-active { - transition: opacity 0.28s; -} - -.fade-enter, -.fade-leave-active { - opacity: 0; -} - -/* fade-transform */ -.fade-transform--move, -.fade-transform-leave-active, -.fade-transform-enter-active { - transition: all .5s; -} - -.fade-transform-enter { - opacity: 0; - transform: translateX(-30px); -} - -.fade-transform-leave-to { - opacity: 0; - transform: translateX(30px); -} - -/* breadcrumb transition */ -.breadcrumb-enter-active, -.breadcrumb-leave-active { - transition: all .5s; -} - -.breadcrumb-enter, -.breadcrumb-leave-active { - opacity: 0; - transform: translateX(20px); -} - -.breadcrumb-move { - transition: all .5s; -} - -.breadcrumb-leave-active { - position: absolute; -} diff --git a/frontend/src/assets/styles/variables.scss b/frontend/src/assets/styles/variables.scss deleted file mode 100644 index 0c8cb1db0..000000000 --- a/frontend/src/assets/styles/variables.scss +++ /dev/null @@ -1,35 +0,0 @@ -// base color -$blue:#324157; -$light-blue:#3A71A8; -$red:#C03639; -$pink: #E65D6E; -$green: #30B08F; -$tiffany: #4AB7BD; -$yellow:#FEC171; -$panGreen: #30B08F; - -// 默认菜单主题风格(学院绿) -$base-menu-color: #dcebe6; -$base-menu-color-active: #ffffff; -$base-menu-background: #0b5f4a; - -$base-menu-light-color:rgba(0,0,0,.70); -$base-menu-light-background:#ffffff; - -$base-sub-menu-background: #084c3f; -$base-sub-menu-hover: rgba(255,255,255,.10); - -$base-sidebar-width: 200px; - -// the :export directive is the magic sauce for webpack -// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass -:export { - menuColor: $base-menu-color; - menuLightColor: $base-menu-light-color; - menuColorActive: $base-menu-color-active; - menuBackground: $base-menu-background; - menuLightBackground: $base-menu-light-background; - subMenuBackground: $base-sub-menu-background; - subMenuHover: $base-sub-menu-hover; - sideBarWidth: $base-sidebar-width; -} diff --git a/frontend/src/components/Breadcrumb/index.vue b/frontend/src/components/Breadcrumb/index.vue deleted file mode 100644 index 7f9fc0758..000000000 --- a/frontend/src/components/Breadcrumb/index.vue +++ /dev/null @@ -1,102 +0,0 @@ - - - - - diff --git a/frontend/src/components/Crontab/day.vue b/frontend/src/components/Crontab/day.vue deleted file mode 100644 index bd3a4207d..000000000 --- a/frontend/src/components/Crontab/day.vue +++ /dev/null @@ -1,161 +0,0 @@ - - - diff --git a/frontend/src/components/Crontab/hour.vue b/frontend/src/components/Crontab/hour.vue deleted file mode 100644 index 5a606044f..000000000 --- a/frontend/src/components/Crontab/hour.vue +++ /dev/null @@ -1,120 +0,0 @@ - - - diff --git a/frontend/src/components/Crontab/index.vue b/frontend/src/components/Crontab/index.vue deleted file mode 100644 index f72c118d1..000000000 --- a/frontend/src/components/Crontab/index.vue +++ /dev/null @@ -1,430 +0,0 @@ - - - - diff --git a/frontend/src/components/Crontab/min.vue b/frontend/src/components/Crontab/min.vue deleted file mode 100644 index ba4a3c51b..000000000 --- a/frontend/src/components/Crontab/min.vue +++ /dev/null @@ -1,116 +0,0 @@ - - - \ No newline at end of file diff --git a/frontend/src/components/Crontab/month.vue b/frontend/src/components/Crontab/month.vue deleted file mode 100644 index 59ace6178..000000000 --- a/frontend/src/components/Crontab/month.vue +++ /dev/null @@ -1,114 +0,0 @@ - - - diff --git a/frontend/src/components/Crontab/result.vue b/frontend/src/components/Crontab/result.vue deleted file mode 100644 index 6aba01336..000000000 --- a/frontend/src/components/Crontab/result.vue +++ /dev/null @@ -1,558 +0,0 @@ - - - diff --git a/frontend/src/components/Crontab/second.vue b/frontend/src/components/Crontab/second.vue deleted file mode 100644 index 9c104358b..000000000 --- a/frontend/src/components/Crontab/second.vue +++ /dev/null @@ -1,117 +0,0 @@ - - - diff --git a/frontend/src/components/Crontab/week.vue b/frontend/src/components/Crontab/week.vue deleted file mode 100644 index 50cea4854..000000000 --- a/frontend/src/components/Crontab/week.vue +++ /dev/null @@ -1,202 +0,0 @@ - - - diff --git a/frontend/src/components/Crontab/year.vue b/frontend/src/components/Crontab/year.vue deleted file mode 100644 index f95eb8933..000000000 --- a/frontend/src/components/Crontab/year.vue +++ /dev/null @@ -1,131 +0,0 @@ - - - diff --git a/frontend/src/components/DictData/index.js b/frontend/src/components/DictData/index.js deleted file mode 100644 index e3199034e..000000000 --- a/frontend/src/components/DictData/index.js +++ /dev/null @@ -1,49 +0,0 @@ -import Vue from 'vue' -import store from '@/store' -import DataDict from '@/utils/dict' -import { getDicts as getDicts } from '@/api/system/dict/data' - -function searchDictByKey(dict, key) { - if (key == null && key == "") { - return null - } - try { - for (let i = 0; i < dict.length; i++) { - if (dict[i].key == key) { - return dict[i].value - } - } - } catch (e) { - return null - } -} - -function install() { - Vue.use(DataDict, { - metas: { - '*': { - labelField: 'dictLabel', - valueField: 'dictValue', - request(dictMeta) { - const storeDict = searchDictByKey(store.getters.dict, dictMeta.type) - if (storeDict) { - return new Promise(resolve => { resolve(storeDict) }) - } else { - return new Promise((resolve, reject) => { - getDicts(dictMeta.type).then(res => { - store.dispatch('dict/setDict', { key: dictMeta.type, value: res.data }) - resolve(res.data) - }).catch(error => { - reject(error) - }) - }) - } - }, - }, - }, - }) -} - -export default { - install, -} \ No newline at end of file diff --git a/frontend/src/components/DictTag/index.vue b/frontend/src/components/DictTag/index.vue deleted file mode 100644 index 573714f55..000000000 --- a/frontend/src/components/DictTag/index.vue +++ /dev/null @@ -1,93 +0,0 @@ - - - - diff --git a/frontend/src/components/Editor/index.vue b/frontend/src/components/Editor/index.vue deleted file mode 100644 index bb827c76d..000000000 --- a/frontend/src/components/Editor/index.vue +++ /dev/null @@ -1,297 +0,0 @@ - - - - - diff --git a/frontend/src/components/ExcelImportDialog/index.vue b/frontend/src/components/ExcelImportDialog/index.vue deleted file mode 100644 index 935045626..000000000 --- a/frontend/src/components/ExcelImportDialog/index.vue +++ /dev/null @@ -1,126 +0,0 @@ - - - diff --git a/frontend/src/components/FileUpload/index.vue b/frontend/src/components/FileUpload/index.vue deleted file mode 100644 index 84a081230..000000000 --- a/frontend/src/components/FileUpload/index.vue +++ /dev/null @@ -1,262 +0,0 @@ - - - - - diff --git a/frontend/src/components/Hamburger/index.vue b/frontend/src/components/Hamburger/index.vue deleted file mode 100644 index daf414e45..000000000 --- a/frontend/src/components/Hamburger/index.vue +++ /dev/null @@ -1,44 +0,0 @@ - - - - - diff --git a/frontend/src/components/HeaderSearch/index.vue b/frontend/src/components/HeaderSearch/index.vue deleted file mode 100644 index be8528929..000000000 --- a/frontend/src/components/HeaderSearch/index.vue +++ /dev/null @@ -1,394 +0,0 @@ - - - - - \ No newline at end of file diff --git a/frontend/src/components/IconSelect/index.vue b/frontend/src/components/IconSelect/index.vue deleted file mode 100644 index 9ec4dbd34..000000000 --- a/frontend/src/components/IconSelect/index.vue +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - diff --git a/frontend/src/components/IconSelect/requireIcons.js b/frontend/src/components/IconSelect/requireIcons.js deleted file mode 100644 index 075fec349..000000000 --- a/frontend/src/components/IconSelect/requireIcons.js +++ /dev/null @@ -1,11 +0,0 @@ - -const req = require.context('../../assets/icons/svg', false, /\.svg$/) -const requireAll = requireContext => requireContext.keys() - -const re = /\.\/(.*)\.svg/ - -const icons = requireAll(req).map(i => { - return i.match(re)[1] -}) - -export default icons diff --git a/frontend/src/components/ImagePreview/index.vue b/frontend/src/components/ImagePreview/index.vue deleted file mode 100644 index 9a08a63d7..000000000 --- a/frontend/src/components/ImagePreview/index.vue +++ /dev/null @@ -1,90 +0,0 @@ - - - - - diff --git a/frontend/src/components/ImageUpload/index.vue b/frontend/src/components/ImageUpload/index.vue deleted file mode 100644 index bd2934313..000000000 --- a/frontend/src/components/ImageUpload/index.vue +++ /dev/null @@ -1,272 +0,0 @@ - - - - - diff --git a/frontend/src/components/Pagination/index.vue b/frontend/src/components/Pagination/index.vue deleted file mode 100644 index 4b93b4bbe..000000000 --- a/frontend/src/components/Pagination/index.vue +++ /dev/null @@ -1,113 +0,0 @@ - - - - - diff --git a/frontend/src/components/PanThumb/index.vue b/frontend/src/components/PanThumb/index.vue deleted file mode 100644 index ccd287a8e..000000000 --- a/frontend/src/components/PanThumb/index.vue +++ /dev/null @@ -1,141 +0,0 @@ - - - - - diff --git a/frontend/src/components/ParentView/index.vue b/frontend/src/components/ParentView/index.vue deleted file mode 100644 index 0229f7c74..000000000 --- a/frontend/src/components/ParentView/index.vue +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/frontend/src/components/PlaceholderPage/index.vue b/frontend/src/components/PlaceholderPage/index.vue deleted file mode 100644 index b668a7841..000000000 --- a/frontend/src/components/PlaceholderPage/index.vue +++ /dev/null @@ -1,85 +0,0 @@ - - - - - diff --git a/frontend/src/components/RightToolbar/index.vue b/frontend/src/components/RightToolbar/index.vue deleted file mode 100644 index 624591231..000000000 --- a/frontend/src/components/RightToolbar/index.vue +++ /dev/null @@ -1,253 +0,0 @@ - - - - - diff --git a/frontend/src/components/Screenfull/index.vue b/frontend/src/components/Screenfull/index.vue deleted file mode 100644 index c34357d54..000000000 --- a/frontend/src/components/Screenfull/index.vue +++ /dev/null @@ -1,57 +0,0 @@ - - - - - diff --git a/frontend/src/components/SizeSelect/index.vue b/frontend/src/components/SizeSelect/index.vue deleted file mode 100644 index 540cf7c10..000000000 --- a/frontend/src/components/SizeSelect/index.vue +++ /dev/null @@ -1,55 +0,0 @@ - - - diff --git a/frontend/src/components/SvgIcon/index.vue b/frontend/src/components/SvgIcon/index.vue deleted file mode 100644 index f0850511f..000000000 --- a/frontend/src/components/SvgIcon/index.vue +++ /dev/null @@ -1,61 +0,0 @@ - - - - - diff --git a/frontend/src/components/TreePanel/index.vue b/frontend/src/components/TreePanel/index.vue deleted file mode 100644 index d69f296f9..000000000 --- a/frontend/src/components/TreePanel/index.vue +++ /dev/null @@ -1,709 +0,0 @@ - - - - - \ No newline at end of file diff --git a/frontend/src/components/iFrame/index.vue b/frontend/src/components/iFrame/index.vue deleted file mode 100644 index 9655dabf8..000000000 --- a/frontend/src/components/iFrame/index.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - diff --git a/frontend/src/layout/components/Navbar.vue b/frontend/src/layout/components/Navbar.vue deleted file mode 100644 index 2bfd00346..000000000 --- a/frontend/src/layout/components/Navbar.vue +++ /dev/null @@ -1,406 +0,0 @@ - - - - - diff --git a/frontend/src/layout/components/SemesterBar.vue b/frontend/src/layout/components/SemesterBar.vue deleted file mode 100644 index c028415cb..000000000 --- a/frontend/src/layout/components/SemesterBar.vue +++ /dev/null @@ -1,273 +0,0 @@ - - - - - diff --git a/frontend/src/layout/components/Sidebar/FixiOSBug.js b/frontend/src/layout/components/Sidebar/FixiOSBug.js deleted file mode 100644 index e78ef2a52..000000000 --- a/frontend/src/layout/components/Sidebar/FixiOSBug.js +++ /dev/null @@ -1,25 +0,0 @@ -export default { - computed: { - device() { - return this.$store.state.app.device - } - }, - mounted() { - // In order to fix the click on menu on the ios device will trigger the mouseleave bug - this.fixBugIniOS() - }, - methods: { - fixBugIniOS() { - const $subMenu = this.$refs.subMenu - if ($subMenu) { - const handleMouseleave = $subMenu.handleMouseleave - $subMenu.handleMouseleave = (e) => { - if (this.device === 'mobile') { - return - } - handleMouseleave(e) - } - } - } - } -} diff --git a/frontend/src/layout/components/Sidebar/Item.vue b/frontend/src/layout/components/Sidebar/Item.vue deleted file mode 100644 index 952a42018..000000000 --- a/frontend/src/layout/components/Sidebar/Item.vue +++ /dev/null @@ -1,33 +0,0 @@ - diff --git a/frontend/src/layout/components/Sidebar/Link.vue b/frontend/src/layout/components/Sidebar/Link.vue deleted file mode 100644 index 5fdf1d267..000000000 --- a/frontend/src/layout/components/Sidebar/Link.vue +++ /dev/null @@ -1,43 +0,0 @@ - - - diff --git a/frontend/src/layout/components/Sidebar/SidebarItem.vue b/frontend/src/layout/components/Sidebar/SidebarItem.vue deleted file mode 100644 index 0e87064c5..000000000 --- a/frontend/src/layout/components/Sidebar/SidebarItem.vue +++ /dev/null @@ -1,99 +0,0 @@ - - - diff --git a/frontend/src/layout/components/Sidebar/index.vue b/frontend/src/layout/components/Sidebar/index.vue deleted file mode 100644 index c6f2598b9..000000000 --- a/frontend/src/layout/components/Sidebar/index.vue +++ /dev/null @@ -1,103 +0,0 @@ - - - - - diff --git a/frontend/src/layout/components/TagsView/ScrollPane.vue b/frontend/src/layout/components/TagsView/ScrollPane.vue deleted file mode 100644 index fd8d93651..000000000 --- a/frontend/src/layout/components/TagsView/ScrollPane.vue +++ /dev/null @@ -1,149 +0,0 @@ - - - - - diff --git a/frontend/src/layout/components/TagsView/index.vue b/frontend/src/layout/components/TagsView/index.vue deleted file mode 100644 index 92a750ba3..000000000 --- a/frontend/src/layout/components/TagsView/index.vue +++ /dev/null @@ -1,761 +0,0 @@ - - - - - - - diff --git a/frontend/src/layout/components/index.js b/frontend/src/layout/components/index.js deleted file mode 100644 index a727059b3..000000000 --- a/frontend/src/layout/components/index.js +++ /dev/null @@ -1,4 +0,0 @@ -export { default as AppMain } from './AppMain' -export { default as Navbar } from './Navbar' -export { default as Sidebar } from './Sidebar/index.vue' -export { default as TagsView } from './TagsView/index.vue' diff --git a/frontend/src/layout/index.vue b/frontend/src/layout/index.vue deleted file mode 100644 index a2bd3bbca..000000000 --- a/frontend/src/layout/index.vue +++ /dev/null @@ -1,207 +0,0 @@ - - - - - diff --git a/frontend/src/layout/mixin/ResizeHandler.js b/frontend/src/layout/mixin/ResizeHandler.js deleted file mode 100644 index 01580de0b..000000000 --- a/frontend/src/layout/mixin/ResizeHandler.js +++ /dev/null @@ -1,45 +0,0 @@ -import store from '@/store' - -const { body } = document -const WIDTH = 992 // refer to Bootstrap's responsive design - -export default { - watch: { - $route(route) { - if (this.device === 'mobile' && this.sidebar.opened) { - store.dispatch('app/closeSideBar', { withoutAnimation: false }) - } - } - }, - beforeMount() { - window.addEventListener('resize', this.$_resizeHandler) - }, - beforeDestroy() { - window.removeEventListener('resize', this.$_resizeHandler) - }, - mounted() { - const isMobile = this.$_isMobile() - if (isMobile) { - store.dispatch('app/toggleDevice', 'mobile') - store.dispatch('app/closeSideBar', { withoutAnimation: true }) - } - }, - methods: { - // use $_ for mixins properties - // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential - $_isMobile() { - const rect = body.getBoundingClientRect() - return rect.width - 1 < WIDTH - }, - $_resizeHandler() { - if (!document.hidden) { - const isMobile = this.$_isMobile() - store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop') - - if (isMobile) { - store.dispatch('app/closeSideBar', { withoutAnimation: true }) - } - } - } - } -} diff --git a/frontend/src/main.js b/frontend/src/main.js deleted file mode 100644 index bcb172b5d..000000000 --- a/frontend/src/main.js +++ /dev/null @@ -1,78 +0,0 @@ -import Vue from 'vue' - -import Cookies from 'js-cookie' - -import Element from 'element-ui' -import './assets/styles/element-variables.scss' - -import '@/assets/styles/index.scss' // global css -import '@/assets/styles/roomroot.scss' // roomroot css -import App from './App' -import store from './store' -import router from './router' -import directive from './directive' // directive -import plugins from './plugins' // plugins -import { download } from '@/utils/request' -import { initAdaptive } from '@/utils/adaptive' // 全局视口等比缩放自适应 - -// 初始化全局自适应,保障不同大小屏幕下页面布局不崩塌 -initAdaptive() - -import './assets/icons' // icon -import './permission' // permission control -import { getDicts } from "@/api/system/dict/data" -import { getConfigKey } from "@/api/system/config" -import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, handleTree } from "@/utils/roomroot" -// 分页组件 -import Pagination from "@/components/Pagination" -// 自定义表格工具组件 -import RightToolbar from "@/components/RightToolbar" -// 富文本组件 -import Editor from "@/components/Editor" -// 文件上传组件 -import FileUpload from "@/components/FileUpload" -// 图片上传组件 -import ImageUpload from "@/components/ImageUpload" -// 图片预览组件 -import ImagePreview from "@/components/ImagePreview" -// 字典标签组件 -import DictTag from '@/components/DictTag' -// 字典数据组件 -import DictData from '@/components/DictData' - -// 全局方法挂载 -Vue.prototype.getDicts = getDicts -Vue.prototype.getConfigKey = getConfigKey -Vue.prototype.parseTime = parseTime -Vue.prototype.resetForm = resetForm -Vue.prototype.addDateRange = addDateRange -Vue.prototype.selectDictLabel = selectDictLabel -Vue.prototype.selectDictLabels = selectDictLabels -Vue.prototype.download = download -Vue.prototype.handleTree = handleTree - -// 全局组件挂载 -Vue.component('DictTag', DictTag) -Vue.component('Pagination', Pagination) -Vue.component('RightToolbar', RightToolbar) -Vue.component('Editor', Editor) -Vue.component('FileUpload', FileUpload) -Vue.component('ImageUpload', ImageUpload) -Vue.component('ImagePreview', ImagePreview) - -Vue.use(directive) -Vue.use(plugins) -DictData.install() - -Vue.use(Element, { - size: Cookies.get('size') || 'medium' // set element-ui default size -}) - -Vue.config.productionTip = false - -new Vue({ - el: '#app', - router, - store, - render: h => h(App) -}) diff --git a/frontend/src/permission.js b/frontend/src/permission.js deleted file mode 100644 index 1a621df0d..000000000 --- a/frontend/src/permission.js +++ /dev/null @@ -1,69 +0,0 @@ -import router from './router' -import store from './store' -import { Message } from 'element-ui' -import NProgress from 'nprogress' -import 'nprogress/nprogress.css' -import { getToken } from '@/utils/auth' -import { isPathMatch } from '@/utils/validate' -import { isRelogin } from '@/utils/request' - -NProgress.configure({ showSpinner: false }) - -const whiteList = ['/login', '/register'] - -const isWhiteList = (path) => { - return whiteList.some(pattern => isPathMatch(pattern, path)) -} - -router.beforeEach((to, from, next) => { - NProgress.start() - if (getToken()) { - const isLock = store.getters.isLock - /* has token*/ - if (to.path === '/login') { - next({ path: '/' }) - NProgress.done() - } else if (isWhiteList(to.path)) { - next() - } else if (isLock && to.path !== '/lock') { - next({ path: '/lock' }) - NProgress.done() - } else if (!isLock && to.path === '/lock') { - next({ path: '/' }) - NProgress.done() - } else { - if (store.getters.roles.length === 0) { - isRelogin.show = true - // 判断当前用户是否已拉取完user_info信息 - store.dispatch('GetInfo').then(() => { - isRelogin.show = false - store.dispatch('GenerateRoutes').then(accessRoutes => { - // 根据roles权限生成可访问的路由表 - router.addRoutes(accessRoutes) // 动态添加可访问路由表 - next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 - }) - }).catch(err => { - store.dispatch('LogOut').then(() => { - Message.error(err) - next({ path: '/' }) - }) - }) - } else { - next() - } - } - } else { - // 没有token - if (isWhiteList(to.path)) { - // 在免登录白名单,直接进入 - next() - } else { - next(`/login?redirect=${encodeURIComponent(to.fullPath)}`) // 否则全部重定向到登录页 - NProgress.done() - } - } -}) - -router.afterEach(() => { - NProgress.done() -}) diff --git a/frontend/src/plugins/auth.js b/frontend/src/plugins/auth.js deleted file mode 100644 index eabe9b0d2..000000000 --- a/frontend/src/plugins/auth.js +++ /dev/null @@ -1,60 +0,0 @@ -import store from '@/store' - -function authPermission(permission) { - const all_permission = "*:*:*" - const permissions = store.getters && store.getters.permissions - if (permission && permission.length > 0) { - return permissions.some(v => { - return all_permission === v || v === permission - }) - } else { - return false - } -} - -function authRole(role) { - const super_admin = "admin" - const roles = store.getters && store.getters.roles - if (role && role.length > 0) { - return roles.some(v => { - return super_admin === v || v === role - }) - } else { - return false - } -} - -export default { - // 验证用户是否具备某权限 - hasPermi(permission) { - return authPermission(permission) - }, - // 验证用户是否含有指定权限,只需包含其中一个 - hasPermiOr(permissions) { - return permissions.some(item => { - return authPermission(item) - }) - }, - // 验证用户是否含有指定权限,必须全部拥有 - hasPermiAnd(permissions) { - return permissions.every(item => { - return authPermission(item) - }) - }, - // 验证用户是否具备某角色 - hasRole(role) { - return authRole(role) - }, - // 验证用户是否含有指定角色,只需包含其中一个 - hasRoleOr(roles) { - return roles.some(item => { - return authRole(item) - }) - }, - // 验证用户是否含有指定角色,必须全部拥有 - hasRoleAnd(roles) { - return roles.every(item => { - return authRole(item) - }) - } -} diff --git a/frontend/src/plugins/cache.js b/frontend/src/plugins/cache.js deleted file mode 100644 index 23e7cb949..000000000 --- a/frontend/src/plugins/cache.js +++ /dev/null @@ -1,79 +0,0 @@ -const sessionCache = { - set (key, value) { - if (!sessionStorage) { - return - } - if (key != null && value != null) { - sessionStorage.setItem(key, value) - } - }, - get (key) { - if (!sessionStorage) { - return null - } - if (key == null) { - return null - } - return sessionStorage.getItem(key) - }, - setJSON (key, jsonValue) { - if (jsonValue != null) { - this.set(key, JSON.stringify(jsonValue)) - } - }, - getJSON (key) { - const value = this.get(key) - if (value != null) { - return JSON.parse(value) - } - return null - }, - remove (key) { - sessionStorage.removeItem(key) - } -} -const localCache = { - set (key, value) { - if (!localStorage) { - return - } - if (key != null && value != null) { - localStorage.setItem(key, value) - } - }, - get (key) { - if (!localStorage) { - return null - } - if (key == null) { - return null - } - return localStorage.getItem(key) - }, - setJSON (key, jsonValue) { - if (jsonValue != null) { - this.set(key, JSON.stringify(jsonValue)) - } - }, - getJSON (key) { - const value = this.get(key) - if (value != null) { - return JSON.parse(value) - } - return null - }, - remove (key) { - localStorage.removeItem(key) - } -} - -export default { - /** - * 会话级缓存 - */ - session: sessionCache, - /** - * 本地缓存 - */ - local: localCache -} diff --git a/frontend/src/plugins/download.js b/frontend/src/plugins/download.js deleted file mode 100644 index c528a2410..000000000 --- a/frontend/src/plugins/download.js +++ /dev/null @@ -1,79 +0,0 @@ -import axios from 'axios' -import {Loading, Message} from 'element-ui' -import { saveAs } from 'file-saver' -import { getToken } from '@/utils/auth' -import errorCode from '@/utils/errorCode' -import { blobValidate } from "@/utils/roomroot" - -const baseURL = process.env.VUE_APP_BASE_API -let downloadLoadingInstance - -export default { - name(name, isDelete = true) { - var url = baseURL + "/common/download?fileName=" + encodeURIComponent(name) + "&delete=" + isDelete - axios({ - method: 'get', - url: url, - responseType: 'blob', - headers: { 'Authorization': 'Bearer ' + getToken() } - }).then((res) => { - const isBlob = blobValidate(res.data) - if (isBlob) { - const blob = new Blob([res.data]) - this.saveAs(blob, decodeURIComponent(res.headers['download-filename'])) - } else { - this.printErrMsg(res.data) - } - }) - }, - resource(resource) { - var url = baseURL + "/common/download/resource?resource=" + encodeURIComponent(resource) - axios({ - method: 'get', - url: url, - responseType: 'blob', - headers: { 'Authorization': 'Bearer ' + getToken() } - }).then((res) => { - const isBlob = blobValidate(res.data) - if (isBlob) { - const blob = new Blob([res.data]) - this.saveAs(blob, decodeURIComponent(res.headers['download-filename'])) - } else { - this.printErrMsg(res.data) - } - }) - }, - zip(url, name) { - var url = baseURL + url - downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", }) - axios({ - method: 'get', - url: url, - responseType: 'blob', - headers: { 'Authorization': 'Bearer ' + getToken() } - }).then((res) => { - const isBlob = blobValidate(res.data) - if (isBlob) { - const blob = new Blob([res.data], { type: 'application/zip' }) - this.saveAs(blob, name) - } else { - this.printErrMsg(res.data) - } - downloadLoadingInstance.close() - }).catch((r) => { - console.error(r) - Message.error('下载文件出现错误,请联系管理员!') - downloadLoadingInstance.close() - }) - }, - saveAs(text, name, opts) { - saveAs(text, name, opts) - }, - async printErrMsg(data) { - const resText = await data.text() - const rspObj = JSON.parse(resText) - const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default'] - Message.error(errMsg) - } -} - diff --git a/frontend/src/plugins/index.js b/frontend/src/plugins/index.js deleted file mode 100644 index 7182bb0a9..000000000 --- a/frontend/src/plugins/index.js +++ /dev/null @@ -1,20 +0,0 @@ -import tab from './tab' -import auth from './auth' -import cache from './cache' -import modal from './modal' -import download from './download' - -export default { - install(Vue) { - // 页签操作 - Vue.prototype.$tab = tab - // 认证对象 - Vue.prototype.$auth = auth - // 缓存对象 - Vue.prototype.$cache = cache - // 模态框对象 - Vue.prototype.$modal = modal - // 下载文件 - Vue.prototype.$download = download - } -} diff --git a/frontend/src/plugins/modal.js b/frontend/src/plugins/modal.js deleted file mode 100644 index bd4cd0260..000000000 --- a/frontend/src/plugins/modal.js +++ /dev/null @@ -1,83 +0,0 @@ -import { Message, MessageBox, Notification, Loading } from 'element-ui' - -let loadingInstance - -export default { - // 消息提示 - msg(content) { - Message.info(content) - }, - // 错误消息 - msgError(content) { - Message.error(content) - }, - // 成功消息 - msgSuccess(content) { - Message.success(content) - }, - // 警告消息 - msgWarning(content) { - Message.warning(content) - }, - // 弹出提示 - alert(content) { - MessageBox.alert(content, "系统提示") - }, - // 错误提示 - alertError(content) { - MessageBox.alert(content, "系统提示", { type: 'error' }) - }, - // 成功提示 - alertSuccess(content) { - MessageBox.alert(content, "系统提示", { type: 'success' }) - }, - // 警告提示 - alertWarning(content) { - MessageBox.alert(content, "系统提示", { type: 'warning' }) - }, - // 通知提示 - notify(content) { - Notification.info(content) - }, - // 错误通知 - notifyError(content) { - Notification.error(content) - }, - // 成功通知 - notifySuccess(content) { - Notification.success(content) - }, - // 警告通知 - notifyWarning(content) { - Notification.warning(content) - }, - // 确认窗体 - confirm(content) { - return MessageBox.confirm(content, "系统提示", { - confirmButtonText: '确定', - cancelButtonText: '取消', - type: "warning", - }) - }, - // 提交内容 - prompt(content) { - return MessageBox.prompt(content, "系统提示", { - confirmButtonText: '确定', - cancelButtonText: '取消', - type: "warning", - }) - }, - // 打开遮罩层 - loading(content) { - loadingInstance = Loading.service({ - lock: true, - text: content, - spinner: "el-icon-loading", - background: "rgba(0, 0, 0, 0.7)", - }) - }, - // 关闭遮罩层 - closeLoading() { - loadingInstance.close() - } -} diff --git a/frontend/src/plugins/tab.js b/frontend/src/plugins/tab.js deleted file mode 100644 index f83ac08a2..000000000 --- a/frontend/src/plugins/tab.js +++ /dev/null @@ -1,75 +0,0 @@ -import store from '@/store' -import router from '@/router' - -export default { - // 刷新当前tab页签 - refreshPage(obj) { - const { path, query, matched } = router.currentRoute - // 防止在重定向过程中重复刷新 - if (path.startsWith('/redirect/')) { - return Promise.resolve() - } - if (obj === undefined) { - matched.forEach((m) => { - if (m.components && m.components.default && m.components.default.name) { - if (!['Layout', 'ParentView'].includes(m.components.default.name)) { - obj = { name: m.components.default.name, path: path, query: query } - } - } - }) - } - return store.dispatch('tagsView/delCachedView', obj).then(() => { - const { path, query } = obj - router.replace({ - path: '/redirect' + path, - query: query - }) - }) - }, - // 关闭当前tab页签,打开新页签 - closeOpenPage(obj) { - store.dispatch("tagsView/delView", router.currentRoute) - if (obj !== undefined) { - return router.push(obj) - } - }, - // 关闭指定tab页签 - closePage(obj) { - if (obj === undefined) { - return store.dispatch('tagsView/delView', router.currentRoute).then(({ visitedViews }) => { - const latestView = visitedViews.slice(-1)[0] - if (latestView) { - return router.push(latestView.fullPath) - } - return router.push('/') - }) - } - return store.dispatch('tagsView/delView', obj) - }, - // 关闭所有tab页签 - closeAllPage() { - return store.dispatch('tagsView/delAllViews') - }, - // 关闭左侧tab页签 - closeLeftPage(obj) { - return store.dispatch('tagsView/delLeftTags', obj || router.currentRoute) - }, - // 关闭右侧tab页签 - closeRightPage(obj) { - return store.dispatch('tagsView/delRightTags', obj || router.currentRoute) - }, - // 关闭其他tab页签 - closeOtherPage(obj) { - return store.dispatch('tagsView/delOthersViews', obj || router.currentRoute) - }, - // 添加tab页签 - openPage(title, url, params) { - const obj = { path: url, meta: { title: title } } - store.dispatch('tagsView/addView', obj) - return router.push({ path: url, query: params }) - }, - // 修改tab页签 - updatePage(obj) { - return store.dispatch('tagsView/updateVisitedView', obj) - } -} diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js deleted file mode 100644 index 2dd6e790a..000000000 --- a/frontend/src/router/index.js +++ /dev/null @@ -1,189 +0,0 @@ -import Vue from 'vue' -import Router from 'vue-router' - -Vue.use(Router) - -/* Layout */ -import Layout from '@/layout' - -/** - * Note: 路由配置项 - * - * hidden: true // 当设置 true 的时候该路由不会再侧边栏出现 如401,login等页面,或者如一些编辑页面/edit/1 - * alwaysShow: true // 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面 - * // 只有一个时,会将那个子路由当做根路由显示在侧边栏--如引导页面 - * // 若你想不管路由下面的 children 声明的个数都显示你的根路由 - * // 你可以设置 alwaysShow: true,这样它就会忽略之前定义的规则,一直显示根路由 - * redirect: noRedirect // 当设置 noRedirect 的时候该路由在面包屑导航中不可被点击 - * name:'router-name' // 设定路由的名字,一定要填写不然使用时会出现各种问题 - * query: '{"id": 1, "name": "ry"}' // 访问路由的默认传递参数 - * roles: ['admin', 'common'] // 访问路由的角色权限 - * permissions: ['a:a:a', 'b:b:b'] // 访问路由的菜单权限 - * meta : { - noCache: true // 如果设置为true,则不会被 缓存(默认 false) - title: 'title' // 设置该路由在侧边栏和面包屑中展示的名字 - icon: 'svg-name' // 设置该路由的图标,对应路径src/assets/icons/svg - breadcrumb: false // 如果设置为false,则不会在breadcrumb面包屑中显示 - activeMenu: '/system/user' // 当路由设置了该属性,则会高亮相对应的侧边栏。 - } - */ - -// 公共路由 -export const constantRoutes = [ - { - path: '/redirect', - component: Layout, - hidden: true, - children: [ - { - path: '/redirect/:path(.*)', - component: () => import('@/views/redirect') - } - ] - }, - { - path: '/login', - component: () => import('@/views/login'), - hidden: true - }, - { - path: '/register', - component: () => import('@/views/register'), - hidden: true - }, - { - path: '/404', - component: () => import('@/views/error/404'), - hidden: true - }, - { - path: '/401', - component: () => import('@/views/error/401'), - hidden: true - }, - { - path: '', - component: Layout, - redirect: 'index', - children: [ - { - path: 'index', - component: () => import('@/views/index'), - name: 'Index', - meta: { title: '首页', icon: 'dashboard', affix: true } - } - ] - }, - { - path: '/lock', - component: () => import('@/views/lock'), - hidden: true, - meta: { title: '锁定屏幕' } - }, - { - path: '/user', - component: Layout, - hidden: true, - redirect: 'noredirect', - children: [ - { - path: 'profile', - component: () => import('@/views/system/user/profile/index'), - name: 'Profile', - meta: { title: '个人中心', icon: 'user' } - } - ] - } -] - -// 动态路由,基于用户权限动态去加载 -export const dynamicRoutes = [ - { - path: '/system/user-auth', - component: Layout, - hidden: true, - permissions: ['system:user:edit'], - children: [ - { - path: 'role/:userId(\\d+)', - component: () => import('@/views/system/user/authRole'), - name: 'AuthRole', - meta: { title: '分配角色', activeMenu: '/system/user' } - } - ] - }, - { - path: '/system/role-auth', - component: Layout, - hidden: true, - permissions: ['system:role:edit'], - children: [ - { - path: 'user/:roleId(\\d+)', - component: () => import('@/views/system/role/authUser'), - name: 'AuthUser', - meta: { title: '分配用户', activeMenu: '/system/role' } - } - ] - }, - { - path: '/system/dict-data', - component: Layout, - hidden: true, - permissions: ['system:dict:list'], - children: [ - { - path: 'index/:dictId(\\d+)', - component: () => import('@/views/system/dict/data'), - name: 'Data', - meta: { title: '字典数据', activeMenu: '/system/dict' } - } - ] - }, - { - path: '/monitor/job-log', - component: Layout, - hidden: true, - permissions: ['monitor:job:list'], - children: [ - { - path: 'index/:jobId(\\d+)', - component: () => import('@/views/monitor/job/log'), - name: 'JobLog', - meta: { title: '调度日志', activeMenu: '/monitor/job' } - } - ] - }, - { - path: '/tool/gen-edit', - component: Layout, - hidden: true, - permissions: ['tool:gen:edit'], - children: [ - { - path: 'index/:tableId(\\d+)', - component: () => import('@/views/tool/gen/editTable'), - name: 'GenEdit', - meta: { title: '修改生成配置', activeMenu: '/tool/gen' } - } - ] - } -] - -// 防止连续点击多次路由报错 -let routerPush = Router.prototype.push -let routerReplace = Router.prototype.replace -// push -Router.prototype.push = function push(location) { - return routerPush.call(this, location).catch(err => err) -} -// replace -Router.prototype.replace = function push(location) { - return routerReplace.call(this, location).catch(err => err) -} - -export default new Router({ - mode: 'history', // 去掉url中的# - scrollBehavior: () => ({ y: 0 }), - routes: constantRoutes -}) diff --git a/frontend/src/shims-modules.d.ts b/frontend/src/shims-modules.d.ts deleted file mode 100644 index d7b3a710a..000000000 --- a/frontend/src/shims-modules.d.ts +++ /dev/null @@ -1,21 +0,0 @@ -declare module 'fuse.js/dist/fuse.min.js' { - const Fuse: any - export default Fuse -} - -declare module 'compression-webpack-plugin' { - const CompressionPlugin: any - export default CompressionPlugin -} - -declare module 'vuex' { - export function mapState(...args: any[]): any - export function mapGetters(...args: any[]): any - export function mapMutations(...args: any[]): any - export function mapActions(...args: any[]): any - export function createNamespacedHelpers(...args: any[]): any - const Store: any - export { Store } - const Vuex: any - export default Vuex -} diff --git a/frontend/src/store/getters.js b/frontend/src/store/getters.js deleted file mode 100644 index 375a04bee..000000000 --- a/frontend/src/store/getters.js +++ /dev/null @@ -1,23 +0,0 @@ -const getters = { - sidebar: state => state.app.sidebar, - size: state => state.app.size, - device: state => state.app.device, - dict: state => state.dict.dict, - isLock: state => state.lock.isLock, - lockPath: state => state.lock.lockPath, - visitedViews: state => state.tagsView.visitedViews, - cachedViews: state => state.tagsView.cachedViews, - token: state => state.user.token, - avatar: state => state.user.avatar, - id: state => state.user.id, - name: state => state.user.name, - nickName: state => state.user.nickName, - introduction: state => state.user.introduction, - roles: state => state.user.roles, - permissions: state => state.user.permissions, - permission_routes: state => state.permission.routes, - topbarRouters: state => state.permission.topbarRouters, - defaultRoutes: state => state.permission.defaultRoutes, - sidebarRouters: state => state.permission.sidebarRouters -} -export default getters diff --git a/frontend/src/store/index.js b/frontend/src/store/index.js deleted file mode 100644 index e6ae21ff0..000000000 --- a/frontend/src/store/index.js +++ /dev/null @@ -1,25 +0,0 @@ -import Vue from 'vue' -import Vuex from 'vuex' -import app from './modules/app' -import lock from './modules/lock' -import dict from './modules/dict' -import user from './modules/user' -import tagsView from './modules/tagsView' -import permission from './modules/permission' -import getters from './getters' - -Vue.use(Vuex) - -const store = new Vuex.Store({ - modules: { - app, - lock, - dict, - user, - tagsView, - permission - }, - getters -}) - -export default store diff --git a/frontend/src/store/modules/app.js b/frontend/src/store/modules/app.js deleted file mode 100644 index 29c70a596..000000000 --- a/frontend/src/store/modules/app.js +++ /dev/null @@ -1,66 +0,0 @@ -import Cookies from 'js-cookie' - -const state = { - sidebar: { - opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true, - withoutAnimation: false, - hide: false - }, - device: 'desktop', - size: Cookies.get('size') || 'medium' -} - -const mutations = { - TOGGLE_SIDEBAR: state => { - if (state.sidebar.hide) { - return false - } - state.sidebar.opened = !state.sidebar.opened - state.sidebar.withoutAnimation = false - if (state.sidebar.opened) { - Cookies.set('sidebarStatus', 1) - } else { - Cookies.set('sidebarStatus', 0) - } - }, - CLOSE_SIDEBAR: (state, withoutAnimation) => { - Cookies.set('sidebarStatus', 0) - state.sidebar.opened = false - state.sidebar.withoutAnimation = withoutAnimation - }, - TOGGLE_DEVICE: (state, device) => { - state.device = device - }, - SET_SIZE: (state, size) => { - state.size = size - Cookies.set('size', size) - }, - SET_SIDEBAR_HIDE: (state, status) => { - state.sidebar.hide = status - } -} - -const actions = { - toggleSideBar({ commit }) { - commit('TOGGLE_SIDEBAR') - }, - closeSideBar({ commit }, { withoutAnimation }) { - commit('CLOSE_SIDEBAR', withoutAnimation) - }, - toggleDevice({ commit }, device) { - commit('TOGGLE_DEVICE', device) - }, - setSize({ commit }, size) { - commit('SET_SIZE', size) - }, - toggleSideBarHide({ commit }, status) { - commit('SET_SIDEBAR_HIDE', status) - } -} - -export default { - namespaced: true, - state, - mutations, - actions -} diff --git a/frontend/src/store/modules/dict.js b/frontend/src/store/modules/dict.js deleted file mode 100644 index 5b5013687..000000000 --- a/frontend/src/store/modules/dict.js +++ /dev/null @@ -1,50 +0,0 @@ -const state = { - dict: new Array() -} -const mutations = { - SET_DICT: (state, { key, value }) => { - if (key !== null && key !== "") { - state.dict.push({ - key: key, - value: value - }) - } - }, - REMOVE_DICT: (state, key) => { - try { - for (let i = 0; i < state.dict.length; i++) { - if (state.dict[i].key == key) { - state.dict.splice(i, 1) - return true - } - } - } catch (e) { - } - }, - CLEAN_DICT: (state) => { - state.dict = new Array() - } -} - -const actions = { - // 设置字典 - setDict({ commit }, data) { - commit('SET_DICT', data) - }, - // 删除字典 - removeDict({ commit }, key) { - commit('REMOVE_DICT', key) - }, - // 清空字典 - cleanDict({ commit }) { - commit('CLEAN_DICT') - } -} - -export default { - namespaced: true, - state, - mutations, - actions -} - diff --git a/frontend/src/store/modules/lock.js b/frontend/src/store/modules/lock.js deleted file mode 100644 index bc496ebad..000000000 --- a/frontend/src/store/modules/lock.js +++ /dev/null @@ -1,34 +0,0 @@ -const LOCK_KEY = 'screen-lock' -const LOCK_PATH_KEY = 'screen-lock-path' - -const lock = { - namespaced: true, - state: { - isLock: JSON.parse(localStorage.getItem(LOCK_KEY) || 'false'), - lockPath: localStorage.getItem(LOCK_PATH_KEY) || '/index' - }, - mutations: { - SET_LOCK(state, status) { - state.isLock = status - localStorage.setItem(LOCK_KEY, JSON.stringify(status)) - }, - SET_LOCK_PATH(state, path) { - state.lockPath = path - localStorage.setItem(LOCK_PATH_KEY, path) - } - }, - actions: { - // 锁定屏幕,同时记录当前路径 - lockScreen({ commit }, currentPath) { - commit('SET_LOCK_PATH', currentPath || '/index') - commit('SET_LOCK', true) - }, - // 解锁屏幕,清除路径 - unlockScreen({ commit }) { - commit('SET_LOCK', false) - commit('SET_LOCK_PATH', '/index') - } - } -} - -export default lock diff --git a/frontend/src/store/modules/permission.js b/frontend/src/store/modules/permission.js deleted file mode 100644 index b549ef070..000000000 --- a/frontend/src/store/modules/permission.js +++ /dev/null @@ -1,122 +0,0 @@ -import auth from '@/plugins/auth' -import router, { constantRoutes, dynamicRoutes } from '@/router' -import { getRouters } from '@/api/menu' -import Layout from '@/layout/index' -import ParentView from '@/components/ParentView' -import InnerLink from '@/layout/components/InnerLink' - -const permission = { - state: { - routes: [], - addRoutes: [], - defaultRoutes: [], - topbarRouters: [], - sidebarRouters: [] - }, - mutations: { - SET_ROUTES: (state, routes) => { - state.addRoutes = routes - state.routes = constantRoutes.concat(routes) - }, - SET_DEFAULT_ROUTES: (state, routes) => { - state.defaultRoutes = constantRoutes.concat(routes) - }, - SET_TOPBAR_ROUTES: (state, routes) => { - state.topbarRouters = routes - }, - SET_SIDEBAR_ROUTERS: (state, routes) => { - state.sidebarRouters = routes - }, - }, - actions: { - // 生成路由 - GenerateRoutes({ commit }) { - return new Promise(resolve => { - // 向后端请求路由数据 - getRouters().then(res => { - const sdata = JSON.parse(JSON.stringify(res.data)) - const rdata = JSON.parse(JSON.stringify(res.data)) - const sidebarRoutes = filterAsyncRouter(sdata) - const rewriteRoutes = filterAsyncRouter(rdata, false, true) - const asyncRoutes = filterDynamicRoutes(dynamicRoutes) - rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true }) - router.addRoutes(asyncRoutes) - commit('SET_ROUTES', rewriteRoutes) - commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes)) - commit('SET_DEFAULT_ROUTES', sidebarRoutes) - commit('SET_TOPBAR_ROUTES', sidebarRoutes) - resolve(rewriteRoutes) - }) - }) - } - } -} - -// 遍历后台传来的路由字符串,转换为组件对象 -function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) { - return asyncRouterMap.filter(route => { - if (type && route.children) { - route.children = filterChildren(route.children) - } - if (route.component) { - // Layout ParentView 组件特殊处理 - if (route.component === 'Layout') { - route.component = Layout - } else if (route.component === 'ParentView') { - route.component = ParentView - } else if (route.component === 'InnerLink') { - route.component = InnerLink - } else { - route.component = loadView(route.component) - } - } - if (route.children != null && route.children && route.children.length) { - route.children = filterAsyncRouter(route.children, route, type) - } else { - delete route['children'] - delete route['redirect'] - } - return true - }) -} - -function filterChildren(childrenMap, lastRouter = false) { - var children = [] - childrenMap.forEach(el => { - el.path = lastRouter ? lastRouter.path + '/' + el.path : el.path - if (el.children && el.children.length && el.component === 'ParentView') { - children = children.concat(filterChildren(el.children, el)) - } else { - children.push(el) - } - }) - return children -} - -// 动态路由遍历,验证是否具备权限 -export function filterDynamicRoutes(routes) { - const res = [] - routes.forEach(route => { - if (route.permissions) { - if (auth.hasPermiOr(route.permissions)) { - res.push(route) - } - } else if (route.roles) { - if (auth.hasRoleOr(route.roles)) { - res.push(route) - } - } - }) - return res -} - -export const loadView = (view) => { - if (process.env.NODE_ENV === 'development') { - return (resolve) => require([`@/views/${view}`], resolve) - } else { - // 使用 import 实现生产环境的路由懒加载 - return () => import(`@/views/${view}`) - } -} - -export default permission diff --git a/frontend/src/store/modules/tagsView.js b/frontend/src/store/modules/tagsView.js deleted file mode 100644 index 93c508275..000000000 --- a/frontend/src/store/modules/tagsView.js +++ /dev/null @@ -1,303 +0,0 @@ -import cache from '@/plugins/cache' - -const PERSIST_KEY = 'tags-view-visited' -const MAX_VISITED_VIEWS = 8 - -function removeViewCache(state, view) { - const cachedViewIndex = state.cachedViews.indexOf(view.name) - if (cachedViewIndex > -1) { - state.cachedViews.splice(cachedViewIndex, 1) - } - state.iframeViews = state.iframeViews.filter(item => item.path !== view.path) -} - -function trimVisitedViews(state, currentView) { - while (state.visitedViews.length > MAX_VISITED_VIEWS) { - const removableViewIndex = state.visitedViews.findIndex(view => { - const isAffix = view.meta && view.meta.affix - - return !isAffix && view.path !== currentView.path - }) - - if (removableViewIndex === -1) { - return - } - - const [removedView] = state.visitedViews.splice(removableViewIndex, 1) - removeViewCache(state, removedView) - } -} - -// 布局已固定,不启用标签页持久化 -function isPersistEnabled() { - return false -} - -function saveVisitedViews(views) { - if (!isPersistEnabled()) return - const toSave = views.filter(v => !(v.meta && v.meta.affix)).map(v => ({ path: v.path, fullPath: v.fullPath, name: v.name, title: v.title, query: v.query, meta: v.meta })) - cache.local.setJSON(PERSIST_KEY, toSave) -} - -function loadVisitedViews() { - return cache.local.getJSON(PERSIST_KEY) || [] -} - -function clearVisitedViews() { - cache.local.remove(PERSIST_KEY) -} - -const state = { - visitedViews: [], - cachedViews: [], - iframeViews: [] -} - -const mutations = { - ADD_IFRAME_VIEW: (state, view) => { - if (state.iframeViews.some(v => v.path === view.path)) return - state.iframeViews.push( - Object.assign({}, view, { - title: view.meta.title || 'no-name' - }) - ) - }, - ADD_VISITED_VIEW: (state, view) => { - if (state.visitedViews.some(v => v.path === view.path)) return - state.visitedViews.push( - Object.assign({}, view, { - title: view.meta.title || 'no-name' - }) - ) - trimVisitedViews(state, view) - saveVisitedViews(state.visitedViews) - }, - ADD_VISITED_VIEW_FIRST: (state, view) => { - if (state.visitedViews.some(v => v.path === view.path)) return - state.visitedViews.unshift( - Object.assign({}, view, { - title: view.meta.title || 'no-name' - }) - ) - trimVisitedViews(state, view) - }, - ADD_CACHED_VIEW: (state, view) => { - if (state.cachedViews.includes(view.name)) return - if (view.meta && !view.meta.noCache) { - state.cachedViews.push(view.name) - } - }, - DEL_VISITED_VIEW: (state, view) => { - for (const [i, v] of state.visitedViews.entries()) { - if (v.path === view.path) { - state.visitedViews.splice(i, 1) - break - } - } - state.iframeViews = state.iframeViews.filter(item => item.path !== view.path) - saveVisitedViews(state.visitedViews) - }, - DEL_IFRAME_VIEW: (state, view) => { - state.iframeViews = state.iframeViews.filter(item => item.path !== view.path) - }, - DEL_CACHED_VIEW: (state, view) => { - const index = state.cachedViews.indexOf(view.name) - index > -1 && state.cachedViews.splice(index, 1) - }, - - DEL_OTHERS_VISITED_VIEWS: (state, view) => { - state.visitedViews = state.visitedViews.filter(v => { - return v.meta.affix || v.path === view.path - }) - state.iframeViews = state.iframeViews.filter(item => item.path === view.path) - saveVisitedViews(state.visitedViews) - }, - DEL_OTHERS_CACHED_VIEWS: (state, view) => { - const index = state.cachedViews.indexOf(view.name) - if (index > -1) { - state.cachedViews = state.cachedViews.slice(index, index + 1) - } else { - state.cachedViews = [] - } - }, - DEL_ALL_VISITED_VIEWS: state => { - // keep affix tags - const affixTags = state.visitedViews.filter(tag => tag.meta.affix) - state.visitedViews = affixTags - state.iframeViews = [] - clearVisitedViews() - }, - DEL_ALL_CACHED_VIEWS: state => { - state.cachedViews = [] - }, - UPDATE_VISITED_VIEW: (state, view) => { - for (let v of state.visitedViews) { - if (v.path === view.path) { - v = Object.assign(v, view) - break - } - } - }, - DEL_RIGHT_VIEWS: (state, view) => { - const index = state.visitedViews.findIndex(v => v.path === view.path) - if (index === -1) { - return - } - state.visitedViews = state.visitedViews.filter((item, idx) => { - if (idx <= index || (item.meta && item.meta.affix)) { - return true - } - const i = state.cachedViews.indexOf(item.name) - if (i > -1) { - state.cachedViews.splice(i, 1) - } - if (item.meta.link) { - const fi = state.iframeViews.findIndex(v => v.path === item.path) - state.iframeViews.splice(fi, 1) - } - return false - }) - saveVisitedViews(state.visitedViews) - }, - DEL_LEFT_VIEWS: (state, view) => { - const index = state.visitedViews.findIndex(v => v.path === view.path) - if (index === -1) { - return - } - state.visitedViews = state.visitedViews.filter((item, idx) => { - if (idx >= index || (item.meta && item.meta.affix)) { - return true - } - const i = state.cachedViews.indexOf(item.name) - if (i > -1) { - state.cachedViews.splice(i, 1) - } - if (item.meta.link) { - const fi = state.iframeViews.findIndex(v => v.path === item.path) - state.iframeViews.splice(fi, 1) - } - return false - }) - saveVisitedViews(state.visitedViews) - } -} - -const actions = { - addView({ dispatch }, view) { - dispatch('addVisitedView', view) - dispatch('addCachedView', view) - }, - addIframeView({ commit }, view) { - commit('ADD_IFRAME_VIEW', view) - }, - addVisitedView({ commit }, view) { - commit('ADD_VISITED_VIEW', view) - }, - addAffixView({ commit }, view) { - commit('ADD_VISITED_VIEW_FIRST', view) - }, - addCachedView({ commit }, view) { - commit('ADD_CACHED_VIEW', view) - }, - delView({ dispatch, state }, view) { - return new Promise(resolve => { - dispatch('delVisitedView', view) - dispatch('delCachedView', view) - resolve({ - visitedViews: [...state.visitedViews], - cachedViews: [...state.cachedViews] - }) - }) - }, - delVisitedView({ commit, state }, view) { - return new Promise(resolve => { - commit('DEL_VISITED_VIEW', view) - resolve([...state.visitedViews]) - }) - }, - delIframeView({ commit, state }, view) { - return new Promise(resolve => { - commit('DEL_IFRAME_VIEW', view) - resolve([...state.iframeViews]) - }) - }, - delCachedView({ commit, state }, view) { - return new Promise(resolve => { - commit('DEL_CACHED_VIEW', view) - resolve([...state.cachedViews]) - }) - }, - delOthersViews({ dispatch, state }, view) { - return new Promise(resolve => { - dispatch('delOthersVisitedViews', view) - dispatch('delOthersCachedViews', view) - resolve({ - visitedViews: [...state.visitedViews], - cachedViews: [...state.cachedViews] - }) - }) - }, - delOthersVisitedViews({ commit, state }, view) { - return new Promise(resolve => { - commit('DEL_OTHERS_VISITED_VIEWS', view) - resolve([...state.visitedViews]) - }) - }, - delOthersCachedViews({ commit, state }, view) { - return new Promise(resolve => { - commit('DEL_OTHERS_CACHED_VIEWS', view) - resolve([...state.cachedViews]) - }) - }, - delAllViews({ dispatch, state }, view) { - return new Promise(resolve => { - dispatch('delAllVisitedViews', view) - dispatch('delAllCachedViews', view) - resolve({ - visitedViews: [...state.visitedViews], - cachedViews: [...state.cachedViews] - }) - }) - }, - delAllVisitedViews({ commit, state }) { - return new Promise(resolve => { - commit('DEL_ALL_VISITED_VIEWS') - resolve([...state.visitedViews]) - }) - }, - delAllCachedViews({ commit, state }) { - return new Promise(resolve => { - commit('DEL_ALL_CACHED_VIEWS') - resolve([...state.cachedViews]) - }) - }, - updateVisitedView({ commit }, view) { - commit('UPDATE_VISITED_VIEW', view) - }, - delRightTags({ commit }, view) { - return new Promise(resolve => { - commit('DEL_RIGHT_VIEWS', view) - resolve([...state.visitedViews]) - }) - }, - delLeftTags({ commit }, view) { - return new Promise(resolve => { - commit('DEL_LEFT_VIEWS', view) - resolve([...state.visitedViews]) - }) - }, - // 恢复持久化的 tags - loadPersistedViews({ commit }) { - const views = loadVisitedViews() - views.forEach(view => { - commit('ADD_VISITED_VIEW', view) - }) - }, -} - -export default { - namespaced: true, - state, - mutations, - actions -} diff --git a/frontend/src/store/modules/user.js b/frontend/src/store/modules/user.js deleted file mode 100644 index 82d418841..000000000 --- a/frontend/src/store/modules/user.js +++ /dev/null @@ -1,129 +0,0 @@ -import store from '@/store' -import router from '@/router' -import cache from '@/plugins/cache' -import { MessageBox } from 'element-ui' -import { login, logout, getInfo } from '@/api/login' -import { getToken, setToken, removeToken } from '@/utils/auth' -import { isHttp, isEmpty } from "@/utils/validate" -import defAva from '@/assets/images/profile.jpg' - -const user = { - state: { - token: getToken(), - id: '', - name: '', - nickName: '', - avatar: '', - roles: [], - permissions: [] - }, - - mutations: { - SET_TOKEN: (state, token) => { - state.token = token - }, - SET_ID: (state, id) => { - state.id = id - }, - SET_NAME: (state, name) => { - state.name = name - }, - SET_NICK_NAME: (state, nickName) => { - state.nickName = nickName - }, - SET_AVATAR: (state, avatar) => { - state.avatar = avatar - }, - SET_ROLES: (state, roles) => { - state.roles = roles - }, - SET_PERMISSIONS: (state, permissions) => { - state.permissions = permissions - } - }, - - actions: { - // 登录 - Login({ commit }, userInfo) { - const username = userInfo.username.trim() - const password = userInfo.password - const code = userInfo.code - const uuid = userInfo.uuid - return new Promise((resolve, reject) => { - login(username, password, code, uuid).then(res => { - setToken(res.token) - commit('SET_TOKEN', res.token) - store.dispatch('lock/unlockScreen') - resolve() - }).catch(error => { - reject(error) - }) - }) - }, - - // 获取用户信息 - GetInfo({ commit, state }) { - return new Promise((resolve, reject) => { - getInfo().then(res => { - const user = res.user - let avatar = user.avatar || "" - if (!isHttp(avatar)) { - avatar = (isEmpty(avatar)) ? defAva : process.env.VUE_APP_BASE_API + avatar - } - if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组 - commit('SET_ROLES', res.roles) - commit('SET_PERMISSIONS', res.permissions) - } else { - commit('SET_ROLES', ['ROLE_DEFAULT']) - } - commit('SET_ID', user.userId) - commit('SET_NAME', user.userName) - commit('SET_NICK_NAME', user.nickName) - commit('SET_AVATAR', avatar) - cache.session.set('pwrChrtype', res.pwdChrtype) - /* 初始密码提示 */ - if(res.isDefaultModifyPwd) { - MessageBox.confirm('您的密码还是初始密码,请修改密码!', '安全提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { - router.push({ name: 'Profile', params: { activeTab: 'resetPwd' } }) - }).catch(() => {}) - } - /* 过期密码提示 */ - if(!res.isDefaultModifyPwd && res.isPasswordExpired) { - MessageBox.confirm('您的密码已过期,请尽快修改密码!', '安全提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { - router.push({ name: 'Profile', params: { activeTab: 'resetPwd' } }) - }).catch(() => {}) - } - resolve(res) - }).catch(error => { - reject(error) - }) - }) - }, - - // 退出系统 - LogOut({ commit, state }) { - return new Promise((resolve, reject) => { - logout(state.token).then(() => { - commit('SET_TOKEN', '') - commit('SET_ROLES', []) - commit('SET_PERMISSIONS', []) - removeToken() - resolve() - }).catch(error => { - reject(error) - }) - }) - }, - - // 前端 登出 - FedLogOut({ commit }) { - return new Promise(resolve => { - commit('SET_TOKEN', '') - removeToken() - resolve() - }) - } - } -} - -export default user diff --git a/frontend/src/utils/adaptive.js b/frontend/src/utils/adaptive.js deleted file mode 100644 index 7beb35232..000000000 --- a/frontend/src/utils/adaptive.js +++ /dev/null @@ -1,161 +0,0 @@ -/** - * 全局视口等比缩放 —— 让整个系统在不同大小屏幕(桌面 1280~4K)下布局不崩塌。 - * - * 原理: - * 以 DESIGN_WIDTH(1920)为设计基准宽度。将视口宽度与设计宽的比值作为缩放倍数, - * 作用到文档根节点 的 zoom 上: - * - 视口 < 设计宽(如 1280):zoom < 1,整体等比缩小,避免窄屏布局被撑破; - * - 视口 = 设计宽(1920):zoom = 1,原生 1:1 显示; - * - 视口 > 设计宽(如 4K 3840):zoom = 2,整体等比放大,大屏不再留白/字小。 - * 缩放倍数被限制在 MIN_SCALE ~ MAX_SCALE 之间,MAX_SCALE=2 恰好覆盖 4K(3840/1920)。 - * - * 采用 zoom 挂在 documentElement 上,可覆盖包括 Element UI 挂载到 body 的 - * 弹窗/提示/下拉选择在内的所有内容,保证整套界面一致缩放、不塌陷。 - * - * 兼容性: - * - zoom:Chrome/Edge/Safari/Opera 全系、Firefox 126+(2024-05 起)、 - * 以及国内常见 Chromium 内核浏览器(360/QQ/微信等)均支持; - * - 本方案对不支持 zoom 的旧浏览器(如 2024 前的 Firefox)做能力探测, - * 自动降级为 transform: scale() 回退,保证不崩塌、可正常使用。 - */ - -let initialized = false - -export const DEFAULT_DESIGN_WIDTH = 1920 -// 最小缩放倍数:极窄视口的安全下限,避免文字过小/布局异常 -export const MIN_SCALE = 0.5 -// 最大缩放倍数:2 对应 4K(3840/1920=2),更高分辨率也封顶在此,避免过度放大 -export const MAX_SCALE = 2 - -/** - * 探测当前浏览器是否支持 CSS zoom 属性。 - * 现代 Chromium/Safari/Firefox(≥126) 返回 true;旧 Firefox(<126) 返回 false。 - * @returns {boolean} - */ -function isZoomSupported() { - const el = document.createElement('div') - el.style.zoom = '0.5' - // 能读回 "0.5" 说明浏览器真正支持 - return el.style.zoom === '0.5' -} - -/** - * 初始化全局自适应。可在任意入口调用,重复调用幂等。 - * @param {number} [designWidth] 设计基准宽度,默认 1920 - */ -export function initAdaptive(designWidth = DEFAULT_DESIGN_WIDTH) { - if (initialized) { - return - } - initialized = true - - const useZoom = isZoomSupported() - - // rAF 帧对齐节流:把同一帧内多次 resize 合并为一次 - let rafId = null - // 真实写入节流 + 尾随兜底:拖拽/设备模拟期间 resize 高频触发, - // 若每帧都写 html.zoom 会强制整页重排+重绘导致卡顿,因此限制真实写入频率 - let lastAppliedScale = -1 - let lastWriteAt = 0 - let trailingTimer = null - const WRITE_MIN_INTERVAL = 100 // ms - - function computeScale() { - const root = document.documentElement - const width = window.innerWidth || (root && root.clientWidth) || designWidth - const ratio = width / designWidth - // 收敛到 [MIN_SCALE, MAX_SCALE],规避极端宽高的异常比例 - return Math.min(MAX_SCALE, Math.max(MIN_SCALE, ratio)) - } - - function writeScale(scale) { - const root = document.documentElement - if (!root) { - return - } - // 值未变化:跳过,避免冗余的样式失效/整页重排 - if (Math.abs(scale - lastAppliedScale) < 1e-4) { - return - } - lastAppliedScale = scale - - if (scale === 1) { - clearScale(root) - return - } - - if (useZoom) { - // 首选:zoom 参与布局计算,视觉与占位一致,最平滑 - root.style.zoom = String(scale) - // 注入缩放与逆缩放变量:逆缩放用于把挂到 body 的 Element 浮层还原为 1:1, - // 以抵消 zoom 对 getBoundingClientRect 坐标造成的二次缩放(否则下拉框位置错乱) - root.style.setProperty('--adaptive-scale', String(scale)) - root.style.setProperty('--adaptive-scale-inv', String(1 / scale)) - } else { - // 回退:transform 仅影响视觉;将布局宽度固定为设计宽并从左上角缩放, - // 使其铺满视口且不改变内部结构,旧浏览器也能正常使用 - root.style.transformOrigin = 'top left' - root.style.width = `${designWidth}px` - root.style.transform = `scale(${scale})` - } - } - - function clearScale(root) { - if (useZoom) { - root.style.zoom = '' - root.style.removeProperty('--adaptive-scale') - root.style.removeProperty('--adaptive-scale-inv') - } else { - root.style.transform = '' - root.style.transformOrigin = '' - root.style.width = '' - } - } - - /** 立即计算并写入一次(带值变化守卫) */ - function applyNow() { - lastWriteAt = Date.now() - writeScale(computeScale()) - } - - function onResize() { - if (document.hidden) { - return // 后台标签不执行,避免无谓开销 - } - if (rafId) { - return // 本帧内已有待执行任务,合并 - } - rafId = window.requestAnimationFrame(() => { - rafId = null - if (document.hidden) { - return - } - const now = Date.now() - if (trailingTimer) { - clearTimeout(trailingTimer) - } - // 距上次真实写入已超过阈值才立即写入,其余情况靠尾随兜底,避免满帧整页重排 - if (now - lastWriteAt >= WRITE_MIN_INTERVAL) { - applyNow() - } - // 尾随:拖拽/改变尺寸停下后,确保落到最终窗口尺寸 - trailingTimer = setTimeout(applyNow, WRITE_MIN_INTERVAL) - }) - } - - function onVisibilityChange() { - if (!document.hidden) { - // 从后台切回时补算一次 - if (trailingTimer) { - clearTimeout(trailingTimer) - } - applyNow() - } - } - - // 首次:渲染前同步应用一次,避免首帧闪烁 - applyNow() - window.addEventListener('resize', onResize) - // 从后台标签切回来时,若期间窗口尺寸变化(因 hidden 被跳过)需补算一次 - document.addEventListener('visibilitychange', onVisibilityChange) -} \ No newline at end of file diff --git a/frontend/src/utils/auth.js b/frontend/src/utils/auth.js deleted file mode 100644 index 51a5f6e4f..000000000 --- a/frontend/src/utils/auth.js +++ /dev/null @@ -1,15 +0,0 @@ -import Cookies from 'js-cookie' - -const TokenKey = 'Admin-Token' - -export function getToken() { - return Cookies.get(TokenKey) -} - -export function setToken(token) { - return Cookies.set(TokenKey, token) -} - -export function removeToken() { - return Cookies.remove(TokenKey) -} diff --git a/frontend/src/utils/dict/Dict.js b/frontend/src/utils/dict/Dict.js deleted file mode 100644 index db9f15900..000000000 --- a/frontend/src/utils/dict/Dict.js +++ /dev/null @@ -1,82 +0,0 @@ -import Vue from 'vue' -import { mergeRecursive } from "@/utils/roomroot" -import DictMeta from './DictMeta' -import DictData from './DictData' - -const DEFAULT_DICT_OPTIONS = { - types: [], -} - -/** - * @classdesc 字典 - * @property {Object} label 标签对象,内部属性名为字典类型名称 - * @property {Object} dict 字段数组,内部属性名为字典类型名称 - * @property {Array.} _dictMetas 字典元数据数组 - */ -export default class Dict { - constructor() { - this.owner = null - this.label = {} - this.type = {} - } - - init(options) { - if (options instanceof Array) { - options = { types: options } - } - const opts = mergeRecursive(DEFAULT_DICT_OPTIONS, options) - if (opts.types === undefined) { - throw new Error('need dict types') - } - const ps = [] - this._dictMetas = opts.types.map(t => DictMeta.parse(t)) - this._dictMetas.forEach(dictMeta => { - const type = dictMeta.type - Vue.set(this.label, type, {}) - Vue.set(this.type, type, []) - if (dictMeta.lazy) { - return - } - ps.push(loadDict(this, dictMeta)) - }) - return Promise.all(ps) - } - - /** - * 重新加载字典 - * @param {String} type 字典类型 - */ - reloadDict(type) { - const dictMeta = this._dictMetas.find(e => e.type === type) - if (dictMeta === undefined) { - return Promise.reject(`the dict meta of ${type} was not found`) - } - return loadDict(this, dictMeta) - } -} - -/** - * 加载字典 - * @param {Dict} dict 字典 - * @param {DictMeta} dictMeta 字典元数据 - * @returns {Promise} - */ -function loadDict(dict, dictMeta) { - return dictMeta.request(dictMeta) - .then(response => { - const type = dictMeta.type - let dicts = dictMeta.responseConverter(response, dictMeta) - if (!(dicts instanceof Array)) { - console.error('the return of responseConverter must be Array.') - dicts = [] - } else if (dicts.filter(d => d instanceof DictData).length !== dicts.length) { - console.error('the type of elements in dicts must be DictData') - dicts = [] - } - dict.type[type].splice(0, Number.MAX_SAFE_INTEGER, ...dicts) - dicts.forEach(d => { - Vue.set(dict.label[type], d.value, d.label) - }) - return dicts - }) -} diff --git a/frontend/src/utils/dict/DictConverter.js b/frontend/src/utils/dict/DictConverter.js deleted file mode 100644 index 2bd4f1c85..000000000 --- a/frontend/src/utils/dict/DictConverter.js +++ /dev/null @@ -1,17 +0,0 @@ -import DictOptions from './DictOptions' -import DictData from './DictData' - -export default function(dict, dictMeta) { - const label = determineDictField(dict, dictMeta.labelField, ...DictOptions.DEFAULT_LABEL_FIELDS) - const value = determineDictField(dict, dictMeta.valueField, ...DictOptions.DEFAULT_VALUE_FIELDS) - return new DictData(dict[label], dict[value], dict) -} - -/** - * 确定字典字段 - * @param {DictData} dict - * @param {...String} fields - */ -function determineDictField(dict, ...fields) { - return fields.find(f => Object.prototype.hasOwnProperty.call(dict, f)) -} diff --git a/frontend/src/utils/dict/DictData.js b/frontend/src/utils/dict/DictData.js deleted file mode 100644 index 402ae6069..000000000 --- a/frontend/src/utils/dict/DictData.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @classdesc 字典数据 - * @property {String} label 标签 - * @property {*} value 标签 - * @property {Object} raw 原始数据 - */ -export default class DictData { - constructor(label, value, raw) { - this.label = label - this.value = value - this.raw = raw - } -} diff --git a/frontend/src/utils/dict/DictMeta.js b/frontend/src/utils/dict/DictMeta.js deleted file mode 100644 index ac43591ff..000000000 --- a/frontend/src/utils/dict/DictMeta.js +++ /dev/null @@ -1,38 +0,0 @@ -import { mergeRecursive } from "@/utils/roomroot" -import DictOptions from './DictOptions' - -/** - * @classdesc 字典元数据 - * @property {String} type 类型 - * @property {Function} request 请求 - * @property {String} label 标签字段 - * @property {String} value 值字段 - */ -export default class DictMeta { - constructor(options) { - this.type = options.type - this.request = options.request - this.responseConverter = options.responseConverter - this.labelField = options.labelField - this.valueField = options.valueField - this.lazy = options.lazy === true - } -} - - -/** - * 解析字典元数据 - * @param {Object} options - * @returns {DictMeta} - */ -DictMeta.parse= function(options) { - let opts = null - if (typeof options === 'string') { - opts = DictOptions.metas[options] || {} - opts.type = options - } else if (typeof options === 'object') { - opts = options - } - opts = mergeRecursive(DictOptions.metas['*'], opts) - return new DictMeta(opts) -} diff --git a/frontend/src/utils/dict/DictOptions.js b/frontend/src/utils/dict/DictOptions.js deleted file mode 100644 index e5165e54c..000000000 --- a/frontend/src/utils/dict/DictOptions.js +++ /dev/null @@ -1,51 +0,0 @@ -import { mergeRecursive } from "@/utils/roomroot" -import dictConverter from './DictConverter' - -export const options = { - metas: { - '*': { - /** - * 字典请求,方法签名为function(dictMeta: DictMeta): Promise - */ - request: (dictMeta) => { - console.log(`load dict ${dictMeta.type}`) - return Promise.resolve([]) - }, - /** - * 字典响应数据转换器,方法签名为function(response: Object, dictMeta: DictMeta): DictData - */ - responseConverter, - labelField: 'label', - valueField: 'value', - }, - }, - /** - * 默认标签字段 - */ - DEFAULT_LABEL_FIELDS: ['label', 'name', 'title'], - /** - * 默认值字段 - */ - DEFAULT_VALUE_FIELDS: ['value', 'id', 'uid', 'key'], -} - -/** - * 映射字典 - * @param {Object} response 字典数据 - * @param {DictMeta} dictMeta 字典元数据 - * @returns {DictData} - */ -function responseConverter(response, dictMeta) { - const dicts = response.content instanceof Array ? response.content : response - if (dicts === undefined) { - console.warn(`no dict data of "${dictMeta.type}" found in the response`) - return [] - } - return dicts.map(d => dictConverter(d, dictMeta)) -} - -export function mergeOptions(src) { - mergeRecursive(options, src) -} - -export default options diff --git a/frontend/src/utils/dict/index.js b/frontend/src/utils/dict/index.js deleted file mode 100644 index 79ee16f83..000000000 --- a/frontend/src/utils/dict/index.js +++ /dev/null @@ -1,33 +0,0 @@ -import Dict from './Dict' -import { mergeOptions } from './DictOptions' - -export default function(Vue, options) { - mergeOptions(options) - Vue.mixin({ - data() { - if (this.$options === undefined || this.$options.dicts === undefined || this.$options.dicts === null) { - return {} - } - const dict = new Dict() - dict.owner = this - return { - dict - } - }, - created() { - if (!(this.dict instanceof Dict)) { - return - } - options.onCreated && options.onCreated(this.dict) - this.dict.init(this.$options.dicts).then(() => { - options.onReady && options.onReady(this.dict) - this.$nextTick(() => { - this.$emit('dictReady', this.dict) - if (this.$options.methods && this.$options.methods.onDictReady instanceof Function) { - this.$options.methods.onDictReady.call(this, this.dict) - } - }) - }) - }, - }) -} diff --git a/frontend/src/utils/errorCode.js b/frontend/src/utils/errorCode.js deleted file mode 100644 index 62640f37c..000000000 --- a/frontend/src/utils/errorCode.js +++ /dev/null @@ -1,6 +0,0 @@ -export default { - '401': '认证失败,无法访问系统资源', - '403': '当前操作没有权限', - '404': '访问资源不存在', - 'default': '系统未知错误,请反馈给管理员' -} diff --git a/frontend/src/utils/generator/config.js b/frontend/src/utils/generator/config.js deleted file mode 100644 index 72417393b..000000000 --- a/frontend/src/utils/generator/config.js +++ /dev/null @@ -1,438 +0,0 @@ -export const formConf = { - formRef: 'elForm', - formModel: 'formData', - size: 'medium', - labelPosition: 'right', - labelWidth: 100, - formRules: 'rules', - gutter: 15, - disabled: false, - span: 24, - formBtns: true -} - -export const inputComponents = [ - { - label: '单行文本', - tag: 'el-input', - tagIcon: 'input', - placeholder: '请输入', - defaultValue: undefined, - span: 24, - labelWidth: null, - style: { width: '100%' }, - clearable: true, - prepend: '', - append: '', - 'prefix-icon': '', - 'suffix-icon': '', - maxlength: null, - 'show-word-limit': false, - readonly: false, - disabled: false, - required: true, - regList: [], - changeTag: true, - document: 'https://element.eleme.cn/#/zh-CN/component/input' - }, - { - label: '多行文本', - tag: 'el-input', - tagIcon: 'textarea', - type: 'textarea', - placeholder: '请输入', - defaultValue: undefined, - span: 24, - labelWidth: null, - autosize: { - minRows: 4, - maxRows: 4 - }, - style: { width: '100%' }, - maxlength: null, - 'show-word-limit': false, - readonly: false, - disabled: false, - required: true, - regList: [], - changeTag: true, - document: 'https://element.eleme.cn/#/zh-CN/component/input' - }, - { - label: '密码', - tag: 'el-input', - tagIcon: 'password', - placeholder: '请输入', - defaultValue: undefined, - span: 24, - 'show-password': true, - labelWidth: null, - style: { width: '100%' }, - clearable: true, - prepend: '', - append: '', - 'prefix-icon': '', - 'suffix-icon': '', - maxlength: null, - 'show-word-limit': false, - readonly: false, - disabled: false, - required: true, - regList: [], - changeTag: true, - document: 'https://element.eleme.cn/#/zh-CN/component/input' - }, - { - label: '计数器', - tag: 'el-input-number', - tagIcon: 'number', - placeholder: '', - defaultValue: undefined, - span: 24, - labelWidth: null, - min: undefined, - max: undefined, - step: undefined, - 'step-strictly': false, - precision: undefined, - 'controls-position': '', - disabled: false, - required: true, - regList: [], - changeTag: true, - document: 'https://element.eleme.cn/#/zh-CN/component/input-number' - } -] - -export const selectComponents = [ - { - label: '下拉选择', - tag: 'el-select', - tagIcon: 'select', - placeholder: '请选择', - defaultValue: undefined, - span: 24, - labelWidth: null, - style: { width: '100%' }, - clearable: true, - disabled: false, - required: true, - filterable: false, - multiple: false, - options: [{ - label: '选项一', - value: 1 - }, { - label: '选项二', - value: 2 - }], - regList: [], - changeTag: true, - document: 'https://element.eleme.cn/#/zh-CN/component/select' - }, - { - label: '级联选择', - tag: 'el-cascader', - tagIcon: 'cascader', - placeholder: '请选择', - defaultValue: [], - span: 24, - labelWidth: null, - style: { width: '100%' }, - props: { - props: { - multiple: false - } - }, - 'show-all-levels': true, - disabled: false, - clearable: true, - filterable: false, - required: true, - options: [{ - id: 1, - value: 1, - label: '选项1', - children: [{ - id: 2, - value: 2, - label: '选项1-1' - }] - }], - dataType: 'dynamic', - labelKey: 'label', - valueKey: 'value', - childrenKey: 'children', - separator: '/', - regList: [], - changeTag: true, - document: 'https://element.eleme.cn/#/zh-CN/component/cascader' - }, - { - label: '单选框组', - tag: 'el-radio-group', - tagIcon: 'radio', - defaultValue: undefined, - span: 24, - labelWidth: null, - style: {}, - optionType: 'default', - border: false, - size: 'medium', - disabled: false, - required: true, - options: [{ - label: '选项一', - value: 1 - }, { - label: '选项二', - value: 2 - }], - regList: [], - changeTag: true, - document: 'https://element.eleme.cn/#/zh-CN/component/radio' - }, - { - label: '多选框组', - tag: 'el-checkbox-group', - tagIcon: 'checkbox', - defaultValue: [], - span: 24, - labelWidth: null, - style: {}, - optionType: 'default', - border: false, - size: 'medium', - disabled: false, - required: true, - options: [{ - label: '选项一', - value: 1 - }, { - label: '选项二', - value: 2 - }], - regList: [], - changeTag: true, - document: 'https://element.eleme.cn/#/zh-CN/component/checkbox' - }, - { - label: '开关', - tag: 'el-switch', - tagIcon: 'switch', - defaultValue: false, - span: 24, - labelWidth: null, - style: {}, - disabled: false, - required: true, - 'active-text': '', - 'inactive-text': '', - 'active-color': null, - 'inactive-color': null, - 'active-value': true, - 'inactive-value': false, - regList: [], - changeTag: true, - document: 'https://element.eleme.cn/#/zh-CN/component/switch' - }, - { - label: '滑块', - tag: 'el-slider', - tagIcon: 'slider', - defaultValue: null, - span: 24, - labelWidth: null, - disabled: false, - required: true, - min: 0, - max: 100, - step: 1, - 'show-stops': false, - range: false, - regList: [], - changeTag: true, - document: 'https://element.eleme.cn/#/zh-CN/component/slider' - }, - { - label: '时间选择', - tag: 'el-time-picker', - tagIcon: 'time', - placeholder: '请选择', - defaultValue: null, - span: 24, - labelWidth: null, - style: { width: '100%' }, - disabled: false, - clearable: true, - required: true, - 'picker-options': { - selectableRange: '00:00:00-23:59:59' - }, - format: 'HH:mm:ss', - 'value-format': 'HH:mm:ss', - regList: [], - changeTag: true, - document: 'https://element.eleme.cn/#/zh-CN/component/time-picker' - }, - { - label: '时间范围', - tag: 'el-time-picker', - tagIcon: 'time-range', - defaultValue: null, - span: 24, - labelWidth: null, - style: { width: '100%' }, - disabled: false, - clearable: true, - required: true, - 'is-range': true, - 'range-separator': '至', - 'start-placeholder': '开始时间', - 'end-placeholder': '结束时间', - format: 'HH:mm:ss', - 'value-format': 'HH:mm:ss', - regList: [], - changeTag: true, - document: 'https://element.eleme.cn/#/zh-CN/component/time-picker' - }, - { - label: '日期选择', - tag: 'el-date-picker', - tagIcon: 'date', - placeholder: '请选择', - defaultValue: null, - type: 'date', - span: 24, - labelWidth: null, - style: { width: '100%' }, - disabled: false, - clearable: true, - required: true, - format: 'yyyy-MM-dd', - 'value-format': 'yyyy-MM-dd', - readonly: false, - regList: [], - changeTag: true, - document: 'https://element.eleme.cn/#/zh-CN/component/date-picker' - }, - { - label: '日期范围', - tag: 'el-date-picker', - tagIcon: 'date-range', - defaultValue: null, - span: 24, - labelWidth: null, - style: { width: '100%' }, - type: 'daterange', - 'range-separator': '至', - 'start-placeholder': '开始日期', - 'end-placeholder': '结束日期', - disabled: false, - clearable: true, - required: true, - format: 'yyyy-MM-dd', - 'value-format': 'yyyy-MM-dd', - readonly: false, - regList: [], - changeTag: true, - document: 'https://element.eleme.cn/#/zh-CN/component/date-picker' - }, - { - label: '评分', - tag: 'el-rate', - tagIcon: 'rate', - defaultValue: 0, - span: 24, - labelWidth: null, - style: {}, - max: 5, - 'allow-half': false, - 'show-text': false, - 'show-score': false, - disabled: false, - required: true, - regList: [], - changeTag: true, - document: 'https://element.eleme.cn/#/zh-CN/component/rate' - }, - { - label: '颜色选择', - tag: 'el-color-picker', - tagIcon: 'color', - defaultValue: null, - labelWidth: null, - 'show-alpha': false, - 'color-format': '', - disabled: false, - required: true, - size: 'medium', - regList: [], - changeTag: true, - document: 'https://element.eleme.cn/#/zh-CN/component/color-picker' - }, - { - label: '上传', - tag: 'el-upload', - tagIcon: 'upload', - action: 'https://jsonplaceholder.typicode.com/posts/', - defaultValue: null, - labelWidth: null, - disabled: false, - required: true, - accept: '', - name: 'file', - 'auto-upload': true, - showTip: false, - buttonText: '点击上传', - fileSize: 2, - sizeUnit: 'MB', - 'list-type': 'text', - multiple: false, - regList: [], - changeTag: true, - document: 'https://element.eleme.cn/#/zh-CN/component/upload' - } -] - -export const layoutComponents = [ - { - layout: 'rowFormItem', - tagIcon: 'row', - type: 'default', - justify: 'start', - align: 'top', - label: '行容器', - layoutTree: true, - children: [], - document: 'https://element.eleme.cn/#/zh-CN/component/layout' - }, - { - layout: 'colFormItem', - label: '按钮', - changeTag: true, - labelWidth: null, - tag: 'el-button', - tagIcon: 'button', - span: 24, - default: '主要按钮', - type: 'primary', - icon: 'el-icon-search', - size: 'medium', - disabled: false, - document: 'https://element.eleme.cn/#/zh-CN/component/button' - } -] - -// 组件rule的触发方式,无触发方式的组件不生成rule -export const trigger = { - 'el-input': 'blur', - 'el-input-number': 'blur', - 'el-select': 'change', - 'el-radio-group': 'change', - 'el-checkbox-group': 'change', - 'el-cascader': 'change', - 'el-time-picker': 'change', - 'el-date-picker': 'change', - 'el-rate': 'change' -} diff --git a/frontend/src/utils/generator/css.js b/frontend/src/utils/generator/css.js deleted file mode 100644 index d6830ec6a..000000000 --- a/frontend/src/utils/generator/css.js +++ /dev/null @@ -1,18 +0,0 @@ -const styles = { - 'el-rate': '.el-rate{display: inline-block; vertical-align: text-top;}', - 'el-upload': '.el-upload__tip{line-height: 1.2;}' -} - -function addCss(cssList, el) { - const css = styles[el.tag] - css && cssList.indexOf(css) === -1 && cssList.push(css) - if (el.children) { - el.children.forEach(el2 => addCss(cssList, el2)) - } -} - -export function makeUpCss(conf) { - const cssList = [] - conf.fields.forEach(el => addCss(cssList, el)) - return cssList.join('\n') -} diff --git a/frontend/src/utils/generator/drawingDefault.js b/frontend/src/utils/generator/drawingDefault.js deleted file mode 100644 index 0b9ad2c3b..000000000 --- a/frontend/src/utils/generator/drawingDefault.js +++ /dev/null @@ -1,37 +0,0 @@ -export const drawingDefaultValue = [] - -export function initDrawingDefaultValue() { - if (drawingDefaultValue.length === 0) { - drawingDefaultValue.push({ - layout: 'colFormItem', - tagIcon: 'input', - label: '手机号', - vModel: 'mobile', - formId: 6, - tag: 'el-input', - placeholder: '请输入手机号', - defaultValue: '', - span: 24, - style: {width: '100%'}, - clearable: true, - prepend: '', - append: '', - 'prefix-icon': 'el-icon-mobile', - 'suffix-icon': '', - maxlength: 11, - 'show-word-limit': true, - readonly: false, - disabled: false, - required: true, - changeTag: true, - regList: [{ - pattern: '/^1(3|4|5|7|8|9)\\d{9}$/', - message: '手机号格式错误' - }] - }) - } -} - -export function cleanDrawingDefaultValue() { - drawingDefaultValue.splice(0, drawingDefaultValue.length) -} diff --git a/frontend/src/utils/generator/html.js b/frontend/src/utils/generator/html.js deleted file mode 100644 index c1d7950f4..000000000 --- a/frontend/src/utils/generator/html.js +++ /dev/null @@ -1,358 +0,0 @@ -import { trigger } from './config' - -let confGlobal -let someSpanIsNot24 - -export function dialogWrapper(str) { - return ` - ${str} -
- 取消 - 确定 -
-
` -} - -export function vueTemplate(str) { - return `` -} - -export function vueScript(str) { - return `` -} - -export function cssStyle(cssStr) { - return `` -} - -function buildFormTemplate(conf, child, type) { - let labelPosition = '' - if (conf.labelPosition !== 'right') { - labelPosition = `label-position="${conf.labelPosition}"` - } - const disabled = conf.disabled ? `:disabled="${conf.disabled}"` : '' - let str = ` - ${child} - ${buildFromBtns(conf, type)} - ` - if (someSpanIsNot24) { - str = ` - ${str} - ` - } - return str -} - -function buildFromBtns(conf, type) { - let str = '' - if (conf.formBtns && type === 'file') { - str = ` - 提交 - 重置 - ` - if (someSpanIsNot24) { - str = ` - ${str} - ` - } - } - return str -} - -// span不为24的用el-col包裹 -function colWrapper(element, str) { - if (someSpanIsNot24 || element.span !== 24) { - return ` - ${str} - ` - } - return str -} - -const layouts = { - colFormItem(element) { - let labelWidth = '' - if (element.labelWidth && element.labelWidth !== confGlobal.labelWidth) { - labelWidth = `label-width="${element.labelWidth}px"` - } - const required = !trigger[element.tag] && element.required ? 'required' : '' - const tagDom = tags[element.tag] ? tags[element.tag](element) : null - let str = ` - ${tagDom} - ` - str = colWrapper(element, str) - return str - }, - rowFormItem(element) { - const type = element.type === 'default' ? '' : `type="${element.type}"` - const justify = element.type === 'default' ? '' : `justify="${element.justify}"` - const align = element.type === 'default' ? '' : `align="${element.align}"` - const gutter = element.gutter ? `gutter="${element.gutter}"` : '' - const children = element.children.map(el => layouts[el.layout](el)) - let str = ` - ${children.join('\n')} - ` - str = colWrapper(element, str) - return str - } -} - -const tags = { - 'el-button': el => { - const { - tag, disabled - } = attrBuilder(el) - const type = el.type ? `type="${el.type}"` : '' - const icon = el.icon ? `icon="${el.icon}"` : '' - const size = el.size ? `size="${el.size}"` : '' - let child = buildElButtonChild(el) - - if (child) child = `\n${child}\n` // 换行 - return `<${el.tag} ${type} ${icon} ${size} ${disabled}>${child}` - }, - 'el-input': el => { - const { - disabled, vModel, clearable, placeholder, width - } = attrBuilder(el) - const maxlength = el.maxlength ? `:maxlength="${el.maxlength}"` : '' - const showWordLimit = el['show-word-limit'] ? 'show-word-limit' : '' - const readonly = el.readonly ? 'readonly' : '' - const prefixIcon = el['prefix-icon'] ? `prefix-icon='${el['prefix-icon']}'` : '' - const suffixIcon = el['suffix-icon'] ? `suffix-icon='${el['suffix-icon']}'` : '' - const showPassword = el['show-password'] ? 'show-password' : '' - const type = el.type ? `type="${el.type}"` : '' - const autosize = el.autosize && el.autosize.minRows - ? `:autosize="{minRows: ${el.autosize.minRows}, maxRows: ${el.autosize.maxRows}}"` - : '' - let child = buildElInputChild(el) - - if (child) child = `\n${child}\n` // 换行 - return `<${el.tag} ${vModel} ${type} ${placeholder} ${maxlength} ${showWordLimit} ${readonly} ${disabled} ${clearable} ${prefixIcon} ${suffixIcon} ${showPassword} ${autosize} ${width}>${child}` - }, - 'el-input-number': el => { - const { disabled, vModel, placeholder } = attrBuilder(el) - const controlsPosition = el['controls-position'] ? `controls-position=${el['controls-position']}` : '' - const min = el.min ? `:min='${el.min}'` : '' - const max = el.max ? `:max='${el.max}'` : '' - const step = el.step ? `:step='${el.step}'` : '' - const stepStrictly = el['step-strictly'] ? 'step-strictly' : '' - const precision = el.precision ? `:precision='${el.precision}'` : '' - - return `<${el.tag} ${vModel} ${placeholder} ${step} ${stepStrictly} ${precision} ${controlsPosition} ${min} ${max} ${disabled}>` - }, - 'el-select': el => { - const { - disabled, vModel, clearable, placeholder, width - } = attrBuilder(el) - const filterable = el.filterable ? 'filterable' : '' - const multiple = el.multiple ? 'multiple' : '' - let child = buildElSelectChild(el) - - if (child) child = `\n${child}\n` // 换行 - return `<${el.tag} ${vModel} ${placeholder} ${disabled} ${multiple} ${filterable} ${clearable} ${width}>${child}` - }, - 'el-radio-group': el => { - const { disabled, vModel } = attrBuilder(el) - const size = `size="${el.size}"` - let child = buildElRadioGroupChild(el) - - if (child) child = `\n${child}\n` // 换行 - return `<${el.tag} ${vModel} ${size} ${disabled}>${child}` - }, - 'el-checkbox-group': el => { - const { disabled, vModel } = attrBuilder(el) - const size = `size="${el.size}"` - const min = el.min ? `:min="${el.min}"` : '' - const max = el.max ? `:max="${el.max}"` : '' - let child = buildElCheckboxGroupChild(el) - - if (child) child = `\n${child}\n` // 换行 - return `<${el.tag} ${vModel} ${min} ${max} ${size} ${disabled}>${child}` - }, - 'el-switch': el => { - const { disabled, vModel } = attrBuilder(el) - const activeText = el['active-text'] ? `active-text="${el['active-text']}"` : '' - const inactiveText = el['inactive-text'] ? `inactive-text="${el['inactive-text']}"` : '' - const activeColor = el['active-color'] ? `active-color="${el['active-color']}"` : '' - const inactiveColor = el['inactive-color'] ? `inactive-color="${el['inactive-color']}"` : '' - const activeValue = el['active-value'] !== true ? `:active-value='${JSON.stringify(el['active-value'])}'` : '' - const inactiveValue = el['inactive-value'] !== false ? `:inactive-value='${JSON.stringify(el['inactive-value'])}'` : '' - - return `<${el.tag} ${vModel} ${activeText} ${inactiveText} ${activeColor} ${inactiveColor} ${activeValue} ${inactiveValue} ${disabled}>` - }, - 'el-cascader': el => { - const { - disabled, vModel, clearable, placeholder, width - } = attrBuilder(el) - const options = el.options ? `:options="${el.vModel}Options"` : '' - const props = el.props ? `:props="${el.vModel}Props"` : '' - const showAllLevels = el['show-all-levels'] ? '' : ':show-all-levels="false"' - const filterable = el.filterable ? 'filterable' : '' - const separator = el.separator === '/' ? '' : `separator="${el.separator}"` - - return `<${el.tag} ${vModel} ${options} ${props} ${width} ${showAllLevels} ${placeholder} ${separator} ${filterable} ${clearable} ${disabled}>` - }, - 'el-slider': el => { - const { disabled, vModel } = attrBuilder(el) - const min = el.min ? `:min='${el.min}'` : '' - const max = el.max ? `:max='${el.max}'` : '' - const step = el.step ? `:step='${el.step}'` : '' - const range = el.range ? 'range' : '' - const showStops = el['show-stops'] ? `:show-stops="${el['show-stops']}"` : '' - - return `<${el.tag} ${min} ${max} ${step} ${vModel} ${range} ${showStops} ${disabled}>` - }, - 'el-time-picker': el => { - const { - disabled, vModel, clearable, placeholder, width - } = attrBuilder(el) - const startPlaceholder = el['start-placeholder'] ? `start-placeholder="${el['start-placeholder']}"` : '' - const endPlaceholder = el['end-placeholder'] ? `end-placeholder="${el['end-placeholder']}"` : '' - const rangeSeparator = el['range-separator'] ? `range-separator="${el['range-separator']}"` : '' - const isRange = el['is-range'] ? 'is-range' : '' - const format = el.format ? `format="${el.format}"` : '' - const valueFormat = el['value-format'] ? `value-format="${el['value-format']}"` : '' - const pickerOptions = el['picker-options'] ? `:picker-options='${JSON.stringify(el['picker-options'])}'` : '' - - return `<${el.tag} ${vModel} ${isRange} ${format} ${valueFormat} ${pickerOptions} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${disabled}>` - }, - 'el-date-picker': el => { - const { - disabled, vModel, clearable, placeholder, width - } = attrBuilder(el) - const startPlaceholder = el['start-placeholder'] ? `start-placeholder="${el['start-placeholder']}"` : '' - const endPlaceholder = el['end-placeholder'] ? `end-placeholder="${el['end-placeholder']}"` : '' - const rangeSeparator = el['range-separator'] ? `range-separator="${el['range-separator']}"` : '' - const format = el.format ? `format="${el.format}"` : '' - const valueFormat = el['value-format'] ? `value-format="${el['value-format']}"` : '' - const type = el.type === 'date' ? '' : `type="${el.type}"` - const readonly = el.readonly ? 'readonly' : '' - - return `<${el.tag} ${type} ${vModel} ${format} ${valueFormat} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${readonly} ${disabled}>` - }, - 'el-rate': el => { - const { disabled, vModel } = attrBuilder(el) - const max = el.max ? `:max='${el.max}'` : '' - const allowHalf = el['allow-half'] ? 'allow-half' : '' - const showText = el['show-text'] ? 'show-text' : '' - const showScore = el['show-score'] ? 'show-score' : '' - - return `<${el.tag} ${vModel} ${allowHalf} ${showText} ${showScore} ${disabled}>` - }, - 'el-color-picker': el => { - const { disabled, vModel } = attrBuilder(el) - const size = `size="${el.size}"` - const showAlpha = el['show-alpha'] ? 'show-alpha' : '' - const colorFormat = el['color-format'] ? `color-format="${el['color-format']}"` : '' - - return `<${el.tag} ${vModel} ${size} ${showAlpha} ${colorFormat} ${disabled}>` - }, - 'el-upload': el => { - const disabled = el.disabled ? ':disabled=\'true\'' : '' - const action = el.action ? `:action="${el.vModel}Action"` : '' - const multiple = el.multiple ? 'multiple' : '' - const listType = el['list-type'] !== 'text' ? `list-type="${el['list-type']}"` : '' - const accept = el.accept ? `accept="${el.accept}"` : '' - const name = el.name !== 'file' ? `name="${el.name}"` : '' - const autoUpload = el['auto-upload'] === false ? ':auto-upload="false"' : '' - const beforeUpload = `:before-upload="${el.vModel}BeforeUpload"` - const fileList = `:file-list="${el.vModel}fileList"` - const ref = `ref="${el.vModel}"` - let child = buildElUploadChild(el) - - if (child) child = `\n${child}\n` // 换行 - return `<${el.tag} ${ref} ${fileList} ${action} ${autoUpload} ${multiple} ${beforeUpload} ${listType} ${accept} ${name} ${disabled}>${child}` - } -} - -function attrBuilder(el) { - return { - vModel: `v-model="${confGlobal.formModel}.${el.vModel}"`, - clearable: el.clearable ? 'clearable' : '', - placeholder: el.placeholder ? `placeholder="${el.placeholder}"` : '', - width: el.style && el.style.width ? ':style="{width: \'100%\'}"' : '', - disabled: el.disabled ? ':disabled=\'true\'' : '' - } -} - -// el-buttin 子级 -function buildElButtonChild(conf) { - const children = [] - if (conf.default) { - children.push(conf.default) - } - return children.join('\n') -} - -// el-input innerHTML -function buildElInputChild(conf) { - const children = [] - if (conf.prepend) { - children.push(``) - } - if (conf.append) { - children.push(``) - } - return children.join('\n') -} - -function buildElSelectChild(conf) { - const children = [] - if (conf.options && conf.options.length) { - children.push(``) - } - return children.join('\n') -} - -function buildElRadioGroupChild(conf) { - const children = [] - if (conf.options && conf.options.length) { - const tag = conf.optionType === 'button' ? 'el-radio-button' : 'el-radio' - const border = conf.border ? 'border' : '' - children.push(`<${tag} v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}`) - } - return children.join('\n') -} - -function buildElCheckboxGroupChild(conf) { - const children = [] - if (conf.options && conf.options.length) { - const tag = conf.optionType === 'button' ? 'el-checkbox-button' : 'el-checkbox' - const border = conf.border ? 'border' : '' - children.push(`<${tag} v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}`) - } - return children.join('\n') -} - -function buildElUploadChild(conf) { - const list = [] - if (conf['list-type'] === 'picture-card') list.push('') - else list.push(`${conf.buttonText}`) - if (conf.showTip) list.push(`
只能上传不超过 ${conf.fileSize}${conf.sizeUnit} 的${conf.accept}文件
`) - return list.join('\n') -} - -export function makeUpHtml(conf, type) { - const htmlList = [] - confGlobal = conf - someSpanIsNot24 = conf.fields.some(item => item.span !== 24) - conf.fields.forEach(el => { - htmlList.push(layouts[el.layout](el)) - }) - const htmlStr = htmlList.join('\n') - - let temp = buildFormTemplate(conf, htmlStr, type) - if (type === 'dialog') { - temp = dialogWrapper(temp) - } - confGlobal = null - return temp -} diff --git a/frontend/src/utils/generator/icon.json b/frontend/src/utils/generator/icon.json deleted file mode 100644 index 2d9999a31..000000000 --- a/frontend/src/utils/generator/icon.json +++ /dev/null @@ -1 +0,0 @@ -["platform-eleme","eleme","delete-solid","delete","s-tools","setting","user-solid","user","phone","phone-outline","more","more-outline","star-on","star-off","s-goods","goods","warning","warning-outline","question","info","remove","circle-plus","success","error","zoom-in","zoom-out","remove-outline","circle-plus-outline","circle-check","circle-close","s-help","help","minus","plus","check","close","picture","picture-outline","picture-outline-round","upload","upload2","download","camera-solid","camera","video-camera-solid","video-camera","message-solid","bell","s-cooperation","s-order","s-platform","s-fold","s-unfold","s-operation","s-promotion","s-home","s-release","s-ticket","s-management","s-open","s-shop","s-marketing","s-flag","s-comment","s-finance","s-claim","s-custom","s-opportunity","s-data","s-check","s-grid","menu","share","d-caret","caret-left","caret-right","caret-bottom","caret-top","bottom-left","bottom-right","back","right","bottom","top","top-left","top-right","arrow-left","arrow-right","arrow-down","arrow-up","d-arrow-left","d-arrow-right","video-pause","video-play","refresh","refresh-right","refresh-left","finished","sort","sort-up","sort-down","rank","loading","view","c-scale-to-original","date","edit","edit-outline","folder","folder-opened","folder-add","folder-remove","folder-delete","folder-checked","tickets","document-remove","document-delete","document-copy","document-checked","document","document-add","printer","paperclip","takeaway-box","search","monitor","attract","mobile","scissors","umbrella","headset","brush","mouse","coordinate","magic-stick","reading","data-line","data-board","pie-chart","data-analysis","collection-tag","film","suitcase","suitcase-1","receiving","collection","files","notebook-1","notebook-2","toilet-paper","office-building","school","table-lamp","house","no-smoking","smoking","shopping-cart-full","shopping-cart-1","shopping-cart-2","shopping-bag-1","shopping-bag-2","sold-out","sell","present","box","bank-card","money","coin","wallet","discount","price-tag","news","guide","male","female","thumb","cpu","link","connection","open","turn-off","set-up","chat-round","chat-line-round","chat-square","chat-dot-round","chat-dot-square","chat-line-square","message","postcard","position","turn-off-microphone","microphone","close-notification","bangzhu","time","odometer","crop","aim","switch-button","full-screen","copy-document","mic","stopwatch","medal-1","medal","trophy","trophy-1","first-aid-kit","discover","place","location","location-outline","location-information","add-location","delete-location","map-location","alarm-clock","timer","watch-1","watch","lock","unlock","key","service","mobile-phone","bicycle","truck","ship","basketball","football","soccer","baseball","wind-power","light-rain","lightning","heavy-rain","sunrise","sunrise-1","sunset","sunny","cloudy","partly-cloudy","cloudy-and-sunny","moon","moon-night","dish","dish-1","food","chicken","fork-spoon","knife-fork","burger","tableware","sugar","dessert","ice-cream","hot-water","water-cup","coffee-cup","cold-drink","goblet","goblet-full","goblet-square","goblet-square-full","refrigerator","grape","watermelon","cherry","apple","pear","orange","coffee","ice-tea","ice-drink","milk-tea","potato-strips","lollipop","ice-cream-square","ice-cream-round"] \ No newline at end of file diff --git a/frontend/src/utils/generator/js.js b/frontend/src/utils/generator/js.js deleted file mode 100644 index cde8bf240..000000000 --- a/frontend/src/utils/generator/js.js +++ /dev/null @@ -1,235 +0,0 @@ -import { exportDefault, titleCase } from '@/utils/index' -import { trigger } from './config' - -const units = { - KB: '1024', - MB: '1024 / 1024', - GB: '1024 / 1024 / 1024' -} -let confGlobal -const inheritAttrs = { - file: '', - dialog: 'inheritAttrs: false,' -} - - -export function makeUpJs(conf, type) { - confGlobal = conf = JSON.parse(JSON.stringify(conf)) - const dataList = [] - const ruleList = [] - const optionsList = [] - const propsList = [] - const methodList = mixinMethod(type) - const uploadVarList = [] - - conf.fields.forEach(el => { - buildAttributes(el, dataList, ruleList, optionsList, methodList, propsList, uploadVarList) - }) - - const script = buildexport( - conf, - type, - dataList.join('\n'), - ruleList.join('\n'), - optionsList.join('\n'), - uploadVarList.join('\n'), - propsList.join('\n'), - methodList.join('\n') - ) - confGlobal = null - return script -} - -function buildAttributes(el, dataList, ruleList, optionsList, methodList, propsList, uploadVarList) { - buildData(el, dataList) - buildRules(el, ruleList) - - if (el.options && el.options.length) { - buildOptions(el, optionsList) - if (el.dataType === 'dynamic') { - const model = `${el.vModel}Options` - const options = titleCase(model) - buildOptionMethod(`get${options}`, model, methodList) - } - } - - if (el.props && el.props.props) { - buildProps(el, propsList) - } - - if (el.action && el.tag === 'el-upload') { - uploadVarList.push( - `${el.vModel}Action: '${el.action}', - ${el.vModel}fileList: [],` - ) - methodList.push(buildBeforeUpload(el)) - if (!el['auto-upload']) { - methodList.push(buildSubmitUpload(el)) - } - } - - if (el.children) { - el.children.forEach(el2 => { - buildAttributes(el2, dataList, ruleList, optionsList, methodList, propsList, uploadVarList) - }) - } -} - -function mixinMethod(type) { - const list = []; const - minxins = { - file: confGlobal.formBtns ? { - submitForm: `submitForm() { - this.$refs['${confGlobal.formRef}'].validate(valid => { - if(!valid) return - // TODO 提交表单 - }) - },`, - resetForm: `resetForm() { - this.$refs['${confGlobal.formRef}'].resetFields() - },` - } : null, - dialog: { - onOpen: 'onOpen() {},', - onClose: `onClose() { - this.$refs['${confGlobal.formRef}'].resetFields() - },`, - close: `close() { - this.$emit('update:visible', false) - },`, - handleConfirm: `handleConfirm() { - this.$refs['${confGlobal.formRef}'].validate(valid => { - if(!valid) return - this.close() - }) - },` - } - } - - const methods = minxins[type] - if (methods) { - Object.keys(methods).forEach(key => { - list.push(methods[key]) - }) - } - - return list -} - -function buildData(conf, dataList) { - if (conf.vModel === undefined) return - let defaultValue - if (typeof (conf.defaultValue) === 'string' && !conf.multiple) { - defaultValue = `'${conf.defaultValue}'` - } else { - defaultValue = `${JSON.stringify(conf.defaultValue)}` - } - dataList.push(`${conf.vModel}: ${defaultValue},`) -} - -function buildRules(conf, ruleList) { - if (conf.vModel === undefined) return - const rules = [] - if (trigger[conf.tag]) { - if (conf.required) { - const type = Array.isArray(conf.defaultValue) ? 'type: \'array\',' : '' - let message = Array.isArray(conf.defaultValue) ? `请至少选择一个${conf.vModel}` : conf.placeholder - if (message === undefined) message = `${conf.label}不能为空` - rules.push(`{ required: true, ${type} message: '${message}', trigger: '${trigger[conf.tag]}' }`) - } - if (conf.regList && Array.isArray(conf.regList)) { - conf.regList.forEach(item => { - if (item.pattern) { - rules.push(`{ pattern: ${eval(item.pattern)}, message: '${item.message}', trigger: '${trigger[conf.tag]}' }`) - } - }) - } - ruleList.push(`${conf.vModel}: [${rules.join(',')}],`) - } -} - -function buildOptions(conf, optionsList) { - if (conf.vModel === undefined) return - if (conf.dataType === 'dynamic') { conf.options = [] } - const str = `${conf.vModel}Options: ${JSON.stringify(conf.options)},` - optionsList.push(str) -} - -function buildProps(conf, propsList) { - if (conf.dataType === 'dynamic') { - conf.valueKey !== 'value' && (conf.props.props.value = conf.valueKey) - conf.labelKey !== 'label' && (conf.props.props.label = conf.labelKey) - conf.childrenKey !== 'children' && (conf.props.props.children = conf.childrenKey) - } - const str = `${conf.vModel}Props: ${JSON.stringify(conf.props.props)},` - propsList.push(str) -} - -function buildBeforeUpload(conf) { - const unitNum = units[conf.sizeUnit]; let rightSizeCode = ''; let acceptCode = ''; const - returnList = [] - if (conf.fileSize) { - rightSizeCode = `let isRightSize = file.size / ${unitNum} < ${conf.fileSize} - if(!isRightSize){ - this.$message.error('文件大小超过 ${conf.fileSize}${conf.sizeUnit}') - }` - returnList.push('isRightSize') - } - if (conf.accept) { - acceptCode = `let isAccept = new RegExp('${conf.accept}').test(file.type) - if(!isAccept){ - this.$message.error('应该选择${conf.accept}类型的文件') - }` - returnList.push('isAccept') - } - const str = `${conf.vModel}BeforeUpload(file) { - ${rightSizeCode} - ${acceptCode} - return ${returnList.join('&&')} - },` - return returnList.length ? str : '' -} - -function buildSubmitUpload(conf) { - const str = `submitUpload() { - this.$refs['${conf.vModel}'].submit() - },` - return str -} - -function buildOptionMethod(methodName, model, methodList) { - const str = `${methodName}() { - // TODO 发起请求获取数据 - this.${model} - },` - methodList.push(str) -} - -function buildexport(conf, type, data, rules, selectOptions, uploadVar, props, methods) { - const str = `${exportDefault}{ - ${inheritAttrs[type]} - components: {}, - props: [], - data () { - return { - ${conf.formModel}: { - ${data} - }, - ${conf.formRules}: { - ${rules} - }, - ${uploadVar} - ${selectOptions} - ${props} - } - }, - computed: {}, - watch: {}, - created () {}, - mounted () {}, - methods: { - ${methods} - } -}` - return str -} diff --git a/frontend/src/utils/generator/render.js b/frontend/src/utils/generator/render.js deleted file mode 100644 index c312ae566..000000000 --- a/frontend/src/utils/generator/render.js +++ /dev/null @@ -1,126 +0,0 @@ -import { makeMap } from '@/utils/index' - -// 参考https://github.com/vuejs/vue/blob/v2.6.10/src/platforms/web/server/util.js -const isAttr = makeMap( - 'accept,accept-charset,accesskey,action,align,alt,async,autocomplete,' - + 'autofocus,autoplay,autosave,bgcolor,border,buffered,challenge,charset,' - + 'checked,cite,class,code,codebase,color,cols,colspan,content,http-equiv,' - + 'name,contenteditable,contextmenu,controls,coords,data,datetime,default,' - + 'defer,dir,dirname,disabled,download,draggable,dropzone,enctype,method,for,' - + 'form,formaction,headers,height,hidden,high,href,hreflang,http-equiv,' - + 'icon,id,ismap,itemprop,keytype,kind,label,lang,language,list,loop,low,' - + 'manifest,max,maxlength,media,method,GET,POST,min,multiple,email,file,' - + 'muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,' - + 'preload,radiogroup,readonly,rel,required,reversed,rows,rowspan,sandbox,' - + 'scope,scoped,seamless,selected,shape,size,type,text,password,sizes,span,' - + 'spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,' - + 'target,title,type,usemap,value,width,wrap' -) - -function vModel(self, dataObject, defaultValue) { - dataObject.props.value = defaultValue - - dataObject.on.input = val => { - self.$emit('input', val) - } -} - -const componentChild = { - 'el-button': { - default(h, conf, key) { - return conf[key] - }, - }, - 'el-input': { - prepend(h, conf, key) { - return - }, - append(h, conf, key) { - return - } - }, - 'el-select': { - options(h, conf, key) { - const list = [] - conf.options.forEach(item => { - list.push() - }) - return list - } - }, - 'el-radio-group': { - options(h, conf, key) { - const list = [] - conf.options.forEach(item => { - if (conf.optionType === 'button') list.push({item.label}) - else list.push({item.label}) - }) - return list - } - }, - 'el-checkbox-group': { - options(h, conf, key) { - const list = [] - conf.options.forEach(item => { - if (conf.optionType === 'button') { - list.push({item.label}) - } else { - list.push({item.label}) - } - }) - return list - } - }, - 'el-upload': { - 'list-type': (h, conf, key) => { - const list = [] - if (conf['list-type'] === 'picture-card') { - list.push() - } else { - list.push({conf.buttonText}) - } - if (conf.showTip) { - list.push(
只能上传不超过 {conf.fileSize}{conf.sizeUnit} 的{conf.accept}文件
) - } - return list - } - } -} - -export default { - render(h) { - const dataObject = { - attrs: {}, - props: {}, - on: {}, - style: {} - } - const confClone = JSON.parse(JSON.stringify(this.conf)) - const children = [] - - const childObjs = componentChild[confClone.tag] - if (childObjs) { - Object.keys(childObjs).forEach(key => { - const childFunc = childObjs[key] - if (confClone[key]) { - children.push(childFunc(h, confClone, key)) - } - }) - } - - Object.keys(confClone).forEach(key => { - const val = confClone[key] - if (key === 'vModel') { - vModel(this, dataObject, confClone.defaultValue) - } else if (dataObject[key]) { - dataObject[key] = val - } else if (!isAttr(key)) { - dataObject.props[key] = val - } else { - dataObject.attrs[key] = val - } - }) - return h(this.conf.tag, dataObject, children) - }, - props: ['conf'] -} diff --git a/frontend/src/utils/index.js b/frontend/src/utils/index.js deleted file mode 100644 index 2a92f1529..000000000 --- a/frontend/src/utils/index.js +++ /dev/null @@ -1,390 +0,0 @@ -import { parseTime } from './roomroot' - -/** - * 表格时间格式化 - */ -export function formatDate(cellValue) { - if (cellValue == null || cellValue == "") return "" - var date = new Date(cellValue) - var year = date.getFullYear() - var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1 - var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate() - var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours() - var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes() - var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds() - return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds -} - -/** - * @param {number} time - * @param {string} option - * @returns {string} - */ -export function formatTime(time, option) { - if (('' + time).length === 10) { - time = parseInt(time) * 1000 - } else { - time = +time - } - const d = new Date(time) - const now = Date.now() - - const diff = (now - d) / 1000 - - if (diff < 30) { - return '刚刚' - } else if (diff < 3600) { - // less 1 hour - return Math.ceil(diff / 60) + '分钟前' - } else if (diff < 3600 * 24) { - return Math.ceil(diff / 3600) + '小时前' - } else if (diff < 3600 * 24 * 2) { - return '1天前' - } - if (option) { - return parseTime(time, option) - } else { - return ( - d.getMonth() + - 1 + - '月' + - d.getDate() + - '日' + - d.getHours() + - '时' + - d.getMinutes() + - '分' - ) - } -} - -/** - * @param {string} url - * @returns {Object} - */ -export function getQueryObject(url) { - url = url == null ? window.location.href : url - const search = url.substring(url.lastIndexOf('?') + 1) - const obj = {} - const reg = /([^?&=]+)=([^?&=]*)/g - search.replace(reg, (rs, $1, $2) => { - const name = decodeURIComponent($1) - let val = decodeURIComponent($2) - val = String(val) - obj[name] = val - return rs - }) - return obj -} - -/** - * @param {string} input value - * @returns {number} output value - */ -export function byteLength(str) { - // returns the byte length of an utf8 string - let s = str.length - for (var i = str.length - 1; i >= 0; i--) { - const code = str.charCodeAt(i) - if (code > 0x7f && code <= 0x7ff) s++ - else if (code > 0x7ff && code <= 0xffff) s += 2 - if (code >= 0xDC00 && code <= 0xDFFF) i-- - } - return s -} - -/** - * @param {Array} actual - * @returns {Array} - */ -export function cleanArray(actual) { - const newArray = [] - for (let i = 0; i < actual.length; i++) { - if (actual[i]) { - newArray.push(actual[i]) - } - } - return newArray -} - -/** - * @param {Object} json - * @returns {Array} - */ -export function param(json) { - if (!json) return '' - return cleanArray( - Object.keys(json).map(key => { - if (json[key] === undefined) return '' - return encodeURIComponent(key) + '=' + encodeURIComponent(json[key]) - }) - ).join('&') -} - -/** - * @param {string} url - * @returns {Object} - */ -export function param2Obj(url) { - const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ') - if (!search) { - return {} - } - const obj = {} - const searchArr = search.split('&') - searchArr.forEach(v => { - const index = v.indexOf('=') - if (index !== -1) { - const name = v.substring(0, index) - const val = v.substring(index + 1, v.length) - obj[name] = val - } - }) - return obj -} - -/** - * @param {string} val - * @returns {string} - */ -export function html2Text(val) { - const div = document.createElement('div') - div.innerHTML = val - return div.textContent || div.innerText -} - -/** - * Merges two objects, giving the last one precedence - * @param {Object} target - * @param {(Object|Array)} source - * @returns {Object} - */ -export function objectMerge(target, source) { - if (typeof target !== 'object') { - target = {} - } - if (Array.isArray(source)) { - return source.slice() - } - Object.keys(source).forEach(property => { - const sourceProperty = source[property] - if (typeof sourceProperty === 'object') { - target[property] = objectMerge(target[property], sourceProperty) - } else { - target[property] = sourceProperty - } - }) - return target -} - -/** - * @param {HTMLElement} element - * @param {string} className - */ -export function toggleClass(element, className) { - if (!element || !className) { - return - } - let classString = element.className - const nameIndex = classString.indexOf(className) - if (nameIndex === -1) { - classString += '' + className - } else { - classString = - classString.substr(0, nameIndex) + - classString.substr(nameIndex + className.length) - } - element.className = classString -} - -/** - * @param {string} type - * @returns {Date} - */ -export function getTime(type) { - if (type === 'start') { - return new Date().getTime() - 3600 * 1000 * 24 * 90 - } else { - return new Date(new Date().toDateString()) - } -} - -/** - * @param {Function} func - * @param {number} wait - * @param {boolean} immediate - * @return {*} - */ -export function debounce(func, wait, immediate) { - let timeout, args, context, timestamp, result - - const later = function() { - // 据上一次触发时间间隔 - const last = +new Date() - timestamp - - // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait - if (last < wait && last > 0) { - timeout = setTimeout(later, wait - last) - } else { - timeout = null - // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用 - if (!immediate) { - result = func.apply(context, args) - if (!timeout) context = args = null - } - } - } - - return function(...args) { - context = this - timestamp = +new Date() - const callNow = immediate && !timeout - // 如果延时不存在,重新设定延时 - if (!timeout) timeout = setTimeout(later, wait) - if (callNow) { - result = func.apply(context, args) - context = args = null - } - - return result - } -} - -/** - * This is just a simple version of deep copy - * Has a lot of edge cases bug - * If you want to use a perfect deep copy, use lodash's _.cloneDeep - * @param {Object} source - * @returns {Object} - */ -export function deepClone(source) { - if (!source && typeof source !== 'object') { - throw new Error('error arguments', 'deepClone') - } - const targetObj = source.constructor === Array ? [] : {} - Object.keys(source).forEach(keys => { - if (source[keys] && typeof source[keys] === 'object') { - targetObj[keys] = deepClone(source[keys]) - } else { - targetObj[keys] = source[keys] - } - }) - return targetObj -} - -/** - * @param {Array} arr - * @returns {Array} - */ -export function uniqueArr(arr) { - return Array.from(new Set(arr)) -} - -/** - * @returns {string} - */ -export function createUniqueString() { - const timestamp = +new Date() + '' - const randomNum = parseInt((1 + Math.random()) * 65536) + '' - return (+(randomNum + timestamp)).toString(32) -} - -/** - * Check if an element has a class - * @param {HTMLElement} elm - * @param {string} cls - * @returns {boolean} - */ -export function hasClass(ele, cls) { - return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)')) -} - -/** - * Add class to element - * @param {HTMLElement} elm - * @param {string} cls - */ -export function addClass(ele, cls) { - if (!hasClass(ele, cls)) ele.className += ' ' + cls -} - -/** - * Remove class from element - * @param {HTMLElement} elm - * @param {string} cls - */ -export function removeClass(ele, cls) { - if (hasClass(ele, cls)) { - const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)') - ele.className = ele.className.replace(reg, ' ') - } -} - -export function makeMap(str, expectsLowerCase) { - const map = Object.create(null) - const list = str.split(',') - for (let i = 0; i < list.length; i++) { - map[list[i]] = true - } - return expectsLowerCase - ? val => map[val.toLowerCase()] - : val => map[val] -} - -export const exportDefault = 'export default ' - -export const beautifierConf = { - html: { - indent_size: '2', - indent_char: ' ', - max_preserve_newlines: '-1', - preserve_newlines: false, - keep_array_indentation: false, - break_chained_methods: false, - indent_scripts: 'separate', - brace_style: 'end-expand', - space_before_conditional: true, - unescape_strings: false, - jslint_happy: false, - end_with_newline: true, - wrap_line_length: '110', - indent_inner_html: true, - comma_first: false, - e4x: true, - indent_empty_lines: true - }, - js: { - indent_size: '2', - indent_char: ' ', - max_preserve_newlines: '-1', - preserve_newlines: false, - keep_array_indentation: false, - break_chained_methods: false, - indent_scripts: 'normal', - brace_style: 'end-expand', - space_before_conditional: true, - unescape_strings: false, - jslint_happy: true, - end_with_newline: true, - wrap_line_length: '110', - indent_inner_html: true, - comma_first: false, - e4x: true, - indent_empty_lines: true - } -} - -// 首字母大小 -export function titleCase(str) { - return str.replace(/( |^)[a-z]/g, L => L.toUpperCase()) -} - -// 下划转驼峰 -export function camelCase(str) { - return str.replace(/_[a-z]/g, str1 => str1.substr(-1).toUpperCase()) -} - -export function isNumberStr(str) { - return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str) -} - diff --git a/frontend/src/utils/jsencrypt.js b/frontend/src/utils/jsencrypt.js deleted file mode 100644 index 0316c7136..000000000 --- a/frontend/src/utils/jsencrypt.js +++ /dev/null @@ -1,30 +0,0 @@ -import JSEncrypt from 'jsencrypt/bin/jsencrypt.min' - -// 密钥对生成 http://web.chacuo.net/netrsakeypair - -const publicKey = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdH\n' + - 'nzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==' - -const privateKey = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY\n' + - '7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKN\n' + - 'PuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gA\n' + - 'kM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWow\n' + - 'cSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99Ecv\n' + - 'DQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthh\n' + - 'YhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3\n' + - 'UP8iWi1Qw0Y=' - -// 加密 -export function encrypt(txt) { - const encryptor = new JSEncrypt() - encryptor.setPublicKey(publicKey) // 设置公钥 - return encryptor.encrypt(txt) // 对数据进行加密 -} - -// 解密 -export function decrypt(txt) { - const encryptor = new JSEncrypt() - encryptor.setPrivateKey(privateKey) // 设置私钥 - return encryptor.decrypt(txt) // 对数据进行解密 -} - diff --git a/frontend/src/utils/passwordRule.js b/frontend/src/utils/passwordRule.js deleted file mode 100644 index 3f29680fa..000000000 --- a/frontend/src/utils/passwordRule.js +++ /dev/null @@ -1,71 +0,0 @@ -/** - * 密码强度规则 - * 根据参数 chrtype 动态生成校验规则 - * - * chrtype 说明: - * 0 - 任意字符(默认) - * 1 - 纯数字(0-9) - * 2 - 纯字母(a-z / A-Z) - * 3 - 字母 + 数字(必须同时包含) - * 4 - 字母 + 数字 + 特殊字符(必须同时包含,特殊字符:~!@#$%^&*()-=_+) - */ -import cache from '@/plugins/cache' - -// 各类型对应的正则、错误提示 -const PWD_RULES = { - '0': { pattern: /^[^<>"'|\\]+$/, message: '密码不能包含非法字符:< > " \' \\ |' }, - '1': { pattern: /^[0-9]+$/, message: '密码只能为数字(0-9)' }, - '2': { pattern: /^[a-zA-Z]+$/, message: '密码只能为英文字母(a-z、A-Z)' }, - '3': { pattern: /^(?=.*[a-zA-Z])(?=.*[0-9])[a-zA-Z0-9]+$/, message: '密码必须同时包含字母和数字' }, - '4': { pattern: /^(?=.*[A-Za-z])(?=.*\d)(?=.*[~!@#$%^&*()\-=_+])[A-Za-z\d~!@#$%^&*()\-=_+]+$/, message: '密码必须同时包含字母、数字和特殊字符(~!@#$%^&*()-=_+)' } -} - -export default { - data() { - return { - // 密码限制类型 - pwdChrType: cache.session.get('pwrChrtype') || '0' - } - }, - computed: { - // 默认密码校验 - pwdValidator() { - const rule = PWD_RULES[this.pwdChrType] || PWD_RULES['0'] - return [ - { required: true, message: '密码不能为空', trigger: 'blur' }, - { min: 6, max: 20, message: '密码长度必须介于 6 和 20 之间', trigger: 'blur' }, - { pattern: rule.pattern, message: rule.message, trigger: 'blur' } - ] - }, - // 校验prompt的inputValidator函数 - pwdPromptValidator() { - const rule = PWD_RULES['0'] - return (value) => { - if (!value || value.length < 6 || value.length > 20) { - return '密码长度必须介于 6 和 20 之间' - } - if (!rule.pattern.test(value)) { - return rule.message - } - } - }, - // 个人中心密码校验 - infoPwdValidator() { - const rule = PWD_RULES[this.pwdChrType] || PWD_RULES['0'] - return [ - { required: true, message: '新密码不能为空', trigger: 'blur' }, - { min: 6, max: 20, message: '新密码长度必须介于 6 和 20 之间', trigger: 'blur' }, - { pattern: rule.pattern, message: rule.message, trigger: 'blur' } - ] - }, - // 注册页面密码校验 - registerPwdValidator() { - const rule = PWD_RULES['0'] - return [ - { required: true, message: '请输入您的密码', trigger: 'blur' }, - { min: 6, max: 20, message: '用户密码长度必须介于 6 和 20 之间', trigger: 'blur' }, - { pattern: rule.pattern, message: rule.message, trigger: 'blur' } - ] - } - } -} diff --git a/frontend/src/utils/permission.js b/frontend/src/utils/permission.js deleted file mode 100644 index 43998fa3f..000000000 --- a/frontend/src/utils/permission.js +++ /dev/null @@ -1,47 +0,0 @@ -import store from '@/store' - -/** - * 字符权限校验 - * @param {Array} value 校验值 - * @returns {Boolean} - */ -export function checkPermi(value) { - if (value && value instanceof Array && value.length > 0) { - const permissions = store.getters && store.getters.permissions - const permissionDatas = value - const all_permission = "*:*:*" - - const hasPermission = permissions.some(permission => { - return all_permission === permission || permissionDatas.includes(permission) - }) - - return hasPermission - - } else { - console.error(`need roles! Like checkPermi="['system:user:add','system:user:edit']"`) - return false - } -} - -/** - * 角色权限校验 - * @param {Array} value 校验值 - * @returns {Boolean} - */ -export function checkRole(value) { - if (value && value instanceof Array && value.length > 0) { - const roles = store.getters && store.getters.roles - const permissionRoles = value - const super_admin = "admin" - - const hasRole = roles.some(role => { - return super_admin === role || permissionRoles.includes(role) - }) - - return hasRole - - } else { - console.error(`need roles! Like checkRole="['admin','editor']"`) - return false - } -} \ No newline at end of file diff --git a/frontend/src/utils/request.js b/frontend/src/utils/request.js deleted file mode 100644 index 8865fcdb0..000000000 --- a/frontend/src/utils/request.js +++ /dev/null @@ -1,153 +0,0 @@ -import axios from 'axios' -import { Notification, MessageBox, Message, Loading } from 'element-ui' -import store from '@/store' -import { getToken } from '@/utils/auth' -import errorCode from '@/utils/errorCode' -import { tansParams, blobValidate } from "@/utils/roomroot" -import cache from '@/plugins/cache' -import { saveAs } from 'file-saver' - -let downloadLoadingInstance -// 是否显示重新登录 -export let isRelogin = { show: false } - -axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8' -// 创建axios实例 -const service = axios.create({ - // axios中请求配置有baseURL选项,表示请求URL公共部分 - baseURL: process.env.VUE_APP_BASE_API, - // 超时 - timeout: 10000 -}) - -// request拦截器 -service.interceptors.request.use(config => { - // 是否需要设置 token - const isToken = (config.headers || {}).isToken === false - // 是否需要防止数据重复提交 - const isRepeatSubmit = (config.headers || {}).repeatSubmit === false - // 间隔时间(ms),小于此时间视为重复提交 - const interval = (config.headers || {}).interval || 1000 - if (getToken() && !isToken) { - config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改 - } - // get请求映射params参数 - if (config.method === 'get' && config.params) { - let url = config.url + '?' + tansParams(config.params) - url = url.slice(0, -1) - config.params = {} - config.url = url - } - if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) { - const requestObj = { - url: config.url, - data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data, - time: new Date().getTime() - } - const requestSize = Object.keys(JSON.stringify(requestObj)).length // 请求数据大小 - const limitSize = 5 * 1024 * 1024 // 限制存放数据5M - if (requestSize >= limitSize) { - console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制,无法进行防重复提交验证。') - return config - } - const sessionObj = cache.session.getJSON('sessionObj') - if (sessionObj === undefined || sessionObj === null || sessionObj === '') { - cache.session.setJSON('sessionObj', requestObj) - } else { - const s_url = sessionObj.url // 请求地址 - const s_data = sessionObj.data // 请求数据 - const s_time = sessionObj.time // 请求时间 - if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) { - const message = '数据正在处理,请勿重复提交' - console.warn(`[${s_url}]: ` + message) - return Promise.reject(new Error(message)) - } else { - cache.session.setJSON('sessionObj', requestObj) - } - } - } - return config -}, error => { - console.log(error) - Promise.reject(error) -}) - -// 响应拦截器 -service.interceptors.response.use(res => { - // 未设置状态码则默认成功状态 - const code = res.data.code || 200 - // 获取错误信息 - const msg = errorCode[code] || res.data.msg || errorCode['default'] - // 二进制数据则直接返回 - if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') { - return res.data - } - if (code === 401) { - if (!isRelogin.show) { - isRelogin.show = true - MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => { - isRelogin.show = false - store.dispatch('LogOut').then(() => { - location.href = '/index' - }) - }).catch(() => { - isRelogin.show = false - }) - } - return Promise.reject('无效的会话,或者会话已过期,请重新登录。') - } else if (code === 500) { - Message({ message: msg, type: 'error' }) - return Promise.reject(new Error(msg)) - } else if (code === 601) { - Message({ message: msg, type: 'warning' }) - return Promise.reject('error') - } else if (code !== 200) { - Notification.error({ title: msg }) - return Promise.reject('error') - } else { - return res.data - } -}, -error => { - console.log('err' + error) - let { message } = error - if (message == "Network Error") { - message = "后端接口连接异常" - } else if (message.includes("timeout")) { - message = "系统接口请求超时" - } else if (message.includes("Request failed with status code")) { - message = "系统接口" + message.slice(-3) + "异常" - } - Message({ message: message, type: 'error', duration: 5 * 1000 }) - return Promise.reject(error) -} -) - -// 通用下载方法 -export function download(url, params, filename, config) { - downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", }) - return service.post(url, params, { - transformRequest: [(params) => { return tansParams(params) }], - headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, - responseType: 'blob', - ...config - }).then(async (data) => { - const isBlob = blobValidate(data) - if (isBlob) { - const blob = new Blob([data]) - saveAs(blob, filename) - } else { - const resText = await data.text() - const rspObj = JSON.parse(resText) - const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default'] - Message.error(errMsg) - } - downloadLoadingInstance.close() - }).catch((r) => { - console.error(r) - Message.error('下载文件出现错误,请联系管理员!') - downloadLoadingInstance.close() - }) -} - -export default service diff --git a/frontend/src/utils/roomroot.js b/frontend/src/utils/roomroot.js deleted file mode 100644 index bde9752b7..000000000 --- a/frontend/src/utils/roomroot.js +++ /dev/null @@ -1,228 +0,0 @@ -/** - * 通用js方法封装处理 - * Copyright (c) 2019 roomroot - */ - -// 日期格式化 -export function parseTime(time, pattern) { - if (arguments.length === 0 || !time) { - return null - } - const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}' - let date - if (typeof time === 'object') { - date = time - } else { - if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) { - time = parseInt(time) - } else if (typeof time === 'string') { - time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm), '') - } - if ((typeof time === 'number') && (time.toString().length === 10)) { - time = time * 1000 - } - date = new Date(time) - } - const formatObj = { - y: date.getFullYear(), - m: date.getMonth() + 1, - d: date.getDate(), - h: date.getHours(), - i: date.getMinutes(), - s: date.getSeconds(), - a: date.getDay() - } - const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => { - let value = formatObj[key] - // Note: getDay() returns 0 on Sunday - if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] } - if (result.length > 0 && value < 10) { - value = '0' + value - } - return value || 0 - }) - return time_str -} - -// 表单重置 -export function resetForm(refName) { - if (this.$refs[refName]) { - this.$refs[refName].resetFields() - } -} - -// 添加日期范围 -export function addDateRange(params, dateRange, propName) { - let search = params - search.params = typeof (search.params) === 'object' && search.params !== null && !Array.isArray(search.params) ? search.params : {} - dateRange = Array.isArray(dateRange) ? dateRange : [] - if (typeof (propName) === 'undefined') { - search.params['beginTime'] = dateRange[0] - search.params['endTime'] = dateRange[1] - } else { - search.params['begin' + propName] = dateRange[0] - search.params['end' + propName] = dateRange[1] - } - return search -} - -// 回显数据字典 -export function selectDictLabel(datas, value) { - if (value === undefined) { - return "" - } - var actions = [] - Object.keys(datas).some((key) => { - if (datas[key].value == ('' + value)) { - actions.push(datas[key].label) - return true - } - }) - if (actions.length === 0) { - actions.push(value) - } - return actions.join('') -} - -// 回显数据字典(字符串、数组) -export function selectDictLabels(datas, value, separator) { - if (value === undefined || value.length === 0) { - return "" - } - if (Array.isArray(value)) { - value = value.join(",") - } - var actions = [] - var currentSeparator = undefined === separator ? "," : separator - var temp = value.split(currentSeparator) - Object.keys(value.split(currentSeparator)).some((val) => { - var match = false - Object.keys(datas).some((key) => { - if (datas[key].value == ('' + temp[val])) { - actions.push(datas[key].label + currentSeparator) - match = true - } - }) - if (!match) { - actions.push(temp[val] + currentSeparator) - } - }) - return actions.join('').substring(0, actions.join('').length - 1) -} - -// 字符串格式化(%s ) -export function sprintf(str) { - var args = arguments, flag = true, i = 1 - str = str.replace(/%s/g, function () { - var arg = args[i++] - if (typeof arg === 'undefined') { - flag = false - return '' - } - return arg - }) - return flag ? str : '' -} - -// 转换字符串,undefined,null等转化为"" -export function parseStrEmpty(str) { - if (!str || str == "undefined" || str == "null") { - return "" - } - return str -} - -// 数据合并 -export function mergeRecursive(source, target) { - for (var p in target) { - try { - if (target[p].constructor == Object) { - source[p] = mergeRecursive(source[p], target[p]) - } else { - source[p] = target[p] - } - } catch (e) { - source[p] = target[p] - } - } - return source -} - -/** - * 构造树型结构数据 - * @param {*} data 数据源 - * @param {*} id id字段 默认 'id' - * @param {*} parentId 父节点字段 默认 'parentId' - * @param {*} children 孩子节点字段 默认 'children' - */ -export function handleTree(data, id, parentId, children) { - let config = { - id: id || 'id', - parentId: parentId || 'parentId', - childrenList: children || 'children' - } - - var childrenListMap = {} - var tree = [] - for (let d of data) { - let id = d[config.id] - childrenListMap[id] = d - if (!d[config.childrenList]) { - d[config.childrenList] = [] - } - } - - for (let d of data) { - let parentId = d[config.parentId] - let parentObj = childrenListMap[parentId] - if (!parentObj) { - tree.push(d) - } else { - parentObj[config.childrenList].push(d) - } - } - return tree -} - -/** -* 参数处理 -* @param {*} params 参数 -*/ -export function tansParams(params) { - let result = '' - for (const propName of Object.keys(params)) { - const value = params[propName] - var part = encodeURIComponent(propName) + "=" - if (value !== null && value !== "" && typeof (value) !== "undefined") { - if (typeof value === 'object') { - for (const key of Object.keys(value)) { - if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') { - let params = propName + '[' + key + ']' - var subPart = encodeURIComponent(params) + "=" - result += subPart + encodeURIComponent(value[key]) + "&" - } - } - } else { - result += part + encodeURIComponent(value) + "&" - } - } - } - return result -} - -// 返回项目路径 -export function getNormalPath(p) { - if (p.length === 0 || !p || p == 'undefined') { - return p - } - let res = p.replace('//', '/') - if (res[res.length - 1] === '/') { - return res.slice(0, res.length - 1) - } - return res -} - -// 验证是否为blob格式 -export function blobValidate(data) { - return data.type !== 'application/json' -} diff --git a/frontend/src/utils/ruoyi.js b/frontend/src/utils/ruoyi.js deleted file mode 100644 index bde9752b7..000000000 --- a/frontend/src/utils/ruoyi.js +++ /dev/null @@ -1,228 +0,0 @@ -/** - * 通用js方法封装处理 - * Copyright (c) 2019 roomroot - */ - -// 日期格式化 -export function parseTime(time, pattern) { - if (arguments.length === 0 || !time) { - return null - } - const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}' - let date - if (typeof time === 'object') { - date = time - } else { - if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) { - time = parseInt(time) - } else if (typeof time === 'string') { - time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm), '') - } - if ((typeof time === 'number') && (time.toString().length === 10)) { - time = time * 1000 - } - date = new Date(time) - } - const formatObj = { - y: date.getFullYear(), - m: date.getMonth() + 1, - d: date.getDate(), - h: date.getHours(), - i: date.getMinutes(), - s: date.getSeconds(), - a: date.getDay() - } - const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => { - let value = formatObj[key] - // Note: getDay() returns 0 on Sunday - if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] } - if (result.length > 0 && value < 10) { - value = '0' + value - } - return value || 0 - }) - return time_str -} - -// 表单重置 -export function resetForm(refName) { - if (this.$refs[refName]) { - this.$refs[refName].resetFields() - } -} - -// 添加日期范围 -export function addDateRange(params, dateRange, propName) { - let search = params - search.params = typeof (search.params) === 'object' && search.params !== null && !Array.isArray(search.params) ? search.params : {} - dateRange = Array.isArray(dateRange) ? dateRange : [] - if (typeof (propName) === 'undefined') { - search.params['beginTime'] = dateRange[0] - search.params['endTime'] = dateRange[1] - } else { - search.params['begin' + propName] = dateRange[0] - search.params['end' + propName] = dateRange[1] - } - return search -} - -// 回显数据字典 -export function selectDictLabel(datas, value) { - if (value === undefined) { - return "" - } - var actions = [] - Object.keys(datas).some((key) => { - if (datas[key].value == ('' + value)) { - actions.push(datas[key].label) - return true - } - }) - if (actions.length === 0) { - actions.push(value) - } - return actions.join('') -} - -// 回显数据字典(字符串、数组) -export function selectDictLabels(datas, value, separator) { - if (value === undefined || value.length === 0) { - return "" - } - if (Array.isArray(value)) { - value = value.join(",") - } - var actions = [] - var currentSeparator = undefined === separator ? "," : separator - var temp = value.split(currentSeparator) - Object.keys(value.split(currentSeparator)).some((val) => { - var match = false - Object.keys(datas).some((key) => { - if (datas[key].value == ('' + temp[val])) { - actions.push(datas[key].label + currentSeparator) - match = true - } - }) - if (!match) { - actions.push(temp[val] + currentSeparator) - } - }) - return actions.join('').substring(0, actions.join('').length - 1) -} - -// 字符串格式化(%s ) -export function sprintf(str) { - var args = arguments, flag = true, i = 1 - str = str.replace(/%s/g, function () { - var arg = args[i++] - if (typeof arg === 'undefined') { - flag = false - return '' - } - return arg - }) - return flag ? str : '' -} - -// 转换字符串,undefined,null等转化为"" -export function parseStrEmpty(str) { - if (!str || str == "undefined" || str == "null") { - return "" - } - return str -} - -// 数据合并 -export function mergeRecursive(source, target) { - for (var p in target) { - try { - if (target[p].constructor == Object) { - source[p] = mergeRecursive(source[p], target[p]) - } else { - source[p] = target[p] - } - } catch (e) { - source[p] = target[p] - } - } - return source -} - -/** - * 构造树型结构数据 - * @param {*} data 数据源 - * @param {*} id id字段 默认 'id' - * @param {*} parentId 父节点字段 默认 'parentId' - * @param {*} children 孩子节点字段 默认 'children' - */ -export function handleTree(data, id, parentId, children) { - let config = { - id: id || 'id', - parentId: parentId || 'parentId', - childrenList: children || 'children' - } - - var childrenListMap = {} - var tree = [] - for (let d of data) { - let id = d[config.id] - childrenListMap[id] = d - if (!d[config.childrenList]) { - d[config.childrenList] = [] - } - } - - for (let d of data) { - let parentId = d[config.parentId] - let parentObj = childrenListMap[parentId] - if (!parentObj) { - tree.push(d) - } else { - parentObj[config.childrenList].push(d) - } - } - return tree -} - -/** -* 参数处理 -* @param {*} params 参数 -*/ -export function tansParams(params) { - let result = '' - for (const propName of Object.keys(params)) { - const value = params[propName] - var part = encodeURIComponent(propName) + "=" - if (value !== null && value !== "" && typeof (value) !== "undefined") { - if (typeof value === 'object') { - for (const key of Object.keys(value)) { - if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') { - let params = propName + '[' + key + ']' - var subPart = encodeURIComponent(params) + "=" - result += subPart + encodeURIComponent(value[key]) + "&" - } - } - } else { - result += part + encodeURIComponent(value) + "&" - } - } - } - return result -} - -// 返回项目路径 -export function getNormalPath(p) { - if (p.length === 0 || !p || p == 'undefined') { - return p - } - let res = p.replace('//', '/') - if (res[res.length - 1] === '/') { - return res.slice(0, res.length - 1) - } - return res -} - -// 验证是否为blob格式 -export function blobValidate(data) { - return data.type !== 'application/json' -} diff --git a/frontend/src/utils/scroll-to.js b/frontend/src/utils/scroll-to.js deleted file mode 100644 index 5c2bc4492..000000000 --- a/frontend/src/utils/scroll-to.js +++ /dev/null @@ -1,58 +0,0 @@ -Math.easeInOutQuad = function(t, b, c, d) { - t /= d / 2 - if (t < 1) { - return c / 2 * t * t + b - } - t-- - return -c / 2 * (t * (t - 2) - 1) + b -} - -// requestAnimationFrame for Smart Animating http://goo.gl/sx5sts -var requestAnimFrame = (function() { - return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) } -})() - -/** - * Because it's so fucking difficult to detect the scrolling element, just move them all - * @param {number} amount - */ -function move(amount) { - document.documentElement.scrollTop = amount - document.body.parentNode.scrollTop = amount - document.body.scrollTop = amount -} - -function position() { - return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop -} - -/** - * @param {number} to - * @param {number} duration - * @param {Function} callback - */ -export function scrollTo(to, duration, callback) { - const start = position() - const change = to - start - const increment = 20 - let currentTime = 0 - duration = (typeof (duration) === 'undefined') ? 500 : duration - var animateScroll = function() { - // increment the time - currentTime += increment - // find the value with the quadratic in-out easing function - var val = Math.easeInOutQuad(currentTime, start, change, duration) - // move the document.body - move(val) - // do the animation unless its over - if (currentTime < duration) { - requestAnimFrame(animateScroll) - } else { - if (callback && typeof (callback) === 'function') { - // the animation is done so lets callback - callback() - } - } - } - animateScroll() -} diff --git a/frontend/src/utils/validate.js b/frontend/src/utils/validate.js deleted file mode 100644 index d3b425bce..000000000 --- a/frontend/src/utils/validate.js +++ /dev/null @@ -1,119 +0,0 @@ -/** - * 路径匹配器 - * @param {string} pattern - * @param {string} path - * @returns {Boolean} - */ -export function isPathMatch(pattern, path) { - const regexPattern = pattern - .replace(/([.+^${}()|\[\]\\])/g, '\\$1') - .replace(/\*\*/g, '__DOUBLE_STAR__') - .replace(/\*/g, '[^/]*') - .replace(/__DOUBLE_STAR__/g, '.*') - .replace(/\?/g, '[^/]') - const regex = new RegExp(`^${regexPattern}$`) - return regex.test(path) -} - -/** - * 判断value字符串是否为空 - * @param {string} value - * @returns {Boolean} - */ -export function isEmpty(value) { - if (value == null || value == "" || value == undefined || value == "undefined") { - return true - } - return false -} - -/** - * 判断url是否是http或https - * @param {string} url - * @returns {Boolean} - */ -export function isHttp(url) { - return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1 -} - -/** - * 判断path是否为外链 - * @param {string} path - * @returns {Boolean} - */ -export function isExternal(path) { - return /^(https?:|mailto:|tel:)/.test(path) -} - -/** - * @param {string} str - * @returns {Boolean} - */ -export function validUsername(str) { - const valid_map = ['admin', 'editor'] - return valid_map.indexOf(str.trim()) >= 0 -} - -/** - * @param {string} url - * @returns {Boolean} - */ -export function validURL(url) { - const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/ - return reg.test(url) -} - -/** - * @param {string} str - * @returns {Boolean} - */ -export function validLowerCase(str) { - const reg = /^[a-z]+$/ - return reg.test(str) -} - -/** - * @param {string} str - * @returns {Boolean} - */ -export function validUpperCase(str) { - const reg = /^[A-Z]+$/ - return reg.test(str) -} - -/** - * @param {string} str - * @returns {Boolean} - */ -export function validAlphabets(str) { - const reg = /^[A-Za-z]+$/ - return reg.test(str) -} - -/** - * @param {string} email - * @returns {Boolean} - */ -export function validEmail(email) { - const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ - return reg.test(email) -} - -/** - * @param {string} str - * @returns {Boolean} - */ -export function isString(str) { - return typeof str === 'string' || str instanceof String -} - -/** - * @param {Array} arg - * @returns {Boolean} - */ -export function isArray(arg) { - if (typeof Array.isArray === 'undefined') { - return Object.prototype.toString.call(arg) === '[object Array]' - } - return Array.isArray(arg) -} diff --git a/frontend/src/views/classHour/jointTraining/index.vue b/frontend/src/views/classHour/jointTraining/index.vue deleted file mode 100644 index 55ead9f1a..000000000 --- a/frontend/src/views/classHour/jointTraining/index.vue +++ /dev/null @@ -1,531 +0,0 @@ - - - - - diff --git a/frontend/src/views/classHour/plan/index.vue b/frontend/src/views/classHour/plan/index.vue deleted file mode 100644 index 626e0e2e0..000000000 --- a/frontend/src/views/classHour/plan/index.vue +++ /dev/null @@ -1,679 +0,0 @@ - - - - - diff --git a/frontend/src/views/classHour/subsidy/index.vue b/frontend/src/views/classHour/subsidy/index.vue deleted file mode 100644 index b4a16d849..000000000 --- a/frontend/src/views/classHour/subsidy/index.vue +++ /dev/null @@ -1,299 +0,0 @@ - - - - - diff --git a/frontend/src/views/dashboard/BarChart.vue b/frontend/src/views/dashboard/BarChart.vue deleted file mode 100644 index ff7fd445c..000000000 --- a/frontend/src/views/dashboard/BarChart.vue +++ /dev/null @@ -1,102 +0,0 @@ - - - diff --git a/frontend/src/views/dashboard/LineChart.vue b/frontend/src/views/dashboard/LineChart.vue deleted file mode 100644 index bf92302a6..000000000 --- a/frontend/src/views/dashboard/LineChart.vue +++ /dev/null @@ -1,135 +0,0 @@ - - - diff --git a/frontend/src/views/dashboard/PanelGroup.vue b/frontend/src/views/dashboard/PanelGroup.vue deleted file mode 100644 index 1cd34c803..000000000 --- a/frontend/src/views/dashboard/PanelGroup.vue +++ /dev/null @@ -1,181 +0,0 @@ - - - - - diff --git a/frontend/src/views/dashboard/PieChart.vue b/frontend/src/views/dashboard/PieChart.vue deleted file mode 100644 index 084180f76..000000000 --- a/frontend/src/views/dashboard/PieChart.vue +++ /dev/null @@ -1,79 +0,0 @@ - - - diff --git a/frontend/src/views/dashboard/RaddarChart.vue b/frontend/src/views/dashboard/RaddarChart.vue deleted file mode 100644 index 66e2f8d07..000000000 --- a/frontend/src/views/dashboard/RaddarChart.vue +++ /dev/null @@ -1,116 +0,0 @@ - - - diff --git a/frontend/src/views/dashboard/mixins/resize.js b/frontend/src/views/dashboard/mixins/resize.js deleted file mode 100644 index 23c158ffa..000000000 --- a/frontend/src/views/dashboard/mixins/resize.js +++ /dev/null @@ -1,56 +0,0 @@ -import { debounce } from '@/utils' - -export default { - data() { - return { - $_sidebarElm: null, - $_resizeHandler: null - } - }, - mounted() { - this.initListener() - }, - activated() { - if (!this.$_resizeHandler) { - // avoid duplication init - this.initListener() - } - - // when keep-alive chart activated, auto resize - this.resize() - }, - beforeDestroy() { - this.destroyListener() - }, - deactivated() { - this.destroyListener() - }, - methods: { - // use $_ for mixins properties - // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential - $_sidebarResizeHandler(e) { - if (e.propertyName === 'width') { - this.$_resizeHandler() - } - }, - initListener() { - this.$_resizeHandler = debounce(() => { - this.resize() - }, 100) - window.addEventListener('resize', this.$_resizeHandler) - - this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0] - this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler) - }, - destroyListener() { - window.removeEventListener('resize', this.$_resizeHandler) - this.$_resizeHandler = null - - this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler) - }, - resize() { - const { chart } = this - chart && chart.resize() - } - } -} diff --git a/frontend/src/views/error/401.vue b/frontend/src/views/error/401.vue deleted file mode 100644 index bba557b11..000000000 --- a/frontend/src/views/error/401.vue +++ /dev/null @@ -1,88 +0,0 @@ - - - - - diff --git a/frontend/src/views/error/404.vue b/frontend/src/views/error/404.vue deleted file mode 100644 index b0addcc85..000000000 --- a/frontend/src/views/error/404.vue +++ /dev/null @@ -1,233 +0,0 @@ - - - - - diff --git a/frontend/src/views/index.vue b/frontend/src/views/index.vue deleted file mode 100644 index 53cb8c8c3..000000000 --- a/frontend/src/views/index.vue +++ /dev/null @@ -1,326 +0,0 @@ - - - - - diff --git a/frontend/src/views/lock.vue b/frontend/src/views/lock.vue deleted file mode 100644 index 5fbc3326f..000000000 --- a/frontend/src/views/lock.vue +++ /dev/null @@ -1,375 +0,0 @@ - - - - - diff --git a/frontend/src/views/login.vue b/frontend/src/views/login.vue deleted file mode 100644 index 7da0004ba..000000000 --- a/frontend/src/views/login.vue +++ /dev/null @@ -1,180 +0,0 @@ - - - - - diff --git a/frontend/src/views/monitor/cache/index.vue b/frontend/src/views/monitor/cache/index.vue deleted file mode 100644 index 3e14ecb1d..000000000 --- a/frontend/src/views/monitor/cache/index.vue +++ /dev/null @@ -1,148 +0,0 @@ - - - diff --git a/frontend/src/views/monitor/cache/list.vue b/frontend/src/views/monitor/cache/list.vue deleted file mode 100644 index fc103240a..000000000 --- a/frontend/src/views/monitor/cache/list.vue +++ /dev/null @@ -1,241 +0,0 @@ - - - diff --git a/frontend/src/views/monitor/druid/index.vue b/frontend/src/views/monitor/druid/index.vue deleted file mode 100644 index 1ccd4b496..000000000 --- a/frontend/src/views/monitor/druid/index.vue +++ /dev/null @@ -1,15 +0,0 @@ - - diff --git a/frontend/src/views/monitor/job/detail.vue b/frontend/src/views/monitor/job/detail.vue deleted file mode 100644 index 0a7dcdb49..000000000 --- a/frontend/src/views/monitor/job/detail.vue +++ /dev/null @@ -1,197 +0,0 @@ - - - - - diff --git a/frontend/src/views/monitor/job/index.vue b/frontend/src/views/monitor/job/index.vue deleted file mode 100644 index f69816979..000000000 --- a/frontend/src/views/monitor/job/index.vue +++ /dev/null @@ -1,508 +0,0 @@ - - - - - diff --git a/frontend/src/views/monitor/job/log.vue b/frontend/src/views/monitor/job/log.vue deleted file mode 100644 index aa5ba5d7e..000000000 --- a/frontend/src/views/monitor/job/log.vue +++ /dev/null @@ -1,300 +0,0 @@ - - - - - diff --git a/frontend/src/views/monitor/logininfor/index.vue b/frontend/src/views/monitor/logininfor/index.vue deleted file mode 100644 index d750e9d06..000000000 --- a/frontend/src/views/monitor/logininfor/index.vue +++ /dev/null @@ -1,274 +0,0 @@ - - - - - - diff --git a/frontend/src/views/monitor/online/index.vue b/frontend/src/views/monitor/online/index.vue deleted file mode 100644 index f94695e96..000000000 --- a/frontend/src/views/monitor/online/index.vue +++ /dev/null @@ -1,152 +0,0 @@ - - - - - - diff --git a/frontend/src/views/monitor/operlog/detail.vue b/frontend/src/views/monitor/operlog/detail.vue deleted file mode 100644 index 7bb26a010..000000000 --- a/frontend/src/views/monitor/operlog/detail.vue +++ /dev/null @@ -1,147 +0,0 @@ - - - diff --git a/frontend/src/views/monitor/operlog/index.vue b/frontend/src/views/monitor/operlog/index.vue deleted file mode 100644 index 8f95dc5bb..000000000 --- a/frontend/src/views/monitor/operlog/index.vue +++ /dev/null @@ -1,306 +0,0 @@ - - - - - diff --git a/frontend/src/views/monitor/server/index.vue b/frontend/src/views/monitor/server/index.vue deleted file mode 100644 index fb429eace..000000000 --- a/frontend/src/views/monitor/server/index.vue +++ /dev/null @@ -1,207 +0,0 @@ - - - diff --git a/frontend/src/views/redirect.vue b/frontend/src/views/redirect.vue deleted file mode 100644 index dbdaa97f3..000000000 --- a/frontend/src/views/redirect.vue +++ /dev/null @@ -1,12 +0,0 @@ - diff --git a/frontend/src/views/register.vue b/frontend/src/views/register.vue deleted file mode 100644 index 5b757f25a..000000000 --- a/frontend/src/views/register.vue +++ /dev/null @@ -1,167 +0,0 @@ - - - - - diff --git a/frontend/src/views/schedule/planImport/index.vue b/frontend/src/views/schedule/planImport/index.vue deleted file mode 100644 index 35889cc5c..000000000 --- a/frontend/src/views/schedule/planImport/index.vue +++ /dev/null @@ -1,399 +0,0 @@ - - - - - diff --git a/frontend/src/views/student/score/index.vue b/frontend/src/views/student/score/index.vue deleted file mode 100644 index fa2acd7ea..000000000 --- a/frontend/src/views/student/score/index.vue +++ /dev/null @@ -1,249 +0,0 @@ - - - - - \ No newline at end of file diff --git a/frontend/src/views/student/shiftTeam/index.vue b/frontend/src/views/student/shiftTeam/index.vue deleted file mode 100644 index 450f397ab..000000000 --- a/frontend/src/views/student/shiftTeam/index.vue +++ /dev/null @@ -1,717 +0,0 @@ - - - - - diff --git a/frontend/src/views/student/statusChange/index.vue b/frontend/src/views/student/statusChange/index.vue deleted file mode 100644 index 555d60f28..000000000 --- a/frontend/src/views/student/statusChange/index.vue +++ /dev/null @@ -1,494 +0,0 @@ - - - - - diff --git a/frontend/src/views/student/studentInfo/index.vue b/frontend/src/views/student/studentInfo/index.vue deleted file mode 100644 index 4b6d6ea6d..000000000 --- a/frontend/src/views/student/studentInfo/index.vue +++ /dev/null @@ -1,488 +0,0 @@ - - - - - diff --git a/frontend/src/views/student/warningCondition/index.vue b/frontend/src/views/student/warningCondition/index.vue deleted file mode 100644 index d81be0738..000000000 --- a/frontend/src/views/student/warningCondition/index.vue +++ /dev/null @@ -1,544 +0,0 @@ - - - - - \ No newline at end of file diff --git a/frontend/src/views/student/warningResult/index.vue b/frontend/src/views/student/warningResult/index.vue deleted file mode 100644 index 5e6acb072..000000000 --- a/frontend/src/views/student/warningResult/index.vue +++ /dev/null @@ -1,256 +0,0 @@ - - - - - diff --git a/frontend/src/views/subjectMajor/discipline/index.vue b/frontend/src/views/subjectMajor/discipline/index.vue deleted file mode 100644 index a77d6a0a1..000000000 --- a/frontend/src/views/subjectMajor/discipline/index.vue +++ /dev/null @@ -1,560 +0,0 @@ - - - - - diff --git a/frontend/src/views/subjectMajor/major/index.vue b/frontend/src/views/subjectMajor/major/index.vue deleted file mode 100644 index 1a6571f74..000000000 --- a/frontend/src/views/subjectMajor/major/index.vue +++ /dev/null @@ -1,726 +0,0 @@ - - - - - diff --git a/frontend/src/views/system/config/index.vue b/frontend/src/views/system/config/index.vue deleted file mode 100644 index f45e291f0..000000000 --- a/frontend/src/views/system/config/index.vue +++ /dev/null @@ -1,380 +0,0 @@ - - - - - diff --git a/frontend/src/views/system/dept/index.vue b/frontend/src/views/system/dept/index.vue deleted file mode 100644 index 601e226b4..000000000 --- a/frontend/src/views/system/dept/index.vue +++ /dev/null @@ -1,430 +0,0 @@ - - - - - diff --git a/frontend/src/views/system/dict/data.vue b/frontend/src/views/system/dict/data.vue deleted file mode 100644 index 4ad1f322a..000000000 --- a/frontend/src/views/system/dict/data.vue +++ /dev/null @@ -1,437 +0,0 @@ - - - - - diff --git a/frontend/src/views/system/dict/detail.vue b/frontend/src/views/system/dict/detail.vue deleted file mode 100644 index 028d151b7..000000000 --- a/frontend/src/views/system/dict/detail.vue +++ /dev/null @@ -1,203 +0,0 @@ - - - - - diff --git a/frontend/src/views/system/dict/index.vue b/frontend/src/views/system/dict/index.vue deleted file mode 100644 index bab1b55db..000000000 --- a/frontend/src/views/system/dict/index.vue +++ /dev/null @@ -1,412 +0,0 @@ - - - - - \ No newline at end of file diff --git a/frontend/src/views/system/menu/index.vue b/frontend/src/views/system/menu/index.vue deleted file mode 100644 index 49fac46ce..000000000 --- a/frontend/src/views/system/menu/index.vue +++ /dev/null @@ -1,571 +0,0 @@ - - - - - diff --git a/frontend/src/views/system/notice/ReadUsers.vue b/frontend/src/views/system/notice/ReadUsers.vue deleted file mode 100644 index b0e56221d..000000000 --- a/frontend/src/views/system/notice/ReadUsers.vue +++ /dev/null @@ -1,109 +0,0 @@ - - - - - diff --git a/frontend/src/views/system/notice/index.vue b/frontend/src/views/system/notice/index.vue deleted file mode 100644 index dcd0bab97..000000000 --- a/frontend/src/views/system/notice/index.vue +++ /dev/null @@ -1,369 +0,0 @@ - - - - diff --git a/frontend/src/views/system/post/index.vue b/frontend/src/views/system/post/index.vue deleted file mode 100644 index 6bdc3a3bd..000000000 --- a/frontend/src/views/system/post/index.vue +++ /dev/null @@ -1,346 +0,0 @@ - - - - diff --git a/frontend/src/views/system/role/authUser.vue b/frontend/src/views/system/role/authUser.vue deleted file mode 100644 index 49c79ff97..000000000 --- a/frontend/src/views/system/role/authUser.vue +++ /dev/null @@ -1,234 +0,0 @@ - - - - diff --git a/frontend/src/views/system/role/index.vue b/frontend/src/views/system/role/index.vue deleted file mode 100644 index 17468da66..000000000 --- a/frontend/src/views/system/role/index.vue +++ /dev/null @@ -1,642 +0,0 @@ - - - - \ No newline at end of file diff --git a/frontend/src/views/system/role/selectUser.vue b/frontend/src/views/system/role/selectUser.vue deleted file mode 100644 index 64df530eb..000000000 --- a/frontend/src/views/system/role/selectUser.vue +++ /dev/null @@ -1,136 +0,0 @@ - - - diff --git a/frontend/src/views/system/user/authRole.vue b/frontend/src/views/system/user/authRole.vue deleted file mode 100644 index 909fe29bc..000000000 --- a/frontend/src/views/system/user/authRole.vue +++ /dev/null @@ -1,152 +0,0 @@ - - - - \ No newline at end of file diff --git a/frontend/src/views/system/user/index.vue b/frontend/src/views/system/user/index.vue deleted file mode 100644 index 30bc674c4..000000000 --- a/frontend/src/views/system/user/index.vue +++ /dev/null @@ -1,509 +0,0 @@ - - - - diff --git a/frontend/src/views/system/user/profile/index.vue b/frontend/src/views/system/user/profile/index.vue deleted file mode 100644 index 42687a4c8..000000000 --- a/frontend/src/views/system/user/profile/index.vue +++ /dev/null @@ -1,109 +0,0 @@ - - - diff --git a/frontend/src/views/system/user/profile/resetPwd.vue b/frontend/src/views/system/user/profile/resetPwd.vue deleted file mode 100644 index c82134522..000000000 --- a/frontend/src/views/system/user/profile/resetPwd.vue +++ /dev/null @@ -1,70 +0,0 @@ - - - diff --git a/frontend/src/views/system/user/profile/userAvatar.vue b/frontend/src/views/system/user/profile/userAvatar.vue deleted file mode 100644 index 718cf541c..000000000 --- a/frontend/src/views/system/user/profile/userAvatar.vue +++ /dev/null @@ -1,184 +0,0 @@ - - - - diff --git a/frontend/src/views/system/user/profile/userInfo.vue b/frontend/src/views/system/user/profile/userInfo.vue deleted file mode 100644 index 0589a159d..000000000 --- a/frontend/src/views/system/user/profile/userInfo.vue +++ /dev/null @@ -1,88 +0,0 @@ - - - diff --git a/frontend/src/views/system/user/view.vue b/frontend/src/views/system/user/view.vue deleted file mode 100644 index 663262e15..000000000 --- a/frontend/src/views/system/user/view.vue +++ /dev/null @@ -1,177 +0,0 @@ - - - diff --git a/frontend/src/views/teachBusiness/calendar/components/SchoolCalendarEditor.vue b/frontend/src/views/teachBusiness/calendar/components/SchoolCalendarEditor.vue deleted file mode 100644 index e7a47594f..000000000 --- a/frontend/src/views/teachBusiness/calendar/components/SchoolCalendarEditor.vue +++ /dev/null @@ -1,753 +0,0 @@ - - - - - diff --git a/frontend/src/views/teachBusiness/calendar/index.vue b/frontend/src/views/teachBusiness/calendar/index.vue deleted file mode 100644 index d5bcb56fd..000000000 --- a/frontend/src/views/teachBusiness/calendar/index.vue +++ /dev/null @@ -1,489 +0,0 @@ - - - - - diff --git a/frontend/src/views/teachBusiness/semester/calendar.vue b/frontend/src/views/teachBusiness/semester/calendar.vue deleted file mode 100644 index 9d5eb5d20..000000000 --- a/frontend/src/views/teachBusiness/semester/calendar.vue +++ /dev/null @@ -1,53 +0,0 @@ - - - - - diff --git a/frontend/src/views/teachBusiness/semester/index.vue b/frontend/src/views/teachBusiness/semester/index.vue deleted file mode 100644 index 27f792078..000000000 --- a/frontend/src/views/teachBusiness/semester/index.vue +++ /dev/null @@ -1,621 +0,0 @@ - - - - - diff --git a/frontend/src/views/teachBusiness/syllabus/index.vue b/frontend/src/views/teachBusiness/syllabus/index.vue deleted file mode 100644 index cda411597..000000000 --- a/frontend/src/views/teachBusiness/syllabus/index.vue +++ /dev/null @@ -1,591 +0,0 @@ - - - - - diff --git a/frontend/src/views/teachBusiness/teachingTask/index.vue b/frontend/src/views/teachBusiness/teachingTask/index.vue deleted file mode 100644 index 03e9075fd..000000000 --- a/frontend/src/views/teachBusiness/teachingTask/index.vue +++ /dev/null @@ -1,296 +0,0 @@ - - - - - diff --git a/frontend/src/views/teachBusiness/timetable/index.vue b/frontend/src/views/teachBusiness/timetable/index.vue deleted file mode 100644 index 73696369a..000000000 --- a/frontend/src/views/teachBusiness/timetable/index.vue +++ /dev/null @@ -1,453 +0,0 @@ - - - - - diff --git a/frontend/src/views/teachBusiness/timetableAdjust/index.vue b/frontend/src/views/teachBusiness/timetableAdjust/index.vue deleted file mode 100644 index 71e96de42..000000000 --- a/frontend/src/views/teachBusiness/timetableAdjust/index.vue +++ /dev/null @@ -1,726 +0,0 @@ - - - - - diff --git a/frontend/src/views/teachBusiness/timetableConflict/index.vue b/frontend/src/views/teachBusiness/timetableConflict/index.vue deleted file mode 100644 index dc69101a7..000000000 --- a/frontend/src/views/teachBusiness/timetableConflict/index.vue +++ /dev/null @@ -1,417 +0,0 @@ - - - - - diff --git a/frontend/src/views/teachBusiness/trainingPlan/index.vue b/frontend/src/views/teachBusiness/trainingPlan/index.vue deleted file mode 100644 index 21811aa2b..000000000 --- a/frontend/src/views/teachBusiness/trainingPlan/index.vue +++ /dev/null @@ -1,676 +0,0 @@ - - - - - diff --git a/frontend/src/views/teachBusiness/venue/index.vue b/frontend/src/views/teachBusiness/venue/index.vue deleted file mode 100644 index 6c3bbefe4..000000000 --- a/frontend/src/views/teachBusiness/venue/index.vue +++ /dev/null @@ -1,484 +0,0 @@ - - - - - diff --git a/frontend/src/views/teachNotice/index.vue b/frontend/src/views/teachNotice/index.vue deleted file mode 100644 index 5f6bc26e1..000000000 --- a/frontend/src/views/teachNotice/index.vue +++ /dev/null @@ -1,437 +0,0 @@ - - - - - diff --git a/frontend/src/views/teachOffice/elective/index.vue b/frontend/src/views/teachOffice/elective/index.vue deleted file mode 100644 index 482589415..000000000 --- a/frontend/src/views/teachOffice/elective/index.vue +++ /dev/null @@ -1,550 +0,0 @@ - - - - - diff --git a/frontend/src/views/teachOffice/office/index.vue b/frontend/src/views/teachOffice/office/index.vue deleted file mode 100644 index 24319f4d6..000000000 --- a/frontend/src/views/teachOffice/office/index.vue +++ /dev/null @@ -1,348 +0,0 @@ - - - - - diff --git a/frontend/src/views/teachOffice/shiftSemester/ClassCalendarDialog.vue b/frontend/src/views/teachOffice/shiftSemester/ClassCalendarDialog.vue deleted file mode 100644 index d0ddbf5c7..000000000 --- a/frontend/src/views/teachOffice/shiftSemester/ClassCalendarDialog.vue +++ /dev/null @@ -1,752 +0,0 @@ - - - - - - diff --git a/frontend/src/views/teachOffice/shiftSemester/ClassSemesterDetailDialog.vue b/frontend/src/views/teachOffice/shiftSemester/ClassSemesterDetailDialog.vue deleted file mode 100644 index 0320bd1f9..000000000 --- a/frontend/src/views/teachOffice/shiftSemester/ClassSemesterDetailDialog.vue +++ /dev/null @@ -1,223 +0,0 @@ - - - - - diff --git a/frontend/src/views/teachOffice/shiftSemester/ClassTeamSelectDialog.vue b/frontend/src/views/teachOffice/shiftSemester/ClassTeamSelectDialog.vue deleted file mode 100644 index 113ce28af..000000000 --- a/frontend/src/views/teachOffice/shiftSemester/ClassTeamSelectDialog.vue +++ /dev/null @@ -1,224 +0,0 @@ - - - - - diff --git a/frontend/src/views/teachOffice/shiftSemester/index.vue b/frontend/src/views/teachOffice/shiftSemester/index.vue deleted file mode 100644 index 220480e55..000000000 --- a/frontend/src/views/teachOffice/shiftSemester/index.vue +++ /dev/null @@ -1,649 +0,0 @@ - - - - - diff --git a/frontend/src/views/teachOffice/subject/index.vue b/frontend/src/views/teachOffice/subject/index.vue deleted file mode 100644 index d530ad533..000000000 --- a/frontend/src/views/teachOffice/subject/index.vue +++ /dev/null @@ -1,744 +0,0 @@ - - - - - diff --git a/frontend/src/views/teachOffice/taskPlan/index.vue b/frontend/src/views/teachOffice/taskPlan/index.vue deleted file mode 100644 index 42940f691..000000000 --- a/frontend/src/views/teachOffice/taskPlan/index.vue +++ /dev/null @@ -1,513 +0,0 @@ - - - - - diff --git a/frontend/src/views/teachOffice/teacher/index.vue b/frontend/src/views/teachOffice/teacher/index.vue deleted file mode 100644 index 0e825d338..000000000 --- a/frontend/src/views/teachOffice/teacher/index.vue +++ /dev/null @@ -1,1090 +0,0 @@ - - - - - - - diff --git a/frontend/src/views/teachingLog/organLog/components/auditedView.vue b/frontend/src/views/teachingLog/organLog/components/auditedView.vue deleted file mode 100644 index 82541d0e6..000000000 --- a/frontend/src/views/teachingLog/organLog/components/auditedView.vue +++ /dev/null @@ -1,388 +0,0 @@ - - - - - diff --git a/frontend/src/views/teachingLog/organLog/components/logView.vue b/frontend/src/views/teachingLog/organLog/components/logView.vue deleted file mode 100644 index 11b2d2f1a..000000000 --- a/frontend/src/views/teachingLog/organLog/components/logView.vue +++ /dev/null @@ -1,542 +0,0 @@ - - - - - diff --git a/frontend/src/views/teachingLog/organLog/components/reportedView.vue b/frontend/src/views/teachingLog/organLog/components/reportedView.vue deleted file mode 100644 index 8ec46cfbc..000000000 --- a/frontend/src/views/teachingLog/organLog/components/reportedView.vue +++ /dev/null @@ -1,511 +0,0 @@ - - - - - diff --git a/frontend/src/views/teachingLog/organLog/index.vue b/frontend/src/views/teachingLog/organLog/index.vue deleted file mode 100644 index a5d517e85..000000000 --- a/frontend/src/views/teachingLog/organLog/index.vue +++ /dev/null @@ -1,51 +0,0 @@ - - - - - \ No newline at end of file diff --git a/frontend/src/views/textbook/index.vue b/frontend/src/views/textbook/index.vue deleted file mode 100644 index a2450c7cb..000000000 --- a/frontend/src/views/textbook/index.vue +++ /dev/null @@ -1,1558 +0,0 @@ - - - - - diff --git a/frontend/src/views/tool/build/CodeTypeDialog.vue b/frontend/src/views/tool/build/CodeTypeDialog.vue deleted file mode 100644 index 1b8207d37..000000000 --- a/frontend/src/views/tool/build/CodeTypeDialog.vue +++ /dev/null @@ -1,106 +0,0 @@ - - diff --git a/frontend/src/views/tool/build/DraggableItem.vue b/frontend/src/views/tool/build/DraggableItem.vue deleted file mode 100644 index 6eb960e09..000000000 --- a/frontend/src/views/tool/build/DraggableItem.vue +++ /dev/null @@ -1,100 +0,0 @@ - diff --git a/frontend/src/views/tool/build/IconsDialog.vue b/frontend/src/views/tool/build/IconsDialog.vue deleted file mode 100644 index 84dd9207e..000000000 --- a/frontend/src/views/tool/build/IconsDialog.vue +++ /dev/null @@ -1,123 +0,0 @@ - - - diff --git a/frontend/src/views/tool/build/RightPanel.vue b/frontend/src/views/tool/build/RightPanel.vue deleted file mode 100644 index 01e755c7e..000000000 --- a/frontend/src/views/tool/build/RightPanel.vue +++ /dev/null @@ -1,944 +0,0 @@ - - - - - diff --git a/frontend/src/views/tool/build/TreeNodeDialog.vue b/frontend/src/views/tool/build/TreeNodeDialog.vue deleted file mode 100644 index 61b19b939..000000000 --- a/frontend/src/views/tool/build/TreeNodeDialog.vue +++ /dev/null @@ -1,148 +0,0 @@ - - diff --git a/frontend/src/views/tool/build/index.vue b/frontend/src/views/tool/build/index.vue deleted file mode 100644 index 42a739c24..000000000 --- a/frontend/src/views/tool/build/index.vue +++ /dev/null @@ -1,775 +0,0 @@ - - - - - diff --git a/frontend/src/views/tool/gen/basicInfoForm.vue b/frontend/src/views/tool/gen/basicInfoForm.vue deleted file mode 100644 index 0d55f9e60..000000000 --- a/frontend/src/views/tool/gen/basicInfoForm.vue +++ /dev/null @@ -1,60 +0,0 @@ - - - diff --git a/frontend/src/views/tool/gen/createTable.vue b/frontend/src/views/tool/gen/createTable.vue deleted file mode 100644 index eedb09fb3..000000000 --- a/frontend/src/views/tool/gen/createTable.vue +++ /dev/null @@ -1,45 +0,0 @@ - - - diff --git a/frontend/src/views/tool/gen/editTable.vue b/frontend/src/views/tool/gen/editTable.vue deleted file mode 100644 index e6b12a8ed..000000000 --- a/frontend/src/views/tool/gen/editTable.vue +++ /dev/null @@ -1,230 +0,0 @@ - - - diff --git a/frontend/src/views/tool/gen/genInfoForm.vue b/frontend/src/views/tool/gen/genInfoForm.vue deleted file mode 100644 index 398bf30de..000000000 --- a/frontend/src/views/tool/gen/genInfoForm.vue +++ /dev/null @@ -1,336 +0,0 @@ - - - diff --git a/frontend/src/views/tool/gen/importTable.vue b/frontend/src/views/tool/gen/importTable.vue deleted file mode 100644 index 855f63a19..000000000 --- a/frontend/src/views/tool/gen/importTable.vue +++ /dev/null @@ -1,120 +0,0 @@ - - - diff --git a/frontend/src/views/tool/gen/index.vue b/frontend/src/views/tool/gen/index.vue deleted file mode 100644 index d4d4733fd..000000000 --- a/frontend/src/views/tool/gen/index.vue +++ /dev/null @@ -1,386 +0,0 @@ - - - - - diff --git a/frontend/src/views/tool/swagger/index.vue b/frontend/src/views/tool/swagger/index.vue deleted file mode 100644 index bf1e8f72a..000000000 --- a/frontend/src/views/tool/swagger/index.vue +++ /dev/null @@ -1,15 +0,0 @@ - - diff --git a/frontend/vue.config.js b/frontend/vue.config.js deleted file mode 100644 index f3767b08e..000000000 --- a/frontend/vue.config.js +++ /dev/null @@ -1,136 +0,0 @@ -'use strict' -const path = require('path') - -function resolve(dir) { - return path.join(__dirname, dir) -} - -const CompressionPlugin = require('compression-webpack-plugin') - -const name = process.env.VUE_APP_TITLE || '教学管理信息系统' // 网页标题 - -const baseUrl = 'http://10.1.1.17:8080' // 后端接口 - -const port = 80 // 固定开发服务器端口,避免多实例端口混乱 - -// vue.config.js 配置说明 -//官方vue.config.js 参考文档 https://cli.vuejs.org/zh/config/#css-loaderoptions -// 这里只列一部分,具体配置参考文档 -module.exports = { - // 部署生产环境和开发环境下的URL。 - // 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上 - // 例如 https://www.roomroot.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.roomroot.vip/admin/,则设置 baseUrl 为 /admin/。 - publicPath: process.env.NODE_ENV === "production" ? "/" : "/", - // 在npm run build 或 yarn build 时 ,生成文件的目录名称(要和baseUrl的生产环境路径一致)(默认dist) - outputDir: 'dist', - // 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下) - assetsDir: 'static', - // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。 - productionSourceMap: false, - transpileDependencies: ['quill'], - // webpack-dev-server 相关配置 - devServer: { - host: '0.0.0.0', - port: port, - open: true, - proxy: { - // detail: https://cli.vuejs.org/config/#devserver-proxy - [process.env.VUE_APP_BASE_API]: { - target: baseUrl, - changeOrigin: true, - pathRewrite: { - ['^/api']: '/api' - } - }, - // springdoc proxy - '^/v3/api-docs/(.*)': { - target: baseUrl, - changeOrigin: true - } - }, - disableHostCheck: true - }, - css: { - loaderOptions: { - sass: { - sassOptions: { outputStyle: "expanded" } - } - } - }, - configureWebpack: { - name: name, - resolve: { - alias: { - '@': resolve('src') - } - }, - plugins: [ - // http://doc.roomroot.vip/roomroot-vue/other/faq.html#使用gzip解压缩静态文件 - new CompressionPlugin({ - cache: false, // 不启用文件缓存 - test: /\.(js|css|html|jpe?g|png|gif|svg)?$/i, // 压缩文件格式 - filename: '[path][base].gz[query]', // 压缩后的文件名 - algorithm: 'gzip', // 使用gzip压缩 - minRatio: 0.8, // 压缩比例,小于 80% 的文件不会被压缩 - deleteOriginalAssets: false // 压缩后删除原文件 - }) - ], - }, - chainWebpack(config) { - config.plugins.delete('preload') // TODO: need test - config.plugins.delete('prefetch') // TODO: need test - - // set svg-sprite-loader - config.module - .rule('svg') - .exclude.add(resolve('src/assets/icons')) - .end() - config.module - .rule('icons') - .test(/\.svg$/) - .include.add(resolve('src/assets/icons')) - .end() - .use('svg-sprite-loader') - .loader('svg-sprite-loader') - .options({ - symbolId: 'icon-[name]' - }) - .end() - - config.when(process.env.NODE_ENV !== 'development', config => { - config - .plugin('ScriptExtHtmlWebpackPlugin') - .after('html') - .use('script-ext-html-webpack-plugin', [{ - // `runtime` must same as runtimeChunk name. default is `runtime` - inline: /runtime\..*\.js$/ - }]) - .end() - - config.optimization.splitChunks({ - chunks: 'all', - cacheGroups: { - libs: { - name: 'chunk-libs', - test: /[\\/]node_modules[\\/]/, - priority: 10, - chunks: 'initial' // only package third parties that are initially dependent - }, - elementUI: { - name: 'chunk-elementUI', // split elementUI into a single package - test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm - priority: 20 // the weight needs to be larger than libs and app or it will be packaged into libs or app - }, - commons: { - name: 'chunk-commons', - test: resolve('src/components'), // can customize your rules - minChunks: 3, // minimum common number - priority: 5, - reuseExistingChunk: true - } - } - }) - config.optimization.runtimeChunk('single') - }) - } -}