提交代码
This commit is contained in:
1 parent
594d0c5df3
commit
f89d747952
13 files changed
+2655
No files matched your search
+87
@@ -0,0 +1,87 @@
|
||||
package org.dromara.xg.controller;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.xg.domain.vo.XgDormApplicationVo;
|
||||
import org.dromara.xg.domain.vo.XgHolidayStayVo;
|
||||
import org.dromara.xg.domain.vo.XgStudentLeaveVo;
|
||||
import org.dromara.xg.domain.bo.XgDormApplicationBo;
|
||||
import org.dromara.xg.domain.bo.XgHolidayStayBo;
|
||||
import org.dromara.xg.domain.bo.XgStudentLeaveBo;
|
||||
import org.dromara.xg.service.IXgStudentDynamicsService;
|
||||
|
||||
/**
|
||||
* 学生动向信息管理(宿管员)
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/studentDynamics")
|
||||
public class XgStudentDynamicsController extends BaseController {
|
||||
|
||||
private final IXgStudentDynamicsService xgStudentDynamicsService;
|
||||
|
||||
/**
|
||||
* 查询宿管员权限内的学生调宿退宿申请列表
|
||||
*/
|
||||
@SaCheckPermission("studentDynamics:dormApplication:list")
|
||||
@GetMapping("/dormApplicationList")
|
||||
public TableDataInfo<XgDormApplicationVo> getDormApplicationList(XgDormApplicationBo bo, PageQuery pageQuery) {
|
||||
return xgStudentDynamicsService.queryDormApplicationPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询宿管员权限内的学生假期留宿信息列表
|
||||
*/
|
||||
@SaCheckPermission("studentDynamics:holidayStay:list")
|
||||
@GetMapping("/holidayStayList")
|
||||
public TableDataInfo<XgHolidayStayVo> getHolidayStayList(XgHolidayStayBo bo, PageQuery pageQuery) {
|
||||
return xgStudentDynamicsService.queryHolidayStayPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询宿管员权限内的学生请假信息列表
|
||||
*/
|
||||
@SaCheckPermission("studentDynamics:studentLeave:list")
|
||||
@GetMapping("/studentLeaveList")
|
||||
public TableDataInfo<XgStudentLeaveVo> getStudentLeaveList(XgStudentLeaveBo bo, PageQuery pageQuery) {
|
||||
return xgStudentDynamicsService.queryStudentLeavePageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取调宿退宿申请详细信息
|
||||
*/
|
||||
@SaCheckPermission("studentDynamics:dormApplication:query")
|
||||
@GetMapping("/dormApplication/{id}")
|
||||
public R<XgDormApplicationVo> getDormApplicationInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
|
||||
return R.ok(xgStudentDynamicsService.queryDormApplicationById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取假期留宿详细信息
|
||||
*/
|
||||
@SaCheckPermission("studentDynamics:holidayStay:query")
|
||||
@GetMapping("/holidayStay/{id}")
|
||||
public R<XgHolidayStayVo> getHolidayStayInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
|
||||
return R.ok(xgStudentDynamicsService.queryHolidayStayById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取学生请假详细信息
|
||||
*/
|
||||
@SaCheckPermission("studentDynamics:studentLeave:query")
|
||||
@GetMapping("/studentLeave/{id}")
|
||||
public R<XgStudentLeaveVo> getStudentLeaveInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
|
||||
return R.ok(xgStudentDynamicsService.queryStudentLeaveById(id));
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package org.dromara.xg.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 学生动向信息管理(宿管员)Mapper接口
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
public interface XgStudentDynamicsMapper {
|
||||
|
||||
/**
|
||||
* 检查用户是否有宿舍管理权限
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 管理员类型列表 (1全校管理员 2校区管理员 3宿舍区管理员 4宿舍楼管理员)
|
||||
*/
|
||||
List<String> checkUserDormManagerType(@Param("userId") Long userId);
|
||||
|
||||
/**
|
||||
* 获取全校管理员权限的所有楼栋ID列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 楼栋ID列表
|
||||
*/
|
||||
List<Long> getBuildingIdsBySchoolAdmin(@Param("userId") Long userId);
|
||||
|
||||
/**
|
||||
* 获取校区管理员权限的楼栋ID列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 楼栋ID列表
|
||||
*/
|
||||
List<Long> getBuildingIdsByCampusAdmin(@Param("userId") Long userId);
|
||||
|
||||
/**
|
||||
* 获取宿舍区管理员权限的楼栋ID列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 楼栋ID列表
|
||||
*/
|
||||
List<Long> getBuildingIdsByAreaAdmin(@Param("userId") Long userId);
|
||||
|
||||
/**
|
||||
* 获取宿舍楼管理员权限的楼栋ID列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 楼栋ID列表
|
||||
*/
|
||||
List<Long> getBuildingIdsByBuildingAdmin(@Param("userId") Long userId);
|
||||
|
||||
/**
|
||||
* 获取全校管理员权限的所有学生ID列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 学生ID列表
|
||||
*/
|
||||
List<Long> getStudentIdsBySchoolAdmin(@Param("userId") Long userId);
|
||||
|
||||
/**
|
||||
* 获取校区管理员权限的学生ID列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 学生ID列表
|
||||
*/
|
||||
List<Long> getStudentIdsByCampusAdmin(@Param("userId") Long userId);
|
||||
|
||||
/**
|
||||
* 获取宿舍区管理员权限的学生ID列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 学生ID列表
|
||||
*/
|
||||
List<Long> getStudentIdsByAreaAdmin(@Param("userId") Long userId);
|
||||
|
||||
/**
|
||||
* 获取宿舍楼管理员权限的学生ID列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 学生ID列表
|
||||
*/
|
||||
List<Long> getStudentIdsByBuildingAdmin(@Param("userId") Long userId);
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package org.dromara.xg.service;
|
||||
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.xg.domain.vo.XgDormApplicationVo;
|
||||
import org.dromara.xg.domain.vo.XgHolidayStayVo;
|
||||
import org.dromara.xg.domain.vo.XgStudentLeaveVo;
|
||||
import org.dromara.xg.domain.bo.XgDormApplicationBo;
|
||||
import org.dromara.xg.domain.bo.XgHolidayStayBo;
|
||||
import org.dromara.xg.domain.bo.XgStudentLeaveBo;
|
||||
|
||||
/**
|
||||
* 学生动向信息管理(宿管员)Service接口
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
public interface IXgStudentDynamicsService {
|
||||
|
||||
/**
|
||||
* 查询宿管员权限内的学生调宿退宿申请列表
|
||||
*/
|
||||
TableDataInfo<XgDormApplicationVo> queryDormApplicationPageList(XgDormApplicationBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询宿管员权限内的学生假期留宿信息列表
|
||||
*/
|
||||
TableDataInfo<XgHolidayStayVo> queryHolidayStayPageList(XgHolidayStayBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询宿管员权限内的学生请假信息列表
|
||||
*/
|
||||
TableDataInfo<XgStudentLeaveVo> queryStudentLeavePageList(XgStudentLeaveBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 根据主键查询调宿退宿申请详情
|
||||
*/
|
||||
XgDormApplicationVo queryDormApplicationById(Long id);
|
||||
|
||||
/**
|
||||
* 根据主键查询假期留宿详情
|
||||
*/
|
||||
XgHolidayStayVo queryHolidayStayById(Long id);
|
||||
|
||||
/**
|
||||
* 根据主键查询学生请假详情
|
||||
*/
|
||||
XgStudentLeaveVo queryStudentLeaveById(Long id);
|
||||
}
|
||||
+329
@@ -0,0 +1,329 @@
|
||||
package org.dromara.xg.service.impl;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.xg.domain.vo.XgDormApplicationVo;
|
||||
import org.dromara.xg.domain.vo.XgHolidayStayVo;
|
||||
import org.dromara.xg.domain.vo.XgStudentLeaveVo;
|
||||
import org.dromara.xg.domain.bo.XgDormApplicationBo;
|
||||
import org.dromara.xg.domain.bo.XgHolidayStayBo;
|
||||
import org.dromara.xg.domain.bo.XgStudentLeaveBo;
|
||||
import org.dromara.xg.domain.XgDormApplication;
|
||||
import org.dromara.xg.domain.XgHolidayStay;
|
||||
import org.dromara.xg.domain.XgStudentLeave;
|
||||
import org.dromara.xg.mapper.XgDormApplicationMapper;
|
||||
import org.dromara.xg.mapper.XgHolidayStayMapper;
|
||||
import org.dromara.xg.mapper.XgStudentLeaveMapper;
|
||||
import org.dromara.xg.mapper.XgStudentDynamicsMapper;
|
||||
import org.dromara.xg.service.IXgStudentDynamicsService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 学生动向信息管理(宿管员)Service实现
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class XgStudentDynamicsServiceImpl implements IXgStudentDynamicsService {
|
||||
|
||||
private final XgDormApplicationMapper dormApplicationMapper;
|
||||
private final XgHolidayStayMapper holidayStayMapper;
|
||||
private final XgStudentLeaveMapper studentLeaveMapper;
|
||||
private final XgStudentDynamicsMapper studentDynamicsMapper;
|
||||
|
||||
/**
|
||||
* 查询宿管员权限内的学生调宿退宿申请列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<XgDormApplicationVo> queryDormApplicationPageList(XgDormApplicationBo bo,
|
||||
PageQuery pageQuery) {
|
||||
// 获取当前登录用户ID
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
|
||||
// 构建查询条件
|
||||
LambdaQueryWrapper<XgDormApplication> lqw = buildDormApplicationQueryWrapper(bo, currentUserId);
|
||||
|
||||
// 分页查询
|
||||
Page<XgDormApplicationVo> result = dormApplicationMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询宿管员权限内的学生假期留宿信息列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<XgHolidayStayVo> queryHolidayStayPageList(XgHolidayStayBo bo, PageQuery pageQuery) {
|
||||
// 获取当前登录用户ID
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
|
||||
// 构建查询条件
|
||||
LambdaQueryWrapper<XgHolidayStay> lqw = buildHolidayStayQueryWrapper(bo, currentUserId);
|
||||
|
||||
// 分页查询
|
||||
Page<XgHolidayStayVo> result = holidayStayMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询宿管员权限内的学生请假信息列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<XgStudentLeaveVo> queryStudentLeavePageList(XgStudentLeaveBo bo, PageQuery pageQuery) {
|
||||
// 获取当前登录用户ID
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
|
||||
// 构建查询条件
|
||||
LambdaQueryWrapper<XgStudentLeave> lqw = buildStudentLeaveQueryWrapper(bo, currentUserId);
|
||||
|
||||
// 分页查询
|
||||
Page<XgStudentLeaveVo> result = studentLeaveMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据主键查询调宿退宿申请详情
|
||||
*/
|
||||
@Override
|
||||
public XgDormApplicationVo queryDormApplicationById(Long id) {
|
||||
return dormApplicationMapper.selectVoById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据主键查询假期留宿详情
|
||||
*/
|
||||
@Override
|
||||
public XgHolidayStayVo queryHolidayStayById(Long id) {
|
||||
return holidayStayMapper.selectVoById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据主键查询学生请假详情
|
||||
*/
|
||||
@Override
|
||||
public XgStudentLeaveVo queryStudentLeaveById(Long id) {
|
||||
return studentLeaveMapper.selectVoById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建调宿退宿申请查询条件(带宿管员权限)
|
||||
*/
|
||||
private LambdaQueryWrapper<XgDormApplication> buildDormApplicationQueryWrapper(XgDormApplicationBo bo,
|
||||
Long currentUserId) {
|
||||
LambdaQueryWrapper<XgDormApplication> lqw = new LambdaQueryWrapper<>();
|
||||
|
||||
// 获取宿管员管理的楼栋ID列表
|
||||
List<Long> managedBuildingIds = getManagedBuildingIds(currentUserId);
|
||||
|
||||
if (managedBuildingIds.isEmpty()) {
|
||||
// 如果没有管理权限,返回空结果
|
||||
lqw.eq(XgDormApplication::getId, -1);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
// 只查询宿管员权限内楼栋的学生申请
|
||||
lqw.in(XgDormApplication::getCurrentBuildingId, managedBuildingIds);
|
||||
|
||||
// 添加其他查询条件
|
||||
lqw.like(bo.getStudentName() != null, XgDormApplication::getStudentName, bo.getStudentName());
|
||||
lqw.like(bo.getStudentNo() != null, XgDormApplication::getStudentNo, bo.getStudentNo());
|
||||
lqw.like(bo.getCollegeName() != null, XgDormApplication::getCollegeName, bo.getCollegeName());
|
||||
lqw.like(bo.getMajorName() != null, XgDormApplication::getMajorName, bo.getMajorName());
|
||||
lqw.like(bo.getClassName() != null, XgDormApplication::getClassName, bo.getClassName());
|
||||
lqw.eq(bo.getApplicationType() != null, XgDormApplication::getApplicationType, bo.getApplicationType());
|
||||
lqw.eq(bo.getApplicationStatus() != null, XgDormApplication::getApplicationStatus, bo.getApplicationStatus());
|
||||
lqw.ge(bo.getApplyTime() != null, XgDormApplication::getApplyTime, bo.getApplyTime());
|
||||
|
||||
// 默认按创建时间倒序
|
||||
lqw.orderByDesc(XgDormApplication::getCreateTime);
|
||||
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建假期留宿查询条件(带宿管员权限)
|
||||
*/
|
||||
private LambdaQueryWrapper<XgHolidayStay> buildHolidayStayQueryWrapper(XgHolidayStayBo bo, Long currentUserId) {
|
||||
LambdaQueryWrapper<XgHolidayStay> lqw = new LambdaQueryWrapper<>();
|
||||
|
||||
// 获取宿管员管理的楼栋ID列表
|
||||
List<Long> managedBuildingIds = getManagedBuildingIds(currentUserId);
|
||||
|
||||
if (managedBuildingIds.isEmpty()) {
|
||||
// 如果没有管理权限,返回空结果
|
||||
lqw.eq(XgHolidayStay::getId, -1);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
// 只查询宿管员权限内楼栋的学生留宿
|
||||
lqw.in(XgHolidayStay::getBuildingId, managedBuildingIds);
|
||||
|
||||
// 添加其他查询条件
|
||||
lqw.like(bo.getStudentName() != null, XgHolidayStay::getStudentName, bo.getStudentName());
|
||||
lqw.like(bo.getStudentNo() != null, XgHolidayStay::getStudentNo, bo.getStudentNo());
|
||||
lqw.like(bo.getCollegeName() != null, XgHolidayStay::getCollegeName, bo.getCollegeName());
|
||||
lqw.like(bo.getMajorName() != null, XgHolidayStay::getMajorName, bo.getMajorName());
|
||||
lqw.like(bo.getClassName() != null, XgHolidayStay::getClassName, bo.getClassName());
|
||||
lqw.eq(bo.getHolidayType() != null, XgHolidayStay::getHolidayType, bo.getHolidayType());
|
||||
lqw.ge(bo.getApplyStartDate() != null, XgHolidayStay::getApplyStartDate, bo.getApplyStartDate());
|
||||
lqw.le(bo.getApplyEndDate() != null, XgHolidayStay::getApplyEndDate, bo.getApplyEndDate());
|
||||
|
||||
// 默认按创建时间倒序
|
||||
lqw.orderByDesc(XgHolidayStay::getCreateTime);
|
||||
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建学生请假查询条件(带宿管员权限)
|
||||
*/
|
||||
private LambdaQueryWrapper<XgStudentLeave> buildStudentLeaveQueryWrapper(XgStudentLeaveBo bo, Long currentUserId) {
|
||||
LambdaQueryWrapper<XgStudentLeave> lqw = new LambdaQueryWrapper<>();
|
||||
|
||||
// 获取宿管员权限内的学生ID列表
|
||||
List<Long> managedStudentIds = getManagedStudentIds(currentUserId);
|
||||
|
||||
if (managedStudentIds.isEmpty()) {
|
||||
// 如果没有管理权限,返回空结果
|
||||
lqw.eq(XgStudentLeave::getId, -1);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
// 只查询宿管员权限内的学生请假
|
||||
lqw.in(XgStudentLeave::getStudentId, managedStudentIds);
|
||||
|
||||
// 添加其他查询条件
|
||||
lqw.like(bo.getStudentName() != null, XgStudentLeave::getStudentName, bo.getStudentName());
|
||||
lqw.like(bo.getStudentNo() != null, XgStudentLeave::getStudentNo, bo.getStudentNo());
|
||||
lqw.like(bo.getCollegeName() != null, XgStudentLeave::getCollegeName, bo.getCollegeName());
|
||||
lqw.like(bo.getMajorName() != null, XgStudentLeave::getMajorName, bo.getMajorName());
|
||||
lqw.like(bo.getClassName() != null, XgStudentLeave::getClassName, bo.getClassName());
|
||||
lqw.like(bo.getLeaveTypeName() != null, XgStudentLeave::getLeaveTypeName, bo.getLeaveTypeName());
|
||||
lqw.eq(bo.getApprovalStatus() != null, XgStudentLeave::getApprovalStatus, bo.getApprovalStatus());
|
||||
lqw.ge(bo.getStartTime() != null, XgStudentLeave::getStartTime, bo.getStartTime());
|
||||
lqw.le(bo.getEndTime() != null, XgStudentLeave::getEndTime, bo.getEndTime());
|
||||
|
||||
// 默认按创建时间倒序
|
||||
lqw.orderByDesc(XgStudentLeave::getCreateTime);
|
||||
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取宿管员管理的楼栋ID列表(支持多级权限合并)
|
||||
*/
|
||||
private List<Long> getManagedBuildingIds(Long userId) {
|
||||
// 查询用户管理权限类型
|
||||
List<String> managerTypes = studentDynamicsMapper.checkUserDormManagerType(userId);
|
||||
|
||||
if (managerTypes == null || managerTypes.isEmpty()) {
|
||||
// 没有宿舍管理权限,返回空列表
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 存储所有权限的楼栋ID,使用Set去重
|
||||
Set<Long> buildingIdSet = new HashSet<>();
|
||||
|
||||
// 按照权限分别查询并合并结果(支持用户拥有多种角色的情况)
|
||||
if (managerTypes.contains("1")) {
|
||||
// 全校管理员,获取所有楼栋
|
||||
List<Long> allBuildings = studentDynamicsMapper.getBuildingIdsBySchoolAdmin(userId);
|
||||
if (allBuildings != null) {
|
||||
buildingIdSet.addAll(allBuildings);
|
||||
}
|
||||
// 全校管理员可以查看所有楼栋,直接返回
|
||||
return new ArrayList<>(buildingIdSet);
|
||||
}
|
||||
|
||||
// 对于非全校管理员,合并多种权限的结果
|
||||
if (managerTypes.contains("2")) {
|
||||
// 校区管理员,获取管理的校区下的楼栋
|
||||
List<Long> campusBuildings = studentDynamicsMapper.getBuildingIdsByCampusAdmin(userId);
|
||||
if (campusBuildings != null) {
|
||||
buildingIdSet.addAll(campusBuildings);
|
||||
}
|
||||
}
|
||||
|
||||
if (managerTypes.contains("3")) {
|
||||
// 宿舍区管理员,获取管理的宿舍区下的楼栋
|
||||
List<Long> areaBuildings = studentDynamicsMapper.getBuildingIdsByAreaAdmin(userId);
|
||||
if (areaBuildings != null) {
|
||||
buildingIdSet.addAll(areaBuildings);
|
||||
}
|
||||
}
|
||||
|
||||
if (managerTypes.contains("4")) {
|
||||
// 宿舍楼管理员,获取管理的楼栋
|
||||
List<Long> directBuildings = studentDynamicsMapper.getBuildingIdsByBuildingAdmin(userId);
|
||||
if (directBuildings != null) {
|
||||
buildingIdSet.addAll(directBuildings);
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayList<>(buildingIdSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取宿管员权限内的学生ID列表(支持多级权限合并)
|
||||
*/
|
||||
private List<Long> getManagedStudentIds(Long userId) {
|
||||
// 查询用户管理权限类型
|
||||
List<String> managerTypes = studentDynamicsMapper.checkUserDormManagerType(userId);
|
||||
|
||||
if (managerTypes == null || managerTypes.isEmpty()) {
|
||||
// 没有宿舍管理权限,返回空列表
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 存储所有权限的学生ID,使用Set去重
|
||||
Set<Long> studentIdSet = new HashSet<>();
|
||||
|
||||
// 按照权限分别查询并合并结果(支持用户拥有多种角色的情况)
|
||||
if (managerTypes.contains("1")) {
|
||||
// 全校管理员,获取所有学生
|
||||
List<Long> allStudents = studentDynamicsMapper.getStudentIdsBySchoolAdmin(userId);
|
||||
if (allStudents != null) {
|
||||
studentIdSet.addAll(allStudents);
|
||||
}
|
||||
// 全校管理员可以查看所有学生,直接返回
|
||||
return new ArrayList<>(studentIdSet);
|
||||
}
|
||||
|
||||
// 对于非全校管理员,合并多种权限的结果
|
||||
if (managerTypes.contains("2")) {
|
||||
// 校区管理员,获取管理的校区下的学生
|
||||
List<Long> campusStudents = studentDynamicsMapper.getStudentIdsByCampusAdmin(userId);
|
||||
if (campusStudents != null) {
|
||||
studentIdSet.addAll(campusStudents);
|
||||
}
|
||||
}
|
||||
|
||||
if (managerTypes.contains("3")) {
|
||||
// 宿舍区管理员,获取管理的宿舍区下的学生
|
||||
List<Long> areaStudents = studentDynamicsMapper.getStudentIdsByAreaAdmin(userId);
|
||||
if (areaStudents != null) {
|
||||
studentIdSet.addAll(areaStudents);
|
||||
}
|
||||
}
|
||||
|
||||
if (managerTypes.contains("4")) {
|
||||
// 宿舍楼管理员,获取管理的楼栋下的学生
|
||||
List<Long> buildingStudents = studentDynamicsMapper.getStudentIdsByBuildingAdmin(userId);
|
||||
if (buildingStudents != null) {
|
||||
studentIdSet.addAll(buildingStudents);
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayList<>(studentIdSet);
|
||||
}
|
||||
}
|
||||
+213
@@ -0,0 +1,213 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.xg.mapper.XgStudentDynamicsMapper">
|
||||
|
||||
<!-- 检查用户是否有宿舍管理权限 -->
|
||||
<select id="checkUserDormManagerType" resultType="String">
|
||||
SELECT
|
||||
DISTINCT manager_type
|
||||
FROM
|
||||
xg_dorm_manager
|
||||
WHERE
|
||||
user_id = #{userId}
|
||||
AND deleted = '0'
|
||||
AND status = '0'
|
||||
</select>
|
||||
|
||||
<!-- 获取全校管理员权限的所有楼栋ID列表 -->
|
||||
<select id="getBuildingIdsBySchoolAdmin" resultType="Long">
|
||||
SELECT
|
||||
id
|
||||
FROM
|
||||
xg_dorm_building
|
||||
WHERE
|
||||
deleted = '0'
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM xg_dorm_manager m
|
||||
WHERE m.user_id = #{userId}
|
||||
AND m.manager_type = '1'
|
||||
AND m.deleted = '0'
|
||||
AND m.status = '0'
|
||||
)
|
||||
</select>
|
||||
|
||||
<!-- 获取校区管理员权限的楼栋ID列表 -->
|
||||
<select id="getBuildingIdsByCampusAdmin" resultType="Long">
|
||||
SELECT
|
||||
b.id
|
||||
FROM
|
||||
xg_dorm_building b
|
||||
WHERE
|
||||
b.deleted = '0'
|
||||
AND b.campus_id IN (
|
||||
SELECT
|
||||
s.auth_source
|
||||
FROM
|
||||
xg_dorm_manager m
|
||||
JOIN
|
||||
xg_dorm_manager_source s ON m.id = s.manager_id
|
||||
WHERE
|
||||
m.user_id = #{userId}
|
||||
AND m.manager_type = '2'
|
||||
AND m.deleted = '0'
|
||||
AND m.status = '0'
|
||||
AND s.deleted = '0'
|
||||
AND s.status = '0'
|
||||
)
|
||||
</select>
|
||||
|
||||
<!-- 获取宿舍区管理员权限的楼栋ID列表 -->
|
||||
<select id="getBuildingIdsByAreaAdmin" resultType="Long">
|
||||
SELECT
|
||||
b.id
|
||||
FROM
|
||||
xg_dorm_building b
|
||||
WHERE
|
||||
b.deleted = '0'
|
||||
AND b.area_id IN (
|
||||
SELECT
|
||||
s.auth_source
|
||||
FROM
|
||||
xg_dorm_manager m
|
||||
JOIN
|
||||
xg_dorm_manager_source s ON m.id = s.manager_id
|
||||
WHERE
|
||||
m.user_id = #{userId}
|
||||
AND m.manager_type = '3'
|
||||
AND m.deleted = '0'
|
||||
AND m.status = '0'
|
||||
AND s.deleted = '0'
|
||||
AND s.status = '0'
|
||||
)
|
||||
</select>
|
||||
|
||||
<!-- 获取宿舍楼管理员权限的楼栋ID列表 -->
|
||||
<select id="getBuildingIdsByBuildingAdmin" resultType="Long">
|
||||
SELECT
|
||||
b.id
|
||||
FROM
|
||||
xg_dorm_building b
|
||||
WHERE
|
||||
b.deleted = '0'
|
||||
AND b.id IN (
|
||||
SELECT
|
||||
s.auth_source
|
||||
FROM
|
||||
xg_dorm_manager m
|
||||
JOIN
|
||||
xg_dorm_manager_source s ON m.id = s.manager_id
|
||||
WHERE
|
||||
m.user_id = #{userId}
|
||||
AND m.manager_type = '4'
|
||||
AND m.deleted = '0'
|
||||
AND m.status = '0'
|
||||
AND s.deleted = '0'
|
||||
AND s.status = '0'
|
||||
)
|
||||
</select>
|
||||
|
||||
<!-- 获取全校管理员权限的所有学生ID列表 -->
|
||||
<select id="getStudentIdsBySchoolAdmin" resultType="Long">
|
||||
SELECT
|
||||
sm.id
|
||||
FROM
|
||||
xg_student_msg sm
|
||||
WHERE
|
||||
sm.deleted = 0
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM xg_dorm_manager m
|
||||
WHERE m.user_id = #{userId}
|
||||
AND m.manager_type = '1'
|
||||
AND m.deleted = '0'
|
||||
AND m.status = '0'
|
||||
)
|
||||
</select>
|
||||
|
||||
<!-- 获取校区管理员权限的学生ID列表 -->
|
||||
<select id="getStudentIdsByCampusAdmin" resultType="Long">
|
||||
SELECT
|
||||
sm.id
|
||||
FROM
|
||||
xg_student_msg sm
|
||||
INNER JOIN
|
||||
xg_dorm_building db ON sm.dormitory_building = db.id
|
||||
WHERE
|
||||
sm.deleted = 0
|
||||
AND db.deleted = '0'
|
||||
AND db.campus_id IN (
|
||||
SELECT
|
||||
s.auth_source
|
||||
FROM
|
||||
xg_dorm_manager m
|
||||
JOIN
|
||||
xg_dorm_manager_source s ON m.id = s.manager_id
|
||||
WHERE
|
||||
m.user_id = #{userId}
|
||||
AND m.manager_type = '2'
|
||||
AND m.deleted = '0'
|
||||
AND m.status = '0'
|
||||
AND s.deleted = '0'
|
||||
AND s.status = '0'
|
||||
)
|
||||
</select>
|
||||
|
||||
<!-- 获取宿舍区管理员权限的学生ID列表 -->
|
||||
<select id="getStudentIdsByAreaAdmin" resultType="Long">
|
||||
SELECT
|
||||
sm.id
|
||||
FROM
|
||||
xg_student_msg sm
|
||||
INNER JOIN
|
||||
xg_dorm_building db ON sm.dormitory_building = db.id
|
||||
WHERE
|
||||
sm.deleted = 0
|
||||
AND db.deleted = '0'
|
||||
AND db.area_id IN (
|
||||
SELECT
|
||||
s.auth_source
|
||||
FROM
|
||||
xg_dorm_manager m
|
||||
JOIN
|
||||
xg_dorm_manager_source s ON m.id = s.manager_id
|
||||
WHERE
|
||||
m.user_id = #{userId}
|
||||
AND m.manager_type = '3'
|
||||
AND m.deleted = '0'
|
||||
AND m.status = '0'
|
||||
AND s.deleted = '0'
|
||||
AND s.status = '0'
|
||||
)
|
||||
</select>
|
||||
|
||||
<!-- 获取宿舍楼管理员权限的学生ID列表 -->
|
||||
<select id="getStudentIdsByBuildingAdmin" resultType="Long">
|
||||
SELECT
|
||||
sm.id
|
||||
FROM
|
||||
xg_student_msg sm
|
||||
INNER JOIN
|
||||
xg_dorm_building db ON sm.dormitory_building = db.id
|
||||
WHERE
|
||||
sm.deleted = 0
|
||||
AND db.deleted = '0'
|
||||
AND db.id IN (
|
||||
SELECT
|
||||
s.auth_source
|
||||
FROM
|
||||
xg_dorm_manager m
|
||||
JOIN
|
||||
xg_dorm_manager_source s ON m.id = s.manager_id
|
||||
WHERE
|
||||
m.user_id = #{userId}
|
||||
AND m.manager_type = '4'
|
||||
AND m.deleted = '0'
|
||||
AND m.status = '0'
|
||||
AND s.deleted = '0'
|
||||
AND s.status = '0'
|
||||
)
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -0,0 +1,269 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
/**
|
||||
* 学生动向信息管理(宿管员)API
|
||||
* 这些接口专门用于学生动向Tab页,会自动根据宿管员权限过滤数据
|
||||
*/
|
||||
|
||||
// ==================== 调宿退宿申请相关接口 ====================
|
||||
|
||||
export interface DormApplicationQuery {
|
||||
pageNum?: number;
|
||||
pageSize?: number;
|
||||
studentName?: string;
|
||||
studentNo?: string;
|
||||
collegeName?: string;
|
||||
majorName?: string;
|
||||
className?: string;
|
||||
applicationType?: string;
|
||||
applicationStatus?: string;
|
||||
applyTime?: string;
|
||||
params?: any;
|
||||
}
|
||||
|
||||
export interface DormApplicationVO {
|
||||
id: string | number;
|
||||
applicationName: string;
|
||||
applicationType: string;
|
||||
applicationStatus: string;
|
||||
studentId: string | number;
|
||||
studentNo: string;
|
||||
studentName: string;
|
||||
studentPhone: string;
|
||||
collegeId: string | number;
|
||||
collegeName: string;
|
||||
majorId: string | number;
|
||||
majorName: string;
|
||||
classId: string | number;
|
||||
className: string;
|
||||
currentCampusId: string | number;
|
||||
currentCampusName: string;
|
||||
currentBuildingId: string | number;
|
||||
currentBuildingName: string;
|
||||
currentRoomId: string | number;
|
||||
currentRoomNo: string;
|
||||
currentBedId: string | number;
|
||||
currentBedNo: string;
|
||||
targetCampusId?: string | number;
|
||||
targetCampusName?: string;
|
||||
targetBuildingId?: string | number;
|
||||
targetBuildingName?: string;
|
||||
targetRoomId?: string | number;
|
||||
targetRoomNo?: string;
|
||||
targetBedId?: string | number;
|
||||
targetBedNo?: string;
|
||||
reasonDetail: string;
|
||||
applyTime: string;
|
||||
attachmentOssIds?: string;
|
||||
remark?: string;
|
||||
createTime: string;
|
||||
updateTime: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询宿管员权限内的学生调宿退宿申请列表
|
||||
*/
|
||||
export function listDormApplication(query?: DormApplicationQuery): AxiosPromise<any> {
|
||||
return request({
|
||||
url: '/studentDynamics/dormApplicationList',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取调宿退宿申请详细信息
|
||||
*/
|
||||
export function getDormApplication(id: string | number): AxiosPromise<DormApplicationVO> {
|
||||
return request({
|
||||
url: '/studentDynamics/dormApplication/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取调宿退宿申请详细信息(别名)
|
||||
*/
|
||||
export const getDormApplicationInfo = getDormApplication;
|
||||
|
||||
/**
|
||||
* 修改调宿退宿申请信息
|
||||
*/
|
||||
export function updateDormApplication(data: DormApplicationVO): AxiosPromise<any> {
|
||||
return request({
|
||||
url: '/studentDynamics/dormApplication',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除调宿退宿申请
|
||||
*/
|
||||
export function delDormApplication(id: string | number | Array<string | number>): AxiosPromise<any> {
|
||||
return request({
|
||||
url: '/studentDynamics/dormApplication/' + id,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== 假期留宿相关接口 ====================
|
||||
|
||||
export interface HolidayStayQuery {
|
||||
pageNum?: number;
|
||||
pageSize?: number;
|
||||
studentName?: string;
|
||||
studentNo?: string;
|
||||
collegeName?: string;
|
||||
majorName?: string;
|
||||
className?: string;
|
||||
holidayType?: string;
|
||||
applyStartDate?: string;
|
||||
applyEndDate?: string;
|
||||
status?: string;
|
||||
params?: any;
|
||||
}
|
||||
|
||||
export interface HolidayStayVO {
|
||||
id: string | number;
|
||||
studentId: string | number;
|
||||
studentName: string;
|
||||
studentNo: string;
|
||||
classId: string | number;
|
||||
className: string;
|
||||
majorId: string | number;
|
||||
majorName: string;
|
||||
collegeId: string | number;
|
||||
collegeName: string;
|
||||
campusId: string | number;
|
||||
campusName: string;
|
||||
areaId?: string | number;
|
||||
areaName?: string;
|
||||
buildingId: string | number;
|
||||
buildingName: string;
|
||||
roomId: string | number;
|
||||
roomName: string;
|
||||
bedId: string | number;
|
||||
bedName: string;
|
||||
holidayType: string;
|
||||
applyStartDate: string;
|
||||
applyEndDate: string;
|
||||
stayReason: string;
|
||||
stayReasonType: string;
|
||||
studentPhone: string;
|
||||
emergencyContact: string;
|
||||
emergencyPhone: string;
|
||||
parentConsent: string;
|
||||
attachmentOssIds?: string;
|
||||
remark?: string;
|
||||
createTime: string;
|
||||
updateTime: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询宿管员权限内的学生假期留宿信息列表
|
||||
*/
|
||||
export function listHolidayStay(query?: HolidayStayQuery): AxiosPromise<any> {
|
||||
return request({
|
||||
url: '/studentDynamics/holidayStayList',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取假期留宿详细信息
|
||||
*/
|
||||
export function getHolidayStay(id: string | number): AxiosPromise<HolidayStayVO> {
|
||||
return request({
|
||||
url: '/studentDynamics/holidayStay/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取假期留宿详细信息(别名)
|
||||
*/
|
||||
export const getHolidayStayInfo = getHolidayStay;
|
||||
|
||||
// ==================== 学生请假相关接口 ====================
|
||||
|
||||
export interface StudentLeaveQuery {
|
||||
pageNum?: number;
|
||||
pageSize?: number;
|
||||
studentName?: string;
|
||||
studentNo?: string;
|
||||
collegeName?: string;
|
||||
majorName?: string;
|
||||
className?: string;
|
||||
leaveTypeName?: string;
|
||||
approvalStatus?: string;
|
||||
startTime?: string;
|
||||
endTime?: string;
|
||||
params?: any;
|
||||
}
|
||||
|
||||
export interface StudentLeaveVO {
|
||||
id: string | number;
|
||||
studentId: string | number;
|
||||
studentName: string;
|
||||
studentNo: string;
|
||||
classId: string | number;
|
||||
className: string;
|
||||
majorId: string | number;
|
||||
majorName: string;
|
||||
collegeId: string | number;
|
||||
collegeName: string;
|
||||
leaveTypeCode: string;
|
||||
leaveTypeName: string;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
leaveDuration: number;
|
||||
isLeaveSchool: string;
|
||||
needCancel: string;
|
||||
emergencyContact: string;
|
||||
emergencyPhone: string;
|
||||
leaveReason: string;
|
||||
leaveLocation?: string;
|
||||
attachmentOssIds?: string;
|
||||
approvalStatus: string;
|
||||
approvalOpinion?: string;
|
||||
approvalTime?: string;
|
||||
approvalBy?: string | number;
|
||||
approvalByName?: string;
|
||||
cancelStatus?: string;
|
||||
cancelTime?: string;
|
||||
cancelLocation?: string;
|
||||
cancelPhotoOssIds?: string;
|
||||
cancelRemark?: string;
|
||||
createTime: string;
|
||||
updateTime: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询宿管员权限内的学生请假信息列表
|
||||
*/
|
||||
export function listStudentLeave(query?: StudentLeaveQuery): AxiosPromise<any> {
|
||||
return request({
|
||||
url: '/studentDynamics/studentLeaveList',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取学生请假详细信息
|
||||
*/
|
||||
export function getStudentLeave(id: string | number): AxiosPromise<StudentLeaveVO> {
|
||||
return request({
|
||||
url: '/studentDynamics/studentLeave/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取学生请假详细信息(别名)
|
||||
*/
|
||||
export const getStudentLeaveInfo = getStudentLeave;
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
<template>
|
||||
<el-dialog :title="dialogTitle" v-model="dialogOpen" width="800px" append-to-body @close="cancel">
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px" v-loading="loading">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="申请名称:">
|
||||
<span>{{ form.applicationName }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="申请类型:">
|
||||
<dict-tag :options="dorm_application_type" :value="form.applicationType" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="学生姓名:">
|
||||
<span>{{ form.studentName }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="学号:">
|
||||
<span>{{ form.studentNo }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="学院:">
|
||||
<span>{{ form.collegeName }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="专业:">
|
||||
<span>{{ form.majorName }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="班级:">
|
||||
<span>{{ form.className }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="联系电话:">
|
||||
<span>{{ form.studentPhone }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="当前宿舍:">
|
||||
<span>{{ form.currentCampusName }} {{ form.currentBuildingName }} {{ form.currentRoomNo }} {{ form.currentBedNo }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" v-if="form.applicationType === '1'">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="目标宿舍:">
|
||||
<span>{{ form.targetCampusName }} {{ form.targetBuildingName }} {{ form.targetRoomNo }} {{ form.targetBedNo }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="申请时间:">
|
||||
<span>{{ form.applyTime }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="审批状态:">
|
||||
<dict-tag :options="student_leave_approval_status" :value="form.applicationStatus" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="申请原因:" prop="reasonDetail">
|
||||
<el-input
|
||||
v-if="isEditable"
|
||||
v-model="form.reasonDetail"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入申请原因"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
/>
|
||||
<span v-else>{{ form.reasonDetail || '无' }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="备注信息:" prop="remark">
|
||||
<el-input
|
||||
v-if="isEditable"
|
||||
v-model="form.remark"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
placeholder="请输入备注信息"
|
||||
maxlength="200"
|
||||
show-word-limit
|
||||
/>
|
||||
<span v-else>{{ form.remark || '无' }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancel">{{ isEditable ? '取消' : '关闭' }}</el-button>
|
||||
<el-button v-if="isEditable" type="primary" @click="submitForm" :loading="submitLoading">保存</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="DormApplicationDetail">
|
||||
import { getCurrentInstance, ref, toRefs, computed, type ComponentInternalInstance } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { getDormApplicationInfo, updateDormApplication, type DormApplicationVO } from '@/api/xg/studentDynamics';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { dorm_application_type, student_leave_approval_status } = toRefs(
|
||||
proxy?.useDict('dorm_application_type', 'student_leave_approval_status') || {}
|
||||
);
|
||||
|
||||
const emit = defineEmits(['refresh']);
|
||||
|
||||
// 弹窗状态
|
||||
const dialogOpen = ref(false);
|
||||
const loading = ref(false);
|
||||
const submitLoading = ref(false);
|
||||
|
||||
// 表单数据
|
||||
const form = ref<DormApplicationVO>({} as DormApplicationVO);
|
||||
|
||||
// 表单引用
|
||||
const formRef = ref();
|
||||
|
||||
// 表单校验规则
|
||||
const rules = {
|
||||
reasonDetail: [{ required: true, message: '请输入申请原因', trigger: 'blur' }]
|
||||
};
|
||||
|
||||
/**
|
||||
* 是否可编辑
|
||||
* 草稿、已撤销、已退回状态可编辑
|
||||
*/
|
||||
const isEditable = computed(() => {
|
||||
return ['draft', 'cancel', 'back'].includes(form.value.applicationStatus || '');
|
||||
});
|
||||
|
||||
/**
|
||||
* 弹窗标题
|
||||
*/
|
||||
const dialogTitle = computed(() => {
|
||||
return isEditable.value ? '修改调宿/退宿申请' : '调宿/退宿申请详情';
|
||||
});
|
||||
|
||||
/**
|
||||
* 打开弹窗
|
||||
*/
|
||||
const openDialog = (id: number) => {
|
||||
reset();
|
||||
getDetail(id);
|
||||
dialogOpen.value = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取详情数据
|
||||
*/
|
||||
const getDetail = async (id: number) => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const response = await getDormApplicationInfo(id);
|
||||
form.value = response.data;
|
||||
} catch (error) {
|
||||
console.error('获取调宿退宿申请详情失败:', error);
|
||||
ElMessage.error('获取详情失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 重置表单
|
||||
*/
|
||||
const reset = () => {
|
||||
form.value = {} as DormApplicationVO;
|
||||
formRef.value?.resetFields();
|
||||
};
|
||||
|
||||
/**
|
||||
* 提交表单
|
||||
*/
|
||||
const submitForm = async () => {
|
||||
if (!formRef.value) return;
|
||||
|
||||
await formRef.value.validate(async (valid: boolean) => {
|
||||
if (!valid) return;
|
||||
|
||||
submitLoading.value = true;
|
||||
try {
|
||||
await updateDormApplication(form.value);
|
||||
ElMessage.success('保存成功');
|
||||
dialogOpen.value = false;
|
||||
emit('refresh');
|
||||
} catch (error) {
|
||||
console.error('保存失败:', error);
|
||||
ElMessage.error('保存失败');
|
||||
} finally {
|
||||
submitLoading.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 取消操作
|
||||
*/
|
||||
const cancel = () => {
|
||||
dialogOpen.value = false;
|
||||
reset();
|
||||
};
|
||||
|
||||
// 暴露方法
|
||||
defineExpose({
|
||||
open: openDialog
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.dialog-footer {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
:deep(.el-form-item__label) {
|
||||
font-weight: 600;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
:deep(.el-form-item__content) {
|
||||
color: #303133;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,258 @@
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<!-- 搜索表单 -->
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div v-show="showSearch" style="margin-bottom: 10px">
|
||||
<el-card shadow="hover">
|
||||
<el-form ref="queryFormRef" :model="queryParams" label-width="100px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6">
|
||||
<el-form-item label="学生姓名" prop="studentName">
|
||||
<el-input v-model="queryParams.studentName" placeholder="请输入学生姓名" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="学号" prop="studentNo">
|
||||
<el-input v-model="queryParams.studentNo" placeholder="请输入学号" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="学院名称" prop="collegeName">
|
||||
<el-input v-model="queryParams.collegeName" placeholder="请输入学院名称" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="专业名称" prop="majorName">
|
||||
<el-input v-model="queryParams.majorName" placeholder="请输入专业名称" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6">
|
||||
<el-form-item label="班级名称" prop="className">
|
||||
<el-input v-model="queryParams.className" placeholder="请输入班级名称" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="申请类型" prop="applicationType">
|
||||
<el-select v-model="queryParams.applicationType" placeholder="请选择申请类型" clearable style="width: 100%">
|
||||
<el-option v-for="dict in dorm_application_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="申请时间" prop="applyTime">
|
||||
<el-date-picker
|
||||
clearable
|
||||
v-model="queryParams.applyTime"
|
||||
type="date"
|
||||
style="width: 100%"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="请选择申请时间"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="审批状态" prop="applicationStatus">
|
||||
<el-select v-model="queryParams.applicationStatus" placeholder="请选择审批状态" clearable style="width: 100%">
|
||||
<el-option v-for="dict in student_leave_approval_status" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24" class="search-btn-container">
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<span class="card-title">调宿/退宿申请列表</span>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
|
||||
<el-table-column label="学生姓名" align="center" prop="studentName" />
|
||||
<el-table-column label="学号" align="center" prop="studentNo" />
|
||||
<el-table-column label="学院" align="center" prop="collegeName" show-overflow-tooltip />
|
||||
<el-table-column label="专业" align="center" prop="majorName" show-overflow-tooltip />
|
||||
<el-table-column label="班级" align="center" prop="className" show-overflow-tooltip />
|
||||
<el-table-column label="申请类型" align="center">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="dorm_application_type" :value="scope.row.applicationType" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="当前宿舍" align="center" show-overflow-tooltip>
|
||||
<template #default="scope"> {{ scope.row.currentBuildingName }}{{ scope.row.currentRoomNo }}{{ scope.row.currentBedNo }} </template>
|
||||
</el-table-column>
|
||||
<el-table-column label="目标宿舍" align="center" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.applicationType === '1'">
|
||||
{{ scope.row.targetBuildingName }}{{ scope.row.targetRoomNo }}{{ scope.row.targetBedNo }}
|
||||
</span>
|
||||
<span v-else>—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="审批状态" align="center">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="student_leave_approval_status" :value="scope.row.applicationStatus" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="申请时间" align="center" prop="applyTime" width="180" />
|
||||
<el-table-column label="操作" align="center" width="150" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-tooltip content="查看" placement="top">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
icon="View"
|
||||
@click="handleView(scope.row)"
|
||||
v-hasPermi="['studentDynamics:dormApplication:query']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="DormApplicationTab">
|
||||
import { getCurrentInstance, ref, onMounted, toRefs, type ComponentInternalInstance } from 'vue';
|
||||
import { listDormApplication, type DormApplicationQuery } from '@/api/xg/studentDynamics';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { dorm_application_type, student_leave_approval_status } = toRefs(
|
||||
proxy?.useDict('dorm_application_type', 'student_leave_approval_status') || {}
|
||||
);
|
||||
|
||||
// 数据状态
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const dataList = ref([]);
|
||||
const total = ref(0);
|
||||
const ids = ref<Array<string | number>>([]);
|
||||
const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
|
||||
// 查询参数
|
||||
const queryParams = ref<DormApplicationQuery & any>({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
studentName: undefined,
|
||||
studentNo: undefined,
|
||||
collegeName: undefined,
|
||||
majorName: undefined,
|
||||
className: undefined,
|
||||
applicationType: undefined,
|
||||
applicationStatus: undefined,
|
||||
applyTime: undefined
|
||||
});
|
||||
|
||||
// 表单引用
|
||||
const queryFormRef = ref();
|
||||
|
||||
/**
|
||||
* 查询列表数据
|
||||
*/
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const response = await listDormApplication(queryParams.value);
|
||||
dataList.value = response.rows;
|
||||
total.value = response.total;
|
||||
} catch (error) {
|
||||
console.error('获取调宿退宿申请列表失败:', error);
|
||||
proxy?.$modal.msgError('获取数据失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 搜索按钮操作
|
||||
*/
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
};
|
||||
|
||||
/**
|
||||
* 重置按钮操作
|
||||
*/
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
/**
|
||||
* 多选框选中数据
|
||||
*/
|
||||
const handleSelectionChange = (selection: any) => {
|
||||
ids.value = selection.map((item: any) => item.id);
|
||||
single.value = selection.length !== 1;
|
||||
multiple.value = !selection.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* 查看详情
|
||||
*/
|
||||
const handleView = (row: any) => {
|
||||
// 跳转到调宿退宿申请详情页面
|
||||
proxy.$router.push({
|
||||
path: `/xg/xsjcxx/xssssq/dialog`,
|
||||
query: {
|
||||
id: row.id,
|
||||
type: 'update'
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 页面初始化
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 页面容器样式 */
|
||||
.page-container {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.mb8 {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
/* 搜索按钮容器样式 */
|
||||
.search-btn-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.search-btn-container .el-form-item {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,474 @@
|
||||
<template>
|
||||
<el-dialog title="假期留宿详情" v-model="dialogOpen" width="1000px" append-to-body>
|
||||
<el-form :model="form" label-width="120px" v-loading="loading">
|
||||
<el-row :gutter="20">
|
||||
<!-- 左列:学生基本信息 -->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="学生姓名">
|
||||
<el-input v-model="form.studentName" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="学号">
|
||||
<el-input v-model="form.studentNo" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="学生联系电话">
|
||||
<el-input v-model="form.studentPhone" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="学院名称">
|
||||
<el-input v-model="form.collegeName" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="专业名称">
|
||||
<el-input v-model="form.majorName" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="班级名称">
|
||||
<el-input v-model="form.className" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<!-- 右列:宿舍信息 -->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="校区名称">
|
||||
<el-input v-model="form.campusName" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="宿舍区名称">
|
||||
<el-input v-model="form.areaName" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="宿舍楼名称">
|
||||
<el-input v-model="form.buildingName" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="房间名称">
|
||||
<el-input v-model="form.roomName" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="床位名称">
|
||||
<el-input v-model="form.bedName" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 假期申请信息 -->
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="假期类型">
|
||||
<el-input v-model="holidayTypeLabel" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="留宿原因类型">
|
||||
<el-input v-model="stayReasonTypeLabel" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="留宿开始日期">
|
||||
<el-input v-model="form.applyStartDate" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="留宿结束日期">
|
||||
<el-input v-model="form.applyEndDate" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 联系信息 -->
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="紧急联系人姓名">
|
||||
<el-input v-model="form.emergencyContact" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="紧急联系人电话">
|
||||
<el-input v-model="form.emergencyPhone" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="家长同意">
|
||||
<el-input v-model="parentConsentLabel" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 留宿原因 -->
|
||||
<el-form-item label="留宿原因">
|
||||
<el-input v-model="form.stayReason" type="textarea" :rows="3" disabled />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 附件显示 -->
|
||||
<el-form-item label="附件">
|
||||
<div class="attachment-view-container" v-if="attachmentList.length > 0">
|
||||
<div class="attachment-grid">
|
||||
<div v-for="file in attachmentList" :key="file.ossId" class="attachment-item">
|
||||
<!-- 缩略图区域 -->
|
||||
<div class="attachment-thumb">
|
||||
<image-preview v-if="isImageFile(file)" :src="file.ossId" class="thumb-image" :isOssId="true" />
|
||||
<div v-else class="file-placeholder">
|
||||
<el-icon><Document /></el-icon>
|
||||
<span class="file-ext">{{ getFileExt(file.name) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 文件名称 -->
|
||||
<div class="attachment-name" :title="file.name">
|
||||
{{ getShortFileName(file.name) }}
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="attachment-actions">
|
||||
<el-button type="success" size="small" @click="handleDownload(file)" title="下载">
|
||||
<el-icon><Download /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="no-attachment">
|
||||
<el-empty description="暂无附件" :image-size="60" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 备注信息 -->
|
||||
<el-form-item label="备注信息">
|
||||
<el-input v-model="form.remark" type="textarea" :rows="3" disabled />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="dialogOpen = false">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="HolidayStayDetail">
|
||||
import { ref, computed, toRefs, getCurrentInstance, type ComponentInternalInstance } from 'vue';
|
||||
import ElMessage from 'element-plus/es/components/message/index';
|
||||
import ElLoading from 'element-plus/es/components/loading/index';
|
||||
import { Document, Download } from '@element-plus/icons-vue';
|
||||
import { getHolidayStay, type HolidayStayVO } from '@/api/xg/studentDynamics';
|
||||
import ImagePreview from '@/components/ImagePreview/index.vue';
|
||||
import request from '@/utils/request';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
// 字典数据
|
||||
const { xg_holiday_type, xg_stay_reason_type, sys_yesno } = toRefs<any>(proxy?.useDict('xg_holiday_type', 'xg_stay_reason_type', 'sys_yesno'));
|
||||
|
||||
// 对话框状态
|
||||
const dialogOpen = ref(false);
|
||||
const loading = ref(false);
|
||||
|
||||
// 表单数据
|
||||
const form = ref<Partial<HolidayStayVO>>({
|
||||
id: undefined,
|
||||
studentId: undefined,
|
||||
studentName: '',
|
||||
studentNo: '',
|
||||
classId: undefined,
|
||||
className: '',
|
||||
majorId: undefined,
|
||||
majorName: '',
|
||||
collegeId: undefined,
|
||||
collegeName: '',
|
||||
campusId: undefined,
|
||||
campusName: '',
|
||||
areaId: undefined,
|
||||
areaName: '',
|
||||
buildingId: undefined,
|
||||
buildingName: '',
|
||||
roomId: undefined,
|
||||
roomName: '',
|
||||
bedId: undefined,
|
||||
bedName: '',
|
||||
holidayType: '',
|
||||
applyStartDate: '',
|
||||
applyEndDate: '',
|
||||
stayReason: '',
|
||||
stayReasonType: '',
|
||||
studentPhone: '',
|
||||
emergencyContact: '',
|
||||
emergencyPhone: '',
|
||||
parentConsent: '',
|
||||
attachmentOssIds: '',
|
||||
remark: ''
|
||||
});
|
||||
|
||||
// 附件列表
|
||||
const attachmentList = ref<any[]>([]);
|
||||
|
||||
// 字典标签计算属性
|
||||
const holidayTypeLabel = computed(() => {
|
||||
if (!form.value.holidayType || !xg_holiday_type.value) return '';
|
||||
const dict = xg_holiday_type.value.find((item: any) => item.value === form.value.holidayType);
|
||||
return dict ? dict.label : form.value.holidayType;
|
||||
});
|
||||
|
||||
const stayReasonTypeLabel = computed(() => {
|
||||
if (!form.value.stayReasonType || !xg_stay_reason_type.value) return '';
|
||||
const dict = xg_stay_reason_type.value.find((item: any) => item.value === form.value.stayReasonType);
|
||||
return dict ? dict.label : form.value.stayReasonType;
|
||||
});
|
||||
|
||||
const parentConsentLabel = computed(() => {
|
||||
if (!form.value.parentConsent || !sys_yesno.value) return '';
|
||||
const dict = sys_yesno.value.find((item: any) => item.value === form.value.parentConsent);
|
||||
return dict ? dict.label : form.value.parentConsent;
|
||||
});
|
||||
|
||||
/**
|
||||
* 打开详情弹窗
|
||||
*/
|
||||
const open = async (id: string | number) => {
|
||||
loading.value = true;
|
||||
dialogOpen.value = true;
|
||||
|
||||
try {
|
||||
// 获取详情数据
|
||||
const response = await getHolidayStay(id);
|
||||
form.value = response.data;
|
||||
|
||||
// 处理附件数据
|
||||
await handleAttachmentData();
|
||||
} catch (error) {
|
||||
console.error('获取假期留宿详情失败:', error);
|
||||
ElMessage.error('获取详情失败');
|
||||
dialogOpen.value = false;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理附件数据
|
||||
*/
|
||||
const handleAttachmentData = async () => {
|
||||
try {
|
||||
if (form.value.attachmentOssIds && form.value.attachmentOssIds.toString().trim()) {
|
||||
// 将逗号分隔的字符串转换为数组
|
||||
const ossIdsArray = form.value.attachmentOssIds
|
||||
.toString()
|
||||
.split(',')
|
||||
.map((id) => id.trim())
|
||||
.filter((id) => id);
|
||||
|
||||
// 调用接口获取附件信息
|
||||
const response = await request({
|
||||
url: `/resource/oss/listByIds/${ossIdsArray.join(',')}`,
|
||||
method: 'get'
|
||||
});
|
||||
|
||||
if (response.code === 200 && response.data) {
|
||||
// 将附件信息转换为显示需要的格式
|
||||
attachmentList.value = response.data.map((item: any) => ({
|
||||
ossId: item.ossId,
|
||||
name: item.originalName || '附件',
|
||||
url: item.url,
|
||||
type: item.contentType || ''
|
||||
}));
|
||||
} else {
|
||||
attachmentList.value = [];
|
||||
}
|
||||
} else {
|
||||
attachmentList.value = [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('处理附件数据失败:', error);
|
||||
attachmentList.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 判断是否为图片文件
|
||||
*/
|
||||
const isImageFile = (file: any) => {
|
||||
const imageTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/bmp', 'image/webp'];
|
||||
return imageTypes.includes(file.type) || /\.(jpg|jpeg|png|gif|bmp|webp)$/i.test(file.name);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取文件扩展名
|
||||
*/
|
||||
const getFileExt = (fileName: string) => {
|
||||
const ext = fileName.split('.').pop()?.toUpperCase();
|
||||
return ext || 'FILE';
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取缩短的文件名
|
||||
*/
|
||||
const getShortFileName = (fileName: string) => {
|
||||
if (!fileName) return '';
|
||||
|
||||
const lastDotIndex = fileName.lastIndexOf('.');
|
||||
if (lastDotIndex === -1) {
|
||||
return fileName.length > 12 ? fileName.substring(0, 12) + '...' : fileName;
|
||||
}
|
||||
|
||||
const name = fileName.substring(0, lastDotIndex);
|
||||
const ext = fileName.substring(lastDotIndex);
|
||||
|
||||
if (name.length <= 8) {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
return name.substring(0, 8) + '...' + ext;
|
||||
};
|
||||
|
||||
/**
|
||||
* 下载附件
|
||||
*/
|
||||
const handleDownload = async (file: any) => {
|
||||
try {
|
||||
const loading = ElLoading.service({
|
||||
text: '正在下载文件...',
|
||||
target: document.body
|
||||
});
|
||||
|
||||
const response = await request({
|
||||
url: '/resource/oss/download/' + file.ossId,
|
||||
method: 'get',
|
||||
responseType: 'blob',
|
||||
timeout: 300000
|
||||
});
|
||||
|
||||
// 验证响应数据
|
||||
if (!response) {
|
||||
throw new Error('响应数据为空');
|
||||
}
|
||||
|
||||
// 检查response的结构
|
||||
let blobData: Blob;
|
||||
if (response instanceof Blob) {
|
||||
blobData = response;
|
||||
} else if (response.data instanceof Blob) {
|
||||
blobData = response.data;
|
||||
} else {
|
||||
throw new Error('无效的响应数据格式');
|
||||
}
|
||||
|
||||
const url = window.URL.createObjectURL(blobData);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = file.name;
|
||||
link.style.display = 'none';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(url);
|
||||
loading?.close();
|
||||
ElMessage.success('下载成功');
|
||||
} catch (error) {
|
||||
console.error('下载文件失败:', error);
|
||||
ElMessage.error('下载文件失败,请稍后重试');
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({ open });
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 附件查看容器样式 */
|
||||
.attachment-view-container {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 6px;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.attachment-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.attachment-item {
|
||||
background: #fff;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.attachment-item:hover {
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.attachment-thumb {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 110px;
|
||||
background: #f5f5f5;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.thumb-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.file-placeholder {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.file-placeholder .el-icon {
|
||||
font-size: 28px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.file-ext {
|
||||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.attachment-name {
|
||||
padding: 6px 8px;
|
||||
font-size: 11px;
|
||||
color: #303133;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
background: #fafafa;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
line-height: 1.2;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.attachment-actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 6px 8px;
|
||||
background: #fafafa;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
.attachment-actions .el-button {
|
||||
padding: 4px 12px;
|
||||
font-size: 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.no-attachment {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
color: #909399;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,263 @@
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<!-- 搜索表单 -->
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div v-show="showSearch" class="mb-[10px]">
|
||||
<el-card shadow="hover">
|
||||
<el-form ref="queryFormRef" :model="queryParams" label-width="100px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6">
|
||||
<el-form-item label="学生姓名" prop="studentName">
|
||||
<el-input v-model="queryParams.studentName" placeholder="请输入学生姓名" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="学号" prop="studentNo">
|
||||
<el-input v-model="queryParams.studentNo" placeholder="请输入学号" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="学院名称" prop="collegeName">
|
||||
<el-input v-model="queryParams.collegeName" placeholder="请输入学院名称" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="专业名称" prop="majorName">
|
||||
<el-input v-model="queryParams.majorName" placeholder="请输入专业名称" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6">
|
||||
<el-form-item label="班级名称" prop="className">
|
||||
<el-input v-model="queryParams.className" placeholder="请输入班级名称" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="假期类型" prop="holidayType">
|
||||
<el-select v-model="queryParams.holidayType" placeholder="请选择假期类型" clearable style="width: 100%">
|
||||
<el-option v-for="dict in xg_holiday_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="开始日期" prop="applyStartDate">
|
||||
<el-date-picker
|
||||
clearable
|
||||
v-model="queryParams.applyStartDate"
|
||||
type="date"
|
||||
style="width: 100%"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="请选择开始日期"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="结束日期" prop="applyEndDate">
|
||||
<el-date-picker
|
||||
clearable
|
||||
v-model="queryParams.applyEndDate"
|
||||
type="date"
|
||||
style="width: 100%"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="请选择结束日期"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24" class="search-btn-container">
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<span class="card-title">假期留宿信息列表</span>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
|
||||
<el-table-column label="学生姓名" align="center" prop="studentName" />
|
||||
<el-table-column label="学号" align="center" prop="studentNo" />
|
||||
<el-table-column label="学院" align="center" prop="collegeName" show-overflow-tooltip />
|
||||
<el-table-column label="专业" align="center" prop="majorName" show-overflow-tooltip />
|
||||
<el-table-column label="班级" align="center" prop="className" show-overflow-tooltip />
|
||||
<el-table-column label="宿舍信息" align="center" show-overflow-tooltip>
|
||||
<template #default="scope"> {{ scope.row.buildingName }}{{ scope.row.roomName }} </template>
|
||||
</el-table-column>
|
||||
<el-table-column label="假期类型" align="center" prop="holidayType">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="xg_holiday_type" :value="scope.row.holidayType" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="留宿时间" align="center" show-overflow-tooltip>
|
||||
<template #default="scope"> {{ scope.row.applyStartDate }} 至 {{ scope.row.applyEndDate }} </template>
|
||||
</el-table-column>
|
||||
<el-table-column label="留宿原因类型" align="center" prop="stayReasonType">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="xg_stay_reason_type" :value="scope.row.stayReasonType" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="联系电话" align="center" prop="studentPhone" />
|
||||
<el-table-column label="紧急联系人" align="center" prop="emergencyContact" />
|
||||
<el-table-column label="操作" align="center" width="150" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-tooltip content="查看" placement="top">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
icon="View"
|
||||
@click="handleView(scope.row)"
|
||||
v-hasPermi="['studentDynamics:holidayStay:query']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||
</el-card>
|
||||
|
||||
<!-- 查看详情弹窗 -->
|
||||
<HolidayStayDetail ref="detailRef" @refresh="getList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="HolidayStayTab">
|
||||
import { getCurrentInstance, ref, onMounted, toRefs } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { listHolidayStay, type HolidayStayQuery } from '@/api/xg/studentDynamics';
|
||||
import HolidayStayDetail from './HolidayStayDetail.vue';
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
|
||||
// 字典数据
|
||||
const { xg_holiday_type, xg_stay_reason_type } = toRefs(proxy?.useDict('xg_holiday_type', 'xg_stay_reason_type') || {});
|
||||
|
||||
// 数据状态
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const dataList = ref([]);
|
||||
const total = ref(0);
|
||||
const ids = ref<Array<string | number>>([]);
|
||||
const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
|
||||
// 查询参数
|
||||
const queryParams = ref<HolidayStayQuery & any>({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
studentName: undefined,
|
||||
studentNo: undefined,
|
||||
collegeName: undefined,
|
||||
majorName: undefined,
|
||||
className: undefined,
|
||||
holidayType: undefined,
|
||||
applyStartDate: undefined,
|
||||
applyEndDate: undefined,
|
||||
status: undefined
|
||||
});
|
||||
|
||||
// 表单引用
|
||||
const queryFormRef = ref();
|
||||
const detailRef = ref();
|
||||
|
||||
/**
|
||||
* 查询列表数据
|
||||
*/
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const response = await listHolidayStay(queryParams.value);
|
||||
dataList.value = response.rows;
|
||||
total.value = response.total;
|
||||
} catch (error) {
|
||||
console.error('获取假期留宿信息列表失败:', error);
|
||||
ElMessage.error('获取数据失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 搜索按钮操作
|
||||
*/
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
};
|
||||
|
||||
/**
|
||||
* 重置按钮操作
|
||||
*/
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
/**
|
||||
* 多选框选中数据
|
||||
*/
|
||||
const handleSelectionChange = (selection: any) => {
|
||||
ids.value = selection.map((item: any) => item.id);
|
||||
single.value = selection.length !== 1;
|
||||
multiple.value = !selection.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* 查看详情
|
||||
*/
|
||||
const handleView = (row: any) => {
|
||||
detailRef.value?.open(row.id);
|
||||
};
|
||||
|
||||
// 页面初始化
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 页面容器样式 */
|
||||
.page-container {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.mb-[10px] {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.mb8 {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
/* 搜索按钮容器样式 */
|
||||
.search-btn-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.search-btn-container .el-form-item {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,21 @@
|
||||
<template>
|
||||
<el-dialog title="学生请假详情" v-model="dialogOpen" width="800px" append-to-body>
|
||||
<div>学生请假详情组件待实现</div>
|
||||
<template #footer>
|
||||
<el-button @click="dialogOpen = false">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="StudentLeaveDetail">
|
||||
import { ref } from 'vue';
|
||||
|
||||
const dialogOpen = ref(false);
|
||||
|
||||
const open = (id: number) => {
|
||||
console.log('打开学生请假详情,ID:', id);
|
||||
dialogOpen.value = true;
|
||||
};
|
||||
|
||||
defineExpose({ open });
|
||||
</script>
|
||||
@@ -0,0 +1,271 @@
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<!-- 搜索表单 -->
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div v-show="showSearch" style="margin-bottom: 10px">
|
||||
<el-card shadow="hover">
|
||||
<el-form ref="queryFormRef" :model="queryParams" label-width="100px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6">
|
||||
<el-form-item label="学生姓名" prop="studentName">
|
||||
<el-input v-model="queryParams.studentName" placeholder="请输入学生姓名" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="学号" prop="studentNo">
|
||||
<el-input v-model="queryParams.studentNo" placeholder="请输入学号" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="学院名称" prop="collegeName">
|
||||
<el-input v-model="queryParams.collegeName" placeholder="请输入学院名称" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="专业名称" prop="majorName">
|
||||
<el-input v-model="queryParams.majorName" placeholder="请输入专业名称" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6">
|
||||
<el-form-item label="班级名称" prop="className">
|
||||
<el-input v-model="queryParams.className" placeholder="请输入班级名称" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="请假类型" prop="leaveTypeName">
|
||||
<el-input v-model="queryParams.leaveTypeName" placeholder="请输入请假类型名称" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="开始时间" prop="startTime">
|
||||
<el-date-picker
|
||||
clearable
|
||||
v-model="queryParams.startTime"
|
||||
type="date"
|
||||
style="width: 100%"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="请选择开始时间"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="结束时间" prop="endTime">
|
||||
<el-date-picker
|
||||
clearable
|
||||
v-model="queryParams.endTime"
|
||||
type="date"
|
||||
style="width: 100%"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="请选择结束时间"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6">
|
||||
<el-form-item label="审批状态" prop="approvalStatus">
|
||||
<el-select v-model="queryParams.approvalStatus" placeholder="请选择审批状态" clearable style="width: 100%">
|
||||
<el-option v-for="dict in student_leave_approval_status" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24" class="search-btn-container">
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<span class="card-title">学生请假信息列表</span>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
|
||||
<el-table-column label="学生姓名" align="center" prop="studentName" />
|
||||
<el-table-column label="学号" align="center" prop="studentNo" />
|
||||
<el-table-column label="学院" align="center" prop="collegeName" show-overflow-tooltip />
|
||||
<el-table-column label="专业" align="center" prop="majorName" show-overflow-tooltip />
|
||||
<el-table-column label="班级" align="center" prop="className" show-overflow-tooltip />
|
||||
<el-table-column label="请假类型" align="center" prop="leaveTypeName" />
|
||||
<el-table-column label="请假时间" align="center" show-overflow-tooltip>
|
||||
<template #default="scope"> {{ scope.row.startTime }} 至 {{ scope.row.endTime }} </template>
|
||||
</el-table-column>
|
||||
<el-table-column label="请假时长" align="center">
|
||||
<template #default="scope"> {{ scope.row.leaveDuration }}天 </template>
|
||||
</el-table-column>
|
||||
<el-table-column label="是否离校" align="center">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="sys_yesno" :value="scope.row.isLeaveSchool" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="审批状态" align="center">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="student_leave_approval_status" :value="scope.row.approvalStatus" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="销假状态" align="center">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="xg_xsqj_cancel_status" :value="scope.row.cancelStatus" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="150" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-tooltip content="查看" placement="top">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
icon="View"
|
||||
@click="handleView(scope.row)"
|
||||
v-hasPermi="['studentDynamics:studentLeave:query']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="StudentLeaveTab">
|
||||
import { getCurrentInstance, ref, onMounted, toRefs } from 'vue';
|
||||
import { listStudentLeave, type StudentLeaveQuery } from '@/api/xg/studentDynamics';
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const { sys_yesno, student_leave_approval_status, xg_xsqj_cancel_status } = toRefs(
|
||||
proxy?.useDict('sys_yesno', 'student_leave_approval_status', 'xg_xsqj_cancel_status') || {}
|
||||
);
|
||||
|
||||
// 数据状态
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const dataList = ref([]);
|
||||
const total = ref(0);
|
||||
const ids = ref<Array<string | number>>([]);
|
||||
const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
|
||||
// 查询参数
|
||||
const queryParams = ref<StudentLeaveQuery & any>({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
studentName: undefined,
|
||||
studentNo: undefined,
|
||||
collegeName: undefined,
|
||||
majorName: undefined,
|
||||
className: undefined,
|
||||
leaveTypeName: undefined,
|
||||
approvalStatus: undefined,
|
||||
startTime: undefined,
|
||||
endTime: undefined
|
||||
});
|
||||
|
||||
// 表单引用
|
||||
const queryFormRef = ref();
|
||||
|
||||
/**
|
||||
* 查询列表数据
|
||||
*/
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const response = await listStudentLeave(queryParams.value);
|
||||
dataList.value = response.rows;
|
||||
total.value = response.total;
|
||||
} catch (error) {
|
||||
console.error('获取学生请假信息列表失败:', error);
|
||||
proxy?.$modal.msgError('获取数据失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 搜索按钮操作
|
||||
*/
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
};
|
||||
|
||||
/**
|
||||
* 重置按钮操作
|
||||
*/
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
/**
|
||||
* 多选框选中数据
|
||||
*/
|
||||
const handleSelectionChange = (selection: any) => {
|
||||
ids.value = selection.map((item: any) => item.id);
|
||||
single.value = selection.length !== 1;
|
||||
multiple.value = !selection.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* 查看详情
|
||||
*/
|
||||
const handleView = (row: any) => {
|
||||
// 跳转到学生请假详情页面
|
||||
proxy.$router.push({
|
||||
path: `/xg/xsjcxx/xsqj/leaveEdit/index`,
|
||||
query: {
|
||||
id: row.id,
|
||||
type: 'update'
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 页面初始化
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 页面容器样式 */
|
||||
.page-container {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.mb8 {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
/* 搜索按钮容器样式 */
|
||||
.search-btn-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.search-btn-container .el-form-item {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<!-- Tab页组件 -->
|
||||
<el-tabs v-model="activeTab" @tab-click="handleTabClick" class="mb-4">
|
||||
<!-- 调宿/退宿信息Tab页 -->
|
||||
<el-tab-pane label="调宿/退宿信息" name="dormApplication">
|
||||
<DormApplicationTab v-if="activeTab === 'dormApplication'" ref="dormApplicationTabRef" />
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 假期留宿信息Tab页 -->
|
||||
<el-tab-pane label="假期留宿信息" name="holidayStay">
|
||||
<HolidayStayTab v-if="activeTab === 'holidayStay'" ref="holidayStayTabRef" />
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 请假信息Tab页 -->
|
||||
<el-tab-pane label="请假信息" name="studentLeave">
|
||||
<StudentLeaveTab v-if="activeTab === 'studentLeave'" ref="studentLeaveTabRef" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="StudentDynamics">
|
||||
import { ref, onMounted } from 'vue';
|
||||
import DormApplicationTab from './components/DormApplicationTab.vue';
|
||||
import HolidayStayTab from './components/HolidayStayTab.vue';
|
||||
import StudentLeaveTab from './components/StudentLeaveTab.vue';
|
||||
|
||||
// Tab页状态
|
||||
const activeTab = ref('dormApplication');
|
||||
|
||||
// 子组件引用
|
||||
const dormApplicationTabRef = ref();
|
||||
const holidayStayTabRef = ref();
|
||||
const studentLeaveTabRef = ref();
|
||||
|
||||
/**
|
||||
* Tab页切换处理
|
||||
*/
|
||||
const handleTabClick = (tab: any) => {
|
||||
console.log('切换到Tab页:', tab.name);
|
||||
// 可以在这里添加Tab切换的逻辑
|
||||
};
|
||||
|
||||
/**
|
||||
* 页面初始化
|
||||
*/
|
||||
onMounted(() => {
|
||||
console.log('学生动向信息管理页面已加载');
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.p-2 {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.mb-4 {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
/* Tab页样式优化 */
|
||||
:deep(.el-tabs__header) {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__item) {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__item.is-active) {
|
||||
/* color: #409eff; */
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__content) {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user