南京理工-分级核对需求:

1.工会组织管理页面仅给‘机关党委工会’的成员单位列表加三级单位管理员设置按钮;
2.新增‘分级核对管理’(校工会管理员可见)和‘单位数据核对’(三级单位管理员和分工会管理员可见)菜单页面;
This commit is contained in:
2026-10-14 16:26:16 +08:00
parent f9a87d12e2
commit eaac21eebc
17 changed files with 2853 additions and 4 deletions
@@ -16,6 +16,11 @@ public interface Roles {
*/ */
String UNION_MANGER = "5d342e614e9a48288d50154bcdcc75d3"; String UNION_MANGER = "5d342e614e9a48288d50154bcdcc75d3";
/**
* 三级单位管理员
*/
String THIRD_UNIT_MANGER = "e8d957d1ab9f4e56a60b5a53929d18bb";
/** /**
* 体育活动联合工会管理员 * 体育活动联合工会管理员
*/ */
@@ -0,0 +1,12 @@
package io.v.nutz.levelcheck.constant;
/**
* 分级核对操作类型
*/
public interface LevelCheckAction {
String DISTRIBUTE = "DISTRIBUTE";
String CONFIRM = "CONFIRM";
String SUBMIT_REVISION = "SUBMIT_REVISION";
String APPROVE = "APPROVE";
String REJECT = "REJECT";
}
@@ -0,0 +1,12 @@
package io.v.nutz.levelcheck.constant;
/**
* 分级核对状态
*/
public interface LevelCheckState {
int PENDING_CHECK = 0;
int CONFIRMED = 1;
int PENDING_AUDIT = 2;
int REJECTED = 3;
int APPROVED = 4;
}
@@ -0,0 +1,184 @@
package io.v.nutz.levelcheck.controller;
import cn.wizzer.framework.base.Result;
import io.v.nutz.annontation.ViReturn;
import io.v.nutz.levelcheck.service.LevelCheckService;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.mvc.annotation.*;
import org.nutz.mvc.upload.TempFile;
import org.nutz.mvc.upload.UploadAdaptor;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
/**
* 校工会分级核对管理
*/
@IocBean
@At("/platform/levelCheck/school")
@Ok("json:full")
@RequiresAuthentication
public class LevelCheckSchoolController {
@Inject
private LevelCheckService levelCheckService;
@At("")
@Ok("beetl:/platform/levelCheck/school.html")
public void index() {
levelCheckService.requireSchoolAdmin();
}
@At
@ViReturn
public Object taskData(String taskName, String taskDate, int pageNumber, int pageSize) {
try {
levelCheckService.requireSchoolAdmin();
return Result.success().addData(levelCheckService.schoolTasks(
taskName, taskDate, pageNumber, pageSize));
} catch (Exception e) {
return Result.error(e.getMessage());
}
}
@At
@ViReturn
public Object unitTaskData(String taskId, String unitName, Integer state, Integer managerState,
int pageNumber, int pageSize) {
try {
levelCheckService.requireSchoolAdmin();
return Result.success().addData(levelCheckService.schoolUnitTasks(
taskId, unitName, state, managerState, pageNumber, pageSize));
} catch (Exception e) {
return Result.error(e.getMessage());
}
}
@At
@ViReturn
public Object unitDataPage(String unitTaskId, String versionType, String searchName, String searchKeyword,
Integer state,
int pageNumber, int pageSize) {
try {
return Result.success().addData(levelCheckService.unitDataPage(
unitTaskId, versionType, searchName, searchKeyword, state, pageNumber, pageSize));
} catch (Exception e) {
return Result.error(e.getMessage());
}
}
@At
@ViReturn
public Object currentDataPage(String taskId, String searchName, String searchKeyword, Integer state,
int pageNumber, int pageSize) {
try {
return Result.success().addData(levelCheckService.currentDataPage(
taskId, searchName, searchKeyword, state, pageNumber, pageSize));
} catch (Exception e) {
return Result.error(e.getMessage());
}
}
@At
@POST
@ViReturn
@Aop(TransAop.READ_COMMITTED)
public Object doDelete(String taskId) {
try {
levelCheckService.deleteTask(taskId);
return null;
} catch (Exception e) {
return Result.error(e.getMessage());
}
}
@At
@POST
@ViReturn
@Aop(TransAop.READ_COMMITTED)
@AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"})
public Object doUpload(String taskName, String description,
@Param("files") TempFile[] files) {
try {
levelCheckService.requireSchoolAdmin();
NutMap result = levelCheckService.createTask(taskName, description, files);
String message = result.getInt("errorCount") > 0 ? "导入完成,部分数据未分发" : "分发成功";
return Result.success(message).addData(result);
} catch (Exception e) {
return Result.error(e.getMessage());
}
}
@At
public void exportImportErrors(String cacheKey, HttpServletResponse response) {
try {
levelCheckService.requireSchoolAdmin();
byte[] bytes = levelCheckService.getImportErrorFile(cacheKey);
String fileName = "分级核对导入错误.xlsx";
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment;filename="
+ URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()));
response.getOutputStream().write(bytes);
} catch (Exception e) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
}
}
@At
public void downloadTemplate(HttpServletResponse response) {
try {
byte[] bytes = levelCheckService.getImportTemplate();
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment;filename="
+ URLEncoder.encode("分级核对导入模板.xlsx", StandardCharsets.UTF_8.name()));
response.getOutputStream().write(bytes);
} catch (Exception e) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
}
}
@At
@ViReturn
@Aop(TransAop.READ_COMMITTED)
public Object doAudit(String unitTaskId, boolean approved, String opinion) {
try {
levelCheckService.audit(unitTaskId, approved, opinion);
return null;
} catch (Exception e) {
return Result.error(e.getMessage());
}
}
@At
public void download(String unitTaskId, String versionType, HttpServletResponse response) {
try {
byte[] bytes = levelCheckService.getDownloadBytes(unitTaskId, versionType, true);
String fileName = levelCheckService.getDownloadFileName(unitTaskId, versionType, true);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment;filename="
+ URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()));
response.getOutputStream().write(bytes);
} catch (Exception e) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
}
}
@At
public void exportCurrent(String taskId, HttpServletResponse response) {
try {
byte[] bytes = levelCheckService.exportCurrent(taskId);
String fileName = "分级核对当前生效数据.xlsx";
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment;filename="
+ URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()));
response.getOutputStream().write(bytes);
} catch (Exception e) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
}
}
}
@@ -0,0 +1,97 @@
package io.v.nutz.levelcheck.controller;
import cn.wizzer.framework.base.Result;
import io.v.nutz.annontation.ViReturn;
import io.v.nutz.levelcheck.service.LevelCheckService;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.*;
import org.nutz.mvc.upload.TempFile;
import org.nutz.mvc.upload.UploadAdaptor;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
/**
* 单位分级核对
*/
@IocBean
@At("/platform/levelCheck/unit")
@Ok("json:full")
@RequiresAuthentication
public class LevelCheckUnitController {
@Inject
private LevelCheckService levelCheckService;
@At("")
@Ok("beetl:/platform/levelCheck/unit.html")
public void index() {
}
@At
@ViReturn
public Object taskData(String keyword, Integer state, int pageNumber, int pageSize) {
try {
return Result.success().addData(levelCheckService.myUnitTasks(
keyword, state, pageNumber, pageSize));
} catch (Exception e) {
return Result.error(e.getMessage());
}
}
@At
@ViReturn
@Aop(TransAop.READ_COMMITTED)
public Object doConfirm(String unitTaskId) {
try {
levelCheckService.confirm(unitTaskId);
return null;
} catch (Exception e) {
return Result.error(e.getMessage());
}
}
@At
@ViReturn
public Object dataPage(String unitTaskId, String searchName, String searchKeyword, Integer state,
int pageNumber, int pageSize) {
try {
return Result.success().addData(levelCheckService.myUnitDataPage(
unitTaskId, searchName, searchKeyword, state, pageNumber, pageSize));
} catch (Exception e) {
return Result.error(e.getMessage());
}
}
@At
@POST
@ViReturn
@Aop(TransAop.READ_COMMITTED)
@AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"})
public Object doUploadRevision(String unitTaskId, @Param("file") TempFile file) {
try {
levelCheckService.submitRevision(unitTaskId, file);
return null;
} catch (Exception e) {
return Result.error(e.getMessage());
}
}
@At
public void download(String unitTaskId, HttpServletResponse response) {
try {
byte[] bytes = levelCheckService.getDownloadBytes(unitTaskId, "current", false);
String fileName = levelCheckService.getDownloadFileName(unitTaskId, "current", false);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment;filename="
+ URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()));
response.getOutputStream().write(bytes);
} catch (Exception e) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
}
}
}
@@ -0,0 +1,49 @@
package io.v.nutz.levelcheck.model;
import io.v.nutz.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@Table("level_check_action_log")
@TableIndexes({@Index(name = "IDX_LEVEL_CHECK_LOG_UNIT", fields = {"unitTaskId"}, unique = false)})
public class LevelCheckActionLog extends BaseModel {
@Name
@PrevInsert(uu32 = true)
@ColDefine(type = ColType.VARCHAR, width = 32)
private String id;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
private String unitTaskId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 30)
private String action;
@Column
private Integer fromState;
@Column
private Integer toState;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
private String operatorId;
@Column
private Long operateAt;
@Column
@ColDefine(type = ColType.VARCHAR, width = 500)
private String opinion;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
private String fileVersionId;
}
@@ -0,0 +1,54 @@
package io.v.nutz.levelcheck.model;
import io.v.nutz.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
/**
* 分级核对固定模板数据明细
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@Table("level_check_data_row")
@TableIndexes({@Index(name = "IDX_LEVEL_CHECK_DATA_VERSION", fields = {"versionId", "sequenceNo"}, unique = true)})
public class LevelCheckDataRow extends BaseModel {
@Name
@PrevInsert(uu32 = true)
@ColDefine(type = ColType.VARCHAR, width = 32)
private String id;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
private String versionId;
@Column
private Integer sequenceNo;
@Column
@ColDefine(customType = "text")
private String salaryUnitCode;
@Column
@ColDefine(customType = "text")
private String employeeNo;
@Column
@ColDefine(customType = "text")
private String employeeName;
@Column
@ColDefine(customType = "text")
private String unionFee;
@Column
@ColDefine(customType = "text")
private String yearMonth;
@Column
@ColDefine(customType = "text")
private String unitName;
}
@@ -0,0 +1,53 @@
package io.v.nutz.levelcheck.model;
import io.v.nutz.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@Table("level_check_file_version")
@TableIndexes({@Index(name = "IDX_LEVEL_CHECK_FILE_UNIT", fields = {"unitTaskId", "versionNo"}, unique = true)})
public class LevelCheckFileVersion extends BaseModel {
@Name
@PrevInsert(uu32 = true)
@ColDefine(type = ColType.VARCHAR, width = 32)
private String id;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
private String unitTaskId;
@Column
private Integer versionNo;
@Column
@ColDefine(type = ColType.VARCHAR, width = 20)
private String versionType;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
private String sysFileId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 200)
private String originalFileName;
@Column
private Integer rowCount;
@Column
@ColDefine(type = ColType.VARCHAR, width = 64)
private String sha256;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
private String uploadedBy;
@Column
private Long uploadedAt;
}
@@ -0,0 +1,41 @@
package io.v.nutz.levelcheck.model;
import io.v.nutz.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@Table("level_check_task")
public class LevelCheckTask extends BaseModel {
@Name
@PrevInsert(uu32 = true)
@ColDefine(type = ColType.VARCHAR, width = 32)
private String id;
@Column
@ColDefine(type = ColType.VARCHAR, width = 100)
@Comment("任务名称")
private String name;
@Column
@Comment("任务日期")
private Long taskDate;
@Column
@Comment("总单位数")
private Integer totalUnits;
@Column
@Comment("已完成单位数")
private Integer finishedUnits;
@Column
@ColDefine(type = ColType.VARCHAR, width = 500)
@Comment("任务说明")
private String description;
}
@@ -0,0 +1,85 @@
package io.v.nutz.levelcheck.model;
import io.v.nutz.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@Table("level_check_unit_task")
@TableIndexes({
@Index(name = "IDX_LEVEL_CHECK_UNIT_TASK", fields = {"taskId", "unitId"}, unique = true),
@Index(name = "IDX_LEVEL_CHECK_UNIT_STATE", fields = {"state"}, unique = false)
})
public class LevelCheckUnitTask extends BaseModel {
@Name
@PrevInsert(uu32 = true)
@ColDefine(type = ColType.VARCHAR, width = 32)
private String id;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
private String taskId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
private String unitId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 100)
private String unitName;
@Column
private Integer unitLevel;
@Column
@ColDefine(type = ColType.VARCHAR, width = 20)
private String managerType;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
private String unionId;
@Column
private Integer state;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
private String originalVersionId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
private String currentVersionId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
private String pendingVersionId;
@Column
private Integer rowCount;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
private String checkedBy;
@Column
private Long checkedAt;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
private String auditedBy;
@Column
private Long auditedAt;
@Column
@ColDefine(type = ColType.VARCHAR, width = 500)
private String auditOpinion;
@Column
private Integer dataVersion;
}
File diff suppressed because it is too large Load Diff
@@ -33,8 +33,17 @@ public class ProposalUnderTakeListener implements SysCommonDataChange {
case UPDATE -> { case UPDATE -> {
Sys_unit sys_unit = dao.fetch(Sys_unit.class, bizId); Sys_unit sys_unit = dao.fetch(Sys_unit.class, bizId);
ProposalUndertake undertake = dao.fetch(ProposalUndertake.class, Cnd.where("unitCode", "=", sys_unit.getUnitcode())); ProposalUndertake undertake = dao.fetch(ProposalUndertake.class, Cnd.where("unitCode", "=", sys_unit.getUnitcode()));
undertake.setUnitName(sys_unit.getName()); if (undertake == null) {
dao.updateIgnoreNull(undertake); // 兼容历史单位缺少提案承办单位记录的情况
undertake = new ProposalUndertake();
undertake.setUnitCode(sys_unit.getUnitcode());
undertake.setUnitName(sys_unit.getName());
undertake.setIsEnable(Boolean.TRUE);
dao.insert(undertake);
} else {
undertake.setUnitName(sys_unit.getName());
dao.updateIgnoreNull(undertake);
}
} }
case DELETE -> { case DELETE -> {
dao.clear(ProposalUndertake.class, Cnd.where("id", "=", bizId)); dao.clear(ProposalUndertake.class, Cnd.where("id", "=", bizId));
@@ -347,12 +347,120 @@ public class SysUnionMangeCon {
@At @At
public Object getUnitsByUnion(String unionid) { public Object getUnitsByUnion(String unionid) {
try { try {
return Result.success().addData(sysUnitService.query(Cnd.where("unionid", "=", unionid).and("unitlevel", "=", 2))); Sql sql = Sqls.create("""
SELECT un.*,
GROUP_CONCAT(DISTINCT CONCAT(u.username, '(', u.loginname, ')')) thirdManagerNames
FROM sys_unit un
LEFT JOIN sys_user_role sur ON sur.unitid = un.id AND sur.roleId = @roleId
LEFT JOIN sys_user u ON u.id = sur.userId
WHERE un.unionid = @unionId AND un.unitlevel = 2
GROUP BY un.id
ORDER BY un.location
""");
sql.setParam("roleId", Roles.THIRD_UNIT_MANGER);
sql.setParam("unionId", unionid);
return Result.success().addData(sysUnitService.list(sql));
} catch (Exception e) { } catch (Exception e) {
return Result.error(); return Result.error();
} }
} }
/**
* 查询机关党委工会成员单位的可选人员和已设置管理员
*/
@At
public Object findThirdUnitManagerUsers(String unionId, String unitId) {
try {
checkThirdUnitManagerScope(unionId, unitId);
Sql userSql = Sqls.create("""
SELECT id, CONCAT(username, '(', loginname, ')') name
FROM `user`
WHERE unionid = @unionId
AND unitid = @unitId
ORDER BY username
""");
userSql.setParam("unionId", unionId);
userSql.setParam("unitId", unitId);
Sql selectedSql = Sqls.create("""
SELECT userId
FROM sys_user_role
WHERE roleId = @roleId AND unitid = @unitId
""");
selectedSql.setParam("roleId", Roles.THIRD_UNIT_MANGER);
selectedSql.setParam("unitId", unitId);
List<Record> selectedUsers = sysUnionService.list(selectedSql);
List<String> selectedUserIds = selectedUsers.stream()
.map(v -> v.getString("userId")).collect(Collectors.toList());
return Result.success().addData(Record.create()
.set("allUsers", sysUnionService.list(userSql))
.set("selectedUserIds", selectedUserIds));
} catch (Exception e) {
return Result.error(e.getMessage());
}
}
/**
* 设置机关党委工会成员单位管理员
*/
@At
@Aop(TransAop.READ_COMMITTED)
public Object doSetThirdUnitManagerUsers(String unionId, String unitId, String userIds) {
try {
checkThirdUnitManagerScope(unionId, unitId);
List<String> ids = Strings.isBlank(userIds)
? new java.util.ArrayList<>() : Json.fromJsonAsList(String.class, userIds);
for (String userId : ids) {
Sql userCheckSql = Sqls.create("""
SELECT id
FROM `user`
WHERE id = @userId
AND unionid = @unionId
AND unitid = @unitId
LIMIT 1
""");
userCheckSql.setParam("userId", userId);
userCheckSql.setParam("unionId", unionId);
userCheckSql.setParam("unitId", unitId);
if (sysUnionService.list(userCheckSql).isEmpty()) {
return Result.error("所选人员不属于当前成员单位");
}
}
List<Sys_user_role> userRoles = new java.util.ArrayList<>();
for (String userId : ids) {
Sys_user_role userRole = new Sys_user_role();
userRole.setRoleId(Roles.THIRD_UNIT_MANGER);
userRole.setUserId(userId);
userRole.setUnitid(unitId);
userRoles.add(userRole);
}
sysUserRoleService.clear(Cnd.where("roleId", "=", Roles.THIRD_UNIT_MANGER)
.and("unitid", "=", unitId));
if (!userRoles.isEmpty()) {
sysUserRoleService.dao().insert(userRoles);
}
sysUserService.clearCache();
sysRoleService.clearCache();
return Result.success();
} catch (Exception e) {
log.error(e);
return Result.error(e.getMessage());
}
}
private void checkThirdUnitManagerScope(String unionId, String unitId) {
if (!checkRole()) {
throw new SecurityException("仅校工会管理员可设置三级管理员");
}
Sys_union union = sysUnionService.fetch(unionId);
if (union == null || !"机关党委工会".equals(Strings.trim(union.getUnionname()))) {
throw new IllegalArgumentException("仅机关党委工会的成员单位可设置三级管理员");
}
Sys_unit unit = sysUnitService.fetch(unitId);
if (unit == null || !unionId.equals(unit.getUnionid()) || unit.getUnitlevel() != 2) {
throw new IllegalArgumentException("成员单位不属于机关党委工会");
}
}
@At // 会员档案 @At // 会员档案
public Object hyPageData(String unitid, String unionid, String searchName, String searchKeyword, int pageNumber, int pageSize, String pageOrderName, String pageOrderBy) { public Object hyPageData(String unitid, String unionid, String searchName, String searchKeyword, int pageNumber, int pageSize, String pageOrderName, String pageOrderBy) {
@@ -0,0 +1,72 @@
/*
分级核对与审核初始化脚本
说明:脚本可重复执行,不自动给任何用户分配三级单位管理员角色。
*/
SET @third_unit_manager_role_id = 'e8d957d1ab9f4e56a60b5a53929d18bb';
SET @school_union_admin_role_id = '9b01918f873645048f8a85a4fc06d135';
SET @union_manager_role_id = '5d342e614e9a48288d50154bcdcc75d3';
SET @sysadmin_role_id = (SELECT id FROM sys_role WHERE code = 'sysadmin' LIMIT 1);
SET @level_check_root_menu_id = 'a63f7fd56f594b29b2b5616d0d7f0101';
SET @level_check_school_menu_id = 'a63f7fd56f594b29b2b5616d0d7f0102';
SET @level_check_unit_menu_id = 'a63f7fd56f594b29b2b5616d0d7f0103';
INSERT INTO sys_role
(id, name, code, aliasName, disabled, note, createdBy, createdAt, updatedBy, updatedAt, delFlag)
SELECT @third_unit_manager_role_id, '三级单位管理员', 'ThirdUnitCheckAdmin', '三级单位管理员',
0, '机关党委工会成员单位的数据核对管理员', '', 0, '', 0, 0
WHERE NOT EXISTS (
SELECT 1 FROM sys_role
WHERE id = @third_unit_manager_role_id OR code = 'ThirdUnitCheckAdmin'
);
INSERT INTO sys_menu
(id, parentId, path, name, aliasName, type, href, target, icon, showit, disabled,
permission, note, location, hasChildren, createdBy, createdAt, updatedBy, updatedAt, delFlag)
SELECT @level_check_root_menu_id, '', '0098', '分级核对', 'LevelCheck', 'menu', '', '',
'ti-check-box', 1, 0, 'levelCheck', NULL, 980, 1, '', 0, '', 0, 0
WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE permission = 'levelCheck');
INSERT INTO sys_menu
(id, parentId, path, name, aliasName, type, href, target, icon, showit, disabled,
permission, note, location, hasChildren, createdBy, createdAt, updatedBy, updatedAt, delFlag)
SELECT @level_check_school_menu_id, @level_check_root_menu_id, '00980001', '分级核对管理',
'LevelCheckSchool', 'menu', '/platform/levelCheck/school', 'data-pjax', '', 1, 0,
'levelCheck.school', NULL, 981, 0, '', 0, '', 0, 0
WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE permission = 'levelCheck.school');
INSERT INTO sys_menu
(id, parentId, path, name, aliasName, type, href, target, icon, showit, disabled,
permission, note, location, hasChildren, createdBy, createdAt, updatedBy, updatedAt, delFlag)
SELECT @level_check_unit_menu_id, @level_check_root_menu_id, '00980002', '单位数据核对',
'LevelCheckUnit', 'menu', '/platform/levelCheck/unit', 'data-pjax', '', 1, 0,
'levelCheck.unit', NULL, 982, 0, '', 0, '', 0, 0
WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE permission = 'levelCheck.unit');
INSERT INTO sys_role_menu (roleId, menuId)
SELECT role_menu.roleId, role_menu.menuId
FROM (
SELECT @sysadmin_role_id roleId, @level_check_root_menu_id menuId
UNION ALL SELECT @sysadmin_role_id, @level_check_school_menu_id
UNION ALL SELECT @sysadmin_role_id, @level_check_unit_menu_id
UNION ALL SELECT @school_union_admin_role_id, @level_check_root_menu_id
UNION ALL SELECT @school_union_admin_role_id, @level_check_school_menu_id
UNION ALL SELECT @union_manager_role_id, @level_check_root_menu_id
UNION ALL SELECT @union_manager_role_id, @level_check_unit_menu_id
UNION ALL SELECT @third_unit_manager_role_id, @level_check_root_menu_id
UNION ALL SELECT @third_unit_manager_role_id, @level_check_unit_menu_id
) role_menu
WHERE NOT EXISTS (
SELECT 1 FROM sys_role_menu current_role_menu
WHERE current_role_menu.roleId = role_menu.roleId
AND current_role_menu.menuId = role_menu.menuId
);
INSERT INTO sys_config
(configKey, configValue, note, createdBy, createdAt, updatedBy, updatedAt, delFlag)
SELECT 'LevelCheckThirdAdminUnionId', IFNULL((
SELECT id FROM sys_union WHERE unionname = '机关党委工会' ORDER BY id LIMIT 1
), ''), '允许设置三级管理员的特殊工会ID', '', 0, '', 0, 0
WHERE NOT EXISTS (
SELECT 1 FROM sys_config WHERE configKey = 'LevelCheckThirdAdminUnionId'
);
@@ -0,0 +1,549 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava @vchange="guavaViewChange" ref="guava">
<template>
<el-card shadow="never">
<div slot="header">
<span>分级核对任务</span>
<el-button @click="uploadDialogVisible=true" icon="el-icon-upload2"
size="small" style="float:right" type="primary">上传并分发</el-button>
</div>
<el-alert :closable="false" show-icon style="margin-bottom:15px"
title="系统仅按 Excel 的“所在单位”列分发,文件名不参与匹配。"></el-alert>
<el-form :inline="true" :model="taskSearch" size="small">
<el-form-item label="任务名称">
<el-input clearable placeholder="请输入任务名称" v-model="taskSearch.taskName"></el-input>
</el-form-item>
<el-form-item label="任务日期">
<el-date-picker clearable format="yyyy-MM-dd" placeholder="请选择任务日期" type="date"
value-format="yyyy-MM-dd" v-model="taskSearch.taskDate"></el-date-picker>
</el-form-item>
<el-form-item>
<el-button @click="loadTasks(true)" icon="el-icon-search" type="primary">查询</el-button>
<el-button @click="resetTaskSearch">重置</el-button>
</el-form-item>
</el-form>
<el-table :data="tasks" border v-loading="loading">
<el-table-column label="任务名称" prop="name"></el-table-column>
<el-table-column align="center" label="任务日期" min-width="160">
<template slot-scope="scope">{{formatDateTime(scope.row.taskDate)}}</template>
</el-table-column>
<el-table-column align="center" label="完成进度" width="180">
<template slot-scope="scope">{{scope.row.finishedUnits || 0}} / {{scope.row.totalUnits || 0}}</template>
</el-table-column>
<el-table-column label="任务说明" prop="description" show-overflow-tooltip></el-table-column>
<el-table-column align="center" label="操作" width="300">
<template slot-scope="scope">
<el-button @click="openUnits(scope.row)" size="mini" type="primary">单位核对明细</el-button>
<el-button @click="openCurrentData(scope.row)" size="mini" type="primary">查看数据</el-button>
<el-button @click="deleteTask(scope.row)" size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination :current-page="taskPage.pageNumber" :page-size="taskPage.pageSize"
:page-sizes="[10,20,50,100]" :total="taskPage.totalCount"
@current-change="taskPageNumberChange" @size-change="taskPageSizeChange"
layout="total, sizes, prev, pager, next, jumper"
style="margin-top:15px;text-align:right"></el-pagination>
</el-card>
</template>
<template #edit_func>
<el-button @click="exportCurrent(dataTarget)" icon="el-icon-download"
size="small" type="primary"
v-if="detailView==='data' && dataScope==='task'">导出生效数据</el-button>
<template v-if="detailView==='data' && dataScope==='unit'">
<el-button @click="download(dataTarget,'original')" icon="el-icon-download"
size="small">下载原始数据</el-button>
<el-button @click="download(dataTarget,'pending')" icon="el-icon-download"
size="small" v-if="dataTarget.state===2">下载修改版</el-button>
<el-button @click="download(dataTarget,'current')" icon="el-icon-download"
size="small" type="primary"
v-if="dataVersionType==='current' && dataTarget.state===4">导出已核对版</el-button>
</template>
</template>
<template #edit>
<div key="unit-detail" v-if="detailView==='units'">
<el-divider content-position="left">{{currentTask.name}} - 单位核对明细</el-divider>
<el-form :inline="true" :model="unitSearch" size="small">
<el-form-item label="单位名称">
<el-input clearable placeholder="请输入单位名称" v-model="unitSearch.unitName"></el-input>
</el-form-item>
<el-form-item label="核对状态">
<el-select clearable placeholder="全部" v-model="unitSearch.state">
<el-option :key="index" :label="name" :value="index"
v-for="(name,index) in statusOptions"></el-option>
</el-select>
</el-form-item>
<el-form-item label="核对人员状态">
<el-select clearable placeholder="全部" v-model="unitSearch.managerState">
<el-option label="已分配核对人员" :value="1"></el-option>
<el-option label="未分配核对人员" :value="0"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="loadUnitTasks(true)" icon="el-icon-search" type="primary">查询</el-button>
<el-button @click="resetUnitSearch">重置</el-button>
</el-form-item>
</el-form>
<el-table :data="unitTasks" border v-loading="unitLoading">
<el-table-column label="单位" prop="unitName" show-overflow-tooltip></el-table-column>
<el-table-column align="center" label="行数" prop="rowCount" width="90"></el-table-column>
<el-table-column align="center" label="状态" width="120">
<template slot-scope="scope">
<el-tag :type="statusType(scope.row.state)">{{statusText(scope.row.state)}}</el-tag>
</template>
</el-table-column>
<el-table-column label="核对人员" min-width="180" show-overflow-tooltip>
<template slot-scope="scope">
<span v-if="scope.row.managerNames || scope.row.managernames">
{{scope.row.managerNames || scope.row.managernames}}
</span>
<el-tag type="warning" v-else>未分配核对人员</el-tag>
</template>
</el-table-column>
<el-table-column label="审核意见" prop="auditOpinion" show-overflow-tooltip></el-table-column>
<el-table-column align="center" label="核对日期" min-width="160">
<template slot-scope="scope">
{{formatDateTime(scope.row.checkedAt)}}
</template>
</el-table-column>
<el-table-column align="center" label="操作" width="450">
<template slot-scope="scope">
<el-button @click="openUnitData(scope.row)" size="mini" type="primary">查看原始数据</el-button>
<template v-if="scope.row.state===2">
<el-button @click="openUnitData(scope.row,'pending')" size="mini" type="primary">查看修改版</el-button>
<el-button @click="audit(scope.row,true)" size="mini" type="success">通过</el-button>
<el-button @click="audit(scope.row,false)" size="mini" type="danger">退回</el-button>
</template>
</template>
</el-table-column>
</el-table>
<el-pagination :current-page="unitPage.pageNumber" :page-size="unitPage.pageSize"
:page-sizes="[10,20,50,100]" :total="unitPage.totalCount"
@current-change="unitPageNumberChange" @size-change="unitPageSizeChange"
layout="total, sizes, prev, pager, next, jumper"
style="margin-top:15px;text-align:right"></el-pagination>
</div>
<div key="data-detail" v-else>
<el-divider content-position="left">{{dataDialogTitle}}</el-divider>
<el-form :inline="true" :model="dataSearch" size="small">
<el-form-item>
<el-input @keyup.enter.native="loadDataRows(true)" clearable placeholder="请输入查询内容"
v-model="dataSearch.searchKeyword">
<el-select placeholder="查询字段" slot="prepend" style="width:120px"
v-model="dataSearch.searchName">
<el-option label="薪酬单位代码" value="salaryUnitCode"></el-option>
<el-option label="职工号" value="employeeNo"></el-option>
<el-option label="姓名" value="employeeName"></el-option>
<el-option label="扣工会会费" value="unionFee"></el-option>
<el-option label="年月" value="yearMonth"></el-option>
<el-option label="所在单位" value="unitName"></el-option>
</el-select>
</el-input>
</el-form-item>
<el-form-item label="核对情况">
<el-select clearable placeholder="全部" v-model="dataSearch.state">
<el-option :key="index" :label="name" :value="index"
v-for="(name,index) in statusOptions"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="loadDataRows(true)" icon="el-icon-search" type="primary">查询</el-button>
<el-button @click="resetDataSearch">重置</el-button>
</el-form-item>
</el-form>
<el-table :data="dataRows" border v-loading="dataLoading">
<el-table-column align="center" label="序号" width="70">
<template slot-scope="scope">
{{scope.$index + (dataPage.pageNumber - 1) * dataPage.pageSize + 1}}
</template>
</el-table-column>
<el-table-column label="薪酬单位代码" min-width="130" prop="薪酬单位代码" show-overflow-tooltip></el-table-column>
<el-table-column label="职工号" min-width="120" prop="职工号" show-overflow-tooltip></el-table-column>
<el-table-column label="姓名" min-width="100" prop="姓名" show-overflow-tooltip></el-table-column>
<el-table-column label="扣工会会费" min-width="120" prop="扣工会会费" show-overflow-tooltip></el-table-column>
<el-table-column label="年月" min-width="100" prop="年月" show-overflow-tooltip></el-table-column>
<el-table-column label="所在单位" min-width="180" prop="所在单位" show-overflow-tooltip></el-table-column>
<el-table-column align="center" label="核对情况" min-width="110">
<template slot-scope="scope">
<el-tag :type="statusType(scope.row.state)">{{statusText(scope.row.state)}}</el-tag>
</template>
</el-table-column>
<el-table-column label="核对人员" min-width="180" show-overflow-tooltip>
<template slot-scope="scope">
<span v-if="scope.row.managerNames || scope.row.managernames">
{{scope.row.managerNames || scope.row.managernames}}
</span>
<el-tag type="warning" v-else>未分配核对人员</el-tag>
</template>
</el-table-column>
<el-table-column label="核对日期" min-width="160">
<template slot-scope="scope">
{{formatDateTime(scope.row.checkedAt)}}
</template>
</el-table-column>
</el-table>
<el-pagination :current-page="dataPage.pageNumber" :page-size="dataPage.pageSize"
:page-sizes="[10,20,50,100]" :total="dataPage.totalCount"
@current-change="dataPageNumberChange" @size-change="dataPageSizeChange"
layout="total, sizes, prev, pager, next, jumper"
style="margin-top:15px;text-align:right"></el-pagination>
</div>
</template>
</guava>
<el-dialog :close-on-click-modal="false" :visible.sync="uploadDialogVisible" title="上传并分发" width="50%">
<el-form label-width="90px">
<el-form-item label="任务名称" required>
<el-input maxlength="100" v-model="uploadForm.taskName"></el-input>
</el-form-item>
<el-form-item label="任务说明">
<el-input maxlength="500" type="textarea" v-model="uploadForm.description"></el-input>
</el-form-item>
<el-form-item label="Excel文件" required>
<el-upload :action="uploadAction" :auto-upload="false" :data="uploadForm"
:limit="20" :multiple="true" :on-error="uploadError"
:on-success="uploadSuccess" accept=".xls,.xlsx" name="files" ref="upload">
<el-button icon="el-icon-plus" size="small">选择文件</el-button>
<div class="el-upload__tip" slot="tip">可同时选择多个文件,数据按“所在单位”首段归组。</div>
</el-upload>
<el-button @click="downloadTemplate" icon="el-icon-download"
size="small" style="margin-top:10px">下载导入模板</el-button>
</el-form-item>
</el-form>
<span class="dialog-footer" slot="footer">
<el-button @click="uploadDialogVisible=false">取 消</el-button>
<el-button :loading="uploading" @click="submitUpload" type="primary">上传并分发</el-button>
</span>
</el-dialog>
<el-dialog :close-on-click-modal="false" :visible.sync="rejectDialogVisible"
title="退回修改版" width="45%">
<el-form label-width="90px">
<el-form-item label="退回原因" required>
<el-input :rows="5" maxlength="500" placeholder="请输入退回原因"
show-word-limit type="textarea" v-model="rejectOpinion"></el-input>
</el-form-item>
</el-form>
<span class="dialog-footer" slot="footer">
<el-button @click="rejectDialogVisible=false">取 消</el-button>
<el-button :loading="auditSubmitting" @click="submitReject" type="primary">确 定</el-button>
</span>
</el-dialog>
</div>
<script>
const vue = new Vue({
el: '#app',
data() {
return {
loading: false,
unitLoading: false,
uploading: false,
tasks: [],
unitTasks: [],
statusOptions: ['待核对', '已确认', '待审核', '已退回', '已通过'],
taskSearch: {taskName: '', taskDate: ''},
taskPage: {pageNumber: 1, pageSize: 20, totalCount: 0},
unitSearch: {unitName: '', state: null, managerState: null},
unitPage: {pageNumber: 1, pageSize: 20, totalCount: 0},
currentTask: {},
detailView: '',
dataTarget: {},
dataScope: '',
dataVersionType: 'current',
dataRows: [],
dataLoading: false,
dataDialogTitle: '',
dataSearch: {searchName: 'employeeNo', searchKeyword: '', state: null},
dataPage: {pageNumber: 1, pageSize: 10, totalCount: 0},
uploadDialogVisible: false,
uploadForm: {taskName: '', description: ''},
uploadAction: loc() + '/doUpload',
rejectDialogVisible: false,
rejectTarget: {},
rejectOpinion: '',
auditSubmitting: false
}
},
components: {
'guava': httpVueLoader('/components/plugins/Guava.vue')
},
methods: {
formatDateTime(value) {
return value ? moment(value).format('YYYY-MM-DD HH:mm') : '-'
},
statusText(state) {
return ['待核对', '已确认', '待审核', '已退回', '已通过'][state] || '未知'
},
statusType(state) {
return ['', 'success', 'warning', 'danger', 'success'][state] || 'info'
},
async loadTasks(resetPage) {
if (resetPage) this.taskPage.pageNumber = 1
this.loading = true
const resp = await $.post(loc() + '/taskData', {
taskName: this.taskSearch.taskName,
taskDate: this.taskSearch.taskDate,
pageNumber: this.taskPage.pageNumber,
pageSize: this.taskPage.pageSize
})
this.loading = false
if (resp.code === 0) {
const page = resp.data || {}
this.tasks = page.list || []
this.taskPage.totalCount = page.totalCount || 0
} else this.$notify.warning(resp.msg)
},
resetTaskSearch() {
this.taskSearch = {taskName: '', taskDate: ''}
this.loadTasks(true)
},
taskPageNumberChange(value) {
this.taskPage.pageNumber = value
this.loadTasks(false)
},
taskPageSizeChange(value) {
this.taskPage.pageSize = value
this.loadTasks(true)
},
submitUpload() {
if (!this.uploadForm.taskName) {
this.$notify.warning('请输入任务名称')
return
}
if (!this.$refs.upload.uploadFiles.length) {
this.$notify.warning('请选择 Excel 文件')
return
}
this.uploading = true
const formData = new FormData()
formData.append('taskName', this.uploadForm.taskName)
formData.append('description', this.uploadForm.description || '')
this.$refs.upload.uploadFiles.forEach(item => formData.append('files', item.raw))
$.ajax({
url: this.uploadAction,
type: 'POST',
data: formData,
processData: false,
contentType: false,
dataType: 'json',
success: resp => this.uploadSuccess(resp),
error: () => this.uploadError()
})
},
downloadTemplate() {
window.open(loc() + '/downloadTemplate')
},
uploadSuccess(resp) {
this.uploading = false
if (resp.code === 0) {
this.uploadDialogVisible = false
this.$refs.upload.clearFiles()
this.loadTasks(true)
const result = resp.data || {}
if (result.errorCount > 0) {
this.$confirm('共读取 ' + result.totalCount + ' 条,成功分发 ' + result.successCount
+ ' 条,失败 ' + result.errorCount + ' 条。', '导入完成', {
confirmButtonText: '导出错误信息',
cancelButtonText: '关闭',
type: 'warning'
}).then(() => {
window.open(loc() + '/exportImportErrors?cacheKey=' + encodeURIComponent(result.errorCacheKey))
}).catch(() => {})
} else {
this.$notify.success(resp.msg)
}
} else {
this.$notify.warning(resp.msg)
}
},
uploadError() {
this.uploading = false
this.$notify.error('上传失败')
},
async openUnits(row) {
this.currentTask = row
this.detailView = 'units'
this.unitSearch = {unitName: '', state: null, managerState: null}
this.unitPage.pageNumber = 1
this.$refs.guava.edit()
await this.loadUnitTasks(false)
},
guavaViewChange(view) {
if (view.newValue === 'index' && view.oldValue === 'edit'
&& this.detailView === 'data' && this.dataScope === 'unit') {
this.detailView = 'units'
this.$nextTick(() => this.$refs.guava.edit())
}
},
async loadUnitTasks(resetPage) {
if (resetPage) this.unitPage.pageNumber = 1
this.unitLoading = true
const resp = await $.post(loc() + '/unitTaskData', {
taskId: this.currentTask.id,
unitName: this.unitSearch.unitName,
state: this.unitSearch.state,
managerState: this.unitSearch.managerState,
pageNumber: this.unitPage.pageNumber,
pageSize: this.unitPage.pageSize
})
this.unitLoading = false
if (resp.code === 0) {
const page = resp.data || {}
this.unitTasks = page.list || []
this.unitPage.totalCount = page.totalCount || 0
} else this.$notify.warning(resp.msg)
},
resetUnitSearch() {
this.unitSearch = {unitName: '', state: null, managerState: null}
this.loadUnitTasks(true)
},
unitPageNumberChange(value) {
this.unitPage.pageNumber = value
this.loadUnitTasks(false)
},
unitPageSizeChange(value) {
this.unitPage.pageSize = value
this.loadUnitTasks(true)
},
openUnitData(row, versionType) {
this.detailView = 'data'
this.dataScope = 'unit'
this.dataVersionType = versionType || 'current'
this.dataTarget = row
this.dataDialogTitle = row.unitName
+ (this.dataVersionType === 'pending' ? ' - 待审核修改版数据' : ' - 当前生效数据')
this.dataSearch = {searchName: 'employeeNo', searchKeyword: '', state: null}
this.dataPage.pageNumber = 1
this.$refs.guava.edit()
this.loadDataRows(false)
},
openCurrentData(row) {
this.detailView = 'data'
this.dataScope = 'task'
this.dataVersionType = 'current'
this.dataTarget = row
this.dataDialogTitle = row.name + ' - 生效数据'
this.dataSearch = {searchName: 'employeeNo', searchKeyword: '', state: null}
this.dataPage.pageNumber = 1
this.$refs.guava.edit()
this.loadDataRows(false)
},
async loadDataRows(resetPage) {
if (resetPage) this.dataPage.pageNumber = 1
this.dataLoading = true
const url = this.dataScope === 'unit' ? '/unitDataPage' : '/currentDataPage'
const params = {
searchName: this.dataSearch.searchName,
searchKeyword: this.dataSearch.searchKeyword,
state: this.dataSearch.state,
pageNumber: this.dataPage.pageNumber,
pageSize: this.dataPage.pageSize
}
if (this.dataScope === 'unit') {
params.unitTaskId = this.dataTarget.id
params.versionType = this.dataVersionType
}
else params.taskId = this.dataTarget.id
const resp = await $.post(loc() + url, params)
this.dataLoading = false
if (resp.code === 0) {
const page = resp.data || {}
this.dataRows = page.list || []
this.dataPage.totalCount = page.totalCount || 0
} else {
this.dataRows = []
this.dataPage.totalCount = 0
this.$notify.warning(resp.msg)
}
},
resetDataSearch() {
this.dataSearch = {searchName: 'employeeNo', searchKeyword: '', state: null}
this.loadDataRows(true)
},
dataPageNumberChange(value) {
this.dataPage.pageNumber = value
this.loadDataRows(false)
},
dataPageSizeChange(value) {
this.dataPage.pageSize = value
this.loadDataRows(true)
},
download(row, versionType) {
window.open(loc() + '/download?unitTaskId=' + row.id + '&versionType=' + versionType)
},
exportCurrent(row) {
window.open(loc() + '/exportCurrent?taskId=' + row.id)
},
async deleteTask(row) {
try {
await this.$confirm('删除后,该任务的单位数据、修改数据和审核记录都将被清除,且无法恢复。',
'确认删除“' + row.name + '”?', {
confirmButtonText: '确认删除',
cancelButtonText: '取消',
type: 'warning'
})
} catch (e) {
return
}
const resp = await $.post(loc() + '/doDelete', {taskId: row.id})
if (resp.code === 0) {
this.$notify.success(resp.msg)
if (this.currentTask.id === row.id) {
this.$refs.guava.index()
this.currentTask = {}
this.unitTasks = []
}
if (this.dataScope === 'task' && this.dataTarget.id === row.id) {
this.$refs.guava.index()
this.dataTarget = {}
this.dataRows = []
}
this.loadTasks(false)
} else this.$notify.warning(resp.msg)
},
async audit(row, approved) {
if (!approved) {
this.rejectTarget = row
this.rejectOpinion = ''
this.rejectDialogVisible = true
return
}
await this.submitAudit(row, true, '')
},
async submitReject() {
const opinion = (this.rejectOpinion || '').trim()
if (!opinion) {
this.$notify.warning('请输入退回原因')
return
}
this.auditSubmitting = true
const success = await this.submitAudit(this.rejectTarget, false, opinion)
this.auditSubmitting = false
if (success) this.rejectDialogVisible = false
},
async submitAudit(row, approved, opinion) {
const resp = await $.post(loc() + '/doAudit', {unitTaskId: row.id, approved, opinion})
if (resp.code === 0) {
this.$notify.success(resp.msg)
await this.loadUnitTasks(false)
this.loadTasks(false)
return true
}
this.$notify.warning(resp.msg)
return false
}
},
created() {
this.loadTasks(false)
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,318 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<div slot="header">我的分级核对任务</div>
<el-alert :closable="false" show-icon style="margin-bottom:15px" type="warning"
title="温馨提示:请先下载或查看核对数据。若数据有误,请按原模板修改后上传修改版,提交后进入校工会审核;若数据无误,无需上传文件,进入“核对数据”页面点击“确认无误”即可完成核对。"></el-alert>
<el-form :inline="true" :model="searchForm" size="small">
<el-form-item label="任务/单位">
<el-input clearable placeholder="请输入任务名称、单位或任务日期" v-model="searchForm.keyword"></el-input>
</el-form-item>
<el-form-item label="核对状态">
<el-select clearable placeholder="全部" v-model="searchForm.state">
<el-option :key="index" :label="name" :value="index"
v-for="(name,index) in statusOptions"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="loadTasks(true)" icon="el-icon-search" type="primary">查询</el-button>
<el-button @click="resetSearch">重置</el-button>
</el-form-item>
</el-form>
<el-table :data="tasks" border v-loading="loading">
<el-table-column label="任务名称" prop="taskName" show-overflow-tooltip></el-table-column>
<el-table-column label="单位" prop="unitName" show-overflow-tooltip></el-table-column>
<el-table-column align="center" label="任务日期" min-width="160">
<template slot-scope="scope">{{formatDateTime(scope.row.taskDate || scope.row.taskdate)}}</template>
</el-table-column>
<el-table-column align="center" label="核对日期" min-width="160">
<template slot-scope="scope">
{{formatDateTime(scope.row.checkedAt)}}
</template>
</el-table-column>
<el-table-column align="center" label="行数" prop="rowCount" width="80"></el-table-column>
<el-table-column align="center" label="状态" width="110">
<template slot-scope="scope">
<el-tag :type="statusType(scope.row.state)">{{statusText(scope.row.state)}}</el-tag>
</template>
</el-table-column>
<el-table-column label="审核意见" prop="auditOpinion" show-overflow-tooltip></el-table-column>
<el-table-column align="center" label="操作" width="350">
<template slot-scope="scope">
<el-button @click="openData(scope.row)" size="mini" type="primary">核对数据</el-button>
<el-button @click="download(scope.row)" size="mini">下载数据</el-button>
<!--<el-button @click="confirm(scope.row)" size="mini" type="success"
v-if="scope.row.state===0">确认无误</el-button>-->
<el-button @click="openRevision(scope.row)" size="mini" type="primary"
v-if="scope.row.state===0 || scope.row.state===3">上传修改版</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination :current-page="pageForm.pageNumber" :page-size="pageForm.pageSize"
:page-sizes="[10,20,50,100]" :total="pageForm.totalCount"
@current-change="pageNumberChange" @size-change="pageSizeChange"
layout="total, sizes, prev, pager, next, jumper"
style="margin-top:15px;text-align:right"></el-pagination>
</el-card>
</template>
<template #edit_func>
<el-button @click="confirm(currentTask)" size="small" type="success"
v-if="currentTask.state===0">确认无误</el-button>
<el-button @click="openRevision(currentTask)" size="small" type="primary"
v-if="currentTask.state===0 || currentTask.state===3">上传修改版</el-button>
</template>
<template #edit>
<el-divider content-position="left">{{dataDialogTitle}}</el-divider>
<el-form :inline="true" :model="dataSearch" size="small">
<el-form-item>
<el-input @keyup.enter.native="loadDataRows(true)" clearable placeholder="请输入查询内容"
v-model="dataSearch.searchKeyword">
<el-select placeholder="查询字段" slot="prepend" style="width:120px"
v-model="dataSearch.searchName">
<el-option label="薪酬单位代码" value="salaryUnitCode"></el-option>
<el-option label="职工号" value="employeeNo"></el-option>
<el-option label="姓名" value="employeeName"></el-option>
<el-option label="扣工会会费" value="unionFee"></el-option>
<el-option label="年月" value="yearMonth"></el-option>
<el-option label="所在单位" value="unitName"></el-option>
</el-select>
</el-input>
</el-form-item>
<el-form-item label="核对情况">
<el-select clearable placeholder="全部" v-model="dataSearch.state">
<el-option :key="index" :label="name" :value="index"
v-for="(name,index) in statusOptions"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="loadDataRows(true)" icon="el-icon-search" type="primary">查询</el-button>
<el-button @click="resetDataSearch">重置</el-button>
</el-form-item>
</el-form>
<el-table :data="dataRows" border v-loading="dataLoading">
<el-table-column align="center" label="序号" width="70">
<template slot-scope="scope">
{{scope.$index + (dataPage.pageNumber - 1) * dataPage.pageSize + 1}}
</template>
</el-table-column>
<el-table-column label="薪酬单位代码" min-width="130" prop="薪酬单位代码" show-overflow-tooltip></el-table-column>
<el-table-column label="职工号" min-width="120" prop="职工号" show-overflow-tooltip></el-table-column>
<el-table-column label="姓名" min-width="100" prop="姓名" show-overflow-tooltip></el-table-column>
<el-table-column label="扣工会会费" min-width="120" prop="扣工会会费" show-overflow-tooltip></el-table-column>
<el-table-column label="年月" min-width="100" prop="年月" show-overflow-tooltip></el-table-column>
<el-table-column label="所在单位" min-width="180" prop="所在单位" show-overflow-tooltip></el-table-column>
<el-table-column align="center" label="核对情况" min-width="110">
<template slot-scope="scope">
<el-tag :type="statusType(scope.row.state)">{{statusText(scope.row.state)}}</el-tag>
</template>
</el-table-column>
<el-table-column label="核对人员" min-width="180" show-overflow-tooltip>
<template slot-scope="scope">
<span v-if="scope.row.managerNames || scope.row.managernames">
{{scope.row.managerNames || scope.row.managernames}}
</span>
<el-tag type="warning" v-else>未分配核对人员</el-tag>
</template>
</el-table-column>
<el-table-column label="核对日期" min-width="160">
<template slot-scope="scope">
{{formatDateTime(scope.row.checkedAt)}}
</template>
</el-table-column>
</el-table>
<el-pagination :current-page="dataPage.pageNumber" :page-size="dataPage.pageSize"
:page-sizes="[10,20,50,100]" :total="dataPage.totalCount"
@current-change="dataPageNumberChange" @size-change="dataPageSizeChange"
layout="total, sizes, prev, pager, next, jumper"
style="margin-top:15px;text-align:right"></el-pagination>
</template>
</guava>
<el-dialog :visible.sync="revisionDialogVisible" title="上传修改后的数据" width="45%">
<el-alert :closable="false" show-icon style="margin-bottom:15px" type="warning"
title="修改版必须使用固定导入模板,且只能包含当前单位数据。"></el-alert>
<el-upload :action="revisionAction" :auto-upload="false" :data="revisionData"
:limit="1" :on-error="uploadError" :on-success="uploadSuccess"
accept=".xls,.xlsx" name="file" ref="revisionUpload">
<el-button icon="el-icon-plus" size="small">选择修改版</el-button>
</el-upload>
<span class="dialog-footer" slot="footer">
<el-button @click="revisionDialogVisible=false">取 消</el-button>
<el-button :loading="uploading" @click="submitRevision" type="primary">提 交</el-button>
</span>
</el-dialog>
</div>
<script>
const vue = new Vue({
el: '#app',
data() {
return {
loading: false,
uploading: false,
tasks: [],
currentTask: {},
dataRows: [],
dataLoading: false,
dataDialogTitle: '',
dataSearch: {searchName: 'employeeNo', searchKeyword: '', state: null},
dataPage: {pageNumber: 1, pageSize: 10, totalCount: 0},
statusOptions: ['待核对', '已确认', '待审核', '已退回', '已通过'],
searchForm: {keyword: '', state: null},
pageForm: {pageNumber: 1, pageSize: 10, totalCount: 0},
revisionDialogVisible: false,
revisionAction: loc() + '/doUploadRevision',
revisionData: {unitTaskId: ''}
}
},
components: {
'guava': httpVueLoader('/components/plugins/Guava.vue')
},
methods: {
formatDateTime(value) {
return value ? moment(value).format('YYYY-MM-DD HH:mm') : '-'
},
statusText(state) {
return ['待核对', '已确认', '待审核', '已退回', '已通过'][state] || '未知'
},
statusType(state) {
return ['', 'success', 'warning', 'danger', 'success'][state] || 'info'
},
async loadTasks(resetPage) {
if (resetPage) this.pageForm.pageNumber = 1
this.loading = true
const resp = await $.post(loc() + '/taskData', {
keyword: this.searchForm.keyword,
state: this.searchForm.state,
pageNumber: this.pageForm.pageNumber,
pageSize: this.pageForm.pageSize
})
this.loading = false
if (resp.code === 0) {
const page = resp.data || {}
this.tasks = page.list || []
this.pageForm.totalCount = page.totalCount || 0
} else this.$notify.warning(resp.msg)
},
resetSearch() {
this.searchForm = {keyword: '', state: null}
this.loadTasks(true)
},
pageNumberChange(value) {
this.pageForm.pageNumber = value
this.loadTasks(false)
},
pageSizeChange(value) {
this.pageForm.pageSize = value
this.loadTasks(true)
},
download(row) {
window.open(loc() + '/download?unitTaskId=' + row.id)
},
openData(row) {
this.currentTask = row
this.dataDialogTitle = row.taskName + ' - ' + row.unitName + ' - 数据详情'
this.dataSearch = {searchName: 'employeeNo', searchKeyword: '', state: null}
this.dataPage.pageNumber = 1
this.$refs.guava.edit()
this.loadDataRows(false)
},
async loadDataRows(resetPage) {
if (resetPage) this.dataPage.pageNumber = 1
this.dataLoading = true
const resp = await $.post(loc() + '/dataPage', {
unitTaskId: this.currentTask.id,
searchName: this.dataSearch.searchName,
searchKeyword: this.dataSearch.searchKeyword,
state: this.dataSearch.state,
pageNumber: this.dataPage.pageNumber,
pageSize: this.dataPage.pageSize
})
this.dataLoading = false
if (resp.code === 0) {
const page = resp.data || {}
this.dataRows = page.list || []
this.dataPage.totalCount = page.totalCount || 0
} else {
this.dataRows = []
this.dataPage.totalCount = 0
this.$notify.warning(resp.msg)
}
},
resetDataSearch() {
this.dataSearch = {searchName: 'employeeNo', searchKeyword: '', state: null}
this.loadDataRows(true)
},
dataPageNumberChange(value) {
this.dataPage.pageNumber = value
this.loadDataRows(false)
},
dataPageSizeChange(value) {
this.dataPage.pageSize = value
this.loadDataRows(true)
},
async confirm(row) {
try {
await this.$confirm('确认本单位数据无误吗?确认后不能再上传修改数据,无修改内容时不会进入审核流程!', '提示', {type: 'warning'})
} catch (e) {
return
}
const resp = await $.post(loc() + '/doConfirm', {unitTaskId: row.id})
if (resp.code === 0) {
this.$notify.success(resp.msg)
this.$refs.guava.index()
this.loadTasks(false)
} else this.$notify.warning(resp.msg)
},
openRevision(row) {
this.revisionData.unitTaskId = row.id
this.revisionDialogVisible = true
this.$nextTick(() => this.$refs.revisionUpload.clearFiles())
},
submitRevision() {
if (!this.$refs.revisionUpload.uploadFiles.length) {
this.$notify.warning('请选择修改版 Excel')
return
}
this.uploading = true
const formData = new FormData()
formData.append('unitTaskId', this.revisionData.unitTaskId)
formData.append('file', this.$refs.revisionUpload.uploadFiles[0].raw)
$.ajax({
url: this.revisionAction,
type: 'POST',
data: formData,
processData: false,
contentType: false,
dataType: 'json',
success: resp => this.uploadSuccess(resp),
error: () => this.uploadError()
})
},
uploadSuccess(resp) {
this.uploading = false
if (resp.code === 0) {
this.$notify.success(resp.msg)
this.revisionDialogVisible = false
this.$refs.guava.index()
this.loadTasks(false)
} else this.$notify.warning(resp.msg)
},
uploadError() {
this.uploading = false
this.$notify.error('上传失败')
}
},
created() {
this.loadTasks(false)
}
})
</script>
<!--#
}
#-->
@@ -306,6 +306,22 @@ layout("/layouts/platform.html"){
<el-table-column align="center" header-align="center" label="单位名称" <el-table-column align="center" header-align="center" label="单位名称"
prop="name"> prop="name">
</el-table-column> </el-table-column>
<el-table-column align="center" header-align="center" label="单位管理员"
prop="thirdmanagernames" show-overflow-tooltip
v-if="isSpecialUnion">
<template slot-scope="scope">
{{scope.row.thirdmanagernames || '未设置'}}
</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="操作"
width="250" v-if="isSpecialUnion">
<template slot-scope="scope">
<el-button @click="openThirdManager(scope.row, false)" size="mini">编辑</el-button>
<el-button @click="openThirdManager(scope.row, true)" size="mini" type="primary">
设置单位管理员
</el-button>
</template>
</el-table-column>
</el-table> </el-table>
</el-card> </el-card>
</el-tab-pane> </el-tab-pane>
@@ -433,6 +449,26 @@ layout("/layouts/platform.html"){
</span> </span>
</el-dialog> </el-dialog>
<el-dialog :title="thirdManagerQuick ? '设置单位管理员' : '编辑成员单位'"
:visible.sync="thirdManagerDialogVisible" width="55%">
<el-form label-width="100px">
<el-form-item label="成员单位">
<el-input :value="thirdManagerUnit.name" disabled></el-input>
</el-form-item>
<el-form-item label="单位管理员">
<el-select filterable multiple placeholder="请选择单位管理员" style="width:100%"
v-model="thirdManagerUserIds">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in thirdManagerUsers"></el-option>
</el-select>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="thirdManagerDialogVisible=false">取 消</el-button>
<el-button @click="doSetThirdManager" type="primary">确 定</el-button>
</span>
</el-dialog>
<el-dialog <el-dialog
title="设置管理员" title="设置管理员"
:visible.sync="fzrDialogVisible" width="55%"> :visible.sync="fzrDialogVisible" width="55%">
@@ -630,6 +666,11 @@ layout("/layouts/platform.html"){
fzrValue: [], fzrValue: [],
data: [], data: [],
zcdwTableData: [], zcdwTableData: [],
thirdManagerDialogVisible: false,
thirdManagerQuick: false,
thirdManagerUnit: {},
thirdManagerUsers: [],
thirdManagerUserIds: [],
lxrTableData: [], lxrTableData: [],
defaultProps: { defaultProps: {
children: 'childrens', children: 'childrens',
@@ -762,7 +803,42 @@ layout("/layouts/platform.html"){
return val return val
}, },
}, },
computed: {
isSpecialUnion() {
return this.sysadmin && this.node && this.node.data
&& this.node.data.unionname === '机关党委工会'
}
},
methods: { methods: {
async openThirdManager(row, quick) {
const resp = await $.post(loc() + '/findThirdUnitManagerUsers', {
unionId: this.node.data.id,
unitId: row.id
})
if (resp.code === 0) {
this.thirdManagerQuick = quick
this.thirdManagerUnit = row
this.thirdManagerUsers = resp.data.allusers
this.thirdManagerUserIds = resp.data.selecteduserids
this.thirdManagerDialogVisible = true
} else {
this.$notify.warning(resp.msg)
}
},
async doSetThirdManager() {
const resp = await $.post(loc() + '/doSetThirdUnitManagerUsers', {
unionId: this.node.data.id,
unitId: this.thirdManagerUnit.id,
userIds: JSON.stringify(this.thirdManagerUserIds)
})
if (resp.code === 0) {
this.thirdManagerDialogVisible = false
this.$notify.success(resp.msg)
this.getZcdwTabData()
} else {
this.$notify.warning(resp.msg)
}
},
doExport() { doExport() {
window.location.href = loc() + "/doExport" window.location.href = loc() + "/doExport"
}, },