提交
This commit is contained in:
1 parent
aec39f984b
commit
e772cd1435
55 files changed
+4466
-652
No files matched your search
+37
-40
@@ -44,7 +44,7 @@ public class CwApprovalRecordController extends BaseController {
|
||||
/**
|
||||
* 查询审批记录列表
|
||||
*/
|
||||
//@SaCheckPermission("cw:approval:list")
|
||||
// @SaCheckPermission("cw:approval:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<CwApprovalRecordVo> list(CwApprovalRecordBo bo, PageQuery pageQuery) {
|
||||
return approvalRecordService.queryPageList(bo, pageQuery);
|
||||
@@ -53,7 +53,7 @@ public class CwApprovalRecordController extends BaseController {
|
||||
/**
|
||||
* 导出审批记录列表
|
||||
*/
|
||||
//@SaCheckPermission("cw:approval:export")
|
||||
// @SaCheckPermission("cw:approval:export")
|
||||
@Log(title = "审批记录", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(CwApprovalRecordBo bo, HttpServletResponse response) {
|
||||
@@ -64,17 +64,16 @@ public class CwApprovalRecordController extends BaseController {
|
||||
/**
|
||||
* 获取审批记录详细信息
|
||||
*/
|
||||
//@SaCheckPermission("cw:approval:query")
|
||||
// @SaCheckPermission("cw:approval:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<CwApprovalRecordVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
public R<CwApprovalRecordVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
|
||||
return R.ok(approvalRecordService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据申报ID查询审批记录列表
|
||||
*/
|
||||
//@SaCheckPermission("cw:approval:query")
|
||||
// @SaCheckPermission("cw:approval:query")
|
||||
@GetMapping("/byApplication/{applicationId}")
|
||||
public R<List<CwApprovalRecordVo>> getByApplicationId(@PathVariable Long applicationId) {
|
||||
List<CwApprovalRecordVo> list = approvalRecordService.queryByApplicationId(applicationId);
|
||||
@@ -84,7 +83,7 @@ public class CwApprovalRecordController extends BaseController {
|
||||
/**
|
||||
* 查询当前用户待审批记录列表
|
||||
*/
|
||||
//@SaCheckPermission("cw:approval:list")
|
||||
// @SaCheckPermission("cw:approval:list")
|
||||
@GetMapping("/pending")
|
||||
public R<List<CwApprovalRecordVo>> getPendingList() {
|
||||
List<CwApprovalRecordVo> list = approvalRecordService.queryPendingByCurrentUser();
|
||||
@@ -94,7 +93,7 @@ public class CwApprovalRecordController extends BaseController {
|
||||
/**
|
||||
* 查询当前用户已审批记录列表
|
||||
*/
|
||||
//@SaCheckPermission("cw:approval:list")
|
||||
// @SaCheckPermission("cw:approval:list")
|
||||
@GetMapping("/my")
|
||||
public R<List<CwApprovalRecordVo>> getMyApprovedList() {
|
||||
List<CwApprovalRecordVo> list = approvalRecordService.queryApprovedByCurrentUser();
|
||||
@@ -104,7 +103,7 @@ public class CwApprovalRecordController extends BaseController {
|
||||
/**
|
||||
* 查询部门待审批申报列表
|
||||
*/
|
||||
//@SaCheckPermission("cw:approval:dept")
|
||||
// @SaCheckPermission("cw:approval:dept")
|
||||
@GetMapping("/dept/pending")
|
||||
public R<List<CwApprovalRecordVo>> getDeptPendingList() {
|
||||
List<CwApprovalRecordVo> list = approvalRecordService.queryDeptPendingApprovals();
|
||||
@@ -114,7 +113,7 @@ public class CwApprovalRecordController extends BaseController {
|
||||
/**
|
||||
* 查询财务待审批申报列表
|
||||
*/
|
||||
//@SaCheckPermission("cw:approval:finance")
|
||||
// @SaCheckPermission("cw:approval:finance")
|
||||
@GetMapping("/finance/pending")
|
||||
public R<List<CwApprovalRecordVo>> getFinancePendingList() {
|
||||
List<CwApprovalRecordVo> list = approvalRecordService.queryFinancePendingApprovals();
|
||||
@@ -124,7 +123,7 @@ public class CwApprovalRecordController extends BaseController {
|
||||
/**
|
||||
* 查询财务已审批申报列表
|
||||
*/
|
||||
//@SaCheckPermission("cw:approval:finance")
|
||||
// @SaCheckPermission("cw:approval:finance")
|
||||
@GetMapping("/finance/approved")
|
||||
public R<List<CwApprovalRecordVo>> getFinanceApprovedList() {
|
||||
List<CwApprovalRecordVo> list = approvalRecordService.queryFinanceApprovedRecords();
|
||||
@@ -134,9 +133,8 @@ public class CwApprovalRecordController extends BaseController {
|
||||
/**
|
||||
* 查询学院领导待审批申报列表
|
||||
*/
|
||||
//@SaCheckPermission("cw:approval:leader")
|
||||
@GetMapping("/leader/pending")</xai:function_call name="search_replace">
|
||||
<parameter name="file_path">backend/ruoyi-modules/ruoyi-cw/src/main/java/org/dromara/cw/controller/CwApprovalRecordController.java
|
||||
// @SaCheckPermission("cw:approval:leader")
|
||||
@GetMapping("/leader/pending")
|
||||
public R<List<CwApprovalRecordVo>> getLeaderPendingList() {
|
||||
List<CwApprovalRecordVo> list = approvalRecordService.queryLeaderPendingApprovals();
|
||||
return R.ok(list);
|
||||
@@ -145,7 +143,7 @@ public class CwApprovalRecordController extends BaseController {
|
||||
/**
|
||||
* 查询学院领导已审批申报列表
|
||||
*/
|
||||
//@SaCheckPermission("cw:approval:leader")
|
||||
// @SaCheckPermission("cw:approval:leader")
|
||||
@GetMapping("/leader/approved")
|
||||
public R<List<CwApprovalRecordVo>> getLeaderApprovedList() {
|
||||
List<CwApprovalRecordVo> list = approvalRecordService.queryLeaderApprovedApprovals();
|
||||
@@ -155,7 +153,7 @@ public class CwApprovalRecordController extends BaseController {
|
||||
/**
|
||||
* 查询所有待审批申报列表(超级管理员专用)
|
||||
*/
|
||||
//@SaCheckPermission("cw:approval:list")
|
||||
// @SaCheckPermission("cw:approval:list")
|
||||
@GetMapping("/all/pending")
|
||||
public R<List<CwApprovalRecordVo>> getAllPendingList() {
|
||||
List<CwApprovalRecordVo> list = approvalRecordService.queryAllPendingApprovals();
|
||||
@@ -165,7 +163,7 @@ public class CwApprovalRecordController extends BaseController {
|
||||
/**
|
||||
* 新增审批记录
|
||||
*/
|
||||
//@SaCheckPermission("cw:approval:add")
|
||||
// @SaCheckPermission("cw:approval:add")
|
||||
@Log(title = "审批记录", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
@@ -176,7 +174,7 @@ public class CwApprovalRecordController extends BaseController {
|
||||
/**
|
||||
* 修改审批记录
|
||||
*/
|
||||
//@SaCheckPermission("cw:approval:edit")
|
||||
// @SaCheckPermission("cw:approval:edit")
|
||||
@Log(title = "审批记录", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
@@ -187,18 +185,17 @@ public class CwApprovalRecordController extends BaseController {
|
||||
/**
|
||||
* 删除审批记录
|
||||
*/
|
||||
//@SaCheckPermission("cw:approval:remove")
|
||||
// @SaCheckPermission("cw:approval:remove")
|
||||
@Log(title = "审批记录", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
|
||||
return toAjax(approvalRecordService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建审批流程
|
||||
*/
|
||||
//@SaCheckPermission("cw:approval:create")
|
||||
// @SaCheckPermission("cw:approval:create")
|
||||
@Log(title = "创建审批流程", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/create/{applicationId}")
|
||||
public R<Void> createProcess(@PathVariable Long applicationId, @RequestParam String applicationNo) {
|
||||
@@ -216,34 +213,34 @@ public class CwApprovalRecordController extends BaseController {
|
||||
/**
|
||||
* 审批操作
|
||||
*/
|
||||
//@SaCheckPermission("cw:approval:process")
|
||||
// @SaCheckPermission("cw:approval:process")
|
||||
@Log(title = "审批操作", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/process")
|
||||
public R<Void> processApproval(@RequestParam Long applicationId,
|
||||
@RequestParam String nodeCode,
|
||||
@RequestParam String approveAction,
|
||||
@RequestParam(required = false) String approveOpinion) {
|
||||
@RequestParam String nodeCode,
|
||||
@RequestParam String approveAction,
|
||||
@RequestParam(required = false) String approveOpinion) {
|
||||
return toAjax(approvalRecordService.processApproval(applicationId, nodeCode, approveAction, approveOpinion));
|
||||
}
|
||||
|
||||
/**
|
||||
* 部门审批
|
||||
*/
|
||||
//@SaCheckPermission("cw:approval:dept")
|
||||
// @SaCheckPermission("cw:approval:dept")
|
||||
@Log(title = "部门审批", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/dept")
|
||||
public R<Void> deptApprove(@RequestParam Long applicationId,
|
||||
@RequestParam String approveAction,
|
||||
@RequestParam(required = false) String approveOpinion) {
|
||||
@RequestParam String approveAction,
|
||||
@RequestParam(required = false) String approveOpinion) {
|
||||
return toAjax(approvalRecordService.deptApprove(applicationId, approveAction, approveOpinion));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前审批节点
|
||||
*/
|
||||
//@SaCheckPermission("cw:approval:query")
|
||||
// @SaCheckPermission("cw:approval:query")
|
||||
@GetMapping("/current/{applicationId}")
|
||||
public R<CwApprovalRecordVo> getCurrentNode(@PathVariable Long applicationId) {
|
||||
CwApprovalRecordVo record = approvalRecordService.queryCurrentApprovalNode(applicationId);
|
||||
@@ -253,7 +250,7 @@ public class CwApprovalRecordController extends BaseController {
|
||||
/**
|
||||
* 检查审批权限
|
||||
*/
|
||||
//@SaCheckPermission("cw:approval:check")
|
||||
// @SaCheckPermission("cw:approval:check")
|
||||
@GetMapping("/check/{applicationId}")
|
||||
public R<Boolean> checkPermission(@PathVariable Long applicationId, @RequestParam String nodeCode) {
|
||||
Boolean hasPermission = approvalRecordService.checkApprovalPermission(applicationId, nodeCode);
|
||||
@@ -263,7 +260,7 @@ public class CwApprovalRecordController extends BaseController {
|
||||
/**
|
||||
* 检查部门审批权限
|
||||
*/
|
||||
//@SaCheckPermission("cw:approval:dept")
|
||||
// @SaCheckPermission("cw:approval:dept")
|
||||
@GetMapping("/check/dept/{applicationId}")
|
||||
public R<Boolean> checkDeptPermission(@PathVariable Long applicationId) {
|
||||
Boolean hasPermission = approvalRecordService.checkDeptApprovalPermission(applicationId);
|
||||
@@ -273,7 +270,7 @@ public class CwApprovalRecordController extends BaseController {
|
||||
/**
|
||||
* 获取可选审批人列表(院领导)
|
||||
*/
|
||||
//@SaCheckPermission("cw:approval:finance")
|
||||
// @SaCheckPermission("cw:approval:finance")
|
||||
@GetMapping("/approvers/{applicationId}")
|
||||
public R<List<Map<String, Object>>> getAvailableApprovers(@PathVariable Long applicationId) {
|
||||
List<Map<String, Object>> approvers = approvalRecordService.getAvailableApprovers(applicationId);
|
||||
@@ -283,11 +280,11 @@ public class CwApprovalRecordController extends BaseController {
|
||||
/**
|
||||
* 分管领导审批
|
||||
*/
|
||||
//@SaCheckPermission("cw:approval:leader")
|
||||
// @SaCheckPermission("cw:approval:leader")
|
||||
@PostMapping("/leader")
|
||||
public R<Void> leaderApproval(@RequestParam Long applicationId,
|
||||
@RequestParam String approveAction,
|
||||
@RequestParam String approveOpinion) {
|
||||
@RequestParam String approveAction,
|
||||
@RequestParam String approveOpinion) {
|
||||
log.info("🔍 分管领导审批:applicationId={}, approveAction={}, approveOpinion={}",
|
||||
applicationId, approveAction, approveOpinion);
|
||||
|
||||
@@ -308,12 +305,12 @@ public class CwApprovalRecordController extends BaseController {
|
||||
/**
|
||||
* 财务审批
|
||||
*/
|
||||
//@SaCheckPermission("cw:approval:finance")
|
||||
// @SaCheckPermission("cw:approval:finance")
|
||||
@PostMapping("/finance")
|
||||
public R<Void> financeApproval(@RequestParam Long applicationId,
|
||||
@RequestParam String approveAction,
|
||||
@RequestParam String approveOpinion,
|
||||
@RequestParam(required = false) Long selectedApproverId) {
|
||||
@RequestParam String approveAction,
|
||||
@RequestParam String approveOpinion,
|
||||
@RequestParam(required = false) Long selectedApproverId) {
|
||||
log.info("🔍 财务审批:applicationId={}, approveAction={}, approveOpinion={}, selectedApproverId={}",
|
||||
applicationId, approveAction, approveOpinion, selectedApproverId);
|
||||
|
||||
|
||||
+265
@@ -0,0 +1,265 @@
|
||||
package org.dromara.rs.controller;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.*;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
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.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.excel.core.ExcelResult;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.rs.domain.vo.RsStaffInfoVo;
|
||||
import org.dromara.rs.domain.bo.RsStaffInfoBo;
|
||||
import org.dromara.rs.domain.vo.RsStaffInfoImportVo;
|
||||
import org.dromara.rs.listener.RsStaffInfoImportListener;
|
||||
import org.dromara.rs.service.IRsStaffInfoService;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.system.service.ISysDeptService;
|
||||
import org.dromara.system.domain.vo.SysDeptVo;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* 人员信息
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-09
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/staff/staffInfo")
|
||||
@Slf4j
|
||||
public class RsStaffInfoController extends BaseController {
|
||||
|
||||
private final IRsStaffInfoService staffInfoService;
|
||||
private final ISysDeptService deptService;
|
||||
|
||||
/**
|
||||
* 查询人员信息列表
|
||||
*/
|
||||
// @SaCheckPermission("rs:staffInfo:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<RsStaffInfoVo> list(RsStaffInfoBo bo, PageQuery pageQuery) {
|
||||
return staffInfoService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据部门ID查询人员信息列表
|
||||
*/
|
||||
// @SaCheckPermission("rs:staffInfo:list")
|
||||
@PostMapping("/listByDeptId")
|
||||
public TableDataInfo<RsStaffInfoVo> listByDeptId(@RequestBody Map<String, Object> requestBody,
|
||||
PageQuery pageQuery) {
|
||||
// 从请求体中解析查询条件和部门ID
|
||||
RsStaffInfoBo bo = new RsStaffInfoBo();
|
||||
|
||||
// 设置基础查询条件
|
||||
if (requestBody.containsKey("name")) {
|
||||
bo.setName((String) requestBody.get("name"));
|
||||
}
|
||||
if (requestBody.containsKey("staffNo")) {
|
||||
bo.setStaffNo((String) requestBody.get("staffNo"));
|
||||
}
|
||||
if (requestBody.containsKey("phone")) {
|
||||
bo.setPhone((String) requestBody.get("phone"));
|
||||
}
|
||||
if (requestBody.containsKey("staffType")) {
|
||||
bo.setStaffType((String) requestBody.get("staffType"));
|
||||
}
|
||||
if (requestBody.containsKey("status")) {
|
||||
bo.setStatus((String) requestBody.get("status"));
|
||||
}
|
||||
|
||||
// 设置时间范围查询条件
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
if (requestBody.containsKey("beginTime")) {
|
||||
params.put("beginTime", requestBody.get("beginTime"));
|
||||
}
|
||||
if (requestBody.containsKey("endTime")) {
|
||||
params.put("endTime", requestBody.get("endTime"));
|
||||
}
|
||||
bo.setParams(params);
|
||||
|
||||
// 提取部门ID参数
|
||||
Object deptIdValue = null;
|
||||
if (requestBody.containsKey("deptId") && requestBody.get("deptId") != null) {
|
||||
deptIdValue = requestBody.get("deptId");
|
||||
} else if (requestBody.containsKey("dept_id") && requestBody.get("dept_id") != null) {
|
||||
deptIdValue = requestBody.get("dept_id");
|
||||
}
|
||||
|
||||
if (deptIdValue != null) {
|
||||
bo.setDeptId(Long.valueOf(deptIdValue.toString()));
|
||||
}
|
||||
|
||||
// 处理排序参数
|
||||
if (requestBody.containsKey("orderBy")) {
|
||||
String orderBy = (String) requestBody.get("orderBy");
|
||||
// 解析 orderBy 字符串,格式如 "staffType ASC, createTime DESC"
|
||||
if (StringUtils.isNotBlank(orderBy)) {
|
||||
String[] orderParts = orderBy.split(",");
|
||||
StringBuilder columns = new StringBuilder();
|
||||
StringBuilder directions = new StringBuilder();
|
||||
|
||||
for (String part : orderParts) {
|
||||
part = part.trim();
|
||||
String[] columnAndDirection = part.split("\\s+");
|
||||
if (columnAndDirection.length == 2) {
|
||||
if (columns.length() > 0) {
|
||||
columns.append(",");
|
||||
directions.append(",");
|
||||
}
|
||||
columns.append(columnAndDirection[0].trim());
|
||||
String direction = columnAndDirection[1].trim().toLowerCase();
|
||||
directions.append("asc".equals(direction) ? "asc" : "desc");
|
||||
}
|
||||
}
|
||||
|
||||
if (columns.length() > 0) {
|
||||
pageQuery.setOrderByColumn(columns.toString());
|
||||
pageQuery.setIsAsc(directions.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return staffInfoService.queryPageListByDeptId(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取人员信息详细信息
|
||||
*/
|
||||
// @SaCheckPermission("rs:staffInfo:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<RsStaffInfoVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
|
||||
return R.ok(staffInfoService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增人员信息
|
||||
*/
|
||||
// @SaCheckPermission("rs:staffInfo:add")
|
||||
@Log(title = "人员信息", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody RsStaffInfoBo bo) {
|
||||
return toAjax(staffInfoService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改人员信息
|
||||
*/
|
||||
// @SaCheckPermission("rs:staffInfo:edit")
|
||||
@Log(title = "人员信息", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody RsStaffInfoBo bo) {
|
||||
return toAjax(staffInfoService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除人员信息
|
||||
*/
|
||||
// @SaCheckPermission("rs:staffInfo:remove")
|
||||
@Log(title = "人员信息", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
|
||||
return toAjax(staffInfoService.deleteWithRelatedData(java.util.Arrays.asList(ids)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取部门树形数据
|
||||
*/
|
||||
// @SaCheckPermission("rs:staffInfo:list")
|
||||
@GetMapping("/deptTree")
|
||||
public R<List<SysDeptVo>> deptTree() {
|
||||
List<SysDeptVo> depts = deptService.selectDeptList(
|
||||
new org.dromara.system.domain.bo.SysDeptBo());
|
||||
return R.ok(depts);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出人员信息
|
||||
*/
|
||||
// @SaCheckPermission("rs:staffInfo:export")
|
||||
@Log(title = "人员信息", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, RsStaffInfoBo query) {
|
||||
try {
|
||||
List<RsStaffInfoVo> list = staffInfoService.queryList(query);
|
||||
ExcelUtil.exportExcel(list, "人员信息", RsStaffInfoVo.class, response);
|
||||
} catch (Exception e) {
|
||||
log.error("导出人员信息失败", e);
|
||||
throw new org.dromara.common.core.exception.ServiceException("导出失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载人员信息导入模板
|
||||
*/
|
||||
@PostMapping("/importTemplate")
|
||||
public void importTemplate(HttpServletResponse response) {
|
||||
try {
|
||||
// 创建示例数据
|
||||
List<RsStaffInfoImportVo> templateData = new ArrayList<>();
|
||||
RsStaffInfoImportVo example = new RsStaffInfoImportVo();
|
||||
|
||||
// 设置示例数据
|
||||
example.setName("张三");
|
||||
example.setGender("0"); // Excel中会显示为"男"
|
||||
example.setPosition("讲师");
|
||||
example.setDeptName("计算机学院");
|
||||
example.setPhone("13800138000");
|
||||
example.setStaffType("0"); // Excel中会显示为"正式工"
|
||||
|
||||
templateData.add(example);
|
||||
|
||||
// 动态生成Excel模板(自动包含字典下拉选项)
|
||||
ExcelUtil.exportExcel(templateData, "人员信息导入模板", RsStaffInfoImportVo.class, response);
|
||||
} catch (Exception e) {
|
||||
log.error("生成导入模板失败", e);
|
||||
throw new org.dromara.common.core.exception.ServiceException("生成模板失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入人员数据
|
||||
*/
|
||||
// @SaCheckPermission("rs:staffInfo:import")
|
||||
@Log(title = "人员信息", businessType = BusinessType.IMPORT)
|
||||
@PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
public R<Void> importData(@RequestPart("file") MultipartFile file, String deptId, boolean updateSupport) throws Exception {
|
||||
log.info("导入人员信息,部门ID: {}, 更新支持: {}", deptId, updateSupport);
|
||||
log.info("导入文件名: {}, 文件大小: {} bytes", file.getOriginalFilename(), file.getSize());
|
||||
|
||||
try {
|
||||
ExcelResult<RsStaffInfoImportVo> result = ExcelUtil.importExcel(
|
||||
file.getInputStream(),
|
||||
RsStaffInfoImportVo.class,
|
||||
new RsStaffInfoImportListener(updateSupport, deptId)
|
||||
);
|
||||
|
||||
log.info("Excel导入完成,结果: {}", result.getAnalysis());
|
||||
return R.ok(result.getAnalysis());
|
||||
} catch (Exception e) {
|
||||
log.error("Excel导入失败", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package org.dromara.rs.domain;
|
||||
|
||||
import org.dromara.common.tenant.core.TenantEntity;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* 人员信息对象 rs_staff_info
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-09
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("rs_staff_info")
|
||||
public class RsStaffInfo extends TenantEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID(雪花ID)
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
@TableLogic(value = "0", delval = "1")
|
||||
private String delFlag;
|
||||
|
||||
/**
|
||||
* 工号
|
||||
*/
|
||||
private String staffNo;
|
||||
|
||||
/**
|
||||
* 姓名
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 性别:0-男,1-女
|
||||
*/
|
||||
private String gender;
|
||||
|
||||
/**
|
||||
* 职务
|
||||
*/
|
||||
private String position;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 手机号
|
||||
*/
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 人员类型(0正式工 1临时工 2外聘工)
|
||||
*/
|
||||
private String staffType;
|
||||
|
||||
/**
|
||||
* 关联的用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 状态(0正常 1停用)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
package org.dromara.rs.domain.bo;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import jakarta.validation.constraints.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.rs.domain.RsStaffInfo;
|
||||
|
||||
/**
|
||||
* 人员信息业务对象 rs_staff_info
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-09
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = RsStaffInfo.class, reverseConvertGenerate = false)
|
||||
public class RsStaffInfoBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 工号
|
||||
*/
|
||||
private String staffNo;
|
||||
|
||||
/**
|
||||
* 姓名
|
||||
*/
|
||||
@NotBlank(message = "姓名不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 性别
|
||||
*/
|
||||
@NotBlank(message = "性别不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@Pattern(regexp = "^[01]$", message = "性别只能是0(男)或1(女)", groups = { AddGroup.class, EditGroup.class })
|
||||
private String gender;
|
||||
|
||||
/**
|
||||
* 职务
|
||||
*/
|
||||
private String position;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
@NotNull(message = "部门ID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 手机号
|
||||
*/
|
||||
@NotBlank(message = "手机号不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确", groups = { AddGroup.class, EditGroup.class })
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 人员类型
|
||||
*/
|
||||
@NotBlank(message = "人员类型不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@Pattern(regexp = "^[0-2]$", message = "人员类型只能是0(正式工)、1(临时工)或2(外聘工)", groups = { AddGroup.class, EditGroup.class })
|
||||
private String staffType;
|
||||
|
||||
/**
|
||||
* 关联的用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
package org.dromara.rs.domain.vo;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
|
||||
import org.dromara.common.excel.convert.ExcelDictPreloadConvert;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 人员信息导入VO rs_staff_info
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-09
|
||||
*/
|
||||
@Data
|
||||
@cn.idev.excel.annotation.ExcelIgnoreUnannotated
|
||||
public class RsStaffInfoImportVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 工号
|
||||
*/
|
||||
@ExcelProperty("工号")
|
||||
private String staffNo;
|
||||
|
||||
/**
|
||||
* 姓名
|
||||
*/
|
||||
@ExcelProperty("姓名")
|
||||
@NotBlank(message = "姓名不能为空")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 性别
|
||||
*/
|
||||
@ExcelProperty(value = "性别", converter = ExcelDictPreloadConvert.class)
|
||||
@org.dromara.common.excel.annotation.ExcelDictFormat(dictType = "sys_user_sex")
|
||||
@Pattern(regexp = "^[01]$", message = "性别只能选择:0-男,1-女")
|
||||
private String gender;
|
||||
|
||||
/**
|
||||
* 职务
|
||||
*/
|
||||
@ExcelProperty("职务")
|
||||
private String position;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
@ExcelProperty("部门名称")
|
||||
@NotBlank(message = "部门名称不能为空")
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 手机号
|
||||
*/
|
||||
@ExcelProperty("手机号")
|
||||
@NotBlank(message = "手机号不能为空")
|
||||
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 人员类型
|
||||
*/
|
||||
@ExcelProperty(value = "人员类型", converter = ExcelDictPreloadConvert.class)
|
||||
@org.dromara.common.excel.annotation.ExcelDictFormat(readConverterExp = "0=正式工,1=临时工,2=外聘工")
|
||||
@Pattern(regexp = "^[0-2]$", message = "人员类型只能选择:0-正式工,1-临时工,2-外聘工")
|
||||
private String staffType;
|
||||
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
package org.dromara.rs.domain.vo;
|
||||
|
||||
import org.dromara.rs.domain.RsStaffInfo;
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
|
||||
import org.dromara.common.excel.convert.ExcelDictPreloadConvert;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 人员信息视图对象 rs_staff_info
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-09
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = RsStaffInfo.class)
|
||||
public class RsStaffInfoVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@ExcelProperty(value = "主键ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 工号
|
||||
*/
|
||||
@ExcelProperty(value = "工号")
|
||||
private String staffNo;
|
||||
|
||||
/**
|
||||
* 姓名
|
||||
*/
|
||||
@ExcelProperty(value = "姓名")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 性别
|
||||
*/
|
||||
@ExcelProperty(value = "性别", converter = ExcelDictPreloadConvert.class)
|
||||
@ExcelDictFormat(dictType = "sys_user_sex")
|
||||
private String gender;
|
||||
|
||||
/**
|
||||
* 职务
|
||||
*/
|
||||
@ExcelProperty(value = "职务")
|
||||
private String position;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
@ExcelProperty(value = "部门名称")
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 手机号
|
||||
*/
|
||||
@ExcelProperty(value = "手机号")
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 人员类型
|
||||
*/
|
||||
@ExcelProperty(value = "人员类型", converter = ExcelDictPreloadConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "0=正式工,1=临时工,2=外聘工")
|
||||
private String staffType;
|
||||
|
||||
/**
|
||||
* 关联的用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
@ExcelProperty(value = "状态", converter = ExcelDictPreloadConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "0=正常,1=停用")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@ExcelProperty(value = "创建时间")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
+214
@@ -0,0 +1,214 @@
|
||||
package org.dromara.rs.listener;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.idev.excel.context.AnalysisContext;
|
||||
import cn.idev.excel.event.AnalysisEventListener;
|
||||
import cn.idev.excel.util.ListUtils;
|
||||
import jakarta.validation.ConstraintViolation;
|
||||
import jakarta.validation.ConstraintViolationException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.core.utils.SpringUtils;
|
||||
import org.dromara.common.core.utils.StreamUtils;
|
||||
import org.dromara.common.core.utils.ValidatorUtils;
|
||||
import org.dromara.common.excel.core.ExcelListener;
|
||||
import org.dromara.common.excel.core.ExcelResult;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.rs.domain.bo.RsStaffInfoBo;
|
||||
import org.dromara.rs.domain.vo.RsStaffInfoImportVo;
|
||||
import org.dromara.rs.service.IRsStaffInfoService;
|
||||
import org.dromara.system.service.ISysDeptService;
|
||||
import org.dromara.system.service.ISysUserService;
|
||||
import org.dromara.system.domain.vo.SysDeptVo;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import cn.hutool.http.HtmlUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 人员信息自定义导入
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-09
|
||||
*/
|
||||
@Slf4j
|
||||
public class RsStaffInfoImportListener extends AnalysisEventListener<RsStaffInfoImportVo>
|
||||
implements ExcelListener<RsStaffInfoImportVo> {
|
||||
|
||||
private final IRsStaffInfoService staffInfoService;
|
||||
private final ISysDeptService deptService;
|
||||
private final ISysUserService userService;
|
||||
private final Boolean isUpdateSupport;
|
||||
private final Long operUserId;
|
||||
private final String deptId;
|
||||
|
||||
private int successNum = 0;
|
||||
private int failureNum = 0;
|
||||
private final StringBuilder successMsg = new StringBuilder();
|
||||
private final StringBuilder failureMsg = new StringBuilder();
|
||||
|
||||
public RsStaffInfoImportListener(Boolean isUpdateSupport, String deptId) {
|
||||
this.staffInfoService = SpringUtils.getBean(IRsStaffInfoService.class);
|
||||
this.deptService = SpringUtils.getBean(ISysDeptService.class);
|
||||
this.userService = SpringUtils.getBean(ISysUserService.class);
|
||||
this.isUpdateSupport = isUpdateSupport;
|
||||
this.deptId = deptId;
|
||||
this.operUserId = LoginHelper.getUserId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(RsStaffInfoImportVo staffVo, AnalysisContext context) {
|
||||
try {
|
||||
// 1. 验证数据完整性
|
||||
validateImportData(staffVo);
|
||||
|
||||
// 2. 验证唯一性(工号、手机号)
|
||||
if (!checkUniqueness(staffVo)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 根据部门名称查找部门ID
|
||||
Long deptId = findDeptByName(staffVo.getDeptName());
|
||||
if (deptId == null) {
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>").append(failureNum).append("、部门 ").append(staffVo.getDeptName()).append(" 不存在");
|
||||
return;
|
||||
}
|
||||
|
||||
// 4. 转换并保存数据
|
||||
RsStaffInfoBo staffBo = convertToBo(staffVo, deptId);
|
||||
staffInfoService.insertByBo(staffBo);
|
||||
|
||||
successNum++;
|
||||
successMsg.append("<br/>").append(successNum).append("、工号 ").append(staffBo.getStaffNo()).append(" 导入成功");
|
||||
|
||||
} catch (Exception e) {
|
||||
handleImportError(staffVo, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证导入数据
|
||||
*/
|
||||
private void validateImportData(RsStaffInfoImportVo staffVo) {
|
||||
if (staffVo == null) {
|
||||
throw new ServiceException("导入数据为空");
|
||||
}
|
||||
|
||||
// 验证必填字段
|
||||
if (StringUtils.isBlank(staffVo.getName())) {
|
||||
throw new ServiceException("姓名不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(staffVo.getGender())) {
|
||||
throw new ServiceException("性别不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(staffVo.getDeptName())) {
|
||||
throw new ServiceException("部门名称不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(staffVo.getPhone())) {
|
||||
throw new ServiceException("手机号不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(staffVo.getStaffType())) {
|
||||
throw new ServiceException("人员类型不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证唯一性
|
||||
*/
|
||||
private boolean checkUniqueness(RsStaffInfoImportVo staffVo) {
|
||||
// 验证工号唯一性(如果提供了工号)
|
||||
if (StringUtils.isNotBlank(staffVo.getStaffNo())) {
|
||||
// 这里可以添加工号唯一性验证逻辑
|
||||
// 暂时跳过,因为工号是自动生成的
|
||||
}
|
||||
|
||||
// 验证手机号唯一性
|
||||
if (StringUtils.isNotBlank(staffVo.getPhone())) {
|
||||
var existingUser = userService.selectUserByPhonenumber(staffVo.getPhone());
|
||||
if (existingUser != null) {
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>").append(failureNum).append("、手机号 ").append(staffVo.getPhone()).append(" 已存在");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据部门名称查找部门ID
|
||||
*/
|
||||
private Long findDeptByName(String deptName) {
|
||||
if (StringUtils.isBlank(deptName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 查询所有部门
|
||||
List<SysDeptVo> allDepts = deptService.selectDeptList(new org.dromara.system.domain.bo.SysDeptBo());
|
||||
for (SysDeptVo dept : allDepts) {
|
||||
if (deptName.equals(dept.getDeptName())) {
|
||||
return dept.getDeptId();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换VO到BO
|
||||
*/
|
||||
private RsStaffInfoBo convertToBo(RsStaffInfoImportVo staffVo, Long deptId) {
|
||||
RsStaffInfoBo staffBo = BeanUtil.toBean(staffVo, RsStaffInfoBo.class);
|
||||
staffBo.setDeptId(deptId);
|
||||
staffBo.setCreateBy(operUserId);
|
||||
staffBo.setUpdateBy(operUserId);
|
||||
return staffBo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理导入错误
|
||||
*/
|
||||
private void handleImportError(RsStaffInfoImportVo staffVo, Exception e) {
|
||||
failureNum++;
|
||||
String msg = "<br/>" + failureNum + "、姓名 " + HtmlUtil.cleanHtmlTag(staffVo.getName()) + " 导入失败:";
|
||||
String message = e.getMessage();
|
||||
if (e instanceof ConstraintViolationException cvException) {
|
||||
message = StreamUtils.join(cvException.getConstraintViolations(), ConstraintViolation::getMessage,
|
||||
", ");
|
||||
}
|
||||
failureMsg.append(msg).append(message);
|
||||
log.error(msg, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAfterAllAnalysed(AnalysisContext context) {
|
||||
// 处理完成后的逻辑
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExcelResult<RsStaffInfoImportVo> getExcelResult() {
|
||||
return new ExcelResult<>() {
|
||||
@Override
|
||||
public String getAnalysis() {
|
||||
if (failureNum > 0) {
|
||||
failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
|
||||
throw new ServiceException(failureMsg.toString());
|
||||
} else {
|
||||
successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
|
||||
}
|
||||
return successMsg.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RsStaffInfoImportVo> getList() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getErrorList() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package org.dromara.rs.mapper;
|
||||
|
||||
import org.dromara.rs.domain.RsStaffInfo;
|
||||
import org.dromara.rs.domain.vo.RsStaffInfoVo;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 人员信息Mapper接口
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-09
|
||||
*/
|
||||
public interface RsStaffInfoMapper extends BaseMapperPlus<RsStaffInfo, RsStaffInfoVo> {
|
||||
|
||||
/**
|
||||
* 根据人员类型获取该类别最大的工号
|
||||
*
|
||||
* @param staffType 人员类型(0正式工 1临时工 2外聘工)
|
||||
* @param prefix 工号前缀
|
||||
* @return 该类别最大的工号
|
||||
*/
|
||||
String selectMaxStaffNoByType(@Param("staffType") String staffType, @Param("prefix") String prefix);
|
||||
|
||||
/**
|
||||
* 根据部门ID列表查询人员信息
|
||||
*
|
||||
* @param deptIds 部门ID列表
|
||||
* @return 人员信息列表
|
||||
*/
|
||||
List<RsStaffInfoVo> selectListByDeptIds(@Param("deptIds") List<Long> deptIds);
|
||||
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package org.dromara.rs.service;
|
||||
|
||||
import org.dromara.rs.domain.RsStaffInfo;
|
||||
import org.dromara.rs.domain.bo.RsStaffInfoBo;
|
||||
import org.dromara.rs.domain.vo.RsStaffInfoVo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 人员信息Service接口
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-09
|
||||
*/
|
||||
public interface IRsStaffInfoService {
|
||||
|
||||
/**
|
||||
* 查询人员信息
|
||||
*/
|
||||
RsStaffInfoVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 查询人员信息列表
|
||||
*/
|
||||
TableDataInfo<RsStaffInfoVo> queryPageList(RsStaffInfoBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 根据部门ID查询人员信息列表
|
||||
*/
|
||||
TableDataInfo<RsStaffInfoVo> queryPageListByDeptId(RsStaffInfoBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询人员信息列表
|
||||
*/
|
||||
List<RsStaffInfoVo> queryList(RsStaffInfoBo bo);
|
||||
|
||||
/**
|
||||
* 新增人员信息
|
||||
*/
|
||||
Boolean insertByBo(RsStaffInfoBo bo);
|
||||
|
||||
/**
|
||||
* 修改人员信息
|
||||
*/
|
||||
Boolean updateByBo(RsStaffInfoBo bo);
|
||||
|
||||
/**
|
||||
* 批量删除人员信息
|
||||
*/
|
||||
Boolean deleteWithRelatedData(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 生成工号
|
||||
*/
|
||||
String generateStaffNo(String staffType);
|
||||
|
||||
}
|
||||
+285
@@ -0,0 +1,285 @@
|
||||
package org.dromara.rs.service.impl;
|
||||
|
||||
import cn.hutool.crypto.digest.BCrypt;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.dromara.rs.domain.bo.RsStaffInfoBo;
|
||||
import org.dromara.rs.domain.vo.RsStaffInfoVo;
|
||||
import org.dromara.rs.domain.RsStaffInfo;
|
||||
import org.dromara.rs.mapper.RsStaffInfoMapper;
|
||||
import org.dromara.rs.service.IRsStaffInfoService;
|
||||
import org.dromara.system.service.ISysUserService;
|
||||
import org.dromara.system.service.ISysDeptService;
|
||||
import org.dromara.system.domain.bo.SysUserBo;
|
||||
import org.dromara.system.domain.vo.SysDeptVo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 人员信息Service业务层处理
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-09
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class RsStaffInfoServiceImpl implements IRsStaffInfoService {
|
||||
|
||||
private final RsStaffInfoMapper baseMapper;
|
||||
private final ISysUserService sysUserService;
|
||||
private final ISysDeptService sysDeptService;
|
||||
|
||||
/**
|
||||
* 查询人员信息
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 人员信息
|
||||
*/
|
||||
@Override
|
||||
public RsStaffInfoVo queryById(Long id) {
|
||||
return baseMapper.selectVoById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询人员信息列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 人员信息分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<RsStaffInfoVo> queryPageList(RsStaffInfoBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<RsStaffInfo> lqw = buildQueryWrapper(bo);
|
||||
Page<RsStaffInfoVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据部门ID查询人员信息列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 人员信息分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<RsStaffInfoVo> queryPageListByDeptId(RsStaffInfoBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<RsStaffInfo> lqw = buildQueryWrapper(bo);
|
||||
Page<RsStaffInfoVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<RsStaffInfo> buildQueryWrapper(RsStaffInfoBo bo) {
|
||||
LambdaQueryWrapper<RsStaffInfo> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getDeptId() != null, RsStaffInfo::getDeptId, bo.getDeptId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getName()), RsStaffInfo::getName, bo.getName());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getStaffNo()), RsStaffInfo::getStaffNo, bo.getStaffNo());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getPhone()), RsStaffInfo::getPhone, bo.getPhone());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getStaffType()), RsStaffInfo::getStaffType, bo.getStaffType());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), RsStaffInfo::getStatus, bo.getStatus());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询人员信息列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 人员信息列表
|
||||
*/
|
||||
@Override
|
||||
public List<RsStaffInfoVo> queryList(RsStaffInfoBo bo) {
|
||||
LambdaQueryWrapper<RsStaffInfo> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增人员信息
|
||||
*
|
||||
* @param bo 人员信息
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean insertByBo(RsStaffInfoBo bo) {
|
||||
// 1. 生成工号
|
||||
String staffNo = generateStaffNo(bo.getStaffType());
|
||||
bo.setStaffNo(staffNo);
|
||||
|
||||
// 2. 插入人员主表
|
||||
RsStaffInfo entity = MapstructUtils.convert(bo, RsStaffInfo.class);
|
||||
entity.setCreateBy(LoginHelper.getUserId());
|
||||
entity.setCreateDept(LoginHelper.getDeptId());
|
||||
entity.setStatus("0"); // 默认正常状态
|
||||
boolean flag = baseMapper.insert(entity) > 0;
|
||||
|
||||
if (flag) {
|
||||
try {
|
||||
// 3. 获取部门名称
|
||||
if (bo.getDeptId() != null) {
|
||||
SysDeptVo dept = sysDeptService.selectDeptById(bo.getDeptId());
|
||||
if (dept != null) {
|
||||
entity.setDeptName(dept.getDeptName());
|
||||
baseMapper.updateById(entity);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 创建sys_user记录
|
||||
SysUserBo sysUserBo = new SysUserBo();
|
||||
sysUserBo.setUserId(entity.getId());
|
||||
sysUserBo.setUserName(bo.getPhone());
|
||||
sysUserBo.setNickName(bo.getName());
|
||||
sysUserBo.setUserType("sys_user");
|
||||
sysUserBo.setEmail("");
|
||||
sysUserBo.setPhonenumber(bo.getPhone());
|
||||
sysUserBo.setSex(bo.getGender());
|
||||
sysUserBo.setDeptId(bo.getDeptId());
|
||||
sysUserBo.setPassword(BCrypt.hashpw("Hzdyjs123456!@#", BCrypt.gensalt()));
|
||||
sysUserBo.setStatus("0");
|
||||
sysUserBo.setAccountType("1"); // 账号类型:教职工
|
||||
sysUserBo.setUserNo(bo.getStaffNo());
|
||||
|
||||
int userResult = sysUserService.insertUser(sysUserBo);
|
||||
if (userResult > 0) {
|
||||
// 5. 绑定默认角色(4和1938120323613728770)
|
||||
Long[] roleIds = { 4L, 1938120323613728770L };
|
||||
sysUserService.insertUserAuth(entity.getId(), roleIds);
|
||||
|
||||
// 6. 更新人员表的user_id关联
|
||||
entity.setUserId(entity.getId());
|
||||
baseMapper.updateById(entity);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("创建人员系统用户失败: {}", e.getMessage(), e);
|
||||
throw new RuntimeException("创建人员系统用户失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改人员信息
|
||||
*
|
||||
* @param bo 人员信息
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean updateByBo(RsStaffInfoBo bo) {
|
||||
RsStaffInfo update = MapstructUtils.convert(bo, RsStaffInfo.class);
|
||||
update.setUpdateBy(LoginHelper.getUserId());
|
||||
boolean flag = baseMapper.updateById(update) > 0;
|
||||
|
||||
if (flag) {
|
||||
try {
|
||||
// 查询现有的sys_user记录
|
||||
var existingUser = sysUserService.selectUserById(bo.getId());
|
||||
if (existingUser != null) {
|
||||
// 更新sys_user表信息
|
||||
SysUserBo sysUserBo = new SysUserBo();
|
||||
sysUserBo.setUserId(bo.getId());
|
||||
sysUserBo.setUserName(bo.getPhone());
|
||||
sysUserBo.setNickName(bo.getName());
|
||||
sysUserBo.setPhonenumber(bo.getPhone());
|
||||
sysUserBo.setSex(bo.getGender());
|
||||
sysUserBo.setDeptId(bo.getDeptId());
|
||||
sysUserBo.setUserNo(bo.getStaffNo());
|
||||
sysUserBo.setAccountType("1");
|
||||
|
||||
sysUserService.updateUser(sysUserBo);
|
||||
log.info("成功更新人员 {} 的系统用户信息", bo.getName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("更新人员系统用户信息失败: {}", e.getMessage(), e);
|
||||
throw new RuntimeException("更新人员系统用户信息失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除人员信息
|
||||
*
|
||||
* @param ids 人员ID集合
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean deleteWithRelatedData(Collection<Long> ids) {
|
||||
// 1. 删除人员主表记录(逻辑删除)
|
||||
boolean staffDeleteResult = baseMapper.deleteByIds(ids) > 0;
|
||||
|
||||
if (staffDeleteResult) {
|
||||
try {
|
||||
// 2. 同步删除sys_user表中的对应数据(逻辑删除)
|
||||
Long[] userIds = ids.toArray(new Long[0]);
|
||||
int userDeleteResult = sysUserService.deleteUserByIds(userIds);
|
||||
|
||||
if (userDeleteResult > 0) {
|
||||
log.info("成功删除 {} 个人员对应的系统用户", userDeleteResult);
|
||||
} else {
|
||||
log.warn("删除人员对应的系统用户失败,删除数量: {}", userDeleteResult);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("删除人员信息时同步删除系统用户失败: {}", e.getMessage(), e);
|
||||
throw new RuntimeException("删除人员信息时同步删除系统用户失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
return staffDeleteResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成工号
|
||||
*
|
||||
* @param staffType 人员类型(0正式工 1临时工 2外聘工)
|
||||
* @return 新生成的工号
|
||||
*/
|
||||
@Override
|
||||
public String generateStaffNo(String staffType) {
|
||||
// 根据人员类型确定前缀
|
||||
String prefix = switch (staffType) {
|
||||
case "0" -> "0"; // 正式工
|
||||
case "1" -> "L"; // 临时工
|
||||
case "2" -> "W"; // 外聘工
|
||||
default -> throw new ServiceException("无效的人员类型: " + staffType);
|
||||
};
|
||||
|
||||
// 从rs_staff_info表中获取该类别最大工号
|
||||
String maxStaffNo = baseMapper.selectMaxStaffNoByType(staffType, prefix);
|
||||
|
||||
int nextNumber = 1;
|
||||
if (StringUtils.isNotBlank(maxStaffNo)) {
|
||||
String numberPart = maxStaffNo.substring(1);
|
||||
try {
|
||||
nextNumber = Integer.parseInt(numberPart) + 1;
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("工号格式错误: {}, 使用默认值1", maxStaffNo);
|
||||
nextNumber = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 生成新的工号,确保是5位数字
|
||||
String numberStr = String.format("%05d", nextNumber);
|
||||
|
||||
// 检查是否超过最大值
|
||||
if (nextNumber > 99999) {
|
||||
throw new ServiceException("工号已达到最大值,无法生成新的工号");
|
||||
}
|
||||
|
||||
return prefix + numberStr;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?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.rs.mapper.RsStaffInfoMapper">
|
||||
|
||||
<resultMap type="org.dromara.rs.domain.RsStaffInfo" id="RsStaffInfoResult">
|
||||
<result property="id" column="id"/>
|
||||
<result property="tenantId" column="tenant_id"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
<result property="staffNo" column="staff_no"/>
|
||||
<result property="name" column="name"/>
|
||||
<result property="gender" column="gender"/>
|
||||
<result property="position" column="position"/>
|
||||
<result property="deptId" column="dept_id"/>
|
||||
<result property="deptName" column="dept_name"/>
|
||||
<result property="phone" column="phone"/>
|
||||
<result property="staffType" column="staff_type"/>
|
||||
<result property="userId" column="user_id"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="createDept" column="create_dept"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 根据人员类型获取该类别最大的工号 -->
|
||||
<select id="selectMaxStaffNoByType" resultType="java.lang.String">
|
||||
SELECT MAX(staff_no) as maxStaffNo
|
||||
FROM rs_staff_info
|
||||
WHERE staff_type = #{staffType}
|
||||
AND del_flag = '0'
|
||||
AND staff_no LIKE CONCAT(#{prefix}, '%')
|
||||
</select>
|
||||
|
||||
<!-- 根据部门ID列表查询人员信息 -->
|
||||
<select id="selectListByDeptIds" resultMap="RsStaffInfoResult">
|
||||
SELECT
|
||||
id,
|
||||
tenant_id,
|
||||
del_flag,
|
||||
staff_no,
|
||||
name,
|
||||
gender,
|
||||
position,
|
||||
dept_id,
|
||||
dept_name,
|
||||
phone,
|
||||
staff_type,
|
||||
user_id,
|
||||
status,
|
||||
create_dept,
|
||||
create_by,
|
||||
create_time,
|
||||
update_by,
|
||||
update_time,
|
||||
remark
|
||||
FROM rs_staff_info
|
||||
WHERE del_flag = '0'
|
||||
<if test="deptIds != null and deptIds.size() > 0">
|
||||
AND dept_id IN
|
||||
<foreach collection="deptIds" item="deptId" open="(" close=")" separator=",">
|
||||
#{deptId}
|
||||
</foreach>
|
||||
</if>
|
||||
ORDER BY create_time DESC
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
+5
@@ -37,6 +37,11 @@ public class SysUser extends TenantEntity {
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
private String userNo;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
|
||||
+6
@@ -42,6 +42,12 @@ public class SysUserBo extends BaseEntity {
|
||||
@Size(min = 0, max = 30, message = "用户账号长度不能超过{max}个字符")
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
@Size(min = 0, max = 30, message = "用户编号长度不能超过{max}个字符")
|
||||
private String userNo;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
|
||||
+205
-10
@@ -1,6 +1,7 @@
|
||||
package org.dromara.xg.controller;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.math.BigDecimal;
|
||||
@@ -9,6 +10,8 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.*;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
@@ -17,7 +20,12 @@ import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.excel.core.ExcelResult;
|
||||
import org.dromara.xg.listener.XgConductScoreImportListener;
|
||||
import org.dromara.xg.domain.vo.XgConductScoreVo;
|
||||
import org.dromara.xg.domain.vo.XgConductScoreExportVo;
|
||||
import org.dromara.xg.domain.vo.XgConductScoreImportVo;
|
||||
import org.dromara.xg.domain.vo.XgConductScoreSemesterAverageExportVo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreBo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreQueryBo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreBatchBo;
|
||||
@@ -282,7 +290,62 @@ public class XgConductScoreController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
ExcelUtil.exportExcel(list, "学生操行分", XgConductScoreVo.class, response);
|
||||
// 如果需要友好格式的学年显示,使用导出专用VO类
|
||||
if (requestBody.containsKey("academicYearFormat") &&
|
||||
"friendly".equals(requestBody.get("academicYearFormat").toString())) {
|
||||
// 创建导出专用的VO列表,将学年转换为友好格式
|
||||
java.util.List<XgConductScoreExportVo> exportList = new java.util.ArrayList<>();
|
||||
for (XgConductScoreVo vo : list) {
|
||||
XgConductScoreExportVo exportVo = new XgConductScoreExportVo();
|
||||
|
||||
// 复制所有基础字段
|
||||
exportVo.setId(vo.getId());
|
||||
exportVo.setTenantId(vo.getTenantId());
|
||||
exportVo.setStudentId(vo.getStudentId());
|
||||
exportVo.setStudentName(vo.getStudentName());
|
||||
exportVo.setStudentNo(vo.getStudentNo());
|
||||
exportVo.setClassId(vo.getClassId());
|
||||
exportVo.setClassName(vo.getClassName());
|
||||
exportVo.setCollegeName(vo.getCollegeName());
|
||||
exportVo.setMajorName(vo.getMajorName());
|
||||
exportVo.setClassTeacherId(vo.getClassTeacherId());
|
||||
exportVo.setClassTeacherName(vo.getClassTeacherName());
|
||||
exportVo.setScore(vo.getScore());
|
||||
exportVo.setRemark(vo.getRemark());
|
||||
exportVo.setEvaluationResult(vo.getEvaluationResult());
|
||||
exportVo.setCreateTime(vo.getCreateTime());
|
||||
exportVo.setCreateBy(vo.getCreateBy());
|
||||
exportVo.setCreateByName(vo.getCreateByName());
|
||||
exportVo.setUpdateBy(vo.getUpdateBy());
|
||||
exportVo.setUpdateTime(vo.getUpdateTime());
|
||||
|
||||
// 学年:转换为友好格式,如 2026 -> "2025-2026学年"
|
||||
String academicYearStr = vo.getAcademicYear() != null
|
||||
? (vo.getAcademicYear() - 1) + "-" + vo.getAcademicYear() + "学年"
|
||||
: "";
|
||||
exportVo.setAcademicYear(academicYearStr);
|
||||
|
||||
// 学期:转换为中文,如 1 -> "第一学期"
|
||||
String semesterStr = vo.getSemester() != null
|
||||
? (vo.getSemester() == 1 ? "第一学期" : "第二学期")
|
||||
: "";
|
||||
exportVo.setSemester(semesterStr);
|
||||
|
||||
// 月份:转换为带月字,如 1 -> "1月"
|
||||
String monthStr = vo.getMonth() != null
|
||||
? vo.getMonth() + "月"
|
||||
: "";
|
||||
exportVo.setMonth(monthStr);
|
||||
|
||||
exportList.add(exportVo);
|
||||
}
|
||||
|
||||
// 使用导出专用VO类进行导出
|
||||
ExcelUtil.exportExcel(exportList, "学生操行分", XgConductScoreExportVo.class, response);
|
||||
} else {
|
||||
// 正常导出,使用原始VO类
|
||||
ExcelUtil.exportExcel(list, "学生操行分", XgConductScoreVo.class, response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -518,16 +581,92 @@ public class XgConductScoreController extends BaseController {
|
||||
List<XgConductScoreSemesterAverageVo> list = xgConductScoreService
|
||||
.getSemesterAverageByDeptId(academicYear, semester, bo, deptParams, pageQuery).getRows();
|
||||
|
||||
// 为每条数据计算评判结果
|
||||
for (XgConductScoreSemesterAverageVo vo : list) {
|
||||
if (vo.getAvgScore() != null && vo.getRecordCount() != null && vo.getRecordCount() > 0) {
|
||||
vo.setEvaluationResult(calculateEvaluationResult(vo.getAvgScore()));
|
||||
} else {
|
||||
vo.setEvaluationResult("");
|
||||
}
|
||||
}
|
||||
// 如果需要友好格式的学年显示,使用导出专用VO类
|
||||
if (requestBody.containsKey("academicYearFormat") &&
|
||||
"friendly".equals(requestBody.get("academicYearFormat").toString())) {
|
||||
// 创建导出专用的VO列表,将学年转换为友好格式
|
||||
java.util.List<XgConductScoreSemesterAverageExportVo> exportList = new java.util.ArrayList<>();
|
||||
for (XgConductScoreSemesterAverageVo vo : list) {
|
||||
XgConductScoreSemesterAverageExportVo exportVo = new XgConductScoreSemesterAverageExportVo();
|
||||
|
||||
ExcelUtil.exportExcel(list, "学期平均分统计", XgConductScoreSemesterAverageVo.class, response);
|
||||
// 复制所有基础字段
|
||||
exportVo.setStudentId(vo.getStudentId());
|
||||
exportVo.setStudentNo(vo.getStudentNo());
|
||||
exportVo.setStudentName(vo.getStudentName());
|
||||
exportVo.setGender(vo.getGender());
|
||||
exportVo.setClassId(vo.getClassId());
|
||||
exportVo.setCollegeName(vo.getCollegeName());
|
||||
exportVo.setMajorName(vo.getMajorName());
|
||||
exportVo.setClassName(vo.getClassName());
|
||||
exportVo.setAvgScore(vo.getAvgScore());
|
||||
exportVo.setRecordCount(vo.getRecordCount());
|
||||
exportVo.setMaxScore(vo.getMaxScore());
|
||||
exportVo.setMinScore(vo.getMinScore());
|
||||
exportVo.setScoreRange(vo.getScoreRange());
|
||||
exportVo.setLastUpdateTime(vo.getLastUpdateTime());
|
||||
exportVo.setCreateBy(vo.getCreateBy());
|
||||
exportVo.setCreateTime(vo.getCreateTime());
|
||||
exportVo.setUpdateBy(vo.getUpdateBy());
|
||||
exportVo.setUpdateTime(vo.getUpdateTime());
|
||||
|
||||
// 计算评判结果
|
||||
if (vo.getAvgScore() != null && vo.getRecordCount() != null && vo.getRecordCount() > 0) {
|
||||
exportVo.setEvaluationResult(calculateEvaluationResult(vo.getAvgScore()));
|
||||
} else {
|
||||
exportVo.setEvaluationResult("");
|
||||
}
|
||||
|
||||
// 学年:转换为友好格式,如 2026 -> "2025-2026学年"
|
||||
String academicYearStr = vo.getAcademicYear() != null
|
||||
? (vo.getAcademicYear() - 1) + "-" + vo.getAcademicYear() + "学年"
|
||||
: "";
|
||||
exportVo.setAcademicYear(academicYearStr);
|
||||
|
||||
// 学期:转换为中文,如 1 -> "第一学期"
|
||||
String semesterStr = vo.getSemester() != null
|
||||
? (vo.getSemester() == 1 ? "第一学期" : "第二学期")
|
||||
: "";
|
||||
exportVo.setSemester(semesterStr);
|
||||
|
||||
exportList.add(exportVo);
|
||||
}
|
||||
|
||||
// 按学院、专业、班级、学号排序
|
||||
exportList.sort((a, b) -> {
|
||||
int result = java.util.Comparator.nullsLast(String::compareTo)
|
||||
.compare(a.getCollegeName(), b.getCollegeName());
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
result = java.util.Comparator.nullsLast(String::compareTo)
|
||||
.compare(a.getMajorName(), b.getMajorName());
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
result = java.util.Comparator.nullsLast(String::compareTo)
|
||||
.compare(a.getClassName(), b.getClassName());
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
return java.util.Comparator.nullsLast(String::compareTo)
|
||||
.compare(a.getStudentNo(), b.getStudentNo());
|
||||
});
|
||||
|
||||
// 使用导出专用VO类进行导出
|
||||
ExcelUtil.exportExcel(exportList, "学期平均分统计", XgConductScoreSemesterAverageExportVo.class, response);
|
||||
} else {
|
||||
// 为每条数据计算评判结果
|
||||
for (XgConductScoreSemesterAverageVo vo : list) {
|
||||
if (vo.getAvgScore() != null && vo.getRecordCount() != null && vo.getRecordCount() > 0) {
|
||||
vo.setEvaluationResult(calculateEvaluationResult(vo.getAvgScore()));
|
||||
} else {
|
||||
vo.setEvaluationResult("");
|
||||
}
|
||||
}
|
||||
|
||||
// 正常导出,使用原始VO类
|
||||
ExcelUtil.exportExcel(list, "学期平均分统计", XgConductScoreSemesterAverageVo.class, response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -584,4 +723,60 @@ public class XgConductScoreController extends BaseController {
|
||||
return R.ok(xgConductScoreService.checkInputPermission());
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载操行分导入模板
|
||||
*/
|
||||
// @SaCheckPermission("xg:conductScore:importTemplate")
|
||||
@PostMapping("/importTemplate")
|
||||
public void importTemplate(HttpServletResponse response) {
|
||||
try {
|
||||
// 创建示例数据
|
||||
List<XgConductScoreImportVo> templateData = new ArrayList<>();
|
||||
XgConductScoreImportVo example = new XgConductScoreImportVo();
|
||||
|
||||
// 设置示例数据
|
||||
example.setStudentNo("2024001");
|
||||
example.setStudentName("张三");
|
||||
example.setScore(85);
|
||||
example.setRemark("表现良好");
|
||||
|
||||
templateData.add(example);
|
||||
|
||||
// 动态生成Excel模板
|
||||
ExcelUtil.exportExcel(templateData, "操行分导入模板", XgConductScoreImportVo.class, response);
|
||||
} catch (Exception e) {
|
||||
log.error("生成导入模板失败", e);
|
||||
throw new org.dromara.common.core.exception.ServiceException("生成模板失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入操行分数据
|
||||
*/
|
||||
// @SaCheckPermission("xg:conductScore:importData")
|
||||
@Log(title = "学生操行分", businessType = BusinessType.IMPORT)
|
||||
@PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
public R<Void> importData(@RequestPart("file") MultipartFile file,
|
||||
@NotNull(message = "学年不能为空") Integer academicYear,
|
||||
@NotNull(message = "学期不能为空") Integer semester,
|
||||
@NotNull(message = "月份不能为空") Integer month,
|
||||
String classId) throws Exception {
|
||||
log.info("导入操行分数据,学年: {}, 学期: {}, 月份: {}, 班级ID: {}", academicYear, semester, month, classId);
|
||||
log.info("导入文件名: {}, 文件大小: {} bytes", file.getOriginalFilename(), file.getSize());
|
||||
|
||||
try {
|
||||
ExcelResult<XgConductScoreImportVo> result = ExcelUtil.importExcel(
|
||||
file.getInputStream(),
|
||||
XgConductScoreImportVo.class,
|
||||
new XgConductScoreImportListener(academicYear, semester, month, classId)
|
||||
);
|
||||
|
||||
log.info("Excel导入完成,结果: {}", result.getAnalysis());
|
||||
return R.ok(result.getAnalysis());
|
||||
} catch (Exception e) {
|
||||
log.error("Excel导入失败", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+3
@@ -5,6 +5,8 @@ import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.xg.domain.XgConductScore;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import jakarta.validation.constraints.*;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@@ -16,6 +18,7 @@ import java.math.BigDecimal;
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = XgConductScore.class, reverseConvertGenerate = false)
|
||||
public class XgConductScoreBo extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
package org.dromara.xg.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import org.dromara.xg.domain.XgConductScore;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
|
||||
/**
|
||||
* 学生操行分导出视图对象
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-01-13
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = XgConductScore.class)
|
||||
public class XgConductScoreExportVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
@cn.idev.excel.annotation.ExcelProperty(value = "记录ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 学年(友好格式,如:2025-2026学年)
|
||||
*/
|
||||
@cn.idev.excel.annotation.ExcelProperty(value = "学年")
|
||||
private String academicYear;
|
||||
|
||||
/**
|
||||
* 学期(中文格式,如:第一学期)
|
||||
*/
|
||||
@cn.idev.excel.annotation.ExcelProperty(value = "学期")
|
||||
private String semester;
|
||||
|
||||
/**
|
||||
* 月份(带月字,如:1月)
|
||||
*/
|
||||
@cn.idev.excel.annotation.ExcelProperty(value = "月份")
|
||||
private String month;
|
||||
|
||||
/**
|
||||
* 学生ID
|
||||
*/
|
||||
private Long studentId;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
@cn.idev.excel.annotation.ExcelProperty(value = "学生姓名")
|
||||
private String studentName;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
@cn.idev.excel.annotation.ExcelProperty(value = "学号")
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 班级ID
|
||||
*/
|
||||
private Long classId;
|
||||
|
||||
/**
|
||||
* 班级名称
|
||||
*/
|
||||
@cn.idev.excel.annotation.ExcelProperty(value = "班级名称")
|
||||
private String className;
|
||||
|
||||
/**
|
||||
* 学院名称
|
||||
*/
|
||||
@cn.idev.excel.annotation.ExcelProperty(value = "学院名称")
|
||||
private String collegeName;
|
||||
|
||||
/**
|
||||
* 专业名称
|
||||
*/
|
||||
@cn.idev.excel.annotation.ExcelProperty(value = "专业名称")
|
||||
private String majorName;
|
||||
|
||||
/**
|
||||
* 班主任ID
|
||||
*/
|
||||
private Long classTeacherId;
|
||||
|
||||
/**
|
||||
* 班主任姓名
|
||||
*/
|
||||
private String classTeacherName;
|
||||
|
||||
/**
|
||||
* 分数
|
||||
*/
|
||||
@cn.idev.excel.annotation.ExcelProperty(value = "分数")
|
||||
private BigDecimal score;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@cn.idev.excel.annotation.ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 评判结果
|
||||
*/
|
||||
@cn.idev.excel.annotation.ExcelProperty(value = "评判结果")
|
||||
private String evaluationResult;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@cn.idev.excel.annotation.ExcelProperty(value = "录入时间")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建者姓名
|
||||
*/
|
||||
@cn.idev.excel.annotation.ExcelProperty(value = "录入人")
|
||||
private String createByName;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package org.dromara.xg.domain.vo;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import jakarta.validation.constraints.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 学生操行分导入VO xg_conduct_score
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-01-13
|
||||
*/
|
||||
@Data
|
||||
@cn.idev.excel.annotation.ExcelIgnoreUnannotated
|
||||
public class XgConductScoreImportVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
@ExcelProperty("学号")
|
||||
@NotBlank(message = "学号不能为空")
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
@ExcelProperty("学生姓名")
|
||||
@NotBlank(message = "学生姓名不能为空")
|
||||
private String studentName;
|
||||
|
||||
/**
|
||||
* 分数
|
||||
*/
|
||||
@ExcelProperty("分数")
|
||||
@NotNull(message = "分数不能为空")
|
||||
@Min(value = 0, message = "分数不能小于0")
|
||||
@Max(value = 100, message = "分数不能大于100")
|
||||
private Integer score;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ExcelProperty("备注")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
package org.dromara.xg.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
|
||||
|
||||
/**
|
||||
* 操行分学期平均分导出视图对象
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-01-13
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class XgConductScoreSemesterAverageExportVo {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 学生ID
|
||||
*/
|
||||
private Long studentId;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
@ExcelProperty(value = "学号")
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
@ExcelProperty(value = "学生姓名")
|
||||
private String studentName;
|
||||
|
||||
/**
|
||||
* 性别
|
||||
*/
|
||||
@ExcelProperty(value = "性别", converter = org.dromara.common.excel.convert.ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "0=男,1=女")
|
||||
private String gender;
|
||||
|
||||
/**
|
||||
* 班级ID
|
||||
*/
|
||||
private Long classId;
|
||||
|
||||
/**
|
||||
* 学院名称
|
||||
*/
|
||||
@ExcelProperty(value = "学院")
|
||||
private String collegeName;
|
||||
|
||||
/**
|
||||
* 专业名称
|
||||
*/
|
||||
@ExcelProperty(value = "专业")
|
||||
private String majorName;
|
||||
|
||||
/**
|
||||
* 班级名称
|
||||
*/
|
||||
@ExcelProperty(value = "班级")
|
||||
private String className;
|
||||
|
||||
/**
|
||||
* 学年(友好格式,如:2025-2026学年)
|
||||
*/
|
||||
@ExcelProperty(value = "学年")
|
||||
private String academicYear;
|
||||
|
||||
/**
|
||||
* 学期(中文格式,如:第一学期)
|
||||
*/
|
||||
@ExcelProperty(value = "学期")
|
||||
private String semester;
|
||||
|
||||
/**
|
||||
* 学期平均分
|
||||
*/
|
||||
@ExcelProperty(value = "学期平均分")
|
||||
private BigDecimal avgScore;
|
||||
|
||||
/**
|
||||
* 评判结果
|
||||
*/
|
||||
@ExcelProperty(value = "评判结果")
|
||||
private String evaluationResult;
|
||||
|
||||
/**
|
||||
* 录入月份数
|
||||
*/
|
||||
@ExcelProperty(value = "录入月份")
|
||||
private Integer recordCount;
|
||||
|
||||
/**
|
||||
* 最高分
|
||||
*/
|
||||
@ExcelProperty(value = "最高分")
|
||||
private BigDecimal maxScore;
|
||||
|
||||
/**
|
||||
* 最低分
|
||||
*/
|
||||
@ExcelProperty(value = "最低分")
|
||||
private BigDecimal minScore;
|
||||
|
||||
/**
|
||||
* 分数范围
|
||||
*/
|
||||
private String scoreRange;
|
||||
|
||||
/**
|
||||
* 最后更新时间
|
||||
*/
|
||||
private Date lastUpdateTime;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
|
||||
}
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
package org.dromara.xg.listener;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.http.HtmlUtil;
|
||||
import cn.idev.excel.context.AnalysisContext;
|
||||
import cn.idev.excel.event.AnalysisEventListener;
|
||||
import jakarta.validation.ConstraintViolation;
|
||||
import jakarta.validation.ConstraintViolationException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.core.utils.SpringUtils;
|
||||
import org.dromara.common.core.utils.StreamUtils;
|
||||
import org.dromara.common.core.utils.ValidatorUtils;
|
||||
import org.dromara.common.excel.core.ExcelListener;
|
||||
import org.dromara.common.excel.core.ExcelResult;
|
||||
import org.dromara.common.excel.core.ExcelResult;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreBo;
|
||||
import org.dromara.xg.domain.bo.XgStudentMsgBo;
|
||||
import org.dromara.xg.domain.vo.XgConductScoreImportVo;
|
||||
import org.dromara.xg.domain.vo.XgConductScoreVo;
|
||||
import org.dromara.xg.domain.vo.XgStudentMsgVo;
|
||||
import org.dromara.xg.service.IXgConductScoreService;
|
||||
import org.dromara.xg.service.IXgStudentMsgService;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 学生操行分自定义导入
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-01-13
|
||||
*/
|
||||
@Slf4j
|
||||
public class XgConductScoreImportListener extends AnalysisEventListener<XgConductScoreImportVo>
|
||||
implements ExcelListener<XgConductScoreImportVo> {
|
||||
|
||||
private final IXgConductScoreService conductScoreService;
|
||||
private final IXgStudentMsgService studentMsgService;
|
||||
private final Integer academicYear;
|
||||
private final Integer semester;
|
||||
private final Integer month;
|
||||
private final String classId; // 可选,指定班级ID
|
||||
private final Long operUserId;
|
||||
|
||||
private int successNum = 0;
|
||||
private int failureNum = 0;
|
||||
private final StringBuilder successMsg = new StringBuilder();
|
||||
private final StringBuilder failureMsg = new StringBuilder();
|
||||
|
||||
public XgConductScoreImportListener(Integer academicYear, Integer semester, Integer month, String classId) {
|
||||
this.conductScoreService = SpringUtils.getBean(IXgConductScoreService.class);
|
||||
this.studentMsgService = SpringUtils.getBean(IXgStudentMsgService.class);
|
||||
this.academicYear = academicYear;
|
||||
this.semester = semester;
|
||||
this.month = month;
|
||||
this.classId = classId;
|
||||
this.operUserId = LoginHelper.getUserId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(XgConductScoreImportVo importVo, AnalysisContext context) {
|
||||
try {
|
||||
// 1. 验证数据完整性
|
||||
validateImportData(importVo);
|
||||
|
||||
// 2. 根据学号查找学生信息
|
||||
XgStudentMsgBo queryBo = new XgStudentMsgBo();
|
||||
queryBo.setStudentNo(importVo.getStudentNo());
|
||||
List<XgStudentMsgVo> students = studentMsgService.queryList(queryBo);
|
||||
if (students == null || students.isEmpty()) {
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>").append(failureNum).append("、学号 ").append(importVo.getStudentNo()).append(" 不存在");
|
||||
return;
|
||||
}
|
||||
XgStudentMsgVo student = students.get(0);
|
||||
|
||||
// 3. 验证学生姓名匹配
|
||||
if (!importVo.getStudentName().equals(student.getName())) {
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>").append(failureNum).append("、学号 ").append(importVo.getStudentNo())
|
||||
.append(" 姓名不匹配,Excel中:").append(importVo.getStudentName())
|
||||
.append(",系统中:").append(student.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
// 4. 验证班级权限(如果指定了班级)
|
||||
if (StringUtils.isNotBlank(classId) && !classId.equals(student.getClassId())) {
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>").append(failureNum).append("、学号 ").append(importVo.getStudentNo()).append(" 不属于指定班级");
|
||||
return;
|
||||
}
|
||||
|
||||
// 5. 检查是否已有记录
|
||||
XgConductScoreVo existingRecord = conductScoreService.selectByStudentAndTime(
|
||||
student.getId(), academicYear, semester, month);
|
||||
|
||||
if (existingRecord != null) {
|
||||
// 更新现有记录
|
||||
XgConductScoreBo updateBo = new XgConductScoreBo();
|
||||
updateBo.setId(existingRecord.getId());
|
||||
updateBo.setScore(java.math.BigDecimal.valueOf(importVo.getScore()));
|
||||
updateBo.setRemark(importVo.getRemark());
|
||||
updateBo.setUpdateBy(operUserId);
|
||||
conductScoreService.updateByBo(updateBo);
|
||||
|
||||
successNum++;
|
||||
successMsg.append("<br/>").append(successNum).append("、学号 ").append(importVo.getStudentNo())
|
||||
.append(" 更新成功(覆盖原有分数 ").append(existingRecord.getScore()).append(" → ").append(importVo.getScore()).append(")");
|
||||
} else {
|
||||
// 插入新记录
|
||||
XgConductScoreBo insertBo = new XgConductScoreBo();
|
||||
insertBo.setAcademicYear(academicYear);
|
||||
insertBo.setSemester(semester);
|
||||
insertBo.setMonth(month);
|
||||
insertBo.setStudentId(student.getId());
|
||||
insertBo.setClassId(Long.valueOf(student.getClassId()));
|
||||
insertBo.setClassTeacherId(student.getClassTeacherId());
|
||||
insertBo.setScore(java.math.BigDecimal.valueOf(importVo.getScore()));
|
||||
insertBo.setRemark(importVo.getRemark());
|
||||
insertBo.setCreateBy(operUserId);
|
||||
insertBo.setUpdateBy(operUserId);
|
||||
conductScoreService.insertByBo(insertBo);
|
||||
|
||||
successNum++;
|
||||
successMsg.append("<br/>").append(successNum).append("、学号 ").append(importVo.getStudentNo()).append(" 导入成功");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
handleImportError(importVo, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证导入数据
|
||||
*/
|
||||
private void validateImportData(XgConductScoreImportVo importVo) {
|
||||
if (importVo == null) {
|
||||
throw new ServiceException("导入数据为空");
|
||||
}
|
||||
|
||||
// 验证必填字段
|
||||
if (StringUtils.isBlank(importVo.getStudentNo())) {
|
||||
throw new ServiceException("学号不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(importVo.getStudentName())) {
|
||||
throw new ServiceException("学生姓名不能为空");
|
||||
}
|
||||
if (importVo.getScore() == null) {
|
||||
throw new ServiceException("分数不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理导入错误
|
||||
*/
|
||||
private void handleImportError(XgConductScoreImportVo importVo, Exception e) {
|
||||
failureNum++;
|
||||
String msg = "<br/>" + failureNum + "、学号 " + HtmlUtil.cleanHtmlTag(importVo.getStudentNo()) + " 导入失败:";
|
||||
String message = e.getMessage();
|
||||
if (e instanceof ConstraintViolationException cvException) {
|
||||
message = StreamUtils.join(cvException.getConstraintViolations(), ConstraintViolation::getMessage,
|
||||
", ");
|
||||
}
|
||||
failureMsg.append(msg).append(message);
|
||||
log.error(msg, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAfterAllAnalysed(AnalysisContext context) {
|
||||
// 处理完成后的逻辑
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExcelResult<XgConductScoreImportVo> getExcelResult() {
|
||||
return new ExcelResult<>() {
|
||||
@Override
|
||||
public String getAnalysis() {
|
||||
if (failureNum > 0) {
|
||||
failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
|
||||
throw new ServiceException(failureMsg.toString());
|
||||
} else {
|
||||
successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
|
||||
}
|
||||
return successMsg.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<XgConductScoreImportVo> getList() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getErrorList() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+16
@@ -111,6 +111,22 @@ public interface IXgConductScoreMapper extends BaseMapperPlus<XgConductScore, Xg
|
||||
@org.apache.ibatis.annotations.Param("month") Integer month,
|
||||
@org.apache.ibatis.annotations.Param("tenantId") String tenantId);
|
||||
|
||||
/**
|
||||
* 根据学生ID、学年、学期、月份查询单个记录
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @param academicYear 学年
|
||||
* @param semester 学期
|
||||
* @param month 月份
|
||||
* @param tenantId 租户ID
|
||||
* @return 记录信息
|
||||
*/
|
||||
XgConductScoreVo selectByStudentAndTime(@org.apache.ibatis.annotations.Param("studentId") Long studentId,
|
||||
@org.apache.ibatis.annotations.Param("academicYear") Integer academicYear,
|
||||
@org.apache.ibatis.annotations.Param("semester") Integer semester,
|
||||
@org.apache.ibatis.annotations.Param("month") Integer month,
|
||||
@org.apache.ibatis.annotations.Param("tenantId") String tenantId);
|
||||
|
||||
/**
|
||||
* 批量插入操行分记录
|
||||
*
|
||||
|
||||
+11
@@ -159,6 +159,17 @@ public interface IXgConductScoreService {
|
||||
boolean existsByStudentAndMonth(Long studentId, Integer academicYear, Integer semester, Integer month,
|
||||
String tenantId);
|
||||
|
||||
/**
|
||||
* 根据学生ID、学年、学期、月份查询单个记录
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @param academicYear 学年
|
||||
* @param semester 学期
|
||||
* @param month 月份
|
||||
* @return 记录信息
|
||||
*/
|
||||
XgConductScoreVo selectByStudentAndTime(Long studentId, Integer academicYear, Integer semester, Integer month);
|
||||
|
||||
/**
|
||||
* 获取班主任负责的班级ID列表
|
||||
*
|
||||
|
||||
+6
@@ -611,6 +611,12 @@ public class XgConductScoreServiceImpl implements IXgConductScoreService {
|
||||
return baseMapper.existsByStudentAndMonth(studentId, academicYear, semester, month, tenantId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XgConductScoreVo selectByStudentAndTime(Long studentId, Integer academicYear, Integer semester, Integer month) {
|
||||
String tenantId = LoginHelper.getTenantId();
|
||||
return baseMapper.selectByStudentAndTime(studentId, academicYear, semester, month, tenantId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取班主任负责的班级ID列表
|
||||
*
|
||||
|
||||
+24
@@ -491,6 +491,30 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
AND deleted = 0
|
||||
</select>
|
||||
|
||||
<select id="selectByStudentAndTime" resultMap="XgConductScoreResult">
|
||||
SELECT
|
||||
id,
|
||||
tenant_id,
|
||||
academic_year,
|
||||
semester,
|
||||
month,
|
||||
student_id,
|
||||
score,
|
||||
remark,
|
||||
create_time,
|
||||
update_time,
|
||||
create_by,
|
||||
update_by
|
||||
FROM xg_conduct_score
|
||||
WHERE student_id = #{studentId}
|
||||
AND academic_year = #{academicYear}
|
||||
AND semester = #{semester}
|
||||
AND month = #{month}
|
||||
AND tenant_id = #{tenantId}
|
||||
AND deleted = 0
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<insert id="insertBatch" parameterType="java.util.List">
|
||||
INSERT INTO xg_conduct_score (
|
||||
id, tenant_id, academic_year, semester, month,
|
||||
|
||||
@@ -49,6 +49,3 @@ export const listImportItems = (batchId: number, params?: any) => {
|
||||
params: { batchId, ...params }
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import request from '@/utils/request'
|
||||
import type { AxiosPromise } from 'axios'
|
||||
import type { CwProjectPerformanceSelfEvaluationVO, CwProjectPerformanceSelfEvaluationQuery } from './performanceEvaluation'
|
||||
import request from '@/utils/request';
|
||||
import type { AxiosPromise } from 'axios';
|
||||
import type { CwProjectPerformanceSelfEvaluationVO, CwProjectPerformanceSelfEvaluationQuery } from './performanceEvaluation';
|
||||
|
||||
/**
|
||||
* 运行监控管理API
|
||||
@@ -11,7 +11,7 @@ import type { CwProjectPerformanceSelfEvaluationVO, CwProjectPerformanceSelfEval
|
||||
* 运行监控管理查询对象
|
||||
*/
|
||||
export interface MonitoringManagementQuery extends CwProjectPerformanceSelfEvaluationQuery {
|
||||
isLocked?: number
|
||||
isLocked?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -22,7 +22,7 @@ export function listMonitoringManagement(query: MonitoringManagementQuery): Axio
|
||||
url: '/cw/monitoringManagement/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -32,7 +32,7 @@ export function getMonitoringManagement(id: number): AxiosPromise<CwProjectPerfo
|
||||
return request({
|
||||
url: `/cw/monitoringManagement/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -42,7 +42,7 @@ export function lockEvaluation(id: number): AxiosPromise<any> {
|
||||
return request({
|
||||
url: `/cw/monitoringManagement/lock/${id}`,
|
||||
method: 'post'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,7 +52,7 @@ export function unlockEvaluation(id: number): AxiosPromise<any> {
|
||||
return request({
|
||||
url: `/cw/monitoringManagement/unlock/${id}`,
|
||||
method: 'post'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,7 +63,7 @@ export function lockBatchEvaluation(ids: number[]): AxiosPromise<any> {
|
||||
url: '/cw/monitoringManagement/lock/batch',
|
||||
method: 'post',
|
||||
data: ids
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,6 +74,5 @@ export function unlockBatchEvaluation(ids: number[]): AxiosPromise<any> {
|
||||
url: '/cw/monitoringManagement/unlock/batch',
|
||||
method: 'post',
|
||||
data: ids
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import request from '@/utils/request'
|
||||
import type { AxiosPromise } from 'axios'
|
||||
import request from '@/utils/request';
|
||||
import type { AxiosPromise } from 'axios';
|
||||
|
||||
// ========== 绩效自评API ==========
|
||||
|
||||
@@ -7,300 +7,300 @@ import type { AxiosPromise } from 'axios'
|
||||
* 项目绩效自评视图对象
|
||||
*/
|
||||
export interface CwProjectPerformanceSelfEvaluationVO {
|
||||
id?: number
|
||||
tenantId?: string
|
||||
projectApplicationId: number
|
||||
applicationNo: string
|
||||
projectName: string
|
||||
supervisoryDept?: string
|
||||
implementUnit?: string
|
||||
evaluationYear: number
|
||||
initialBudget?: number
|
||||
principal?: string
|
||||
contactPhone?: string
|
||||
startDate?: string
|
||||
endDate?: string
|
||||
totalInvestment?: number
|
||||
annualBudget?: number
|
||||
actualExpenditure?: number
|
||||
budgetExecutionRate?: number
|
||||
id?: number;
|
||||
tenantId?: string;
|
||||
projectApplicationId: number;
|
||||
applicationNo: string;
|
||||
projectName: string;
|
||||
supervisoryDept?: string;
|
||||
implementUnit?: string;
|
||||
evaluationYear: number;
|
||||
initialBudget?: number;
|
||||
principal?: string;
|
||||
contactPhone?: string;
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
totalInvestment?: number;
|
||||
annualBudget?: number;
|
||||
actualExpenditure?: number;
|
||||
budgetExecutionRate?: number;
|
||||
|
||||
// 资金到位(年度资金总额)
|
||||
fundValue?: number
|
||||
fundExecutionRate?: number
|
||||
fundScore?: number
|
||||
fundValue?: number;
|
||||
fundExecutionRate?: number;
|
||||
fundScore?: number;
|
||||
|
||||
// 当年财政拨款
|
||||
currentYearBudgetInitial?: number
|
||||
currentYearBudgetAnnual?: number
|
||||
currentYearBudgetActual?: number
|
||||
currentYearBudgetValue?: number
|
||||
currentYearBudgetExecutionRate?: number
|
||||
currentYearBudgetScore?: number
|
||||
currentYearBudgetInitial?: number;
|
||||
currentYearBudgetAnnual?: number;
|
||||
currentYearBudgetActual?: number;
|
||||
currentYearBudgetValue?: number;
|
||||
currentYearBudgetExecutionRate?: number;
|
||||
currentYearBudgetScore?: number;
|
||||
|
||||
// 上年结转资金
|
||||
lastYearCarryoverInitial?: number
|
||||
lastYearCarryoverAnnual?: number
|
||||
lastYearCarryoverActual?: number
|
||||
lastYearCarryoverValue?: number
|
||||
lastYearCarryoverExecutionRate?: number
|
||||
lastYearCarryoverScore?: number
|
||||
lastYearCarryoverInitial?: number;
|
||||
lastYearCarryoverAnnual?: number;
|
||||
lastYearCarryoverActual?: number;
|
||||
lastYearCarryoverValue?: number;
|
||||
lastYearCarryoverExecutionRate?: number;
|
||||
lastYearCarryoverScore?: number;
|
||||
|
||||
// 其他资金
|
||||
otherFundsInitial?: number
|
||||
otherFundsAnnual?: number
|
||||
otherFundsActual?: number
|
||||
otherFundsValue?: number
|
||||
otherFundsExecutionRate?: number
|
||||
otherFundsScore?: number
|
||||
otherFundsInitial?: number;
|
||||
otherFundsAnnual?: number;
|
||||
otherFundsActual?: number;
|
||||
otherFundsValue?: number;
|
||||
otherFundsExecutionRate?: number;
|
||||
otherFundsScore?: number;
|
||||
|
||||
performanceGoal?: string
|
||||
targetCompletion?: string
|
||||
performanceGoal?: string;
|
||||
targetCompletion?: string;
|
||||
|
||||
// 数量指标
|
||||
quantityIndicator?: string
|
||||
quantityTarget?: string
|
||||
quantityActual?: string
|
||||
quantityValue?: number
|
||||
quantityScore?: number
|
||||
quantityDeviation?: string
|
||||
quantityIndicator?: string;
|
||||
quantityTarget?: string;
|
||||
quantityActual?: string;
|
||||
quantityValue?: number;
|
||||
quantityScore?: number;
|
||||
quantityDeviation?: string;
|
||||
|
||||
// 质量指标
|
||||
qualityIndicator?: string
|
||||
qualityTarget?: string
|
||||
qualityActual?: string
|
||||
qualityValue?: number
|
||||
qualityScore?: number
|
||||
qualityDeviation?: string
|
||||
qualityIndicator?: string;
|
||||
qualityTarget?: string;
|
||||
qualityActual?: string;
|
||||
qualityValue?: number;
|
||||
qualityScore?: number;
|
||||
qualityDeviation?: string;
|
||||
|
||||
// 时效指标
|
||||
timelinessIndicator?: string
|
||||
timelinessTarget?: string
|
||||
timelinessActual?: string
|
||||
timelinessValue?: number
|
||||
timelinessScore?: number
|
||||
timelinessDeviation?: string
|
||||
timelinessIndicator?: string;
|
||||
timelinessTarget?: string;
|
||||
timelinessActual?: string;
|
||||
timelinessValue?: number;
|
||||
timelinessScore?: number;
|
||||
timelinessDeviation?: string;
|
||||
|
||||
// 成本指标
|
||||
costIndicator?: string
|
||||
costTarget?: string
|
||||
costActual?: string
|
||||
costValue?: number
|
||||
costScore?: number
|
||||
costDeviation?: string
|
||||
costIndicator?: string;
|
||||
costTarget?: string;
|
||||
costActual?: string;
|
||||
costValue?: number;
|
||||
costScore?: number;
|
||||
costDeviation?: string;
|
||||
|
||||
// 经济效益指标
|
||||
economicIndicator?: string
|
||||
economicTarget?: string
|
||||
economicActual?: string
|
||||
economicValue?: number
|
||||
economicScore?: number
|
||||
economicDeviation?: string
|
||||
economicIndicator?: string;
|
||||
economicTarget?: string;
|
||||
economicActual?: string;
|
||||
economicValue?: number;
|
||||
economicScore?: number;
|
||||
economicDeviation?: string;
|
||||
|
||||
// 社会效益指标
|
||||
socialIndicator?: string
|
||||
socialTarget?: string
|
||||
socialActual?: string
|
||||
socialValue?: number
|
||||
socialScore?: number
|
||||
socialDeviation?: string
|
||||
socialIndicator?: string;
|
||||
socialTarget?: string;
|
||||
socialActual?: string;
|
||||
socialValue?: number;
|
||||
socialScore?: number;
|
||||
socialDeviation?: string;
|
||||
|
||||
// 生态效益指标
|
||||
ecologicalIndicator?: string
|
||||
ecologicalTarget?: string
|
||||
ecologicalActual?: string
|
||||
ecologicalValue?: number
|
||||
ecologicalScore?: number
|
||||
ecologicalDeviation?: string
|
||||
ecologicalIndicator?: string;
|
||||
ecologicalTarget?: string;
|
||||
ecologicalActual?: string;
|
||||
ecologicalValue?: number;
|
||||
ecologicalScore?: number;
|
||||
ecologicalDeviation?: string;
|
||||
|
||||
// 满意度指标
|
||||
satisfactionIndicator?: string
|
||||
satisfactionTarget?: string
|
||||
satisfactionActual?: string
|
||||
satisfactionValue?: number
|
||||
satisfactionScore?: number
|
||||
satisfactionDeviation?: string
|
||||
satisfactionIndicator?: string;
|
||||
satisfactionTarget?: string;
|
||||
satisfactionActual?: string;
|
||||
satisfactionValue?: number;
|
||||
satisfactionScore?: number;
|
||||
satisfactionDeviation?: string;
|
||||
|
||||
decisionScore?: number
|
||||
decisionContent?: string
|
||||
processScore?: number
|
||||
processContent?: string
|
||||
outputScore?: number
|
||||
outputContent?: string
|
||||
benefitScore?: number
|
||||
benefitContent?: string
|
||||
totalScore?: number
|
||||
selfEvaluationLevel?: string
|
||||
existingProblems?: string
|
||||
improvementMeasures?: string
|
||||
evaluationStatus: string
|
||||
allowEditAfterSubmit?: number
|
||||
submitTime?: string
|
||||
submitBy?: number
|
||||
submitByName?: string
|
||||
approveTime?: string
|
||||
approveBy?: number
|
||||
approveByName?: string
|
||||
approveOpinion?: string
|
||||
remark?: string
|
||||
decisionScore?: number;
|
||||
decisionContent?: string;
|
||||
processScore?: number;
|
||||
processContent?: string;
|
||||
outputScore?: number;
|
||||
outputContent?: string;
|
||||
benefitScore?: number;
|
||||
benefitContent?: string;
|
||||
totalScore?: number;
|
||||
selfEvaluationLevel?: string;
|
||||
existingProblems?: string;
|
||||
improvementMeasures?: string;
|
||||
evaluationStatus: string;
|
||||
allowEditAfterSubmit?: number;
|
||||
submitTime?: string;
|
||||
submitBy?: number;
|
||||
submitByName?: string;
|
||||
approveTime?: string;
|
||||
approveBy?: number;
|
||||
approveByName?: string;
|
||||
approveOpinion?: string;
|
||||
remark?: string;
|
||||
// 锁定相关字段
|
||||
isLocked?: number
|
||||
lockTime?: string
|
||||
lockBy?: number
|
||||
lockByName?: string
|
||||
createTime?: string
|
||||
updateTime?: string
|
||||
isLocked?: number;
|
||||
lockTime?: string;
|
||||
lockBy?: number;
|
||||
lockByName?: string;
|
||||
createTime?: string;
|
||||
updateTime?: string;
|
||||
// 前端使用的字段,用于标记是否有运行监控数据
|
||||
hasMonitoringData?: boolean
|
||||
hasMonitoringData?: boolean;
|
||||
// 运行监控数据列表
|
||||
monitoringList?: CwPerformanceMonitoringVO[]
|
||||
monitoringList?: CwPerformanceMonitoringVO[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 项目绩效自评表单对象
|
||||
*/
|
||||
export interface CwProjectPerformanceSelfEvaluationForm {
|
||||
id?: number
|
||||
projectApplicationId: number
|
||||
applicationNo?: string
|
||||
projectName: string
|
||||
supervisoryDept?: string
|
||||
implementUnit?: string
|
||||
evaluationYear: number
|
||||
initialBudget?: number
|
||||
principal?: string
|
||||
contactPhone?: string
|
||||
startDate?: string
|
||||
endDate?: string
|
||||
totalInvestment?: number
|
||||
annualBudget?: number
|
||||
actualExpenditure?: number
|
||||
budgetExecutionRate?: number
|
||||
id?: number;
|
||||
projectApplicationId: number;
|
||||
applicationNo?: string;
|
||||
projectName: string;
|
||||
supervisoryDept?: string;
|
||||
implementUnit?: string;
|
||||
evaluationYear: number;
|
||||
initialBudget?: number;
|
||||
principal?: string;
|
||||
contactPhone?: string;
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
totalInvestment?: number;
|
||||
annualBudget?: number;
|
||||
actualExpenditure?: number;
|
||||
budgetExecutionRate?: number;
|
||||
|
||||
// 资金到位(年度资金总额)
|
||||
fundValue?: number
|
||||
fundExecutionRate?: number
|
||||
fundScore?: number
|
||||
fundValue?: number;
|
||||
fundExecutionRate?: number;
|
||||
fundScore?: number;
|
||||
|
||||
// 当年财政拨款
|
||||
currentYearBudgetInitial?: number
|
||||
currentYearBudgetAnnual?: number
|
||||
currentYearBudgetActual?: number
|
||||
currentYearBudgetValue?: number
|
||||
currentYearBudgetExecutionRate?: number
|
||||
currentYearBudgetScore?: number
|
||||
currentYearBudgetInitial?: number;
|
||||
currentYearBudgetAnnual?: number;
|
||||
currentYearBudgetActual?: number;
|
||||
currentYearBudgetValue?: number;
|
||||
currentYearBudgetExecutionRate?: number;
|
||||
currentYearBudgetScore?: number;
|
||||
|
||||
// 上年结转资金
|
||||
lastYearCarryoverInitial?: number
|
||||
lastYearCarryoverAnnual?: number
|
||||
lastYearCarryoverActual?: number
|
||||
lastYearCarryoverValue?: number
|
||||
lastYearCarryoverExecutionRate?: number
|
||||
lastYearCarryoverScore?: number
|
||||
lastYearCarryoverInitial?: number;
|
||||
lastYearCarryoverAnnual?: number;
|
||||
lastYearCarryoverActual?: number;
|
||||
lastYearCarryoverValue?: number;
|
||||
lastYearCarryoverExecutionRate?: number;
|
||||
lastYearCarryoverScore?: number;
|
||||
|
||||
// 其他资金
|
||||
otherFundsInitial?: number
|
||||
otherFundsAnnual?: number
|
||||
otherFundsActual?: number
|
||||
otherFundsValue?: number
|
||||
otherFundsExecutionRate?: number
|
||||
otherFundsScore?: number
|
||||
otherFundsInitial?: number;
|
||||
otherFundsAnnual?: number;
|
||||
otherFundsActual?: number;
|
||||
otherFundsValue?: number;
|
||||
otherFundsExecutionRate?: number;
|
||||
otherFundsScore?: number;
|
||||
|
||||
performanceGoal?: string
|
||||
targetCompletion?: string
|
||||
performanceGoal?: string;
|
||||
targetCompletion?: string;
|
||||
|
||||
// 数量指标
|
||||
quantityIndicator?: string
|
||||
quantityTarget?: string
|
||||
quantityActual?: string
|
||||
quantityValue?: number
|
||||
quantityScore?: number
|
||||
quantityDeviation?: string
|
||||
quantityIndicator?: string;
|
||||
quantityTarget?: string;
|
||||
quantityActual?: string;
|
||||
quantityValue?: number;
|
||||
quantityScore?: number;
|
||||
quantityDeviation?: string;
|
||||
|
||||
// 质量指标
|
||||
qualityIndicator?: string
|
||||
qualityTarget?: string
|
||||
qualityActual?: string
|
||||
qualityValue?: number
|
||||
qualityScore?: number
|
||||
qualityDeviation?: string
|
||||
qualityIndicator?: string;
|
||||
qualityTarget?: string;
|
||||
qualityActual?: string;
|
||||
qualityValue?: number;
|
||||
qualityScore?: number;
|
||||
qualityDeviation?: string;
|
||||
|
||||
// 时效指标
|
||||
timelinessIndicator?: string
|
||||
timelinessTarget?: string
|
||||
timelinessActual?: string
|
||||
timelinessValue?: number
|
||||
timelinessScore?: number
|
||||
timelinessDeviation?: string
|
||||
timelinessIndicator?: string;
|
||||
timelinessTarget?: string;
|
||||
timelinessActual?: string;
|
||||
timelinessValue?: number;
|
||||
timelinessScore?: number;
|
||||
timelinessDeviation?: string;
|
||||
|
||||
// 成本指标
|
||||
costIndicator?: string
|
||||
costTarget?: string
|
||||
costActual?: string
|
||||
costValue?: number
|
||||
costScore?: number
|
||||
costDeviation?: string
|
||||
costIndicator?: string;
|
||||
costTarget?: string;
|
||||
costActual?: string;
|
||||
costValue?: number;
|
||||
costScore?: number;
|
||||
costDeviation?: string;
|
||||
|
||||
// 经济效益指标
|
||||
economicIndicator?: string
|
||||
economicTarget?: string
|
||||
economicActual?: string
|
||||
economicValue?: number
|
||||
economicScore?: number
|
||||
economicDeviation?: string
|
||||
economicIndicator?: string;
|
||||
economicTarget?: string;
|
||||
economicActual?: string;
|
||||
economicValue?: number;
|
||||
economicScore?: number;
|
||||
economicDeviation?: string;
|
||||
|
||||
// 社会效益指标
|
||||
socialIndicator?: string
|
||||
socialTarget?: string
|
||||
socialActual?: string
|
||||
socialValue?: number
|
||||
socialScore?: number
|
||||
socialDeviation?: string
|
||||
socialIndicator?: string;
|
||||
socialTarget?: string;
|
||||
socialActual?: string;
|
||||
socialValue?: number;
|
||||
socialScore?: number;
|
||||
socialDeviation?: string;
|
||||
|
||||
// 生态效益指标
|
||||
ecologicalIndicator?: string
|
||||
ecologicalTarget?: string
|
||||
ecologicalActual?: string
|
||||
ecologicalValue?: number
|
||||
ecologicalScore?: number
|
||||
ecologicalDeviation?: string
|
||||
ecologicalIndicator?: string;
|
||||
ecologicalTarget?: string;
|
||||
ecologicalActual?: string;
|
||||
ecologicalValue?: number;
|
||||
ecologicalScore?: number;
|
||||
ecologicalDeviation?: string;
|
||||
|
||||
// 满意度指标
|
||||
satisfactionIndicator?: string
|
||||
satisfactionTarget?: string
|
||||
satisfactionActual?: string
|
||||
satisfactionValue?: number
|
||||
satisfactionScore?: number
|
||||
satisfactionDeviation?: string
|
||||
satisfactionIndicator?: string;
|
||||
satisfactionTarget?: string;
|
||||
satisfactionActual?: string;
|
||||
satisfactionValue?: number;
|
||||
satisfactionScore?: number;
|
||||
satisfactionDeviation?: string;
|
||||
|
||||
decisionScore?: number
|
||||
decisionContent?: string
|
||||
processScore?: number
|
||||
processContent?: string
|
||||
outputScore?: number
|
||||
outputContent?: string
|
||||
benefitScore?: number
|
||||
benefitContent?: string
|
||||
totalScore?: number
|
||||
selfEvaluationLevel?: string
|
||||
existingProblems?: string
|
||||
improvementMeasures?: string
|
||||
evaluationStatus?: string
|
||||
remark?: string
|
||||
decisionScore?: number;
|
||||
decisionContent?: string;
|
||||
processScore?: number;
|
||||
processContent?: string;
|
||||
outputScore?: number;
|
||||
outputContent?: string;
|
||||
benefitScore?: number;
|
||||
benefitContent?: string;
|
||||
totalScore?: number;
|
||||
selfEvaluationLevel?: string;
|
||||
existingProblems?: string;
|
||||
improvementMeasures?: string;
|
||||
evaluationStatus?: string;
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 项目绩效自评查询对象
|
||||
*/
|
||||
export interface CwProjectPerformanceSelfEvaluationQuery {
|
||||
pageNum?: number
|
||||
pageSize?: number
|
||||
projectApplicationId?: number
|
||||
applicationNo?: string
|
||||
projectName?: string
|
||||
evaluationYear?: number
|
||||
evaluationStatus?: string
|
||||
selfEvaluationLevel?: string
|
||||
pageNum?: number;
|
||||
pageSize?: number;
|
||||
projectApplicationId?: number;
|
||||
applicationNo?: string;
|
||||
projectName?: string;
|
||||
evaluationYear?: number;
|
||||
evaluationStatus?: string;
|
||||
selfEvaluationLevel?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -311,7 +311,7 @@ export function listEvaluation(query: CwProjectPerformanceSelfEvaluationQuery):
|
||||
url: '/cw/evaluation/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -321,7 +321,7 @@ export function getEvaluation(id: number): AxiosPromise<CwProjectPerformanceSelf
|
||||
return request({
|
||||
url: `/cw/evaluation/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -332,7 +332,7 @@ export function addEvaluation(data: CwProjectPerformanceSelfEvaluationForm): Axi
|
||||
url: '/cw/evaluation',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -343,7 +343,7 @@ export function updateEvaluation(data: CwProjectPerformanceSelfEvaluationForm):
|
||||
url: '/cw/evaluation',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -354,7 +354,7 @@ export function saveDraft(data: CwProjectPerformanceSelfEvaluationForm): AxiosPr
|
||||
url: '/cw/evaluation/saveDraft',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -364,7 +364,7 @@ export function submitEvaluation(id: number): AxiosPromise<any> {
|
||||
return request({
|
||||
url: `/cw/evaluation/submit/${id}`,
|
||||
method: 'post'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -375,7 +375,7 @@ export function approveEvaluation(id: number, opinion: string, approved: boolean
|
||||
url: `/cw/evaluation/approve/${id}`,
|
||||
method: 'post',
|
||||
params: { opinion, approved }
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -385,7 +385,7 @@ export function delEvaluation(ids: number | number[]): AxiosPromise<any> {
|
||||
return request({
|
||||
url: `/cw/evaluation/${ids}`,
|
||||
method: 'delete'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -395,7 +395,7 @@ export function getMyEvaluations(): AxiosPromise<CwProjectPerformanceSelfEvaluat
|
||||
return request({
|
||||
url: '/cw/evaluation/my',
|
||||
method: 'get'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -405,7 +405,7 @@ export function getPendingApprovals(): AxiosPromise<CwProjectPerformanceSelfEval
|
||||
return request({
|
||||
url: '/cw/evaluation/pending',
|
||||
method: 'get'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -417,7 +417,7 @@ export function exportEvaluation(query: CwProjectPerformanceSelfEvaluationQuery)
|
||||
method: 'post',
|
||||
data: query,
|
||||
responseType: 'blob'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// ========== 月度运行监控API ==========
|
||||
@@ -426,59 +426,59 @@ export function exportEvaluation(query: CwProjectPerformanceSelfEvaluationQuery)
|
||||
* 项目月度运行监控视图对象
|
||||
*/
|
||||
export interface CwProjectMonthlyMonitoringVO {
|
||||
id?: number
|
||||
evaluationId: number
|
||||
projectApplicationId: number
|
||||
monitoringYear: number
|
||||
monitoringMonth: number
|
||||
plannedProgress?: number
|
||||
actualProgress?: number
|
||||
progressVariance?: number
|
||||
monthlyBudget?: number
|
||||
monthlyExpenditure?: number
|
||||
cumulativeBudget?: number
|
||||
cumulativeExpenditure?: number
|
||||
fundExecutionRate?: number
|
||||
keyMilestones?: string
|
||||
milestoneCompletion?: string
|
||||
problemsEncountered?: string
|
||||
riskDescription?: string
|
||||
countermeasures?: string
|
||||
nextMonthPlan?: string
|
||||
fillStatus: string
|
||||
fillTime?: string
|
||||
fillBy?: number
|
||||
fillByName?: string
|
||||
remark?: string
|
||||
createTime?: string
|
||||
updateTime?: string
|
||||
id?: number;
|
||||
evaluationId: number;
|
||||
projectApplicationId: number;
|
||||
monitoringYear: number;
|
||||
monitoringMonth: number;
|
||||
plannedProgress?: number;
|
||||
actualProgress?: number;
|
||||
progressVariance?: number;
|
||||
monthlyBudget?: number;
|
||||
monthlyExpenditure?: number;
|
||||
cumulativeBudget?: number;
|
||||
cumulativeExpenditure?: number;
|
||||
fundExecutionRate?: number;
|
||||
keyMilestones?: string;
|
||||
milestoneCompletion?: string;
|
||||
problemsEncountered?: string;
|
||||
riskDescription?: string;
|
||||
countermeasures?: string;
|
||||
nextMonthPlan?: string;
|
||||
fillStatus: string;
|
||||
fillTime?: string;
|
||||
fillBy?: number;
|
||||
fillByName?: string;
|
||||
remark?: string;
|
||||
createTime?: string;
|
||||
updateTime?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 项目月度运行监控表单对象
|
||||
*/
|
||||
export interface CwProjectMonthlyMonitoringForm {
|
||||
id?: number
|
||||
evaluationId: number
|
||||
projectApplicationId: number
|
||||
monitoringYear: number
|
||||
monitoringMonth: number
|
||||
plannedProgress?: number
|
||||
actualProgress?: number
|
||||
progressVariance?: number
|
||||
monthlyBudget?: number
|
||||
monthlyExpenditure?: number
|
||||
cumulativeBudget?: number
|
||||
cumulativeExpenditure?: number
|
||||
fundExecutionRate?: number
|
||||
keyMilestones?: string
|
||||
milestoneCompletion?: string
|
||||
problemsEncountered?: string
|
||||
riskDescription?: string
|
||||
countermeasures?: string
|
||||
nextMonthPlan?: string
|
||||
fillStatus?: string
|
||||
remark?: string
|
||||
id?: number;
|
||||
evaluationId: number;
|
||||
projectApplicationId: number;
|
||||
monitoringYear: number;
|
||||
monitoringMonth: number;
|
||||
plannedProgress?: number;
|
||||
actualProgress?: number;
|
||||
progressVariance?: number;
|
||||
monthlyBudget?: number;
|
||||
monthlyExpenditure?: number;
|
||||
cumulativeBudget?: number;
|
||||
cumulativeExpenditure?: number;
|
||||
fundExecutionRate?: number;
|
||||
keyMilestones?: string;
|
||||
milestoneCompletion?: string;
|
||||
problemsEncountered?: string;
|
||||
riskDescription?: string;
|
||||
countermeasures?: string;
|
||||
nextMonthPlan?: string;
|
||||
fillStatus?: string;
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -488,7 +488,7 @@ export function getYearlyMonitoring(evaluationId: number, year: number): AxiosPr
|
||||
return request({
|
||||
url: `/cw/monitoring/year/${evaluationId}/${year}`,
|
||||
method: 'get'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -498,7 +498,7 @@ export function getMonitoringByEvaluationId(evaluationId: number): AxiosPromise<
|
||||
return request({
|
||||
url: `/cw/monitoring/evaluation/${evaluationId}`,
|
||||
method: 'get'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -509,7 +509,7 @@ export function fillMonthlyData(data: CwProjectMonthlyMonitoringForm): AxiosProm
|
||||
url: '/cw/monitoring/fill',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -523,7 +523,7 @@ export function batchSaveMonitoring(evaluationId: number, list: CwProjectMonthly
|
||||
evaluationId,
|
||||
list
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -534,7 +534,7 @@ export function updateMonitoring(data: CwProjectMonthlyMonitoringForm): AxiosPro
|
||||
url: '/cw/monitoring',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// ========== 绩效运行监控API ==========
|
||||
@@ -543,36 +543,36 @@ export function updateMonitoring(data: CwProjectMonthlyMonitoringForm): AxiosPro
|
||||
* 绩效运行监控视图对象
|
||||
*/
|
||||
export interface CwPerformanceMonitoringVO {
|
||||
id?: number
|
||||
evaluationId: number
|
||||
monitoringPeriod: string
|
||||
fundUsage: string
|
||||
performanceTargetCompletion: string
|
||||
indicators?: string // JSON字符串,存储指标数组
|
||||
existingProblems?: string
|
||||
indicatorVarianceAnalysis?: string
|
||||
nextStepSuggestions?: string
|
||||
fillBy?: number
|
||||
fillByName?: string
|
||||
createTime?: string
|
||||
updateTime?: string
|
||||
id?: number;
|
||||
evaluationId: number;
|
||||
monitoringPeriod: string;
|
||||
fundUsage: string;
|
||||
performanceTargetCompletion: string;
|
||||
indicators?: string; // JSON字符串,存储指标数组
|
||||
existingProblems?: string;
|
||||
indicatorVarianceAnalysis?: string;
|
||||
nextStepSuggestions?: string;
|
||||
fillBy?: number;
|
||||
fillByName?: string;
|
||||
createTime?: string;
|
||||
updateTime?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绩效运行监控表单数据结构
|
||||
*/
|
||||
export interface PerformanceMonitoringForm {
|
||||
id?: number
|
||||
evaluationId: number
|
||||
monitoringPeriod: string
|
||||
fundUsage: string
|
||||
performanceTargetCompletion: string
|
||||
indicators: string // JSON字符串,存储指标数组
|
||||
existingProblems?: string
|
||||
indicatorVarianceAnalysis?: string
|
||||
nextStepSuggestions?: string
|
||||
fillByName?: string
|
||||
createTime?: string
|
||||
id?: number;
|
||||
evaluationId: number;
|
||||
monitoringPeriod: string;
|
||||
fundUsage: string;
|
||||
performanceTargetCompletion: string;
|
||||
indicators: string; // JSON字符串,存储指标数组
|
||||
existingProblems?: string;
|
||||
indicatorVarianceAnalysis?: string;
|
||||
nextStepSuggestions?: string;
|
||||
fillByName?: string;
|
||||
createTime?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -582,7 +582,7 @@ export function listPerformanceMonitoring(evaluationId: number): AxiosPromise<Pe
|
||||
return request({
|
||||
url: `/cw/performanceMonitoring/list/${evaluationId}`,
|
||||
method: 'get'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -592,7 +592,7 @@ export function getPerformanceMonitoring(id: number): AxiosPromise<PerformanceMo
|
||||
return request({
|
||||
url: `/cw/performanceMonitoring/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -603,7 +603,7 @@ export function addPerformanceMonitoring(data: PerformanceMonitoringForm): Axios
|
||||
url: '/cw/performanceMonitoring',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -614,7 +614,7 @@ export function updatePerformanceMonitoring(data: PerformanceMonitoringForm): Ax
|
||||
url: '/cw/performanceMonitoring',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -624,6 +624,5 @@ export function delPerformanceMonitoring(id: number): AxiosPromise<any> {
|
||||
return request({
|
||||
url: `/cw/performanceMonitoring/${id}`,
|
||||
method: 'delete'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ export interface BatchAddDetailRequest {
|
||||
nickName: string;
|
||||
deptId: string | number;
|
||||
deptName: string;
|
||||
phoneNumber: string; // 注意:这里使用驼峰命名,确保与数据库字段映射
|
||||
phoneNumber: string; // 注意:这里使用驼峰命名,确保与数据库字段映射
|
||||
email: string;
|
||||
}>;
|
||||
remark?: string;
|
||||
|
||||
+11
-11
@@ -93,11 +93,11 @@ export interface OverseasApplicationVO {
|
||||
administrativeLevelText?: string;
|
||||
personnelCategoryText?: string;
|
||||
// 工作流相关字段
|
||||
approvalStatus?: string; // 工作流审批状态:draft/waiting/finish/back/cancel
|
||||
approvalStatusText?: string; // 工作流审批状态文本
|
||||
taskId?: string; // 当前待办任务ID(用于审批跳转)
|
||||
approvalStatus?: string; // 工作流审批状态:draft/waiting/finish/back/cancel
|
||||
approvalStatusText?: string; // 工作流审批状态文本
|
||||
taskId?: string; // 当前待办任务ID(用于审批跳转)
|
||||
// 附件相关字段
|
||||
attachmentIds?: string; // 附件OSS ID列表(逗号分隔)
|
||||
attachmentIds?: string; // 附件OSS ID列表(逗号分隔)
|
||||
}
|
||||
|
||||
// 出国申请表单类型
|
||||
@@ -152,9 +152,9 @@ export interface OverseasApplicationForm {
|
||||
transportationPlan?: string;
|
||||
applicantRemark?: string;
|
||||
// 工作流相关字段
|
||||
approvalStatus?: string; // 工作流审批状态
|
||||
approvalStatus?: string; // 工作流审批状态
|
||||
// 附件相关字段
|
||||
attachmentIds?: string; // 附件OSS ID列表(逗号分隔)
|
||||
attachmentIds?: string; // 附件OSS ID列表(逗号分隔)
|
||||
}
|
||||
|
||||
// 审批请求类型(支持标准工作流模式)
|
||||
@@ -353,13 +353,13 @@ export function listPendingOverseasApplicationPage(query: OverseasApplicationQue
|
||||
|
||||
// ========================================
|
||||
// 🚨 标准化改造:删除自定义待审批查询API
|
||||
//
|
||||
//
|
||||
// 原因:出国申请工作流应使用标准工作流模式
|
||||
// 用户应通过工作流API pageByTaskWait() 获取待办任务
|
||||
// 而不是调用自定义的业务API
|
||||
//
|
||||
//
|
||||
// 删除的API:listPendingOverseasApplication()
|
||||
//
|
||||
//
|
||||
// 标准工作流模式:
|
||||
// 1. 导入工作流API:import { pageByTaskWait } from '@/api/workflow/task'
|
||||
// 2. 调用标准API:pageByTaskWait(queryParams)
|
||||
@@ -865,9 +865,9 @@ export interface ItineraryChangeVO {
|
||||
// 行程变更表单类型
|
||||
export interface ItineraryChangeForm {
|
||||
changeId?: number | string;
|
||||
recordId: number; // 关联出国记录ID(必填)
|
||||
recordId: number; // 关联出国记录ID(必填)
|
||||
applicationId: number;
|
||||
applicantId: number; // 申请人ID(必填)
|
||||
applicantId: number; // 申请人ID(必填)
|
||||
applicantName?: string;
|
||||
gender?: string;
|
||||
birthDate?: string;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import request from '@/utils/request'
|
||||
import request from '@/utils/request';
|
||||
|
||||
// API基础路径
|
||||
const baseUrl = '/rs/overseas/monitor'
|
||||
const baseUrl = '/rs/overseas/monitor';
|
||||
|
||||
/**
|
||||
* 查询审批中的申请列表
|
||||
@@ -9,11 +9,11 @@ const baseUrl = '/rs/overseas/monitor'
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function getPendingList(query) {
|
||||
return request({
|
||||
url: `${baseUrl}/pending/list`,
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
return request({
|
||||
url: `${baseUrl}/pending/list`,
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -22,11 +22,11 @@ export function getPendingList(query) {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function getCompletedList(query) {
|
||||
return request({
|
||||
url: `${baseUrl}/completed/list`,
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
return request({
|
||||
url: `${baseUrl}/completed/list`,
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,10 +35,10 @@ export function getCompletedList(query) {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function getApprovalHistory(applicationId) {
|
||||
return request({
|
||||
url: `${baseUrl}/history/${applicationId}`,
|
||||
method: 'get'
|
||||
})
|
||||
return request({
|
||||
url: `${baseUrl}/history/${applicationId}`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,10 +47,10 @@ export function getApprovalHistory(applicationId) {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function getDetail(applicationId) {
|
||||
return request({
|
||||
url: `${baseUrl}/detail/${applicationId}`,
|
||||
method: 'get'
|
||||
})
|
||||
return request({
|
||||
url: `${baseUrl}/detail/${applicationId}`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,12 +59,12 @@ export function getDetail(applicationId) {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function exportPending(query) {
|
||||
return request({
|
||||
url: `${baseUrl}/pending/export`,
|
||||
method: 'post',
|
||||
data: query,
|
||||
responseType: 'blob'
|
||||
})
|
||||
return request({
|
||||
url: `${baseUrl}/pending/export`,
|
||||
method: 'post',
|
||||
data: query,
|
||||
responseType: 'blob'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,12 +73,12 @@ export function exportPending(query) {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function exportCompleted(query) {
|
||||
return request({
|
||||
url: `${baseUrl}/completed/export`,
|
||||
method: 'post',
|
||||
data: query,
|
||||
responseType: 'blob'
|
||||
})
|
||||
return request({
|
||||
url: `${baseUrl}/completed/export`,
|
||||
method: 'post',
|
||||
data: query,
|
||||
responseType: 'blob'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,9 +86,8 @@ export function exportCompleted(query) {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function getStatistics() {
|
||||
return request({
|
||||
url: `${baseUrl}/statistics`,
|
||||
method: 'get'
|
||||
})
|
||||
return request({
|
||||
url: `${baseUrl}/statistics`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { StaffInfoQuery, StaffInfoVO, StaffInfoForm, DeptTreeVO, R, TableDataInfo } from './types';
|
||||
|
||||
/**
|
||||
* 查询人员信息列表
|
||||
* @param query 查询参数
|
||||
*/
|
||||
export function listStaffInfo(query?: StaffInfoQuery): AxiosPromise<R<TableDataInfo<StaffInfoVO[]>>> {
|
||||
return request({
|
||||
url: '/staff/staffInfo/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据部门ID查询人员信息列表
|
||||
* @param query 查询参数
|
||||
*/
|
||||
export function listStaffInfoByDeptId(query?: any): AxiosPromise<R<TableDataInfo<StaffInfoVO[]>>> {
|
||||
return request({
|
||||
url: '/staff/staffInfo/listByDeptId',
|
||||
method: 'post',
|
||||
data: query
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取人员信息详细信息
|
||||
* @param id 人员ID
|
||||
*/
|
||||
export function getStaffInfo(id: number | string): AxiosPromise<R<StaffInfoVO>> {
|
||||
return request({
|
||||
url: '/staff/staffInfo/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增人员信息
|
||||
* @param data 人员信息
|
||||
*/
|
||||
export function addStaffInfo(data: StaffInfoForm): AxiosPromise<R<void>> {
|
||||
return request({
|
||||
url: '/staff/staffInfo',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改人员信息
|
||||
* @param data 人员信息
|
||||
*/
|
||||
export function updateStaffInfo(data: StaffInfoForm): AxiosPromise<R<void>> {
|
||||
return request({
|
||||
url: '/staff/staffInfo',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除人员信息
|
||||
* @param ids 人员ID数组
|
||||
*/
|
||||
export function delStaffInfo(ids: (number | string)[]): AxiosPromise<R<void>> {
|
||||
return request({
|
||||
url: '/staff/staffInfo/' + ids.join(','),
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取部门树形数据
|
||||
*/
|
||||
export function getDeptTree(): AxiosPromise<R<DeptTreeVO[]>> {
|
||||
return request({
|
||||
url: '/staff/staffInfo/deptTree',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出人员信息
|
||||
* @param query 查询参数
|
||||
*/
|
||||
export function exportStaffInfo(query?: StaffInfoQuery): AxiosPromise<any> {
|
||||
return request({
|
||||
url: '/staff/staffInfo/export',
|
||||
method: 'post',
|
||||
params: query,
|
||||
responseType: 'blob'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载人员信息导入模板
|
||||
*/
|
||||
export function downloadImportTemplate(): AxiosPromise<any> {
|
||||
return request({
|
||||
url: '/staff/staffInfo/importTemplate',
|
||||
method: 'post',
|
||||
responseType: 'blob'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入人员数据
|
||||
* @param file 上传的文件
|
||||
* @param deptId 部门ID
|
||||
* @param updateSupport 是否支持更新
|
||||
*/
|
||||
export function importStaffInfo(file: File, deptId?: string, updateSupport: boolean = false): AxiosPromise<R<string>> {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
if (deptId) {
|
||||
formData.append('deptId', deptId);
|
||||
}
|
||||
formData.append('updateSupport', updateSupport.toString());
|
||||
|
||||
return request({
|
||||
url: '/staff/staffInfo/importData',
|
||||
method: 'post',
|
||||
data: formData,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* 人员信息查询参数
|
||||
*/
|
||||
export interface StaffInfoQuery {
|
||||
pageNum: number;
|
||||
pageSize: number;
|
||||
name?: string;
|
||||
staffNo?: string;
|
||||
phone?: string;
|
||||
staffType?: string;
|
||||
status?: string;
|
||||
deptId?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 人员信息视图对象
|
||||
*/
|
||||
export interface StaffInfoVO {
|
||||
id: number | string;
|
||||
staffNo: string;
|
||||
name: string;
|
||||
gender: string;
|
||||
position: string;
|
||||
deptId: number;
|
||||
deptName: string;
|
||||
phone: string;
|
||||
staffType: string;
|
||||
userId?: number;
|
||||
status: string;
|
||||
createTime?: string;
|
||||
updateTime?: string;
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 人员信息表单对象
|
||||
*/
|
||||
export interface StaffInfoForm {
|
||||
id?: number | string;
|
||||
staffNo?: string;
|
||||
name: string;
|
||||
gender: string;
|
||||
position: string;
|
||||
deptId: number;
|
||||
deptName?: string;
|
||||
phone: string;
|
||||
staffType: string;
|
||||
status?: string;
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 人员信息导入VO
|
||||
*/
|
||||
export interface StaffInfoImportVo {
|
||||
staffNo?: string;
|
||||
name: string;
|
||||
gender: string;
|
||||
position?: string;
|
||||
deptName: string;
|
||||
phone: string;
|
||||
staffType: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 部门树结构
|
||||
*/
|
||||
export interface DeptTreeVO {
|
||||
deptId: number;
|
||||
parentId: number;
|
||||
deptName: string;
|
||||
children?: DeptTreeVO[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用响应对象
|
||||
*/
|
||||
export interface R<T = any> {
|
||||
code: number;
|
||||
msg: string;
|
||||
data: T;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页数据信息
|
||||
*/
|
||||
export interface TableDataInfo<T = any> {
|
||||
total: number;
|
||||
rows: T[];
|
||||
code: number;
|
||||
msg: string;
|
||||
}
|
||||
+29
-29
@@ -70,15 +70,15 @@ export interface ApplicationVO {
|
||||
userName: string;
|
||||
department: string;
|
||||
position?: string;
|
||||
currentTitle?: string; // 现职称
|
||||
currentPosition?: string; // 现岗位
|
||||
workStartTime?: string; // 参加工作时间
|
||||
phone?: string; // 联系电话
|
||||
organizerUnit?: string; // 主办单位
|
||||
trainingType?: string; // 培训类型
|
||||
trainingFee?: number; // 培训费用
|
||||
companions?: string; // 同行人员(JSON字符串)
|
||||
trainingPurpose?: string; // 培训目的
|
||||
currentTitle?: string; // 现职称
|
||||
currentPosition?: string; // 现岗位
|
||||
workStartTime?: string; // 参加工作时间
|
||||
phone?: string; // 联系电话
|
||||
organizerUnit?: string; // 主办单位
|
||||
trainingType?: string; // 培训类型
|
||||
trainingFee?: number; // 培训费用
|
||||
companions?: string; // 同行人员(JSON字符串)
|
||||
trainingPurpose?: string; // 培训目的
|
||||
reason?: string;
|
||||
status: string;
|
||||
applyTime: string;
|
||||
@@ -87,12 +87,12 @@ export interface ApplicationVO {
|
||||
duration?: number;
|
||||
startTime?: string;
|
||||
endTime?: string;
|
||||
rejectTime?: string; // 拒绝时间
|
||||
attachmentIds?: string; // 附件ID列表
|
||||
rejectTime?: string; // 拒绝时间
|
||||
attachmentIds?: string; // 附件ID列表
|
||||
createTime: string;
|
||||
updateTime: string;
|
||||
createBy: number; // 修正类型:string -> number
|
||||
updateBy: number; // 修正类型:string -> number
|
||||
createBy: number; // 修正类型:string -> number
|
||||
updateBy: number; // 修正类型:string -> number
|
||||
remark: string;
|
||||
}
|
||||
|
||||
@@ -105,23 +105,23 @@ export interface ApplicationForm {
|
||||
userName?: string;
|
||||
department?: string;
|
||||
position?: string;
|
||||
currentTitle?: string; // 现职称
|
||||
currentPosition?: string; // 现岗位
|
||||
workStartTime?: string; // 参加工作时间
|
||||
phone?: string; // 联系电话
|
||||
organizerUnit?: string; // 主办单位
|
||||
trainingType?: string; // 培训类型
|
||||
trainingTypeOther?: string; // 其他培训类型描述
|
||||
trainingFee?: number; // 培训费用
|
||||
currentTitle?: string; // 现职称
|
||||
currentPosition?: string; // 现岗位
|
||||
workStartTime?: string; // 参加工作时间
|
||||
phone?: string; // 联系电话
|
||||
organizerUnit?: string; // 主办单位
|
||||
trainingType?: string; // 培训类型
|
||||
trainingTypeOther?: string; // 其他培训类型描述
|
||||
trainingFee?: number; // 培训费用
|
||||
companions?: (string | number)[]; // 同行人员数组
|
||||
trainingPurpose?: string; // 培训目的
|
||||
trainingPurpose?: string; // 培训目的
|
||||
reason?: string;
|
||||
status?: string;
|
||||
location?: string;
|
||||
duration?: number;
|
||||
startTime?: string;
|
||||
endTime?: string;
|
||||
attachmentIds?: string[]; // 附件ID数组
|
||||
attachmentIds?: string[]; // 附件ID数组
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
@@ -164,11 +164,11 @@ export interface RecordVO {
|
||||
updateBy: string;
|
||||
remark: string;
|
||||
// 关联字段 - 从申请表获取
|
||||
organizerUnit?: string; // 主办单位
|
||||
trainingType?: string; // 培训类型
|
||||
companions?: string; // 同行人员
|
||||
startTime?: string; // 开始时间
|
||||
endTime?: string; // 结束时间
|
||||
organizerUnit?: string; // 主办单位
|
||||
trainingType?: string; // 培训类型
|
||||
companions?: string; // 同行人员
|
||||
startTime?: string; // 开始时间
|
||||
endTime?: string; // 结束时间
|
||||
}
|
||||
|
||||
// 培训记录表单类型
|
||||
@@ -440,7 +440,7 @@ export function updateRecordAttachments(recordId: string | number, data: { attac
|
||||
// 审批培训申请(7级审批制度)
|
||||
export function approveTrainingApplication(data: {
|
||||
applicationId: number | string;
|
||||
approvalStatus: string; // 1-通过,2-拒绝
|
||||
approvalStatus: string; // 1-通过,2-拒绝
|
||||
approvalOpinion?: string;
|
||||
approvalSignature?: string; // base64格式
|
||||
}) {
|
||||
|
||||
@@ -128,4 +128,3 @@ export const delActivityAudit = (id: string | number | Array<string | number>) =
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import request from '@/utils/request'
|
||||
import { AxiosPromise } from 'axios'
|
||||
import { StglAuditorVO, StglAuditorForm, StglAuditorQuery } from './types'
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { StglAuditorVO, StglAuditorForm, StglAuditorQuery } from './types';
|
||||
|
||||
/**
|
||||
* 查询社团管理审核人配置列表
|
||||
@@ -13,8 +13,8 @@ export const listStglAuditor = (query?: StglAuditorQuery): AxiosPromise<StglAudi
|
||||
url: '/stgl/auditor/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询社团管理审核人配置详细
|
||||
@@ -24,8 +24,8 @@ export const getStglAuditor = (id: string | number): AxiosPromise<StglAuditorVO>
|
||||
return request({
|
||||
url: '/stgl/auditor/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 新增社团管理审核人配置
|
||||
@@ -36,8 +36,8 @@ export const addStglAuditor = (data: StglAuditorForm) => {
|
||||
url: '/stgl/auditor',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 修改社团管理审核人配置
|
||||
@@ -48,8 +48,8 @@ export const updateStglAuditor = (data: StglAuditorForm) => {
|
||||
url: '/stgl/auditor',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除社团管理审核人配置
|
||||
@@ -59,8 +59,8 @@ export const delStglAuditor = (id: string | number | Array<string | number>) =>
|
||||
return request({
|
||||
url: '/stgl/auditor/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 导出社团管理审核人配置
|
||||
@@ -73,8 +73,8 @@ export const exportStglAuditor = (query?: StglAuditorQuery) => {
|
||||
method: 'post',
|
||||
data: query,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量添加审核人
|
||||
@@ -89,8 +89,8 @@ export const batchAddAuditors = (userIds: number[], remark?: string) => {
|
||||
userIds,
|
||||
remark
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询我配置的审核人列表
|
||||
@@ -101,8 +101,8 @@ export const listMyConfigAuditors = (query?: StglAuditorQuery): AxiosPromise<Stg
|
||||
url: '/stgl/auditor/myConfig',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量启用审核人
|
||||
@@ -113,8 +113,8 @@ export const enableAuditors = (ids: number[]) => {
|
||||
url: '/stgl/auditor/enable',
|
||||
method: 'post',
|
||||
data: ids
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量停用审核人
|
||||
@@ -125,8 +125,8 @@ export const disableAuditors = (ids: number[]) => {
|
||||
url: '/stgl/auditor/disable',
|
||||
method: 'post',
|
||||
data: ids
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 根据部门ID获取用户列表
|
||||
@@ -136,5 +136,5 @@ export const listUserByDeptId = (deptId: string | number) => {
|
||||
return request({
|
||||
url: '/stgl/auditor/users/' + deptId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PageQuery } from '@/api/types'
|
||||
import { PageQuery } from '@/api/types';
|
||||
|
||||
export interface StglAuditorVO {
|
||||
/**
|
||||
@@ -145,7 +145,6 @@ export interface StglAuditorForm {
|
||||
}
|
||||
|
||||
export interface StglAuditorQuery extends PageQuery {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@@ -176,9 +175,9 @@ export interface StglAuditorQuery extends PageQuery {
|
||||
*/
|
||||
configBy?: number;
|
||||
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
'params[beginCreateTime]'?: string;
|
||||
'params[endCreateTime]'?: string;
|
||||
}
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
'params[beginCreateTime]'?: string;
|
||||
'params[endCreateTime]'?: string;
|
||||
}
|
||||
@@ -176,10 +176,10 @@ export interface StglClubAdvisorHistoryQuery extends PageQuery {
|
||||
*/
|
||||
endTime?: string;
|
||||
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
params?: any;
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
params?: any;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -273,4 +273,4 @@ export const delStglClubAdvisorHistory = (id: string | number | Array<string | n
|
||||
url: '/stgl/club/advisor/history/' + id,
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
};
|
||||
@@ -124,12 +124,7 @@ export const withdrawStglClubAnnualReview = (id: string | number) => {
|
||||
* 审核年审记录
|
||||
* @param params
|
||||
*/
|
||||
export const auditStglClubAnnualReview = (params: {
|
||||
id: string | number;
|
||||
auditResult: string;
|
||||
auditOpinion?: string;
|
||||
auditType: string;
|
||||
}) => {
|
||||
export const auditStglClubAnnualReview = (params: { id: string | number; auditResult: string; auditOpinion?: string; auditType: string }) => {
|
||||
return request({
|
||||
url: '/stgl/club/annualReview/audit',
|
||||
method: 'post',
|
||||
@@ -205,7 +200,7 @@ export const getClubActivitiesByReviewYear = (clubId: string | number, reviewYea
|
||||
isEncrypt: 'true'
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取年审记录的活动数据(从stgl_club_annual_review_activity表中获取)
|
||||
@@ -219,4 +214,4 @@ export const getAnnualReviewActivities = (annualReviewId: string | number) => {
|
||||
isEncrypt: 'true'
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
@@ -320,4 +320,4 @@ export const ANNUAL_REVIEW_STATUS_OPTIONS = [
|
||||
export const YES_NO_OPTIONS = [
|
||||
{ label: '是', value: 'Y' },
|
||||
{ label: '否', value: 'N' }
|
||||
];
|
||||
];
|
||||
@@ -91,10 +91,10 @@ export const delStglAnnualReviewAudit = (id: string | number | Array<string | nu
|
||||
* @param nextAuditors 下一步审核人列表(可选)
|
||||
*/
|
||||
export const approveAnnualReview = (
|
||||
auditId: string | number,
|
||||
approveResult: string,
|
||||
approveOpinion: string,
|
||||
nextAuditors?: Array<{userId: string | number; userName: string; nickName: string}>
|
||||
auditId: string | number,
|
||||
approveResult: string,
|
||||
approveOpinion: string,
|
||||
nextAuditors?: Array<{ userId: string | number; userName: string; nickName: string }>
|
||||
) => {
|
||||
return request({
|
||||
url: '/stgl/annualReviewAudit/approve',
|
||||
@@ -106,4 +106,4 @@ export const approveAnnualReview = (
|
||||
nextAuditors: nextAuditors || []
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
@@ -179,4 +179,4 @@ export const AUDIT_NODE_STATUS_OPTIONS = [
|
||||
export const APPROVE_RESULT_OPTIONS = [
|
||||
{ label: '通过', value: '通过' },
|
||||
{ label: '不通过', value: '不通过' }
|
||||
];
|
||||
];
|
||||
@@ -1,22 +1,22 @@
|
||||
import request from '@/utils/request'
|
||||
import request from '@/utils/request';
|
||||
|
||||
// 社团活动权限检查结果类型定义
|
||||
export interface ClubActivityPermissionResult {
|
||||
canCreateActivity: boolean
|
||||
status: 'NORMAL' | 'TEMPORARILY_LIMITED' | 'PERMANENTLY_LIMITED'
|
||||
message: string
|
||||
deadlineTime?: string
|
||||
remainingHours?: number
|
||||
remainingDays?: number
|
||||
annualReviewStartTime?: string
|
||||
canCreateActivity: boolean;
|
||||
status: 'NORMAL' | 'TEMPORARILY_LIMITED' | 'PERMANENTLY_LIMITED';
|
||||
message: string;
|
||||
deadlineTime?: string;
|
||||
remainingHours?: number;
|
||||
remainingDays?: number;
|
||||
annualReviewStartTime?: string;
|
||||
}
|
||||
|
||||
// 权限详情类型定义
|
||||
export interface ClubPermissionDetails {
|
||||
permissionResult: ClubActivityPermissionResult
|
||||
isInAnnualReviewWindow: boolean
|
||||
daysUntilNextAnnualReview: number
|
||||
hasSubmittedCurrentYearAnnualReview: boolean
|
||||
permissionResult: ClubActivityPermissionResult;
|
||||
isInAnnualReviewWindow: boolean;
|
||||
daysUntilNextAnnualReview: number;
|
||||
hasSubmittedCurrentYearAnnualReview: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -28,7 +28,7 @@ export function checkClubActivityPermission(clubId: number | string) {
|
||||
return request<ClubActivityPermissionResult>({
|
||||
url: `/stgl/club/permission/checkActivityPermission/${clubId}`,
|
||||
method: 'get'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,7 +41,7 @@ export function batchCheckClubPermission(clubIds: number[]) {
|
||||
url: '/stgl/club/permission/batchCheckPermission',
|
||||
method: 'post',
|
||||
data: clubIds
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,7 +53,7 @@ export function isInAnnualReviewWindow(clubId: number) {
|
||||
return request<boolean>({
|
||||
url: `/stgl/club/permission/isInAnnualReviewWindow/${clubId}`,
|
||||
method: 'get'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,7 +65,7 @@ export function getDaysUntilNextAnnualReview(clubId: number) {
|
||||
return request<number>({
|
||||
url: `/stgl/club/permission/getDaysUntilNextAnnualReview/${clubId}`,
|
||||
method: 'get'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,7 +77,7 @@ export function hasSubmittedCurrentYearAnnualReview(clubId: number) {
|
||||
return request<boolean>({
|
||||
url: `/stgl/club/permission/hasSubmittedCurrentYearAnnualReview/${clubId}`,
|
||||
method: 'get'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,5 +89,5 @@ export function getClubPermissionDetails(clubId: number) {
|
||||
return request<ClubPermissionDetails>({
|
||||
url: `/stgl/club/permission/getPermissionDetails/${clubId}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import request from '@/utils/request'
|
||||
import request from '@/utils/request';
|
||||
|
||||
// 查询操行分列表
|
||||
export function conductScoreList(query: any) {
|
||||
@@ -6,7 +6,7 @@ export function conductScoreList(query: any) {
|
||||
url: '/xg/conduct-score/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// 根据部门ID查询操行分列表(带权限过滤)
|
||||
@@ -15,7 +15,7 @@ export function conductScoreListByDeptId(query: any) {
|
||||
url: '/xg/conduct-score/listByDeptId',
|
||||
method: 'post',
|
||||
data: query
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// 查询操行分详细
|
||||
@@ -23,7 +23,7 @@ export function conductScoreInfo(id: any) {
|
||||
return request({
|
||||
url: '/xg/conduct-score/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// 新增操行分
|
||||
@@ -32,7 +32,7 @@ export function conductScoreAdd(data: any) {
|
||||
url: '/xg/conduct-score',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// 修改操行分
|
||||
@@ -41,7 +41,7 @@ export function conductScoreEdit(data: any) {
|
||||
url: '/xg/conduct-score/' + data.id,
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// 删除操行分
|
||||
@@ -49,7 +49,7 @@ export function conductScoreRemove(ids: any) {
|
||||
return request({
|
||||
url: '/xg/conduct-score/' + ids,
|
||||
method: 'delete'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// 导出操行分
|
||||
@@ -58,7 +58,7 @@ export function conductScoreExport(query: any) {
|
||||
url: '/xg/conduct-score/export',
|
||||
method: 'post',
|
||||
params: query
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// 批量录入操行分
|
||||
@@ -67,7 +67,7 @@ export function conductScoreBatchAdd(data: any) {
|
||||
url: '/xg/conduct-score/batch',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// 获取班主任负责的班级学生列表
|
||||
@@ -76,7 +76,7 @@ export function conductScoreClassStudents(query: any) {
|
||||
url: '/xg/conduct-score/class-students',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// 查询学期平均分统计
|
||||
@@ -85,7 +85,7 @@ export function conductScoreSemesterAverage(query: any) {
|
||||
url: '/xg/conduct-score/semester-average',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// 根据部门ID查询学期平均分统计(带权限过滤)
|
||||
@@ -94,7 +94,7 @@ export function conductScoreSemesterAverageByDeptId(query: any) {
|
||||
url: '/xg/conduct-score/semester-average-by-dept-id',
|
||||
method: 'post',
|
||||
data: query
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// 导出学期统计数据
|
||||
@@ -103,7 +103,7 @@ export function conductScoreExportSemester(query: any) {
|
||||
url: '/xg/conduct-score/export-semester',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// 验证录入权限
|
||||
@@ -112,7 +112,7 @@ export function conductScoreCheckPermission(query: any) {
|
||||
url: '/xg/conduct-score/check-permission',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// 获取学生详细记录(按月份)
|
||||
@@ -121,5 +121,5 @@ export function conductScoreGetStudentRecords(studentId: any, academicYear: any,
|
||||
url: `/xg/conduct-score/student-records/${studentId}`,
|
||||
method: 'get',
|
||||
params: { academicYear, semester, tenantId }
|
||||
})
|
||||
});
|
||||
}
|
||||
@@ -114,4 +114,3 @@ export function exportCollegeLeader(query: any) {
|
||||
responseType: 'blob'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -266,4 +266,3 @@ export function getStudentLeave(id: string | number): AxiosPromise<StudentLeaveV
|
||||
* 获取学生请假详细信息(别名)
|
||||
*/
|
||||
export const getStudentLeaveInfo = getStudentLeave;
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
import request from '@/utils/request'
|
||||
import request from '@/utils/request';
|
||||
|
||||
export interface StudentStatisticsBo {
|
||||
startTime: string
|
||||
endTime: string
|
||||
collegeId?: number
|
||||
majorId?: number
|
||||
classId?: number
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
collegeId?: number;
|
||||
majorId?: number;
|
||||
classId?: number;
|
||||
}
|
||||
|
||||
export interface StatisticsChartData {
|
||||
name: string
|
||||
dormDeductionCount: number
|
||||
dormViolationCount: number
|
||||
dormViolationDeduction: number
|
||||
teachingViolationCount: number
|
||||
teachingViolationDeduction: number
|
||||
name: string;
|
||||
dormDeductionCount: number;
|
||||
dormViolationCount: number;
|
||||
dormViolationDeduction: number;
|
||||
teachingViolationCount: number;
|
||||
teachingViolationDeduction: number;
|
||||
}
|
||||
|
||||
export interface StatisticsDetailData {
|
||||
id: number
|
||||
name: string
|
||||
parentName: string
|
||||
dormDeductionCount: number
|
||||
dormViolationCount: number
|
||||
dormViolationDeduction: number
|
||||
teachingViolationCount: number
|
||||
teachingViolationDeduction: number
|
||||
totalDeduction: number
|
||||
id: number;
|
||||
name: string;
|
||||
parentName: string;
|
||||
dormDeductionCount: number;
|
||||
dormViolationCount: number;
|
||||
dormViolationDeduction: number;
|
||||
teachingViolationCount: number;
|
||||
teachingViolationDeduction: number;
|
||||
totalDeduction: number;
|
||||
}
|
||||
|
||||
export interface StudentStatisticsVo {
|
||||
dimension: string
|
||||
chartData: StatisticsChartData[]
|
||||
detailData: StatisticsDetailData[]
|
||||
dimension: string;
|
||||
chartData: StatisticsChartData[];
|
||||
detailData: StatisticsDetailData[];
|
||||
}
|
||||
|
||||
export interface CascadeOptionVo {
|
||||
id: number
|
||||
label: string
|
||||
value: string
|
||||
sort: number
|
||||
id: number;
|
||||
label: string;
|
||||
value: string;
|
||||
sort: number;
|
||||
}
|
||||
|
||||
// 获取统计数据
|
||||
@@ -48,7 +48,7 @@ export function getStatistics(data: StudentStatisticsBo) {
|
||||
url: '/xg/studentStatistics/statistics',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// 导出统计数据
|
||||
@@ -58,7 +58,7 @@ export function exportStatistics(data: StudentStatisticsBo) {
|
||||
method: 'post',
|
||||
data: data,
|
||||
responseType: 'blob'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// 获取二级学院列表
|
||||
@@ -66,7 +66,7 @@ export function getColleges() {
|
||||
return request({
|
||||
url: '/xg/studentStatistics/colleges',
|
||||
method: 'get'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// 根据学院ID获取专业列表
|
||||
@@ -74,7 +74,7 @@ export function getMajorsByCollegeId(collegeId: number) {
|
||||
return request({
|
||||
url: `/xg/studentStatistics/majors/${collegeId}`,
|
||||
method: 'get'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// 根据专业ID获取班级列表
|
||||
@@ -82,5 +82,5 @@ export function getClassesByMajorId(majorId: number) {
|
||||
return request({
|
||||
url: `/xg/studentStatistics/classes/${majorId}`,
|
||||
method: 'get'
|
||||
})
|
||||
});
|
||||
}
|
||||
@@ -1,6 +1,12 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { HolidayStayVO, HolidayStayForm, HolidayStayQuery, StudentOptionVO, StudentOptionQuery } from '@/api/xg/xgss/holidayStay/holidayStay/types-sg';
|
||||
import {
|
||||
HolidayStayVO,
|
||||
HolidayStayForm,
|
||||
HolidayStayQuery,
|
||||
StudentOptionVO,
|
||||
StudentOptionQuery
|
||||
} from '@/api/xg/xgss/holidayStay/holidayStay/types-sg';
|
||||
|
||||
/**
|
||||
* 查询假期留宿管理列表
|
||||
|
||||
@@ -484,8 +484,8 @@ export interface DormApplicationQuery extends PageQuery {
|
||||
applyTime?: string;
|
||||
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
* 日期范围参数
|
||||
*/
|
||||
params?: any;
|
||||
}
|
||||
|
||||
|
||||
@@ -239,8 +239,8 @@ export const listXljkConsulter = (query?: XljkConsulterQuery): AxiosPromise<Xljk
|
||||
url: '/xljk/consulter/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询心理咨询师配置详细
|
||||
@@ -250,8 +250,8 @@ export const getXljkConsulter = (id: string | number): AxiosPromise<XljkConsulte
|
||||
return request({
|
||||
url: '/xljk/consulter/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 新增心理咨询师配置
|
||||
@@ -262,8 +262,8 @@ export const addXljkConsulter = (data: XljkConsulterForm) => {
|
||||
url: '/xljk/consulter',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 修改心理咨询师配置
|
||||
@@ -274,8 +274,8 @@ export const updateXljkConsulter = (data: XljkConsulterForm) => {
|
||||
url: '/xljk/consulter',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除心理咨询师配置
|
||||
@@ -285,8 +285,8 @@ export const delXljkConsulter = (id: string | number | Array<string | number>) =
|
||||
return request({
|
||||
url: '/xljk/consulter/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 导出心理咨询师配置
|
||||
@@ -299,8 +299,8 @@ export const exportXljkConsulter = (query?: XljkConsulterQuery) => {
|
||||
method: 'post',
|
||||
data: query,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量添加咨询师
|
||||
@@ -315,8 +315,8 @@ export const batchAddConsulters = (userIds: number[], remark?: string) => {
|
||||
userIds,
|
||||
remark
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询我配置的咨询师列表
|
||||
@@ -327,8 +327,8 @@ export const listMyConfigConsulters = (query?: XljkConsulterQuery): AxiosPromise
|
||||
url: '/xljk/consulter/myConfig',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量启用咨询师
|
||||
@@ -339,8 +339,8 @@ export const enableConsulters = (ids: number[]) => {
|
||||
url: '/xljk/consulter/enable',
|
||||
method: 'post',
|
||||
data: ids
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量停用咨询师
|
||||
@@ -351,8 +351,8 @@ export const disableConsulters = (ids: number[]) => {
|
||||
url: '/xljk/consulter/disable',
|
||||
method: 'post',
|
||||
data: ids
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 根据部门ID获取用户列表
|
||||
@@ -362,5 +362,5 @@ export const listUserByDeptId = (deptId: string | number) => {
|
||||
return request({
|
||||
url: '/xljk/consulter/users/' + deptId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PageQuery } from '@/api/types'
|
||||
import { PageQuery } from '@/api/types';
|
||||
|
||||
export interface XljkConsultationScheduleVO {
|
||||
/**
|
||||
@@ -941,7 +941,6 @@ export interface XljkConsulterForm {
|
||||
}
|
||||
|
||||
export interface XljkConsulterQuery extends PageQuery {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@@ -977,9 +976,9 @@ export interface XljkConsulterQuery extends PageQuery {
|
||||
*/
|
||||
office?: string;
|
||||
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
'params[beginCreateTime]'?: string;
|
||||
'params[endCreateTime]'?: string;
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
'params[beginCreateTime]'?: string;
|
||||
'params[endCreateTime]'?: string;
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
# 人员录入功能说明
|
||||
|
||||
## 📋 功能概述
|
||||
|
||||
人员录入功能支持录入正式工、临时工、外聘工三种类型的人员信息,包含完整的增删改查、导入导出功能。
|
||||
|
||||
## 🔧 功能特性
|
||||
|
||||
### 核心功能
|
||||
- ✅ 人员信息录入(姓名、性别、职务、部门、手机号、工号)
|
||||
- ✅ 工号自动生成(正式工0XXXXX、临时工LXXXXX、外聘工WXXXXX)
|
||||
- ✅ 增删改查操作
|
||||
- ✅ 数据同步(自动同步sys_user和sys_user_role表)
|
||||
- ✅ 导入导出Excel功能
|
||||
- ✅ 部门树形选择
|
||||
|
||||
### 工号规则
|
||||
| 人员类型 | 工号格式 | 示例 |
|
||||
|---------|---------|------|
|
||||
| 正式工 | 0XXXXX | 000001 |
|
||||
| 临时工 | LXXXXX | L00001 |
|
||||
| 外聘工 | WXXXXX | W00001 |
|
||||
|
||||
## 📁 文件结构
|
||||
|
||||
```
|
||||
backend/ruoyi-modules/ruoyi-rs/
|
||||
├── domain/
|
||||
│ ├── RsStaffInfo.java # 实体类
|
||||
│ ├── vo/
|
||||
│ │ ├── RsStaffInfoVo.java # 视图对象
|
||||
│ │ └── RsStaffInfoImportVo.java # 导入VO
|
||||
│ └── bo/
|
||||
│ └── RsStaffInfoBo.java # 业务对象
|
||||
├── mapper/
|
||||
│ ├── RsStaffInfoMapper.java # 数据访问层接口
|
||||
│ └── RsStaffInfoMapper.xml # MyBatis映射文件
|
||||
├── service/
|
||||
│ ├── IRsStaffInfoService.java # 服务接口
|
||||
│ └── impl/
|
||||
│ └── RsStaffInfoServiceImpl.java # 服务实现
|
||||
├── listener/
|
||||
│ └── RsStaffInfoImportListener.java # 导入监听器
|
||||
└── controller/
|
||||
└── RsStaffInfoController.java # 控制器
|
||||
|
||||
web/src/views/rs/staff-info/
|
||||
├── index.vue # 主页面
|
||||
└── README.md # 说明文档
|
||||
|
||||
web/src/api/rs/staffInfo/
|
||||
├── index.ts # API接口
|
||||
└── types.ts # 类型定义
|
||||
```
|
||||
|
||||
## 🔌 API接口
|
||||
|
||||
### 主要接口
|
||||
- `GET /staff/staffInfo/list` - 查询人员列表
|
||||
- `POST /staff/staffInfo/listByDeptId` - 根据部门查询人员列表
|
||||
- `GET /staff/staffInfo/{id}` - 获取人员详情
|
||||
- `POST /staff/staffInfo` - 新增人员
|
||||
- `PUT /staff/staffInfo` - 修改人员
|
||||
- `DELETE /staff/staffInfo/{ids}` - 删除人员
|
||||
- `GET /staff/staffInfo/deptTree` - 获取部门树
|
||||
- `POST /staff/staffInfo/importData` - 导入人员数据
|
||||
- `POST /staff/staffInfo/importTemplate` - 下载导入模板
|
||||
- `POST /staff/staffInfo/export` - 导出人员数据
|
||||
|
||||
## 📊 数据同步逻辑
|
||||
|
||||
### 新增人员时同步操作
|
||||
1. 在`rs_staff_info`表插入人员记录
|
||||
2. 自动生成工号(根据人员类型)
|
||||
3. 在`sys_user`表创建用户记录
|
||||
4. 在`sys_user_role`表添加角色(4和1938120323613728770)
|
||||
|
||||
### 修改人员时同步操作
|
||||
1. 更新`rs_staff_info`表记录
|
||||
2. 同步更新`sys_user`表的对应字段
|
||||
|
||||
### 删除人员时同步操作
|
||||
1. 逻辑删除`rs_staff_info`表记录
|
||||
2. 逻辑删除`sys_user`表对应记录
|
||||
3. 级联删除`sys_user_role`表记录
|
||||
|
||||
## 📥 导入导出功能
|
||||
|
||||
### 导入模板格式
|
||||
```excel
|
||||
| 姓名 | 性别 | 职务 | 部门名称 | 手机号 | 人员类型 |
|
||||
|------|------|------|----------|--------|----------|
|
||||
| 张三 | 男 | 讲师 | 计算机学院 | 13800138000 | 正式工 |
|
||||
```
|
||||
|
||||
### 模板特性
|
||||
- **性别列**:下拉选择(男/女)
|
||||
- **人员类型列**:下拉选择(正式工/临时工/外聘工)
|
||||
- **数据验证**:自动校验必填字段和格式
|
||||
|
||||
### 导入验证规则
|
||||
- 姓名:必填
|
||||
- 性别:必填,必须是"男"或"女"
|
||||
- 部门名称:必填,必须存在于系统中
|
||||
- 手机号:必填,11位数字格式,且系统中唯一
|
||||
- 人员类型:必填,必须是"正式工"、"临时工"或"外聘工"
|
||||
|
||||
## 🎨 前端页面布局
|
||||
|
||||
### 页面结构
|
||||
```
|
||||
├── 左侧部门树
|
||||
│ ├── 部门搜索框
|
||||
│ └── 部门树形结构
|
||||
└── 右侧内容区域
|
||||
├── 搜索表单
|
||||
│ ├── 姓名、工号、手机号等查询条件
|
||||
│ └── 时间范围选择
|
||||
├── 操作按钮栏
|
||||
│ ├── 新增、修改、删除按钮
|
||||
│ └── 导入、导出按钮
|
||||
└── 数据表格
|
||||
├── 工号、姓名、性别等列
|
||||
└── 操作列(修改、删除、详情)
|
||||
```
|
||||
|
||||
### 交互逻辑
|
||||
1. **部门选择**:点击左侧部门树节点,右侧显示该部门人员
|
||||
2. **搜索过滤**:支持多条件组合查询
|
||||
3. **批量操作**:支持批量删除
|
||||
4. **导入导出**:完整的Excel导入导出流程
|
||||
|
||||
## 🔧 使用说明
|
||||
|
||||
### 1. 访问页面
|
||||
在系统菜单中配置人员录入功能入口,路径为:`/rs/staff-info`
|
||||
|
||||
### 2. 新增人员
|
||||
1. 选择左侧部门节点
|
||||
2. 点击"新增"按钮
|
||||
3. 填写人员信息
|
||||
4. 系统自动生成工号
|
||||
5. 点击"确定"保存
|
||||
|
||||
### 3. 导入人员
|
||||
1. 选择左侧部门节点
|
||||
2. 点击"更多" → "导入数据"
|
||||
3. 下载导入模板
|
||||
4. 按照模板格式填写数据
|
||||
5. 上传Excel文件
|
||||
6. 查看导入结果
|
||||
|
||||
### 4. 导出人员
|
||||
1. 设置查询条件(可选)
|
||||
2. 点击"更多" → "导出数据"
|
||||
3. 系统自动下载Excel文件
|
||||
|
||||
## ⚠️ 注意事项
|
||||
|
||||
1. **部门选择**:导入和新增操作前必须先选择部门节点
|
||||
2. **数据唯一性**:手机号在整个系统中必须唯一
|
||||
3. **工号生成**:工号自动生成,无需手动填写
|
||||
4. **角色分配**:新增人员自动分配默认角色
|
||||
5. **权限控制**:不同操作需要相应权限
|
||||
|
||||
## 🔄 数据流转
|
||||
|
||||
```
|
||||
用户操作 → 前端页面 → API接口 → 控制器 → 服务层 → 数据访问层 → 数据库
|
||||
↑ ↓
|
||||
导入文件 ← Excel处理 ← 导入监听器 ← 业务验证 ← 数据转换 ← 自动生成工号
|
||||
↑ ↓
|
||||
导出文件 ← Excel生成 ← 模板下载 ← 查询结果 ← 条件筛选 ← 用户查询
|
||||
```
|
||||
|
||||
## 📞 技术支持
|
||||
|
||||
如有问题,请联系开发团队或查看系统日志获取详细错误信息。
|
||||
File diff suppressed because it is too large.
Load diff
@@ -73,12 +73,7 @@
|
||||
collapse-tags-tooltip
|
||||
@change="handleQuery"
|
||||
>
|
||||
<el-option
|
||||
v-for="status in student_status"
|
||||
:key="status.value"
|
||||
:label="status.label"
|
||||
:value="status.value"
|
||||
/>
|
||||
<el-option v-for="status in student_status" :key="status.value" :label="status.label" :value="status.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -108,6 +103,20 @@
|
||||
<el-col :span="1.5">
|
||||
<el-button icon="Refresh" @click="handleRefresh">刷新</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-dropdown class="mt-[1px]">
|
||||
<el-button>
|
||||
更多
|
||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item icon="Download" @click="handleImportTemplate">下载模板</el-dropdown-item>
|
||||
<el-dropdown-item icon="Top" @click="handleImportData">导入数据</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</el-col>
|
||||
<RightToolbar v-model:show-search="showSearch" :columns="columns" :search="true" @query-table="getList"></RightToolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
@@ -120,8 +129,8 @@
|
||||
v-model="batchModalForm.score"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:precision="2"
|
||||
:step="0.5"
|
||||
:precision="0"
|
||||
:step="1"
|
||||
size="small"
|
||||
placeholder="输入分数"
|
||||
style="width: 100%"
|
||||
@@ -146,6 +155,70 @@
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 导入数据弹窗 -->
|
||||
<el-dialog
|
||||
v-model="importModalVisible"
|
||||
title="导入操行分数据"
|
||||
width="500px"
|
||||
append-to-body
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close
|
||||
>
|
||||
<div class="mb-4">
|
||||
<div class="text-sm text-gray-600 mb-2">
|
||||
<strong>当前录入条件:</strong>
|
||||
{{ queryParams.academicYear - 1 }}-{{ queryParams.academicYear }}学年
|
||||
{{ queryParams.semester === 1 ? '第一学期' : '第二学期' }}
|
||||
{{ queryParams.month }}月
|
||||
{{ activeTab ? `(${classTabs.find((tab) => tab.classId.toString() === activeTab)?.className})` : '' }}
|
||||
</div>
|
||||
<div class="text-sm text-red-600 mb-3">
|
||||
<el-icon class="mr-1"><InfoFilled /></el-icon>
|
||||
如果学生已有该月份的分数记录,将被Excel中的数据覆盖
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-upload
|
||||
ref="importUploadRef"
|
||||
:limit="1"
|
||||
accept=".xlsx, .xls"
|
||||
:headers="importUpload.headers"
|
||||
:action="getImportUrl()"
|
||||
:disabled="importUpload.isUploading"
|
||||
:on-progress="handleImportFileUploadProgress"
|
||||
:on-success="handleImportFileSuccess"
|
||||
:on-error="handleImportFileError"
|
||||
:auto-upload="false"
|
||||
drag
|
||||
>
|
||||
<el-icon class="el-icon--upload">
|
||||
<i-ep-upload-filled />
|
||||
</el-icon>
|
||||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
||||
<template #tip>
|
||||
<div class="text-center el-upload__tip">
|
||||
<div class="el-upload__tip" style="color: #409eff; margin-bottom: 5px">模板包含4列:学号、学生姓名、分数、备注</div>
|
||||
<div class="el-upload__tip" style="color: red">仅处理班主任负责班级的学生数据,学号不存在或姓名不匹配的数据将被跳过</div>
|
||||
<span>仅允许导入xls、xlsx格式文件。</span>
|
||||
<el-link
|
||||
type="primary"
|
||||
:underline="false"
|
||||
style="font-size: 12px; vertical-align: baseline; margin-left: 10px"
|
||||
@click="handleImportTemplate"
|
||||
>
|
||||
下载模板
|
||||
</el-link>
|
||||
</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="importModalVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submitImportFile" :loading="importUpload.isUploading">确定导入</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-table
|
||||
v-if="currentClassStudents && currentClassStudents.length > 0"
|
||||
v-loading="tabLoading"
|
||||
@@ -189,7 +262,7 @@
|
||||
</el-table-column>
|
||||
<el-table-column v-if="columns[3].visible" key="score" label="分数" align="center" width="150">
|
||||
<template #default="scope">
|
||||
<el-input-number v-model="scope.row.score" :min="0" :max="100" :precision="2" :step="0.5" size="small" placeholder="输入分数" />
|
||||
<el-input-number v-model="scope.row.score" :min="0" :max="100" :precision="0" :step="1" size="small" placeholder="输入分数" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="columns[4].visible" key="evaluation" label="评判结果" align="center" width="100">
|
||||
@@ -250,9 +323,11 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="ConductScoreInput">
|
||||
import { ref, reactive, onMounted, computed, getCurrentInstance, toRefs } from 'vue';
|
||||
import { ref, reactive, onMounted, computed, getCurrentInstance, toRefs, nextTick } from 'vue';
|
||||
import ElMessage from 'element-plus/es/components/message/index';
|
||||
import ElMessageBox from 'element-plus/es/components/message-box/index';
|
||||
import { ArrowDown, InfoFilled } from '@element-plus/icons-vue';
|
||||
import { globalHeaders } from '@/utils/request';
|
||||
|
||||
// API接口
|
||||
import { conductScoreClassStudents, conductScoreBatchAdd } from '@/api/xg/conductScore';
|
||||
@@ -265,7 +340,20 @@ const { student_status } = toRefs<any>(proxy?.useDict('student_status'));
|
||||
|
||||
// 响应式数据
|
||||
const queryParams = reactive({
|
||||
academicYear: new Date().getFullYear(),
|
||||
academicYear: (() => {
|
||||
const now = new Date();
|
||||
const currentYear = now.getFullYear();
|
||||
const currentMonth = now.getMonth() + 1; // 1-12
|
||||
const currentDate = now.getDate();
|
||||
|
||||
// 判断是否在9月1日之后(包括9月1日)
|
||||
// 如果是9月之后,或者是9月1日及之后,则属于下一学年
|
||||
if (currentMonth > 9 || (currentMonth === 9 && currentDate >= 1)) {
|
||||
return currentYear + 1; // 下一学年,如2026年9月1日后,选中2026-2027学年(值为2027)
|
||||
} else {
|
||||
return currentYear; // 当前学年,如2026年9月1日前,选中2025-2026学年(值为2026)
|
||||
}
|
||||
})(),
|
||||
semester: 1,
|
||||
month: new Date().getMonth() + 1,
|
||||
studentNo: '',
|
||||
@@ -355,10 +443,14 @@ const queryFormRef = ref();
|
||||
// 选项数据
|
||||
const yearOptions = computed(() => {
|
||||
const currentYear = new Date().getFullYear();
|
||||
return Array.from({ length: 8 }, (_, i) => ({
|
||||
label: `${currentYear - 7 + i}年`,
|
||||
value: currentYear - 7 + i
|
||||
}));
|
||||
// 生成9个学年选项(往前7个 + 当前1个 + 往后多生成1个)
|
||||
return Array.from({ length: 9 }, (_, i) => {
|
||||
const yearValue = currentYear - 7 + i;
|
||||
return {
|
||||
label: `${yearValue - 1}-${yearValue}学年`,
|
||||
value: yearValue
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const semesterOptions = [
|
||||
@@ -601,6 +693,15 @@ const batchModalForm = reactive({
|
||||
remark: ''
|
||||
});
|
||||
|
||||
// 导入数据相关
|
||||
const importModalVisible = ref(false);
|
||||
const importUploadRef = ref<any>();
|
||||
const importUpload = reactive({
|
||||
isUploading: false,
|
||||
headers: globalHeaders(),
|
||||
url: ''
|
||||
});
|
||||
|
||||
const confirmBatchModalSave = () => {
|
||||
// 批量录入弹窗填写的分数/备注将应用到所有已勾选的学生(包含已录入的,视为覆盖)
|
||||
const targets = selectedStudents.value || [];
|
||||
@@ -662,6 +763,90 @@ const handleSelectionChange = (selection) => {
|
||||
selectedStudents.value = selection;
|
||||
};
|
||||
|
||||
// 导入相关方法
|
||||
const handleImportData = () => {
|
||||
if (!activeTab.value) {
|
||||
ElMessage.warning('请先选择要导入数据的班级');
|
||||
return;
|
||||
}
|
||||
importModalVisible.value = true;
|
||||
};
|
||||
|
||||
const handleImportTemplate = () => {
|
||||
proxy?.download('xg/conduct-score/importTemplate', {}, `操行分导入模板_${new Date().getTime()}.xlsx`);
|
||||
};
|
||||
|
||||
const getImportUrl = () => {
|
||||
const baseUrl = import.meta.env.VITE_APP_BASE_API + '/xg/conduct-score/importData';
|
||||
const params = new URLSearchParams();
|
||||
params.append('academicYear', queryParams.academicYear.toString());
|
||||
params.append('semester', queryParams.semester.toString());
|
||||
params.append('month', queryParams.month.toString());
|
||||
|
||||
// 如果选择了特定班级,则只导入该班级数据
|
||||
if (activeTab.value) {
|
||||
params.append('classId', activeTab.value);
|
||||
}
|
||||
|
||||
return `${baseUrl}?${params.toString()}`;
|
||||
};
|
||||
|
||||
const handleImportFileUploadProgress = () => {
|
||||
importUpload.isUploading = true;
|
||||
};
|
||||
|
||||
const handleImportFileSuccess = (response) => {
|
||||
importModalVisible.value = false;
|
||||
importUpload.isUploading = false;
|
||||
importUploadRef.value[0]?.clearFiles();
|
||||
|
||||
ElMessage.closeAll();
|
||||
|
||||
ElMessageBox.alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + '</div>', '导入结果', {
|
||||
dangerouslyUseHTMLString: true
|
||||
});
|
||||
|
||||
// 刷新数据
|
||||
getList();
|
||||
};
|
||||
|
||||
const handleImportFileError = (error) => {
|
||||
importUpload.isUploading = false;
|
||||
importUploadRef.value[0]?.clearFiles();
|
||||
|
||||
ElMessage.closeAll();
|
||||
|
||||
console.error('文件上传失败:', error);
|
||||
ElMessage.error('导入失败,请检查文件格式或网络连接');
|
||||
};
|
||||
|
||||
const submitImportFile = () => {
|
||||
if (!importUploadRef.value || !importUploadRef.value[0]) {
|
||||
ElMessage.error('上传组件未初始化');
|
||||
return;
|
||||
}
|
||||
|
||||
ElMessage({
|
||||
message: '正在导入数据,请耐心等待...',
|
||||
type: 'info',
|
||||
duration: 0,
|
||||
zIndex: 4000
|
||||
});
|
||||
|
||||
importUpload.isUploading = true;
|
||||
|
||||
// 使用 nextTick 确保组件已完全挂载
|
||||
nextTick(() => {
|
||||
try {
|
||||
importUploadRef.value[0]?.submit();
|
||||
} catch (error) {
|
||||
console.error('Submit error:', error);
|
||||
ElMessage.error('上传失败:' + error.message);
|
||||
importUpload.isUploading = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
getList();
|
||||
|
||||
@@ -184,7 +184,11 @@
|
||||
width="100"
|
||||
:show-overflow-tooltip="true"
|
||||
/>
|
||||
<el-table-column v-if="columns[5].visible" key="academicYear" label="学年" align="center" prop="academicYear" width="80" />
|
||||
<el-table-column v-if="columns[5].visible" key="academicYear" label="学年" align="center" width="120">
|
||||
<template #default="scope">
|
||||
{{ scope.row.academicYear ? `${scope.row.academicYear - 1}-${scope.row.academicYear}学年` : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="columns[6].visible" key="semester" label="学期" align="center" prop="semester" width="80">
|
||||
<template #default="scope">
|
||||
{{ scope.row.semester === 1 ? '第一学期' : '第二学期' }}
|
||||
@@ -345,7 +349,20 @@ const { xg_class_status } = toRefs<any>(proxy?.useDict('xg_class_status'));
|
||||
const queryParams = reactive({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
academicYear: new Date().getFullYear(),
|
||||
academicYear: (() => {
|
||||
const now = new Date();
|
||||
const currentYear = now.getFullYear();
|
||||
const currentMonth = now.getMonth() + 1; // 1-12
|
||||
const currentDate = now.getDate();
|
||||
|
||||
// 判断是否在9月1日之后(包括9月1日)
|
||||
// 如果是9月之后,或者是9月1日及之后,则属于下一学年
|
||||
if (currentMonth > 9 || (currentMonth === 9 && currentDate >= 1)) {
|
||||
return currentYear + 1; // 下一学年,如2026年9月1日后,选中2026-2027学年(值为2027)
|
||||
} else {
|
||||
return currentYear; // 当前学年,如2026年9月1日前,选中2025-2026学年(值为2026)
|
||||
}
|
||||
})(),
|
||||
semester: 1,
|
||||
month: new Date().getMonth() + 1, // 默认当前月份
|
||||
studentName: '',
|
||||
@@ -428,11 +445,14 @@ const modalMode = ref<'single' | 'batch'>('single');
|
||||
// 选项数据
|
||||
const yearOptions = computed(() => {
|
||||
const currentYear = new Date().getFullYear();
|
||||
// 历史8年:从 currentYear - 7 到 currentYear
|
||||
return Array.from({ length: 8 }, (_, i) => ({
|
||||
label: `${currentYear - 7 + i}年`,
|
||||
value: currentYear - 7 + i
|
||||
}));
|
||||
// 生成9个学年选项(往前7个 + 当前1个 + 往后多生成1个)
|
||||
return Array.from({ length: 9 }, (_, i) => {
|
||||
const yearValue = currentYear - 7 + i;
|
||||
return {
|
||||
label: `${yearValue - 1}-${yearValue}学年`,
|
||||
value: yearValue
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const semesterOptions = [
|
||||
@@ -916,7 +936,8 @@ const handleExport = () => {
|
||||
{
|
||||
...queryParams,
|
||||
...proxy?.addDateRange(queryParams, dateRange.value),
|
||||
includeEvaluation: true // 添加标识,表示需要包含评判结果
|
||||
includeEvaluation: true, // 添加标识,表示需要包含评判结果
|
||||
academicYearFormat: 'friendly' // 添加标识,表示需要将学年格式化为友好形式(如2025-2026学年)
|
||||
},
|
||||
`conduct_score_${new Date().getTime()}.xlsx`
|
||||
)
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<transition enter-active-class="animate__animated animate__fadeIn" leave-active-class="animate__animated animate__fadeOut">
|
||||
<div v-show="showSearch" class="mb-[10px]">
|
||||
<el-card shadow="hover">
|
||||
<el-form ref="queryFormRef" :model="queryParams">
|
||||
<el-form ref="queryFormRef" :model="queryParams" label-width="80px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6">
|
||||
<el-form-item label="学年" prop="academicYear">
|
||||
@@ -357,7 +357,20 @@ const { xg_class_status } = toRefs<any>(proxy?.useDict('xg_class_status'));
|
||||
const queryParams = reactive({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
academicYear: new Date().getFullYear(),
|
||||
academicYear: (() => {
|
||||
const now = new Date();
|
||||
const currentYear = now.getFullYear();
|
||||
const currentMonth = now.getMonth() + 1; // 1-12
|
||||
const currentDate = now.getDate();
|
||||
|
||||
// 判断是否在9月1日之后(包括9月1日)
|
||||
// 如果是9月之后,或者是9月1日及之后,则属于下一学年
|
||||
if (currentMonth > 9 || (currentMonth === 9 && currentDate >= 1)) {
|
||||
return currentYear + 1; // 下一学年,如2026年9月1日后,选中2026-2027学年(值为2027)
|
||||
} else {
|
||||
return currentYear; // 当前学年,如2026年9月1日前,选中2025-2026学年(值为2026)
|
||||
}
|
||||
})(),
|
||||
semester: 1,
|
||||
className: '',
|
||||
studentName: '',
|
||||
@@ -431,11 +444,14 @@ const monthlyRecords = ref([]);
|
||||
// 选项数据
|
||||
const yearOptions = computed(() => {
|
||||
const currentYear = new Date().getFullYear();
|
||||
// 历史8年:从 currentYear - 7 到 currentYear
|
||||
return Array.from({ length: 8 }, (_, i) => ({
|
||||
label: `${currentYear - 7 + i}年`,
|
||||
value: currentYear - 7 + i
|
||||
}));
|
||||
// 生成9个学年选项(往前7个 + 当前1个 + 往后多生成1个)
|
||||
return Array.from({ length: 9 }, (_, i) => {
|
||||
const yearValue = currentYear - 7 + i;
|
||||
return {
|
||||
label: `${yearValue - 1}-${yearValue}学年`,
|
||||
value: yearValue
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const semesterOptions = [
|
||||
@@ -898,7 +914,8 @@ const handleExport = () => {
|
||||
'xg/conduct-score/export-semester',
|
||||
{
|
||||
...queryParams,
|
||||
...proxy?.addDateRange(queryParams, dateRange.value)
|
||||
...proxy?.addDateRange(queryParams, dateRange.value),
|
||||
academicYearFormat: 'friendly' // 添加标识,表示需要将学年格式化为友好形式(如2025-2026学年)
|
||||
},
|
||||
`semester_statistics_${new Date().getTime()}.xlsx`
|
||||
)
|
||||
|
||||
@@ -188,10 +188,10 @@
|
||||
<el-table-column label="操作" fixed="right" width="240" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-tooltip content="修改" placement="top">
|
||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
|
||||
<el-button v-hasPermi="['stu:studentMsg:update']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="删除" placement="top">
|
||||
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
||||
<el-button v-hasPermi="['stu:studentMsg:delete']" link type="danger" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
||||
</el-tooltip>
|
||||
<!--
|
||||
<el-tooltip content="重置密码" placement="top">
|
||||
|
||||
Reference in new issue
Block a user