体检管理

This commit is contained in:
2026-11-12 09:39:55 +08:00
parent c05014fd87
commit 0397547b19
49 changed files with 7304 additions and 2287 deletions
+1 -1
View File
@@ -182,8 +182,8 @@
<properties> <properties>
<easypoi.version>4.5.0</easypoi.version> <easypoi.version>4.5.0</easypoi.version>
<jsoup.veision>1.15.3</jsoup.veision> <jsoup.veision>1.15.3</jsoup.veision>
<tomcat.version>9.0.121</tomcat.version>
<mysql-connector-java.version>8.0.28</mysql-connector-java.version> <mysql-connector-java.version>8.0.28</mysql-connector-java.version>
<tomcat.version>9.0.121</tomcat.version>
<sa-token.version>1.25.0</sa-token.version> <sa-token.version>1.25.0</sa-token.version>
<easy-captcha.version>1.6.2</easy-captcha.version> <easy-captcha.version>1.6.2</easy-captcha.version>
<emoji-java.veision>4.0.0</emoji-java.veision> <emoji-java.veision>4.0.0</emoji-java.veision>
@@ -10,6 +10,7 @@ import com.budwk.app.base.result.Result;
import com.budwk.app.sys.models.Sys_home_activity; import com.budwk.app.sys.models.Sys_home_activity;
import com.budwk.app.sys.models.Sys_menu; import com.budwk.app.sys.models.Sys_menu;
import com.budwk.app.sys.services.SysMenuService; import com.budwk.app.sys.services.SysMenuService;
import com.budwk.app.sys.services.SysHomeActivityService;
import com.budwk.app.sys.services.SysUserService; import com.budwk.app.sys.services.SysUserService;
import com.budwk.app.web.commons.auth.utils.SecurityUtil; import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.activity.basic.models.ActivityUserScope; import com.budwk.app.zhgh.activity.basic.models.ActivityUserScope;
@@ -57,6 +58,8 @@ public class SysHomeController {
@Inject @Inject
private SysUserService sysUserService; private SysUserService sysUserService;
@Inject @Inject
private SysHomeActivityService sysHomeActivityService;
@Inject
private RedisService redisService; private RedisService redisService;
@At("") @At("")
@@ -195,9 +198,9 @@ public class SysHomeController {
@SaCheckLogin @SaCheckLogin
@ApiOperation("首页推送活动") @ApiOperation("首页推送活动")
@Ok("json") @Ok("json")
public Result listHomeActivity() { public Result listHomeActivity(String platform) {
FieldFilter fieldFilter = FieldFilter.locked(Sys_home_activity.class, "classPath"); // platform=PC 仅过滤电脑首页;手机端未传此参数时保持原范围,返回 Result.data 活动列表。
List<Sys_home_activity> list = Daos.ext(dao, fieldFilter).query(Sys_home_activity.class, Cnd.where("enable", "=", 1).desc("top")); List<Sys_home_activity> list = sysHomeActivityService.listHomeCandidates(platform);
String userId = SecurityUtil.getUserId(); String userId = SecurityUtil.getUserId();
List<Sys_home_activity> allowActivityList = new ArrayList<>(); List<Sys_home_activity> allowActivityList = new ArrayList<>();
// 今天的时间 // 今天的时间
@@ -3,5 +3,13 @@ package com.budwk.app.sys.services;
import com.budwk.app.base.service.BaseService; import com.budwk.app.base.service.BaseService;
import com.budwk.app.sys.models.Sys_home_activity; import com.budwk.app.sys.models.Sys_home_activity;
import java.util.List;
public interface SysHomeActivityService extends BaseService<Sys_home_activity> { public interface SysHomeActivityService extends BaseService<Sys_home_activity> {
/**
* 查询首页启用活动,PC 端排除仅在手机端报名的体检项目。
* @param platform PC 表示电脑首页;其他值保留原活动范围
* @return 按置顶顺序排列的候选活动,人员范围和时间仍由原流程判断
*/
List<Sys_home_activity> listHomeCandidates(String platform);
} }
@@ -4,6 +4,11 @@ import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.sys.models.Sys_home_activity; import com.budwk.app.sys.models.Sys_home_activity;
import com.budwk.app.sys.services.SysHomeActivityService; import com.budwk.app.sys.services.SysHomeActivityService;
import org.nutz.dao.Dao; import org.nutz.dao.Dao;
import org.nutz.dao.Cnd;
import org.nutz.dao.FieldFilter;
import org.nutz.dao.util.Daos;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupProject;
import java.util.List;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
@IocBean(args = {"refer:dao"}) @IocBean(args = {"refer:dao"})
@@ -12,4 +17,17 @@ public class SysHomeActivityServiceImpl extends BaseServiceImpl<Sys_home_activit
public SysHomeActivityServiceImpl(Dao dao) { public SysHomeActivityServiceImpl(Dao dao) {
super(dao); super(dao);
} }
/** {@inheritDoc} */
@Override
public List<Sys_home_activity> listHomeCandidates(String platform) {
Cnd condition = Cnd.where("enable", "=", 1);
if ("PC".equalsIgnoreCase(platform)) {
// 保留未绑定业务类的手工活动,仅排除体检项目生成的首页活动。
condition.and(Cnd.exps("classPath", "is", null)
.or("classPath", "!=", HealthCheckupProject.class.getName()));
}
condition.desc("top");
return Daos.ext(dao(), FieldFilter.locked(Sys_home_activity.class, "classPath"))
.query(Sys_home_activity.class, condition);
}
} }
@@ -1,25 +1,21 @@
package com.budwk.app.zhgh.dayofficework.healthCheckup.controller; package com.budwk.app.zhgh.dayofficework.healthCheckup.controller;
import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupCampusApplicationService;
import cn.dev33.satoken.annotation.SaCheckLogin; import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckPermission;
import com.budwk.app.base.annotation.SLog; import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.param.PageForm; import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result; import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupCampus; import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupCampus;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param; import org.nutz.mvc.annotation.Param;
import java.util.List;
/** /**
* @ClassName HealthCheckupCampusController * @ClassName HealthCheckupCampusController
@@ -36,9 +32,10 @@ import java.util.List;
public class HealthCheckupCampusController { public class HealthCheckupCampusController {
@Inject @Inject
private BaseService baseService; private HealthCheckupCampusApplicationService applicationService;
@At("")
@At("")
@Ok("beetl:/platform/zhgh/dayofficework/healthCheckup/campus/index.html") @Ok("beetl:/platform/zhgh/dayofficework/healthCheckup/campus/index.html")
@SaCheckPermission("healthCheckup.campus") @SaCheckPermission("healthCheckup.campus")
public void index() { public void index() {
@@ -48,51 +45,25 @@ public class HealthCheckupCampusController {
@ApiOperation("分页查询") @ApiOperation("分页查询")
@SaCheckPermission("healthCheckup.campus") @SaCheckPermission("healthCheckup.campus")
public Result pageData(PageForm pageForm, @Param(value = "campusName") String campusName) { public Result pageData(PageForm pageForm, @Param(value = "campusName") String campusName) {
Cnd cnd = Cnd.NEW(); return applicationService.pageData(pageForm, campusName);
Sql sql = Sqls.create("select * from health_checkup_campus $condition");
cnd.and(Cnd.likeEX("campusName", campusName));
cnd.asc("campusCode");
sql.setCondition(cnd);
return Result.success(baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql));
} }
@At @At
@ApiOperation("添加院区") @ApiOperation("添加院区")
@SLog(type = "healthCheckup", tag = "体检管理", msg = "添加院区") @SLog(type = "healthCheckup", tag = "体检管理", msg = "添加院区")
@SaCheckPermission("healthCheckup.campus") @SaCheckPermission("healthCheckup.campus")
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result doAdd(HealthCheckupCampus campus) { public Result doAdd(HealthCheckupCampus campus) {
try { return applicationService.doAdd(campus);
int count = baseService.dao().count(HealthCheckupCampus.class, Cnd.where(HealthCheckupCampus::getCampusCode, "=", campus.getCampusCode()));
if (count > 0) {
return Result.error("编码重复");
}
baseService.dao().insert(campus);
return Result.success();
} catch (Exception e) {
e.printStackTrace();
return Result.error();
}
} }
@At @At
@ApiOperation("编辑院区") @ApiOperation("编辑院区")
@SLog(type = "healthCheckup", tag = "体检管理", msg = "编辑院区") @SLog(type = "healthCheckup", tag = "体检管理", msg = "编辑院区")
@SaCheckPermission("healthCheckup.campus") @SaCheckPermission("healthCheckup.campus")
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result doEdit(HealthCheckupCampus campus) { public Result doEdit(HealthCheckupCampus campus) {
try { return applicationService.doEdit(campus);
int count = baseService.dao().count(HealthCheckupCampus.class,
Cnd.where(HealthCheckupCampus::getCampusCode, "=", campus.getCampusCode())
.and(HealthCheckupCampus::getId, "!=", campus.getId()));
if (count > 0) {
return Result.error("编码重复");
}
baseService.dao().update(campus);
return Result.success();
} catch (Exception e) {
e.printStackTrace();
return Result.error();
}
} }
@@ -100,26 +71,15 @@ public class HealthCheckupCampusController {
@ApiOperation("编辑院区") @ApiOperation("编辑院区")
@SLog(type = "healthCheckup", tag = "体检管理", msg = "删除院区") @SLog(type = "healthCheckup", tag = "体检管理", msg = "删除院区")
@SaCheckPermission("healthCheckup.campus") @SaCheckPermission("healthCheckup.campus")
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result doDelete(String id) { public Result doDelete(String id) {
try { return applicationService.doDelete(id);
baseService.dao().clear(HealthCheckupCampus.class, Cnd.where(HealthCheckupCampus::getId, "=", id));
return Result.success();
} catch (Exception e) {
e.printStackTrace();
return Result.error();
}
} }
@At @At
@ApiOperation("查询所有院区") @ApiOperation("查询所有院区")
@SaCheckLogin @SaCheckLogin
public Result queryCampus() { public Result queryCampus() {
try { return applicationService.queryCampus();
List<HealthCheckupCampus> campusList = baseService.dao().query(HealthCheckupCampus.class, Cnd.NEW().asc("campusCode"));
return Result.success(campusList);
} catch (Exception e) {
e.printStackTrace();
return Result.error();
}
} }
} }
@@ -1,45 +1,21 @@
package com.budwk.app.zhgh.dayofficework.healthCheckup.controller; package com.budwk.app.zhgh.dayofficework.healthCheckup.controller;
import cn.afterturn.easypoi.excel.ExcelExportUtil; import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupListApplicationService;
import cn.afterturn.easypoi.excel.entity.ExportParams; import com.budwk.app.zhgh.dayofficework.healthCheckup.param.HealthCheckupFilterUserPageForm;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity; import javax.validation.Valid;
import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.budwk.app.base.annotation.SLog; import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.model.ExcelImportRes;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm; import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result; import com.budwk.app.base.result.Result;
import com.budwk.app.base.utils.CommonDownloadUtil;
import com.budwk.app.base.utils.easyexcel.EasyExcelUtil;
import com.budwk.app.sys.views.View_user;
import com.budwk.app.web.commons.auth.utils.AuthUtil;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.activity.basic.models.ActivityUserScope;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.*; import com.budwk.app.zhgh.dayofficework.healthCheckup.model.*;
import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupProjectService; import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupProjectService;
import com.budwk.app.zhgh.dayofficework.healthCheckup.template.HealthCheckupImportTemp;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.apache.poi.ss.usermodel.Workbook;
import org.nutz.aop.interceptor.ioc.TransAop; import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.ioc.aop.Aop; import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.AdaptBy; import org.nutz.mvc.annotation.AdaptBy;
import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Ok;
@@ -47,11 +23,7 @@ import org.nutz.mvc.upload.TempFile;
import org.nutz.mvc.upload.UploadAdaptor; import org.nutz.mvc.upload.UploadAdaptor;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
/** /**
* @ClassName HealthCheckupListController * @ClassName HealthCheckupListController
@@ -67,88 +39,53 @@ import java.util.stream.Collectors;
public class HealthCheckupListController { public class HealthCheckupListController {
@Inject @Inject
private Dao dao; private HealthCheckupListApplicationService applicationService;
@Inject
@Inject
private HealthCheckupProjectService healthCheckupProjectService; private HealthCheckupProjectService healthCheckupProjectService;
@At("") @At("")
@Ok("beetl:/platform/zhgh/dayofficework/healthCheckup/listMange/index.html") @Ok("beetl:/platform/zhgh/dayofficework/healthCheckup/listMange/index.html")
@SaCheckPermission("healthCheckup.list.mange") @SaCheckPermission("healthCheckup.list.mange")
public void index() { public void index() {
} }
@At("/feedback/query")
@Ok("beetl:/platform/zhgh/dayofficework/healthCheckup/feedbackQuery/index.html")
@SaCheckPermission("healthCheckup.list.mange.feedback")
public void feedbackQueryIndex() {
}
/**
* @param pageForm 当前项目 ID、人员筛选及分页排序参数;空筛选项表示不限。
* @return Result,code=0 时 data.list 为候选人员,data.totalCount 为总人数。
*/
@At
@SaCheckPermission("healthCheckup.list.import")
@Ok("json:{dateFormat:'yyyy-MM-dd'}")
public Result candidatePageData(@Valid HealthCheckupFilterUserPageForm pageForm) {
return applicationService.candidatePageData(pageForm);
}
/**
* @param pageForm 当前项目 ID 和人员筛选条件;添加全部匹配人员,不受分页限制。
* @return Result,code=0 表示成功,msg 说明实际新增人数。
*/
@At
@SaCheckPermission("healthCheckup.list.import")
@Aop(TransAop.READ_COMMITTED)
@SLog(type = "healthCheckup", tag = "体检管理", msg = "管理员添加体检人员")
public Result addUsers(@Valid HealthCheckupFilterUserPageForm pageForm) {
return applicationService.addUsers(pageForm);
}
@At @At
@ApiOperation("分页查询") @ApiOperation("分页查询")
@SaCheckPermission("healthCheckup.list.mange") @SaCheckPermission("healthCheckup.list.mange")
public Result pageData(PageForm pageForm, public Result pageData(PageForm pageForm, String projectId, String subjectId,
String projectId, String unionId, String unitId, String physicalExaminationStatus, String isAudit) {
String unionId, return applicationService.pageData(pageForm, projectId, subjectId, unionId, unitId, physicalExaminationStatus, isAudit);
String unitId) {
List<HealthCheckupUnionConfirm> confirms = dao.query(HealthCheckupUnionConfirm.class, Cnd.where("projectId", "=", projectId));
HealthCheckupProject project = healthCheckupProjectService.findOne(projectId);
Cnd cnd = Cnd.NEW();
Sql sql = Sqls.create("""
SELECT
hcu.userId AS id,
hcu.loginName,
hcu.userName,
hcu.sex,
hcu.unionId,
hcu.unionName,
hcu.unitName,
hcus.selectTime,
hcus.campus,
hcus.subjectId,
hcus.bz,
hcus.receiveAddress,
ca.campusName
FROM
health_checkup_user hcu
LEFT JOIN health_checkup_user_selection hcus ON hcu.userId = hcus.selectUserId
AND hcus.projectId=@projectId
LEFT JOIN health_checkup_campus ca on ca.id=hcus.campus
$condition
""").setParam("projectId", projectId);
sql.setCondition(cnd);
cnd.andEX("hcu.projectId", "=", projectId);
cnd.andEX("hcu.unionId", "=", unionId);
cnd.andEX("hcu.unitId", "=", unitId);
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
cnd.andEX("hcu.unionId", "=", SecurityUtil.getUnionId());
}
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
SqlExpressionGroup group = new SqlExpressionGroup();
group.orLike("hcu.userName", pageForm.getSearchKeyword());
group.orLike("hcu.loginName", pageForm.getSearchKeyword());
cnd.and(group);
}
cnd.groupBy("hcu.userId");
if (StrUtil.isNotBlank(pageForm.getPageOrderName()) && Strings.isNotBlank(pageForm.getPageOrderBy())) {
cnd.orderBy(pageForm.getPageOrderName(), "ascending".equalsIgnoreCase(pageForm.getPageOrderBy()) ? "ASC" : "DESC");
} else {
cnd.desc("hcus.selectTime").asc("hcu.unitId");
}
Pagination pagination = healthCheckupProjectService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
List<NutMap> paginationList = pagination.getList();
paginationList.forEach(v -> {
if (StrUtil.isNotBlank(v.getString("subjectId"))) {
List<HealthCheckupProjectSubject> subjects = project.getHealthCheckupProjectSubjects();
HealthCheckupProjectSubject subject = subjects.stream().filter(s -> s.getId().equals(v.getString("subjectId"))).findFirst().orElse(null);
v.setv("optionName", subject.getOptionName());
}
if (StrUtil.isNotBlank(v.getString("unionId"))) {
HealthCheckupUnionConfirm confirm = confirms.stream().filter(o -> o.getUnionId().equals(v.getString("unionId"))).findFirst().orElse(null);
v.setv("isAudit", confirm != null ? confirm.getIsAudit() : "");
v.setv("auditTime", confirm != null ? confirm.getAuditTime() : "");
}
});
return Result.success(pagination);
} }
@At @At
@@ -159,21 +96,7 @@ public class HealthCheckupListController {
public Result doAuditUser(String projectId, public Result doAuditUser(String projectId,
String unionId, String unionId,
Boolean flag) { Boolean flag) {
if (StrUtil.isBlank(unionId)) { return applicationService.doAuditUser(projectId, unionId, flag);
unionId = SecurityUtil.getUnionId();
}
if (flag) {
dao.update(HealthCheckupUnionConfirm.class, Chain.make("isAudit", true)
.add("auditTime", DateUtil.date())
.add("auditUser", SecurityUtil.getUserId()),
Cnd.where("projectId", "=", projectId).and("unionId", "=", unionId));
} else {
dao.update(HealthCheckupUnionConfirm.class, Chain.make("isAudit", null)
.add("auditTime", null)
.add("auditUser", null),
Cnd.where("projectId", "=", projectId).and("unionId", "=", unionId));
}
return Result.success();
} }
@@ -181,93 +104,20 @@ public class HealthCheckupListController {
@ApiOperation("体检名单管理员编辑选择记录") @ApiOperation("体检名单管理员编辑选择记录")
@SLog(type = "healthCheckup", tag = "体检管理", msg = "管理员编辑了一条选择记录") @SLog(type = "healthCheckup", tag = "体检管理", msg = "管理员编辑了一条选择记录")
@SaCheckPermission("healthCheckup.list.mange") @SaCheckPermission("healthCheckup.list.mange")
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result doEditHealthCheckupData(String subjectId, String campus, String projectId, String userId, String bz) { public Result doEditHealthCheckupData(String subjectId, String campus, String projectId, String userId, String bz) {
return applicationService.doEditHealthCheckupData(subjectId, campus, projectId, userId, bz);
//查询用户有没有选择过套餐
HealthCheckupUserSelection userSelection = healthCheckupProjectService.dao().fetch(HealthCheckupUserSelection.class,
Cnd.where("projectId", "=", projectId).and("selectUserId", "=", userId));
//如果选择过套餐就修改选择的套餐id
if (Lang.isNotEmpty(userSelection)) {
userSelection.setSubjectId(subjectId);
userSelection.setCampus(campus);
userSelection.setBz(bz);
healthCheckupProjectService.update(userSelection);
} else {
//如果没有选择过套餐添加一条记录
HealthCheckupUserSelection checkupUserSelection = new HealthCheckupUserSelection();
checkupUserSelection.setSelectUserId(userId);
checkupUserSelection.setProjectId(projectId);
checkupUserSelection.setSubjectId(subjectId);
checkupUserSelection.setCampus(campus);
checkupUserSelection.setSelectTime(new Date());
checkupUserSelection.setBz(bz);
healthCheckupProjectService.insert(checkupUserSelection);
}
return Result.success();
} }
@At @At
@ApiOperation("体检名单导入名单") @ApiOperation("体检名单导入名单")
@SLog(type = "healthCheckup", tag = "体检管理", msg = "管理员导入了体检名单") @SLog(type = "healthCheckup", tag = "体检管理", msg = "管理员导入了体检名单")
@SaCheckPermission("healthCheckup.list.mange") @SaCheckPermission("healthCheckup.list.import")
@Aop(TransAop.READ_COMMITTED) @Aop(TransAop.READ_COMMITTED)
@AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"}) @AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"})
public Result healthImport(TempFile file, String healthProjectId) { public Result healthImport(TempFile file, String healthProjectId) {
// 读取数据 return applicationService.healthImport(file, healthProjectId);
List<T> ts = EasyExcelUtil.syncReadModel(file.getFile(), HealthCheckupImportTemp.class, 0, 1);
List<HealthCheckupImportTemp> healthCheckupImportTemps = JSONUtil.parseArray(JSONUtil.toJsonStr(ts)).toList(HealthCheckupImportTemp.class);
List<String> loginNames = healthCheckupImportTemps.stream().filter(v -> Strings.isNotBlank(v.getLoginName())).map(v -> v.getLoginName()).collect(Collectors.toList());
//全部的体检名单
List<HealthCheckupUser> healthCheckupUserList = dao.query(HealthCheckupUser.class, Cnd.where(HealthCheckupUser::getProjectId, "=", healthProjectId));
List<View_user> userList = dao.query(View_user.class, Cnd.where(View_user::getLoginname, "in", loginNames));
HealthCheckupProject checkupProject = dao.fetch(HealthCheckupProject.class, healthProjectId);
ActivityUserScope userScope = dao.fetch(ActivityUserScope.class, Cnd.where("groupId", "=", checkupProject.getActivityGroupId()));
List<ActivityUserScope> userScopeList = new ArrayList<>();
for (int i = 0; i < healthCheckupImportTemps.size(); i++) {
HealthCheckupImportTemp excel = healthCheckupImportTemps.get(i);
if (StrUtil.isBlank(excel.getLoginName())) {
excel.setErrInfo("工号为空", i + 1);
continue;
}
// 不能在excel里重复
if (healthCheckupImportTemps.stream().filter(s -> s.getLoginName().equals(excel.getLoginName())).count() > 1) {
excel.setErrInfo("重复数据", i + 1);
}
View_user user = userList.stream().filter(s -> s.getLoginname().equals(excel.getLoginName())).findFirst().orElse(null);
if (user == null) {
excel.setErrInfo("无此用户", i + 1);
continue;
}
if (healthCheckupUserList.stream().anyMatch(s -> s.getUserId().equals(user.getId()))) {
excel.setErrInfo("该用户已加入体检名单", i + 1);
continue;
}
ActivityUserScope s = new ActivityUserScope();
s.setGroupId(userScope.getGroupId());
s.setGroupName(userScope.getGroupName());
s.setUserId(user.getId());
s.setCreator(SecurityUtil.getUserId());
userScopeList.add(s);
}
;
dao.insert(userScopeList);
// 创建结果集
ExcelImportRes<HealthCheckupImportTemp> excelImportRes = new ExcelImportRes<>();
excelImportRes.setTotalRecords(healthCheckupImportTemps.size());
// 添加错误记录
excelImportRes.setErrorDetails(healthCheckupImportTemps.stream().filter(s -> StrUtil.isNotBlank(s.getErrMsg())).collect(Collectors.toList()));
excelImportRes.setFailedCount(excelImportRes.getErrorDetails().size());
return Result.success(excelImportRes);
} }
@At @At
@@ -275,12 +125,106 @@ public class HealthCheckupListController {
@ApiOperation("下载体检参加人员导入模版") @ApiOperation("下载体检参加人员导入模版")
@SaCheckPermission("healthCheckup.list.mange") @SaCheckPermission("healthCheckup.list.mange")
public void downloadTem(HttpServletResponse response) { public void downloadTem(HttpServletResponse response) {
List<ExcelExportEntity> entities = new ArrayList<>(); applicationService.downloadTem(response);
entities.add(new ExcelExportEntity("工号", "loginName", 20)); }
entities.add(new ExcelExportEntity("姓名", "userName", 20));
ExportParams exportParams = new ExportParams(); @At
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entities, Collections.emptyList()); @ApiOperation("体检名单删除")
CommonDownloadUtil.download("参加人员导入模版.xlsx", workbook, response); @SaCheckPermission("healthCheckup.list.delete")
@Aop(TransAop.READ_COMMITTED)
public Result doDelete(String id) {
return applicationService.doDelete(id);
}
@At
@Ok("void")
@ApiOperation("下载体检报告导入模版")
@SaCheckPermission("healthCheckup.list.mange")
public void downloadTemMedicalExaminationReport(HttpServletResponse response) {
applicationService.downloadTemMedicalExaminationReport(response);
}
@At
@ApiOperation("体检名单导入名单")
@SLog(type = "healthCheckup", tag = "体检管理", msg = "管理员导入了体检名单")
@SaCheckPermission("healthCheckup.list.import.medicalExamination")
@Aop(TransAop.READ_COMMITTED)
@AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"})
public Result healthImportMedicalExaminationReport(TempFile file, String healthProjectId) {
return applicationService.healthImportMedicalExaminationReport(file, healthProjectId);
}
@At
@ApiOperation("套餐选择器查询")
@SaCheckPermission("healthCheckup.list.mange")
public Result listSubjects(String projectId){
return applicationService.listSubjects(projectId);
}
@At
@ApiOperation("体检反馈列表")
@SaCheckPermission("healthCheckup.list.mange")
public Result feedbackList(String year, String projectId, String unionId) {
return applicationService.feedbackList(year, projectId, unionId);
}
@At
@ApiOperation("保存体检反馈")
@SLog(type = "healthCheckup", tag = "体检管理", msg = "新增体检反馈")
@SaCheckPermission("healthCheckup.list.mange")
@Aop(TransAop.READ_COMMITTED)
public Result saveFeedback(String year, String projectId, String unionId, String feedbackInfo) {
return applicationService.saveFeedback(year, projectId, unionId, feedbackInfo);
}
@At
@ApiOperation("删除体检反馈")
@SLog(type = "healthCheckup", tag = "体检管理", msg = "删除体检反馈")
@SaCheckPermission("healthCheckup.list.mange")
@Aop(TransAop.READ_COMMITTED)
public Result deleteFeedback(String id) {
return applicationService.deleteFeedback(id);
}
@At
@ApiOperation("批量删除体检反馈")
@SLog(type = "healthCheckup", tag = "体检管理", msg = "批量删除体检反馈")
@SaCheckPermission("healthCheckup.list.mange")
@Aop(TransAop.READ_COMMITTED)
public Result deleteFeedbackBatch(String ids) {
return applicationService.deleteFeedbackBatch(ids);
}
@At("/feedback/query/pageData")
@ApiOperation("问题反馈列表分页")
@SaCheckPermission("healthCheckup.list.mange")
public Result feedbackQueryPageData(PageForm pageForm, String year, String projectId, String unionId) {
return applicationService.feedbackQueryPageData(pageForm, year, projectId, unionId);
}
@At
@ApiOperation("体检名单编辑备注")
@SLog(type = "healthCheckup", tag = "体检管理", msg = "编辑备注")
@SaCheckPermission("healthCheckup.list.mange")
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result doEditRemarks(String userId, String projectId,String remarks) {
return applicationService.doEditRemarks(userId, projectId, remarks);
}
@At
@Ok("void")
@ApiOperation("导出")
@SaCheckPermission("healthCheckup.list.mange")
public void exportHealthUser(String projectId,
String unionId,
String searchKeyword,
String subjectId,
String unitId,
String physicalExaminationStatus,
String pageOrderName,
String pageOrderBy,
HttpServletResponse response) {
applicationService.exportHealthUser(projectId, unionId, searchKeyword, subjectId, unitId, physicalExaminationStatus, pageOrderName, pageOrderBy, response);
} }
} }
@@ -0,0 +1,44 @@
package com.budwk.app.zhgh.dayofficework.healthCheckup.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupPersonConfirmStatisticsService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
/**
* @ClassName HealthCheckupPersonConfirmStatisticsController
* @Description 工会确认情况统计
* @Author Codex
* @Date 2026/4/28
*/
@IocBean
@Ok("json:full")
@Api(tags = "体检人员确认情况统计")
@At("/platform/healthCheckup/statistics/personconfirm")
public class HealthCheckupPersonConfirmStatisticsController {
@Inject
private HealthCheckupPersonConfirmStatisticsService healthCheckupPersonConfirmStatisticsService;
@At("")
@Ok("beetl:/platform/zhgh/dayofficework/healthCheckup/personconfirm/index.html")
@SaCheckPermission("healthCheckup.personconfirm")
public void index() {
}
@At
@ApiOperation("工会确认情况分页统计")
@SaCheckPermission("healthCheckup.personconfirm")
public Result pageData(PageForm pageForm, Integer year, String projectId, String unionId) {
// 统计报表按年度、体检项目查询,工会条件选填,统一返回分页结果供前端表格展示。
Pagination statistics = healthCheckupPersonConfirmStatisticsService.personConfirmPageData(pageForm.getPageNumber(), pageForm.getPageSize(), year, projectId, unionId);
return Result.success(statistics);
}
}
@@ -1,33 +1,22 @@
package com.budwk.app.zhgh.dayofficework.healthCheckup.controller; package com.budwk.app.zhgh.dayofficework.healthCheckup.controller;
import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupProjectMangeApplicationService;
import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.annotation.SLog; import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.param.PageForm; import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result; import com.budwk.app.base.result.Result;
import com.budwk.app.sys.models.Sys_union; import com.budwk.app.zhgh.activity.culture.service.ActivityCultureService;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.*; import com.budwk.app.zhgh.dayofficework.healthCheckup.model.*;
import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupProjectService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.nutz.aop.interceptor.ioc.TransAop; import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.Daos;
import org.nutz.ioc.aop.Aop; import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param; import org.nutz.mvc.annotation.Param;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/** /**
* @ClassName HealthCheckupProjectMangeController * @ClassName HealthCheckupProjectMangeController
@@ -42,7 +31,11 @@ import java.util.stream.Collectors;
public class HealthCheckupProjectMangeController { public class HealthCheckupProjectMangeController {
@Inject @Inject
private HealthCheckupProjectService healthCheckupProjectService; private HealthCheckupProjectMangeApplicationService applicationService;
@Inject
private ActivityCultureService activityCultureService;
@At("") @At("")
@@ -58,102 +51,25 @@ public class HealthCheckupProjectMangeController {
public Result pageData(PageForm pageForm, public Result pageData(PageForm pageForm,
Integer year, Integer year,
String name) { String name) {
Sql sql = Sqls.create(""" return applicationService.pageData(pageForm, year, name);
SELECT
hcp.id,
hcp.`year`,
hcp.`name`,
hcp.choiceTimeStart,
hcp.choiceTimeEnd,
hcp.activityGroupId,
hcp.cover,
hcp.activityGroupName,
hcp.healthCheckupType,
IF((select count(userId) from health_checkup_user hcu where hcu.projectId = hcp.id) > 0,true,false) AS isHasUserList,
IF(NOW() > hcp.choiceTimeStart AND NOW() < hcp.choiceTimeEnd, true, false) AS isWithinChoiceTime,
IF(NOW() < hcp.choiceTimeStart, true, false) AS canCreated
FROM
health_checkup_project hcp
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.andEX("hcp.`year`", "=", year);
cnd.andEX("hcp.`name`", "=", name);
cnd.desc("hcp.choiceTimeStart");
sql.setCondition(cnd);
return Result.success(healthCheckupProjectService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql));
} }
@At @At
@ApiOperation("体检名单确认") @ApiOperation("体检项目确认")
@Aop(TransAop.READ_COMMITTED) @Aop(TransAop.READ_COMMITTED)
@SaCheckPermission("healthCheckup.projectMange") @SaCheckPermission("healthCheckup.projectMange")
@SLog(type = "healthCheckup", tag = "体检管理", msg = "提交体检项目") @SLog(type = "healthCheckup", tag = "体检管理", msg = "提交体检项目")
public Result doAdd(HealthCheckupProject healthCheckupProject, public Result doAdd(HealthCheckupProject healthCheckupProject,
@Param(value = "deleteRowIds") String[] deleteRowIds, @Param(value = "deleteRowIds") String[] deleteRowIds,
@Param(value = "deleteSubjectIds") String[] deleteSubjectIds) { @Param(value = "deleteSubjectIds") String[] deleteSubjectIds) {
return applicationService.doAdd(healthCheckupProject, deleteRowIds, deleteSubjectIds);
String projectId;
//如果是保存
if (StrUtil.isBlank(healthCheckupProject.getId())) {
healthCheckupProject.setYear(DateUtil.thisYear());
HealthCheckupProject checkupProject = healthCheckupProjectService.insertWith(healthCheckupProject, "healthCheckupProjectSubjects");
healthCheckupProject.getHealthCheckupProjectSubjects().forEach(v -> {
v.getSubjectMoneys().forEach(m -> {
m.setProjectId(checkupProject.getId());
m.setSubjectId(v.getId());
});
if (Lang.isNotEmpty(v.getSubjectMoneys())) {
healthCheckupProjectService.insert(v.getSubjectMoneys());
}
});
projectId = checkupProject.getId();
} else {
projectId = healthCheckupProject.getId();
//如果删除了医院
if (Lang.isNotEmpty(deleteSubjectIds)) {
healthCheckupProjectService.dao().clear(HealthCheckupProjectSubject.class, Cnd.where("id", "in", deleteSubjectIds));
healthCheckupProjectService.dao().clear(HealthCheckupProjectSubjectMoney.class, Cnd.where("subjectId", "in", deleteSubjectIds));
}
//如果删除了项目
if (Lang.isNotEmpty(deleteRowIds)) {
healthCheckupProjectService.dao().clear(HealthCheckupProjectSubjectMoney.class, Cnd.where("id", "in", deleteRowIds));
}
healthCheckupProjectService.dao().insertOrUpdate(healthCheckupProject.getHealthCheckupProjectSubjects());
healthCheckupProject.getHealthCheckupProjectSubjects().forEach(v -> {
v.setProjectId(projectId);
v.getSubjectMoneys().forEach(m -> {
m.setProjectId(projectId);
m.setSubjectId(v.getId());
});
if (Lang.isNotEmpty(v.getSubjectMoneys())) {
healthCheckupProjectService.insertOrUpdate(v.getSubjectMoneys());
}
});
healthCheckupProjectService.dao().insertOrUpdate(healthCheckupProject.getHealthCheckupProjectSubjects());
healthCheckupProjectService.update(healthCheckupProject);
}
healthCheckupProjectService.dao().clear(HealthCheckupUnionConfirm.class, Cnd.where("projectId", "=", projectId));
List<Sys_union> unionList = healthCheckupProjectService.dao().query(Sys_union.class, Cnd.NEW());
List<HealthCheckupUnionConfirm> confirmList = new ArrayList<>();
unionList.forEach(item -> {
HealthCheckupUnionConfirm c = new HealthCheckupUnionConfirm();
c.setProjectId(projectId);
c.setUnionId(item.getId());
c.setIsAudit(false);
confirmList.add(c);
});
healthCheckupProjectService.dao().insert(confirmList);
return Result.success();
} }
@At @At
@ApiOperation("查询体检项目内容") @ApiOperation("查询体检项目内容")
@SLog(type = "healthCheckup", tag = "体检管理", msg = "查询体检项目内容") @SLog(type = "healthCheckup", tag = "体检管理", msg = "查询体检项目内容")
public Result findOne(String id) { public Result findOne(String id) {
return Result.success(healthCheckupProjectService.findOne(id)); return applicationService.findOne(id);
} }
@At @At
@@ -162,18 +78,14 @@ public class HealthCheckupProjectMangeController {
@SaCheckPermission("healthCheckup.projectMange") @SaCheckPermission("healthCheckup.projectMange")
@SLog(type = "healthCheckup", tag = "体检管理", msg = "删除了一条体检项目") @SLog(type = "healthCheckup", tag = "体检管理", msg = "删除了一条体检项目")
public Result doDelete(String id) { public Result doDelete(String id) {
healthCheckupProjectService.delete(id); return applicationService.doDelete(id);
healthCheckupProjectService.dao().clear(HealthCheckupProjectSubject.class, Cnd.where("projectId", "=", id));
healthCheckupProjectService.dao().clear(HealthCheckupProjectSubjectMoney.class, Cnd.where("projectId", "=", id));
return Result.success();
} }
@At @At
@ApiOperation("按年份获取体检项目") @ApiOperation("按年份获取体检项目")
@SLog(type = "healthCheckup", tag = "体检管理", msg = "查询了所有的体检项目") @SLog(type = "healthCheckup", tag = "体检管理", msg = "查询了所有的体检项目")
public Result getHealthCheckupProject(Integer year) { public Result getHealthCheckupProject(Integer year) {
List<HealthCheckupProject> projectList = healthCheckupProjectService.query(Cnd.NEW().andEX("year", "=", year).desc("choiceTimeStart")); return applicationService.getHealthCheckupProject(year);
return Result.success(projectList);
} }
@@ -189,8 +101,7 @@ public class HealthCheckupProjectMangeController {
@SaCheckPermission("healthCheckup.projectMange") @SaCheckPermission("healthCheckup.projectMange")
@SLog(type = "healthCheckup", tag = "体检管理", msg = "创建体检名单") @SLog(type = "healthCheckup", tag = "体检管理", msg = "创建体检名单")
public Result createUserList(HealthCheckupProject healthCheckupProject) { public Result createUserList(HealthCheckupProject healthCheckupProject) {
healthCheckupProjectService.addHealthCheckupUser(healthCheckupProject); return applicationService.createUserList(healthCheckupProject);
return Result.success();
} }
@@ -206,8 +117,7 @@ public class HealthCheckupProjectMangeController {
@SaCheckPermission("healthCheckup.projectMange") @SaCheckPermission("healthCheckup.projectMange")
@SLog(type = "healthCheckup", tag = "体检管理", msg = "更新体检名单") @SLog(type = "healthCheckup", tag = "体检管理", msg = "更新体检名单")
public Result renewUserList(HealthCheckupProject healthCheckupProject) { public Result renewUserList(HealthCheckupProject healthCheckupProject) {
healthCheckupProjectService.renewHealthCheckupUser(healthCheckupProject); return applicationService.renewUserList(healthCheckupProject);
return Result.success();
} }
@@ -223,16 +133,6 @@ public class HealthCheckupProjectMangeController {
@SaCheckPermission("healthCheckup.projectMange") @SaCheckPermission("healthCheckup.projectMange")
@SLog(type = "healthCheckup", tag = "体检管理", msg = "重置体检名单") @SLog(type = "healthCheckup", tag = "体检管理", msg = "重置体检名单")
public Result resetUserList(HealthCheckupProject healthCheckupProject) { public Result resetUserList(HealthCheckupProject healthCheckupProject) {
//重置名单,清空已选择的用户记录 return applicationService.resetUserList(healthCheckupProject);
Sql sql = Sqls.create("select id,selectUserId from health_checkup_user_selection where projectId = @projectId").setParam("projectId", healthCheckupProject.getId());
List<NutMap> list = (List<NutMap>) Daos.query(healthCheckupProjectService.dao(), sql.toString(), Sqls.callback.maps());
List<String> userSelectionIds = list.stream().map(v -> v.getString("id")).collect(Collectors.toList());
List<String> userIds = list.stream().map(v -> v.getString("selectUserId")).collect(Collectors.toList());
healthCheckupProjectService.dao().clear(HealthCheckupUserSelection.class, Cnd.where("selectUserId", "in", userIds));
healthCheckupProjectService.dao().clear(HealthCheckupUserCompanion.class, Cnd.where("userSelectionId", "in", userSelectionIds));
healthCheckupProjectService.dao().clear(HealthCheckupUser.class, Cnd.where("projectId", "=", healthCheckupProject.getId()));
healthCheckupProjectService.addHealthCheckupUser(healthCheckupProject);
return Result.success();
} }
} }
@@ -1,46 +1,22 @@
package com.budwk.app.zhgh.dayofficework.healthCheckup.controller; package com.budwk.app.zhgh.dayofficework.healthCheckup.controller;
import cn.afterturn.easypoi.excel.ExcelExportUtil; import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupSingleApplicationService;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.date.DateUtil;
import com.budwk.app.base.annotation.SLog; import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm; import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result; import com.budwk.app.base.result.Result;
import com.budwk.app.base.utils.CommonDownloadUtil; import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupProjectService;
import com.budwk.app.base.utils.ConditionGroupUtil;
import com.budwk.app.base.utils.ManyAddOrRenewUtil;
import com.budwk.app.sys.views.View_user;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupProject;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupProjectSubject;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupProjectSubjectMoney;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupUserSelection;
import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupSingleService; import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupSingleService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.apache.poi.ss.usermodel.Workbook;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Ok;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid; import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
/** /**
* @ClassName HealthCheckupSingleController * @ClassName HealthCheckupSingleController
@@ -54,11 +30,14 @@ import java.util.stream.Collectors;
@At("/platform/healthCheckup/statistics/single") @At("/platform/healthCheckup/statistics/single")
public class HealthCheckupSingleController { public class HealthCheckupSingleController {
@Inject
private HealthCheckupSingleApplicationService applicationService;
@Inject
@Inject
private HealthCheckupSingleService healthCheckupSingleService; private HealthCheckupSingleService healthCheckupSingleService;
@Inject @Inject
private ManyAddOrRenewUtil manyAddOrRenewUtil; private HealthCheckupProjectService healthCheckupProjectService;
@At("") @At("")
@Ok("beetl:/platform/zhgh/dayofficework/healthCheckup/statisticsSingle/index.html") @Ok("beetl:/platform/zhgh/dayofficework/healthCheckup/statisticsSingle/index.html")
@@ -66,14 +45,32 @@ public class HealthCheckupSingleController {
public void index() { public void index() {
} }
@At @At
@ApiOperation("首页查询") @ApiOperation("首页查询")
@SaCheckPermission("healthCheckup.statisticsSingle") @SaCheckPermission("healthCheckup.statisticsSingle")
public Result pageData(String projectId, public Result pageData(String projectId,
String unionId) { String unionId) {
NutMap nutMap = healthCheckupSingleService.pageData(projectId, unionId); return applicationService.pageData(projectId, unionId);
return Result.success(nutMap); }
/**
* projectId传体检项目ID;返回Result.data为人数映射,__total__为总人数,其余键为医院ID。
*/
@At
@SaCheckPermission("healthCheckup.statisticsSingle")
public Result actualStatistics(String projectId) {
return applicationService.actualStatistics(projectId);
}
/**
* projectId传体检项目ID,counts传整行人数JSON(__total__及医院ID映射非负整数)。
* 返回Result,data为已保存人数映射;非零code表示校验或权限失败,msg说明原因。
*/
@At
@SaCheckPermission("healthCheckup.statisticsSingle")
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result saveActualStatistics(String projectId, String counts) {
return applicationService.saveActualStatistics(projectId, counts);
} }
/** /**
@@ -91,12 +88,22 @@ public class HealthCheckupSingleController {
public Result receivePageData(PageForm page, String isSelected, public Result receivePageData(PageForm page, String isSelected,
String projectId, String projectId,
String unionId) { String unionId) {
List<NutMap> labelList = healthCheckupSingleService.receivePageDataColumns(projectId); return applicationService.receivePageData(page, isSelected, projectId, unionId);
Pagination list = healthCheckupSingleService.receivePageData(page.getPageNumber(), page.getPageSize(), page.getSearchName(), page.getSearchKeyword(), projectId, unionId, isSelected);
return Result.success(NutMap.NEW().addv("list", list).addv("label", labelList));
} }
/**
* @param projectId 当前教职工体检项目ID;不接收分工会筛选,权限在service中校验
* @param response 返回ZIP附件,其中每个xlsx为一家医院的已选名单,不返回JSON
*/
@At
@Ok("void")
@ApiOperation("按医院导出已选名单ZIP")
@SaCheckPermission("healthCheckup.statisticsSingle")
public void exportSelectedZip(String projectId, HttpServletResponse response) {
applicationService.exportSelectedZip(projectId, response);
}
/** /**
* 导出已选/未选人员名单 * 导出已选/未选人员名单
* *
@@ -114,48 +121,7 @@ public class HealthCheckupSingleController {
String unionId, String unionId,
Integer year, Integer year,
boolean flag, HttpServletResponse response) { boolean flag, HttpServletResponse response) {
applicationService.exportReceiveDetail(projectId, unionId, year, flag, response);
List<ExcelExportEntity> entityList = new ArrayList<>() {{
add(new ExcelExportEntity("职工号", "loginName", 20));
add(new ExcelExportEntity("姓名", "userName", 20));
add(new ExcelExportEntity("性别", "sex", 20));
// add(new ExcelExportEntity("出生年月", "birthday", 20));
add(new ExcelExportEntity("年龄", "age", 20));
add(new ExcelExportEntity("婚姻状况", "marriage", 20));
add(new ExcelExportEntity("身份证号", "idCard", 20));
add(new ExcelExportEntity("部门", "unitName", 20));
// add(new ExcelExportEntity("部门编码", "unitCode", 20));
add(new ExcelExportEntity("医院", "subjectName", 20));
add(new ExcelExportEntity("邮寄地址", "receiveAddress", 50));
}};
List<NutMap> list;
if (flag) {
//已选人员
list = healthCheckupSingleService.receivePageData(projectId, unionId, "0");
} else {
//未选人员
list = healthCheckupSingleService.receivePageData(projectId, unionId, "1");
}
//获取当前年
Calendar calendar = Calendar.getInstance();
int thisYear = calendar.get(Calendar.YEAR);
list.forEach(v -> {
int substring = 0;
if (Strings.isNotBlank(v.getString("birthday"))) {
substring = Integer.parseInt(v.getString("birthday").substring(0, 4));
} else if (Strings.isNotBlank(v.getString("idCard")) && v.getString("idCard").length() >= 10) {
substring = Integer.parseInt(v.getString("idCard").substring(6, 10));
}
v.put("age", thisYear - substring);
});
List<NutMap> list2 = list.stream().filter(v -> Strings.isNotBlank(v.getString("unionName"))).collect(Collectors.toList());
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
exportParams.setSheetName(year + "年教职工体检项目及地点统计表");
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, list2);
CommonDownloadUtil.download((flag ? year + "年教职工体检项目及地点统计表" : "未选名单") + ".xlsx", workbook, response);
} }
@@ -166,69 +132,7 @@ public class HealthCheckupSingleController {
public void exportUserCompanion(String projectId, public void exportUserCompanion(String projectId,
String unionId, String unionId,
Integer year, HttpServletResponse response) { Integer year, HttpServletResponse response) {
Sql sql = Sqls.create(""" applicationService.exportUserCompanion(projectId, unionId, year, response);
SELECT
u.username,
u.unitname unitName,
u.mobile,
hcuc.userName familyName,
hcuc.sex,
hcuc.marry isMarried,
hcuc.idCard,
hcc.campusName,
(
SELECT
GROUP_CONCAT( hcps.optionName )
FROM
health_checkup_user_selection hcus
LEFT JOIN `health_checkup_project_subject` hcps ON hcps.id = hcus.subjectId
WHERE
hcus.projectId = @projectId
AND hcus.selectUserId = u.id
) optionName
FROM
`health_checkup_user_companion` hcuc
LEFT JOIN `health_checkup_user_selection` hcus ON hcus.id = hcuc.userSelectionId
LEFT JOIN `health_checkup_campus` hcc ON hcc.id = hcus.campus
LEFT JOIN `vw_user` u ON u.id = hcus.selectUserId
LEFT JOIN `health_checkup_project` hcp ON hcp.id = hcus.projectId
$condition
""").setParam("projectId", projectId);
Cnd cnd = Cnd.NEW();
cnd.andEX("hcus.projectId", "=", projectId);
cnd.andEX("u.unionid", "=", unionId);
cnd.andEX("hcp.year", "=", year);
cnd.asc("u.unioncode");
sql.setCondition(cnd);
//家属信息表
List<NutMap> companionList = healthCheckupSingleService.listMap(sql);
for (int i = 0; i < companionList.size(); i++) {
companionList.get(i).put("index", i + 1);
}
List<ExcelExportEntity> entityList = new ArrayList<>() {{
add(new ExcelExportEntity("序号", "index", 20));
add(new ExcelExportEntity("教职工姓名", "username", 20));
add(new ExcelExportEntity("学院(部门)", "unitName", 20));
add(new ExcelExportEntity("手机", "mobile", 20));
add(new ExcelExportEntity("体检人姓名", "familyName", 20));
add(new ExcelExportEntity("性别", "sex", 20));
add(new ExcelExportEntity("婚否", "isMarried", 20));
add(new ExcelExportEntity("体检人身份证号", "idCard", 50));
add(new ExcelExportEntity("自选项目", "optionName", 50));
add(new ExcelExportEntity("自选院区", "campusName", 50));
}};
try {
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
exportParams.setTitle(year + "教职工家属体检登记表");
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, companionList);
CommonDownloadUtil.download(year + "教职工家属体检登记表.xlsx", workbook, response);
} catch (Exception e) {
e.printStackTrace();
}
} }
@@ -237,132 +141,20 @@ public class HealthCheckupSingleController {
@Ok("json:full") @Ok("json:full")
@SaCheckPermission("healthCheckup.statisticsSingle") @SaCheckPermission("healthCheckup.statisticsSingle")
@SLog(type = "healthCheckup", tag = "体检管理", msg = "管理员一键代选") @SLog(type = "healthCheckup", tag = "体检管理", msg = "管理员一键代选")
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result doSelectByAdmin(String projectId, String optionId, String campus) { public Result doSelectByAdmin(String projectId, String optionId, String campus) {
Dao dao = healthCheckupSingleService.dao(); return applicationService.doSelectByAdmin(projectId, optionId, campus);
HealthCheckupProject project = dao.fetch(HealthCheckupProject.class, projectId);
Cnd cnd = Cnd.NEW();
Sql sql = Sqls.create("""
SELECT
u.id,
u.loginname loginName,
u.username userName,
u.sex,
u.birthday,
u.unitname unitName,
u.unionname unionName,
u.idcard idCard,
u.mobile
FROM
`activity_user_scope` aus
LEFT JOIN `vw_user` u ON u.id = aus.userId
$projectCnd $condition
""");
cnd.and("aus.groupId", "=", project.getActivityGroupId());
sql.setVar("projectCnd", "AND u.id NOT IN ( SELECT selectUserId FROM `health_checkup_user_selection` WHERE projectId = '" + projectId + "' AND selectUserId IS NOT NULL )");
cnd.groupBy("u.loginname");
sql.setCondition(cnd);
List<NutMap> mapList = healthCheckupSingleService.listMap(sql);
List<String> userIds = mapList.stream().map(v -> v.getString("id")).collect(Collectors.toList());
//题目id
List<HealthCheckupUserSelection> selections = userIds.stream().map(v -> {
HealthCheckupUserSelection selection = new HealthCheckupUserSelection();
selection.setProjectId(projectId);
selection.setSelectUserId(v);
selection.setCampus(campus);
selection.setSubjectId(optionId);
selection.setSelectTime(new Date());
return selection;
}).collect(Collectors.toList());
manyAddOrRenewUtil.asyncExecuteFastInsert(selections, null);
return Result.success();
} }
@At @At
@ApiOperation("管理员一键选择去年数据") @ApiOperation("按上年补齐未选人员")
@Ok("json:full") @Ok("json:full")
@SaCheckPermission("healthCheckup.statisticsSingle") @SaCheckPermission("healthCheckup.statisticsSingle")
@SLog(type = "healthCheckup", tag = "体检管理", msg = "管理员给没选的人统一选择去年的数据") @SLog(type = "healthCheckup", tag = "体检管理", msg = "管理员给没选的人统一选择去年的数据")
public Result selectOptionByLastYear(String projectId) { @org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result selectOptionByLastYear(String projectId, String lastYearProjectId) {
Dao dao = healthCheckupSingleService.dao(); return applicationService.selectOptionByLastYear(projectId, lastYearProjectId);
//获取去年项目
HealthCheckupProject lastYearProject = dao.fetch(HealthCheckupProject.class, Cnd.where("YEAR(year)", "=", DateUtil.thisYear() - 1));
if (lastYearProject == null) {
return Result.error("请先创建去年的体检项目");
}
Cnd cnd = Cnd.NEW();
Sql sql = Sqls.create("""
SELECT
u.id
FROM
health_checkup_user hcu
LEFT JOIN `vw_user` u ON u.id = hcu.userId
$projectCnd $condition
""");
cnd.and("hcu.projectId", "=", projectId);
sql.setVar("projectCnd", "AND u.id NOT IN ( SELECT selectUserId FROM `health_checkup_user_selection` WHERE projectId = '" + projectId + "' AND selectUserId IS NOT NULL )");
cnd.groupBy("u.loginname");
sql.setCondition(cnd);
List<NutMap> mapList = healthCheckupSingleService.listMap(sql);
List<String> userIds = mapList.stream().map(v -> v.getString("id")).toList();
//去年项目的人
List<HealthCheckupUserSelection> lastYearSelectionList = dao.query(HealthCheckupUserSelection.class, Cnd.where(HealthCheckupUserSelection::getProjectId, "=", lastYearProject.getId())
.and(HealthCheckupUserSelection::getSelectUserId, "in", userIds));
//去年项目下的医院
List<HealthCheckupProjectSubject> lastYearSubjectList = dao.query(HealthCheckupProjectSubject.class,
Cnd.where(HealthCheckupProjectSubject::getProjectId, "=", lastYearProject.getId()));
//今年项目下的医院
List<HealthCheckupProjectSubject> thisYearSubjectList = dao.query(HealthCheckupProjectSubject.class,
Cnd.where(HealthCheckupProjectSubject::getProjectId, "=", projectId));
List<HealthCheckupUserSelection> selections = new ArrayList<>();
userIds.forEach(v -> {
//获取去年这个人选择的记录
HealthCheckupUserSelection userSelection = lastYearSelectionList.stream().filter(item -> item.getSelectUserId().equals(v)).findFirst().orElse(null);
//去年这个人选择的选项是什么
HealthCheckupProjectSubject lastYearSubject = lastYearSubjectList.stream().filter(last -> last.getId().equals(userSelection.getSubjectId())).findFirst().orElse(null);
//今年项目下的选项
HealthCheckupProjectSubject thisYearSubject = thisYearSubjectList.stream().filter(thisYear -> thisYear.getOptionName().equals(lastYearSubject.getOptionName())).findFirst().orElse(null);
if (userSelection != null && thisYearSubject != null) {
//获取今年这个选项的收费
List<HealthCheckupProjectSubjectMoney> list = dao.query(HealthCheckupProjectSubjectMoney.class,
Cnd.where(HealthCheckupProjectSubjectMoney::getSubjectId, "=", thisYearSubject.getId()));
BigDecimal money = BigDecimal.valueOf(0.00);
String subjectMoneyId = null;
for (HealthCheckupProjectSubjectMoney subject : list) {
//找出这个人符合哪个项目
Cnd cndUser = Cnd.where("id", "=", v);
ConditionGroupUtil.applyConditionGroup(cndUser, subject.getMatchCnd());
int count = dao.count(View_user.class, cndUser);
if (count > 0) {
money = subject.getMoney();
subjectMoneyId = subject.getId();
break;
}
}
//如果有符合的就添加
if (subjectMoneyId != null) {
HealthCheckupUserSelection selection = new HealthCheckupUserSelection();
selection.setProjectId(projectId);
selection.setSelectUserId(v);
selection.setSubjectId(thisYearSubject.getId());
selection.setSubjectMoneyId(subjectMoneyId);
selection.setMoney(money);
selection.setSelectTime(new Date());
selections.add(selection);
}
}
});
return Result.success();
} }
@@ -372,7 +164,7 @@ public class HealthCheckupSingleController {
@SaCheckPermission("healthCheckup.statisticsSingle") @SaCheckPermission("healthCheckup.statisticsSingle")
@SLog(type = "healthCheckup", tag = "体检管理", msg = "管理员给未选的人发送提醒") @SLog(type = "healthCheckup", tag = "体检管理", msg = "管理员给未选的人发送提醒")
public Result msgNotSelect(@Valid String projectId) { public Result msgNotSelect(@Valid String projectId) {
List<NutMap> userList = healthCheckupSingleService.receivePageData(projectId, null, "1"); return applicationService.msgNotSelect(projectId);
return Result.success("暂未开启消息!");
} }
} }
@@ -1,41 +1,23 @@
package com.budwk.app.zhgh.dayofficework.healthCheckup.h5controller; package com.budwk.app.zhgh.dayofficework.healthCheckup.h5controller;
import com.budwk.app.zhgh.dayofficework.healthCheckup.service.H5HealthCheckupApplicationService;
import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaMode; import cn.dev33.satoken.annotation.SaMode;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm; import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result; import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.BaseService; import com.budwk.app.base.service.BaseService;
import com.budwk.app.base.utils.ConditionGroupUtil; import com.budwk.app.zhgh.dayofficework.healthCheckup.model.*;
import com.budwk.app.sys.views.View_user;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupCampus;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupProject;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupProjectSubjectMoney;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupUserSelection;
import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupProjectService;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.nutz.aop.interceptor.ioc.TransAop; import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.Static;
import org.nutz.ioc.aop.Aop; import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.util.NutMap; import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param; import org.nutz.mvc.annotation.Param;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
/** /**
* @author : hongqiwei * @author : hongqiwei
@@ -49,14 +31,13 @@ import java.util.Map;
public class H5HealthCheckupController { public class H5HealthCheckupController {
@Inject @Inject
private Dao dao; private H5HealthCheckupApplicationService applicationService;
@Inject
@Inject
private BaseService baseService; private BaseService baseService;
@Inject @At("/list")
private HealthCheckupProjectService healthCheckupProjectService;
@At("/list")
@Ok("beetl:/platform/zhghh5/dayofficework/healthCheckup/list/index.html") @Ok("beetl:/platform/zhghh5/dayofficework/healthCheckup/list/index.html")
@SaCheckPermission("h5.healthCheckup.list") @SaCheckPermission("h5.healthCheckup.list")
public void list() { public void list() {
@@ -81,125 +62,42 @@ public class H5HealthCheckupController {
public Object pageData(PageForm pageForm, public Object pageData(PageForm pageForm,
String status, String status,
String name) { String name) {
Sql sql = Sqls.create(""" return applicationService.pageData(pageForm, status, name);
select
*,
(select count(*) from health_checkup_user_selection s where s.projectId=p.id and s.selectUserId=@userId) as selectCount
from
health_checkup_project p
$condition
""");
sql.setParam("userId", SecurityUtil.getUserId());
Cnd cnd = Cnd.NEW();
// 根据 status 参数筛选进行中或已结束的项目
if ("ongoing".equals(status)) {
// 进行中的项目:结束时间大于等于当前时间
cnd.and("p.choiceTimeEnd", ">=", DateUtil.now());
} else if ("finished".equals(status)) {
// 已结束的项目:结束时间小于当前时间
cnd.and("p.choiceTimeEnd", "<", DateUtil.now());
}
cnd.and(new Static("(select count(*) from health_checkup_user where projectId=p.id and userId='%s')>0".formatted(SecurityUtil.getUserId())));
// 只有当name参数不为空时才添加名称查询条件
if (StrUtil.isNotBlank(name)) {
cnd.and("p.name", "like", "%" + name + "%");
}
cnd.asc("selectCount");
sql.setCondition(cnd);
return Result.success(healthCheckupProjectService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql));
} }
@At @At
@SaCheckPermission(value = {"h5.healthCheckup.list", "h5.healthCheckup.mine"}, mode = SaMode.OR) @SaCheckPermission(value = {"h5.healthCheckup.list", "h5.healthCheckup.mine"}, mode = SaMode.OR)
public Object mineData(PageForm pageForm, String status) { public Object mineData(PageForm pageForm, String status, String projectId) {
Sql sql = Sqls.create(""" return applicationService.mineData(pageForm, status, projectId);
SELECT
us.*,
p.name,
p.choiceTimeStart,
p.choiceTimeEnd,
p.cover,
sub.optionName
FROM
health_checkup_user_selection us
LEFT JOIN health_checkup_project p ON us.projectId = p.id
LEFT JOIN health_checkup_project_subject sub on sub.id=us.subjectId
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.and("us.selectUserId", "=", SecurityUtil.getUserId());
// 根据 status 参数筛选进行中或已结束的项目
if ("ongoing".equals(status)) {
// 进行中的项目:结束时间大于等于当前时间
cnd.and("p.choiceTimeEnd", ">=", DateUtil.now());
} else if ("finished".equals(status)) {
// 已结束的项目:结束时间小于当前时间
cnd.and("p.choiceTimeEnd", "<", DateUtil.now());
}
sql.setCondition(cnd);
Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
return Result.success(pagination);
} }
@At @At
@Aop(TransAop.READ_COMMITTED) @Aop(TransAop.READ_COMMITTED)
@SaCheckPermission(value = {"h5.healthCheckup.list", "h5.healthCheckup.mine"}, mode = SaMode.OR) @SaCheckPermission(value = {"h5.healthCheckup.list", "h5.healthCheckup.mine"}, mode = SaMode.OR)
public Result doSubmit(@Param("userSelection") HealthCheckupUserSelection userSelection) { public Result doSubmit(@Param("userSelection") HealthCheckupUserSelection userSelection,
BigDecimal money = userSelection.getMoney(); @Param("baseInfo") HealthCheckupUser baseInfo) {
if (money.compareTo(BigDecimal.ZERO) <= 0) { // 小于等于0 // userSelection 为医院选择JSON,baseInfo 为可选个人信息JSON;返回 Result 表示整体保存结果。
return Result.error("金额必须大于0,当前医院没有符合您的选项!"); return applicationService.submitWithBaseInfo(userSelection, baseInfo);
}
if (StrUtil.isNotBlank(userSelection.getId())) {
baseService.dao().clearLinks(userSelection, "companionList");
baseService.dao().delete(HealthCheckupUserSelection.class, userSelection.getId());
userSelection.setId(null);
}
userSelection.setSelectUserId(SecurityUtil.getUserId());
userSelection.setSelectTime(new Date());
baseService.dao().insertWith(userSelection, "companionList");
return Result.success("提交成功");
} }
@At @At
@Aop(TransAop.READ_COMMITTED) @Aop(TransAop.READ_COMMITTED)
@SaCheckPermission(value = {"h5.healthCheckup.list", "h5.healthCheckup.mine"}, mode = SaMode.OR) @SaCheckPermission(value = {"h5.healthCheckup.list", "h5.healthCheckup.mine"}, mode = SaMode.OR)
public Result cancel(String id, String projectId) { public Result cancel(String id, String projectId) {
HealthCheckupProject checkupProject = baseService.dao().fetch(HealthCheckupProject.class, projectId); return applicationService.cancel(id, projectId);
if (DateUtil.compare(new Date(), checkupProject.getChoiceTimeEnd()) > 0) {
return Result.error("抱歉,当前时间已经不能取消");
}
HealthCheckupUserSelection userSelection = baseService.dao().fetch(HealthCheckupUserSelection.class, id);
baseService.dao().clearLinks(userSelection, "companionList");
baseService.dao().delete(HealthCheckupUserSelection.class, userSelection.getId());
return Result.success("取消成功");
} }
@At @At
@SaCheckPermission(value = {"h5.healthCheckup.list", "h5.healthCheckup.mine"}, mode = SaMode.OR) @SaCheckPermission(value = {"h5.healthCheckup.list", "h5.healthCheckup.mine"}, mode = SaMode.OR)
public Object getCampus() { public Object getCampus() {
return Result.success(baseService.dao().query(HealthCheckupCampus.class, Cnd.NEW().asc("campusCode"))); return applicationService.getCampus();
} }
@At @At
@SaCheckPermission(value = {"h5.healthCheckup.list", "h5.healthCheckup.mine"}, mode = SaMode.OR) @SaCheckPermission(value = {"h5.healthCheckup.list", "h5.healthCheckup.mine"}, mode = SaMode.OR)
public Object selectInfo(String projectId) { public Object selectInfo(String projectId) {
HealthCheckupUserSelection userSelection = healthCheckupProjectService.dao().fetch(HealthCheckupUserSelection.class, return applicationService.selectInfo(projectId);
Cnd.where("projectId", "=", projectId).and("selectUserId", "=", SecurityUtil.getUserId()));
if (userSelection != null) {
baseService.dao().fetchLinks(userSelection, "companionList");
NutMap nutMap = Lang.obj2map(userSelection, NutMap.class);
if (userSelection.getCompanionList().size() > 0) {
nutMap.put("isFamily", "是");
} else {
nutMap.put("isFamily", "否");
}
return Result.success(nutMap);
}
return Result.success();
} }
// @At // @At
@@ -217,25 +115,53 @@ public class H5HealthCheckupController {
@At @At
@SaCheckPermission(value = {"h5.healthCheckup.list", "h5.healthCheckup.mine"}, mode = SaMode.OR) @SaCheckPermission(value = {"h5.healthCheckup.list", "h5.healthCheckup.mine"}, mode = SaMode.OR)
public Result getSubjectMoney(String id, String marriage) { public Result getSubjectMoney(String id, String marriage, Integer age) {
List<HealthCheckupProjectSubjectMoney> list = healthCheckupProjectService.dao().query(HealthCheckupProjectSubjectMoney.class, Cnd.where(HealthCheckupProjectSubjectMoney::getSubjectId, "=", id)); // id 为医院选项ID,age/marriage 为当前表单值;返回 data.money 和 data.subjectMoneyId,仅用于预览。
BigDecimal money = BigDecimal.valueOf(0.00); return applicationService.getSubjectMoney(id, marriage, age);
String subjectMoneyId = "";
for (HealthCheckupProjectSubjectMoney subject : list) {
// 是否满足条件
Cnd cnd = Cnd.where("id", "=", SecurityUtil.getUserId());
ConditionGroupUtil.applyConditionGroup(cnd, subject.getMatchCnd());
int count = dao.count(View_user.class, cnd);
if (count > 0) {
money = subject.getMoney();
subjectMoneyId = subject.getId();
break;
}
} }
return Result.success().addData(Map.of("money", money, "subjectMoneyId", subjectMoneyId)); @At("/listParticulars")
@Ok("beetl:/platform/zhghh5/dayofficework/healthCheckup/listParticulars/index.html")
@SaCheckPermission("h5.healthCheckup.list")
@ApiOperation("体检项目报名详情页面")
public void listParticulars(){}
@At("/userBaseMessage")
@Ok("beetl:/platform/zhghh5/dayofficework/healthCheckup/userBaseMessage/index.html")
@SaCheckPermission("h5.healthCheckup.list")
@ApiOperation("基础信息确认")
public void userBaseMessage(){}
@At
@Aop(TransAop.READ_COMMITTED)
@SaCheckPermission("h5.healthCheckup.list")
@ApiOperation("获取基础信息数据")
public Result findUserBaseMessageData(HealthCheckupUser checkupUser) {
return applicationService.findUserBaseMessageData(checkupUser);
}
@At
@Aop(TransAop.READ_COMMITTED)
@SaCheckPermission("h5.healthCheckup.list")
@ApiOperation("基础信息提交")
public Result doSubmitUserBaseMessage(HealthCheckupUser checkupUser) {
return applicationService.doSubmitUserBaseMessage(checkupUser);
}
@At
@Aop(TransAop.READ_COMMITTED)
@SaCheckPermission("h5.healthCheckup.list")
@ApiOperation("上年度体检医院")
public Result findLastYearHospital(HealthCheckupUserSelection checkupUserSelection) {
return applicationService.findLastYearHospital(checkupUserSelection);
}
@At("/physicalExaminationList")
@Ok("beetl:/platform/zhghh5/dayofficework/healthCheckup/physicalExaminationList/index.html")
@SaCheckPermission("h5.healthCheckup.list")
public void physicalExaminationList() {
} }
} }
@@ -0,0 +1,36 @@
package com.budwk.app.zhgh.dayofficework.healthCheckup.model;
import com.budwk.app.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
/** 项目级实际体检统计,与教职工选择记录独立保存。 */
@Data
@EqualsAndHashCode(callSuper = true)
@Table("health_checkup_actual_statistics")
@TableMeta("{'mysql-charset':'utf8mb4'}")
@TableIndexes({@Index(name = "IDX_CHECKUP_ACTUAL_ITEM", fields = {"projectId", "subjectId"}, unique = true)})
@Comment("实际体检人数统计")
public class HealthCheckupActualStatistics extends BaseModel {
@Name
@PrevInsert(uu32 = true)
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("主键")
private String id;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("体检项目ID")
private String projectId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("医院选项ID;__total__表示本次体检总人数")
private String subjectId;
@Column
@Comment("人工录入的实际体检人数,非负整数")
private Integer actualCount;
}
@@ -0,0 +1,52 @@
package com.budwk.app.zhgh.dayofficework.healthCheckup.model;
import com.budwk.app.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.nutz.dao.entity.annotation.ColDefine;
import org.nutz.dao.entity.annotation.ColType;
import org.nutz.dao.entity.annotation.Column;
import org.nutz.dao.entity.annotation.Comment;
import org.nutz.dao.entity.annotation.Name;
import org.nutz.dao.entity.annotation.Table;
import org.nutz.dao.entity.annotation.TableMeta;
import org.nutz.dao.interceptor.annotation.PrevInsert;
import java.io.Serializable;
/**
* Health checkup feedback record.
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Table("health_checkup_feedback")
@TableMeta("{'mysql-charset':'utf8mb4'}")
@Comment("health checkup feedback")
public class HealthCheckupFeedback extends BaseModel implements Serializable {
@Name
@Comment("id")
@ColDefine(type = ColType.VARCHAR, width = 32)
@PrevInsert(uu32 = true)
private String id;
@Column
@Comment("year")
@ColDefine(type = ColType.VARCHAR, width = 4)
private String year;
@Column
@Comment("project id")
@ColDefine(type = ColType.VARCHAR, width = 32)
private String projectId;
@Column
@Comment("project name")
@ColDefine(type = ColType.VARCHAR, width = 100)
private String projectName;
@Column
@Comment("union id")
@ColDefine(type = ColType.VARCHAR, width = 32)
private String unionId;
@Column
@Comment("union name")
@ColDefine(type = ColType.VARCHAR, width = 100)
private String unionName;
@Column
@Comment("feedback info")
@ColDefine(type = ColType.TEXT)
private String feedbackInfo;
}
@@ -2,10 +2,13 @@ package com.budwk.app.zhgh.dayofficework.healthCheckup.model;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
import com.budwk.app.base.model.BaseModel; import com.budwk.app.base.model.BaseModel;
import com.budwk.app.sys.models.Sys_home_activity;
import com.budwk.app.sys.services.SysHomeConvert;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import org.nutz.dao.entity.annotation.*; import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert; import org.nutz.dao.interceptor.annotation.PrevInsert;
import org.nutz.lang.Lang;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date; import java.util.Date;
@@ -22,7 +25,7 @@ import java.util.List;
@Table("health_checkup_project") @Table("health_checkup_project")
@TableMeta("{'mysql-charset':'utf8mb4'}") @TableMeta("{'mysql-charset':'utf8mb4'}")
@Comment("体检项目表") @Comment("体检项目表")
public class HealthCheckupProject extends BaseModel implements Serializable { public class HealthCheckupProject extends BaseModel implements Serializable, SysHomeConvert {
@Column @Column
@Name @Name
@@ -72,11 +75,33 @@ public class HealthCheckupProject extends BaseModel implements Serializable {
@ColDefine(type = ColType.VARCHAR, width = 200) @ColDefine(type = ColType.VARCHAR, width = 200)
private String cover; private String cover;
@Column
@Comment("温馨提示")
@ColDefine(type = ColType.TEXT)
private String friendlyReminderText;
@Many(field = "projectId") @Many(field = "projectId")
private List<HealthCheckupProjectSubject> healthCheckupProjectSubjects; private List<HealthCheckupProjectSubject> healthCheckupProjectSubjects;
@Column
@Comment("短信信息")
@ColDefine(type = ColType.TEXT)
private String smsMessage;
@Override
public Sys_home_activity covertToSysHomeActivity() {
Sys_home_activity sysHomeActivity = new Sys_home_activity();
sysHomeActivity.setId(this.getId());
sysHomeActivity.setName(this.getName());
sysHomeActivity.setCover(this.getCover());
sysHomeActivity.setH5Url("/platform/healthCheckup/h5/list?id=" + this.getId());
if (Lang.isNotEmpty(this.getChoiceTimeStart())) {
sysHomeActivity.setStartDate(this.getChoiceTimeStart());
sysHomeActivity.setEndDate(this.getChoiceTimeEnd());
}
sysHomeActivity.setEnable(true);
sysHomeActivity.setAllowUserSql("select userId from health_checkup_user where projectId = '" + this.getId() + "' and userId = @userId");
sysHomeActivity.setClassPath(HealthCheckupProject.class.getName());
return sysHomeActivity;
}
} }
@@ -62,4 +62,10 @@ public class HealthCheckupProjectSubjectMoney extends BaseModel implements Seria
@Comment("选项排序") @Comment("选项排序")
@ColDefine(type = ColType.VARCHAR, width = 50) @ColDefine(type = ColType.VARCHAR, width = 50)
private String sort; private String sort;
@Column
@Comment("序号")
@ColDefine(type = ColType.INT)
private Integer serialNumber;
} }
@@ -1,6 +1,7 @@
package com.budwk.app.zhgh.dayofficework.healthCheckup.model; package com.budwk.app.zhgh.dayofficework.healthCheckup.model;
import com.budwk.app.base.model.BaseModel; import com.budwk.app.base.model.BaseModel;
import com.budwk.app.sys.annotation.DataCenterColumn;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import org.nutz.dao.entity.annotation.*; import org.nutz.dao.entity.annotation.*;
@@ -78,4 +79,58 @@ public class HealthCheckupUser extends BaseModel implements Serializable {
@ColDefine(type = ColType.VARCHAR, width = 30) @ColDefine(type = ColType.VARCHAR, width = 30)
private String userState; private String userState;
@Column
@Comment("手机号码")
@ColDefine(type = ColType.VARCHAR, width = 11)
private String phone;
/** 本项目本人填写的年龄;未填写时从系统出生日期计算。 */
@Column
@Comment("体检年龄")
@ColDefine(type = ColType.INT)
private Integer age;
@Column
@Comment("身份证号")
@ColDefine(type = ColType.VARCHAR, width = 18)
private String card;
@Column
@Comment("婚姻状况")
@ColDefine(type = ColType.VARCHAR, width = 20)
@DataCenterColumn(name = "婚姻状况", key = "hyztm", dict = "USER_MARRIAGE")
private String marriage;
@Column
@Comment("教职工类别")
@ColDefine(type = ColType.VARCHAR)
private String personType;
@Column
@Comment("确认状态(用户选择体检医院确认)")
// 确认状态保存单字符值,显式限定长度,避免自动迁移生成 CHAR(0) 导致默认值无效。
@ColDefine(type = ColType.CHAR, width = 1)
@Default("0")
private String confirmStatus;
@Column
@Comment("体检报告")
@ColDefine(type = ColType.TEXT)
private String medicalExamination;
@Column
@Comment("是否自聘")
@ColDefine(type = ColType.VARCHAR, width = 10)
@Default("否")
private String isEmployed;
@Column
@Comment("备注")
@ColDefine(type = ColType.TEXT)
private String bz;
@Column
@Comment("是否确认")
@ColDefine(type = ColType.BOOLEAN)
private Boolean isAudit;
} }
@@ -0,0 +1,61 @@
package com.budwk.app.zhgh.dayofficework.healthCheckup.param;
import com.budwk.app.base.param.PageForm;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
@EqualsAndHashCode(callSuper = true)
@Data
@ApiModel("用户生成体检名单分页查询参数")
public class HealthCheckupFilterUserPageForm extends PageForm {
@ApiModelProperty("体检项目id")
private String projectId;
@ApiModelProperty("姓名")
private String userName;
@ApiModelProperty("工号")
private String loginName;
@ApiModelProperty("性别")
private String sex;
@ApiModelProperty("出生日期")
private Date birthday;
@ApiModelProperty("出生月份")
private String[] birthMonths;
@ApiModelProperty("工会id")
private String unionId;
@ApiModelProperty("工会名称")
private String unionName;
@ApiModelProperty("单位id")
private String[] unitIds;
@ApiModelProperty("单位名称")
private String unitName;
@ApiModelProperty("人员类型")
private String[] personTypes;
@ApiModelProperty("聘用方式")
private String[] preparedBys;
@ApiModelProperty("在职状态")
private String[] userStates;
@ApiModelProperty("是否会员")
private Boolean isMember;
@ApiModelProperty("是否缴费会员")
private Boolean memberFeePaid;
}
@@ -0,0 +1,396 @@
package com.budwk.app.zhgh.dayofficework.healthCheckup.service;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.base.utils.ConditionGroupUtil;
import com.budwk.app.sys.views.View_user;
import com.budwk.app.sys.services.SysUserService;
import org.nutz.dao.Chain;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.*;
import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupProjectService;
import org.apache.commons.lang3.StringUtils;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.dao.util.cri.Static;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.util.NutMap;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
/** 体检接口业务服务;HTTP 路由和权限校验保留在 controller。 */
@IocBean
public class H5HealthCheckupApplicationService {
@Inject
private Dao dao;
@Inject
private BaseService baseService;
@Inject
private HealthCheckupProjectService healthCheckupProjectService;
@Inject
private SysUserService sysUserService;
/**
* 获取项目列表;业务筛选、数据读写和结果组装在本服务内完成。
* @param pageForm 分页、搜索及排序参数
* @param status 进行中 ongoing 或已结束 finished
* @param name 体检项目名称筛选值
* @return Object;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
public Object pageData(PageForm pageForm,
String status,
String name) {
Sql sql = Sqls.create("""
select
*,
(select count(*) from health_checkup_user_selection s where s.projectId=p.id and s.selectUserId=@userId) as selectCount
from
health_checkup_project p
$condition
""");
sql.setParam("userId", SecurityUtil.getUserId());
Cnd cnd = Cnd.NEW();
// 根据 status 参数筛选进行中或已结束的项目
if ("ongoing".equals(status)) {
// 进行中的项目:结束时间大于等于当前时间
SqlExpressionGroup group = Cnd.NEW().where();
group.and("p.choiceTimeStart", "<=", DateUtil.now());
group.and("p.choiceTimeEnd", ">=", DateUtil.now());
cnd.and(group);
} else if ("finished".equals(status)) {
// 已结束的项目:结束时间小于当前时间
cnd.and("p.choiceTimeEnd", "<", DateUtil.now());
}
cnd.and(new Static("(select count(*) from health_checkup_user where projectId=p.id and userId='%s')>0".formatted(SecurityUtil.getUserId())));
// 只有当name参数不为空时才添加名称查询条件
if (StrUtil.isNotBlank(name)) {
cnd.and("p.name", "like", "%" + name + "%");
}
cnd.asc("selectCount");
sql.setCondition(cnd);
return Result.success(healthCheckupProjectService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql));
}
/**
* 读取体检业务数据;业务筛选、数据读写和结果组装在本服务内完成。
* @param pageForm 分页、搜索及排序参数
* @param status 进行中 ongoing 或已结束 finished
* @param projectId 当前体检项目主键
* @return Object;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
public Object mineData(PageForm pageForm, String status, String projectId) {
Sql sql = Sqls.create("""
SELECT
us.*,
p.name,
p.choiceTimeStart,
p.choiceTimeEnd,
p.cover,
sub.optionName
FROM
health_checkup_user_selection us
LEFT JOIN health_checkup_project p ON us.projectId = p.id
LEFT JOIN health_checkup_project_subject sub on sub.id=us.subjectId
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.and("us.selectUserId", "=", SecurityUtil.getUserId());
cnd.andEX("us.projectId", "=", projectId);
cnd.orderBy("us.selectTime","desc");
// 根据 status 参数筛选进行中或已结束的项目
// if ("ongoing".equals(status)) {
// // 进行中的项目:结束时间大于等于当前时间
// cnd.and("p.choiceTimeEnd", ">=", DateUtil.now());
// } else if ("finished".equals(status)) {
// // 已结束的项目:结束时间小于当前时间
// cnd.and("p.choiceTimeEnd", "<", DateUtil.now());
// }
sql.setCondition(cnd);
Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
return Result.success(pagination);
}
/**
* 提交本人的体检医院及家属选择;业务筛选、数据读写和结果组装在本服务内完成。
* @param userSelection 本人选择的医院、套餐及家属信息
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result doSubmit(HealthCheckupUserSelection userSelection) {
// 手机端只允许操作本人在当前项目的选择;时间窗口和金额不能仅依赖页面校验。
HealthCheckupProject project = dao.fetch(HealthCheckupProject.class, userSelection.getProjectId());
Date now = new Date();
if (project == null || project.getChoiceTimeStart() == null || project.getChoiceTimeEnd() == null
|| now.before(project.getChoiceTimeStart()) || now.after(project.getChoiceTimeEnd())) {
return Result.error("当前项目不在报名时间内");
}
HealthCheckupProjectSubject selectedSubject = dao.fetch(HealthCheckupProjectSubject.class, userSelection.getSubjectId());
if (selectedSubject == null || !project.getId().equals(selectedSubject.getProjectId())) {
return Result.error("请选择当前项目的医院");
}
BigDecimal money = BigDecimal.ZERO;
for (HealthCheckupProjectSubjectMoney option : dao.query(HealthCheckupProjectSubjectMoney.class,
Cnd.where("subjectId", "=", selectedSubject.getId()).asc("serialNumber"))) {
Cnd eligible = Cnd.where("id", "=", SecurityUtil.getUserId());
ConditionGroupUtil.applyConditionGroup(eligible, option.getMatchCnd());
if (matchesSubject(userSelection.getProjectId(), option)) {
money = option.getMoney();
userSelection.setSubjectMoneyId(option.getId());
userSelection.setMoney(money);
break;
}
}
if (money == null || money.compareTo(BigDecimal.ZERO) <= 0) { // 小于等于0
return Result.error("金额必须大于0,当前医院没有符合您的选项!");
}
HealthCheckupUser healthCheckupUser = baseService.dao().fetch(HealthCheckupUser.class,
Cnd.NEW().and("projectId", "=", userSelection.getProjectId())
.and("userId", "=", SecurityUtil.getUserId()));
if (ObjectUtil.isEmpty(healthCheckupUser)) {
return Result.error("请确认您的身份信息是否无误!");
} else {
if (StringUtils.isBlank(healthCheckupUser.getPhone())) {
return Result.error("基础信息中,\"手机号\" 不能为空!");
} else if (StringUtils.isBlank(healthCheckupUser.getCard())) {
return Result.error("基础信息中,\"身份证号码\" 不能为空!");
}
}
HealthCheckupUserSelection existing = dao.fetch(HealthCheckupUserSelection.class,
Cnd.where("projectId", "=", project.getId()).and("selectUserId", "=", SecurityUtil.getUserId()));
if (StrUtil.isNotBlank(userSelection.getId()) && (existing == null || !existing.getId().equals(userSelection.getId()))) {
return Result.error("选择记录不属于当前用户");
}
userSelection.setId(existing == null ? null : existing.getId());
if (StrUtil.isNotBlank(userSelection.getId())) {
baseService.dao().clearLinks(userSelection, "companionList");
baseService.dao().delete(HealthCheckupUserSelection.class, userSelection.getId());
userSelection.setId(null);
}
userSelection.setSelectUserId(SecurityUtil.getUserId());
userSelection.setSelectTime(new Date());
baseService.dao().insertWith(userSelection, "companionList");
return Result.success("提交成功");
}
/**
* 在同一事务内保存个人信息、同步档案并提交医院选择。
* @param userSelection 当前项目及医院、家属信息
* @param baseInfo 可选个人信息,仅 age、phone、card、marriage 生效;项目归属取选择记录
* @return Result,code=0 表示全部保存成功;失败抛异常回滚,避免部分保存
*/
@Aop(TransAop.READ_COMMITTED)
public Result submitWithBaseInfo(HealthCheckupUserSelection userSelection, HealthCheckupUser baseInfo) {
if (baseInfo != null) {
baseInfo.setProjectId(userSelection.getProjectId());
Result saved = doSubmitUserBaseMessage(baseInfo);
if (!saved.isSuccess()) throw new com.budwk.app.base.exception.BaseException(saved.getMsg());
}
Result submitted = doSubmit(userSelection);
if (!submitted.isSuccess()) throw new com.budwk.app.base.exception.BaseException(submitted.getMsg());
return submitted;
}
/**
* 取消本人当前项目的体检选择;业务筛选、数据读写和结果组装在本服务内完成。
* @param id 当前业务记录主键
* @param projectId 当前体检项目主键
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result cancel(String id, String projectId) {
HealthCheckupProject checkupProject = baseService.dao().fetch(HealthCheckupProject.class, projectId);
if (checkupProject == null || checkupProject.getChoiceTimeEnd() == null || DateUtil.compare(new Date(), checkupProject.getChoiceTimeEnd()) > 0) {
return Result.error("抱歉,当前时间已经不能取消");
}
HealthCheckupUserSelection userSelection = baseService.dao().fetch(HealthCheckupUserSelection.class, id);
if (userSelection == null || !SecurityUtil.getUserId().equals(userSelection.getSelectUserId())
|| !projectId.equals(userSelection.getProjectId())) {
return Result.error("选择记录不存在或不属于当前用户");
}
baseService.dao().clearLinks(userSelection, "companionList");
baseService.dao().delete(HealthCheckupUserSelection.class, userSelection.getId());
return Result.success("取消成功");
}
/**
* 读取可选体检院区;业务筛选、数据读写和结果组装在本服务内完成。
* @return Object;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
public Object getCampus() {
return Result.success(baseService.dao().query(HealthCheckupCampus.class, Cnd.NEW().asc("campusCode")));
}
/**
* 读取本人当前项目的选择记录和家属明细;业务筛选、数据读写和结果组装在本服务内完成。
* @param projectId 当前体检项目主键
* @return Object;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
public Object selectInfo(String projectId) {
HealthCheckupUserSelection userSelection = healthCheckupProjectService.dao().fetch(HealthCheckupUserSelection.class,
Cnd.where("projectId", "=", projectId).and("selectUserId", "=", SecurityUtil.getUserId()));
if (userSelection != null) {
baseService.dao().fetchLinks(userSelection, "companionList");
NutMap nutMap = Lang.obj2map(userSelection, NutMap.class);
if (userSelection.getCompanionList().size() > 0) {
nutMap.put("isFamily", "是");
} else {
nutMap.put("isFamily", "否");
}
return Result.success(nutMap);
}
return Result.success();
}
/**
* 按本人档案条件匹配医院套餐额度;业务筛选、数据读写和结果组装在本服务内完成。
* @param id 当前业务记录主键
* @param marriage 当前表单婚姻状态;为空时使用已保存值
* @param age 当前表单年龄;为空时使用已保存值,仅预览不写入数据库
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
public Result getSubjectMoney(String id, String marriage, Integer age) {
if (age != null && (age < 0 || age > 120)) return Result.error("请输入0至120的整数年龄");
HealthCheckupProjectSubject hospital = dao.fetch(HealthCheckupProjectSubject.class, id);
if (hospital == null) return Result.error("请选择体检医院");
List<HealthCheckupProjectSubjectMoney> list = healthCheckupProjectService.dao().query(HealthCheckupProjectSubjectMoney.class, Cnd.where(HealthCheckupProjectSubjectMoney::getSubjectId, "=", id).asc("serialNumber"));
BigDecimal money = BigDecimal.valueOf(0.00);
String subjectMoneyId = "";
for (HealthCheckupProjectSubjectMoney subject : list) {
// 是否满足条件
Cnd cnd = Cnd.where("id", "=", SecurityUtil.getUserId());
ConditionGroupUtil.applyConditionGroup(cnd, subject.getMatchCnd());
int count = matchesSubject(hospital.getProjectId(), subject, age, marriage) ? 1 : 0;
if (count > 0) {
money = subject.getMoney();
subjectMoneyId = subject.getId();
break;
}
}
return Result.success().addData(Map.of("money", money, "subjectMoneyId", subjectMoneyId));
}
/**
* 获取基础信息数据;业务筛选、数据读写和结果组装在本服务内完成。
* @param checkupUser 体检人员基本信息
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
public Result findUserBaseMessageData(HealthCheckupUser checkupUser) {
checkupUser.setUserId(SecurityUtil.getUserId());
if(StringUtils.isNotBlank(checkupUser.getProjectId()) && StringUtils.isNotBlank(checkupUser.getUserId())){
Sql sql = Sqls.create("""
select cu.id,cu.projectId,cu.userId,cu.userName,cu.sex,
cu.loginName,cu.phone,cu.card,cu.marriage,
cu.personType, COALESCE(cu.age, TIMESTAMPDIFF(YEAR,u.birthday,CURDATE())) AS age
from health_checkup_user cu
left join sys_user u on cu.userId=u.id
$condition
""");
Cnd cnd = Cnd.NEW().and("cu.projectId", "=", checkupUser.getProjectId())
.and("cu.userId", "=", checkupUser.getUserId());
sql.setCondition(cnd);
NutMap nutMap = baseService.fetchMap(sql);
return Result.success(nutMap);
}
return Result.success();
}
/**
* 保存本人体检信息并同步系统档案;两处更新由同一事务提交。
* @param checkupUser projectId 为当前项目;age 为手填体检年龄,phone 为手机号,
* card 为身份证号,marriage 为已婚或未婚;其余客户端字段不用于更新
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result doSubmitUserBaseMessage(HealthCheckupUser checkupUser) {
// 以登录身份定位本人记录,不使用客户端传入的用户ID或记录ID。
HealthCheckupUser own = dao.fetch(HealthCheckupUser.class,
Cnd.where("projectId", "=", checkupUser.getProjectId()).and("userId", "=", SecurityUtil.getUserId()));
if (own == null) return Result.error("当前项目中没有您的体检记录");
// 仅接受本人当前项目的四个可编辑字段,禁止覆盖姓名、性别、人员类别和归属。
if (checkupUser.getAge() == null || checkupUser.getAge() < 0 || checkupUser.getAge() > 120)
return Result.error("请输入0至120的整数年龄");
String phone = StrUtil.trim(checkupUser.getPhone());
String card = StrUtil.upperFirst(StrUtil.trim(checkupUser.getCard()));
if (phone == null || !phone.matches("1[0-9]{10}")) return Result.error("请输入正确的手机号码");
if (card == null || !cn.hutool.core.util.IdcardUtil.isValidCard(card)) return Result.error("请输入正确的身份证号");
if (!"已婚".equals(checkupUser.getMarriage()) && !"未婚".equals(checkupUser.getMarriage()))
return Result.error("请选择婚姻状态");
if (sysUserService.fetch(SecurityUtil.getUserId()) == null)
return Result.error("当前用户档案不存在");
own.setAge(checkupUser.getAge());
own.setPhone(phone);
own.setCard(card.toUpperCase(java.util.Locale.ROOT));
own.setMarriage(checkupUser.getMarriage());
own.setConfirmStatus("1");
dao.update(own);
// 系统年龄由出生日期计算,使用身份证解析日期,不以手填年龄反推生日。
// 仅同步允许修改的档案列,保留姓名、性别、人员类型及其他系统字段。
sysUserService.update(Chain.make("mobile", phone)
.add("idCard", own.getCard())
.add("marriage", own.getMarriage())
.add("birthday", cn.hutool.core.util.IdcardUtil.getBirthDate(own.getCard())),
Cnd.where("id", "=", SecurityUtil.getUserId()));
sysUserService.deleteCache(SecurityUtil.getUserId());
return Result.success();
}
/**
* 上年度体检医院;业务筛选、数据读写和结果组装在本服务内完成。
* @param checkupUserSelection 查询上一年度医院的人员条件
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
public Result findLastYearHospital(HealthCheckupUserSelection checkupUserSelection) {
checkupUserSelection.setSelectUserId(SecurityUtil.getUserId());
return Result.success("成功",healthCheckupProjectService.findLastYearHospital(checkupUserSelection));
}
/**
* 用当前项目本人信息匹配套餐条件,未填写年龄时沿用系统出生日期。
* @param projectId 体检项目ID
* @param option 当前医院套餐金额选项及条件组
* @return true 表示本人满足该选项条件;名单不存在时为 false
*/
private boolean matchesSubject(String projectId, HealthCheckupProjectSubjectMoney option) {
return matchesSubject(projectId, option, null, null);
}
/** 用表单年龄和婚姻状态预览匹配;仅这两个字段可覆盖,其余信息取本人档案。 */
private boolean matchesSubject(String projectId, HealthCheckupProjectSubjectMoney option, Integer age, String marriage) {
Sql sql = Sqls.create("""
SELECT COUNT(*) AS matched FROM (
SELECT u.id, cu.userName AS username, cu.loginName AS loginname, cu.sex,
COALESCE(@age,cu.age,TIMESTAMPDIFF(YEAR,u.birthday,CURDATE())) AS age,
COALESCE(@marriage,cu.marriage) AS marriage, u.userState, u.preparedBy, cu.personType
FROM health_checkup_user cu JOIN vw_user u ON u.id=cu.userId
WHERE cu.projectId=@projectId AND cu.userId=@userId
) candidate $condition
""");
sql.setParam("age", age);
sql.setParam("marriage", StrUtil.blankToDefault(marriage, null));
sql.setParam("projectId", projectId);
sql.setParam("userId", SecurityUtil.getUserId());
Cnd condition = Cnd.NEW();
ConditionGroupUtil.applyConditionGroup(condition, option.getMatchCnd());
sql.setCondition(condition);
return baseService.fetchMap(sql).getInt("matched") > 0;
}
}
@@ -0,0 +1,108 @@
package com.budwk.app.zhgh.dayofficework.healthCheckup.service;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupCampus;
import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import java.util.List;
/** 体检接口业务服务;HTTP 路由和权限校验保留在 controller。 */
@IocBean
public class HealthCheckupCampusApplicationService {
@Inject
private BaseService baseService;
/**
* 分页查询;业务筛选、数据读写和结果组装在本服务内完成。
* @param pageForm 分页、搜索及排序参数
* @param campusName 院区名称筛选值
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
public Result pageData(PageForm pageForm, String campusName) {
Cnd cnd = Cnd.NEW();
Sql sql = Sqls.create("select * from health_checkup_campus $condition");
cnd.and(Cnd.likeEX("campusName", campusName));
cnd.asc("campusCode");
sql.setCondition(cnd);
return Result.success(baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql));
}
/**
* 添加院区;业务筛选、数据读写和结果组装在本服务内完成。
* @param campus 体检院区主键
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result doAdd(HealthCheckupCampus campus) {
try {
int count = baseService.dao().count(HealthCheckupCampus.class, Cnd.where(HealthCheckupCampus::getCampusCode, "=", campus.getCampusCode()));
if (count > 0) {
return Result.error("编码重复");
}
baseService.dao().insert(campus);
return Result.success();
} catch (Exception e) {
e.printStackTrace();
return Result.error();
}
}
/**
* 编辑院区;业务筛选、数据读写和结果组装在本服务内完成。
* @param campus 体检院区主键
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result doEdit(HealthCheckupCampus campus) {
try {
int count = baseService.dao().count(HealthCheckupCampus.class,
Cnd.where(HealthCheckupCampus::getCampusCode, "=", campus.getCampusCode())
.and(HealthCheckupCampus::getId, "!=", campus.getId()));
if (count > 0) {
return Result.error("编码重复");
}
baseService.dao().update(campus);
return Result.success();
} catch (Exception e) {
e.printStackTrace();
return Result.error();
}
}
/**
* 编辑院区;业务筛选、数据读写和结果组装在本服务内完成。
* @param id 当前业务记录主键
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result doDelete(String id) {
try {
baseService.dao().clear(HealthCheckupCampus.class, Cnd.where(HealthCheckupCampus::getId, "=", id));
return Result.success();
} catch (Exception e) {
e.printStackTrace();
return Result.error();
}
}
/**
* 查询所有院区;业务筛选、数据读写和结果组装在本服务内完成。
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
public Result queryCampus() {
try {
List<HealthCheckupCampus> campusList = baseService.dao().query(HealthCheckupCampus.class, Cnd.NEW().asc("campusCode"));
return Result.success(campusList);
} catch (Exception e) {
e.printStackTrace();
return Result.error();
}
}
}
@@ -0,0 +1,27 @@
package com.budwk.app.zhgh.dayofficework.healthCheckup.service;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupFeedback;
import org.nutz.lang.util.NutMap;
import java.util.List;
public interface HealthCheckupFeedbackService extends BaseService<HealthCheckupFeedback> {
/**
* Query feedback records by the selected filters on the list page.
*/
List<NutMap> listFeedback(String year, String projectId, String unionId);
/**
* Save a feedback record and bind it to the selected year, project and union.
*/
NutMap saveFeedback(String year, String projectId, String unionId, String feedbackInfo);
/**
* 删除单条体检反馈。
*/
NutMap deleteFeedback(String id);
NutMap deleteFeedbackBatch(String[] ids);
/**
* 查询问题反馈列表页数据。
*/
Pagination listFeedbackPage(Integer pageNumber, Integer pageSize, String year, String projectId, String unionId);
}
@@ -0,0 +1,835 @@
package com.budwk.app.zhgh.dayofficework.healthCheckup.service;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.model.ExcelImportRes;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.utils.CommonDownloadUtil;
import com.budwk.app.base.utils.ConditionGroupUtil;
import com.budwk.app.base.utils.easyexcel.EasyExcelUtil;
import com.budwk.app.sys.views.View_user;
import com.budwk.app.web.commons.auth.utils.AuthUtil;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.activity.basic.models.ActivityUserScope;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.*;
import com.budwk.app.zhgh.dayofficework.healthCheckup.param.HealthCheckupFilterUserPageForm;
import java.util.Set;
import java.util.HashSet;
import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupFeedbackService;
import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupProjectService;
import com.budwk.app.zhgh.dayofficework.healthCheckup.template.HealthCheckupImportTemp;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.formula.functions.T;
import org.apache.poi.ss.usermodel.Workbook;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.upload.TempFile;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
/** 体检接口业务服务;HTTP 路由和权限校验保留在 controller。 */
@IocBean
public class HealthCheckupListApplicationService {
@Inject
private Dao dao;
@Inject
private HealthCheckupProjectService healthCheckupProjectService;
@Inject
private HealthCheckupFeedbackService healthCheckupFeedbackService;
/**
* 查询尚未加入当前体检项目的人员;查询与提交共用筛选条件。
* @param pageForm 项目 ID、姓名/工号、人员属性、工会单位和分页排序参数,空筛选项表示不限
* @return Result,code=0 时 data.list 为人员列表,data.totalCount 为匹配总人数
*/
public Result candidatePageData(HealthCheckupFilterUserPageForm pageForm) {
Result invalid = validateAddUsers(pageForm);
if (invalid != null) return invalid;
return Result.success(healthCheckupProjectService.listPageMap(
pageForm.getPageNumber(), pageForm.getPageSize(), candidateSql(pageForm)));
}
/**
* 将全部匹配人员加入体检名单,并补齐项目参与范围;两个写入操作必须一起提交。
* @param pageForm 项目 ID 和人员筛选条件,分页参数仅用于预览,不限制实际添加数量
* @return Result,code=0 表示成功,msg 返回实际新增人数;已有名单和范围均不重复插入
*/
@Aop(TransAop.READ_COMMITTED)
public Result addUsers(HealthCheckupFilterUserPageForm pageForm) {
Result invalid = validateAddUsers(pageForm);
if (invalid != null) return invalid;
HealthCheckupProject project = dao.fetch(HealthCheckupProject.class, pageForm.getProjectId());
// 同一范围的添加请求锁定相同范围记录,避免并发重复写入名单及范围。
ActivityUserScope group = dao.fetch(ActivityUserScope.class,
Cnd.where("groupId", "=", project.getActivityGroupId()).asc("id"));
if (group == null) return Result.error("参与人员范围已变更,请刷新后重试");
List<NutMap> locked = healthCheckupProjectService.listMap(Sqls.create(
"select id from activity_user_scope where id=@id for update").setParam("id", group.getId()));
if (locked.isEmpty()) return Result.error("参与人员范围已变更,请刷新后重试");
List<NutMap> users = healthCheckupProjectService.listMap(candidateSql(pageForm));
Set<String> scopeUserIds = dao.query(ActivityUserScope.class,
Cnd.where("groupId", "=", project.getActivityGroupId())).stream()
.map(ActivityUserScope::getUserId).collect(Collectors.toSet());
Set<String> added = new HashSet<>();
for (NutMap user : users) {
String userId = user.getString("id");
if (!added.add(userId)) continue;
HealthCheckupUser entry = new HealthCheckupUser();
entry.setProjectId(project.getId());
entry.setUserId(userId);
entry.setLoginName(user.getString("loginname"));
entry.setUserName(user.getString("username"));
entry.setSex(user.getString("sex"));
entry.setPhone(user.getString("mobile"));
entry.setCard(user.getString("idCard"));
entry.setMarriage(user.getString("marriage"));
entry.setPersonType(user.getString("personType"));
entry.setUserState(user.getString("userState"));
entry.setUnionId(user.getString("unionId"));
entry.setUnionName(user.getString("unionName"));
entry.setUnitId(user.getString("unitId"));
entry.setUnitName(user.getString("unitName"));
dao.insert(entry);
// 范围已有人时只加名单;缺失时补入,避免后续更新名单将新增人员移除。
if (scopeUserIds.add(userId)) {
ActivityUserScope scope = new ActivityUserScope();
scope.setGroupId(group.getGroupId());
scope.setGroupName(group.getGroupName());
scope.setUserId(userId);
scope.setCreator(SecurityUtil.getUserId());
dao.insert(scope);
}
}
return Result.success("成功添加" + added.size() + "人,参与人员范围已同步");
}
/** 校验导入名单同等角色、目标项目和实际存在的参与范围;返回 null 表示通过。 */
private Result validateAddUsers(HealthCheckupFilterUserPageForm pageForm) {
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name(),
RoleConstant.SCHOOL_UNION_CHAIRMAN.name())) {
return Result.error("您没有【添加人员】的权限");
}
if (pageForm == null || StrUtil.isBlank(pageForm.getProjectId())) return Result.error("请先选择体检项目");
HealthCheckupProject project = dao.fetch(HealthCheckupProject.class, pageForm.getProjectId());
if (project == null) return Result.error("体检项目不存在");
if (project.getActivityGroupId() == null || dao.count(ActivityUserScope.class,
Cnd.where("groupId", "=", project.getActivityGroupId()).and("groupName", "is not", null)) == 0) {
return Result.error("项目未关联有效参与人员范围,请先设置参与人员范围");
}
return null;
}
/** 统一预览与提交的候选条件;项目限定和名单排除不能随可选筛选项省略。 */
private Sql candidateSql(HealthCheckupFilterUserPageForm form) {
Sql sql = Sqls.create("""
select u.* from vw_user u
left join sys_user su on su.id=u.id
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.and("u.id", "not in", Sqls.create(
"select userId from health_checkup_user where projectId=@projectId and userId is not null")
.setParam("projectId", form.getProjectId()));
if (StrUtil.isNotBlank(form.getSearchKeyword())) {
SqlExpressionGroup search = new SqlExpressionGroup();
search.orLike("u.username", form.getSearchKeyword());
search.orLike("u.loginname", form.getSearchKeyword());
cnd.and(search);
}
cnd.andEX("u.sex", "=", form.getSex());
cnd.andEX("u.birthday", "=", form.getBirthday());
cnd.andEX("MONTH(u.birthday)", "in", form.getBirthMonths());
cnd.andEX("u.unionId", "=", form.getUnionId());
cnd.andEX("u.unitId", "in", form.getUnitIds());
cnd.andEX("u.personType", "in", form.getPersonTypes());
cnd.andEX("u.preparedBy", "in", form.getPreparedBys());
cnd.andEX("u.userState", "in", form.getUserStates());
cnd.andEX("u.member", "=", form.getIsMember());
cnd.andEX("IFNULL(su.memberFeePaid, 0)", "=", form.getMemberFeePaid());
// 排序字段仅接受弹窗展示列,禁止将客户端任意表达式拼入 SQL。
Set<String> sortFields = Set.of("loginname", "username", "sex", "birthday", "personType",
"preparedBy", "userState", "unionName", "unitName");
if (form.getPageOrderName() != null && sortFields.contains(form.getPageOrderName())) {
cnd.orderBy("u." + form.getPageOrderName(), "ascending".equals(form.getPageOrderBy()) ? "ASC" : "DESC");
} else {
cnd.asc("u.unionCode").asc("u.unitCode");
}
cnd.asc("u.id");
sql.setCondition(cnd);
return sql;
}
/**
* 分页查询;业务筛选、数据读写和结果组装在本服务内完成。
* @param pageForm 分页、搜索及排序参数
* @param projectId 当前体检项目主键
* @param subjectId 体检医院选项主键
* @param unionId 所属分工会主键,可空时按接口范围处理
* @param unitId 所属单位主键筛选值
* @param physicalExaminationStatus 1 已选、0 未选、2 全部
* @param isAudit 确认状态:1 已确认,0 未确认
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
public Result pageData(PageForm pageForm, String projectId, String subjectId,
String unionId, String unitId, String physicalExaminationStatus, String isAudit) {
List<HealthCheckupUnionConfirm> confirms = dao.query(HealthCheckupUnionConfirm.class, Cnd.where("projectId", "=", projectId));
HealthCheckupProject project = healthCheckupProjectService.findOne(projectId);
Cnd cnd = Cnd.NEW();
Sql sql = Sqls.create("""
SELECT
hcu.id AS headId,
hcu.userId AS id,
hcu.loginName,
hcu.userName,
hcu.sex,
hcu.unionId,
hcu.unionName,
hcu.unitName,
hcus.selectTime,
hcus.campus,
hcus.subjectId,
hcu.bz,
hcu.isAudit,
hcus.receiveAddress,
ca.campusName
FROM
health_checkup_user hcu
LEFT JOIN health_checkup_user_selection hcus ON hcu.userId = hcus.selectUserId
AND hcus.projectId=@projectId
LEFT JOIN health_checkup_campus ca on ca.id=hcus.campus
$condition
""").setParam("projectId", projectId);
sql.setCondition(cnd);
cnd.andEX("hcu.projectId", "=", projectId);
cnd.andEX("hcu.unionId", "=", unionId);
cnd.andEX("hcu.unitId", "=", unitId);
cnd.andEX("hcus.subjectId", "=", subjectId);
if(StringUtils.isNotBlank(isAudit)){
if(isAudit.equals("1")){
cnd.and("hcu.isAudit", "=", "1");
} else if(isAudit.equals("0")){
SqlExpressionGroup group = Cnd.NEW().where();
group.andEX("hcu.isAudit", "=", "0");
group.orIsNull("hcu.isAudit");
cnd.and(group);
}
}
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
cnd.andEX("hcu.unionId", "=", SecurityUtil.getUnionId());
}
//体检状态
if(StringUtils.isNotBlank(physicalExaminationStatus) && !physicalExaminationStatus.equals("2")){
if(physicalExaminationStatus.equals("1")) cnd.where().andNotIsNull("hcus.selectTime");
if(physicalExaminationStatus.equals("0")) cnd.where().andIsNull("hcus.selectTime");
}
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
SqlExpressionGroup group = new SqlExpressionGroup();
group.orLike("hcu.userName", pageForm.getSearchKeyword());
group.orLike("hcu.loginName", pageForm.getSearchKeyword());
cnd.and(group);
}
cnd.groupBy("hcu.userId");
if (StrUtil.isNotBlank(pageForm.getPageOrderName()) && Strings.isNotBlank(pageForm.getPageOrderBy())) {
cnd.orderBy(pageForm.getPageOrderName(), "ascending".equalsIgnoreCase(pageForm.getPageOrderBy()) ? "ASC" : "DESC");
} else {
cnd.desc("hcus.selectTime").asc("hcu.unitId");
}
cnd.desc("hcu.id");
Pagination pagination = healthCheckupProjectService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
List<NutMap> paginationList = pagination.getList();
paginationList.forEach(v -> {
if (StrUtil.isNotBlank(v.getString("subjectId"))) {
List<HealthCheckupProjectSubject> subjects = project.getHealthCheckupProjectSubjects();
HealthCheckupProjectSubject subject = subjects.stream().filter(s -> s.getId().equals(v.getString("subjectId"))).findFirst().orElse(null);
v.setv("optionName", subject.getOptionName());
}
if (StrUtil.isNotBlank(v.getString("unionId")) && ObjectUtil.isNotEmpty(v.getBoolean("isAudit")) && v.getBoolean("isAudit")) {
HealthCheckupUnionConfirm confirm = confirms.stream()
.filter(o -> o.getUnionId().equals(v.getString("unionId")))
.findFirst()
.orElse(null);
// v.setv("isAudit", confirm != null ? confirm.getIsAudit() : "");
v.setv("auditTime", confirm != null ? confirm.getAuditTime() : "");
}
});
return Result.success(pagination);
}
/**
* 体检名单确认;业务筛选、数据读写和结果组装在本服务内完成。
* @param projectId 当前体检项目主键
* @param unionId 所属分工会主键,可空时按接口范围处理
* @param flag 确认或取消、已选或未选的业务标志
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result doAuditUser(String projectId,
String unionId,
Boolean flag) {
if (StrUtil.isBlank(unionId)) {
unionId = SecurityUtil.getUnionId();
}
if (flag) {
dao.update(HealthCheckupUnionConfirm.class, Chain.make("isAudit", true)
.add("auditTime", DateUtil.date())
.add("auditUser", SecurityUtil.getUserId()),
Cnd.where("projectId", "=", projectId).and("unionId", "=", unionId));
dao.update(HealthCheckupUser.class, Chain.make("isAudit", true),
Cnd.where("projectId", "=", projectId).and("unionId", "=", unionId));
} else {
dao.update(HealthCheckupUnionConfirm.class, Chain.make("isAudit", null)
.add("auditTime", null)
.add("auditUser", null),
Cnd.where("projectId", "=", projectId).and("unionId", "=", unionId));
dao.update(HealthCheckupUser.class, Chain.make("isAudit", null),
Cnd.where("projectId", "=", projectId).and("unionId", "=", unionId));
}
return Result.success();
}
/**
* 体检名单管理员编辑选择记录;业务筛选、数据读写和结果组装在本服务内完成。
* @param subjectId 体检医院选项主键
* @param campus 体检院区主键
* @param projectId 当前体检项目主键
* @param userId 教职工主键
* @param bz 选择记录备注
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result doEditHealthCheckupData(String subjectId, String campus, String projectId, String userId, String bz) {
if(!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(),"HEALTH_ADMIN")) {
return Result.error("您没有操作此按钮的权限");
}
//查询用户符合哪个套餐
List<HealthCheckupProjectSubjectMoney> list = healthCheckupProjectService.dao().query(HealthCheckupProjectSubjectMoney.class,
Cnd.where(HealthCheckupProjectSubjectMoney::getSubjectId, "=", subjectId));
BigDecimal money = BigDecimal.valueOf(0.00);
String subjectMoneyId = "";
for (HealthCheckupProjectSubjectMoney subject : list) {
// 是否满足条件
Cnd cnd = Cnd.where("id", "=", userId);
ConditionGroupUtil.applyConditionGroup(cnd, subject.getMatchCnd());
int count = dao.count(View_user.class, cnd);
if (count > 0) {
money = subject.getMoney();
subjectMoneyId = subject.getId();
break;
}
}
//查询用户有没有选择过套餐
HealthCheckupUserSelection userSelection = healthCheckupProjectService.dao().fetch(HealthCheckupUserSelection.class,
Cnd.where("projectId", "=", projectId)
.and("selectUserId", "=", userId));
//如果选择过套餐就修改选择的套餐id
if (Lang.isNotEmpty(userSelection)) {
userSelection.setSubjectId(subjectId);
userSelection.setCampus(campus);
userSelection.setBz(bz);
userSelection.setSubjectMoneyId(subjectMoneyId);
userSelection.setMoney(money);
healthCheckupProjectService.update(userSelection);
} else {
//如果没有选择过套餐添加一条记录
HealthCheckupUserSelection checkupUserSelection = new HealthCheckupUserSelection();
checkupUserSelection.setSelectUserId(userId);
checkupUserSelection.setProjectId(projectId);
checkupUserSelection.setSubjectId(subjectId);
checkupUserSelection.setCampus(campus);
checkupUserSelection.setSelectTime(new Date());
checkupUserSelection.setBz(bz);
checkupUserSelection.setSubjectMoneyId(subjectMoneyId);
checkupUserSelection.setMoney(money);
healthCheckupProjectService.insert(checkupUserSelection);
}
return Result.success();
}
/**
* 体检名单导入名单;业务筛选、数据读写和结果组装在本服务内完成。
* @param file 上传的 Excel 临时文件
* @param healthProjectId 导入目标体检项目主键
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result healthImport(TempFile file, String healthProjectId) {
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(),
RoleConstant.SCHOOL_UNION_ADMIN.name(),
RoleConstant.SCHOOL_UNION_CHAIRMAN.name())) {
return Result.error("您没有【导入名单】的权限");
} else {
// 读取数据
List<T> ts = EasyExcelUtil.syncReadModel(file.getFile(), HealthCheckupImportTemp.class, 0, 1);
List<HealthCheckupImportTemp> healthCheckupImportTemps = JSONUtil.parseArray(JSONUtil.toJsonStr(ts)).toList(HealthCheckupImportTemp.class);
List<String> loginNames = healthCheckupImportTemps.stream().filter(v -> Strings.isNotBlank(v.getLoginName())).map(v -> v.getLoginName()).collect(Collectors.toList());
//全部的体检名单
List<HealthCheckupUser> healthCheckupUserList = dao.query(HealthCheckupUser.class, Cnd.where(HealthCheckupUser::getProjectId, "=", healthProjectId));
List<View_user> userList = dao.query(View_user.class, Cnd.where(View_user::getLoginname, "in", loginNames));
HealthCheckupProject checkupProject = dao.fetch(HealthCheckupProject.class, healthProjectId);
ActivityUserScope userScope = dao.fetch(ActivityUserScope.class, Cnd.where("groupId", "=", checkupProject.getActivityGroupId()));
List<ActivityUserScope> userScopeList = new ArrayList<>();
List<HealthCheckupUser> healthCheckupUsersToAdd = new ArrayList<>();
int successCount = 0;
for (int i = 0; i < healthCheckupImportTemps.size(); i++) {
HealthCheckupImportTemp excel = healthCheckupImportTemps.get(i);
if (StrUtil.isBlank(excel.getLoginName())) {
excel.setErrInfo("工号为空", i + 1);
continue;
}
// 不能在excel里重复
if (healthCheckupImportTemps.stream().filter(s -> s.getLoginName().equals(excel.getLoginName())).count() > 1) {
excel.setErrInfo("重复数据", i + 1);
continue;
}
View_user user = userList.stream().filter(s -> s.getLoginname().equals(excel.getLoginName())).findFirst().orElse(null);
if (user == null) {
excel.setErrInfo("无此用户:" + excel.getLoginName(), i + 1);
continue;
}
String projectName = checkupProject.getName();
if(projectName.contains("在职教职工")) {
projectName = "在职教职工";
}
if(projectName.contains("校聘高知")) {
projectName = "校聘高知";
}
if (healthCheckupUserList.stream().anyMatch(s -> s.getUserId().equals(user.getId()))) {
Chain chain = Chain.make("personType", projectName);
if(StringUtils.isNotBlank(excel.getPhone())){
chain.add("phone", excel.getPhone());
}
dao.update(
HealthCheckupUser.class,chain,
Cnd.NEW().and(HealthCheckupUser::getUserId, "=", user.getId())
.and(HealthCheckupUser::getProjectId, "=", healthProjectId)
);
} else {
ActivityUserScope s = new ActivityUserScope();
s.setGroupId(userScope.getGroupId());
s.setGroupName(userScope.getGroupName());
s.setUserId(user.getId());
s.setCreator(SecurityUtil.getUserId());
userScopeList.add(s);
HealthCheckupUser newHealthUser = new HealthCheckupUser();
newHealthUser.setProjectId(healthProjectId);
newHealthUser.setUserId(user.getId());
newHealthUser.setUserName(user.getUsername());
newHealthUser.setSex(user.getSex());
newHealthUser.setLoginName(user.getLoginname());
newHealthUser.setUnionName(user.getUnionName());
newHealthUser.setUnionId(user.getUnionId());
newHealthUser.setUnitName(user.getUnitName());
newHealthUser.setCard(user.getIdCard());
newHealthUser.setPhone(excel.getPhone());
newHealthUser.setMarriage(user.getMarriage());
newHealthUser.setPersonType(projectName);
healthCheckupUsersToAdd.add(newHealthUser);
successCount++;
}
}
dao.insert(userScopeList);
dao.insert(healthCheckupUsersToAdd);
// 创建结果集
ExcelImportRes<HealthCheckupImportTemp> excelImportRes = new ExcelImportRes<>();
excelImportRes.setTotalRecords(healthCheckupImportTemps.size());
// 添加错误记录
excelImportRes.setErrorDetails(healthCheckupImportTemps.stream().filter(s -> StrUtil.isNotBlank(s.getErrMsg())).collect(Collectors.toList()));
excelImportRes.setFailedCount(excelImportRes.getErrorDetails().size());
excelImportRes.setSuccessCount(successCount);
return Result.success(excelImportRes);
}
}
/**
* 下载体检参加人员导入模版;业务筛选、数据读写和结果组装在本服务内完成。
* @param response 接收 Excel 文件流的 HTTP 响应
* 文件内容直接写入 response,不返回 JSON。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public void downloadTem(HttpServletResponse response) {
List<ExcelExportEntity> entities = new ArrayList<>();
entities.add(new ExcelExportEntity("工号", "loginName", 20));
entities.add(new ExcelExportEntity("姓名", "userName", 20));
entities.add(new ExcelExportEntity("手机号", "phone", 20));
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entities, Collections.emptyList());
CommonDownloadUtil.download("参加人员导入模版.xlsx", workbook, response);
}
/**
* 体检名单删除;业务筛选、数据读写和结果组装在本服务内完成。
* @param id 当前业务记录主键
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result doDelete(String id) {
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(),
RoleConstant.SCHOOL_UNION_ADMIN.name(),
RoleConstant.SCHOOL_UNION_CHAIRMAN.name(),
RoleConstant.BRANCH_UNION_ADMIN.name(),
RoleConstant.BRANCH_UNION_CHAIRMAN.name())) {
return Result.error("您没有【删除】的权限");
} else {
HealthCheckupUser fetch = dao.fetch(HealthCheckupUser.class, Cnd.where(HealthCheckupUser::getId, "=", id));
Cnd and = Cnd.NEW().and(HealthCheckupUserSelection::getProjectId, "=", fetch.getProjectId())
.and(HealthCheckupUserSelection::getSelectUserId, "=", fetch.getUserId());
dao.clear(HealthCheckupUserSelection.class, and);
dao.clear(HealthCheckupUser.class, Cnd.where(HealthCheckupUser::getId, "=", id));
return Result.success();
}
}
/**
* 下载体检报告导入模版;业务筛选、数据读写和结果组装在本服务内完成。
* @param response 接收 Excel 文件流的 HTTP 响应
* 文件内容直接写入 response,不返回 JSON。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public void downloadTemMedicalExaminationReport(HttpServletResponse response) {
List<ExcelExportEntity> entities = new ArrayList<>();
entities.add(new ExcelExportEntity("工号", "loginName", 20));
entities.add(new ExcelExportEntity("体检报告", "medicalExamination", 20));
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entities, Collections.emptyList());
CommonDownloadUtil.download("体检报告导入模版.xlsx", workbook, response);
}
/**
* 体检名单导入名单;业务筛选、数据读写和结果组装在本服务内完成。
* @param file 上传的 Excel 临时文件
* @param healthProjectId 导入目标体检项目主键
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result healthImportMedicalExaminationReport(TempFile file, String healthProjectId) {
// 读取数据
List<T> ts = EasyExcelUtil.syncReadModel(file.getFile(), HealthCheckupImportTemp.class, 0, 1);
List<HealthCheckupImportTemp> healthCheckupImportTemps = JSONUtil.parseArray(JSONUtil.toJsonStr(ts)).toList(HealthCheckupImportTemp.class);
List<String> loginNames = healthCheckupImportTemps.stream().filter(v -> Strings.isNotBlank(v.getLoginName())).map(v -> v.getLoginName()).collect(Collectors.toList());
List<View_user> userList = dao.query(View_user.class, Cnd.where(View_user::getLoginname, "in", loginNames));
int successCount = 0;
for (int i = 0; i < healthCheckupImportTemps.size(); i++) {
HealthCheckupImportTemp excel = healthCheckupImportTemps.get(i);
if (StrUtil.isBlank(excel.getLoginName())) {
excel.setErrInfo("工号为空", i + 1);
continue;
}
// 不能在excel里重复
if (healthCheckupImportTemps.stream().filter(s -> s.getLoginName().equals(excel.getLoginName())).count() > 1) {
excel.setErrInfo("重复数据", i + 1);
}
View_user user = userList.stream().filter(s -> s.getLoginname().equals(excel.getLoginName())).findFirst().orElse(null);
if (user == null) {
excel.setErrInfo("无此用户", i + 1);
continue;
}
dao.update(HealthCheckupUser.class,
Chain.make("medicalExamination", excel.getMedicalExamination()),
Cnd.where("loginName", "=", excel.getLoginName()).and("projectId", "=", healthProjectId));
successCount++;
}
// 创建结果集
ExcelImportRes<HealthCheckupImportTemp> excelImportRes = new ExcelImportRes<>();
excelImportRes.setTotalRecords(healthCheckupImportTemps.size());
// 添加错误记录
excelImportRes.setErrorDetails(healthCheckupImportTemps.stream().filter(s -> StrUtil.isNotBlank(s.getErrMsg())).collect(Collectors.toList()));
excelImportRes.setFailedCount(excelImportRes.getErrorDetails().size());
excelImportRes.setSuccessCount(successCount);
return Result.success(excelImportRes);
}
/**
* 套餐选择器查询;业务筛选、数据读写和结果组装在本服务内完成。
* @param projectId 当前体检项目主键
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
public Result listSubjects(String projectId) {
return Result.success(
dao.query(HealthCheckupProjectSubject.class,
Cnd.NEW().and("projectId","=",projectId))
);
}
/**
* 体检反馈列表;业务筛选、数据读写和结果组装在本服务内完成。
* @param year 四位体检年度
* @param projectId 当前体检项目主键
* @param unionId 所属分工会主键,可空时按接口范围处理
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
public Result feedbackList(String year, String projectId, String unionId) {
if (StrUtil.isBlank(unionId)) {
unionId = SecurityUtil.getUnionId();
}
if (StrUtil.hasBlank(year, projectId, unionId)) {
return Result.error("请选择年度、体检项目、分工会后再查看反馈");
}
return Result.success(healthCheckupFeedbackService.listFeedback(year, projectId, unionId));
}
/**
* 保存体检反馈;业务筛选、数据读写和结果组装在本服务内完成。
* @param year 四位体检年度
* @param projectId 当前体检项目主键
* @param unionId 所属分工会主键,可空时按接口范围处理
* @param feedbackInfo 反馈正文
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result saveFeedback(String year, String projectId, String unionId, String feedbackInfo) {
if (StrUtil.isBlank(unionId)) {
unionId = SecurityUtil.getUnionId();
}
NutMap result = healthCheckupFeedbackService.saveFeedback(year, projectId, unionId, feedbackInfo);
if (result.getInt("code") == 0) {
return Result.success(result.getString("msg"));
}
return Result.error(result.getString("msg"));
}
/**
* 删除体检反馈;业务筛选、数据读写和结果组装在本服务内完成。
* @param id 当前业务记录主键
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result deleteFeedback(String id) {
NutMap result = healthCheckupFeedbackService.deleteFeedback(id);
if (result.getInt("code") == 0) {
return Result.success(result.getString("msg"));
}
return Result.error(result.getString("msg"));
}
/**
* 批量删除体检反馈;业务筛选、数据读写和结果组装在本服务内完成。
* @param ids 逗号分隔或 JSON 数组形式的记录主键
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result deleteFeedbackBatch(String ids) {
String[] idArray = null;
if (StrUtil.isNotBlank(ids)) {
// 兼容前端传逗号分隔字符串和JSON数组字符串两种格式。
if (ids.trim().startsWith("[")) {
idArray = JSONUtil.parseArray(ids).toList(String.class).toArray(new String[0]);
} else {
idArray = ids.split(",");
}
}
NutMap result = healthCheckupFeedbackService.deleteFeedbackBatch(idArray);
if (result.getInt("code") == 0) {
return Result.success(result.getString("msg"));
}
return Result.error(result.getString("msg"));
}
/**
* 问题反馈列表分页;业务筛选、数据读写和结果组装在本服务内完成。
* @param pageForm 分页、搜索及排序参数
* @param year 四位体检年度
* @param projectId 当前体检项目主键
* @param unionId 所属分工会主键,可空时按接口范围处理
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
public Result feedbackQueryPageData(PageForm pageForm, String year, String projectId, String unionId) {
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name()) && StrUtil.isBlank(unionId)) {
unionId = SecurityUtil.getUnionId();
}
return Result.success(healthCheckupFeedbackService.listFeedbackPage(
pageForm.getPageNumber(),
pageForm.getPageSize(),
year,
projectId,
unionId
));
}
/**
* 体检名单编辑备注;业务筛选、数据读写和结果组装在本服务内完成。
* @param userId 教职工主键
* @param projectId 当前体检项目主键
* @param remarks 人员备注内容
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result doEditRemarks(String userId, String projectId,String remarks) {
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.BRANCH_UNION_ADMIN.name(), RoleConstant.BRANCH_UNION_CHAIRMAN.name())) {
return Result.error("您没有操作此按钮的权限");
}
dao.update(HealthCheckupUser.class,
Chain.make("bz", remarks),
Cnd.where("userId", "=", userId)
.and("projectId", "=", projectId));
return Result.success();
}
/**
* 导出;业务筛选、数据读写和结果组装在本服务内完成。
* @param projectId 当前体检项目主键
* @param unionId 所属分工会主键,可空时按接口范围处理
* @param searchKeyword 姓名或工号搜索文本
* @param subjectId 体检医院选项主键
* @param unitId 所属单位主键筛选值
* @param physicalExaminationStatus 1 已选、0 未选、2 全部
* @param pageOrderName 排序字段名
* @param pageOrderBy ascending 升序,否则降序
* @param response 接收 Excel 文件流的 HTTP 响应
* 文件内容直接写入 response,不返回 JSON。
*/
public void exportHealthUser(String projectId,
String unionId,
String searchKeyword,
String subjectId,
String unitId,
String physicalExaminationStatus,
String pageOrderName,
String pageOrderBy,
HttpServletResponse response) {
List<HealthCheckupUnionConfirm> confirms = dao.query(HealthCheckupUnionConfirm.class, Cnd.where("projectId", "=", projectId));
HealthCheckupProject project = healthCheckupProjectService.findOne(projectId);
Cnd cnd = Cnd.NEW();
Sql sql = Sqls.create("""
SELECT
hcu.id AS headId,
hcu.userId AS id,
hcu.loginName,
hcu.userName,
hcu.sex,
hcu.unionId,
hcu.unionName,
hcu.unitName,
hcus.selectTime,
hcus.campus,
hcus.subjectId,
hcu.bz,
hcus.receiveAddress,
ca.campusName
FROM health_checkup_user hcu
LEFT JOIN health_checkup_user_selection hcus ON hcu.userId = hcus.selectUserId
AND hcus.projectId=@projectId
LEFT JOIN health_checkup_campus ca on ca.id=hcus.campus
$condition
""").setParam("projectId", projectId);
sql.setCondition(cnd);
cnd.andEX("hcu.projectId", "=", projectId);
cnd.andEX("hcu.unionId", "=", unionId);
cnd.andEX("hcu.unitId", "=", unitId);
cnd.andEX("hcus.subjectId", "=", subjectId);
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
cnd.andEX("hcu.unionId", "=", SecurityUtil.getUnionId());
}
//体检状态
if(StringUtils.isNotBlank(physicalExaminationStatus) && !physicalExaminationStatus.equals("2")){
if(physicalExaminationStatus.equals("1")) cnd.where().andNotIsNull("hcus.selectTime");
if(physicalExaminationStatus.equals("0")) cnd.where().andIsNull("hcus.selectTime");
}
if (StrUtil.isNotBlank(searchKeyword)) {
SqlExpressionGroup group = new SqlExpressionGroup();
group.orLike("hcu.userName", searchKeyword);
group.orLike("hcu.loginName", searchKeyword);
cnd.and(group);
}
cnd.groupBy("hcu.userId");
if (StrUtil.isNotBlank(pageOrderName) && Strings.isNotBlank(pageOrderBy)) {
cnd.orderBy(pageOrderName, "ascending".equalsIgnoreCase(pageOrderBy) ? "ASC" : "DESC");
} else {
cnd.desc("hcus.selectTime").asc("hcu.unitId");
}
sql.setCondition(cnd);
List<NutMap> paginationList = healthCheckupProjectService.listMap(sql);
paginationList.forEach(v -> {
if (StrUtil.isNotBlank(v.getString("subjectId"))) {
List<HealthCheckupProjectSubject> subjects = project.getHealthCheckupProjectSubjects();
HealthCheckupProjectSubject subject = subjects.stream().filter(s -> s.getId().equals(v.getString("subjectId"))).findFirst().orElse(null);
v.setv("optionName", subject.getOptionName());
}
if (StrUtil.isNotBlank(v.getString("unionId"))) {
HealthCheckupUnionConfirm confirm = confirms.stream().filter(o -> o.getUnionId().equals(v.getString("unionId"))).findFirst().orElse(null);
v.setv("isAudit", confirm != null && confirm.getIsAudit() ? "已确认" : "未确认");
v.setv("auditTime", confirm != null && ObjectUtil.isNotEmpty(confirm.getAuditTime() )
? new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(confirm.getAuditTime()) : "");
}
});
for (int i = 0; i < paginationList.size(); i++) {
paginationList.get(i).put("index", i + 1);
}
List<ExcelExportEntity> entityList = new ArrayList<>() {{
add(new ExcelExportEntity("序号", "index", 20));
add(new ExcelExportEntity("工号", "loginName", 20));
add(new ExcelExportEntity("姓名", "userName", 20));
add(new ExcelExportEntity("性别", "sex", 20));
add(new ExcelExportEntity("所属工会", "unionName", 20));
add(new ExcelExportEntity("所属单位", "unitName", 20));
add(new ExcelExportEntity("所选套餐", "optionName", 20));
add(new ExcelExportEntity("选择时间", "selectTime", 50));
add(new ExcelExportEntity("是否确认", "isAudit", 50));
add(new ExcelExportEntity("确认时间", "auditTime", 50));
add(new ExcelExportEntity("备注", "bz", 50));
}};
try {
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
exportParams.setTitle("体检名单数据导出");
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, paginationList);
CommonDownloadUtil.download("体检名单数据导出.xlsx", workbook, response);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,26 @@
package com.budwk.app.zhgh.dayofficework.healthCheckup.service;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupUser;
/**
* @ClassName HealthCheckupPersonConfirmStatisticsService
* @Description 工会人员确认情况统计
* @Author Codex
* @Date 2026/4/28
*/
public interface HealthCheckupPersonConfirmStatisticsService extends BaseService<HealthCheckupUser> {
/**
* 工会确认情况分页统计
*
* @param pageNumber 页码
* @param pageSize 页大小
* @param year 年度
* @param projectId 体检项目
* @param unionId 工会
* @return 统计分页结果
*/
Pagination personConfirmPageData(Integer pageNumber, Integer pageSize, Integer year, String projectId, String unionId);
}
@@ -0,0 +1,224 @@
package com.budwk.app.zhgh.dayofficework.healthCheckup.service;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.sys.models.Sys_home_activity;
import com.budwk.app.sys.models.Sys_union;
import com.budwk.app.zhgh.activity.culture.service.ActivityCultureService;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.*;
import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupProjectService;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.Daos;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.util.NutMap;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/** 体检接口业务服务;HTTP 路由和权限校验保留在 controller。 */
@IocBean
public class HealthCheckupProjectMangeApplicationService {
@Inject
private HealthCheckupProjectService healthCheckupProjectService;
@Inject
private ActivityCultureService activityCultureService;
/**
* 分页查询;业务筛选、数据读写和结果组装在本服务内完成。
* @param pageForm 分页、搜索及排序参数
* @param year 四位体检年度
* @param name 体检项目名称筛选值
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
public Result pageData(PageForm pageForm,
Integer year,
String name) {
Sql sql = Sqls.create("""
SELECT
hcp.id,
hcp.`year`,
hcp.`name`,
hcp.choiceTimeStart,
hcp.choiceTimeEnd,
hcp.activityGroupId,
hcp.cover,
hcp.activityGroupName,
hcp.healthCheckupType,
IF((select count(userId) from health_checkup_user hcu where hcu.projectId = hcp.id) > 0,true,false) AS isHasUserList,
IF(NOW() > hcp.choiceTimeStart AND NOW() < hcp.choiceTimeEnd, true, false) AS isWithinChoiceTime,
IF(NOW() < hcp.choiceTimeStart, true, false) AS canCreated
FROM
health_checkup_project hcp
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.andEX("hcp.`year`", "=", year);
cnd.andEX("hcp.`name`", "=", name);
cnd.desc("hcp.choiceTimeStart");
sql.setCondition(cnd);
return Result.success(healthCheckupProjectService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql));
}
/**
* 体检项目确认;业务筛选、数据读写和结果组装在本服务内完成。
* @param healthCheckupProject 体检项目及医院套餐明细
* @param deleteRowIds 待删除的套餐金额记录主键数组
* @param deleteSubjectIds 待删除的医院选项主键数组
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result doAdd(HealthCheckupProject healthCheckupProject,
String[] deleteRowIds,
String[] deleteSubjectIds) {
String projectId;
//如果是保存
if (StrUtil.isBlank(healthCheckupProject.getId())) {
healthCheckupProject.setYear(DateUtil.thisYear());
HealthCheckupProject checkupProject = healthCheckupProjectService.insertWith(healthCheckupProject, "healthCheckupProjectSubjects");
healthCheckupProject.getHealthCheckupProjectSubjects().forEach(v -> {
v.getSubjectMoneys().forEach(m -> {
m.setProjectId(checkupProject.getId());
m.setSubjectId(v.getId());
});
if (Lang.isNotEmpty(v.getSubjectMoneys())) {
healthCheckupProjectService.insert(v.getSubjectMoneys());
}
});
projectId = checkupProject.getId();
} else {
projectId = healthCheckupProject.getId();
//如果删除了医院
if (Lang.isNotEmpty(deleteSubjectIds)) {
healthCheckupProjectService.dao().clear(HealthCheckupProjectSubject.class, Cnd.where("id", "in", deleteSubjectIds));
healthCheckupProjectService.dao().clear(HealthCheckupProjectSubjectMoney.class, Cnd.where("subjectId", "in", deleteSubjectIds));
}
//如果删除了项目
if (Lang.isNotEmpty(deleteRowIds)) {
healthCheckupProjectService.dao().clear(HealthCheckupProjectSubjectMoney.class, Cnd.where("id", "in", deleteRowIds));
}
healthCheckupProjectService.dao().insertOrUpdate(healthCheckupProject.getHealthCheckupProjectSubjects());
healthCheckupProject.getHealthCheckupProjectSubjects().forEach(v -> {
v.setProjectId(projectId);
v.getSubjectMoneys().forEach(m -> {
m.setProjectId(projectId);
m.setSubjectId(v.getId());
});
if (Lang.isNotEmpty(v.getSubjectMoneys())) {
healthCheckupProjectService.insertOrUpdate(v.getSubjectMoneys());
}
});
healthCheckupProjectService.dao().insertOrUpdate(healthCheckupProject.getHealthCheckupProjectSubjects());
healthCheckupProjectService.update(healthCheckupProject);
}
// healthCheckupProjectService.dao().clear(HealthCheckupUnionConfirm.class, Cnd.where("projectId", "=", projectId));
// List<Sys_union> unionList = healthCheckupProjectService.dao().query(Sys_union.class, Cnd.NEW());
// List<HealthCheckupUnionConfirm> confirmList = new ArrayList<>();
// unionList.forEach(item -> {
// HealthCheckupUnionConfirm c = new HealthCheckupUnionConfirm();
// c.setProjectId(projectId);
// c.setUnionId(item.getId());
// c.setIsAudit(false);
// confirmList.add(c);
// });
// healthCheckupProjectService.dao().insert(confirmList);
Sys_home_activity sysHomeActivity = activityCultureService.dao().fetch(Sys_home_activity.class, Cnd.where("id", "=", healthCheckupProject.getId()));
if(ObjectUtil.isNotEmpty(sysHomeActivity)){
activityCultureService.dao().clear(Sys_home_activity.class, Cnd.where(Sys_home_activity::getId, "=", sysHomeActivity.getId()));
}
activityCultureService.insertOrUpdate(healthCheckupProject.covertToSysHomeActivity());
return Result.success();
}
/**
* 查询体检项目内容;业务筛选、数据读写和结果组装在本服务内完成。
* @param id 当前业务记录主键
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
public Result findOne(String id) {
return Result.success(healthCheckupProjectService.findOne(id));
}
/**
* 删除体检项目;业务筛选、数据读写和结果组装在本服务内完成。
* @param id 当前业务记录主键
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result doDelete(String id) {
healthCheckupProjectService.delete(id);
healthCheckupProjectService.dao().clear(HealthCheckupProjectSubject.class, Cnd.where("projectId", "=", id));
healthCheckupProjectService.dao().clear(HealthCheckupProjectSubjectMoney.class, Cnd.where("projectId", "=", id));
activityCultureService.dao().clear(Sys_home_activity.class, Cnd.where(Sys_home_activity::getId, "=", id));
return Result.success();
}
/**
* 按年份获取体检项目;业务筛选、数据读写和结果组装在本服务内完成。
* @param year 四位体检年度
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
public Result getHealthCheckupProject(Integer year) {
List<HealthCheckupProject> projectList = healthCheckupProjectService.query(Cnd.NEW().andEX("year", "=", year).desc("choiceTimeStart"));
return Result.success(projectList);
}
/**
* 创建体检名单;业务筛选、数据读写和结果组装在本服务内完成。
* @param healthCheckupProject 体检项目及医院套餐明细
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result createUserList(HealthCheckupProject healthCheckupProject) {
healthCheckupProjectService.addHealthCheckupUser(healthCheckupProject);
return Result.success();
}
/**
* 更新体检名单;业务筛选、数据读写和结果组装在本服务内完成。
* @param healthCheckupProject 体检项目及医院套餐明细
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result renewUserList(HealthCheckupProject healthCheckupProject) {
healthCheckupProjectService.renewHealthCheckupUser(healthCheckupProject);
return Result.success();
}
/**
* 重置体检名单;业务筛选、数据读写和结果组装在本服务内完成。
* @param healthCheckupProject 体检项目及医院套餐明细
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result resetUserList(HealthCheckupProject healthCheckupProject) {
//重置名单,清空已选择的用户记录
Sql sql = Sqls.create("select id,selectUserId from health_checkup_user_selection where projectId = @projectId").setParam("projectId", healthCheckupProject.getId());
List<NutMap> list = (List<NutMap>) Daos.query(healthCheckupProjectService.dao(), sql.toString(), Sqls.callback.maps());
List<String> userSelectionIds = list.stream().map(v -> v.getString("id")).collect(Collectors.toList());
List<String> userIds = list.stream().map(v -> v.getString("selectUserId")).collect(Collectors.toList());
healthCheckupProjectService.dao().clear(HealthCheckupUserSelection.class,
Cnd.NEW().and("selectUserId", "in", userIds)
.and("projectId", "=", healthCheckupProject.getId()));
healthCheckupProjectService.dao().clear(HealthCheckupUserCompanion.class, Cnd.where("userSelectionId", "in", userSelectionIds));
healthCheckupProjectService.dao().clear(HealthCheckupUser.class, Cnd.where("projectId", "=", healthCheckupProject.getId()));
healthCheckupProjectService.addHealthCheckupUser(healthCheckupProject);
return Result.success();
}
}
@@ -2,6 +2,7 @@ package com.budwk.app.zhgh.dayofficework.healthCheckup.service;
import com.budwk.app.base.service.BaseService; import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupProject; import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupProject;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupUserSelection;
public interface HealthCheckupProjectService extends BaseService<HealthCheckupProject> { public interface HealthCheckupProjectService extends BaseService<HealthCheckupProject> {
@@ -20,4 +21,10 @@ public interface HealthCheckupProjectService extends BaseService<HealthCheckupPr
* @param healthCheckupProject * @param healthCheckupProject
*/ */
void renewHealthCheckupUser(HealthCheckupProject healthCheckupProject); void renewHealthCheckupUser(HealthCheckupProject healthCheckupProject);
/**
* 获取用户上年度体检医院
* @param checkupUserSelection
*/
String findLastYearHospital(HealthCheckupUserSelection checkupUserSelection);
} }
@@ -0,0 +1,550 @@
package com.budwk.app.zhgh.dayofficework.healthCheckup.service;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.sms.SmsService;
import com.budwk.app.base.utils.CommonDownloadUtil;
import com.budwk.app.base.utils.ConditionGroupUtil;
import com.budwk.app.base.utils.ManyAddOrRenewUtil;
import com.budwk.app.sys.views.View_user;
import com.budwk.app.web.commons.base.Globals;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupProject;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupProjectSubject;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupProjectSubjectMoney;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupUserSelection;
import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupProjectService;
import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupSingleService;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import javax.servlet.http.HttpServletResponse;
import com.budwk.app.web.commons.auth.utils.AuthUtil;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.exception.BaseException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
/** 体检接口业务服务;HTTP 路由和权限校验保留在 controller。 */
@IocBean
public class HealthCheckupSingleApplicationService {
@Inject
private SmsService smsService;
@Inject
private HealthCheckupSingleService healthCheckupSingleService;
@Inject
private ManyAddOrRenewUtil manyAddOrRenewUtil;
@Inject
private HealthCheckupProjectService healthCheckupProjectService;
/**
* 首页查询;业务筛选、数据读写和结果组装在本服务内完成。
* @param projectId 当前体检项目主键
* @param unionId 所属分工会主键,可空时按接口范围处理
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
public Result pageData(String projectId,
String unionId) {
NutMap nutMap = healthCheckupSingleService.pageData(projectId, unionId);
return Result.success(nutMap);
}
/**
* 首页查询;业务筛选、数据读写和结果组装在本服务内完成。
* @param projectId 当前体检项目主键
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
public Result actualStatistics(String projectId) {
try {
return Result.success(healthCheckupSingleService.actualStatistics(projectId));
} catch (IllegalArgumentException e) {
return Result.error(e.getMessage());
}
}
/**
* 读取体检业务数据;业务筛选、数据读写和结果组装在本服务内完成。
* @param projectId 当前体检项目主键
* @param counts 总人数及各医院人数的 JSON 映射
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result saveActualStatistics(String projectId, String counts) {
try {
return Result.success(healthCheckupSingleService.saveActualStatistics(projectId, counts));
} catch (IllegalArgumentException e) {
return Result.error(e.getMessage());
}
}
/**
* 每个分工会领取人员/未领取人员;业务筛选、数据读写和结果组装在本服务内完成。
* @param page 分页及搜索参数
* @param isSelected 0 已选择,1 未选择
* @param projectId 当前体检项目主键
* @param unionId 所属分工会主键,可空时按接口范围处理
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
public Result receivePageData(PageForm page, String isSelected,
String projectId,
String unionId) {
List<NutMap> labelList = healthCheckupSingleService.receivePageDataColumns(projectId);
Pagination list = healthCheckupSingleService.receivePageData(page.getPageNumber(), page.getPageSize(), page.getSearchName(), page.getSearchKeyword(), projectId, unionId, isSelected);
return Result.success(NutMap.NEW().addv("list", list).addv("label", labelList));
}
/**
* 按医院导出当前项目全部已选教职工;不受页面分工会筛选影响。
* @param projectId 当前教职工体检项目ID
* @param response 输出ZIP附件,每个有报名人员的医院对应一个xlsx文件;无JSON返回值
*/
public void exportSelectedZip(String projectId, HttpServletResponse response) {
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
throw new BaseException("仅系统管理员或校工会管理员可导出全部已选名单");
}
if (Strings.isBlank(projectId)) throw new BaseException("请选择体检项目");
HealthCheckupProject project = healthCheckupProjectService.fetch(projectId);
if (project == null || !"jzg".equals(project.getHealthCheckupType())) {
throw new BaseException("请选择教职工体检项目");
}
// 以已选记录为查询起点,不包含尚未报名人员,也不因分工会为空而丢失报名记录。
Sql sql = Sqls.create("""
SELECT s.subjectId, h.optionName AS subjectName,
c.loginName, c.userName, c.sex,
COALESCE(c.age,TIMESTAMPDIFF(YEAR,u.birthday,CURDATE())) AS age,
c.phone AS mobile, c.card AS idCard,
COALESCE(d.name,c.personType) AS personType,
c.marriage, s.money, m.settlementMoney,
c.unitName, c.unionName, s.receiveAddress, c.isEmployed
FROM health_checkup_user_selection s
JOIN health_checkup_project_subject h ON h.id=s.subjectId AND h.projectId=s.projectId
LEFT JOIN health_checkup_user c ON c.projectId=s.projectId AND c.userId=s.selectUserId
LEFT JOIN sys_user u ON u.id=s.selectUserId
LEFT JOIN health_checkup_project_subject_money m ON m.id=s.subjectMoneyId AND m.subjectId=s.subjectId
LEFT JOIN sys_dict p ON p.code='USER_PERSON_TYPE'
LEFT JOIN sys_dict d ON d.parentId=p.id AND d.code=c.personType
WHERE s.projectId=@projectId
ORDER BY h.optionSort,h.id,c.unionName,c.unitName,c.loginName,s.id
""");
sql.setParam("projectId", projectId);
List<NutMap> rows = healthCheckupSingleService.listMap(sql);
if (rows.isEmpty()) throw new BaseException("当前项目暂无已选名单");
Map<String, List<NutMap>> hospitals = new LinkedHashMap<>();
rows.forEach(row -> hospitals.computeIfAbsent(row.getString("subjectId"), key -> new ArrayList<>()).add(row));
List<ExcelExportEntity> columns = new ArrayList<>();
columns.add(new ExcelExportEntity("工号", "loginName", 20));
columns.add(new ExcelExportEntity("姓名", "userName", 20));
columns.add(new ExcelExportEntity("性别", "sex", 20));
columns.add(new ExcelExportEntity("年龄", "age", 20));
columns.add(new ExcelExportEntity("手机号码", "mobile", 20));
columns.add(new ExcelExportEntity("身份证号", "idCard", 20));
columns.add(new ExcelExportEntity("人员类别", "personType", 20));
columns.add(new ExcelExportEntity("婚姻状况", "marriage", 20));
columns.add(new ExcelExportEntity("医院", "subjectName", 20));
columns.add(new ExcelExportEntity("套餐金额", "money", 20));
columns.add(new ExcelExportEntity("结算金额", "settlementMoney", 20));
columns.add(new ExcelExportEntity("部门", "unitName", 20));
columns.add(new ExcelExportEntity("分工会", "unionName", 20));
columns.add(new ExcelExportEntity("邮寄地址", "receiveAddress", 20));
columns.add(new ExcelExportEntity("是否自聘", "isEmployed", 20));
// 先完整生成压缩包再写响应,生成失败时不返回半截附件;各医院使用独立工作簿。
try (ByteArrayOutputStream bytes = new ByteArrayOutputStream()) {
try (ZipOutputStream zip = new ZipOutputStream(bytes, StandardCharsets.UTF_8)) {
int index = 1;
for (List<NutMap> hospitalRows : hospitals.values()) {
String hospital = hospitalRows.get(0).getString("subjectName");
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
exportParams.setSheetName("已选名单");
exportParams.setTitle(hospital + "已选名单");
// 序号避免同名医院产生重复ZIP条目;替换路径分隔符及文件名非法字符。
String safeName = Strings.sNull(hospital).replaceAll("[\\\\/:*?\"<>|\\p{Cntrl}]", "_");
if (safeName.length() > 80) safeName = safeName.substring(0, 80);
zip.putNextEntry(new ZipEntry((index++) + "_" + safeName + ".xlsx"));
try (Workbook workbook = ExcelExportUtil.exportExcel(exportParams, columns, hospitalRows)) {
workbook.write(zip);
}
zip.closeEntry();
}
}
CommonDownloadUtil.download(project.getName() + "_已选名单.zip", bytes.toByteArray(), response);
} catch (IOException e) {
throw new BaseException("已选名单ZIP生成失败,请重试");
}
}
/**
* 导出已选/未选人员名单;业务筛选、数据读写和结果组装在本服务内完成。
* @param projectId 当前体检项目主键
* @param unionId 所属分工会主键,可空时按接口范围处理
* @param year 四位体检年度
* @param flag 确认或取消、已选或未选的业务标志
* @param response 接收 Excel 文件流的 HTTP 响应
* 文件内容直接写入 response,不返回 JSON。
*/
public void exportReceiveDetail(String projectId,
String unionId,
Integer year,
boolean flag, HttpServletResponse response) {
List<ExcelExportEntity> entityList = new ArrayList<>() {{
add(new ExcelExportEntity("工号", "loginName", 20));
add(new ExcelExportEntity("姓名", "userName", 20));
add(new ExcelExportEntity("性别", "sex", 20));
add(new ExcelExportEntity("年龄", "age", 20));
add(new ExcelExportEntity("手机号码", "mobile", 20));
add(new ExcelExportEntity("身份证号", "idCard", 20));
add(new ExcelExportEntity("用户类型", "personType", 20));
add(new ExcelExportEntity("婚姻状况", "marriage", 20));
add(new ExcelExportEntity("医院", "subjectName", 20));
add(new ExcelExportEntity("套餐金额", "money", 20));
add(new ExcelExportEntity("结算金额", "settlementMoney", 20));
add(new ExcelExportEntity("部门", "unitName", 20));
add(new ExcelExportEntity("分工会", "unionName", 20));
add(new ExcelExportEntity("邮寄地址", "receiveAddress", 50));
add(new ExcelExportEntity("是否自聘", "isEmployed", 50));
}};
List<NutMap> list;
if (flag) {
//已选人员
list = healthCheckupSingleService.receivePageData(projectId, unionId, "0");
} else {
//未选人员
list = healthCheckupSingleService.receivePageData(projectId, unionId, "1");
}
//获取当前年
Calendar calendar = Calendar.getInstance();
int thisYear = calendar.get(Calendar.YEAR);
list.forEach(v -> {
int substring = 0;
if (Strings.isNotBlank(v.getString("birthday"))) {
substring = Integer.parseInt(v.getString("birthday").substring(0, 4));
} else if (Strings.isNotBlank(v.getString("idCard")) && v.getString("idCard").length() >= 10) {
substring = Integer.parseInt(v.getString("idCard").substring(6, 10));
}
v.put("age", thisYear - substring);
if(v.getString("projectName").contains("在职教职工")){
v.put("personType", "在职教职工");
} else if(v.getString("projectName").contains("校聘高知")){
v.put("personType", "校聘高知保健对象");
}
});
List<NutMap> list2 = list.stream().filter(v -> Strings.isNotBlank(v.getString("unionName"))).collect(Collectors.toList());
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
exportParams.setSheetName(year + "年教职工体检项目及地点统计表");
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, list2);
CommonDownloadUtil.download((flag ? year + "年教职工体检项目及地点统计表" : "未选名单") + ".xlsx", workbook, response);
}
/**
* 导出教职工家属体检登记表;业务筛选、数据读写和结果组装在本服务内完成。
* @param projectId 当前体检项目主键
* @param unionId 所属分工会主键,可空时按接口范围处理
* @param year 四位体检年度
* @param response 接收 Excel 文件流的 HTTP 响应
* 文件内容直接写入 response,不返回 JSON。
*/
public void exportUserCompanion(String projectId,
String unionId,
Integer year, HttpServletResponse response) {
Sql sql = Sqls.create("""
SELECT
u.username,
u.unitname unitName,
u.mobile,
hcuc.userName familyName,
hcuc.sex,
hcuc.marry isMarried,
hcuc.idCard,
hcc.campusName,
(
SELECT
GROUP_CONCAT( hcps.optionName )
FROM
health_checkup_user_selection hcus
LEFT JOIN `health_checkup_project_subject` hcps ON hcps.id = hcus.subjectId
WHERE
hcus.projectId = @projectId
AND hcus.selectUserId = u.id
) optionName
FROM
`health_checkup_user_companion` hcuc
LEFT JOIN `health_checkup_user_selection` hcus ON hcus.id = hcuc.userSelectionId
LEFT JOIN `health_checkup_campus` hcc ON hcc.id = hcus.campus
LEFT JOIN `vw_user` u ON u.id = hcus.selectUserId
LEFT JOIN `health_checkup_project` hcp ON hcp.id = hcus.projectId
$condition
""").setParam("projectId", projectId);
Cnd cnd = Cnd.NEW();
cnd.andEX("hcus.projectId", "=", projectId);
cnd.andEX("u.unionid", "=", unionId);
cnd.andEX("hcp.year", "=", year);
cnd.asc("u.unioncode");
sql.setCondition(cnd);
//家属信息表
List<NutMap> companionList = healthCheckupSingleService.listMap(sql);
for (int i = 0; i < companionList.size(); i++) {
companionList.get(i).put("index", i + 1);
}
List<ExcelExportEntity> entityList = new ArrayList<>() {{
add(new ExcelExportEntity("序号", "index", 20));
add(new ExcelExportEntity("教职工姓名", "username", 20));
add(new ExcelExportEntity("学院(部门)", "unitName", 20));
add(new ExcelExportEntity("手机", "mobile", 20));
add(new ExcelExportEntity("体检人姓名", "familyName", 20));
add(new ExcelExportEntity("性别", "sex", 20));
add(new ExcelExportEntity("婚否", "isMarried", 20));
add(new ExcelExportEntity("体检人身份证号", "idCard", 50));
add(new ExcelExportEntity("自选项目", "optionName", 50));
add(new ExcelExportEntity("自选院区", "campusName", 50));
}};
try {
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
exportParams.setTitle(year + "教职工家属体检登记表");
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, companionList);
CommonDownloadUtil.download(year + "教职工家属体检登记表.xlsx", workbook, response);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 管理员一键代选;业务筛选、数据读写和结果组装在本服务内完成。
* @param projectId 当前体检项目主键
* @param optionId 代选的医院选项主键
* @param campus 体检院区主键
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result doSelectByAdmin(String projectId, String optionId, String campus) {
Dao dao = healthCheckupSingleService.dao();
HealthCheckupProject project = dao.fetch(HealthCheckupProject.class, projectId);
Cnd cnd = Cnd.NEW();
Sql sql = Sqls.create("""
SELECT
u.id,
u.loginname loginName,
u.username userName,
u.sex,
u.birthday,
u.unitname unitName,
u.unionname unionName,
u.idcard idCard,
u.mobile
FROM
`activity_user_scope` aus
LEFT JOIN `vw_user` u ON u.id = aus.userId
$projectCnd $condition
""");
cnd.and("aus.groupId", "=", project.getActivityGroupId());
sql.setVar("projectCnd", "AND u.id NOT IN ( SELECT selectUserId FROM `health_checkup_user_selection` WHERE projectId = '" + projectId + "' AND selectUserId IS NOT NULL )");
cnd.groupBy("u.loginname");
sql.setCondition(cnd);
List<NutMap> mapList = healthCheckupSingleService.listMap(sql);
List<String> userIds = mapList.stream().map(v -> v.getString("id")).collect(Collectors.toList());
//题目id
List<HealthCheckupUserSelection> selections = userIds.stream().map(v -> {
HealthCheckupUserSelection selection = new HealthCheckupUserSelection();
selection.setProjectId(projectId);
selection.setSelectUserId(v);
selection.setCampus(campus);
selection.setSubjectId(optionId);
selection.setSelectTime(new Date());
return selection;
}).collect(Collectors.toList());
manyAddOrRenewUtil.asyncExecuteFastInsert(selections, null);
return Result.success();
}
/**
* 按上年补齐未选人员;业务筛选、数据读写和结果组装在本服务内完成。
* @param projectId 当前体检项目主键
* @param lastYearProjectId 上一年度体检项目主键
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public Result selectOptionByLastYear(String projectId, String lastYearProjectId) {
Dao dao = healthCheckupSingleService.dao();
//获取去年项目
HealthCheckupProject lastYearProject = dao.fetch(HealthCheckupProject.class, Cnd.where("id", "=", lastYearProjectId));
if (lastYearProject == null) {
return Result.error("请先创建去年的体检项目");
}
Cnd cnd = Cnd.NEW();
Sql sql = Sqls.create("""
SELECT
u.id
FROM
health_checkup_user hcu
LEFT JOIN `vw_user` u ON u.id = hcu.userId
$projectCnd $condition
""");
cnd.and("hcu.projectId", "=", projectId);
sql.setVar("projectCnd",
"AND u.id NOT IN ( SELECT selectUserId FROM `health_checkup_user_selection` WHERE projectId = '" + projectId + "' AND selectUserId IS NOT NULL )");
cnd.groupBy("u.loginname");
sql.setCondition(cnd);
List<NutMap> mapList = healthCheckupSingleService.listMap(sql);
if(CollectionUtil.isEmpty(mapList)) return Result.success();
List<String> userIds = mapList.stream().map(v -> v.getString("id")).filter(Strings::isNotBlank).toList();
//去年项目的人
Cnd aNew = Cnd.NEW();
aNew.and(HealthCheckupUserSelection::getProjectId, "=", lastYearProject.getId())
.and(HealthCheckupUserSelection::getSelectUserId, "in", userIds);
List<HealthCheckupUserSelection> lastYearSelectionList = dao.query(HealthCheckupUserSelection.class, aNew);
//去年项目下的医院
List<HealthCheckupProjectSubject> lastYearSubjectList = dao.query(HealthCheckupProjectSubject.class,
Cnd.where(HealthCheckupProjectSubject::getProjectId, "=", lastYearProject.getId()));
//今年项目下的医院
List<HealthCheckupProjectSubject> thisYearSubjectList = dao.query(HealthCheckupProjectSubject.class,
Cnd.where(HealthCheckupProjectSubject::getProjectId, "=", projectId));
List<HealthCheckupProjectSubjectMoney> thisYearSubjectMoneyList = dao.query(HealthCheckupProjectSubjectMoney.class,
Cnd.where(HealthCheckupProjectSubject::getProjectId, "=", projectId));
List<HealthCheckupUserSelection> selections = new ArrayList<>();
userIds.forEach(v -> {
//获取去年这个人选择的记录
HealthCheckupUserSelection userSelection = lastYearSelectionList.stream().filter(item -> item.getSelectUserId().equals(v)).findFirst().orElse(null);
if(ObjectUtil.isNotEmpty(userSelection)){
//去年这个人选择的选项是什么
HealthCheckupProjectSubject lastYearSubject = lastYearSubjectList.stream().filter(last -> last.getId().equals(userSelection.getSubjectId())).findFirst().orElse(null);
//今年项目下的选项
HealthCheckupProjectSubject thisYearSubject = thisYearSubjectList.stream().filter(thisYear -> thisYear.getOptionName().equals(lastYearSubject.getOptionName())).findFirst().orElse(null);
if (userSelection != null && thisYearSubject != null) {
//获取今年这个选项的收费
List<HealthCheckupProjectSubjectMoney> list = dao.query(HealthCheckupProjectSubjectMoney.class,
Cnd.where(HealthCheckupProjectSubjectMoney::getSubjectId, "=", thisYearSubject.getId()));
BigDecimal money = BigDecimal.valueOf(0.00);
String subjectMoneyId = null;
for (HealthCheckupProjectSubjectMoney subject : list) {
//找出这个人符合哪个项目
Cnd cndUser = Cnd.where("id", "=", v);
ConditionGroupUtil.applyConditionGroup(cndUser, subject.getMatchCnd());
int count = dao.count(View_user.class, cndUser);
if (count > 0) {
money = subject.getMoney();
subjectMoneyId = subject.getId();
break;
}
}
//如果有符合的就添加
if (subjectMoneyId != null) {
HealthCheckupUserSelection selection = new HealthCheckupUserSelection();
selection.setProjectId(projectId);
selection.setSelectUserId(v);
selection.setSubjectId(thisYearSubject.getId());
selection.setSubjectMoneyId(subjectMoneyId);
selection.setMoney(money);
selection.setSelectTime(new Date());
selections.add(selection);
}
}
} else {
//若去年未体检,则去本年校医院体检
HealthCheckupProjectSubject thisYearProjectSubject = thisYearSubjectList.stream()
.filter(e -> e.getOptionName().contains("校医院"))
.findFirst()
.orElse(null);
if(ObjectUtil.isNotEmpty(thisYearProjectSubject)) {
List<HealthCheckupProjectSubjectMoney> healthCheckupProjectSubjectMonies = thisYearSubjectMoneyList.stream()
.filter(e -> e.getSubjectId().equals(thisYearProjectSubject.getId()))
.collect(Collectors.toList());
if(CollectionUtil.isNotEmpty(healthCheckupProjectSubjectMonies)){
BigDecimal money = BigDecimal.valueOf(0.00);
String subjectMoneyId = null;
for (HealthCheckupProjectSubjectMoney subject : healthCheckupProjectSubjectMonies) {
//找出这个人符合哪个项目
Cnd cndUser = Cnd.where("id", "=", v);
ConditionGroupUtil.applyConditionGroup(cndUser, subject.getMatchCnd());
int count = dao.count(View_user.class, cndUser);
if (count > 0) {
money = subject.getMoney();
subjectMoneyId = subject.getId();
break;
}
}
//如果有符合的就添加
if (subjectMoneyId != null) {
HealthCheckupUserSelection selection = new HealthCheckupUserSelection();
selection.setProjectId(projectId);
selection.setSelectUserId(v);
selection.setSubjectId(thisYearProjectSubject.getId());
selection.setSubjectMoneyId(subjectMoneyId);
selection.setMoney(money);
selection.setSelectTime(new Date());
selections.add(selection);
}
}
}
}
});
dao.insert(selections);
return Result.success();
}
/**
* 给未选的人发送提醒;业务筛选、数据读写和结果组装在本服务内完成。
* @param projectId 当前体检项目主键
* @return Result;Result 的 code 为 0 表示成功,msg 为说明,data 为本接口业务数据。
*/
public Result msgNotSelect(String projectId) {
List<NutMap> userList = healthCheckupSingleService.receivePageData(projectId, null, "1");
if(CollectionUtil.isNotEmpty(userList)){
HealthCheckupProject project = healthCheckupProjectService.dao().fetch(HealthCheckupProject.class, Cnd.where("id", "=", projectId));
String smsMessage = StringUtils.defaultIfBlank(
project.getSmsMessage(),
"系统显示您本年度体检医院信息尚未维护,请尽快登录小程序完成体检医院选择及个人信息确认,以免影响正常体检安排。");
List<String> loginNameList = userList.stream()
.map(e -> e.getString("loginName"))
.collect(Collectors.toList());
// 使用当前项目的消息服务,保留项目标题、提醒正文和手机端入口。
smsService.massSend(loginNameList, project.getName(), smsMessage,
Globals.AppDomain + "/platform/healthCheckup/h5/list");
return Result.success("提醒成功");
} else {
return Result.success("不存在未体检人员");
}
}
}
@@ -9,6 +9,21 @@ import java.util.List;
public interface HealthCheckupSingleService extends BaseService<HealthCheckupProject> { public interface HealthCheckupSingleService extends BaseService<HealthCheckupProject> {
/**
* 查询项目实际人数,不按工会筛选。
* @param projectId 体检项目ID
* @return NutMap:__total__为本次体检人数,其他键为医院选项ID,值为人数;未录入项不返回
*/
NutMap actualStatistics(String projectId);
/**
* 保存当前项目整行实际人数。
* @param projectId 体检项目ID
* @param counts JSON对象,__total__及当前项目全部医院ID为键,非负整数为值
* @return 保存后的实际人数映射
*/
NutMap saveActualStatistics(String projectId, String counts);
/** /**
* 分页查询 * 分页查询
* *
@@ -0,0 +1,129 @@
package com.budwk.app.zhgh.dayofficework.healthCheckup.service.impl;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.sys.models.Sys_union;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupFeedback;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupProject;
import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupFeedbackService;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
import java.util.ArrayList;
import java.util.List;
@IocBean(args = {"refer:dao"})
public class HealthCheckupFeedbackServiceImpl extends BaseServiceImpl<HealthCheckupFeedback> implements HealthCheckupFeedbackService {
public HealthCheckupFeedbackServiceImpl(Dao dao) {
super(dao);
}
@Override
public List<NutMap> listFeedback(String year, String projectId, String unionId) {
Cnd cnd = Cnd.NEW();
cnd.and("year", "=", year)
.and("projectId", "=", projectId)
.and("unionId", "=", unionId)
.desc("createdAt");
List<HealthCheckupFeedback> feedbackList = query(cnd);
List<NutMap> result = new ArrayList<>();
for (HealthCheckupFeedback feedback : feedbackList) {
result.add(NutMap.NEW()
.addv("id", feedback.getId())
.addv("year", feedback.getYear())
.addv("projectName", feedback.getProjectName())
.addv("unionName", feedback.getUnionName())
.addv("feedbackInfo", feedback.getFeedbackInfo())
.addv("createdBy", feedback.getCreatedBy())
.addv("createdAt", feedback.getCreatedAt()));
}
return result;
}
@Override
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public NutMap saveFeedback(String year, String projectId, String unionId, String feedbackInfo) {
if (StrUtil.isBlank(year) || StrUtil.isBlank(projectId) || StrUtil.isBlank(unionId)) {
return NutMap.NEW().addv("code", 1).addv("msg", "请选择年度、体检项目、分工会后再录入反馈");
}
if (StrUtil.isBlank(feedbackInfo)) {
return NutMap.NEW().addv("code", 1).addv("msg", "请输入反馈信息");
}
// 保存前先根据页面选中的条件反查项目和分工会,确保反馈和主列表条件强关联。
HealthCheckupProject project = dao().fetch(HealthCheckupProject.class, projectId);
if (project == null) {
return NutMap.NEW().addv("code", 1).addv("msg", "当前体检项目不存在,请重新选择");
}
Sys_union union = dao().fetch(Sys_union.class, unionId);
if (union == null) {
return NutMap.NEW().addv("code", 1).addv("msg", "当前分工会不存在,请重新选择");
}
HealthCheckupFeedback feedback = new HealthCheckupFeedback();
feedback.setYear(year);
feedback.setProjectId(projectId);
feedback.setProjectName(project.getName());
feedback.setUnionId(unionId);
feedback.setUnionName(union.getName());
feedback.setFeedbackInfo(feedbackInfo);
insert(feedback);
return NutMap.NEW().addv("code", 0).addv("msg", "保存成功");
}
@Override
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public NutMap deleteFeedback(String id) {
if (StrUtil.isBlank(id)) {
return NutMap.NEW().addv("code", 1).addv("msg", "反馈ID不能为空");
}
HealthCheckupFeedback feedback = fetch(id);
if (feedback == null) {
return NutMap.NEW().addv("code", 1).addv("msg", "反馈记录不存在");
}
delete(id);
return NutMap.NEW().addv("code", 0).addv("msg", "删除成功");
}
@Override
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public NutMap deleteFeedbackBatch(String[] ids) {
if (ids == null || ids.length == 0) {
return NutMap.NEW().addv("code", 1).addv("msg", "请选择需要删除的反馈");
}
Cnd cnd = Cnd.NEW();
cnd.and("id", "in", ids);
clear(cnd);
return NutMap.NEW().addv("code", 0).addv("msg", "批量删除成功");
}
@Override
public Pagination listFeedbackPage(Integer pageNumber, Integer pageSize, String year, String projectId, String unionId) {
Cnd cnd = Cnd.NEW();
cnd.andEX("hcf.year", "=", year);
cnd.andEX("hcf.projectId", "=", projectId);
cnd.andEX("hcf.unionId", "=", unionId);
cnd.desc("hcf.createdAt");
Sql sql = Sqls.create("""
SELECT
hcf.id,
hcf.year,
hcf.projectName,
hcf.unionName,
hcf.feedbackInfo,
hcf.createdAt,
su.username AS createdByName
FROM health_checkup_feedback hcf
LEFT JOIN sys_user su ON su.id = hcf.createdBy
$condition
""");
sql.setCondition(cnd);
return listPageMap(pageNumber, pageSize, sql);
}
}
@@ -0,0 +1,60 @@
package com.budwk.app.zhgh.dayofficework.healthCheckup.service.impl;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupUser;
import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupPersonConfirmStatisticsService;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.IocBean;
/**
* @ClassName HealthCheckupPersonConfirmStatisticsServiceImpl
* @Description 工会人员确认情况统计实现
* @Author Codex
* @Date 2026/4/28
*/
@IocBean(args = {"refer:dao"})
public class HealthCheckupPersonConfirmStatisticsServiceImpl extends BaseServiceImpl<HealthCheckupUser> implements HealthCheckupPersonConfirmStatisticsService {
public HealthCheckupPersonConfirmStatisticsServiceImpl(Dao dao) {
super(dao);
}
@Override
public Pagination personConfirmPageData(Integer pageNumber, Integer pageSize, Integer year, String projectId, String unionId) {
// 统计以系统工会为主表,保证未报名的工会也会显示在列表中。
Sql sql = Sqls.create("""
SELECT
su.id AS unionId,
su.name AS unionName,
COUNT(CASE WHEN hcp.id IS NOT NULL THEN hcu.id END) AS totalCount,
SUM(CASE WHEN hcp.id IS NOT NULL AND hcu.isAudit = '1' THEN 1 ELSE 0 END) AS confirmedCount,
SUM(CASE WHEN hcp.id IS NOT NULL AND hcu.id IS NOT NULL AND (hcu.isAudit IS NULL OR hcu.isAudit <> '1') THEN 1 ELSE 0 END) AS unconfirmedCount,
CASE
WHEN COUNT(CASE WHEN hcp.id IS NOT NULL THEN hcu.id END) > 0
AND COUNT(CASE WHEN hcp.id IS NOT NULL THEN hcu.id END) = SUM(CASE WHEN hcp.id IS NOT NULL AND hcu.isAudit = '1' THEN 1 ELSE 0 END) THEN '已完成'
ELSE '未完成'
END AS completeStatus
FROM sys_union su
LEFT JOIN health_checkup_user hcu ON hcu.unionId = su.id
AND hcu.delFlag = 0
AND hcu.projectId = @projectId
LEFT JOIN health_checkup_project hcp ON hcp.id = hcu.projectId
AND hcp.delFlag = 0
AND hcp.year = @year
$condition
""").setParam("projectId", projectId).setParam("year", year);
Cnd cnd = Cnd.NEW();
cnd.andEX("su.id", "=", unionId);
cnd.groupBy("su.id,su.name");
cnd.asc("completeStatus");
cnd.asc("su.unionCode");
sql.setCondition(cnd);
// isAudit 存在于 health_checkup_user 中,只要还有未确认人员,该工会状态就显示未完成。
// 排序按报名总人数倒序,人数相同时再按工会编码升序,保证列表顺序稳定。
return listPageMap(pageNumber, pageSize, sql);
}
}
@@ -1,8 +1,12 @@
package com.budwk.app.zhgh.dayofficework.healthCheckup.service.impl; package com.budwk.app.zhgh.dayofficework.healthCheckup.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.budwk.app.base.service.impl.BaseServiceImpl; import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.base.utils.ConditionGroupUtil;
import com.budwk.app.base.utils.ManyAddOrRenewUtil; import com.budwk.app.base.utils.ManyAddOrRenewUtil;
import com.budwk.app.sys.views.View_user; import com.budwk.app.sys.views.View_user;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.activity.basic.models.ActivityUserScope; import com.budwk.app.zhgh.activity.basic.models.ActivityUserScope;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.*; import com.budwk.app.zhgh.dayofficework.healthCheckup.model.*;
import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupProjectService; import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupProjectService;
@@ -12,6 +16,7 @@ import org.nutz.dao.Dao;
import org.nutz.dao.Sqls; import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql; import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.Daos; import org.nutz.dao.util.Daos;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.ioc.aop.Aop; import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
@@ -19,8 +24,8 @@ import org.nutz.lang.Strings;
import org.nutz.lang.random.R; import org.nutz.lang.random.R;
import org.nutz.lang.util.NutMap; import org.nutz.lang.util.NutMap;
import java.util.List; import java.time.LocalDate;
import java.util.Set; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@@ -47,13 +52,14 @@ public class HealthCheckupProjectServiceImpl extends BaseServiceImpl<HealthCheck
} }
HealthCheckupProject project = fetchLinks(fetch(id), "healthCheckupProjectSubjects", Cnd.NEW().asc("optionSort")); HealthCheckupProject project = fetchLinks(fetch(id), "healthCheckupProjectSubjects", Cnd.NEW().asc("optionSort"));
project.getHealthCheckupProjectSubjects().forEach(v -> { project.getHealthCheckupProjectSubjects().forEach(v -> {
v.setSubjectMoneys(dao().query(HealthCheckupProjectSubjectMoney.class, Cnd.where("subjectId", "=", v.getId()))); v.setSubjectMoneys(dao().query(HealthCheckupProjectSubjectMoney.class, Cnd.where("subjectId", "=", v.getId()).asc("serialNumber")));
}); });
return project; return project;
} }
@Override @Override
@org.nutz.ioc.aop.Aop(org.nutz.aop.interceptor.ioc.TransAop.READ_COMMITTED)
public void addHealthCheckupUser(HealthCheckupProject healthCheckupProject) { public void addHealthCheckupUser(HealthCheckupProject healthCheckupProject) {
List<HealthCheckupUser> needAddUsers = getHealthCheckupUserListByProject(healthCheckupProject); List<HealthCheckupUser> needAddUsers = getHealthCheckupUserListByProject(healthCheckupProject);
manyAddOrRenewUtil.asyncExecuteFastInsert(needAddUsers, null); manyAddOrRenewUtil.asyncExecuteFastInsert(needAddUsers, null);
@@ -86,12 +92,29 @@ public class HealthCheckupProjectServiceImpl extends BaseServiceImpl<HealthCheck
.filter(v -> !sourceSelectionUserIds.contains(v.getUserId())) .filter(v -> !sourceSelectionUserIds.contains(v.getUserId()))
.collect(Collectors.toList()); .collect(Collectors.toList());
List<String> userSelectionIds = userList.stream().filter(needDeleteUserIds::contains).map(HealthCheckupUser::getId).collect(Collectors.toList()); // 更新名单仅清理当前项目,并使用真实选择记录主键清理家属,不能影响其他年度。
dao().clear(HealthCheckupUser.class, Cnd.where("userId", "in", needDeleteUserIds)); if (!needDeleteUserIds.isEmpty()) {
dao().clear(HealthCheckupUserSelection.class, Cnd.where("selectUserId", "in", needDeleteUserIds)); List<HealthCheckupUserSelection> removed = dao().query(HealthCheckupUserSelection.class,
dao().clear(HealthCheckupUserCompanion.class, Cnd.where("userSelectionId", "in", userSelectionIds)); Cnd.where("projectId", "=", healthCheckupProject.getId()).and("selectUserId", "in", needDeleteUserIds));
List<String> selectionIds = removed.stream().map(HealthCheckupUserSelection::getId).collect(Collectors.toList());
if (!selectionIds.isEmpty()) {
dao().clear(HealthCheckupUserCompanion.class, Cnd.where("userSelectionId", "in", selectionIds));
}
dao().clear(HealthCheckupUserSelection.class, Cnd.where("projectId", "=", healthCheckupProject.getId()).and("selectUserId", "in", needDeleteUserIds));
dao().clear(HealthCheckupUser.class, Cnd.where("projectId", "=", healthCheckupProject.getId()).and("userId", "in", needDeleteUserIds));
}
manyAddOrRenewUtil.asyncExecuteFastInsert(needInsertSelectionUsers, null); manyAddOrRenewUtil.asyncExecuteFastInsert(needInsertSelectionUsers, null);
// Sql updateSql = Sqls.create("""
// update health_checkup_user cu
// left join health_checkup_project p on cu.projectId=p.id
// left join sys_user u on cu.userId=u.id
// set cu.phone=if(cu.phone is null,u.mobile,cu.phone),cu.card=u.idCard,cu.marriage=u.marriage
// ,cu.personType=(case when p.name like '%在职教职工%' then '在职教职工' when p.name like '%校聘高知%' then '校聘高知保健对象' else '' end)
// where cu.projectId=@projectId2 and cu.confirmStatus!='1'
// """);
// updateSql.setParam("projectId2", healthCheckupProject.getId());
// dao().execute(updateSql);
} }
@@ -108,6 +131,11 @@ public class HealthCheckupProjectServiceImpl extends BaseServiceImpl<HealthCheck
user.setLoginName(v.getLoginname()); user.setLoginName(v.getLoginname());
user.setUserName(v.getUsername()); user.setUserName(v.getUsername());
user.setSex(v.getSex()); user.setSex(v.getSex());
// 名单生成时带入当前人员档案,手机端只读回显并据此校验报名资格。
user.setPhone(v.getMobile());
user.setCard(v.getIdCard());
user.setMarriage(v.getMarriage());
user.setPersonType(v.getPersonType());
user.setUnitId(v.getUnitId()); user.setUnitId(v.getUnitId());
user.setUnitName(v.getUnitName()); user.setUnitName(v.getUnitName());
user.setUnionId(v.getUnionId()); user.setUnionId(v.getUnionId());
@@ -115,4 +143,35 @@ public class HealthCheckupProjectServiceImpl extends BaseServiceImpl<HealthCheck
return user; return user;
}).collect(Collectors.toList()); }).collect(Collectors.toList());
} }
/**
* 获取上年度体检医院
* @param healthCheckupUserSelection
* @return
*/
public String findLastYearHospital(HealthCheckupUserSelection healthCheckupUserSelection){
Date selectTime = new Date();
if(ObjectUtil.isNotEmpty(selectTime)) {
Calendar instance = Calendar.getInstance();
instance.setTime(selectTime);
int year = instance.get(Calendar.YEAR);
LocalDate start = LocalDate.of(year - 1, 1, 1);
LocalDate end = LocalDate.of(year - 1, 12, 31);
Cnd lastYearCndSelection = Cnd.NEW();
lastYearCndSelection.and("selectUserId","=",healthCheckupUserSelection.getSelectUserId());
lastYearCndSelection.and("selectTime", ">=", start.toString()).and("selectTime", "<=", end.toString());
lastYearCndSelection.where().andNotIsNull("selectTime");
lastYearCndSelection.desc("selectTime");
List<HealthCheckupUserSelection> lastYearSelections = dao().query(HealthCheckupUserSelection.class, lastYearCndSelection);
if(CollectionUtil.isNotEmpty(lastYearSelections)) {
Cnd cnd = Cnd.NEW();
cnd.and("id","=",lastYearSelections.get(0).getSubjectId());
HealthCheckupProjectSubject projectSubject = dao().fetch(HealthCheckupProjectSubject.class, cnd);
if(ObjectUtil.isNotEmpty(projectSubject)) {
return projectSubject.getOptionName();
}
}
}
return null;
}
} }
@@ -1,11 +1,21 @@
package com.budwk.app.zhgh.dayofficework.healthCheckup.service.impl; package com.budwk.app.zhgh.dayofficework.healthCheckup.service.impl;
import com.budwk.app.base.page.Pagination; import com.budwk.app.base.page.Pagination;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupActualStatistics;
import com.budwk.app.web.commons.auth.utils.AuthUtil;
import com.budwk.app.base.constant.RoleConstant;
import org.nutz.ioc.aop.Aop;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.json.Json;
import java.util.LinkedHashSet;
import java.util.Set;
import com.budwk.app.base.service.impl.BaseServiceImpl; import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.base.utils.StringUtil;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupProject; import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupProject;
import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupProjectSubject; import com.budwk.app.zhgh.dayofficework.healthCheckup.model.HealthCheckupProjectSubject;
import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupProjectService; import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupProjectService;
import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupSingleService; import com.budwk.app.zhgh.dayofficework.healthCheckup.service.HealthCheckupSingleService;
import org.apache.commons.lang3.StringUtils;
import org.nutz.dao.Cnd; import org.nutz.dao.Cnd;
import org.nutz.dao.Dao; import org.nutz.dao.Dao;
import org.nutz.dao.Sqls; import org.nutz.dao.Sqls;
@@ -29,6 +39,81 @@ public class HealthCheckupSingleServiceImpl extends BaseServiceImpl<HealthChecku
@Inject @Inject
private HealthCheckupProjectService healthCheckupProjectService; private HealthCheckupProjectService healthCheckupProjectService;
/** {@inheritDoc} */
@Override
public NutMap actualStatistics(String projectId) {
if (Strings.isBlank(projectId) || dao().fetch(HealthCheckupProject.class, projectId) == null) {
throw new IllegalArgumentException("请选择有效的体检项目");
}
NutMap result = NutMap.NEW();
dao().query(HealthCheckupActualStatistics.class, Cnd.where("projectId", "=", projectId))
.forEach(item -> result.put(item.getSubjectId(), item.getActualCount()));
return result;
}
/** {@inheritDoc} */
@Override
@Aop(TransAop.READ_COMMITTED)
public NutMap saveActualStatistics(String projectId, String counts) {
// 实际人数属于整个项目,分工会查看权限不能用于覆盖项目级统计。
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
throw new IllegalArgumentException("仅系统管理员或校工会管理员可维护实际体检人数");
}
actualStatistics(projectId);
NutMap values;
try {
values = Json.fromJson(NutMap.class, counts);
} catch (Exception e) {
throw new IllegalArgumentException("实际人数格式错误");
}
Set<String> keys = new LinkedHashSet<>();
keys.add("__total__");
dao().query(HealthCheckupProjectSubject.class, Cnd.where("projectId", "=", projectId))
.forEach(subject -> keys.add(subject.getId()));
// 要求整行提交且医院仍属于当前项目,防止跨项目写入或医院变更后漏存。
if (values == null || !keys.equals(values.keySet())) {
throw new IllegalArgumentException("医院选项已变化或人数未填全,请刷新后重新录入");
}
for (String key : keys) {
Object value = values.get(key);
if (value == null || !value.toString().matches("[0-9]+")) {
throw new IllegalArgumentException("人数必须为非负整数");
}
try {
values.put(key, Integer.valueOf(value.toString()));
} catch (NumberFormatException e) {
throw new IllegalArgumentException("人数超出允许范围");
}
}
// 在任何写入之前校验医院合计;用long累加,避免多个合法整数相加溢出。
long hospitalTotal = 0L;
for (String key : keys) {
if (!"__total__".equals(key)) {
hospitalTotal += values.getInt(key);
}
}
if (hospitalTotal > values.getInt("__total__")) {
throw new IllegalArgumentException("各医院人数合计不能大于本次体检人数");
}
// 校验整行通过后统一保存,总人数允许大于医院合计。
for (String key : keys) {
HealthCheckupActualStatistics item = dao().fetch(HealthCheckupActualStatistics.class,
Cnd.where("projectId", "=", projectId).and("subjectId", "=", key));
if (item == null) {
item = new HealthCheckupActualStatistics();
item.setProjectId(projectId);
item.setSubjectId(key);
item.setActualCount(values.getInt(key));
dao().insert(item);
} else {
item.setActualCount(values.getInt(key));
dao().update(item);
}
}
return values;
}
@Override @Override
public NutMap pageData(String projectId, String unionId) { public NutMap pageData(String projectId, String unionId) {
HealthCheckupProject project = healthCheckupProjectService.findOne(projectId); HealthCheckupProject project = healthCheckupProjectService.findOne(projectId);
@@ -47,6 +132,7 @@ public class HealthCheckupSingleServiceImpl extends BaseServiceImpl<HealthChecku
sql.setCondition(cnd); sql.setCondition(cnd);
//分工会参加体检人数汇总 //分工会参加体检人数汇总
List<NutMap> healthCheckupList = listMap(sql); List<NutMap> healthCheckupList = listMap(sql);
//该体检项目下的套餐 //该体检项目下的套餐
List<HealthCheckupProjectSubject> subjectList = project.getHealthCheckupProjectSubjects(); List<HealthCheckupProjectSubject> subjectList = project.getHealthCheckupProjectSubjects();
@@ -54,9 +140,12 @@ public class HealthCheckupSingleServiceImpl extends BaseServiceImpl<HealthChecku
List<NutMap> userSelectList = this.getUserSelectionByProjectId(projectId); List<NutMap> userSelectList = this.getUserSelectionByProjectId(projectId);
for (NutMap healthCheckup : healthCheckupList) { for (NutMap healthCheckup : healthCheckupList) {
List<NutMap> thisUnionSelectList = userSelectList.stream().filter(x -> List<NutMap> thisUnionSelectList = userSelectList.stream()
x.getString("unionId").equals(healthCheckup.getString("id")) && .filter(x ->
x.getString("projectId").equals(projectId)).collect(Collectors.toList()); x.getString("unionId").equals(healthCheckup.getString("id"))
&& x.getString("projectId").equals(projectId)
)
.collect(Collectors.toList());
subjectList.forEach(o -> { subjectList.forEach(o -> {
//每一项选择的人数 //每一项选择的人数
@@ -121,7 +210,6 @@ public class HealthCheckupSingleServiceImpl extends BaseServiceImpl<HealthChecku
return listMap(sql); return listMap(sql);
} }
@Override @Override
public List<NutMap> receivePageDataColumns(String projectId) { public List<NutMap> receivePageDataColumns(String projectId) {
List<NutMap> labelList = new ArrayList<>(); List<NutMap> labelList = new ArrayList<>();
@@ -210,16 +298,17 @@ public class HealthCheckupSingleServiceImpl extends BaseServiceImpl<HealthChecku
u.username AS userName, u.username AS userName,
u.sex, u.sex,
u.birthday, u.birthday,
u.personType, hcu.personType,
u.unitName, u.unitName,
u.unitCode, u.unitCode,
u.marriage, hcu.marriage,
u.unionName, hcu.unionName,
u.idCard, hcu.phone as mobile,
u.mobile, hcu.card as idCard,
hcps.optionName subjectName, hcps.optionName subjectName,
hcus.receiveAddress,
hcc.campusName, hcc.campusName,
hcpsm.money,
hcpsm.settlementMoney,
( (
SELECT SELECT
GROUP_CONCAT( hcps.optionName ) GROUP_CONCAT( hcps.optionName )
@@ -229,13 +318,17 @@ public class HealthCheckupSingleServiceImpl extends BaseServiceImpl<HealthChecku
WHERE WHERE
hcus.projectId = @projectId hcus.projectId = @projectId
AND hcus.selectUserId = u.id AND hcus.selectUserId = u.id
) optionName ) optionName,
hcus.receiveAddress,
hcp.name projectName
FROM FROM
`health_checkup_user_selection` hcus `health_checkup_user_selection` hcus
LEFT JOIN `vw_user` u ON u.id = hcus.selectUserId LEFT JOIN `vw_user` u ON u.id = hcus.selectUserId
LEFT JOIN `health_checkup_user` hcu ON hcu.userId = hcus.selectUserId and hcu.projectId=@projectId LEFT JOIN `health_checkup_user` hcu ON hcu.userId = hcus.selectUserId and hcu.projectId=@projectId
LEFT JOIN `health_checkup_project_subject` hcps ON hcps.id = hcus.subjectId LEFT JOIN `health_checkup_project_subject` hcps ON hcps.id = hcus.subjectId
LEFT JOIN `health_checkup_project_subject_money` hcpsm ON hcpsm.projectId = @projectId and hcpsm.subjectId=hcps.id and hcus.subjectMoneyId=hcpsm.id
LEFT JOIN `health_checkup_campus` hcc ON hcc.id = hcus.campus LEFT JOIN `health_checkup_campus` hcc ON hcc.id = hcus.campus
LEFT JOIN `health_checkup_project` hcp ON hcp.id = hcu.projectId
$condition $condition
""").setParam("projectId", projectId); """).setParam("projectId", projectId);
cnd.and("hcus.projectId", "=", projectId); cnd.and("hcus.projectId", "=", projectId);
@@ -253,10 +346,12 @@ public class HealthCheckupSingleServiceImpl extends BaseServiceImpl<HealthChecku
hcu.unitName, hcu.unitName,
hcu.unionName, hcu.unionName,
u.idcard idCard, u.idcard idCard,
u.mobile u.mobile,
hcp.name projectName
FROM FROM
`health_checkup_user` hcu `health_checkup_user` hcu
LEFT JOIN `vw_user` u ON u.id = hcu.userId LEFT JOIN `vw_user` u ON u.id = hcu.userId
LEFT JOIN `health_checkup_project` hcp ON hcp.id = hcu.projectId
$condition $condition
"""); """);
sql.setVar("projectCnd", projectId); sql.setVar("projectCnd", projectId);
@@ -22,4 +22,10 @@ public class HealthCheckupImportTemp extends ExcelImportError {
@ExcelProperty("姓名") @ExcelProperty("姓名")
private String userName; private String userName;
@ExcelProperty("手机号")
private String phone;
@ExcelProperty("体检报告")
private String medicalExamination;
} }
@@ -70,12 +70,14 @@ const initTableMixins = {
pageData(data = null) { pageData(data = null) {
const address = this.pageDataUrl ? this.pageDataUrl : loc() + "/pageData" const address = this.pageDataUrl ? this.pageDataUrl : loc() + "/pageData"
this.tableLoading = true this.tableLoading = true
this.$axios.post(address, data ? data : this.pageForm).then((res) => { return this.$axios.post(address, data ? data : this.pageForm).then((res) => {
this.tableLoading = false
if (res.code === 0) { if (res.code === 0) {
this.tableData = res.data.list this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount this.pageForm.totalCount = res.data.totalCount
} }
}).finally(() => {
// 查询失败也释放表格遮罩,供体检等复用此 mixin 的页面统一处理。
this.tableLoading = false
}) })
}, },
notifySuccess(msg) { notifySuccess(msg) {
@@ -0,0 +1,126 @@
/**
* H5 弹框历史管理:一层可见弹框对应一条历史;关闭和跳转均等待历史回退完成。
* 页面通过 healthCheckupHistory 显式接入,其他业务页保持现有导航行为。
*/
(() => {
const entries = [];
let pending = null;
let root = null;
let sequence = 0;
let syncing = false;
const marker = '__h5Overlay';
const session = Date.now() + '-' + Math.random();
const closeEntries = (depth) => {
syncing = true;
while (entries.length > depth) {
const entry = entries.pop();
entry.close();
}
syncing = false;
};
const backTo = (depth) => {
if (pending) return pending.promise.then(() => backTo(depth));
const count = entries.length - depth;
if (count <= 0) return Promise.resolve();
let resolve;
const promise = new Promise(done => { resolve = done; });
pending = {promise, resolve};
window.history.go(-count);
return promise;
};
const manager = {
// key 标识具体弹框;close 同步关闭其 UI;返回 Promise 在历史状态稳定后结束。
open(key, close) {
if (pending) return pending.promise.then(() => manager.open(key, close));
if (entries.some(entry => entry.key === key)) return Promise.resolve();
entries.push({key, close});
const state = Object.assign({}, window.history.state || {});
state[marker] = {session, depth: entries.length};
window.history.pushState(state, '', window.location.href);
return Promise.resolve();
},
close(key) {
if (syncing) return Promise.resolve();
const index = entries.findIndex(entry => entry.key === key);
// 下层弹框主动关闭时一并清理其上方弹框,防止留下孤立历史。
return index < 0 ? Promise.resolve() : backTo(index);
},
clear() { return backTo(0); },
back() {
return entries.length ? backTo(entries.length - 1) : Promise.resolve().then(() => historyBack());
}
};
window.H5PopupHistory = manager;
// 捕获阶段消费弹框历史,避免 jquery.pjax 把同页历史当成业务页面跳转。
window.addEventListener('popstate', event => {
const state = event.state && event.state[marker];
if (!entries.length && !pending && !state) return;
event.stopImmediatePropagation();
const depth = state && state.session === session ? Math.min(state.depth, entries.length) : 0;
closeEntries(depth);
const waiting = pending;
pending = null;
if (waiting) waiting.resolve();
// 前进到已关闭弹框的历史时不重新打开;去掉旧标记,保持页面状态一致。
if (state && !entries.length) {
const clean = Object.assign({}, event.state);
delete clean[marker];
window.history.replaceState(clean, '', window.location.href);
}
}, true);
Vue.mixin({
created() {
if (this.$options.healthCheckupHistory) root = this;
if (!this.$root.$options.healthCheckupHistory) return;
const name = (this.$options.name || '').toLowerCase().replace(/-/g, '');
if (!['vanpopup', 'vandialog'].includes(name)) return;
// 只登记最外层弹框,避免 Dialog 内部的 Popup 重复增加历史。
let parent = this.$parent;
while (parent && parent !== this.$root) {
const parentName = (parent.$options.name || '').toLowerCase().replace(/-/g, '');
if (['vanpopup', 'vandialog'].includes(parentName)) return;
parent = parent.$parent;
}
const key = 'component-' + (++sequence);
this._overlayKey = key;
this._unwatchOverlay = this.$watch('value', value => {
if (value) {
manager.open(key, () => this.$emit('input', false)).then(() => {
if (!this.value || this._isDestroyed) manager.close(key);
});
} else manager.close(key);
}, {immediate: true});
},
beforeDestroy() {
if (this._unwatchOverlay) this._unwatchOverlay();
if (this._overlayKey) manager.close(this._overlayKey);
if (root === this) {
root = null;
manager.clear();
}
}
});
// PJAX 替换 DOM 不会自动销毁 Vue 实例;主动注销页面及其弹框监听。
$(document).on('pjax:beforeReplace.healthCheckupHistory', () => {
if (root && !root._isDestroyed) root.$destroy();
});
window.healthCheckupHistoryMixin = {
methods: {
historyBack() { return manager.back(); },
navigateHealthCheckup(url, data = null) {
return manager.clear().then(() => pjaxReplace(url, data));
},
// options 是 Vant 确认框配置;只在用户确认且弹框历史已清理后 resolve。
$healthConfirm(options) {
const key = 'confirm-' + (++sequence);
return manager.open(key, () => vant.Dialog.close()).then(() => {
return vant.Dialog.confirm(options).then(value => {
return manager.close(key).then(() => value);
}, error => {
return manager.close(key).then(() => Promise.reject(error));
});
});
}
}
};
})();
@@ -76,6 +76,7 @@
></script> ></script>
<script src="https://map.qq.com/api/gljs?v=2.exp&key=MLLBZ-GQECI-ASXG7-5GNOZ-XW2OF-H5BVH"></script> <script src="https://map.qq.com/api/gljs?v=2.exp&key=MLLBZ-GQECI-ASXG7-5GNOZ-XW2OF-H5BVH"></script>
<script src="${base!}/assets/platform/js/util/h5PopupHistory.js?v=20261110-2"></script>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
Vue.config.devtools = true Vue.config.devtools = true
@@ -2080,7 +2080,7 @@ layout("/layouts/v4/baseLayout.html"){
// 获取活动列表 // 获取活动列表
getActivity() { getActivity() {
$.get("/platform/home/listHomeActivity").then((res) => { $.get("/platform/home/listHomeActivity", {platform: "PC"}).then((res) => {
if (res.code === 0) { if (res.code === 0) {
this.activityList = res.data this.activityList = res.data
} }
@@ -61,7 +61,7 @@ const act = {
methods: { methods: {
/*查询活动*/ /*查询活动*/
listAct() { listAct() {
this.$axios.post("/platform/home/listHomeActivity").then((res) => { this.$axios.post("/platform/home/listHomeActivity", {platform: "PC"}).then((res) => {
if (res.code === 0) { if (res.code === 0) {
// for (let i = 0; i < 10; i++) { // for (let i = 0; i < 10; i++) {
// this.actList = this.actList.concat(res.data) // this.actList = this.actList.concat(res.data)
@@ -58,7 +58,7 @@ layout("/layouts/platform.html"){
</el-form-item> </el-form-item>
</el-form> </el-form>
<span slot="footer" class="dialog-footer"> <span slot="footer" class="dialog-footer">
<el-button @click="addDialogVisible = false">取 消</el-button> <el-button @click="cancelAddCampus">取 消</el-button>
<el-button type="primary" @click="doAdd">确 定</el-button> <el-button type="primary" @click="doAdd">确 定</el-button>
</span> </span>
</el-dialog> </el-dialog>
@@ -73,70 +73,83 @@ layout("/layouts/platform.html"){
</el-form-item> </el-form-item>
</el-form> </el-form>
<span slot="footer" class="dialog-footer"> <span slot="footer" class="dialog-footer">
<el-button @click="editDialogVisible = false">取 消</el-button> <el-button @click="cancelEditCampus">取 消</el-button>
<el-button type="primary" @click="doEdit">确 定</el-button> <el-button type="primary" @click="doEdit">确 定</el-button>
</span> </span>
</el-dialog> </el-dialog>
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
new Vue({ new Vue({
el: '#app', el: '#app',
mixins: [initTableMixins], mixins: [initTableMixins],
data() { data() {
return { return {
addDialogVisible: false, addDialogVisible: false,
editDialogVisible: false, editDialogVisible: false,
formData: {}, formData: {},
rules: { rules: {
campusName: [{required: true, message: '请输入院区名称', trigger: ['change', 'blur']}], campusName: [{
campusCode: [{required: true, message: '请输入院区编码', trigger: ['change', 'blur']}] required: true,
message: '请输入院区名称',
trigger: ['change', 'blur']
}],
campusCode: [{
required: true,
message: '请输入院区编码',
trigger: ['change', 'blur']
}]
}, },
tableData: [] tableData: []
} };
}, },
methods: { methods: {
cancelAddCampus() {
// 仅关闭当前弹框,不执行提交或保存操作。
this.$set(this, 'addDialogVisible', false);
},
cancelEditCampus() {
// 仅关闭当前弹框,不执行提交或保存操作。
this.$set(this, 'editDialogVisible', false);
},
openAdd() { openAdd() {
this.formData = {} this.formData = {};
this.addDialogVisible = true this.addDialogVisible = true;
if (this.$refs["addForm"]) if (this.$refs["addForm"]) this.$refs["addForm"].resetFields();
this.$refs["addForm"].resetFields()
}, },
doAdd() { doAdd() {
this.$refs['addForm'].validate(valid => { this.$refs['addForm'].validate(valid => {
if (valid) { if (valid) {
$.post('/platform/healthCheckup/campus/doAdd', this.formData).then(res => { this.$axios.post('/platform/healthCheckup/campus/doAdd', this.formData).then(res => {
if (res.code === 0) { if (res.code === 0) {
this.addDialogVisible = false this.addDialogVisible = false;
this.pageData() this.pageData();
this.$message.success(res.msg) this.$message.success(res.msg);
} else { } else {
this.$message.error(res.msg) this.$message.error(res.msg);
} }
}) });
} }
}) });
}, },
openEdit(obj) { openEdit(obj) {
this.formData = JSON.parse(JSON.stringify(obj)) this.formData = JSON.parse(JSON.stringify(obj));
this.editDialogVisible = true this.editDialogVisible = true;
}, },
doEdit() { doEdit() {
this.$refs['editForm'].validate(valid => { this.$refs['editForm'].validate(valid => {
if (valid) { if (valid) {
$.post('/platform/healthCheckup/campus/doEdit', this.formData).then(res => { this.$axios.post('/platform/healthCheckup/campus/doEdit', this.formData).then(res => {
if (res.code === 0) { if (res.code === 0) {
this.editDialogVisible = false this.editDialogVisible = false;
this.pageData() this.pageData();
this.$message.success(res.msg) this.$message.success(res.msg);
} else { } else {
this.$message.error(res.msg) this.$message.error(res.msg);
} }
}) });
} }
}) });
}, },
doDelete(id) { doDelete(id) {
this.$confirm('此操作将删除院区,确认删除吗?', '提示', { this.$confirm('此操作将删除院区,确认删除吗?', '提示', {
@@ -144,20 +157,21 @@ layout("/layouts/platform.html"){
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
$.post('/platform/healthCheckup/campus/doDelete', {id: id}).then(res => { this.$axios.post('/platform/healthCheckup/campus/doDelete', {
id: id
}).then(res => {
if (res.code === 0) { if (res.code === 0) {
this.doSearch() this.doSearch();
this.$message.success(res.msg) this.$message.success(res.msg);
} }
}) });
}).catch(() => { }).catch(() => {});
})
} }
}, },
created() { created() {
this.pageData() this.pageData();
} }
}) });
</script> </script>
<!--# <!--#
@@ -1,5 +1,6 @@
const CONDITION_STRUCTURE_DIALOG = { const CONDITION_STRUCTURE_DIALOG = {
template: /*language=HTML*/ ` template: /*language=HTML*/`
<el-dialog <el-dialog
:close-on-click-modal="false" :close-on-click-modal="false"
:visible.sync="dialogVisible" :visible.sync="dialogVisible"
@@ -76,7 +77,7 @@ const CONDITION_STRUCTURE_DIALOG = {
</el-col> </el-col>
</el-row> </el-row>
<span slot="footer"> <span slot="footer">
<el-button @click="dialogVisible = false">关 闭</el-button> <el-button @click="closeConditionDialog">关 闭</el-button>
<el-button type="primary" @click="doSubmit">确 认</el-button> <el-button type="primary" @click="doSubmit">确 认</el-button>
</span> </span>
</el-dialog> </el-dialog>
@@ -89,70 +90,92 @@ const CONDITION_STRUCTURE_DIALOG = {
method: "", method: "",
conditions: [] conditions: []
}, },
fields: [ fields: [{
{
"label": "性别", "label": "性别",
"value": "sex", "value": "sex",
"type": "select", "type": "select",
"options": [{"value": "男", "label": "男"}, {"value": "女", "label": "女"}] "options": [{
}, "value": "男",
{ "label": "男"
}, {
"value": "女",
"label": "女"
}]
}, {
"label": "出生日期", "label": "出生日期",
"value": "birthday", "value": "birthday",
"type": "date", "type": "date"
}, }, {
{
"label": "婚姻状况", "label": "婚姻状况",
"value": "marriage", "value": "marriage",
"type": "select", "type": "select",
"options": [{"value": "未婚", "label": "未婚"}, {"value": "已婚", "label": "已婚"}] "options": [{
} "value": "未婚",
], "label": "未婚"
operationalOption: [ }, {
{"label": "等于(=)", "value": "="}, "value": "已婚",
{"label": "不等于(!=)", "value": "!="}, "label": "已婚"
{"label": "小于(<)", "value": "<"}, }]
{"label": "小于等于(<=)", "value": "<="}, }],
{"label": "大于(>)", "value": ">"}, operationalOption: [{
{"label": "大于等于(>=)", "value": ">="}, "label": "等于(=)",
] "value": "="
} }, {
"label": "不等于(!=)",
"value": "!="
}, {
"label": "小于(<)",
"value": "<"
}, {
"label": "小于等于(<=)",
"value": "<="
}, {
"label": "大于(>)",
"value": ">"
}, {
"label": "大于等于(>=)",
"value": ">="
}]
};
}, },
methods: { methods: {
async onOpen(formData) { closeConditionDialog() {
console.log(formData) // 仅关闭当前弹框,不执行提交或保存操作。
this.$set(this, 'dialogVisible', false);
},
onOpen(formData) {
console.log(formData);
if (formData) { if (formData) {
this.formData = formData this.formData = formData;
}else{ } else {
this.formData = { this.formData = {
method: "", method: "",
conditions: [] conditions: []
};
} }
} this.dialogVisible = true;
this.dialogVisible = true this.$forceUpdate();
this.$forceUpdate()
}, },
fieldChange(val, cnd) { fieldChange(val, cnd) {
this.$set(cnd, "fieldObj", this.fields.find(v => v.value === val)) this.$set(cnd, "fieldObj", this.fields.find(v => v.value === val));
this.$set(cnd, "value", null) this.$set(cnd, "value", null);
this.$forceUpdate() this.$forceUpdate();
}, },
doSubmit() { doSubmit() {
if (!this.formData.method) { if (!this.formData.method) {
this.$message.error("请选择匹配方式") this.$message.error("请选择匹配方式");
return return;
} }
if (this.formData.conditions.length === 0) { if (this.formData.conditions.length === 0) {
this.$message.error("请添加条件") this.$message.error("请添加条件");
return return;
} }
if (this.formData.conditions.some(v => !v.field || !v.operational || !v.value)) { if (this.formData.conditions.some(v => !v.field || !v.operational || !v.value)) {
this.$message.error("请填写完整条件") this.$message.error("请填写完整条件");
return return;
} }
this.$emit("confirm", this.formData) this.$emit("confirm", this.formData);
this.dialogVisible = false this.dialogVisible = false;
} }
} }
} };
@@ -0,0 +1,201 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" class="platform" v-cloak>
<guava ref="guava" padding="0 5%">
<template>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
v-model="pageForm.year"
type="year"
style="width: 100%;"
value-format="yyyy"
placeholder="请选择年度"
@change="yearChange">
</el-date-picker>
</search-item>
<search-item label="体检项目">
<el-select v-model="pageForm.projectId"
style="width: 100%;"
clearable
@change="doSearch">
<el-option v-for="item in projectOptions"
:key="item.id"
:label="item.name"
:value="item.id"></el-option>
</el-select>
</search-item>
<search-item label="分工会" v-if="$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN'])">
<el-select v-model="pageForm.unionId"
style="width: 100%;"
clearable
filterable
@change="doSearch">
<el-option v-for="item in unions"
:key="item.id"
:label="item.name"
:value="item.id"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool label="问题反馈列表">
<el-button type="danger"
size="small"
:disabled="selectedFeedbackIds.length === 0"
@click="deleteFeedbackBatch">批量删除</el-button>
</table-tool>
<el-table :data="tableData"
style="width: 100%"
row-key="id"
:size="tableSize"
v-loading="tableLoading"
@selection-change="handleSelectionChange"
ref="table"
class="vi-table">
<el-table-column type="selection"
width="55"
align="center"
header-align="center"></el-table-column>
<el-table-column type="index"
:index="indexMethod"
label="序号"
width="80px"
align="center"
header-align="center"></el-table-column>
<el-table-column prop="year"
label="年度"
min-width="120px"
align="center"
header-align="center"
show-overflow-tooltip></el-table-column>
<el-table-column prop="projectName"
label="体检项目"
min-width="160px"
align="center"
header-align="center"
show-overflow-tooltip></el-table-column>
<el-table-column prop="unionName"
label="分工会"
min-width="160px"
align="center"
header-align="center"
show-overflow-tooltip></el-table-column>
<el-table-column prop="feedbackInfo"
label="反馈信息"
min-width="240px"
align="center"
header-align="center"
show-overflow-tooltip>
<template slot-scope="{row}">
<div v-html="row.feedbackInfo" style="white-space: pre-line !important;"></div>
</template>
</el-table-column>
<el-table-column prop="createdByName"
label="创建人"
min-width="120px"
align="center"
header-align="center"
show-overflow-tooltip></el-table-column>
<el-table-column prop="createdAt" label="创建时间"
width="180px"
align="center"
header-align="center">
<template slot-scope="{row}">
{{ row.createdAt ? $moment(row.createdAt).format('YYYY-MM-DD HH:mm:ss') : '' }}
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: '#app',
mixins: [initTableMixins],
data() {
return {
tableData: [],
selectedFeedbackIds: [],
unions: [],
projectOptions: []
};
},
methods: {
handleSelectionChange(rows) {
this.selectedFeedbackIds = rows.map(item => {
return item.id;
});
},
deleteFeedbackBatch() {
if (this.selectedFeedbackIds.length === 0) {
this.notifyWarning("请选择需要删除的反馈");
return;
}
return Promise.resolve(this.$confirm("确认批量删除选中的反馈吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})).then(confirm => {
if (confirm === "confirm") {
return this.$axios.post("/platform/healthCheckup/list/mange/deleteFeedbackBatch", {
ids: this.selectedFeedbackIds.join(",")
}).then(resp => {
if (resp.code === 0) {
this.notifySuccess(resp.msg);
return Promise.resolve(this.pageData()).then(() => {});
} else {
this.notifyError(resp.msg);
}
});
} else {}
});
},
yearChange() {
return Promise.resolve($.get("/platform/healthCheckup/project/mange/getHealthCheckupProject", {
year: this.pageForm.year
})).then(resp => {
if (resp.code === 0) {
this.projectOptions = resp.data;
if (resp.data && resp.data.length > 0) {
const currentProjectId = this.pageForm.projectId;
if (!currentProjectId || !resp.data.some(item => {
return item.id === currentProjectId;
})) {
this.pageForm.projectId = resp.data[0].id;
}
} else {
this.pageForm.projectId = "";
}
return Promise.resolve(this.doSearch()).then(() => {});
} else {
this.notifyError(resp.msg);
}
});
}
},
created() {
this.pageForm.year = this.$moment().format('YYYY');
return Promise.resolve(this.$businessTool.listUnion()).then(resolvedValue => {
this.unions = resolvedValue;
if (!this.pageForm.unionId && this.unions && this.unions.length === 1) {
this.pageForm.unionId = this.unions[0].id;
}
return Promise.resolve(this.yearChange()).then(() => {});
});
}
});
</script>
<!--#
}
#-->
@@ -0,0 +1,91 @@
const addHealthCheckupUser = {
template: "#health-checkup-add-user-template",
mixins: [initTableMixins],
data() {
return {
visible: false,
pageDataUrl: "/platform/healthCheckup/list/mange/candidatePageData",
pageForm: {
searchKeyword: null,
sex: null,
birthday: null,
birthMonths: [],
unionId: null,
unitIds: [],
personTypes: [],
preparedBys: [],
userStates: [],
isMember: null,
memberFeePaid: null
},
sexOptions: ["男", "女"],
unionOptions: [],
unitOptions: [],
tableColumns: [
{ prop: "loginname", label: "工号" },
{ prop: "username", label: "姓名" },
{ prop: "sex", label: "性别", sortable: true, checked: 0 },
{ prop: "birthday", label: "出生日期", sortable: true, checked: 0 },
{ prop: "personType", label: "人员类型", sortable: true },
{ prop: "preparedBy", label: "编制类别", sortable: true },
{ prop: "userState", label: "在职状态", sortable: true },
{ prop: "unionName", label: "所属工会", sortable: true },
{ prop: "unitName", label: "所属单位", sortable: true }
]
}
},
methods: {
onCancel() {
// 关闭新增人员弹框,保留现有提交中禁用取消按钮的规则。
this.$set(this, "visible", false);
},
// 每次打开绑定目标项目并清空业务筛选,查询和分页由 mixin 负责。
onOpen(id) {
if (!id) {
this.notifyWarning("请先选择体检项目");
return;
}
this.$set(this, "visible", true);
this.$set(this, "tableData", []);
const defaults = addHealthCheckupUser.data().pageForm;
Object.keys(defaults).forEach(key => this.$set(this.pageForm, key, defaults[key]));
this.$set(this.pageForm, "projectId", id);
this.$businessTool.listUnion().then(rows => { this.unionOptions = rows; });
this.unionIdChange(null);
this.doSearch();
},
// 工会切换后清空旧单位,防止保留不属于当前工会的筛选条件。
unionIdChange(id) {
this.$set(this.pageForm, "unitIds", []);
return this.$businessTool.listUnit(id).then(rows => { this.unitOptions = rows; });
},
onSubmit() {
if (this.formLoading || this.tableLoading) return;
this.formLoading = true;
// 先按最新输入刷新预览,冻结本次筛选,确认后添加全部匹配人员而非当前页。
const params = JSON.parse(JSON.stringify(this.pageForm));
this.$set(this.pageForm, "totalCount", 0);
return this.pageData(params).then(() => {
if (!this.pageForm.totalCount) {
this.notifyWarning("当前筛选没有可添加人员");
return;
}
return this.$confirm("当前筛选出" + this.pageForm.totalCount + "人,确认全部添加到体检名单并补入参与人员范围吗?", "提示", {
confirmButtonText: "确定", cancelButtonText: "取消", type: "warning"
}).then(() => {
return this.$axios.post("/platform/healthCheckup/list/mange/addUsers", params).then(res => {
if (res.code === 0) {
this.notifySuccess(res.msg);
this.$set(this, "visible", false);
this.$emit("refresh");
} else {
this.notifyError(res.msg);
}
});
});
}).catch(error => {
if (error !== "cancel" && error !== "close") this.notifyError("添加未完成,请刷新后重试");
}).finally(() => { this.formLoading = false; });
}
}
};
@@ -1,7 +1,12 @@
<!--# <!--#
layout("/layouts/platform.html"){ layout("/layouts/platform.html"){
#--> #-->
<style>
.el-table .cell.el-tooltip {
white-space: pre-line !important;
min-width: 50px !important;
}
</style>
<div id="app" class="platform" v-cloak> <div id="app" class="platform" v-cloak>
<guava ref="guava" padding="0 5%"> <guava ref="guava" padding="0 5%">
@@ -20,6 +25,9 @@ layout("/layouts/platform.html"){
value-format="yyyy"> value-format="yyyy">
</el-date-picker> </el-date-picker>
</search-item> </search-item>
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="体检项目"> <search-item label="体检项目">
<el-select @change="doSearch();getHealthCheckupSubject();" <el-select @change="doSearch();getHealthCheckupSubject();"
style="width: 100%;" style="width: 100%;"
@@ -28,8 +36,16 @@ layout("/layouts/platform.html"){
v-for="item in projectOptions"></el-option> v-for="item in projectOptions"></el-option>
</el-select> </el-select>
</search-item> </search-item>
<search-item label="姓名/工号"> <search-item label="所选套餐">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword"></el-input> <el-select placeholder="请选择套餐" v-model="pageForm.subjectId"
style="width: 100%;"
clearable
filterable>
<el-option v-for="item in subjects"
:label="item.optionName"
:value="item.id"
:key="item.id"></el-option>
</el-select>
</search-item> </search-item>
<search-item label="所属工会" v-if="$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN'])"> <search-item label="所属工会" v-if="$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN'])">
<el-select placeholder="请选择所属工会" v-model="pageForm.unionId" <el-select placeholder="请选择所属工会" v-model="pageForm.unionId"
@@ -54,12 +70,40 @@ layout("/layouts/platform.html"){
:key="item.id"></el-option> :key="item.id"></el-option>
</el-select> </el-select>
</search-item> </search-item>
<search-item label="确认状态">
<el-select v-model="pageForm.isAudit" placeholder="请选择" clearable>
<el-option
v-for="item in isAuditOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</search-item>
</search> </search>
</el-card> </el-card>
<el-card shadow="never" class="mt10"> <el-card shadow="never" class="mt10">
<table-tool label="体检项目"> <table-tool label="体检项目">
<el-button type="primary" size="small" @click="openImport">导入名单 <el-radio-group v-model="pageForm.physicalExaminationStatus" size="medium" @change="doSearch" class="pr10">
<el-radio-button :label="2">全部</el-radio-button>
<el-radio-button :label="1">已选择</el-radio-button>
<el-radio-button :label="0">未选择</el-radio-button>
</el-radio-group>
<el-button type="primary" size="small" @click="openHealthFeedback"
v-if="$auth.hasRoleOr(['BRANCH_UNION_CHAIRMAN'])">问题反馈</el-button>
<el-button type="primary" size="small" @click="$refs.addUserRef.onOpen(pageForm.projectId)"
:disabled="!pageForm.projectId"
v-if="$auth.hasPermissionOr(['healthCheckup.list.import']) && $auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN','SCHOOL_UNION_CHAIRMAN'])">添加人员
</el-button>
<el-button type="primary" size="small" @click="openImport"
v-if="$auth.hasPermissionOr(['healthCheckup.list.import'])">导入名单
</el-button>
<el-button type="primary" size="small" @click="openImportMedicalExaminationReport"
v-if="$auth.hasPermissionOr(['healthCheckup.list.import.medicalExamination'])">导入体检报告
</el-button>
<el-button type="primary" size="small" @click="exportData"
v-if="$auth.hasRoleOr(['SYSADMIN','BRANCH_UNION_ADMIN','BRANCH_UNION_CHAIRMAN'])">导出
</el-button> </el-button>
<el-button :disabled="!pageForm.projectId" type="primary" size="small" <el-button :disabled="!pageForm.projectId" type="primary" size="small"
@click="doAudit(true)">确认名单 @click="doAudit(true)">确认名单
@@ -68,6 +112,12 @@ layout("/layouts/platform.html"){
<el-button :disabled="!pageForm.projectId" type="danger" size="small" <el-button :disabled="!pageForm.projectId" type="danger" size="small"
@click="doAudit(false)">取消确认 @click="doAudit(false)">取消确认
</el-button> </el-button>
<!-- <el-button @click="msgNotSelect"
icon="el-icon-printer"
size="small"
type="primary"
v-if="$auth.hasRoleOr(['SYSADMIN'])">给未选发送消息
</el-button> -->
</table-tool> </table-tool>
@@ -106,13 +156,24 @@ layout("/layouts/platform.html"){
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="userOnline" align="center" header-align="center" <el-table-column prop="userOnline" align="center" header-align="center"
label="操作" label="操作" width="250px"
fixed="right"> fixed="right">
<template slot-scope="{row}"> <template slot-scope="{row}">
<el-button @click="openEditRemarks(row)" size="mini"
v-if="$auth.hasRoleOr(['SYSADMIN','BRANCH_UNION_ADMIN','BRANCH_UNION_CHAIRMAN'])"
type="primary">
编辑备注
</el-button>
<el-button @click="openEditHealthCheckup(row)" size="mini" <el-button @click="openEditHealthCheckup(row)" size="mini"
:disabled="row.isAudit" type="primary"> v-if="$auth.hasRoleOr(['SYSADMIN', 'HEALTH_ADMIN'])"
type="primary">
编辑 编辑
</el-button> </el-button>
<el-button @click="doDelete(row.headId)" size="mini"
v-if="$auth.hasPermissionOr(['healthCheckup.list.delete']) && $auth.hasRoleOr(['SYSADMIN'])"
type="danger">
删除
</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@@ -126,10 +187,10 @@ layout("/layouts/platform.html"){
:close-on-click-modal="false"> :close-on-click-modal="false">
<el-form :model="editHealthCheckupData" label-width="120px" ref="editHealthCheckupForm"> <el-form :model="editHealthCheckupData" label-width="120px" ref="editHealthCheckupForm">
<el-form-item label="姓名"> <el-form-item label="姓名">
<el-input :value="editHealthCheckupData.userName"></el-input> <el-input :value="editHealthCheckupData.userName" readonly></el-input>
</el-form-item> </el-form-item>
<el-form-item label="工号"> <el-form-item label="工号">
<el-input :value="editHealthCheckupData.loginName"></el-input> <el-input :value="editHealthCheckupData.loginName" readonly></el-input>
</el-form-item> </el-form-item>
<el-form-item label="套餐" <el-form-item label="套餐"
prop="subjectId" prop="subjectId"
@@ -154,12 +215,48 @@ layout("/layouts/platform.html"){
</el-form-item>--> </el-form-item>-->
</el-form> </el-form>
<el-row type="flex" justify="end"> <el-row type="flex" justify="end">
<el-button @click="exportHealthCheckupDialog=false" type="primary" plain>取消</el-button> <el-button @click="cancelHealthCheckupEdit" type="primary" plain>取消</el-button>
<el-button @click="doEditHealthCheckupData" type="primary" v-loading="loading">确定 <el-button @click="doEditHealthCheckupData" type="primary" v-loading="loading">确定
</el-button> </el-button>
</el-row> </el-row>
</el-dialog> </el-dialog>
<el-dialog title="修改备注" :visible.sync="doEditRemarksDialog" width="50%"
:close-on-click-modal="false">
<el-form label-width="120px" ref="editRemarksForm" :model="doEditRemarks">
<el-form-item label="备注" prop="bz">
<el-input v-model="doEditRemarks.remarks" type="textarea" rows="5"
placeholder="请输入备注"></el-input>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="cancelRemarksEdit" type="primary" plain>取消</el-button>
<el-button @click="doEditRemarksFun" type="primary" v-loading="loading">确定</el-button>
</el-row>
</el-dialog>
<el-dialog title="问题反馈" :visible.sync="healthFeedbackDialog" width="60%"
:close-on-click-modal="false">
<el-form :model="healthFeedbackForm" label-width="100px">
<el-form-item label="反馈信息">
<el-input v-model="healthFeedbackForm.feedbackInfo" placeholder="请输入反馈信息"></el-input>
</el-form-item>
</el-form>
<el-row type="flex" justify="end" class="mb10">
<el-button @click="closeHealthFeedback" type="primary" plain>取消</el-button>
<el-button @click="saveHealthFeedback" type="primary" v-loading="healthFeedbackLoading">保存</el-button>
</el-row>
<el-table :data="healthFeedbackList" border >
<el-table-column align="center" label="问题反馈" prop="feedbackInfo" show-overflow-tooltip="false"></el-table-column>
<el-table-column align="center" label="操作" width="100px">
<template slot-scope="{row}">
<el-button @click="deleteHealthFeedback(row)" type="danger" size="mini">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-dialog>
<add-health-checkup-user ref="addUserRef" @refresh="doSearch"></add-health-checkup-user>
<excel-import <excel-import
ref="excelImportRef" ref="excelImportRef"
@@ -171,164 +268,593 @@ layout("/layouts/platform.html"){
:extra_params="{healthProjectId:pageForm.projectId}" :extra_params="{healthProjectId:pageForm.projectId}"
></excel-import> ></excel-import>
<excel-import
ref="excelImportExaminationReportRef"
url="/platform/healthCheckup/list/mange/healthImportMedicalExaminationReport"
template_url="/platform/healthCheckup/list/mange/downloadTemMedicalExaminationReport"
:visible.sync="importVisibleExaminationReport"
title="导入名单数据"
width="700px"
:extra_params="{healthProjectId:pageForm.projectId}"
></excel-import>
</div> </div>
<script type="text/x-template" id="health-checkup-add-user-template">
<el-dialog title="添加人员" :close-on-click-modal="false" :visible.sync="visible" width="80%">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="姓名/工号">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入姓名/工号"
style="width: 100%" v-model="pageForm.searchKeyword">
</el-input>
</search-item>
<search-item label="性别">
<el-select clearable placeholder="请选择性别" style="width: 100%" v-model="pageForm.sex">
<el-option :key="sex" :label="sex" :value="sex"
v-for="sex in sexOptions"></el-option>
</el-select>
</search-item>
<search-item label="出生日期">
<el-date-picker
v-model="pageForm.birthday"
type="date"
placeholder="选择出生日期"
value-format="yyyy-MM-dd"
style="width: 100%">
</el-date-picker>
</search-item>
<search-item label="出生月份">
<el-select
v-model="pageForm.birthMonths"
multiple
collapse-tags
placeholder="请选择出生月份"
style="width: 100%">
<el-option
v-for="month in 12"
:key="month"
:label="month + '月'"
:value="month">
</el-option>
</el-select>
</search-item>
<search-item label="所属工会">
<el-select clearable filterable placeholder="请选择所属工会"
style="width: 100%"
@change="unionIdChange"
v-model="pageForm.unionId">
<el-option
:key="item.id"
:label="item.name"
:value="item.id"
v-for="item in unionOptions">
</el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<el-select clearable
filterable
multiple
collapse-tags
placeholder="请选择所属单位" style="width: 100%"
v-model="pageForm.unitIds">
<el-option
:key="item.id"
:label="item.name"
:value="item.id"
v-for="item in unitOptions">
</el-option>
</el-select>
</search-item>
<search-item label="人员类型:">
<dict-select clearable code="USER_PERSON_TYPE"
multiple
collapse-tags
placeholder="请选择人员类型"
v-model="pageForm.personTypes"></dict-select>
</search-item>
<search-item label="编制类别:">
<dict-select clearable code="USER_PREPARED_BY_TYPE"
multiple
collapse-tags
placeholder="请选择编制类别"
v-model="pageForm.preparedBys"></dict-select>
</search-item>
<search-item label="在职状态:">
<dict-select clearable code="USER_STATE"
multiple
collapse-tags
placeholder="请选择人员状态"
v-model="pageForm.userStates"></dict-select>
</search-item>
<search-item label="是否会员">
<el-select clearable placeholder="请选择是否会员" style="width: 100%"
v-model="pageForm.isMember">
<el-option label="全部" :value="null"></el-option>
<el-option label="是" :value="true"></el-option>
<el-option label="否" :value="false"></el-option>
</el-select>
</search-item>
<search-item label="是否缴费会员">
<el-select clearable placeholder="请选择是否缴费会员" style="width: 100%"
v-model="pageForm.memberFeePaid">
<el-option label="是" :value="true"></el-option>
<el-option label="否" :value="false"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<el-table :data="tableData"
:size="tableSize"
@sort-change="pageOrder"
ref="tableRef"
row-key="id"
v-loading="tableLoading"
style="width: 100%">
<el-table-column
:index="indexMethod"
label="序号"
type="index"
width="80px"
></el-table-column>
<el-table-column
:key="column.prop"
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
align="center"
header-align="center"
show-overflow-tooltip
v-for="column in tableColumns"
>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #footer>
<el-button @click="onCancel" :disabled="formLoading">取消</el-button>
<el-button type="primary" @click="onSubmit" :loading="formLoading" :disabled="tableLoading">确定</el-button>
</template>
<slot></slot>
</el-dialog>
</script>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
const vue = new Vue({ <!--#include("addUser.js"){}#-->
const vue = new Vue({
el: '#app', el: '#app',
mixins: [initTableMixins], mixins: [initTableMixins],
data() { data() {
return { return {
pageForm: { pageForm: {
year: moment().format('YYYY'), year: moment().format('YYYY'),
physicalExaminationStatus: '2'
}, },
unions: [], unions: [],
subjects: [],
units: [], units: [],
projectOptions: [], projectOptions: [],
projectSubjectOptions: [], projectSubjectOptions: [],
tableColumns: [ tableColumns: [{
{prop: 'loginName', label: '工号'}, prop: 'loginName',
{prop: 'userName', label: '姓名'}, label: '工号'
{prop: 'sex', label: '性别', sortable: true}, }, {
{prop: 'unionName', label: '所属工会', sortable: true}, prop: 'userName',
{prop: 'unitName', label: '所属单位', sortable: true}, label: '姓名'
{prop: 'optionName', label: '所选套餐'}, }, {
{prop: 'selectTime', label: '选择时间', width: "160px"}, prop: 'sex',
{prop: 'receiveAddress', label: '邮寄地址', width: "160px"}, label: '性别',
{prop: 'isAudit', label: '是否确认'}, sortable: true
{prop: 'auditTime', label: '确认时间'}, }, {
{prop: 'bz', label: '备注',width: "200px"}, prop: 'unionName',
], label: '所属工会',
sortable: true
}, {
prop: 'unitName',
label: '所属单位',
sortable: true
}, {
prop: 'optionName',
label: '所选套餐'
}, {
prop: 'selectTime',
label: '选择时间',
width: "160px"
}, {
prop: 'isAudit',
label: '是否确认',
sortable: true
}, {
prop: 'auditTime',
label: '确认时间'
}, {
prop: 'bz',
label: '备注',
width: "200px"
}],
exportHealthCheckupDialog: false, exportHealthCheckupDialog: false,
editHealthCheckupData: {}, editHealthCheckupData: {},
loading: false, loading: false,
//导入名单 //导入名单
importVisible: false, importVisible: false,
importVisibleExaminationReport: false,
doEditRemarksDialog: false,
doEditRemarks: {
userId: "",
projectId: "",
remarks: ""
},
healthFeedbackDialog: false,
healthFeedbackLoading: false,
healthFeedbackList: [],
healthFeedbackForm: {
year: "",
projectId: "",
unionId: "",
feedbackInfo: ""
},
campusOptions: [], campusOptions: [],
} isAuditOptions: [{
label: "已确认",
value: "1"
}, {
label: "未确认",
value: "0"
}]
};
}, },
components: { components: {
"add-health-checkup-user": addHealthCheckupUser,
"file-import": httpVueLoader("/components/plugins/sysImport/index.vue?v=" + new Date().getTime()) "file-import": httpVueLoader("/components/plugins/sysImport/index.vue?v=" + new Date().getTime())
}, },
methods: { methods: {
async doAudit(flag) { cancelHealthCheckupEdit() {
// 仅关闭当前弹框,不执行提交或保存操作。
this.$set(this, 'exportHealthCheckupDialog', false);
},
cancelRemarksEdit() {
// 仅关闭当前弹框,不执行提交或保存操作。
this.$set(this, 'doEditRemarksDialog', false);
},
closeHealthFeedback() {
// 仅关闭当前弹框,不执行提交或保存操作。
this.$set(this, 'healthFeedbackDialog', false);
},
doAudit(flag) {
// flag true,确认 false,取消 // flag true,确认 false,取消
if (this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"]) && !this.pageForm.unionId) { if (this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"]) && !this.pageForm.unionId) {
this.notifyWarning("请选择需要提交的分工会") this.notifyWarning("请选择需要提交的分工会");
return return;
} }
if (this.pageForm.totalCount === 0) { if (this.pageForm.totalCount === 0) {
this.notifyWarning("当前分工会没有名单,暂不需要提交") this.notifyWarning("当前分工会没有名单,暂不需要提交");
return return;
} }
const confirm = await this.$confirm(flag ? '您确定名单都已核实,准确无误?' : '您确定取消确认?', '提示', { return Promise.resolve(this.$confirm(flag ? '您确定名单都已核实,准确无误?' : '您确定取消确认?', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}) })).then(confirm => {
if (confirm === "confirm") { if (confirm === "confirm") {
const resp = await $.post("/platform/healthCheckup/list/mange/doAuditUser", { return this.$axios.post("/platform/healthCheckup/list/mange/doAuditUser", {
projectId: this.pageForm.projectId, projectId: this.pageForm.projectId,
unionId: this.pageForm.unionId, unionId: this.pageForm.unionId,
flag: flag flag: flag
}) }).then(resp => {
if (resp.code === 0) { if (resp.code === 0) {
this.notifySuccess(resp.msg) this.notifySuccess(resp.msg);
this.doSearch() this.doSearch();
} else { } else {
this.notifyError(resp.msg) this.notifyError(resp.msg);
}
} }
});
} else {}
});
}, },
doEditHealthCheckupData() { doEditHealthCheckupData() {
this.$refs['editHealthCheckupForm'].validate(async valid => { this.$refs['editHealthCheckupForm'].validate(valid => {
if (valid) { if (valid) {
this.loading = true this.loading = true;
const resp = await $.post(loc() + "/doEditHealthCheckupData", this.editHealthCheckupData) return this.$axios.post(loc() + "/doEditHealthCheckupData", this.editHealthCheckupData).then(resp => {
this.exportHealthCheckupDialog = false this.exportHealthCheckupDialog = false;
if (resp.code === 0) { if (resp.code === 0) {
this.notifySuccess(resp.msg) this.notifySuccess(resp.msg);
this.doSearch() this.doSearch();
} else { } else {
this.notifyWarning(resp.msg) this.notifyWarning(resp.msg);
} }
this.loading = false this.loading = false;
} }).finally(() => {
}) this.loading = false;
});
} else {}
});
}, },
async openEditHealthCheckup(row) { openEditHealthCheckup(row) {
this.editHealthCheckupData = { this.editHealthCheckupData = {
userName: row.userName, userName: row.userName,
loginName: row.loginName, loginName: row.loginName,
subjectId: row.subjectId, subjectId: row.subjectId,
campus: row.campus, campus: row.campus,
projectId: this.pageForm.projectId, projectId: this.pageForm.projectId,
userId: row.id userId: row.id,
} isEmployed: row.isEmployed
this.exportHealthCheckupDialog = true };
this.exportHealthCheckupDialog = true;
}, },
async yearChange() { yearChange() {
const resp = await $.get("/platform/healthCheckup/project/mange/getHealthCheckupProject", {year: this.pageForm.year}) return Promise.resolve($.get("/platform/healthCheckup/project/mange/getHealthCheckupProject", {
year: this.pageForm.year
})).then(resp => {
if (resp.code === 0) { if (resp.code === 0) {
this.projectOptions = resp.data this.projectOptions = resp.data;
if (resp.data && resp.data.length > 0) { if (resp.data && resp.data.length > 0) {
this.$set(this.pageForm, "projectId", resp.data[0].id) this.$set(this.pageForm, "projectId", resp.data[0].id);
} else { } else {
this.$set(this.pageForm, "projectId", null) this.$set(this.pageForm, "projectId", null);
} }
await this.getHealthCheckupSubject() return Promise.resolve(this.getHealthCheckupSubject()).then(() => {});
} else { } else {
this.notifyError(resp.msg) this.notifyError(resp.msg);
} }
});
}, },
async getHealthCheckupSubject() { getHealthCheckupSubject() {
const resp = await $.get("/platform/healthCheckup/project/mange/findOne", {id: this.pageForm.projectId}) return Promise.resolve($.get("/platform/healthCheckup/project/mange/findOne", {
id: this.pageForm.projectId
})).then(resp => {
if (resp.code === 0) { if (resp.code === 0) {
this.projectSubjectOptions = resp.data.healthCheckupProjectSubjects this.projectSubjectOptions = resp.data.healthCheckupProjectSubjects;
} else { } else {
this.notifyError(resp.msg) this.notifyError(resp.msg);
} }
this.$set(this.pageForm, "subjectId", "");
return Promise.resolve(this.listSubjects()).then(() => {
this.doSearch();
});
});
}, },
async queryCampus() { queryCampus() {
const resp = await $.get("/platform/healthCheckup/campus/queryCampus") return Promise.resolve($.get("/platform/healthCheckup/campus/queryCampus")).then(resp => {
if (resp.code === 0) { if (resp.code === 0) {
this.campusOptions = resp.data this.campusOptions = resp.data;
} else { } else {
this.notifyError(resp.msg) this.notifyError(resp.msg);
} }
});
}, },
async flushUnits() { flushUnits() {
this.$set(this.pageForm, "unitId", "") this.$set(this.pageForm, "unitId", "");
if (this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])) { if (this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])) {
this.units = await this.$businessTool.listUnit(this.pageForm.unionId) return Promise.resolve(this.$businessTool.listUnit(this.pageForm.unionId)).then(resolvedValue => {
this.units = resolvedValue;
});
} else { } else {
this.units = await this.$businessTool.listUnit() return Promise.resolve(this.$businessTool.listUnit()).then(resolvedValue => {
this.units = resolvedValue;
});
} }
}, },
listSubjects() {
return Promise.resolve($.get(loc() + "/listSubjects", {
projectId: this.pageForm.projectId,
unionId: this.pageForm.unionId
})).then(resp => {
if (resp.code === 0) {
this.subjects = resp.data;
} else {
this.notifyError(resp.msg);
}
});
},
validateHealthFeedbackCondition() {
// 反馈必须绑定当前筛选的年度和体检项目;分工会未选时由后端自动回落到当前登录人所属分工会。
if (!this.pageForm.year || !this.pageForm.projectId) {
this.notifyWarning("请先选择年度、体检项目后再打开问题反馈");
return false;
}
return true;
},
openHealthFeedback() {
if (!this.validateHealthFeedbackCondition()) {
return;
}
this.healthFeedbackForm.year = this.pageForm.year;
this.healthFeedbackForm.projectId = this.pageForm.projectId;
this.healthFeedbackForm.unionId = this.pageForm.unionId;
this.healthFeedbackForm.feedbackInfo = "";
return Promise.resolve(this.queryHealthFeedbackList()).then(() => {
this.healthFeedbackDialog = true;
});
},
queryHealthFeedbackList() {
return Promise.resolve($.get(loc() + "/feedbackList", {
year: this.pageForm.year,
projectId: this.pageForm.projectId,
unionId: this.pageForm.unionId
})).then(resp => {
if (resp.code === 0) {
this.healthFeedbackList = resp.data || [];
} else {
this.notifyError(resp.msg);
}
});
},
saveHealthFeedback() {
if (!this.validateHealthFeedbackCondition()) {
return;
}
if (!this.healthFeedbackForm.feedbackInfo) {
this.notifyWarning("请输入反馈信息");
return;
}
this.healthFeedbackLoading = true;
return this.$axios.post(loc() + "/saveFeedback", this.healthFeedbackForm).then(resp => {
if (resp.code === 0) {
this.notifySuccess(resp.msg);
this.healthFeedbackForm.feedbackInfo = "";
return Promise.resolve(this.queryHealthFeedbackList()).then(() => {
this.healthFeedbackLoading = false;
});
} else {
this.notifyError(resp.msg);
this.healthFeedbackLoading = false;
}
}).finally(() => {
this.healthFeedbackLoading = false;
});
},
deleteHealthFeedback(row) {
return Promise.resolve(this.$confirm("确认删除这条反馈吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})).then(confirm => {
if (confirm === "confirm") {
return this.$axios.post(loc() + "/deleteFeedback", {
id: row.id
}).then(resp => {
if (resp.code === 0) {
this.notifySuccess(resp.msg);
return Promise.resolve(this.queryHealthFeedbackList()).then(() => {});
} else {
this.notifyError(resp.msg);
}
});
} else {}
});
},
openImport() { openImport() {
// importUser // importUser
this.importVisible = true; this.importVisible = true;
}, },
openImportMedicalExaminationReport() {
// importUser
this.importVisibleExaminationReport = true;
},
successImport() { successImport() {
this.importLoading = false this.importLoading = false;
this.doSearch() this.doSearch();
}, },
doDelete(id) {
}, this.$confirm("您确定要删除吗?", "提示", {
async created() { confirmButtonText: "确定",
this.unions = await this.$businessTool.listUnion() cancelButtonText: "取消",
this.flushUnits() type: "info"
await this.yearChange() }).then(() => {
this.pageData() return this.$axios.post(loc() + '/doDelete', {
await this.queryCampus() id: id
}).then(resp => {
if (resp.code === 0) {
this.notifySuccess(resp.msg);
this.doSearch();
} else {
this.notifyError(resp.msg);
} }
}) });
});
},
msgNotSelect() {
return Promise.resolve(this.$confirm('是否给未体检的教职工发送提醒短信?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})).then(confirm => {
if (confirm === "confirm") {
this.tableLoading = true;
return Promise.resolve($.get('/platform/healthCheckup/statistics/single/msgNotSelect', {
projectId: this.pageForm.projectId
})).then(resp => {
if (resp.code === 0) {
setTimeout(() => {
this.doSearch();
this.tableLoading = false;
this.notifySuccess(resp.msg);
}, 2000);
} else {
this.notifyWarning(resp.msg);
}
}).finally(() => {
this.tableLoading = false;
});
} else {}
});
},
openEditRemarks(row) {
this.doEditRemarks.userId = row.id;
this.doEditRemarks.remarks = row.bz;
this.doEditRemarks.projectId = this.pageForm.projectId;
this.doEditRemarksDialog = true;
},
doEditRemarksFun() {
this.$refs['editRemarksForm'].validate(valid => {
if (valid) {
this.loading = true;
return this.$axios.post(loc() + "/doEditRemarks", this.doEditRemarks).then(resp => {
this.doEditRemarksDialog = false;
if (resp.code === 0) {
this.notifySuccess(resp.msg);
this.doSearch();
this.doEditRemarks = {
userId: '',
projectId: '',
remarks: ''
};
} else {
this.notifyWarning(resp.msg);
}
this.loading = false;
}).finally(() => {
this.loading = false;
});
} else {}
});
},
exportData() {
const {
year,
searchKeyword,
projectId,
subjectId,
unionId,
unitId,
physicalExaminationStatus,
pageOrderName,
pageOrderBy
} = this.pageForm;
window.open(loc() + '/exportHealthUser?year=' + year + '&projectId=' + projectId + '&unionId=' + (unionId ? unionId : '') + '&searchKeyword=' + (searchKeyword ? searchKeyword : '') + '&subjectId=' + (subjectId ? subjectId : '') + '&unitId=' + (unitId ? unitId : '') + '&physicalExaminationStatus=' + (physicalExaminationStatus ? physicalExaminationStatus : '') + '&pageOrderName=' + (pageOrderName ? pageOrderName : '') + '&pageOrderBy=' + (pageOrderBy ? pageOrderBy : ''));
}
},
created() {
return Promise.resolve(this.$businessTool.listUnion()).then(resolvedValue => {
this.unions = resolvedValue;
if (!this.pageForm.unionId && this.unions && this.unions.length === 1) {
this.pageForm.unionId = this.unions[0].id;
}
this.flushUnits();
return Promise.resolve(this.yearChange()).then(() => {
this.pageData();
return Promise.resolve(this.queryCampus()).then(() => {});
});
});
}
});
</script> </script>
<!--# <!--#
@@ -0,0 +1,150 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div class="platform" id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
clearable
@change="yearChange"
placeholder="选择年"
style="width: 100%;"
type="year"
v-model="pageForm.year"
value-format="yyyy">
</el-date-picker>
</search-item>
<search-item label="体检项目">
<el-select @change="doSearch"
clearable
style="width: 100%;"
v-model="pageForm.projectId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in projectOptions"></el-option>
</el-select>
</search-item>
<search-item label="所属工会">
<el-select placeholder="请选择所属工会"
v-model="pageForm.unionId"
style="width: 100%;"
:clearable="clearable"
filterable
@change="doSearch">
<el-option v-for="item in unions"
:label="item.name"
:value="item.id"
:key="item.id"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card class="mt10" shadow="never">
<table-tool label="工会确认情况统计"></table-tool>
<el-table :data="tableData"
:size="tableSize"
@sort-change="pageOrder"
class="vi-table"
ref="table"
row-key="unionId"
style="width: 100%"
v-loading="tableLoading">
<el-table-column label="序号" type="index" width="80px" :index="indexMethod" align="center" header-align="center"></el-table-column>
<el-table-column
v-for="column in tableColumns"
:key="column.prop"
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
align="center"
header-align="center"
min-width="120px"
show-overflow-tooltip>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</guava>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: '#app',
mixins: [initTableMixins],
data() {
return {
clearable: false,
tableData: [],
unions: [],
projectOptions: [],
pageForm: {
year: moment().format('YYYY'),
projectId: '',
unionId: ''
},
tableColumns: [{
prop: 'unionName',
label: '工会名称'
}, {
prop: 'totalCount',
label: '体检总人数'
}, {
prop: 'confirmedCount',
label: '已确认总人数'
}, {
prop: 'unconfirmedCount',
label: '未确认总人数'
}, {
prop: 'completeStatus',
label: '确认完成状态'
}]
};
},
methods: {
yearChange() {
// 年度切换后重新加载该年度下的体检项目,并默认定位到第一条可用项目。
return this.$axios.post('/platform/healthCheckup/project/mange/getHealthCheckupProject', {
year: this.pageForm.year
}).then(resp => {
if (resp.code === 0) {
this.projectOptions = resp.data || [];
if (this.projectOptions.length > 0) {
this.$set(this.pageForm, 'projectId', this.projectOptions[0].id);
} else {
this.$set(this.pageForm, 'projectId', '');
}
this.doSearch();
} else {
this.notifyError(resp.msg);
}
});
},
init() {
if (this.$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN'])) {
return Promise.resolve(this.$businessTool.listUnion()).then(resolvedValue => {
this.unions = resolvedValue;
this.clearable = true;
return Promise.resolve(this.yearChange()).then(() => {});
});
} else {
return Promise.resolve(this.$businessTool.listUnion(this.$store.state.user.union.id)).then(resolvedValue => {
this.unions = resolvedValue;
if (this.unions && this.unions.length > 0) {
this.$set(this.pageForm, 'unionId', this.unions[0].id);
}
return Promise.resolve(this.yearChange()).then(() => {});
});
}
}
},
created() {
this.init();
}
});
</script>
<!--#
}
#-->
@@ -1,8 +1,6 @@
<!--# <!--#
layout("/layouts/platform.html"){ layout("/layouts/platform.html"){
#--> #-->
<div id="app" class="platform" v-cloak> <div id="app" class="platform" v-cloak>
<guava ref="guava" padding="0 5%"> <guava ref="guava" padding="0 5%">
<template> <template>
@@ -85,11 +83,11 @@ layout("/layouts/platform.html"){
:command="{type:'renew',data:row}"> :command="{type:'renew',data:row}">
更新名单 更新名单
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item <!-- <el-dropdown-item-->
v-if="( row.isWithinChoiceTime || row.canCreated ) && row.isHasUserList>0" <!-- v-if="( row.isWithinChoiceTime || row.canCreated ) && row.isHasUserList>0"-->
:command="{type:'reset',data:row}"> <!-- :command="{type:'reset',data:row}">-->
重置名单 <!-- 重置名单-->
</el-dropdown-item> <!-- </el-dropdown-item>-->
<el-dropdown-item :command="{type:'edit',data:row}"> <el-dropdown-item :command="{type:'edit',data:row}">
编辑 编辑
</el-dropdown-item> </el-dropdown-item>
@@ -142,10 +140,21 @@ layout("/layouts/platform.html"){
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24">
<el-form-item label="温馨提示">
<el-input type="textarea" v-model="formData.friendlyReminderText" :rows="4"></el-input>
</el-form-item>
</el-col>
<!-- <el-col :span="24">
<el-form-item label="短信信息">
<el-input type="textarea" v-model="formData.smsMessage" :rows="4"></el-input>
</el-form-item>
</el-col> -->
<el-col :span="24"> <el-col :span="24">
<el-form-item label="体检套餐" prop="healthCheckupProjectSubjects"> <el-form-item label="体检套餐" prop="healthCheckupProjectSubjects">
<el-card shadow="hover" v-for="(item,index) in formData.healthCheckupProjectSubjects" <el-collapse shadow="hover" v-for="(item,index) in formData.healthCheckupProjectSubjects"
:key="index"> :key="index">
<el-collapse-item :title="item.optionName" name="1">
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="4"> <el-col :span="4">
医院名称: 医院名称:
@@ -171,7 +180,7 @@ layout("/layouts/platform.html"){
</div> </div>
</el-col> </el-col>
<el-col :span="2"> <el-col :span="4">
操作: 操作:
<div> <div>
<el-button type="danger" size="small" <el-button type="danger" size="small"
@@ -180,6 +189,15 @@ layout("/layouts/platform.html"){
</el-button> </el-button>
</div> </div>
</el-col> </el-col>
<el-col :span="4">
复用:
<div>
<el-button type="primary" size="small"
:disabled="formData.healthCheckupProjectSubjects.length < 2"
@click="openReuseSubject(item)">复用套餐
</el-button>
</div>
</el-col>
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="24"> <el-col :span="24">
@@ -193,9 +211,18 @@ layout("/layouts/platform.html"){
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
<div class="s-options-list" style="margin-top: 10px;"> <div class="s-options-list" style="margin-top: 10px;">
<el-table :data="item.subjectMoneys" border size="small"> <el-table :data="item.subjectMoneys" border size="small">
<el-table-column label="序号" width="100px">
<template slot-scope="{row}">
<el-input v-model="row.serialNumber"
:value="row.serialNumber"
autosize
class="text-input"
data-type="option"
></el-input>
</template>
</el-table-column>
<el-table-column label="名称"> <el-table-column label="名称">
<template slot-scope="{row}"> <template slot-scope="{row}">
<el-input v-model="row.subjectMoneyName" autosize <el-input v-model="row.subjectMoneyName" autosize
@@ -225,6 +252,7 @@ layout("/layouts/platform.html"){
<template slot-scope="{row,$index}" slot="header"> <template slot-scope="{row,$index}" slot="header">
<el-button size="mini" type="primary" <el-button size="mini" type="primary"
@click="item.subjectMoneys.push({ @click="item.subjectMoneys.push({
serialNumber: item.subjectMoneys.length + 1,
money:'', money:'',
settlementMoney:'', settlementMoney:'',
subjectMoneyName:'', subjectMoneyName:'',
@@ -246,7 +274,8 @@ layout("/layouts/platform.html"){
</el-table-column> </el-table-column>
</el-table> </el-table>
</div> </div>
</el-card> </el-collapse-item>
</el-collapse>
<div class="s-operation"> <div class="s-operation">
<el-button size="small" type="primary" <el-button size="small" type="primary"
@click="formData.healthCheckupProjectSubjects.push({optionNameId:'', @click="formData.healthCheckupProjectSubjects.push({optionNameId:'',
@@ -327,7 +356,7 @@ layout("/layouts/platform.html"){
<qrcode :options="{ width: 400 }" :value="activityUrl"></qrcode> <qrcode :options="{ width: 400 }" :value="activityUrl"></qrcode>
</div> </div>
<span slot="footer" class="dialog-footer"> <span slot="footer" class="dialog-footer">
<el-button @click="codeDialogVisible = false" type="primary">关 闭</el-button> <el-button @click="closeCodeDialog" type="primary">关 闭</el-button>
</span> </span>
</el-dialog> </el-dialog>
@@ -343,11 +372,11 @@ layout("/layouts/platform.html"){
</template> </template>
<span slot="footer" class="dialog-footer"> <span slot="footer" class="dialog-footer">
<template v-if="subjectIndex!==null&&subjectIndex>=0"> <template v-if="subjectIndex!==null&&subjectIndex>=0">
<el-button @click="richTextDialog = false">关 闭</el-button> <el-button @click="closeRichTextDialog">关 闭</el-button>
<el-button type="primary" @click="getRichText">确 定</el-button> <el-button type="primary" @click="getRichText">确 定</el-button>
</template> </template>
<template v-else> <template v-else>
<el-button @click="richTextDialog = false" type="primary">关 闭</el-button> <el-button @click="closeRichTextDialog" type="primary">关 闭</el-button>
</template> </template>
</span> </span>
</el-dialog> </el-dialog>
@@ -364,11 +393,27 @@ layout("/layouts/platform.html"){
<condition-structure-dialog ref="conditionStructureDialog" @confirm="addCondition"></condition-structure-dialog> <condition-structure-dialog ref="conditionStructureDialog" @confirm="addCondition"></condition-structure-dialog>
<el-dialog :visible.sync="reuseSubjectDialogVisible" title="复用套餐" width="500px"
:close-on-click-modal="false" @closed="resetReuseSubject">
<el-alert title="复用会覆盖当前套餐的名称、说明、材料和套餐明细,保留当前位置的排序;提交项目后才会保存。"
type="warning" :closable="false" style="margin-bottom: 16px;"></el-alert>
<el-select v-model="reuseSubjectSourceIndex" placeholder="请选择当前项目中的其他套餐"
filterable style="width: 100%">
<el-option v-for="option in reuseSubjectOptions" :key="option.index"
:label="option.label" :value="option.index"></el-option>
</el-select>
<div slot="footer">
<el-button @click="cancelReuseSubject">取消</el-button>
<el-button type="primary" :disabled="reuseSubjectSourceIndex === null"
@click="confirmReuseSubject">确认复用</el-button>
</div>
</el-dialog>
<el-dialog :visible.sync="conditionStructureDialogVisible" title="条件构造器"> <el-dialog :visible.sync="conditionStructureDialogVisible" title="条件构造器">
<condition-group :group="conditionGroup" :field_options="fieldOptions" <condition-group :group="conditionGroup" :field_options="fieldOptions"
@remove="removeRootGroup"></condition-group> @remove="removeRootGroup"></condition-group>
<div slot="footer"> <div slot="footer">
<el-button @click="conditionStructureDialogVisible = false">取消</el-button> <el-button @click="cancelCnd">取消</el-button>
<el-button type="primary" @click="confirmCnd">确定</el-button> <el-button type="primary" @click="confirmCnd">确定</el-button>
</div> </div>
</el-dialog> </el-dialog>
@@ -376,8 +421,8 @@ layout("/layouts/platform.html"){
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("../common/ConditionStructure.js"){}#--> <!--#include("../common/ConditionStructure.js"){}#-->
const vue = new Vue({ const vue = new Vue({
el: '#app', el: '#app',
mixins: [initTableMixins], mixins: [initTableMixins],
data() { data() {
@@ -385,7 +430,7 @@ layout("/layouts/platform.html"){
showSubmit: true, showSubmit: true,
conditions: { conditions: {
method: "", method: "",
conditions: [{}], conditions: [{}]
}, },
viewData: {}, viewData: {},
subjectIndex: null, subjectIndex: null,
@@ -397,234 +442,375 @@ layout("/layouts/platform.html"){
formData: { formData: {
healthCheckupProjectSubjects: [] healthCheckupProjectSubjects: []
}, },
tableColumns: [ tableColumns: [{
{prop: 'year', label: '年度'}, prop: 'year',
{prop: 'name', label: '项目名称'}, label: '年度'
{prop: 'choiceTime', label: '选择时间'}, }, {
], prop: 'name',
label: '项目名称'
}, {
prop: 'choiceTime',
label: '选择时间'
}],
formRules: { formRules: {
name: [{required: true, message: '必填', trigger: ['blur', 'change']}], name: [{
choiceTime: [{required: true, message: '必填', trigger: ['blur', 'change']}],
activityGroupId: [{required: true, message: '必填', trigger: ['blur', 'change']}],
// cover: [{required: true, message: '必填', trigger: ['blur', 'change']}],
healthCheckupType: [{required: true, message: '必填', trigger: ['blur', 'change']}],
healthCheckupProjectSubjects: [{
required: true, required: true,
message: '必填', message: '必填',
trigger: ['blur', 'change'] trigger: ['blur', 'change']
}], }],
choiceTime: [{
required: true,
message: '必填',
trigger: ['blur', 'change']
}],
activityGroupId: [{
required: true,
message: '必填',
trigger: ['blur', 'change']
}],
// cover: [{required: true, message: '必填', trigger: ['blur', 'change']}],
healthCheckupType: [{
required: true,
message: '必填',
trigger: ['blur', 'change']
}],
healthCheckupProjectSubjects: [{
required: true,
message: '必填',
trigger: ['blur', 'change']
}]
}, },
deleteRowIds: [], deleteRowIds: [],
description: "", description: "",
codeDialogVisible: false, codeDialogVisible: false,
activityUrl: '', activityUrl: '',
rowData: {}, rowData: {},
subjectRowData: {}, subjectRowData: {},
subjectMoneyDialog: false, subjectMoneyDialog: false,
subjectMoneyIndex: null, subjectMoneyIndex: null,
hospitalIndex: null, hospitalIndex: null,
deleteSubjectIds: {}, deleteSubjectIds: [],
reuseSubjectDialogVisible: false,
reuseSubjectTarget: null,
reuseSubjectSourceIndex: null,
// 条件构造器相关 // 条件构造器相关
conditionStructureDialogVisible: false, conditionStructureDialogVisible: false,
// 可选字段列表 // 可选字段列表
fieldOptions: [ fieldOptions: [{
{label: "姓名", value: "username"}, label: "姓名",
{label: "工号", value: "loginname"}, value: "username"
{label: "性别", value: "sex"}, }, {
{label: "年龄", value: "age"}, label: "工号",
{label: "婚姻状况", value: "marriage"}, value: "loginname"
{label: "在职状态", value: "userState"}, }, {
{label: "编制类别", value: "preparedBy"}, label: "性别",
{label: "教职工类别", value: "personType"}, value: "sex"
], }, {
label: "年龄",
value: "age"
}, {
label: "婚姻状况",
value: "marriage"
}, {
label: "在职状态",
value: "userState"
}, {
label: "编制类别",
value: "preparedBy"
}, {
label: "教职工类别",
value: "personType"
}],
conditionGroup: { conditionGroup: {
logic: "AND", logic: "AND",
conditions: [], conditions: [],
groups: [] groups: []
} }
} };
}, },
components: { components: {
"drawer-user-scope": httpVueLoader("/components/module/activity/DrawerUserScope.vue"), "drawer-user-scope": httpVueLoader("/components/module/activity/DrawerUserScope.vue"),
"condition-structure-dialog": CONDITION_STRUCTURE_DIALOG "condition-structure-dialog": CONDITION_STRUCTURE_DIALOG
}, },
computed: {
reuseSubjectOptions() {
// 使用列表位置区分同名套餐,并排除正在接收复用内容的套餐。
return this.formData.healthCheckupProjectSubjects.map((item, index) => ({
item,
index,
label: (index + 1) + ' / ' + (item.optionName || '未命名套餐')
})).filter(option => option.item !== this.reuseSubjectTarget);
}
},
methods: { methods: {
closeCodeDialog() {
// 仅关闭当前弹框,不执行提交或保存操作。
this.$set(this, 'codeDialogVisible', false);
},
closeRichTextDialog() {
// 仅关闭当前弹框,不执行提交或保存操作。
this.$set(this, 'richTextDialog', false);
},
openReuseSubject(item) {
// 新建和编辑项目均可复用当前表单内的其他套餐,不读取历史项目。
if (this.formData.healthCheckupProjectSubjects.length < 2) return;
this.$set(this, 'reuseSubjectTarget', item);
this.$set(this, 'reuseSubjectSourceIndex', null);
this.$set(this, 'reuseSubjectDialogVisible', true);
},
cancelReuseSubject() {
// 取消只关闭选择窗口,确认复用前不改变套餐内容。
this.$set(this, 'reuseSubjectDialogVisible', false);
},
resetReuseSubject() {
// 关闭后释放当前套餐引用,避免下次打开沿用上次的选择。
this.$set(this, 'reuseSubjectTarget', null);
this.$set(this, 'reuseSubjectSourceIndex', null);
},
confirmReuseSubject() {
const subjects = this.formData.healthCheckupProjectSubjects;
const target = this.reuseSubjectTarget;
const source = subjects[this.reuseSubjectSourceIndex];
// 检查来源和目标仍在当前项目中,禁止将自身作为复制来源。
if (!target || !source || source === target || !subjects.includes(target)) {
this.$message.warning('请选择当前项目中的其他套餐');
return;
}
// 只复制业务字段并深拷贝材料、条件,保留目标排序且不带入主键或关联字段。
const copied = JSON.parse(JSON.stringify({
optionName: source.optionName || '',
description: source.description || '',
imgUrl: source.imgUrl || '',
files: source.files || [],
subjectMoneys: (source.subjectMoneys || []).map(row => ({
serialNumber: row.serialNumber,
subjectMoneyName: row.subjectMoneyName,
money: row.money,
settlementMoney: row.settlementMoney,
sort: row.sort,
matchCnd: row.matchCnd
}))
}));
// 编辑时记录被替换的已保存明细,提交时沿用现有删除流程,避免新旧明细同时保留。
(target.subjectMoneys || []).forEach(row => {
if (row.id && !this.deleteRowIds.includes(row.id)) {
this.deleteRowIds.push(row.id);
}
});
Object.keys(copied).forEach(key => {
this.$set(target, key, copied[key]);
});
this.$set(this, 'reuseSubjectDialogVisible', false);
this.$message.success('已复用套餐设置,请提交项目保存');
},
removeRootGroup() { removeRootGroup() {
// 重置根条件组 // 重置根条件组
this.updateFromData.conditionGroup = { this.updateFromData.conditionGroup = {
logic: "AND", logic: "AND",
conditions: [], conditions: [],
groups: [] groups: []
} };
}, },
dropdownCommand(command) { dropdownCommand(command) {
const {type, data} = command const {
type,
data
} = command;
if (type === 'view') { if (type === 'view') {
this.openView(data) this.openView(data);
} else if (type === 'created') { } else if (type === 'created') {
this.createUserList(data) this.createUserList(data);
} else if (type === 'renew') { } else if (type === 'renew') {
this.renewUserList(data) this.renewUserList(data);
} else if (type === 'reset') { } else if (type === 'reset') {
this.resetUserList(data) this.resetUserList(data);
} else if (type === 'edit') { } else if (type === 'edit') {
this.openEdit(data) this.openEdit(data);
} else if (type === 'delete') { } else if (type === 'delete') {
this.doDelete(data.id) this.doDelete(data.id);
} else if (type === 'code') { } else if (type === 'code') {
this.openCode(data.id) this.openCode(data.id);
} }
}, },
openAddSubjectMoney(row, index) { openAddSubjectMoney(row, index) {
row.index = index row.index = index;
this.subjectRowData = row this.subjectRowData = row;
this.subjectMoneyDialog = true this.subjectMoneyDialog = true;
}, },
addCondition(val) { addCondition(val) {
this.$set(this.formData.healthCheckupProjectSubjects[this.subjectMoneyIndex].subjectMoneys[this.rowData.index], 'matchCnd', val) this.$set(this.formData.healthCheckupProjectSubjects[this.subjectMoneyIndex].subjectMoneys[this.rowData.index], 'matchCnd', val);
}, },
openCnd(row, subjectIndex, hospitalIndex) { openCnd(row, subjectIndex, hospitalIndex) {
this.rowData = row this.rowData = row;
this.subjectMoneyIndex = subjectIndex this.subjectMoneyIndex = subjectIndex;
this.hospitalIndex = hospitalIndex this.hospitalIndex = hospitalIndex;
this.conditionStructureDialogVisible = true this.conditionStructureDialogVisible = true;
if (row.matchCnd) { if (row.matchCnd) {
this.conditionGroup = row.matchCnd this.conditionGroup = row.matchCnd;
} else { } else {
this.conditionGroup = { this.conditionGroup = {
logic: "AND", logic: "AND",
conditions: [], conditions: [],
groups: [] groups: []
} };
} }
// this.$refs.conditionStructureDialog.onOpen(row.matchCnd ? row.matchCnd : null) // this.$refs.conditionStructureDialog.onOpen(row.matchCnd ? row.matchCnd : null)
}, },
cancelCnd() {
// 通过 Vue 实例方法关闭可选条件弹框,避免内联事件中的 this 指向错误。
this.$set(this, 'conditionStructureDialogVisible', false);
},
// 条件构造器确认 // 条件构造器确认
confirmCnd() { confirmCnd() {
this.conditionStructureDialogVisible = false this.conditionStructureDialogVisible = false;
this.$set(this.formData.healthCheckupProjectSubjects[this.hospitalIndex].subjectMoneys[this.subjectMoneyIndex], 'matchCnd', this.conditionGroup) this.$set(this.formData.healthCheckupProjectSubjects[this.hospitalIndex].subjectMoneys[this.subjectMoneyIndex], 'matchCnd', this.conditionGroup);
}, },
createUserList(row) {
async createUserList(row) { const msg = '您确定要生成【' + row.name + '】体检名单吗?(该名单生成是按照创建时选择的可报名人员范围来生成)';
const msg = '您确定要生成【' + row.name + '】体检名单吗?(该名单生成是按照创建时选择的可报名人员范围来生成)' return Promise.resolve(this.$confirm(msg, '提示', {
const confirm = await this.$confirm(msg, '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}) })).then(confirm => {
if ('confirm' !== confirm) return if ('confirm' !== confirm) return;
const loading = this.$loading({ const loading = this.$loading({
lock: true, lock: true,
text: '数据更新中,请稍后...', text: '数据更新中,请稍后...',
spinner: 'el-icon-loading', spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)' background: 'rgba(0, 0, 0, 0.7)'
}); });
const resp = await this.$axios.post(loc() + '/createUserList', row) return this.$axios.post(loc() + '/createUserList', row).then(resp => {
if (resp.code === 0) { if (resp.code === 0) {
setTimeout(() => { setTimeout(() => {
loading.close() loading.close();
this.$message.success('操作成功') this.$message.success('操作成功');
this.pageData() this.pageData();
}, 1000) }, 1000);
} else { } else {
this.$message.warning(resp.msg) this.$message.warning(resp.msg);
} }
}).finally(() => {
loading.close();
});
});
}, },
async renewUserList(row) { renewUserList(row) {
const msg = '您确定要更新【' + row.name + '】的体检名单吗?(如可报名人员范围发生变化会删除已选择的人员信息)' const msg = '您确定要更新【' + row.name + '】的体检名单吗?(如可报名人员范围发生变化会删除已选择的人员信息)';
const confirm = await this.$confirm(msg, '提示', { return Promise.resolve(this.$confirm(msg, '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}) })).then(confirm => {
if ('confirm' !== confirm) return if ('confirm' !== confirm) return;
const loading = this.$loading({ const loading = this.$loading({
lock: true, lock: true,
text: '数据更新中,请稍后...', text: '数据更新中,请稍后...',
spinner: 'el-icon-loading', spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)' background: 'rgba(0, 0, 0, 0.7)'
}); });
const resp = await this.$axios.post(loc() + '/renewUserList', row) return this.$axios.post(loc() + '/renewUserList', row).then(resp => {
loading.close() loading.close();
if (resp.code === 0) { if (resp.code === 0) {
this.$message.success('操作成功') this.$message.success('操作成功');
this.pageData() this.pageData();
} else { } else {
this.$message.warning(resp.msg) this.$message.warning(resp.msg);
} }
}).finally(() => {
loading.close();
});
});
}, },
async resetUserList(row) { resetUserList(row) {
const msg = '您确定要重置【' + row.name + '】的体检名单吗?(该操作会将所有已选择的人员清空后,在进行生成)' const msg = '您确定要重置【' + row.name + '】的体检名单吗?(该操作会将所有已选择的人员清空后,在进行生成)';
const confirm = await this.$confirm(msg, '提示', { return Promise.resolve(this.$confirm(msg, '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}) })).then(confirm => {
if ('confirm' !== confirm) return if ('confirm' !== confirm) return;
const loading = this.$loading({ const loading = this.$loading({
lock: true, lock: true,
text: '数据更新中,请稍后...', text: '数据更新中,请稍后...',
spinner: 'el-icon-loading', spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)' background: 'rgba(0, 0, 0, 0.7)'
}); });
const resp = await this.$axios.post(loc() + '/resetUserList', row) return this.$axios.post(loc() + '/resetUserList', row).then(resp => {
loading.close() loading.close();
if (resp.code === 0) { if (resp.code === 0) {
this.$message.success('操作成功') this.$message.success('操作成功');
this.pageData() this.pageData();
} else { } else {
this.$message.warning(resp.msg) this.$message.warning(resp.msg);
} }
}).finally(() => {
loading.close();
});
});
}, },
openCode(id) { openCode(id) {
this.activityUrl = location.origin + "/platform/healthCheckup/project/mange" this.activityUrl = location.origin + "/platform/healthCheckup/h5/listParticulars?projectId=" + encodeURIComponent(id);
this.codeDialogVisible = true this.codeDialogVisible = true;
}, },
deleteSubject(row, index) { deleteSubject(row, index) {
this.formData.healthCheckupProjectSubjects.splice(index, 1) this.formData.healthCheckupProjectSubjects.splice(index, 1);
if (row.id) this.deleteSubjectIds.push(row.id) if (row.id) this.deleteSubjectIds.push(row.id);
}, },
deleteRow(row, index, subjectMoneyIndex) { deleteRow(row, index, subjectMoneyIndex) {
this.formData.healthCheckupProjectSubjects[subjectMoneyIndex].subjectMoneys.splice(index, 1) this.formData.healthCheckupProjectSubjects[subjectMoneyIndex].subjectMoneys.splice(index, 1);
if (row.id) this.deleteRowIds.push(row.id) if (row.id) this.deleteRowIds.push(row.id);
this.reloadSubjectMoneySerialNumber(this.formData.healthCheckupProjectSubjects[subjectMoneyIndex].subjectMoneys);
}, },
async doDelete(id) { reloadSubjectMoneySerialNumber(rowDetail) {
const confirm = await this.$confirm('确定要删除该项目吗?', '提示', {type: 'warning'}) //重新加载体检套餐序号
for (let i = 0; i < rowDetail.length; i++) {
rowDetail[i].serialNumber = i + 1;
}
},
doDelete(id) {
return Promise.resolve(this.$confirm('确定要删除该项目吗?', '提示', {
type: 'warning'
})).then(confirm => {
if (confirm) { if (confirm) {
const resp = await this.$axios.post(loc() + "/doDelete", {id}) return this.$axios.post(loc() + "/doDelete", {
id
}).then(resp => {
if (resp.code === 0) { if (resp.code === 0) {
this.pageData() this.pageData();
this.notifySuccess(resp.msg) this.notifySuccess(resp.msg);
} else { } else {
this.notifyWarning(resp.msg) this.notifyWarning(resp.msg);
}
} }
});
} else {}
});
}, },
async openEdit(row) { openEdit(row) {
this.formData = await this.findOne(row.id) return Promise.resolve(this.findOne(row.id)).then(resolvedValue => {
this.$refs.guava.edit() this.formData = resolvedValue;
this.$refs.guava.edit();
});
}, },
async openView(row) { openView(row) {
this.viewData = await this.findOne(row.id) return Promise.resolve(this.findOne(row.id)).then(resolvedValue => {
this.$refs.guava.view() this.viewData = resolvedValue;
this.$refs.guava.view();
});
}, },
async findOne(id) { findOne(id) {
const resp = await this.$axios.post(loc() + "/findOne", {id: id}) return this.$axios.post(loc() + "/findOne", {
id: id
}).then(resp => {
if (resp.code === 0) { if (resp.code === 0) {
resp.data.choiceTime = [resp.data.choiceTimeStart, resp.data.choiceTimeEnd] resp.data.choiceTime = [resp.data.choiceTimeStart, resp.data.choiceTimeEnd];
return resp.data return resp.data;
} else { } else {
this.notifyError("查询失败") this.notifyError("查询失败");
} }
});
}, },
async doAdd() { doAdd() {
const formValid = await this.$refs["form"].validate() return Promise.resolve(this.$refs["form"].validate()).then(formValid => {
if (formValid) { if (formValid) {
const loading = this.$loading({ const loading = this.$loading({
lock: true, lock: true,
@@ -632,72 +818,76 @@ layout("/layouts/platform.html"){
spinner: 'el-icon-loading', spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)' background: 'rgba(0, 0, 0, 0.7)'
}); });
const formData = clone(this.formData) const formData = clone(this.formData);
formData.choiceTimeStart = formData.choiceTime[0] formData.choiceTimeStart = formData.choiceTime[0];
formData.choiceTimeEnd = formData.choiceTime[1] formData.choiceTimeEnd = formData.choiceTime[1];
formData.healthCheckupProjectSubjects = JSON.stringify(this.formData.healthCheckupProjectSubjects) formData.healthCheckupProjectSubjects = JSON.stringify(this.formData.healthCheckupProjectSubjects);
formData.activityGroupName = this.activityGroupList.find(v => v.groupId === this.formData.activityGroupId).groupName formData.activityGroupName = this.activityGroupList.find(v => v.groupId === this.formData.activityGroupId)?.groupName;
formData.deleteRowIds = JSON.stringify(this.deleteRowIds) formData.deleteRowIds = JSON.stringify(this.deleteRowIds);
formData.deleteSubjectIds = JSON.stringify(this.deleteSubjectIds) formData.deleteSubjectIds = JSON.stringify(this.deleteSubjectIds);
const resp = await this.$axios.post("/platform/healthCheckup/project/mange/doAdd", formData) formData.friendlyReminderText = formData.friendlyReminderText || '';
loading.close() formData.smsMessage = formData.smsMessage || '';
return this.$axios.post("/platform/healthCheckup/project/mange/doAdd", formData).then(resp => {
loading.close();
if (resp.code === 0) { if (resp.code === 0) {
this.pageData() this.pageData();
this.$refs.guava.index() this.$refs.guava.index();
this.deleteRowIds = [] this.deleteRowIds = [];
this.deleteSubjectIds = [] this.deleteSubjectIds = [];
} else { } else {
this.notifyWarning(resp.msg) this.notifyWarning(resp.msg);
}
} }
}).finally(() => {
loading.close();
});
} else {}
});
}, },
openAdd() { openAdd() {
this.formData = { this.formData = {
name: null, name: null,
activityGroupId: null, activityGroupId: null,
choiceTime: null, choiceTime: null,
healthCheckupProjectSubjects: [ healthCheckupProjectSubjects: [{
{
optionName: '套餐1', optionName: '套餐1',
optionNameId: '', optionNameId: '',
optionSort: '1', optionSort: '1',
imgUrl: '', imgUrl: '',
subjectMoneys: [] subjectMoneys: []
} }]
] };
}
if (this.$refs.form) this.$refs.form.resetFields(); if (this.$refs.form) this.$refs.form.resetFields();
this.$refs.guava.edit() this.$refs.guava.edit();
}, },
openDescRichText(richText, sIdx) { openDescRichText(richText, sIdx) {
this.subjectIndex = sIdx this.subjectIndex = sIdx;
this.description = richText this.description = richText;
this.richTextDialog = true this.richTextDialog = true;
}, },
openViewDescRichText(richText) { openViewDescRichText(richText) {
this.subjectIndex = null this.subjectIndex = null;
this.description = richText this.description = richText;
this.richTextDialog = true this.richTextDialog = true;
}, },
getRichText() { getRichText() {
this.formData.healthCheckupProjectSubjects[this.subjectIndex].description = this.description this.formData.healthCheckupProjectSubjects[this.subjectIndex].description = this.description;
this.richTextDialog = false this.richTextDialog = false;
}, },
async getActivityGroup() { getActivityGroup() {
const {data} = await this.$axios.post('/platform/activity/basic/scope/getActivityUserScopeGroup') return this.$axios.post('/platform/activity/basic/scope/getActivityUserScopeGroup').then(({
this.activityGroupList = data data
}, }) => {
}, this.activityGroupList = data;
async created() { });
this.getActivityGroup()
this.pageData()
} }
}) },
created() {
this.getActivityGroup();
this.pageData();
}
});
</script> </script>
<!--# <!--#
} }
#--> #-->
@@ -3,6 +3,54 @@ layout("/layouts/platform.html"){
#--> #-->
<style>
.health-statistics-region { overflow: hidden; }
.health-statistics-region .actual-statistics-row { display: flex; width: 100%; }
.health-statistics-region .actual-statistics-row .actual-statistics-table { flex-shrink: 0; }
/* 延续主表滚动条占位的背景及外边框,保留统计表列宽和操作按钮位置。 */
.health-statistics-region .actual-statistics-gutter {
flex-shrink: 0;
align-self: stretch;
box-sizing: border-box;
background: #f5f7fa;
border-top: 1px solid #ebeef5;
border-right: 1px solid #ebeef5;
border-bottom: 1px solid #ebeef5;
}
.health-statistics-region .actual-statistics-gutter {
border-left: 1px solid #ebeef5;
}
/* 分隔线绘制在可见固定汇总层内,避免被固定列遮挡;2px与两行统计相接的双边框一致。 */
.health-statistics-region > .el-table--scrollable-y > .el-table__fixed-right > .el-table__fixed-footer-wrapper::after {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
width: 2px;
background: #ebeef5;
z-index: 4;
pointer-events: none;
}
.health-statistics-region .actual-statistics-table { border-top: 1px solid #ebeef5; }
.health-statistics-region .actual-statistics-table .el-table__body-wrapper { overflow-x: hidden; }
/* 单行统计隐藏横向滚动条后,固定列铺满实际行高,避免组件预留滚动条高度造成截断。 */
.health-statistics-region .actual-statistics-table .el-table__fixed-right {
top: 0;
bottom: 0;
height: auto !important;
box-shadow: none;
}
.health-statistics-region .actual-statistics-table .el-table__fixed-body-wrapper {
top: 0 !important;
}
.health-statistics-region .actual-statistics-table .el-table__fixed-right::before { display: none; }
.health-statistics-region .el-table__footer-wrapper td,
.health-statistics-region .actual-statistics-table td { background: #f5f7fa; }
</style>
<div class="platform" id="app" v-cloak> <div class="platform" id="app" v-cloak>
<guava padding="0 5%" ref="guava"> <guava padding="0 5%" ref="guava">
<template> <template>
@@ -54,10 +102,13 @@ layout("/layouts/platform.html"){
<template <template
v-if="$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN', 'BRANCH_UNION_CHAIRMAN'])"> v-if="$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN', 'BRANCH_UNION_CHAIRMAN'])">
<template v-if="projectInfo.healthCheckupType==='jzg'"> <template v-if="projectInfo.healthCheckupType==='jzg'">
<el-button v-if="$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN'])"
:disabled="!pageForm.projectId" @click="exportSelectedZip"
icon="el-icon-download" size="small" type="primary">导出已选名单Zip
</el-button>
<el-button :disabled="!pageForm.projectId" <el-button :disabled="!pageForm.projectId"
@click="exportReceiveDetail(true)" @click="exportReceiveDetail(true)"
icon="el-icon-printer" icon="el-icon-printer"
size="small" size="small"
type="primary">导出教职工已选名单 type="primary">导出教职工已选名单
</el-button> </el-button>
@@ -74,18 +125,18 @@ layout("/layouts/platform.html"){
type="primary" type="primary"
v-if="$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN'])">管理员代选择 v-if="$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN'])">管理员代选择
</el-button>--> </el-button>-->
<el-button @click="selectOptionByLastYear" <el-button @click="openLastYear"
icon="el-icon-printer" icon="el-icon-printer"
size="small" size="small"
type="primary" type="primary"
v-if="$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN'])">一键选择去年数据 v-if="$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN'])">按上年补齐未选人员
</el-button> </el-button>
<el-button @click="msgNotSelect" <!-- <el-button @click="msgNotSelect"
icon="el-icon-printer" icon="el-icon-printer"
size="small" size="small"
type="primary" type="primary"
v-if="$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN'])">给未选发送消息 v-if="$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN'])">给未选发送消息
</el-button> </el-button> -->
</template> </template>
<el-button :disabled="!pageForm.projectId" <el-button :disabled="!pageForm.projectId"
@@ -98,13 +149,14 @@ layout("/layouts/platform.html"){
</template> </template>
</table-tool> </table-tool>
<el-table :data="tableData" :size="tableSize" :summary-method="getSummaries" <div ref="statisticsRegion" class="health-statistics-region">
<el-table :height="statisticsHeight" :data="tableData" :size="tableSize" :summary-method="getSummaries"
@sort-change="pageOrder" class="vi-table" @sort-change="pageOrder" class="vi-table"
ref="table" row-key="id" show-summary ref="table" row-key="id" show-summary
style="width: 100%" v-loading="tableLoading"> style="width: 100%" v-loading="tableLoading">
<el-table-column :index="indexMethod" align="center" header-align="center" <el-table-column :index="indexMethod" align="center" header-align="center"
label="序号" type="index" label="序号" type="index"
width="80px"></el-table-column> width="150px"></el-table-column>
<el-table-column <el-table-column
:label="column.label" :label="column.label"
:prop="column.prop" :prop="column.prop"
@@ -135,6 +187,41 @@ layout("/layouts/platform.html"){
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<!-- 实际统计按整个项目维护,与上方按工会筛选的选择统计独立。 -->
<div v-if="actualProjectId" class="actual-statistics-row">
<el-table ref="actualTable" :data="[actualCounts]" :show-header="false"
:size="tableSize" :fit="false" class="vi-table actual-statistics-table"
v-loading="formLoading" :style="{width: actualTableWidth ? actualTableWidth + 'px' : '100%'}">
<el-table-column width="150px" align="center">
<template slot-scope="scope">实际体检统计</template>
</el-table-column>
<el-table-column v-for="(column, columnIndex) in tableColumns" :key="column.prop"
:width="statisticsColumnWidths[columnIndex + 1] || column.width || 100" align="center">
<template slot-scope="scope">
<template v-if="column.actualKey">
<el-input-number v-if="actualEditing" :value="actualDraft[column.actualKey]"
@input="setActualCount(column.actualKey, $event)"
:min="0" :max="2147483647" :precision="0" :controls="false"
size="mini" style="width: 100%"></el-input-number>
<span v-else>{{actualCounts[column.actualKey] == null ? '未录入' : actualCounts[column.actualKey] + ' 人'}}</span>
</template>
<span v-else>{{column.prop === 'unionName' ? '' : '—'}}</span>
</template>
</el-table-column>
<el-table-column width="200px" align="center" fixed="right">
<template slot-scope="scope" v-if="$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN'])">
<template v-if="actualEditing">
<el-button size="mini" type="primary" :loading="formLoading" @click="saveActualCounts">保存</el-button>
<el-button size="mini" :disabled="formLoading" @click="cancelActualEdit">取消</el-button>
</template>
<el-button v-else size="mini" type="primary" :disabled="tableLoading" @click="editActualCounts">编辑</el-button>
</template>
</el-table-column>
</el-table>
<div v-if="actualGutterWidth" class="actual-statistics-gutter" aria-hidden="true"
:style="{width: actualGutterWidth + 'px'}"></div>
</div>
</div>
</el-card> </el-card>
</template> </template>
@@ -222,20 +309,43 @@ layout("/layouts/platform.html"){
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-row justify="end" type="flex"> <el-row justify="end" type="flex">
<el-button @click="selectByAdminDialogVisible=false">取消</el-button> <el-button @click="cancelAdminSelection">取消</el-button>
<el-button @click="doSelectByAdmin" type="primary" :loading="loading">提交</el-button> <el-button @click="doSelectByAdmin" type="primary" :loading="loading">提交</el-button>
</el-row> </el-row>
</el-dialog> </el-dialog>
<el-dialog :visible.sync="selectLastYearProject" title="选择去年项目"
width="35%">
<el-form label-position="right" label-width="120px">
<el-form-item label="体检项目">
<el-select style="width: 100%" v-model="lastYearProjectId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in lastYearProjectSubjectOptions"></el-option>
</el-select>
</el-form-item>
</el-form>
<el-row>
<span style="color: red; padding-left: 52px;">温馨提示:系统默认选择去年的体检项目,新入职教职工选用本年校医院套餐</span>
</el-row>
<el-row justify="end" type="flex" style="margin-top: 15px">
<el-button @click="cancelLastYearSelection">取消</el-button>
<el-button @click="selectOptionByLastYear" type="primary" :loading="loading">提交</el-button>
</el-row>
</el-dialog>
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
const vue = new Vue({ const vue = new Vue({
el: '#app', el: '#app',
mixins: [initTableMixins], mixins: [initTableMixins],
data() { data() {
return { return {
pageForm: { pageForm: {
year: moment().format('YYYY'), year: moment().format('YYYY')
}, },
pageFormUnion: { pageFormUnion: {
pageNumber: 1, pageNumber: 1,
@@ -243,7 +353,7 @@ layout("/layouts/platform.html"){
totalCount: null, totalCount: null,
searchName: 'u.username', searchName: 'u.username',
//0:已选人员页面 1:未选人员页面 //0:已选人员页面 1:未选人员页面
isSelected: '', isSelected: ''
}, },
units: [], units: [],
unions: [], unions: [],
@@ -251,163 +361,357 @@ layout("/layouts/platform.html"){
receive_tableColumns: [], receive_tableColumns: [],
receive_tableData: [], receive_tableData: [],
clearable: false, clearable: false,
tableColumns: [ tableColumns: [{
{prop: 'unionName', label: '所属工会'}, prop: 'unionName',
{prop: 'sumCount', label: '本次体检人数'}, label: '所属工会'
], }, {
prop: 'sumCount',
label: '本次体检人数'
}],
projectInfo: {}, projectInfo: {},
statisticsHeight: 360,
actualTableWidth: 0,
actualGutterWidth: 0,
statisticsColumnWidths: [],
actualCounts: {},
actualDraft: {},
actualProjectId: null,
actualEditing: false,
statisticsRequest: 0,
selectByAdminDialogVisible: false, selectByAdminDialogVisible: false,
projectSubjectOptions: [], projectSubjectOptions: [],
campusOptions: [], campusOptions: [],
noSelectOptionId: null, noSelectOptionId: null,
campus: null, campus: null,
loading: false, loading: false,
selectLastYearProject: false,
lastYearProjectId: null,
lastYearProjectSubjectOptions: [],
isEmployedOptions: [{
value: '是',
label: '是'
}, {
value: '否',
label: '否'
}]
};
},
watch: {
tableData() {
this.queueStatisticsLayout();
},
tableColumns() {
this.queueStatisticsLayout();
},
actualProjectId() {
this.queueStatisticsLayout();
},
actualEditing() {
this.queueStatisticsLayout();
} }
}, },
methods: { methods: {
async msgNotSelect() { exportSelectedZip() {
const confirm = await this.$confirm('请确定未选择的教职工发送提醒短信?', '提示', { // 当前项目全部已选人员按医院打包,不带入页面分工会筛选条件。
if (!this.pageForm.projectId) { this.$message.warning('请选择体检项目'); return; }
window.open(loc() + '/exportSelectedZip?projectId=' + encodeURIComponent(this.pageForm.projectId));
},
cancelAdminSelection() {
// 仅关闭当前弹框,不执行提交或保存操作。
this.$set(this, 'selectByAdminDialogVisible', false);
},
cancelLastYearSelection() {
// 仅关闭当前弹框,不执行提交或保存操作。
this.$set(this, 'selectLastYearProject', false);
},
// 动态医院列和输入控件渲染后,按可用视口高度计算主表高度。
queueStatisticsLayout() {
this.$nextTick(() => {
this.layoutStatistics();
});
},
layoutStatistics() {
const region = this.$refs.statisticsRegion;
const table = this.$refs.table;
if (!region || !table || !region.offsetHeight) return;
const actual = this.$refs.actualTable;
const footerHeight = actual ? actual.$el.offsetHeight : 0;
const height = Math.max(180, Math.floor(window.innerHeight - region.getBoundingClientRect().top - footerHeight - 24));
if (height !== this.statisticsHeight) this.statisticsHeight = height;
this.$nextTick(() => {
if (!this.$refs.table) return;
table.doLayout();
this.$nextTick(() => {
if (!this.$refs.table) return;
// 扣除主表纵向滚动条占位,底部表使用主表实际列宽,避免统计错列。
const widths = table.columns.map(column => column.realWidth || column.width || 100);
if (JSON.stringify(widths) !== JSON.stringify(this.statisticsColumnWidths)) this.statisticsColumnWidths = widths;
// 底部补齐与主表一致的滚动条占位;无纵向滚动条时占位归零。
const gutterWidth = table.layout.scrollY ? table.layout.gutterWidth : 0;
if (gutterWidth !== this.actualGutterWidth) this.actualGutterWidth = gutterWidth;
const width = table.$el.clientWidth - gutterWidth;
if (width !== this.actualTableWidth) this.actualTableWidth = width;
this.bindStatisticsScroll();
this.$nextTick(() => {
if (this.$refs.actualTable) this.$refs.actualTable.doLayout();
this.syncStatisticsScroll();
});
});
});
},
// 仅主表数据区滚动;其横向滚动条同时带动底部实际统计行。
bindStatisticsScroll() {
const body = this.$refs.table && this.$refs.table.bodyWrapper;
if (this.statisticsScrollBody === body) return;
if (this.statisticsScrollBody) this.statisticsScrollBody.removeEventListener('scroll', this.syncStatisticsScroll);
this.statisticsScrollBody = body;
if (body) body.addEventListener('scroll', this.syncStatisticsScroll, {
passive: true
});
},
syncStatisticsScroll() {
const actual = this.$refs.actualTable;
if (actual && this.statisticsScrollBody) actual.bodyWrapper.scrollLeft = this.statisticsScrollBody.scrollLeft;
},
msgNotSelect() {
return Promise.resolve(this.$confirm('请确定未选择的教职工发送提醒短信?', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}) })).then(confirm => {
if (confirm === "confirm") { if (confirm === "confirm") {
this.tableLoading = true this.tableLoading = true;
const resp = await $.get(loc() + '/msgNotSelect', { return Promise.resolve($.get(loc() + '/msgNotSelect', {
projectId: this.pageForm.projectId projectId: this.pageForm.projectId
}) })).then(resp => {
if (resp.code === 0) { if (resp.code === 0) {
setTimeout(() => { setTimeout(() => {
this.doSearch() this.doSearch();
this.tableLoading = false this.tableLoading = false;
this.notifySuccess(resp.msg) this.notifySuccess(resp.msg);
}, 2000) }, 2000);
} else { } else {
this.notifyWarning(resp.msg) this.notifyWarning(resp.msg);
}
} }
}).finally(() => {
this.tableLoading = false;
});
} else {}
});
}, },
async doSelectByAdmin() { doSelectByAdmin() {
if (!this.noSelectOptionId || !this.campus) { if (!this.noSelectOptionId || !this.campus) {
this.notifyWarning('请选择套餐/院区') this.notifyWarning('请选择套餐/院区');
return return;
} }
const {optionName} = this.projectSubjectOptions.find(v => v.id === this.noSelectOptionId) const {
optionName
const confirm = await this.$confirm('请确定是否把【' + optionName + '】套餐赋给未选择的教职工?', '提示', { } = this.projectSubjectOptions.find(v => v.id === this.noSelectOptionId);
return Promise.resolve(this.$confirm('请确定是否把【' + optionName + '】套餐赋给未选择的教职工?', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}) })).then(confirm => {
if (confirm === "confirm") { if (confirm === "confirm") {
this.loading = true this.loading = true;
const resp = await $.get(loc() + '/doSelectByAdmin', { return Promise.resolve($.get(loc() + '/doSelectByAdmin', {
optionId: this.noSelectOptionId, optionId: this.noSelectOptionId,
campus: this.campus, campus: this.campus,
projectId: this.pageForm.projectId projectId: this.pageForm.projectId
}) })).then(resp => {
if (resp.code === 0) { if (resp.code === 0) {
setTimeout(() => { setTimeout(() => {
this.doSearch() this.doSearch();
this.loading = false this.loading = false;
this.selectByAdminDialogVisible = false this.selectByAdminDialogVisible = false;
this.notifySuccess(resp.msg) this.notifySuccess(resp.msg);
}, 2000) }, 2000);
} else { } else {
this.notifyWarning(resp.msg) this.notifyWarning(resp.msg);
} }
} }).finally(() => {
this.loading = false;
});
} else {}
});
}, },
async selectOptionByLastYear() { selectOptionByLastYear() {
const confirm = await this.$confirm('请确定是否把没有选择的教职工统一选择去年的数据?', '提示', { return Promise.resolve(this.$confirm('请确定是否把没有选择的教职工统一选择去年的数据?', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}) })).then(confirm => {
if (!this.lastYearProjectId) {
this.$message().error('请选择上年度体检项目');
}
if (confirm === "confirm") { if (confirm === "confirm") {
const resp = await this.$axios.post(loc() + '/selectOptionByLastYear', { return this.$axios.post(loc() + '/selectOptionByLastYear', {
projectId: this.pageForm.projectId projectId: this.pageForm.projectId,
}) lastYearProjectId: this.lastYearProjectId
}).then(resp => {
if (resp.code === 0) { if (resp.code === 0) {
this.doSearch() this.lastYearProjectId = '';
this.notifySuccess(resp.msg) this.selectLastYearProject = false;
this.doSearch();
this.notifySuccess(resp.msg);
} else { } else {
this.notifyWarning(resp.msg) this.notifyWarning(resp.msg);
}
} }
});
} else {}
});
}, },
selectOptionByAdmin() { selectOptionByAdmin() {
this.noSelectOptionId = null this.noSelectOptionId = null;
this.selectByAdminDialogVisible = true this.selectByAdminDialogVisible = true;
}, },
async yearChange() { yearChange() {
const resp = await this.$axios.post("/platform/healthCheckup/project/mange/getHealthCheckupProject", {year: this.pageForm.year}) const year = this.pageForm.year;
// 清空旧项目状态,年度无项目时不能继续显示或编辑上一次统计。
this.$set(this.pageForm, 'projectId', null);
this.projectSubjectOptions = [];
this.projectInfo = {};
this.pageData();
return this.$axios.post('/platform/healthCheckup/project/mange/getHealthCheckupProject', {
year: year
}).then(resp => {
if (year !== this.pageForm.year) return;
if (resp.code === 0) { if (resp.code === 0) {
this.projectOptions = resp.data this.projectOptions = resp.data || [];
if (resp.data && resp.data.length > 0) { this.$set(this.pageForm, 'projectId', this.projectOptions.length ? this.projectOptions[0].id : null);
this.$set(this.pageForm, "projectId", resp.data[0].id) return this.getHealthCheckupSubject();
} else {
this.$set(this.pageForm, "projectId", null)
} }
await this.getHealthCheckupSubject() this.notifyError(resp.msg);
} else {
this.notifyError(resp.msg)
}
},
async getHealthCheckupSubject() {
this.projectSubjectOptions = []
const resp = await this.$axios.post("/platform/healthCheckup/project/mange/findOne", {id: this.pageForm.projectId})
if (resp.code === 0) {
if (resp.data) {
this.projectInfo = resp.data
this.projectSubjectOptions = resp.data.healthCheckupProjectSubjects
}
} else {
this.notifyError(resp.msg)
}
this.doSearch()
},
async queryCampus() {
const resp = await this.$axios.post("/platform/healthCheckup/campus/queryCampus")
if (resp.code === 0) {
this.campusOptions = resp.data
} else {
this.notifyError(resp.msg)
}
},
async pageData() {
this.tableColumns = []
const loading = this.$loading({
lock: true,
text: '努力加载中。。。',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
}); });
},
this.tableColumns.push( getHealthCheckupSubject() {
{prop: 'unionName', label: '所属工会'}, const projectId = this.pageForm.projectId;
{prop: 'sumCount', label: '本次体检人数'} this.statisticsRequest++;
) this.actualProjectId = null;
if (this.projectSubjectOptions && this.projectSubjectOptions.length > 0) { this.actualEditing = false;
this.projectSubjectOptions.forEach(v => { this.tableData = [];
this.tableColumns.push({prop: v.optionName, label: v.optionName}) this.projectSubjectOptions = [];
}) this.projectInfo = {};
if (!projectId) {
this.tableLoading = false;
return Promise.resolve();
} }
this.tableColumns.push( return this.$axios.post('/platform/healthCheckup/project/mange/findOne', {
{prop: "totalCount", label: "选取人数"}, id: projectId
{prop: "unselectedTeacherSum", label: "未选人数"} }).then(resp => {
) if (projectId !== this.pageForm.projectId) return;
if (!this.pageForm.projectId) { if (resp.code === 0 && resp.data) {
this.tableData = [] this.projectInfo = resp.data;
} this.projectSubjectOptions = resp.data.healthCheckupProjectSubjects || [];
this.doSearch();
const resp = await this.$axios.post(loc() + '/pageData', this.pageForm) } else this.notifyError(resp.msg);
});
},
queryCampus() {
return this.$axios.post("/platform/healthCheckup/campus/queryCampus").then(resp => {
if (resp.code === 0) { if (resp.code === 0) {
this.tableData = resp.data.tableList this.campusOptions = resp.data;
} else {
this.notifyError(resp.msg);
} }
loading.close() });
},
// 同时加载选择统计和项目实际统计;请求序号防止快速切换项目时旧响应覆盖新数据。
pageData() {
const projectId = this.pageForm.projectId;
const request = ++this.statisticsRequest;
this.actualEditing = false;
this.actualProjectId = null;
this.tableData = [];
this.tableColumns = [{
prop: 'unionName',
label: '所属工会'
}, {
prop: 'sumCount',
label: '本次体检人数',
actualKey: '__total__'
}];
(this.projectSubjectOptions || []).forEach(item => {
this.tableColumns.push({
prop: item.optionName,
label: item.optionName,
actualKey: item.id
});
});
this.tableColumns.push({
prop: 'totalCount',
label: '选取人数'
}, {
prop: 'unselectedTeacherSum',
label: '未选人数'
});
if (!projectId) {
this.tableLoading = false;
return;
}
this.tableLoading = true;
Promise.all([this.$axios.post(loc() + '/pageData', this.pageForm), this.$axios.post(loc() + '/actualStatistics', {
projectId: projectId
})]).then(([selection, actual]) => {
if (request !== this.statisticsRequest || projectId !== this.pageForm.projectId) return;
if (selection.code === 0) this.tableData = selection.data.tableList;else this.notifyError(selection.msg);
if (actual.code === 0) {
this.actualCounts = actual.data;
this.actualProjectId = projectId;
} else this.notifyError(actual.msg);
}).finally(() => {
if (request === this.statisticsRequest) this.tableLoading = false;
}).finally(() => {
this.tableLoading = false;
});
},
// 仅编辑已加载项目的快照,未录入项需明确填写,避免自动将空值记为零。
editActualCounts() {
if (this.actualProjectId !== this.pageForm.projectId) return;
this.actualDraft = Object.assign({}, this.actualCounts);
this.actualEditing = true;
},
setActualCount(key, value) {
this.$set(this.actualDraft, key, value);
},
cancelActualEdit() {
this.actualEditing = false;
this.actualDraft = {};
},
// 整行保存项目总人数和各医院人数;零有效,空值、负数和小数不能提交。
saveActualCounts() {
const projectId = this.actualProjectId;
if (!projectId || projectId !== this.pageForm.projectId || this.formLoading) return;
const counts = {};
const columns = this.tableColumns.filter(column => column.actualKey);
if (columns.some(column => !Number.isInteger(this.actualDraft[column.actualKey]) || this.actualDraft[column.actualKey] < 0 || this.actualDraft[column.actualKey] > 2147483647)) {
this.notifyWarning('请完整填写本次体检人数及各医院人数,人数必须为非负整数');
return;
}
// 医院合计只能包含医院选项,不能将本次体检总人数重复累加。
const hospitalTotal = columns.filter(column => column.actualKey !== '__total__').reduce((total, column) => total + this.actualDraft[column.actualKey], 0);
if (hospitalTotal > this.actualDraft.__total__) {
this.notifyWarning('各医院人数合计不能大于本次体检人数');
return;
}
columns.forEach(column => {
counts[column.actualKey] = this.actualDraft[column.actualKey];
});
this.formLoading = true;
this.$axios.post(loc() + '/saveActualStatistics', {
projectId: projectId,
counts: JSON.stringify(counts)
}).then(res => {
if (res.code === 0) {
if (projectId === this.actualProjectId && projectId === this.pageForm.projectId) {
this.actualCounts = res.data;
this.actualEditing = false;
}
this.notifySuccess('实际体检统计已保存');
} else this.notifyError(res.msg);
}).finally(() => {
this.formLoading = false;
});
}, },
pageNumberChange(val) { pageNumberChange(val) {
this.pageFormUnion.pageNumber = val; this.pageFormUnion.pageNumber = val;
@@ -417,69 +721,92 @@ layout("/layouts/platform.html"){
this.pageFormUnion.pageSize = val; this.pageFormUnion.pageSize = val;
this.pageUnionData(); this.pageUnionData();
}, },
async flushUnits() { flushUnits() {
this.$set(this.pageForm, "unitId", "") this.$set(this.pageForm, "unitId", "");
if (this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])) { if (this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])) {
this.units = await this.$businessTool.listUnit(this.pageForm.unionId) return Promise.resolve(this.$businessTool.listUnit(this.pageForm.unionId)).then(resolvedValue => {
this.units = resolvedValue;
});
} else { } else {
this.units = await this.$businessTool.listUnit() return Promise.resolve(this.$businessTool.listUnit()).then(resolvedValue => {
this.units = resolvedValue;
});
} }
}, },
async init() { init() {
if (this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])) { if (this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])) {
this.unions = await this.$businessTool.listUnion() return Promise.resolve(this.$businessTool.listUnion()).then(resolvedValue => {
this.clearable = true this.unions = resolvedValue;
this.clearable = true;
return Promise.resolve(this.yearChange()).then(() => {
return Promise.resolve(this.queryCampus()).then(() => {});
});
});
} else { } else {
this.unions = await this.$businessTool.listUnion(this.$store.state.user.union.id) return Promise.resolve(this.$businessTool.listUnion(this.$store.state.user.union.id)).then(resolvedValue => {
this.$set(this.pageForm, "unionId", this.unions[0].id) this.unions = resolvedValue;
this.$set(this.pageForm, "unionId", this.unions[0].id);
return Promise.resolve(this.yearChange()).then(() => {
return Promise.resolve(this.queryCampus()).then(() => {});
});
});
} }
await this.yearChange()
await this.queryCampus()
}, },
//查看未选择人数 //查看未选择人数
async openUnclaimed(unionId) { openUnclaimed(unionId) {
this.pageFormUnion.isSelected = '1' this.pageFormUnion.isSelected = '1';
this.pageFormUnion.unionId = unionId this.pageFormUnion.unionId = unionId;
this.pageFormUnion.projectId = this.pageForm.projectId this.pageFormUnion.projectId = this.pageForm.projectId;
await this.pageUnionData(); return Promise.resolve(this.pageUnionData()).then(() => {});
}, },
//查看已选人员 //查看已选人员
async openView(unionId) { openView(unionId) {
this.pageFormUnion.isSelected = '0' this.pageFormUnion.isSelected = '0';
this.pageFormUnion.unionId = unionId this.pageFormUnion.unionId = unionId;
this.pageFormUnion.projectId = this.pageForm.projectId this.pageFormUnion.projectId = this.pageForm.projectId;
await this.pageUnionData(); return Promise.resolve(this.pageUnionData()).then(() => {});
}, },
async pageUnionData() { pageUnionData() {
const resp = await this.$axios.post(loc() + '/receivePageData', this.pageFormUnion) return this.$axios.post(loc() + '/receivePageData', this.pageFormUnion).then(resp => {
if (resp.code === 0) { if (resp.code === 0) {
this.$refs.guava.view() this.$refs.guava.view();
this.receive_tableColumns = resp.data.label this.receive_tableColumns = resp.data.label;
this.receive_tableData = resp.data.list.list this.receive_tableData = resp.data.list.list;
this.pageFormUnion.totalCount = resp.data.list.totalCount this.pageFormUnion.totalCount = resp.data.list.totalCount;
} }
});
}, },
doUnionSearch() { doUnionSearch() {
this.pageFormUnion.pageNumber = 1 this.pageFormUnion.pageNumber = 1;
this.pageUnionData(); this.pageUnionData();
}, },
//按分工会导出已选名单 //按分工会导出已选名单
exportReceiveDetail(flag) { exportReceiveDetail(flag) {
const {year, projectId, unionId} = this.pageForm const {
window.open(loc() + '/exportReceiveDetail?year=' + year + '&projectId=' + projectId + '&unionId=' + (unionId ? unionId : '') + '&flag=' + flag) year,
projectId,
unionId
} = this.pageForm;
window.open(loc() + '/exportReceiveDetail?year=' + year + '&projectId=' + projectId + '&unionId=' + (unionId ? unionId : '') + '&flag=' + flag);
}, },
//导出家属信息 //导出家属信息
exportUserCompanion() { exportUserCompanion() {
const {year, projectId, unionId} = this.pageForm const {
window.open(loc() + '/exportUserCompanion?year=' + year + '&projectId=' + projectId + '&unionId=' + (unionId ? unionId : '')) year,
projectId,
unionId
} = this.pageForm;
window.open(loc() + '/exportUserCompanion?year=' + year + '&projectId=' + projectId + '&unionId=' + (unionId ? unionId : ''));
}, },
getSummaries(param) { getSummaries(param) {
const {columns, data} = param; const {
columns,
data
} = param;
const sums = []; const sums = [];
columns.forEach((column, index) => { columns.forEach((column, index) => {
if (index === 0) { if (index === 0) {
sums[index] = '总计'; sums[index] = '院区选择统计';
return; return;
} }
const values = data.map(item => Number(item[column.property])); const values = data.map(item => Number(item[column.property]));
@@ -498,12 +825,40 @@ layout("/layouts/platform.html"){
} }
}); });
return sums; return sums;
},
openLastYear() {
return this.$axios.post("/platform/healthCheckup/project/mange/getHealthCheckupProject", {
year: this.pageForm.year - 1
}).then(resp => {
if (resp.code === 0) {
if (resp.data.length > 0) {
this.lastYearProjectSubjectOptions = resp.data;
this.selectLastYearProject = true;
} else {
this.$message.warning("无上一年度体检项目");
}
}
});
} }
}, },
async created() { mounted() {
this.init() this.queueStatisticsLayout();
window.addEventListener('resize', this.queueStatisticsLayout);
// 侧栏宽度变化、筛选区换行和详情返回时同步重新布局。
this.statisticsResizeObserver = new ResizeObserver(() => {
this.queueStatisticsLayout();
});
this.statisticsResizeObserver.observe(this.$el);
},
beforeDestroy() {
window.removeEventListener('resize', this.queueStatisticsLayout);
if (this.statisticsResizeObserver) this.statisticsResizeObserver.disconnect();
if (this.statisticsScrollBody) this.statisticsScrollBody.removeEventListener('scroll', this.syncStatisticsScroll);
},
created() {
this.init();
} }
}) });
</script> </script>
@@ -29,6 +29,25 @@ layout("/layouts/platform_h5.html"){
<table-list api="/platform/healthCheckup/h5/pageData" :page_form.sync="pageForm" ref="tableListRef" <table-list api="/platform/healthCheckup/h5/pageData" :page_form.sync="pageForm" ref="tableListRef"
@ready="doSearch" img="cover"> @ready="doSearch" img="cover">
<template v-slot="{index,row}"> <template v-slot="{index,row}">
<table-column label="项目名称">
<div style="display: flex;
justify-content: space-between;
align-items: flex-start; /* 关键:改成顶部对齐 */
width: 100%;">
<span style="word-break: break-all;
white-space: normal;
flex: 1;
padding-right: 5px;">{{ row.name }}</span>
<span style="margin-left: 8px; font-size: 14px; white-space: nowrap;">
<span v-if="row.selectCount > 0" style="color: rgb(29 179 76);">
已报名
</span>
<span v-if="row.selectCount == 0" style="color: #ff0000;">
未报名
</span>
</span>
</div>
</table-column>
<table-column label="开始时间"> <table-column label="开始时间">
{{$moment(row.choiceTimeStart).format('MM/DD HH:mm')}} {{$moment(row.choiceTimeStart).format('MM/DD HH:mm')}}
</table-column> </table-column>
@@ -37,23 +56,30 @@ layout("/layouts/platform_h5.html"){
</table-column> </table-column>
</template> </template>
<template #actions="{index,row}"> <template #actions="{index,row}">
<template v-if="$moment().isBefore($moment(row.choiceTimeEnd))"> <template v-if="$moment(row.choiceTimeStart).isBefore($moment()) && $moment().isBefore($moment(row.choiceTimeEnd))">
<div class="action-btn" @click="onView(row)"> <div class="action-btn" style="text-align: right" @click="onView(row)">
<i class="fa fa-edit"></i> <i class="fa fa-edit"></i>
<span>去报名</span> <span>去报名</span>
</div> </div>
</template> </template>
<template v-else>
<div class="action-btn" @click="look(row)">
<van-icon name="eye-o" />
<span>查看</span>
</div>
</template>
</template> </template>
</table-list> </table-list>
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
const vue = new Vue({ const vue = new Vue({
healthCheckupHistory: true,
mixins: [healthCheckupHistoryMixin],
el: "#app", el: "#app",
store, store,
components: { components: {},
},
data() { data() {
return { return {
yearList: [], yearList: [],
@@ -62,10 +88,11 @@ layout("/layouts/platform_h5.html"){
pageSize: 10, pageSize: 10,
totalCount: 0, totalCount: 0,
year: "", year: "",
status: "ongoing", // 默认为进行中 status: "ongoing",
// 默认为进行中
name: "" // 添加搜索名称字段 name: "" // 添加搜索名称字段
},
} }
};
}, },
methods: { methods: {
// 查看项目详情 // 查看项目详情
@@ -73,7 +100,6 @@ layout("/layouts/platform_h5.html"){
// 这里可以添加查看项目详情的逻辑 // 这里可以添加查看项目详情的逻辑
console.log('查看项目详情:', row); console.log('查看项目详情:', row);
}, },
onView(row) { onView(row) {
/* if(row.selectCount > 0) { /* if(row.selectCount > 0) {
vant.Dialog.alert({ vant.Dialog.alert({
@@ -90,14 +116,16 @@ layout("/layouts/platform_h5.html"){
return; return;
} }
this.$pjaxReplace("/platform/healthCheckup/h5/projectManageForm?projectId=" + row.id) // this.navigateHealthCheckup("/platform/healthCheckup/h5/projectManageForm?projectId=" + row.id)
this.navigateHealthCheckup("/platform/healthCheckup/h5/listParticulars?projectId=" + row.id);
sessionStorage.setItem("friendlyReminderStatus", 0);
}, },
doSearch() { doSearch() {
this.$nextTick(() => { this.$nextTick(() => {
this.pageForm.pageNumber = 1 this.pageForm.pageNumber = 1;
this.pageForm.totalCount = 0 this.pageForm.totalCount = 0;
this.$refs.tableListRef.doSearch() this.$refs.tableListRef.doSearch();
}) });
}, },
// 新增状态切换处理方法 // 新增状态切换处理方法
onStatusChange() { onStatusChange() {
@@ -105,17 +133,23 @@ layout("/layouts/platform_h5.html"){
}, },
initData() { initData() {
for (let i = new Date().getFullYear() - 10; i <= new Date().getFullYear(); i++) { for (let i = new Date().getFullYear() - 10; i <= new Date().getFullYear(); i++) {
this.yearList.unshift({value: i, text: i + "年"}) this.yearList.unshift({
value: i,
text: i + "年"
});
} }
this.$set(this.pageForm, "year", this.yearList[0].value) this.$set(this.pageForm, "year", this.yearList[0].value);
// 初始化状态 // 初始化状态
this.$set(this.pageForm, "status", "ongoing") this.$set(this.pageForm, "status", "ongoing");
}, },
look(row) {
this.navigateHealthCheckup("/platform/healthCheckup/h5/physicalExaminationList?projectId=" + row.id);
}
}, },
created() { created() {
this.initData() this.initData();
} }
}) });
</script> </script>
<!--# <!--#
@@ -0,0 +1,116 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style scoped>
.buttonClass {
height: 93px;
margin: 8px 0px;
border-radius: 20px
}
.van-dialog__header {
color: red;
font-size: 20px;
}
.dialog-content > div {
padding: 8px 20px;
}
</style>
<div id="app">
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="报名详情" placeholder
fixed></van-nav-bar>
<div style="padding: 15px 20px">
<van-button round type="primary" size="large" color="#0db776" class="buttonClass" @click="userMessage"><van-icon name="user-o" size="27px"/> 基础信息查询</van-button>
<van-button round type="primary" size="large" color="#2cabdd" class="buttonClass" @click="selectPhysicalExaminationHospital"><van-icon name="records-o" size="27px"/> 选择体检医院</van-button>
<van-button round type="primary" size="large" color="#eca807" class="buttonClass" @click="minePhysicalExaminationHospital"><van-icon name="idcard" size="27px"/> 我的体检医院</van-button>
</div>
<van-dialog v-model="show" title="温馨提醒" @confirm="confirmClick"
:confirm-button-text="confirmButtonText"
:before-close="confirmStatusFun"
:confirm-button-disabled="confirmDisabled">
<div class="dialog-content">
<div style="white-space: pre-line">{{project.friendlyReminderText}}</div>
</div>
</van-dialog>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
healthCheckupHistory: true,
mixins: [healthCheckupHistoryMixin],
el: "#app",
store,
components: {},
data() {
return {
show: false,
confirmButtonText: "",
amount: 0,
project: {
id: "",
friendlyReminderText: ""
},
baseLoc: "",
count: 5,
confirmDisabled: true
};
},
methods: {
confirmStatusFun(action, done) {
if (action === 'confirm' && this.count > 0) {
done(false);
} else {
done();
}
},
userMessage() {
this.navigateHealthCheckup("/platform/healthCheckup/h5/userBaseMessage?projectId=" + this.project.id);
},
selectPhysicalExaminationHospital() {
this.navigateHealthCheckup("/platform/healthCheckup/h5/projectManageForm?projectId=" + this.project.id);
},
minePhysicalExaminationHospital() {
this.navigateHealthCheckup("/platform/healthCheckup/h5/mine?projectId=" + this.project.id);
},
confirmClick() {
sessionStorage.setItem("friendlyReminderStatus", 1);
},
// 查询体检套餐
findSubject(id) {
return Promise.resolve().then(() => {
return this.$axios.post('/platform/healthCheckup/project/mange/findOne', {
id
}).then(resp => {
this.project = resp.data || {};
});
}).catch(error => {
vant.Toast('获取体检项目失败');
});
}
},
beforeDestroy() {
// PJAX 离开页面时释放提示倒计时,避免旧页面继续更新状态。
clearInterval(this.reminderTimer);
},
created() {
let projectId = GetQueryString("projectId");
this.findSubject(projectId);
let friendlyReminderStatus = sessionStorage.getItem("friendlyReminderStatus");
if (friendlyReminderStatus == "0") {
this.show = true;
this.confirmButtonText = '已知悉(' + this.count + ')';
this.reminderTimer = setInterval(() => {
this.count--;
this.confirmButtonText = '已知悉(' + this.count + ')';
if (this.count <= 0) {
this.confirmDisabled = false;
this.confirmButtonText = '已知悉';
clearInterval(this.reminderTimer);
}
}, 1000);
}
}
});
</script>
<!--#
}
#-->
@@ -4,15 +4,6 @@ layout("/layouts/platform_h5.html"){
<div id="app"> <div id="app">
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="我的体检" placeholder fixed></van-nav-bar> <van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="我的体检" placeholder fixed></van-nav-bar>
<van-sticky offset-top="46px">
<van-tabs v-model="pageForm.status"
@change="onStatusChange">
<van-tab title="进行中" name="ongoing"></van-tab>
<van-tab title="已结束" name="finished"></van-tab>
</van-tabs>
</van-sticky>
<table-list api="/platform/healthCheckup/h5/mineData" :page_form.sync="pageForm" ref="tableListRef" <table-list api="/platform/healthCheckup/h5/mineData" :page_form.sync="pageForm" ref="tableListRef"
@ready="doSearch" title="healthCheckupName"> @ready="doSearch" title="healthCheckupName">
<template v-slot="{index,row}"> <template v-slot="{index,row}">
@@ -20,9 +11,13 @@ layout("/layouts/platform_h5.html"){
<table-column label="开始时间">{{row.choiceTimeStart}}</table-column> <table-column label="开始时间">{{row.choiceTimeStart}}</table-column>
<table-column label="结束时间">{{row.choiceTimeEnd}}</table-column> <table-column label="结束时间">{{row.choiceTimeEnd}}</table-column>
<table-column label="选择医院">{{row.optionName}}</table-column> <table-column label="选择医院">{{row.optionName}}</table-column>
<table-column label="邮寄地址">{{row.receiveAddress}}</table-column> <!-- <table-column label="邮寄地址">{{row.receiveAddress}}</table-column>-->
</template> </template>
<template #actions="{index,row}"> <template #actions="{index,row}">
<div class="action-btn" @click="look(row)">
<van-icon name="eye-o" />
<span>查看</span>
</div>
<div class="action-btn" @click="edit(row)" v-if="new Date().getTime() < new Date(row.choiceTimeEnd).getTime()"> <div class="action-btn" @click="edit(row)" v-if="new Date().getTime() < new Date(row.choiceTimeEnd).getTime()">
<i class="fa fa-edit"></i> <i class="fa fa-edit"></i>
<span>修改</span> <span>修改</span>
@@ -33,15 +28,14 @@ layout("/layouts/platform_h5.html"){
</div> </div>
</template> </template>
</table-list> </table-list>
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
const vue = new Vue({ const vue = new Vue({
healthCheckupHistory: true,
mixins: [healthCheckupHistoryMixin],
el: "#app", el: "#app",
store, store,
components: { components: {},
},
data() { data() {
return { return {
viewShow: false, viewShow: false,
@@ -51,69 +45,77 @@ layout("/layouts/platform_h5.html"){
pageSize: 10, pageSize: 10,
totalCount: 0, totalCount: 0,
year: "", year: "",
status: "ongoing", // 默认为进行中 name: "",
name: "" // 添加搜索名称字段 // 添加搜索名称字段
}, projectId: ""
} }
};
}, },
methods: { methods: {
edit(row) { edit(row) {
this.$pjaxReplace("/platform/healthCheckup/h5/projectManageForm?projectId=" + row.projectId) this.navigateHealthCheckup("/platform/healthCheckup/h5/projectManageForm?projectId=" + row.projectId);
}, },
async cancel(o) { cancel(o) {
vant.Dialog.confirm({ this.$healthConfirm({
title: '温馨提醒', title: '温馨提醒',
message: '您确定要取消此选择吗?', message: '您确定要取消此选择吗?'
}).then(async () => { }).then(() => {
const res = await $.post('/platform/healthCheckup/h5/cancel', {id: o.id, projectId: o.projectId}) return this.$axios.post('/platform/healthCheckup/h5/cancel', {
id: o.id,
projectId: o.projectId
}).then(res => {
if (res.code === 0) { if (res.code === 0) {
vant.Toast.success('取消成功') vant.Toast.success('取消成功');
this.doSearch() this.doSearch();
} else { } else {
vant.Toast(res.msg) vant.Toast(res.msg);
} }
}).catch(() => { });
}) }).catch(() => {});
}, },
tabChange(val) { tabChange(val) {
this.tabName = val this.tabName = val;
this.startLoading() this.startLoading();
this.tableData = [] this.tableData = [];
this.pageForm.pageNumber = 1 this.pageForm.pageNumber = 1;
this.pageData() this.pageData();
this.closeLoading() this.closeLoading();
}, },
doSearch() { doSearch() {
this.$nextTick(() => { this.$nextTick(() => {
this.pageForm.pageNumber = 1 this.pageForm.pageNumber = 1;
this.pageForm.totalCount = 0 this.pageForm.totalCount = 0;
this.$refs.tableListRef.doSearch() this.$refs.tableListRef.doSearch();
}) });
}, },
// 新增状态切换处理方法 // 新增状态切换处理方法
onStatusChange() { onStatusChange() {
this.doSearch(); this.doSearch();
}, },
init() { init() {
this.startLoading() this.startLoading();
this.pageForm.tabName = 'ing' this.pageForm.tabName = 'ing';
this.pageData() this.pageData();
this.closeLoading() this.closeLoading();
}, },
initData() { initData() {
for (let i = new Date().getFullYear() - 10; i <= new Date().getFullYear(); i++) { for (let i = new Date().getFullYear() - 10; i <= new Date().getFullYear(); i++) {
this.yearList.unshift({value: i, text: i + "年"}) this.yearList.unshift({
value: i,
text: i + "年"
});
} }
this.$set(this.pageForm, "year", this.yearList[0].value) this.$set(this.pageForm, "year", this.yearList[0].value);
// 初始化状态 this.pageForm.projectId = GetQueryString("projectId");
this.$set(this.pageForm, "status", "ongoing")
}, },
look(row) {
this.navigateHealthCheckup("/platform/healthCheckup/h5/physicalExaminationList?projectId=" + row.projectId);
}
}, },
created() { created() {
this.initData() this.initData();
} }
}) });
</script> </script>
@@ -0,0 +1,531 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app">
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="体检套餐选择" placeholder
fixed></van-nav-bar>
<div class="form-container">
<van-form ref="formRef" @submit="doSubmit">
<van-cell-group title="基础信息">
<!-- 与填写页使用相同的项目个人信息,查看页仅展示已保存值。 -->
<van-field label="姓名" :value="userBaseMessage.userName" input-align="right" readonly></van-field>
<van-field label="性别" :value="userBaseMessage.sex" input-align="right" readonly></van-field>
<van-field label="年龄" :value="userBaseMessage.age" input-align="right" readonly></van-field>
<van-field label="手机号码" :value="userBaseMessage.phone" input-align="right" readonly></van-field>
<van-field label="身份证号" :value="userBaseMessage.card" input-align="right" readonly></van-field>
<van-field label="人员类别" :value="personTypeLabel" input-align="right" readonly></van-field>
<van-field label="婚姻状态" :value="userBaseMessage.marriage" input-align="right" readonly></van-field>
</van-cell-group>
<van-cell-group title="本年度预约体检医院">
<div class="van-card-body">
<van-radio-group v-model="formData.subjectId" class="basic" disabled >
<van-cell-group>
<van-cell
v-for="(item,index) in project.healthCheckupProjectSubjects"
:key="item.id"
:title="(index + 1) + '、' +item.optionName">
<template #label>
<div style="display: flex; justify-content: space-between; margin-left: 8px">
<div @click.stop="viewDesc(item)" style="color: #0e78c5; padding-left: 15px">查看说明</div>
</div>
</template>
<template #right-icon>
<van-radio :name="item.id" ></van-radio>
</template>
</van-cell>
</van-cell-group>
</van-radio-group>
</div>
<van-field
input-align="right"
readonly
required
label="所选医院额度"
name="marriage"
placeholder="请选择医院"
v-model="formData.money"
:rules="[{ required: true, message: '请选择医院' }]"></van-field>
</van-cell-group>
<van-cell-group title="上年度预约体检医院">
<div class="van-card-body">
<van-cell title="上年度体检医院" :value="formData.lastYearHospital" />
</div>
</van-cell-group>
<!-- <van-cell-group title="体检报告邮寄地址">-->
<!-- <van-radio-group v-model="formData.postMethod" disabled>-->
<!-- <van-cell-group>-->
<!-- <van-cell title="单位" >-->
<!-- <template #right-icon>-->
<!-- <van-radio name="1"></van-radio>-->
<!-- </template>-->
<!-- </van-cell>-->
<!-- <van-cell title="自选" >-->
<!-- <template #right-icon>-->
<!-- <van-radio name="2"></van-radio>-->
<!-- </template>-->
<!-- </van-cell>-->
<!-- </van-cell-group>-->
<!-- </van-radio-group>-->
<!-- <template>-->
<!-- <van-field-->
<!-- v-if="formData.postMethod === '2'"-->
<!-- v-model="formData.receiveAddress"-->
<!-- label="邮寄地址"-->
<!-- placeholder="请选择邮寄地址"-->
<!-- readonly-->
<!-- type="textarea"-->
<!-- autosize-->
<!-- rows="2"-->
<!-- is-link-->
<!-- @click="this.$set(this, 'editAddressPopup', true)"-->
<!-- required-->
<!-- ></van-field>-->
<!-- <van-cell title="邮寄地址" v-else>{{formData.receiveAddress}}</van-cell>-->
<!-- <van-cell title="体检报告">-->
<!-- <div v-html="formData.medicalExamination"></div>-->
<!-- </van-cell>-->
<!-- </template>-->
<!-- </van-cell-group>-->
<van-cell-group title="家属信息" v-if="formData.isFamily === '是'">
<div style="padding: 10px;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
<span>家属信息</span>
<div>
<van-tag @click="delCompanion" size="large" type="primary" color="lightgrey">
删除家属
</van-tag>
<van-tag @click="addCompanion" size="large" type="primary" color="#1867b0">
添加家属
</van-tag>
</div>
</div>
<div v-if="formData.companionList && formData.companionList.length > 0">
<van-tabs v-model="active" type="card" color="#0e78c5" animated>
<van-tab
v-for="(item, index) in formData.companionList"
:key="index"
:title="'家属' + (index + 1)">
<van-field
label="姓名"
name="userName"
placeholder="请填写姓名"
v-model="item.userName"
:rules="[{ required: true, message: '请填写姓名' }]">
</van-field>
<van-field
:rules="[{ required: true, message: '请选择性别' }]"
label="性别"
name="sex">
<template #input>
<van-radio-group direction="horizontal" v-model="item.sex">
<van-radio name="男" shape="square">男</van-radio>
<van-radio name="女" shape="square">女</van-radio>
</van-radio-group>
</template>
</van-field>
<van-field
:rules="[{ required: true, message: '请选择婚否' }]"
label="婚否"
name="marry">
<template #input>
<van-radio-group direction="horizontal" v-model="item.marry">
<van-radio name="未婚" shape="square">未婚</van-radio>
<van-radio name="已婚" shape="square">已婚</van-radio>
</van-radio-group>
</template>
</van-field>
<van-field
label="年龄"
name="age"
placeholder="请填写年龄"
type="digit"
:rules="[{ required: true, message: '请填写年龄' }]"
v-model="item.age">
</van-field>
<van-field
label="身份证号"
name="idCard"
placeholder="请填写身份证号"
type="digit"
:rules="[{ required: true, message: '请填写身份证号' }]"
v-model="item.idCard">
</van-field>
<van-field
label="手机号"
name="mobile"
placeholder="请填写手机号"
type="digit"
:rules="[{ required: true, message: '请填写手机号' }]"
v-model="item.mobile">
</van-field>
</van-tab>
</van-tabs>
</div>
<div v-else class="empty_text">
<span>如有家属,请添加家属</span>
</div>
</div>
</van-cell-group>
</van-form>
</div>
<!--体检院区弹出框-->
<van-action-sheet title="体检院区" v-model="campusVisible">
<van-picker
title="院区"
show-toolbar
:columns="campusList"
value-key="campusName"
@confirm="onCampusConfirm"
@cancel="cancelCampusSelection">
</van-picker>
</van-action-sheet>
<!--查看说明-->
<van-action-sheet title="医院说明" v-model="descVisible" :style="{ height: '60%' }">
<div class="form-container" style="margin: 10px;">
<van-cell-group title="说明"></van-cell-group>
<div v-html="desc" class="pre_text"></div>
<div style="margin-top: 10px">
<van-cell-group title="以下内容由医院方提供"></van-cell-group>
<file-preview :files="files" complete_result></file-preview>
</div>
</div>
</van-action-sheet>
<!-- 收货地址选择弹窗 -->
<van-action-sheet v-model="editAddressPopup" title="选择收货地址" :round="true">
<div style="padding: 16px 0 0">
<div
v-for="address in addressOptions"
:key="address.id"
class="address-item"
@click="selectAddress(address)"
style="padding: 12px 16px; border-bottom: 1px solid #f0f0f0; cursor: pointer"
>
<div style="display: flex; justify-content: space-between; align-items: flex-start">
<div style="flex: 1">
<div style="font-size: 16px; font-weight: 500; color: #323233; margin-bottom: 4px">
{{ address.userName }} {{ address.tel }}
</div>
<div style="font-size: 14px; color: #646566; line-height: 1.4">
{{ address.province }}{{ address.city }}{{ address.county }}{{ address.addressDetail
}}
</div>
</div>
<van-tag v-if="address.isDefault" type="primary" size="mini" style="margin-left: 8px">默认
</van-tag>
</div>
</div>
<div v-if="addressOptions.length === 0"
style="text-align: center; padding: 40px 16px; color: #969799">暂无收货地址
</div>
</div>
<div style="padding: 16px; border-top: 1px solid #f0f0f0; background: #fafafa">
<van-button type="info" block round @click="goToAddressManage">收货地址管理</van-button>
</div>
</van-action-sheet>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
healthCheckupHistory: true,
dicts: ["USER_PERSON_TYPE"],
mixins: [healthCheckupHistoryMixin],
el: "#app",
store,
dicts: ["ASSET_USAGE_STATE"],
data() {
return {
formLoading: false,
viewData: {},
formData: {
subjectId: '',
campus: '',
campusName: '',
isFamily: '否',
companionList: [],
projectId: '',
postMethod: ''
},
assetUsageStateNameOption: [],
showAssetUsageStateNamePopup: false,
assetUseUserOption: [],
assetUseNameShow: false,
searchKeyword: "",
active: 0,
campusList: [],
campusVisible: false,
descVisible: false,
desc: '',
files: [],
project: {},
marriageList: ["已婚", "未婚"],
marriageVisible: false,
editAddressPopup: false,
addressOptions: [],
userBaseMessage: {}
};
},
computed: {
personTypeLabel() {
// 人员类别编码使用系统字典展示;兼容已有中文值,避免历史记录显示为空。
const value = this.userBaseMessage.personType;
const options = this.dict.type.USER_PERSON_TYPE || [];
const option = options.find(item => String(item.code) === String(value));
return option ? option.name : (value || '');
},
// 根据 subjectId 自动匹配出 optionName
getSelectedOptionName() {
if (!this.formData.subjectId) return '';
if (!this.project?.healthCheckupProjectSubjects) return '';
const item = this.project.healthCheckupProjectSubjects.find(item => item.id == this.formData.subjectId);
return item ? item.optionName : '';
}
},
methods: {
cancelCampusSelection() {
// 关闭院区选择弹框;已有全局弹框监听会同步回退对应历史记录。
this.$set(this, 'campusVisible', false);
},
// 选择收货地址
selectAddress(address) {
this.formData.receiveAddress = address.userName + " " + address.tel + " " + address.province + address.city + address.county + address.addressDetail;
this.editAddressPopup = false;
},
// 跳转到地址管理页面
goToAddressManage() {
this.navigateHealthCheckup("/platform/h5/welfare/address/list");
},
// 获取收货地址
getAddress() {
this.$axios.post("/platform/welfare/addressManage/selectUserAddress").then(resp => {
if (resp.code === 0) {
this.addressOptions = resp.data;
}
});
},
isEmptyObject(obj) {
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
return false;
}
}
return true;
},
addressClick() {},
// 打开表单
initData() {
return Promise.resolve(this.getCampus()).then(() => {
this.getAddress();
let projectId = GetQueryString("projectId");
return Promise.resolve(this.findSubject(projectId)).then(() => {
if (projectId) {
const {
id,
userState,
marriage,
birthday,
unit
} = this.$store.state.user;
return Promise.resolve(this.selectInfo(projectId)).then(() => {
return Promise.resolve(this.findUserBaseMessage(projectId, id)).then(() => {
return Promise.resolve(this.findLastYearHospital(projectId, id)).then(() => {
this.$set(this.formData, 'projectId', projectId);
this.$set(this.formData, 'idCard', this.userBaseMessage?.card);
this.$set(this.formData, 'userState', userState);
this.$set(this.formData, 'marriage', this.userBaseMessage?.marriage);
this.$set(this.formData, 'birthday', birthday);
this.$set(this.formData, 'unitName', (unit ? unit.name : ''));
this.$set(this.formData, 'postMethod', this.formData?.postMethod ? this.formData.postMethod : "1");
this.$set(this.formData, 'receiveAddress', this.formData?.receiveAddress ? this.formData.receiveAddress : (unit ? unit.name : ''));
this.$set(this.formData, 'medicalExamination', this.formData?.medicalExamination);
});
});
});
} else {}
});
});
},
clickRadio(item) {
const toast = this.$toast.loading({
duration: 0,
// 持续展示 toast
forbidClick: true,
message: '查询中....'
});
this.$axios.post("/platform/healthCheckup/h5/getSubjectMoney", {
id: item.id,
marriage: this.formData.marriage
}).then(resp => {
if (resp.code === 0) {
this.$set(this.formData, 'subjectId', item.id);
this.$set(this.formData, 'money', resp.data.money);
this.$set(this.formData, 'subjectMoneyId', resp.data.subjectMoneyId);
} else {
this.$set(this.formData, 'money', 0);
}
toast.clear();
}).finally(() => {
toast.clear();
});
},
selectInfo(projectId) {
return this.$axios.post('/platform/healthCheckup/h5/selectInfo', {
projectId: projectId
}).then(resp => {
if (resp.data !== null) {
this.formData = resp.data;
}
});
},
// 查看说明
viewDesc(item) {
if (item.description || item.files) {
this.files = item.files;
this.desc = item.description;
this.descVisible = true;
} else {
vant.Toast('暂无详细说明');
}
},
// 执行提交
doSubmit() {
if (this.formLoading) return;
const formData = clone(this.formData);
if (!formData.receiveAddress) {
this.$toast.fail('请填写邮寄地址!');
return;
}
const subject = this.project.healthCheckupProjectSubjects.find(v => v.id === formData.subjectId);
if (!subject) { this.$toast.fail('请选择体检医院'); return; }
this.$healthConfirm({
title: '温馨提示',
message: '您确定要提交选择的【' + subject.optionName + '】吗?'
}).then(() => {
const toast = this.$toast.loading({
duration: 0,
// 持续展示 toast
forbidClick: true,
message: '提交中....'
});
this.formLoading = true;
/* if (formData.isFamily === '否') {
formData.companionList = [];
} else {
// 过滤空的家属信息
formData.companionList = formData.companionList.filter(item => item.userName && item.userName.trim() !== '');
}*/
this.$axios.post('/platform/healthCheckup/h5/doSubmit', {
userSelection: JSON.stringify(formData)
}).then(resp => {
if (resp.code === 0) {
toast.clear();
this.$toast.success(resp.msg);
// 提交成功后展示当前项目的医院选择,避免按来源历史退回基础信息页。
return this.navigateHealthCheckup('/platform/healthCheckup/h5/mine?projectId=' + encodeURIComponent(formData.projectId));
}
}).finally(() => {
toast.clear();
this.formLoading = false;
});
}).catch(() => {});
},
// 添加家属
addCompanion() {
// 检查是否已达到最大数量限制
if (this.formData.companionList && this.formData.companionList.length >= 5) {
vant.Toast('最多只能添加5个家属');
return;
}
if (!this.formData.companionList) {
this.$set(this.formData, 'companionList', []);
}
this.formData.companionList.push({
userName: '',
sex: '',
marry: '',
age: '',
idCard: '',
mobile: ''
});
},
// 删除家属
delCompanion() {
if (this.formData.companionList && this.formData.companionList.length > 0) {
this.formData.companionList.splice(this.active, 1);
// 确保active索引有效
if (this.active >= this.formData.companionList.length && this.active > 0) {
this.active = this.formData.companionList.length - 1;
}
}
},
// 院区选择确认
onCampusConfirm(value) {
this.formData.campusName = value.campusName;
this.formData.campus = value.id;
this.campusVisible = false;
},
// 婚姻状况确认
onMarriageConfirm(value) {
this.$set(this.formData, 'marriage', value);
this.$set(this.formData, 'subjectId', null);
this.marriageVisible = false;
},
// 查询体检套餐
findSubject(id) {
return Promise.resolve().then(() => {
return this.$axios.post('/platform/healthCheckup/project/mange/findOne', {
id: id
}).then(resp => {
this.project = resp.data || {};
});
}).catch(error => {
vant.Toast('获取体检套餐失败');
});
},
// 获取院区
getCampus() {
return Promise.resolve().then(() => {
return this.$axios.post('/platform/healthCheckup/h5/getCampus').then(resp => {
this.campusList = resp.data || [];
});
}).catch(error => {
vant.Toast('获取院区失败');
});
},
findUserBaseMessage(projectId, userId) {
return this.$axios.post('/platform/healthCheckup/h5/findUserBaseMessageData', {
projectId,
userId
}).then(resp => {
if (resp.data !== null) {
this.userBaseMessage = resp.data;
}
});
},
findLastYearHospital(projectId, userId, subjectId) {
return this.$axios.post('/platform/healthCheckup/h5/findLastYearHospital', {
projectId,
selectUserId: userId
}).then(resp => {
if (resp.data !== null) {
this.$set(this.formData, 'lastYearHospital', resp.data);
}
});
}
},
created() {
this.initData();
}
});
</script>
<!--#
}
#-->
@@ -1,7 +1,6 @@
<!--# <!--#
layout("/layouts/platform_h5.html"){ layout("/layouts/platform_h5.html"){
#--> #-->
<div id="app"> <div id="app">
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="体检套餐选择" placeholder <van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="体检套餐选择" placeholder
fixed></van-nav-bar> fixed></van-nav-bar>
@@ -11,41 +10,61 @@ layout("/layouts/platform_h5.html"){
<van-cell-group title="基础信息"> <van-cell-group title="基础信息">
<van-field <van-field
input-align="right" input-align="right"
label="身份证号" label="姓名"
name="idCard" name="userName"
readonly readonly
required required
placeholder="请联系校工会补充身份证号" v-model="userBaseMessage.userName"
v-model="formData.idCard" :rules="[{ required: true, message: '请输入姓名' }]">
:rules="[{ required: true, message: '请输入身份证号' }]">
</van-field> </van-field>
<van-cell title="人员类型">{{formData.userState}}</van-cell>
<van-cell title="性别">
<template #right-icon>
<van-radio-group v-model="userBaseMessage.sex" direction="horizontal" disabled >
<van-radio name="男">男</van-radio>
<van-radio name="女">女</van-radio>
</van-radio-group>
</template>
</van-cell>
<van-field label="年龄" input-align="right" v-model="userBaseMessage.age" type="digit" required :rules="[{ required: true, message: '请输入年龄' }]"></van-field>
<van-field <van-field
input-align="right" input-align="right"
readonly label="手机号码"
name="phone"
required required
label="婚姻状况" v-model="userBaseMessage.phone"
name="marriage" :rules="[{ required: true, message: '请输入手机号码' }, { pattern: /^1[0-9]{10}$/, message: '请输入正确的手机号码' }]">
placeholder="请联系校工会补充婚姻状况" </van-field>
v-model="formData.marriage" <van-field
:rules="[{ required: true, message: '请选择婚姻状况' }]"></van-field> input-align="right"
label="身份证号"
<van-cell title="出生年月">{{$moment(formData.birthday).format('YYYY-MM-DD')}}</van-cell> name="card"
<van-cell title="单位">{{formData.unitName}}</van-cell> required
placeholder="请输入身份证号"
v-model="userBaseMessage.card"
:rules="[{ required: true, message: '请输入身份证号' }]">
</van-field>
<van-cell title="人员类别">{{personTypeLabel}}</van-cell>
<van-cell title="婚姻状态">
<template #right-icon>
<van-radio-group v-model="userBaseMessage.marriage" direction="horizontal" >
<van-radio name="已婚">已婚</van-radio>
<van-radio name="未婚">未婚</van-radio>
</van-radio-group>
</template>
</van-cell>
</van-cell-group> </van-cell-group>
<van-cell-group title="本年度预约体检医院"> <van-cell-group title="本年度预约体检医院">
<div class="van-card-body"> <div class="van-card-body">
<van-radio-group v-model="formData.subjectId" class="basic"> <van-radio-group v-model="formData.subjectId" class="basic">
<van-cell-group> <van-cell-group>
<van-cell <van-cell
v-for="item in project.healthCheckupProjectSubjects" v-for="(item,index) in project.healthCheckupProjectSubjects"
:key="item.id" :key="item.id"
:title="item.optionName"> :title="(index + 1) + '、' +item.optionName">
<template #label> <template #label>
<div style="display: flex; justify-content: space-between; margin-left: 8px"> <div style="display: flex; justify-content: space-between; margin-left: 8px">
<!-- <div>{{ item.optionName }}</div>--> <div @click.stop="viewDesc(item)" style="color: #0e78c5; padding-left: 15px">查看说明</div>
<div></div>
<div @click.stop="viewDesc(item)" style="color: #0e78c5">查看说明</div>
</div> </div>
</template> </template>
<template #right-icon> <template #right-icon>
@@ -60,50 +79,55 @@ layout("/layouts/platform_h5.html"){
readonly readonly
required required
label="所选医院额度" label="所选医院额度"
name="marriage" name="money"
placeholder="请选择医院" placeholder="请选择医院"
v-model="formData.money" v-model="formData.money"
:rules="[{ required: true, message: '请选择医院' }]"></van-field> :rules="[{ required: true, message: '请选择医院' }]"></van-field>
</van-cell-group> </van-cell-group>
<van-cell-group title="体检报告邮寄地址"> <van-cell-group title="上年度预约体检医院">
<van-radio-group v-model="formData.postMethod"> <div class="van-card-body">
<van-cell-group> <van-cell title="上年度体检医院" :value="formData.lastYearHospital" />
<van-cell title="单位" clickable </div>
@click="formData.postMethod = '1';formData.receiveAddress=formData.unitName">
<template #right-icon>
<van-radio name="1"></van-radio>
</template>
</van-cell>
<van-cell title="自选" clickable
@click="formData.postMethod = '2';formData.receiveAddress=''">
<template #right-icon>
<van-radio name="2"></van-radio>
</template>
</van-cell>
</van-cell-group>
</van-radio-group>
<template>
<van-field
v-if="formData.postMethod === '2'"
v-model="formData.receiveAddress"
label="邮寄地址"
placeholder="请选择邮寄地址"
readonly
type="textarea"
autosize
rows="2"
is-link
@click="editAddressPopup = true"
required
></van-field>
<van-cell title="邮寄地址" v-else>{{formData.receiveAddress}}</van-cell>
</template>
</van-cell-group> </van-cell-group>
<!-- <van-cell-group title="体检报告邮寄地址">-->
<!-- <van-radio-group v-model="formData.postMethod">-->
<!-- <van-cell-group>-->
<!-- <van-cell title="单位" clickable-->
<!-- @click="this.$set(formData, 'postMethod', '1');this.$set(formData, 'receiveAddress', formData.unitName)">-->
<!-- <template #right-icon>-->
<!-- <van-radio name="1"></van-radio>-->
<!-- </template>-->
<!-- </van-cell>-->
<!-- <van-cell title="自选" clickable-->
<!-- @click="this.$set(formData, 'postMethod', '2');this.$set(formData, 'receiveAddress', '')">-->
<!-- <template #right-icon>-->
<!-- <van-radio name="2"></van-radio>-->
<!-- </template>-->
<!-- </van-cell>-->
<!-- </van-cell-group>-->
<!-- </van-radio-group>-->
<!-- <template>-->
<!-- <van-field-->
<!-- v-if="formData.postMethod === '2'"-->
<!-- v-model="formData.receiveAddress"-->
<!-- label="邮寄地址"-->
<!-- placeholder="请选择邮寄地址"-->
<!-- readonly-->
<!-- type="textarea"-->
<!-- autosize-->
<!-- rows="2"-->
<!-- is-link-->
<!-- @click="this.$set(this, 'editAddressPopup', true)"-->
<!-- required-->
<!-- ></van-field>-->
<!-- <van-cell title="邮寄地址" v-else>{{formData.receiveAddress}}</van-cell>-->
<!-- </template>-->
<!-- </van-cell-group>-->
<!-- <van-cell-group title="基础信息"> <!-- <van-cell-group title="基础信息">
<div class="van-card-body"> <div class="van-card-body">
<van-field <van-field
@click="campusVisible = true" @click="this.$set(this, 'campusVisible', true)"
readonly readonly
is-link is-link
label="院区" label="院区"
@@ -210,7 +234,7 @@ layout("/layouts/platform_h5.html"){
<!-- 按钮区域 --> <!-- 按钮区域 -->
<div class="form-actions"> <div class="form-actions">
<van-button type="primary" native-type="submit">提交</van-button> <van-button type="primary" native-type="submit" :loading="formLoading" :disabled="formLoading">提交</van-button>
</div> </div>
</van-form> </van-form>
</div> </div>
@@ -223,7 +247,7 @@ layout("/layouts/platform_h5.html"){
:columns="campusList" :columns="campusList"
value-key="campusName" value-key="campusName"
@confirm="onCampusConfirm" @confirm="onCampusConfirm"
@cancel="campusVisible = false"> @cancel="cancelCampusSelection">
</van-picker> </van-picker>
</van-action-sheet> </van-action-sheet>
@@ -276,12 +300,16 @@ layout("/layouts/platform_h5.html"){
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
const vue = new Vue({ const vue = new Vue({
healthCheckupHistory: true,
dicts: ["USER_PERSON_TYPE"],
mixins: [healthCheckupHistoryMixin],
el: "#app", el: "#app",
store, store,
dicts: ["ASSET_USAGE_STATE"], dicts: ["ASSET_USAGE_STATE"],
data() { data() {
return { return {
formLoading: false,
viewData: {}, viewData: {},
formData: { formData: {
subjectId: '', subjectId: '',
@@ -304,93 +332,140 @@ layout("/layouts/platform_h5.html"){
desc: '', desc: '',
files: [], files: [],
project: {}, project: {},
marriageList: ["已婚", "未婚"], marriageList: ["已婚", "未婚"],
marriageVisible: false, marriageVisible: false,
editAddressPopup: false, editAddressPopup: false,
addressOptions: [] addressOptions: [],
userBaseMessage: {}
};
},
computed: {
personTypeLabel() {
// 人员类别编码使用系统字典展示;兼容已有中文值,避免历史记录显示为空。
const value = this.userBaseMessage.personType;
const options = this.dict.type.USER_PERSON_TYPE || [];
const option = options.find(item => String(item.code) === String(value));
return option ? option.name : (value || '');
}
},
watch: {
'userBaseMessage.age'(value, previous) {
if (previous !== undefined && value !== previous) this.resetSubjectForBaseInfo();
},
'userBaseMessage.marriage'(value, previous) {
if (previous !== undefined && value !== previous) this.resetSubjectForBaseInfo();
} }
}, },
methods: { methods: {
resetSubjectForBaseInfo() {
// 年龄或婚姻状态影响套餐资格,修改后需重新选择医院计算额度。
this.$set(this.formData, 'subjectId', null);
this.$set(this.formData, 'subjectMoneyId', null);
this.$set(this.formData, 'money', null);
},
cancelCampusSelection() {
// 关闭院区选择弹框;已有全局弹框监听会同步回退对应历史记录。
this.$set(this, 'campusVisible', false);
},
// 选择收货地址 // 选择收货地址
selectAddress(address) { selectAddress(address) {
this.formData.receiveAddress = this.formData.receiveAddress = address.userName + " " + address.tel + " " + address.province + address.city + address.county + address.addressDetail;
address.userName + " " + address.tel + " " + address.province + address.city + address.county + address.addressDetail this.editAddressPopup = false;
this.editAddressPopup = false
}, },
// 跳转到地址管理页面 // 跳转到地址管理页面
goToAddressManage() { goToAddressManage() {
this.$pjaxReplace("/platform/h5/welfare/address/list") this.navigateHealthCheckup("/platform/h5/welfare/address/list");
}, },
// 获取收货地址 // 获取收货地址
getAddress() { getAddress() {
this.$axios.post("/platform/welfare/addressManage/selectUserAddress").then(resp => { this.$axios.post("/platform/welfare/addressManage/selectUserAddress").then(resp => {
if (resp.code === 0) { if (resp.code === 0) {
this.addressOptions = resp.data this.addressOptions = resp.data;
} }
}) });
}, },
isEmptyObject(obj) { isEmptyObject(obj) {
for (let key in obj) { for (let key in obj) {
if (obj.hasOwnProperty(key)) { if (obj.hasOwnProperty(key)) {
return false return false;
} }
} }
return true return true;
},
addressClick() {
}, },
addressClick() {},
// 打开表单 // 打开表单
async initData() { initData() {
await this.getCampus() return Promise.resolve(this.getCampus()).then(() => {
this.getAddress() this.getAddress();
await this.findSubject(GetQueryString("projectId")) let projectId = GetQueryString("projectId");
if (GetQueryString("projectId")) { return Promise.resolve(this.findSubject(projectId)).then(() => {
await this.selectInfo(GetQueryString("projectId")); if (projectId) {
const {idCard, userState, marriage, birthday, unit} = this.$store.state.user const {
this.$set(this.formData, 'projectId', GetQueryString("projectId")) id,
this.$set(this.formData, 'idCard', idCard) birthday,
this.$set(this.formData, 'userState', userState) unit
this.$set(this.formData, 'marriage', marriage) } = this.$store.state.user;
this.$set(this.formData, 'birthday', birthday) return Promise.resolve(this.selectInfo(projectId)).then(() => {
this.$set(this.formData, 'unitName', unit.name) return Promise.resolve(this.findUserBaseMessage(projectId, id)).then(() => {
this.$set(this.formData, 'postMethod', this.formData?.postMethod ? this.formData.postMethod : "1") return Promise.resolve(this.findLastYearHospital(projectId, id)).then(() => {
this.$set(this.formData, 'receiveAddress', this.formData?.receiveAddress ? this.formData.receiveAddress : unit.name) this.$set(this.formData, 'projectId', projectId);
} this.$set(this.formData, 'idCard', this.userBaseMessage?.card);
this.$set(this.formData, 'marriage', this.userBaseMessage?.marriage);
this.$set(this.formData, 'birthday', birthday);
this.$set(this.formData, 'unitName', (unit ? unit.name : ''));
this.$set(this.formData, 'postMethod', this.formData?.postMethod ? this.formData.postMethod : "1");
this.$set(this.formData, 'receiveAddress', this.formData?.receiveAddress ? this.formData.receiveAddress : (unit ? unit.name : ''));
});
});
});
} else {}
});
});
}, },
clickRadio(item) { clickRadio(item) {
if (this.userBaseMessage.age == null || this.userBaseMessage.age === '' || !this.userBaseMessage.marriage) {
this.$set(this.formData, 'subjectId', null);
this.$toast.fail('请填写年龄并选择婚姻状态');
return;
}
const previewAge = this.userBaseMessage.age;
const previewMarriage = this.userBaseMessage.marriage;
const toast = this.$toast.loading({ const toast = this.$toast.loading({
duration: 0, // 持续展示 toast duration: 0,
// 持续展示 toast
forbidClick: true, forbidClick: true,
message: '查询中....', message: '查询中....'
}); });
$.post("/platform/healthCheckup/h5/getSubjectMoney", { this.$axios.post("/platform/healthCheckup/h5/getSubjectMoney", {
id: item.id, id: item.id,
marriage: this.formData.marriage marriage: previewMarriage,
age: previewAge
}).then(resp => { }).then(resp => {
// 输入在请求期间变化时丢弃旧额度,避免旧条件覆盖新表单。
if (previewAge !== this.userBaseMessage.age || previewMarriage !== this.userBaseMessage.marriage) return;
if (resp.code === 0) { if (resp.code === 0) {
this.$set(this.formData, 'subjectId', item.id) this.$set(this.formData, 'subjectId', item.id);
this.$set(this.formData, 'money', resp.data.money) this.$set(this.formData, 'money', resp.data.money);
this.$set(this.formData, 'subjectMoneyId', resp.data.subjectMoneyId) this.$set(this.formData, 'subjectMoneyId', resp.data.subjectMoneyId);
} else { } else {
this.$set(this.formData, 'money', 0) this.$set(this.formData, 'money', 0);
} }
toast.clear(); toast.clear();
}) }).finally(() => {
toast.clear();
});
}, },
async selectInfo(projectId) { selectInfo(projectId) {
const resp = await this.$axios.post('/platform/healthCheckup/h5/selectInfo', {projectId: projectId}); return this.$axios.post('/platform/healthCheckup/h5/selectInfo', {
projectId: projectId
}).then(resp => {
if (resp.data !== null) { if (resp.data !== null) {
this.formData = resp.data; this.formData = resp.data;
/* const o = this.campusList.find(o => o.id === this.formData.campus) /* const o = this.campusList.find(o => o.id === this.formData.campus)
this.formData.campusName = o.campusName*/ this.formData.campusName = o.campusName*/
} }
});
}, },
// 查看说明 // 查看说明
viewDesc(item) { viewDesc(item) {
if (item.description || item.files) { if (item.description || item.files) {
@@ -401,51 +476,62 @@ layout("/layouts/platform_h5.html"){
vant.Toast('暂无详细说明'); vant.Toast('暂无详细说明');
} }
}, },
// 执行提交 // 执行提交
async doSubmit() { doSubmit() {
if (this.formLoading) return;
const age = Number(this.userBaseMessage.age);
if (this.userBaseMessage.age == null || this.userBaseMessage.age === '' || !Number.isInteger(age) || age < 0 || age > 120) {
this.$toast.fail('请输入0至120的整数年龄');
return;
}
if (!this.userBaseMessage.marriage) { this.$toast.fail('请选择婚姻状态'); return; }
const baseInfo = {age, phone: this.userBaseMessage.phone, card: this.userBaseMessage.card, marriage: this.userBaseMessage.marriage};
const formData = clone(this.formData); const formData = clone(this.formData);
if (!formData.receiveAddress) { if (!formData.receiveAddress) {
this.$toast.fail('请填写邮寄地址!') this.$toast.fail('请填写邮寄地址!');
return;
} }
const subject = this.project.healthCheckupProjectSubjects.find(v => v.id === formData.subjectId);
const subject = this.project.healthCheckupProjectSubjects.find(v => v.id === formData.subjectId) if (!subject) { this.$toast.fail('请选择体检医院'); return; }
this.$healthConfirm({
this.$dialog.confirm({
title: '温馨提示', title: '温馨提示',
message: '您确定要提交选择的【' + subject.optionName + '】吗?', message: '您确定要提交选择的【' + subject.optionName + '】吗?'
}).then(() => { }).then(() => {
const toast = this.$toast.loading({ const toast = this.$toast.loading({
duration: 0, // 持续展示 toast duration: 0,
// 持续展示 toast
forbidClick: true, forbidClick: true,
message: '提交中....', message: '提交中....'
}); });
this.formLoading = true;
/* if (formData.isFamily === '否') { /* if (formData.isFamily === '否') {
formData.companionList = []; formData.companionList = [];
} else { } else {
// 过滤空的家属信息 // 过滤空的家属信息
formData.companionList = formData.companionList.filter(item => item.userName && item.userName.trim() !== ''); formData.companionList = formData.companionList.filter(item => item.userName && item.userName.trim() !== '');
}*/ }*/
this.$axios.post('/platform/healthCheckup/h5/doSubmit', { return this.$axios.post('/platform/healthCheckup/h5/doSubmit', {
userSelection: JSON.stringify(formData), baseInfo: JSON.stringify(baseInfo),
userSelection: JSON.stringify(formData)
}).then(resp => { }).then(resp => {
if (resp.code === 0) { if (resp.code === 0) {
toast.clear(); toast.clear();
this.$toast.success(resp.msg) this.$toast.success(resp.msg);
this.historyBack() // 提交成功后展示当前项目的医院选择,避免按来源历史退回基础信息页。
return this.navigateHealthCheckup('/platform/healthCheckup/h5/mine?projectId=' + encodeURIComponent(formData.projectId));
} }
})
}).catch(() => { }).catch(() => {
toast.clear();
}).finally(() => {
toast.clear();
this.formLoading = false;
}); });
}).catch(() => {});
}, },
// 添加家属 // 添加家属
addCompanion() { addCompanion() {
// 检查是否已达到最大数量限制 // 检查是否已达到最大数量限制
if (this.companionList && this.formData.companionList.length >= 5) { if (this.formData.companionList && this.formData.companionList.length >= 5) {
vant.Toast('最多只能添加5个家属'); vant.Toast('最多只能添加5个家属');
return; return;
} }
@@ -453,10 +539,14 @@ layout("/layouts/platform_h5.html"){
this.$set(this.formData, 'companionList', []); this.$set(this.formData, 'companionList', []);
} }
this.formData.companionList.push({ this.formData.companionList.push({
userName: '', sex: '', marry: '', age: '', idCard: '', mobile: '' userName: '',
sex: '',
marry: '',
age: '',
idCard: '',
mobile: ''
}); });
}, },
// 删除家属 // 删除家属
delCompanion() { delCompanion() {
if (this.formData.companionList && this.formData.companionList.length > 0) { if (this.formData.companionList && this.formData.companionList.length > 0) {
@@ -467,50 +557,66 @@ layout("/layouts/platform_h5.html"){
} }
} }
}, },
// 院区选择确认 // 院区选择确认
onCampusConfirm(value) { onCampusConfirm(value) {
this.formData.campusName = value.campusName; this.formData.campusName = value.campusName;
this.formData.campus = value.id; this.formData.campus = value.id;
this.campusVisible = false; this.campusVisible = false;
}, },
// 婚姻状况确认 // 婚姻状况确认
onMarriageConfirm(value) { onMarriageConfirm(value) {
this.$set(this.formData, 'marriage', value) this.$set(this.formData, 'marriage', value);
this.$set(this.formData, 'subjectId', null) this.$set(this.formData, 'subjectId', null);
this.marriageVisible = false; this.marriageVisible = false;
}, },
// 查询体检套餐 // 查询体检套餐
async findSubject(id) { findSubject(id) {
try { return Promise.resolve().then(() => {
const resp = await this.$axios.post('/platform/healthCheckup/project/mange/findOne', { return this.$axios.post('/platform/healthCheckup/project/mange/findOne', {
id: id id: id
}); }).then(resp => {
this.project = resp.data || {}; this.project = resp.data || {};
} catch (error) { });
}).catch(error => {
vant.Toast('获取体检套餐失败'); vant.Toast('获取体检套餐失败');
} });
}, },
// 获取院区 // 获取院区
async getCampus() { getCampus() {
try { return Promise.resolve().then(() => {
const resp = await this.$axios.post('/platform/healthCheckup/h5/getCampus'); return this.$axios.post('/platform/healthCheckup/h5/getCampus').then(resp => {
this.campusList = resp.data || []; this.campusList = resp.data || [];
} catch (error) { });
}).catch(error => {
vant.Toast('获取院区失败'); vant.Toast('获取院区失败');
});
},
findUserBaseMessage(projectId, userId) {
return this.$axios.post('/platform/healthCheckup/h5/findUserBaseMessageData', {
projectId,
userId
}).then(resp => {
if (resp.data !== null) {
this.userBaseMessage = resp.data;
} }
});
},
findLastYearHospital(projectId, userId, subjectId) {
return this.$axios.post('/platform/healthCheckup/h5/findLastYearHospital', {
projectId,
selectUserId: userId
}).then(resp => {
if (resp.data !== null) {
this.$set(this.formData, 'lastYearHospital', resp.data);
}
});
} }
}, },
created() { created() {
this.initData() this.initData();
} }
}) });
</script> </script>
<!--# <!--#
} }
#--> #-->
@@ -0,0 +1,182 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app">
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="基础信息" placeholder
style="background-color: #ccc5c5;"
fixed></van-nav-bar>
<div class="form-container" v-cloak>
<van-form ref="formRef" @submit="doSubmit">
<van-cell-group>
<van-field
input-align="right"
label="姓名"
name="userName"
readonly
required
v-model="formData.userName"
:rules="[{ required: true, message: '请输入姓名' }]">
</van-field>
<van-cell title="性别">
<template #right-icon>
<van-radio-group v-model="formData.sex" direction="horizontal" disabled >
<van-radio name="男">男</van-radio>
<van-radio name="女">女</van-radio>
</van-radio-group>
</template>
</van-cell>
<van-field label="年龄" input-align="right" v-model="formData.age" type="digit" required :rules="[{ required: true, message: '请输入年龄' }]"></van-field>
<van-field
input-align="right"
label="手机号码"
name="phone"
required
v-model="formData.phone"
:rules="[{ required: true, message: '请输入手机号码' }, { pattern: /^1[0-9]{10}$/, message: '请输入正确的手机号码' }]">
</van-field>
<van-field
input-align="right"
label="身份证号"
name="card"
required
placeholder="请输入身份证号"
v-model="formData.card"
:rules="[{ required: true, message: '请输入身份证号' }]">
</van-field>
<van-cell title="人员类别">{{personTypeLabel}}</van-cell>
<van-cell title="婚姻状态">
<template #right-icon>
<van-radio-group v-model="formData.marriage" direction="horizontal" >
<van-radio name="已婚">已婚</van-radio>
<van-radio name="未婚">未婚</van-radio>
</van-radio-group>
</template>
</van-cell>
</van-cell-group>
<!-- 按钮区域 -->
<div class="form-actions">
<van-button native-type="button" @click="historyBack" :disabled="formLoading">返回</van-button>
<van-button native-type="submit" type="primary" :loading="formLoading">保存并继续体检</van-button>
</div>
</van-form>
</div>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
healthCheckupHistory: true,
dicts: ["USER_PERSON_TYPE"],
mixins: [healthCheckupHistoryMixin],
el: "#app",
store,
data() {
return {
project: {},
formLoading: false,
formData: {
sex: "",
age: 0,
marriage: ""
}
};
},
computed: {
personTypeLabel() {
// 人员类别编码使用系统字典展示;兼容已有中文值,避免历史记录显示为空。
const value = this.formData.personType;
const options = this.dict.type.USER_PERSON_TYPE || [];
const option = options.find(item => String(item.code) === String(value));
return option ? option.name : (value || '');
}
},
methods: {
// 打开表单
initData() {
return Promise.resolve(this.findSubject(GetQueryString("projectId"))).then(() => {
if (GetQueryString("projectId")) {
const {
id,
birthday
} = this.$store.state.user;
return Promise.resolve(this.selectInfo(GetQueryString("projectId"), id)).then(() => {
this.$set(this.formData, 'projectId', GetQueryString("projectId"));
// 1. 转成日期对象
// 1. 转成日期对象
if (this.formData.age == null && birthday) {
const birth = new Date(birthday);
const now = new Date();
let age = now.getFullYear() - birth.getFullYear();
const birthMonth = birth.getMonth();
const nowMonth = now.getMonth();
const birthDate = birth.getDate();
const nowDate = now.getDate();
if (nowMonth < birthMonth || nowMonth === birthMonth && nowDate < birthDate) {
age--;
}
this.$set(this.formData, 'age', age);
}
});
} else {}
});
},
findSubject(id) {
return Promise.resolve().then(() => {
return this.$axios.post('/platform/healthCheckup/project/mange/findOne', {
id
}).then(resp => {
this.project = resp.data || {};
});
}).catch(error => {
vant.Toast('获取体检项目失败');
});
},
// 仅提交当前项目允许修改的字段,保存成功后继续选择医院。
doSubmit() {
if (this.formLoading) return;
const age = Number(this.formData.age);
if (this.formData.age == null || this.formData.age === '' || !Number.isInteger(age) || age < 0 || age > 120) {
vant.Toast('请输入0至120的整数年龄');
return;
}
if (!this.formData.marriage) {
vant.Toast('请选择婚姻状态');
return;
}
this.formLoading = true;
return this.$axios.post('/platform/healthCheckup/h5/doSubmitUserBaseMessage', {
projectId: GetQueryString('projectId'), age,
phone: this.formData.phone, card: this.formData.card, marriage: this.formData.marriage
}).then(resp => {
if (resp.code === 0) {
return this.navigateHealthCheckup('/platform/healthCheckup/h5/projectManageForm?projectId=' + encodeURIComponent(GetQueryString('projectId')));
}
vant.Toast(resp.msg || '保存失败');
}).catch(error => {
// 全局拦截器会拒绝业务失败响应;捕获后保留输入,供用户修正并重试。
vant.Toast((error && (error.msg || error.message)) || '保存失败,请重试');
}).finally(() => { this.formLoading = false; });
},
selectInfo(projectId, userId) {
return this.$axios.post('/platform/healthCheckup/h5/findUserBaseMessageData', {
projectId,
userId
}).then(resp => {
if (resp.data !== null) {
this.formData = resp.data;
}
});
}
},
created() {
this.initData().catch(error => {
// 初始化失败时给出可读提示,避免未捕获的 Promise 异常。
vant.Toast((error && (error.msg || error.message)) || '个人信息加载失败,请重试');
});
}
});
</script>
<!--#
}
#-->