模块移植:场地预约、理论学习()
This commit is contained in:
@@ -27,13 +27,14 @@ import java.util.Map;
|
||||
@IocBean
|
||||
public class SmsJshvcServiceImpl implements SmsService {
|
||||
|
||||
private static final String APPID = "";
|
||||
private static final String APP_SECRET = "";
|
||||
private static final String TOKEN_URL = "";
|
||||
private static final String MSG_URL = "";
|
||||
private static final String REDIS_KEY_MSG_ACCESS_TOKEN = "";
|
||||
private static final String APPID = "1430576717768122368";
|
||||
private static final String APP_SECRET = "19A0ACB03FBQHL4R4XQD";
|
||||
private static final String TOKEN_URL = "https://gateway.jshvc.edu.cn/token/gateway/accessToken";
|
||||
private static final String MSG_URL = "https://gateway.jshvc.edu.cn/mp/restful/v2/message/send";
|
||||
private static final String REDIS_KEY_MSG_ACCESS_TOKEN = "msg:token:";
|
||||
|
||||
@Inject
|
||||
|
||||
@Inject
|
||||
private RedisService redisService;
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,19 +3,38 @@ package com.budwk.app.flow.service;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.budwk.app.base.event.flow.jumptofirsttask.FlowJumpToFirstTaskNodePublisher;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.flow.constant.FlowConst;
|
||||
import com.budwk.app.flow.engine.FlowEngine;
|
||||
import com.budwk.app.flow.engine.event.ProcessEvent;
|
||||
import com.budwk.app.flow.engine.event.ProcessPublisher;
|
||||
import com.budwk.app.flow.entity.ProcessInstance;
|
||||
import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.enums.ProcessEventTypeEnum;
|
||||
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
|
||||
import com.budwk.app.flow.enums.ProcessTaskPerformTypeEnum;
|
||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||
import com.budwk.app.flow.enums.ProcessSubmitTypeEnum;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
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.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@IocBean
|
||||
public class FlowCommonService {
|
||||
|
||||
@Inject
|
||||
private FlowEngine flowEngine;
|
||||
|
||||
@Inject
|
||||
private Dao dao;
|
||||
|
||||
/**
|
||||
* 执行任务
|
||||
* @param args
|
||||
@@ -70,4 +89,44 @@ public class FlowCommonService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤销已流转到下一步的任务,并重新激活当前任务和流程实例。
|
||||
* 场馆预约等业务在校工会审核撤回时复用这里的流程状态处理。
|
||||
*/
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result revokeTask(Long taskId) {
|
||||
// 自己任务
|
||||
ProcessTask selfTask = dao.fetch(ProcessTask.class, taskId);
|
||||
selfTask.setTaskState(ProcessTaskStateEnum.DOING.getCode());
|
||||
|
||||
// 撤销任务
|
||||
List<ProcessTask> taskList = dao.query(ProcessTask.class, Cnd.where(ProcessTask::getTaskParentId, "=", taskId));
|
||||
for (ProcessTask task : taskList) {
|
||||
task.setTaskState(ProcessTaskStateEnum.WITHDRAW.getCode());
|
||||
dao.update(task);
|
||||
}
|
||||
// 会签并行任务 撤销后续任务
|
||||
if (selfTask.getPerformType().equals(ProcessTaskPerformTypeEnum.COUNTERSIGN.getCode())) {
|
||||
List<ProcessTask> doingTasks = dao.query(ProcessTask.class, Cnd.where(ProcessTask::getTaskState, "=", ProcessTaskStateEnum.DOING.getCode())
|
||||
.and(ProcessTask::getProcessInstanceId, "=", selfTask.getProcessInstanceId()));
|
||||
for (ProcessTask doingTask : doingTasks) {
|
||||
doingTask.setTaskState(ProcessTaskStateEnum.WITHDRAW.getCode());
|
||||
dao.update(doingTask);
|
||||
}
|
||||
}
|
||||
|
||||
// 激活
|
||||
dao.update(selfTask);
|
||||
|
||||
// 流程激活
|
||||
dao.update(ProcessInstance.class, Chain.make("state", ProcessInstanceStateEnum.DOING.getCode()), Cnd.where(ProcessInstance::getId, "=", selfTask.getProcessInstanceId()));
|
||||
|
||||
// 发送任务撤回事件,保证业务监听能同步处理已撤回节点。
|
||||
for (ProcessTask task : taskList) {
|
||||
ProcessPublisher.notify(ProcessEvent.builder().eventType(ProcessEventTypeEnum.PROCESS_TASK_REVOKE).sourceId(task.getId()).build());
|
||||
}
|
||||
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -211,4 +211,13 @@ public interface ProcessTaskService extends BaseService<ProcessTask> {
|
||||
*/
|
||||
List<ProcessTask> getDoingTaskByBizIdTaskName(List<String> bizIds, String taskName);
|
||||
|
||||
/**
|
||||
* 获取已结束的任务
|
||||
*
|
||||
* @param bizIds 业务ID
|
||||
* @param taskName 任务名称
|
||||
* @return
|
||||
*/
|
||||
List<ProcessTask> getDoneTaskByBizIdTaskName(List<String> bizIds, String taskName);
|
||||
|
||||
}
|
||||
|
||||
@@ -87,6 +87,16 @@ public class ProcessTaskServiceImpl extends BaseServiceImpl<ProcessTask> impleme
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProcessTask> getDoneTaskByBizIdTaskName(List<String> bizIds, String taskName) {
|
||||
List<ProcessInstance> instances = dao().query(ProcessInstance.class, Cnd.where(ProcessInstance::getBusinessNo, "in", bizIds));
|
||||
List<Long> instanceIds = instances.stream().map(ProcessInstance::getId).toList();
|
||||
List<ProcessTask> tasks = dao().query(ProcessTask.class, Cnd.where(ProcessTask::getProcessInstanceId, "in", instanceIds)
|
||||
.and(ProcessTask::getTaskName, "=", taskName)
|
||||
.and(ProcessTask::getTaskState, "=", ProcessTaskStateEnum.FINISHED.getCode()));
|
||||
return tasks;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void saveProcessTask(ProcessTask processTask) {
|
||||
|
||||
@@ -20,7 +20,8 @@ import java.io.Serializable;
|
||||
@Comment("活动人员范围设置")
|
||||
@TableIndexes({
|
||||
@Index(name = "INDEX_ACTIVITY_USER_SCOPE_GROUPID", fields = {"groupId"}, unique = false),
|
||||
@Index(name = "INDEX_ACTIVITY_USER_SCOPE_USERID", fields = {"userId"}, unique = false)
|
||||
@Index(name = "INDEX_ACTIVITY_USER_SCOPE_USERID", fields = {"userId"}, unique = false),
|
||||
@Index(name = "INDEX_ACTIVITY_USER_SCOPE_GROUPID_USERID", fields = {"groupId", "userId"}, unique = false)
|
||||
})
|
||||
public class ActivityUserScope extends BaseModel implements Serializable {
|
||||
|
||||
@@ -46,6 +47,16 @@ public class ActivityUserScope extends BaseModel implements Serializable {
|
||||
@Comment("userid")
|
||||
private String userId;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.INT, width = 2)
|
||||
@Comment("分组类型 1.结果分组 2.SQL条件分组")
|
||||
private Integer groupType;
|
||||
|
||||
@Column
|
||||
@ColDefine(customType = "longtext")
|
||||
@Comment("SQL条件分组保存的查询SQL")
|
||||
private String groupSql;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@Comment("创建人")
|
||||
|
||||
+45
@@ -21,4 +21,49 @@ public interface ActivityBasicScopeService extends BaseService<ActivityUserScope
|
||||
*/
|
||||
void largeDataInsert(List<ActivityUserScope> list) ;
|
||||
|
||||
/**
|
||||
* 查询分组基础信息。
|
||||
* SQL条件分组与结果分组都只从同一张 activity_user_scope 表读取。
|
||||
*/
|
||||
ActivityUserScope getGroupInfo(Integer groupId);
|
||||
|
||||
/**
|
||||
* 查询分组类型,未配置时默认按结果分组处理。
|
||||
*/
|
||||
Integer getGroupType(Integer groupId);
|
||||
|
||||
/**
|
||||
* 构造分组对应的人员ID子查询。
|
||||
* 结果分组直接取 activity_user_scope.userId,SQL条件分组则按保存的 groupSql 动态生成查询。
|
||||
*/
|
||||
Sql buildGroupUserIdSubSql(Integer groupId);
|
||||
|
||||
/**
|
||||
* 构造可直接拼接到业务SQL中的人员ID子查询文本。
|
||||
* 仅用于已有大量原生SQL场景,避免每个模块重复拼接 groupSql 逻辑。
|
||||
*/
|
||||
String buildGroupUserIdSubSqlText(Integer groupId);
|
||||
|
||||
/**
|
||||
* 查询分组当前命中的人员ID列表。
|
||||
*/
|
||||
List<String> listGroupUserIds(Integer groupId);
|
||||
|
||||
/**
|
||||
* 判断指定用户是否在某个分组内。
|
||||
* SQL条件分组会按保存的 groupSql 动态校验,而不是依赖落库的 userId 明细。
|
||||
*/
|
||||
boolean isUserInGroup(Integer groupId, String userId);
|
||||
|
||||
/**
|
||||
* 批量过滤出当前用户可见的分组ID。
|
||||
* 用于列表页先查活动、再按活动分组做二次权限过滤的场景。
|
||||
*/
|
||||
List<Integer> filterGroupIdsByUser(List<Integer> groupIds, String userId);
|
||||
|
||||
/**
|
||||
* SQL条件分组删除人员时,不再删除主表记录,而是把排除条件追加到已保存的 groupSql 中。
|
||||
*/
|
||||
void excludeUsersFromSqlGroup(Integer groupId, List<String> userIds);
|
||||
|
||||
}
|
||||
|
||||
+123
@@ -1,6 +1,7 @@
|
||||
package com.budwk.app.zhgh.activity.basic.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.base.utils.DateUtil;
|
||||
import com.budwk.app.zhgh.activity.basic.models.ActivityUserScope;
|
||||
@@ -8,17 +9,20 @@ import com.budwk.app.zhgh.activity.basic.service.ActivityBasicScopeService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.impl.NutTxDao;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author zxy
|
||||
@@ -29,6 +33,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
@Slf4j
|
||||
public class ActivityBasicScopeServiceImpl extends BaseServiceImpl<ActivityUserScope> implements ActivityBasicScopeService {
|
||||
|
||||
private static final int GROUP_TYPE_RESULT = 1;
|
||||
|
||||
public ActivityBasicScopeServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
@@ -80,4 +85,122 @@ public class ActivityBasicScopeServiceImpl extends BaseServiceImpl<ActivityUserS
|
||||
}
|
||||
log.info("结束时间" + DateUtil.getDateTime());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivityUserScope getGroupInfo(Integer groupId) {
|
||||
if (groupId == null) {
|
||||
return null;
|
||||
}
|
||||
List<ActivityUserScope> list = dao().query(ActivityUserScope.class, Cnd.where("groupId", "=", groupId).desc("id"));
|
||||
return CollectionUtil.isEmpty(list) ? null : list.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getGroupType(Integer groupId) {
|
||||
ActivityUserScope userScope = getGroupInfo(groupId);
|
||||
if (userScope == null || userScope.getGroupType() == null) {
|
||||
return GROUP_TYPE_RESULT;
|
||||
}
|
||||
return userScope.getGroupType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sql buildGroupUserIdSubSql(Integer groupId) {
|
||||
return Sqls.create(buildGroupUserIdSubSqlText(groupId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildGroupUserIdSubSqlText(Integer groupId) {
|
||||
ActivityUserScope groupInfo = getGroupInfo(groupId);
|
||||
if (groupInfo == null) {
|
||||
return "SELECT NULL AS userId WHERE 1 = 0";
|
||||
}
|
||||
if (GROUP_TYPE_RESULT == getGroupType(groupId)) {
|
||||
return "SELECT userId FROM activity_user_scope WHERE groupId = " + groupId + " AND userId IS NOT NULL";
|
||||
}
|
||||
if (StrUtil.isBlank(groupInfo.getGroupSql())) {
|
||||
return "SELECT NULL AS userId WHERE 1 = 0";
|
||||
}
|
||||
return """
|
||||
SELECT DISTINCT
|
||||
u.id AS userId
|
||||
FROM
|
||||
`vw_user` u
|
||||
LEFT JOIN sys_user_role sur ON sur.userid = u.id
|
||||
LEFT JOIN club_user clubuser ON clubuser.userid = u.id
|
||||
WHERE
|
||||
""" + groupInfo.getGroupSql();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> listGroupUserIds(Integer groupId) {
|
||||
Sql sql = Sqls.queryString(buildGroupUserIdSubSqlText(groupId));
|
||||
dao().execute(sql);
|
||||
String[] userIds = (String[]) sql.getResult();
|
||||
return userIds == null ? new ArrayList<>() : List.of(userIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUserInGroup(Integer groupId, String userId) {
|
||||
if (groupId == null || StrUtil.isBlank(userId)) {
|
||||
return false;
|
||||
}
|
||||
if (GROUP_TYPE_RESULT == getGroupType(groupId)) {
|
||||
return dao().count(ActivityUserScope.class, Cnd.where("groupId", "=", groupId).and("userId", "=", userId)) > 0;
|
||||
}
|
||||
ActivityUserScope groupInfo = getGroupInfo(groupId);
|
||||
if (groupInfo == null || StrUtil.isBlank(groupInfo.getGroupSql())) {
|
||||
return false;
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
COUNT(1)
|
||||
FROM
|
||||
`vw_user` u
|
||||
LEFT JOIN sys_user_role sur ON sur.userid = u.id
|
||||
LEFT JOIN club_user clubuser ON clubuser.userid = u.id
|
||||
WHERE
|
||||
u.id = @userId
|
||||
AND
|
||||
""" + "(" + groupInfo.getGroupSql() + ")");
|
||||
sql.setParam("userId", userId);
|
||||
return count(sql) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Integer> filterGroupIdsByUser(List<Integer> groupIds, String userId) {
|
||||
LinkedHashSet<Integer> result = new LinkedHashSet<>();
|
||||
if (CollectionUtil.isEmpty(groupIds) || StrUtil.isBlank(userId)) {
|
||||
return new ArrayList<>(result);
|
||||
}
|
||||
groupIds.stream()
|
||||
.filter(groupId -> groupId != null)
|
||||
.distinct()
|
||||
.forEach(groupId -> {
|
||||
if (isUserInGroup(groupId, userId)) {
|
||||
result.add(groupId);
|
||||
}
|
||||
});
|
||||
return new ArrayList<>(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void excludeUsersFromSqlGroup(Integer groupId, List<String> userIds) {
|
||||
ActivityUserScope groupInfo = getGroupInfo(groupId);
|
||||
if (groupInfo == null || getGroupType(groupId) != 2 || CollectionUtil.isEmpty(userIds) || StrUtil.isBlank(groupInfo.getGroupSql())) {
|
||||
return;
|
||||
}
|
||||
String excludeUserSql = userIds.stream()
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.distinct()
|
||||
.map(userId -> "'" + StrUtil.replace(userId, "'", "''") + "'")
|
||||
.collect(Collectors.joining(","));
|
||||
if (StrUtil.isBlank(excludeUserSql)) {
|
||||
return;
|
||||
}
|
||||
// SQL分组只有一条主记录,删除人员时通过追加排除条件持久化删除结果。
|
||||
String groupSql = "(" + groupInfo.getGroupSql() + ") AND u.id NOT IN (" + excludeUserSql + ")";
|
||||
groupInfo.setGroupSql(groupSql);
|
||||
dao().updateIgnoreNull(groupInfo);
|
||||
}
|
||||
}
|
||||
|
||||
+823
@@ -0,0 +1,823 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
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.result.Result;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.flow.constant.FlowConst;
|
||||
import com.budwk.app.flow.engine.FlowEngine;
|
||||
import com.budwk.app.flow.entity.ProcessInstance;
|
||||
import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
|
||||
import com.budwk.app.flow.enums.ProcessSubmitTypeEnum;
|
||||
import com.budwk.app.sys.models.SysHoliday;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugApply;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugFunctionType;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugInfo;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.service.SiteCugApplyService;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.service.SiteCugInfoService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import java.time.Year;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@IocBean
|
||||
@Ok("json:full")
|
||||
@Api(tags = "\u573a\u5730\u9884\u7ea6-\u573a\u9986")
|
||||
@At("/platform/siteCug/apply")
|
||||
public class SiteCugApplyController {
|
||||
|
||||
private static final String YEARLY_BATCH_PREFIX = "YEARLY_BATCH:";
|
||||
|
||||
@Inject
|
||||
private Dao dao;
|
||||
@Inject
|
||||
private SiteCugInfoService infoService;
|
||||
@Inject
|
||||
private SiteCugApplyService applyService;
|
||||
@Inject
|
||||
private FlowEngine flowEngine;
|
||||
|
||||
@At("/")
|
||||
@SaCheckPermission("siteCug.apply")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/siteCug/apply/index.html")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At("/h5")
|
||||
@SaCheckPermission(value = {"siteCug.apply", "h5.siteCug.apply"}, mode = SaMode.OR)
|
||||
@Ok("beetl:/platform/zhghh5/dayofficework/siteCug/apply/index.html")
|
||||
public void h5Index() {
|
||||
}
|
||||
|
||||
@At("/form/h5")
|
||||
@SaCheckPermission(value = {"siteCug.apply", "h5.siteCug.apply"}, mode = SaMode.OR)
|
||||
@Ok("beetl:/platform/zhghh5/dayofficework/siteCug/apply/form/index.html")
|
||||
public void h5Form() {
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("\u5206\u9875\u67e5\u8be2\u573a\u5730")
|
||||
@SaCheckPermission(value = {"siteCug.apply", "h5.siteCug.apply"}, mode = SaMode.OR)
|
||||
public Result pageData(PageForm pageForm, @Param("type") String type) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and(SiteCugInfo::getState, "=", true);
|
||||
cnd.andEX(SiteCugInfo::getTypeId, "=", type);
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
seg.or(SiteCugInfo::getName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
seg.or(SiteCugInfo::getAddress, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
cnd.and(seg);
|
||||
}
|
||||
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||
cnd.asc("sortNum * 1");
|
||||
} else {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
}
|
||||
Pagination pagination = infoService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), cnd);
|
||||
List<NutMap> listMap = pagination.getList(NutMap.class);
|
||||
|
||||
List<SiteCugFunctionType> typeList = dao.query(SiteCugFunctionType.class, Cnd.NEW());
|
||||
Map<String, String> typeMap = typeList.stream().collect(Collectors.toMap(SiteCugFunctionType::getId, SiteCugFunctionType::getName));
|
||||
List<String> siteIds = listMap.stream().map(item -> item.getString("id")).filter(StrUtil::isNotBlank).toList();
|
||||
String today = DateUtil.today();
|
||||
String dayStart = today + " 00:00:00";
|
||||
String dayEnd = today + " 23:59:59";
|
||||
Map<String, List<SiteCugApply>> applyMap = queryTodayApplyMap(siteIds, dayStart, dayEnd);
|
||||
Set<String> holidaySet = dao.query(SysHoliday.class, Cnd.NEW()).stream()
|
||||
.map(SysHoliday::getDay)
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.collect(Collectors.toSet());
|
||||
for (NutMap map : listMap) {
|
||||
map.put("typeName", typeMap.get(map.getString("typeId")));
|
||||
map.put("reserveTimeTypeName", getReserveTimeTypeName(map.getInt("reserveTimeType")));
|
||||
map.put("timelineSegments", buildTimelineSegments(map, applyMap.getOrDefault(map.getString("id"), new ArrayList<>()), today, holidaySet));
|
||||
}
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("\u67e5\u8be2\u573a\u5730\u53ef\u9884\u7ea6\u65f6\u6bb5")
|
||||
@SaCheckPermission(value = {"siteCug.apply", "h5.siteCug.apply"}, mode = SaMode.OR)
|
||||
public Result availability(@Param("siteId") String siteId, @Param("date") String date) {
|
||||
if (StrUtil.isBlank(siteId)) {
|
||||
return Result.error("\u573a\u5730\u4e0d\u80fd\u4e3a\u7a7a");
|
||||
}
|
||||
String targetDate = StrUtil.isBlank(date) ? DateUtil.today() : date;
|
||||
if (!targetDate.matches("^\\d{4}-\\d{2}-\\d{2}$")) {
|
||||
return Result.error("\u9884\u7ea6\u65e5\u671f\u683c\u5f0f\u4e0d\u6b63\u786e");
|
||||
}
|
||||
SiteCugInfo siteInfo = infoService.fetch(siteId);
|
||||
if (siteInfo == null) {
|
||||
return Result.error("\u573a\u5730\u4e0d\u5b58\u5728");
|
||||
}
|
||||
Set<String> holidaySet = queryHolidaySet();
|
||||
List<SiteCugApply> applyList = queryDayApplyList(siteId, targetDate + " 00:00:00", targetDate + " 23:59:59");
|
||||
return Result.success(NutMap.NEW()
|
||||
.addv("date", targetDate)
|
||||
.addv("reserveTimeType", siteInfo.getReserveTimeType())
|
||||
.addv("reserveTimeTypeName", getReserveTimeTypeName(siteInfo.getReserveTimeType()))
|
||||
.addv("blocks", buildAvailabilityBlocks(siteInfo, targetDate, applyList, holidaySet)));
|
||||
}
|
||||
|
||||
private Map<String, List<SiteCugApply>> queryTodayApplyMap(List<String> siteIds, String dayStart, String dayEnd) {
|
||||
if (siteIds == null || siteIds.isEmpty()) {
|
||||
return Map.of();
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
select
|
||||
sa.*
|
||||
from
|
||||
site_cug_apply sa
|
||||
left join wf_process_instance ins on ins.businessNo = sa.id
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("sa.siteId", "in", siteIds);
|
||||
cnd.and("ins.state", "in", List.of(
|
||||
ProcessInstanceStateEnum.DOING.getCode(),
|
||||
ProcessInstanceStateEnum.FINISHED.getCode(),
|
||||
ProcessInstanceStateEnum.PENDING.getCode()
|
||||
));
|
||||
cnd.and("sa.reserveEndTime", ">=", dayStart);
|
||||
cnd.and("sa.reserveStartTime", "<=", dayEnd);
|
||||
sql.setCondition(cnd);
|
||||
sql.setEntity(dao.getEntity(SiteCugApply.class));
|
||||
sql.setCallback(Sqls.callback.entities());
|
||||
dao.execute(sql);
|
||||
List<SiteCugApply> applyList = sql.getList(SiteCugApply.class);
|
||||
if (applyList == null || applyList.isEmpty()) {
|
||||
return Map.of();
|
||||
}
|
||||
return applyList.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.groupingBy(SiteCugApply::getSiteId));
|
||||
}
|
||||
|
||||
private List<SiteCugApply> queryDayApplyList(String siteId, String dayStart, String dayEnd) {
|
||||
if (StrUtil.isBlank(siteId)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
select
|
||||
sa.*
|
||||
from
|
||||
site_cug_apply sa
|
||||
left join wf_process_instance ins on ins.businessNo = sa.id
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("sa.siteId", "=", siteId);
|
||||
cnd.and("ins.state", "in", List.of(
|
||||
ProcessInstanceStateEnum.DOING.getCode(),
|
||||
ProcessInstanceStateEnum.FINISHED.getCode(),
|
||||
ProcessInstanceStateEnum.PENDING.getCode()
|
||||
));
|
||||
cnd.and("sa.reserveEndTime", ">=", dayStart);
|
||||
cnd.and("sa.reserveStartTime", "<=", dayEnd);
|
||||
sql.setCondition(cnd);
|
||||
sql.setEntity(dao.getEntity(SiteCugApply.class));
|
||||
sql.setCallback(Sqls.callback.entities());
|
||||
dao.execute(sql);
|
||||
List<SiteCugApply> applyList = sql.getList(SiteCugApply.class);
|
||||
return applyList == null ? new ArrayList<>() : applyList;
|
||||
}
|
||||
|
||||
private Set<String> queryHolidaySet() {
|
||||
return dao.query(SysHoliday.class, Cnd.NEW()).stream()
|
||||
.map(SysHoliday::getDay)
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private String getReserveTimeTypeName(Integer reserveTimeType) {
|
||||
if (reserveTimeType != null && reserveTimeType == 2) {
|
||||
return "\u5168\u5929\u5019\u9884\u7ea6";
|
||||
}
|
||||
return "\u5206\u6bb5\u9884\u7ea6";
|
||||
}
|
||||
|
||||
private List<NutMap> buildTimelineSegments(NutMap site, List<SiteCugApply> applyList, String today, Set<String> holidaySet) {
|
||||
List<NutMap> segments = new ArrayList<>();
|
||||
boolean isWeekend = isWeekend(today);
|
||||
boolean isHoliday = holidaySet.contains(today);
|
||||
List<int[]> openRanges = buildOpenRanges(site, isWeekend, isHoliday);
|
||||
List<int[]> disabledRanges = buildDisabledRanges(site, today);
|
||||
List<int[]> reservedRanges = buildReservedRanges(applyList, today);
|
||||
int totalMinutes = 24 * 60;
|
||||
int segmentMinutes = 30;
|
||||
for (int start = 0; start < totalMinutes; start += segmentMinutes) {
|
||||
int end = start + segmentMinutes;
|
||||
String status = "closed";
|
||||
if (intersectsAny(start, end, openRanges)) {
|
||||
status = "available";
|
||||
}
|
||||
if (intersectsAny(start, end, disabledRanges)) {
|
||||
status = "closed";
|
||||
}
|
||||
if (!"closed".equals(status) && intersectsAny(start, end, reservedRanges)) {
|
||||
status = "reserved";
|
||||
}
|
||||
segments.add(NutMap.NEW()
|
||||
.addv("status", status)
|
||||
.addv("startMinute", start)
|
||||
.addv("endMinute", end));
|
||||
}
|
||||
return segments;
|
||||
}
|
||||
|
||||
private List<int[]> buildOpenRanges(NutMap site, boolean isWeekend, boolean isHoliday) {
|
||||
if (isWeekend) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
if (Boolean.TRUE.equals(site.getBoolean("filterHolidays")) && isHoliday) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
Integer reserveTimeType = site.getInt("reserveTimeType");
|
||||
if (reserveTimeType != null && reserveTimeType == 2) {
|
||||
NutMap fullDayOpenHour = toNutMap(site.get("fullDayOpenHour"));
|
||||
if (fullDayOpenHour.isEmpty()) {
|
||||
List<NutMap> openHours = toNutMapList(site.get("openHours"));
|
||||
fullDayOpenHour = openHours.isEmpty() ? NutMap.NEW() : openHours.get(0);
|
||||
}
|
||||
return parseTimeRanges(List.of(fullDayOpenHour));
|
||||
}
|
||||
List<NutMap> segmentedOpenHours = toNutMapList(site.get("segmentedOpenHours"));
|
||||
if (segmentedOpenHours.isEmpty()) {
|
||||
segmentedOpenHours = toNutMapList(site.get("openHours"));
|
||||
}
|
||||
return parseTimeRanges(segmentedOpenHours);
|
||||
}
|
||||
|
||||
private List<int[]> buildDisabledRanges(NutMap site, String today) {
|
||||
List<NutMap> disabledList = toNutMapList(site.get("notApplyTimeList"));
|
||||
List<int[]> result = new ArrayList<>();
|
||||
for (NutMap item : disabledList) {
|
||||
if (item == null || !StrUtil.equals(today, item.getString("date"))) {
|
||||
continue;
|
||||
}
|
||||
Integer start = parseTimeToMinutes(item.getString("startTime"));
|
||||
Integer end = parseTimeToMinutes(item.getString("endTime"));
|
||||
if (start != null && end != null && end > start) {
|
||||
result.add(new int[]{start, end});
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<int[]> buildReservedRanges(List<SiteCugApply> applyList, String today) {
|
||||
List<int[]> result = new ArrayList<>();
|
||||
String dayStart = today + " 00:00:00";
|
||||
String dayEnd = today + " 23:59:59";
|
||||
DateTime startOfDay = DateUtil.parseDateTime(dayStart);
|
||||
DateTime endOfDay = DateUtil.parseDateTime(dayEnd);
|
||||
for (SiteCugApply item : applyList) {
|
||||
if (item == null || StrUtil.hasBlank(item.getReserveStartTime(), item.getReserveEndTime())) {
|
||||
continue;
|
||||
}
|
||||
DateTime reserveStart = DateUtil.parseDateTime(item.getReserveStartTime());
|
||||
DateTime reserveEnd = DateUtil.parseDateTime(item.getReserveEndTime());
|
||||
if (!reserveEnd.isAfter(reserveStart)) {
|
||||
continue;
|
||||
}
|
||||
DateTime actualStart = reserveStart.isBefore(startOfDay) ? startOfDay : reserveStart;
|
||||
DateTime actualEnd = reserveEnd.isAfter(endOfDay) ? endOfDay : reserveEnd;
|
||||
int startMinute = actualStart.hour(true) * 60 + actualStart.minute();
|
||||
int endMinute = actualEnd.hour(true) * 60 + actualEnd.minute();
|
||||
if (actualEnd.second() > 0) {
|
||||
endMinute = Math.min(24 * 60, endMinute + 1);
|
||||
}
|
||||
if (endMinute > startMinute) {
|
||||
result.add(new int[]{startMinute, endMinute});
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<int[]> parseTimeRanges(List<NutMap> sourceList) {
|
||||
List<int[]> result = new ArrayList<>();
|
||||
for (NutMap item : sourceList) {
|
||||
if (item == null) {
|
||||
continue;
|
||||
}
|
||||
Integer start = parseTimeToMinutes(item.getString("startTime"));
|
||||
Integer end = parseTimeToMinutes(item.getString("endTime"));
|
||||
if (start != null && end != null && end > start) {
|
||||
result.add(new int[]{start, end});
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private NutMap toNutMap(Object value) {
|
||||
if (value instanceof NutMap nutMap) {
|
||||
return nutMap;
|
||||
}
|
||||
if (value instanceof Map<?, ?> map) {
|
||||
NutMap nutMap = NutMap.NEW();
|
||||
map.forEach((key, val) -> nutMap.put(String.valueOf(key), val));
|
||||
return nutMap;
|
||||
}
|
||||
return NutMap.NEW();
|
||||
}
|
||||
|
||||
private List<NutMap> toNutMapList(Object value) {
|
||||
List<NutMap> result = new ArrayList<>();
|
||||
if (!(value instanceof List<?> list)) {
|
||||
return result;
|
||||
}
|
||||
for (Object item : list) {
|
||||
result.add(toNutMap(item));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Integer parseTimeToMinutes(String timeText) {
|
||||
if (StrUtil.isBlank(timeText)) {
|
||||
return null;
|
||||
}
|
||||
List<String> parts = Arrays.stream(timeText.split(":"))
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.toList();
|
||||
if (parts.size() < 2) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
int hour = Integer.parseInt(parts.get(0));
|
||||
int minute = Integer.parseInt(parts.get(1));
|
||||
if (hour < 0 || hour > 24 || minute < 0 || minute > 59) {
|
||||
return null;
|
||||
}
|
||||
if (hour == 24 && minute > 0) {
|
||||
return null;
|
||||
}
|
||||
return hour * 60 + minute;
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean intersectsAny(int start, int end, List<int[]> ranges) {
|
||||
for (int[] range : ranges) {
|
||||
if (range != null && start < range[1] && end > range[0]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isWeekend(String dateText) {
|
||||
DateTime date = DateUtil.parseDate(dateText);
|
||||
int week = date.dayOfWeek() - 1;
|
||||
return week == 0 || week == 6;
|
||||
}
|
||||
|
||||
private List<NutMap> buildAvailabilityBlocks(SiteCugInfo siteInfo, String day, List<SiteCugApply> applyList, Set<String> holidaySet) {
|
||||
if (siteInfo.getReserveTimeType() != null && siteInfo.getReserveTimeType() == 2) {
|
||||
return buildFullDayAvailabilityBlocks(siteInfo, day, applyList, holidaySet);
|
||||
}
|
||||
return buildSegmentedAvailabilityBlocks(siteInfo, day, applyList, holidaySet);
|
||||
}
|
||||
|
||||
private List<NutMap> buildSegmentedAvailabilityBlocks(SiteCugInfo siteInfo, String day, List<SiteCugApply> applyList, Set<String> holidaySet) {
|
||||
List<NutMap> sourceList = siteInfo.getSegmentedOpenHours();
|
||||
if (sourceList == null || sourceList.isEmpty()) {
|
||||
sourceList = siteInfo.getOpenHours();
|
||||
}
|
||||
List<NutMap> result = new ArrayList<>();
|
||||
List<int[]> reservedRanges = buildReservedRanges(applyList, day);
|
||||
List<int[]> disabledRanges = buildDisabledRanges(toSiteNutMap(siteInfo), day);
|
||||
boolean siteClosed = isSiteClosed(siteInfo, day, holidaySet);
|
||||
for (int i = 0; i < sourceList.size(); i++) {
|
||||
NutMap item = toNutMap(sourceList.get(i));
|
||||
Integer slotStart = parseTimeToMinutes(item.getString("startTime"));
|
||||
Integer slotEnd = parseTimeToMinutes(item.getString("endTime"));
|
||||
int unitMinutes = parseTimeUnitMinutes(item.get("timeUnit"));
|
||||
if (slotStart == null || slotEnd == null || slotEnd <= slotStart || unitMinutes <= 0) {
|
||||
continue;
|
||||
}
|
||||
String groupLabel = "\u573a\u6b21" + (i + 1) + " " + formatMinutes(slotStart) + "-" + formatMinutes(slotEnd) + " / " + formatUnitText(unitMinutes);
|
||||
for (int cursor = slotStart; cursor + unitMinutes <= slotEnd; cursor += unitMinutes) {
|
||||
int blockEnd = cursor + unitMinutes;
|
||||
result.add(buildAvailabilityBlock(day, cursor, blockEnd, reservedRanges, disabledRanges, siteClosed, i, groupLabel));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<NutMap> buildFullDayAvailabilityBlocks(SiteCugInfo siteInfo, String day, List<SiteCugApply> applyList, Set<String> holidaySet) {
|
||||
NutMap source = getFullDayOpenHourConfig(siteInfo);
|
||||
Integer slotStart = parseTimeToMinutes(source.getString("startTime"));
|
||||
Integer slotEnd = parseTimeToMinutes(source.getString("endTime"));
|
||||
int unitMinutes = parseTimeUnitMinutes(source.get("timeUnit"));
|
||||
if (slotStart == null || slotEnd == null || slotEnd <= slotStart || unitMinutes <= 0) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
List<NutMap> result = new ArrayList<>();
|
||||
List<int[]> reservedRanges = buildReservedRanges(applyList, day);
|
||||
List<int[]> disabledRanges = buildDisabledRanges(toSiteNutMap(siteInfo), day);
|
||||
boolean siteClosed = isSiteClosed(siteInfo, day, holidaySet);
|
||||
String groupLabel = "\u5168\u5929\u5019\u65f6\u6bb5 / " + formatUnitText(unitMinutes);
|
||||
for (int cursor = slotStart; cursor + unitMinutes <= slotEnd; cursor += unitMinutes) {
|
||||
int blockEnd = cursor + unitMinutes;
|
||||
result.add(buildAvailabilityBlock(day, cursor, blockEnd, reservedRanges, disabledRanges, siteClosed, 0, groupLabel));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当预约日期就是今天时,已经过了开始时间的时间块直接标记为不可预约,
|
||||
* 这样全天候和分段预约在前端展示时都会统一变成禁用状态。
|
||||
*/
|
||||
private NutMap buildAvailabilityBlock(String day, int startMinute, int endMinute, List<int[]> reservedRanges, List<int[]> disabledRanges, boolean siteClosed, int groupIndex, String groupLabel) {
|
||||
String status = "available";
|
||||
if (siteClosed || isExpiredAvailabilityBlock(day, startMinute) || intersectsAny(startMinute, endMinute, disabledRanges)) {
|
||||
status = "closed";
|
||||
} else if (intersectsAny(startMinute, endMinute, reservedRanges)) {
|
||||
status = "reserved";
|
||||
}
|
||||
return NutMap.NEW()
|
||||
.addv("key", day + "_" + startMinute + "_" + endMinute)
|
||||
.addv("groupIndex", groupIndex)
|
||||
.addv("groupLabel", groupLabel)
|
||||
.addv("status", status)
|
||||
.addv("startMinute", startMinute)
|
||||
.addv("endMinute", endMinute)
|
||||
.addv("startTime", formatMinutes(startMinute))
|
||||
.addv("endTime", formatMinutes(endMinute))
|
||||
.addv("label", formatMinutes(startMinute) + "-" + formatMinutes(endMinute))
|
||||
.addv("startDateTime", day + " " + formatMinutes(startMinute) + ":00")
|
||||
.addv("endDateTime", day + " " + formatMinutes(endMinute) + ":00");
|
||||
}
|
||||
|
||||
/**
|
||||
* 仅在当天按“时间块开始时间是否已经过去”判断是否失效,
|
||||
* 避免用户继续选中已经开始或已经结束的预约时段。
|
||||
*/
|
||||
private boolean isExpiredAvailabilityBlock(String day, int startMinute) {
|
||||
String today = DateUtil.today();
|
||||
if (!StrUtil.equals(today, day)) {
|
||||
return false;
|
||||
}
|
||||
DateTime blockStart = DateUtil.parseDateTime(day + " " + formatMinutes(startMinute) + ":00");
|
||||
return !blockStart.isAfter(DateUtil.date());
|
||||
}
|
||||
|
||||
private boolean isSiteClosed(SiteCugInfo siteInfo, String day, Set<String> holidaySet) {
|
||||
if (isWeekend(day)) {
|
||||
return true;
|
||||
}
|
||||
return Boolean.TRUE.equals(siteInfo.getFilterHolidays()) && holidaySet.contains(day);
|
||||
}
|
||||
|
||||
private NutMap toSiteNutMap(SiteCugInfo siteInfo) {
|
||||
return NutMap.NEW()
|
||||
.addv("notApplyTimeList", siteInfo.getNotApplyTimeList())
|
||||
.addv("filterHolidays", siteInfo.getFilterHolidays())
|
||||
.addv("reserveTimeType", siteInfo.getReserveTimeType())
|
||||
.addv("openHours", siteInfo.getOpenHours())
|
||||
.addv("segmentedOpenHours", siteInfo.getSegmentedOpenHours())
|
||||
.addv("fullDayOpenHour", siteInfo.getFullDayOpenHour());
|
||||
}
|
||||
|
||||
private NutMap getFullDayOpenHourConfig(SiteCugInfo siteInfo) {
|
||||
NutMap source = toNutMap(siteInfo.getFullDayOpenHour());
|
||||
if (!source.isEmpty()) {
|
||||
return source;
|
||||
}
|
||||
List<NutMap> openHours = siteInfo.getOpenHours();
|
||||
return openHours == null || openHours.isEmpty() ? NutMap.NEW() : toNutMap(openHours.get(0));
|
||||
}
|
||||
|
||||
private int parseTimeUnitMinutes(Object value) {
|
||||
if (value == null) {
|
||||
return 60;
|
||||
}
|
||||
try {
|
||||
double unit = Double.parseDouble(String.valueOf(value));
|
||||
if (unit <= 0) {
|
||||
return 60;
|
||||
}
|
||||
return (int) Math.round(unit);
|
||||
} catch (NumberFormatException e) {
|
||||
return 60;
|
||||
}
|
||||
}
|
||||
|
||||
private String formatMinutes(int totalMinutes) {
|
||||
int hour = totalMinutes / 60;
|
||||
int minute = totalMinutes % 60;
|
||||
return String.format("%02d:%02d", hour, minute);
|
||||
}
|
||||
|
||||
private String formatUnitText(int unitMinutes) {
|
||||
return unitMinutes + "\u5206\u949f";
|
||||
}
|
||||
|
||||
private Result validateApplySelectionBySchedule(SiteCugApply apply) {
|
||||
if (apply == null || StrUtil.hasBlank(apply.getSiteId(), apply.getReserveStartTime(), apply.getReserveEndTime())) {
|
||||
return Result.success();
|
||||
}
|
||||
SiteCugInfo siteInfo = infoService.fetch(apply.getSiteId());
|
||||
if (siteInfo == null) {
|
||||
return Result.error("\u573a\u5730\u4e0d\u5b58\u5728");
|
||||
}
|
||||
DateTime start = DateUtil.parseDateTime(apply.getReserveStartTime());
|
||||
DateTime end = DateUtil.parseDateTime(apply.getReserveEndTime());
|
||||
String startDay = DateUtil.formatDate(start);
|
||||
String endDay = DateUtil.formatDate(end);
|
||||
if (!StrUtil.equals(startDay, endDay)) {
|
||||
return Result.error("\u9884\u7ea6\u65f6\u95f4\u5fc5\u987b\u5728\u540c\u4e00\u5929\u5185");
|
||||
}
|
||||
Set<String> holidaySet = queryHolidaySet();
|
||||
List<SiteCugApply> applyList = queryDayApplyList(apply.getSiteId(), startDay + " 00:00:00", startDay + " 23:59:59").stream()
|
||||
.filter(item -> item != null && !StrUtil.equals(item.getId(), apply.getId()))
|
||||
.collect(Collectors.toList());
|
||||
if (siteInfo.getReserveTimeType() != null && siteInfo.getReserveTimeType() == 2) {
|
||||
if (!isWithinOpenRanges(siteInfo, startDay, start, end, holidaySet)) {
|
||||
return Result.error("\u5168\u5929\u5019\u9884\u7ea6\u8bf7\u5728\u5f53\u5929\u5f00\u653e\u65f6\u95f4\u5185\u6309\u9884\u7ea6\u65f6\u95f4\u5355\u4f4d\u9009\u62e9\u4e00\u4e2a\u6216\u591a\u4e2a\u8fde\u7eed\u65f6\u6bb5");
|
||||
}
|
||||
if (!isAlignedWithFullDayTimeUnit(siteInfo, start, end)) {
|
||||
return Result.error("\u5168\u5929\u5019\u9884\u7ea6\u7684\u5f00\u59cb\u548c\u7ed3\u675f\u65f6\u95f4\u5fc5\u987b\u7b26\u5408\u9884\u7ea6\u65f6\u95f4\u5355\u4f4d");
|
||||
}
|
||||
return Result.success();
|
||||
}
|
||||
List<NutMap> blocks = buildSegmentedAvailabilityBlocks(siteInfo, startDay, applyList, holidaySet);
|
||||
String startText = apply.getReserveStartTime();
|
||||
String endText = apply.getReserveEndTime();
|
||||
for (int i = 0; i < blocks.size(); i++) {
|
||||
NutMap block = blocks.get(i);
|
||||
if (!"available".equals(block.getString("status"))) {
|
||||
continue;
|
||||
}
|
||||
if (!StrUtil.equals(startText, block.getString("startDateTime"))) {
|
||||
continue;
|
||||
}
|
||||
String currentEnd = block.getString("endDateTime");
|
||||
if (StrUtil.equals(endText, currentEnd)) {
|
||||
return Result.success();
|
||||
}
|
||||
for (int j = i + 1; j < blocks.size(); j++) {
|
||||
NutMap nextBlock = blocks.get(j);
|
||||
NutMap prevBlock = blocks.get(j - 1);
|
||||
if (!"available".equals(nextBlock.getString("status"))) {
|
||||
break;
|
||||
}
|
||||
if (!StrUtil.equals(prevBlock.getString("endDateTime"), nextBlock.getString("startDateTime"))) {
|
||||
break;
|
||||
}
|
||||
currentEnd = nextBlock.getString("endDateTime");
|
||||
if (StrUtil.equals(endText, currentEnd)) {
|
||||
return Result.success();
|
||||
}
|
||||
}
|
||||
}
|
||||
return Result.error("\u5206\u6bb5\u9884\u7ea6\u8bf7\u6309\u573a\u6b21\u65f6\u95f4\u5355\u4f4d\u9009\u62e9\u4e00\u4e2a\u6216\u591a\u4e2a\u8fde\u7eed\u65f6\u6bb5");
|
||||
}
|
||||
|
||||
private boolean isWithinOpenRanges(SiteCugInfo siteInfo, String day, DateTime start, DateTime end, Set<String> holidaySet) {
|
||||
if (isSiteClosed(siteInfo, day, holidaySet)) {
|
||||
return false;
|
||||
}
|
||||
List<int[]> openRanges = buildOpenRanges(toSiteNutMap(siteInfo), false, false);
|
||||
List<int[]> disabledRanges = buildDisabledRanges(toSiteNutMap(siteInfo), day);
|
||||
int startMinute = start.hour(true) * 60 + start.minute();
|
||||
int endMinute = end.hour(true) * 60 + end.minute();
|
||||
if (end.second() > 0) {
|
||||
endMinute = Math.min(24 * 60, endMinute + 1);
|
||||
}
|
||||
final int finalEndMinute = endMinute;
|
||||
boolean inOpenRange = openRanges.stream().anyMatch(range -> startMinute >= range[0] && finalEndMinute <= range[1]);
|
||||
return inOpenRange && !intersectsAny(startMinute, finalEndMinute, disabledRanges);
|
||||
}
|
||||
|
||||
private boolean isAlignedWithFullDayTimeUnit(SiteCugInfo siteInfo, DateTime start, DateTime end) {
|
||||
if (start == null || end == null || start.second() > 0 || end.second() > 0) {
|
||||
return false;
|
||||
}
|
||||
NutMap source = getFullDayOpenHourConfig(siteInfo);
|
||||
Integer slotStart = parseTimeToMinutes(source.getString("startTime"));
|
||||
Integer slotEnd = parseTimeToMinutes(source.getString("endTime"));
|
||||
int unitMinutes = parseTimeUnitMinutes(source.get("timeUnit"));
|
||||
if (slotStart == null || slotEnd == null || slotEnd <= slotStart || unitMinutes <= 0) {
|
||||
return false;
|
||||
}
|
||||
int startMinute = start.hour(true) * 60 + start.minute();
|
||||
int endMinute = end.hour(true) * 60 + end.minute();
|
||||
return startMinute >= slotStart
|
||||
&& endMinute <= slotEnd
|
||||
&& endMinute > startMinute
|
||||
&& (startMinute - slotStart) % unitMinutes == 0
|
||||
&& (endMinute - slotStart) % unitMinutes == 0;
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("\u63d0\u4ea4\u9884\u7ea6")
|
||||
@SaCheckPermission(value = {"siteCug.apply", "h5.siteCug.apply"}, mode = SaMode.OR)
|
||||
@SLog(tag = "\u573a\u9986\u529f\u80fd\u7ba1\u7406-\u573a\u5730\u9884\u7ea6", msg = "\u63d0\u4ea4\u573a\u5730\u9884\u7ea6")
|
||||
public Result submit(@Param("data") SiteCugApply apply) {
|
||||
Result scheduleValidate = validateApplySelectionBySchedule(apply);
|
||||
if (scheduleValidate.getCode() != 0) {
|
||||
return scheduleValidate;
|
||||
}
|
||||
Map<Boolean, String> validate = applyService.validateApply(apply);
|
||||
if (validate.containsKey(false)) {
|
||||
return Result.error(validate.get(false));
|
||||
}
|
||||
submitSingleApply(apply);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At("/submitYearly")
|
||||
@ApiOperation("\u6309\u672c\u5e74\u540e\u7eed\u540c\u661f\u671f\u540c\u65f6\u95f4\u6bb5\u6279\u91cf\u63d0\u4ea4\u9884\u7ea6")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission(value = {"siteCug.apply", "h5.siteCug.apply"}, mode = SaMode.OR)
|
||||
@SLog(tag = "\u573a\u9986\u529f\u80fd\u7ba1\u7406-\u573a\u5730\u9884\u7ea6", msg = "\u6279\u91cf\u63d0\u4ea4\u672c\u5e74\u573a\u5730\u9884\u7ea6")
|
||||
public Result submitYearly(@Param("data") SiteCugApply apply) {
|
||||
List<SiteCugApply> applyList = buildYearlyApplyList(apply);
|
||||
if (applyList.isEmpty()) {
|
||||
return Result.error("\u672a\u751f\u6210\u53ef\u9884\u7ea6\u7684\u65e5\u671f");
|
||||
}
|
||||
for (SiteCugApply item : applyList) {
|
||||
Result scheduleValidate = validateApplySelectionBySchedule(item);
|
||||
if (scheduleValidate.getCode() != 0) {
|
||||
return scheduleValidate;
|
||||
}
|
||||
Map<Boolean, String> validate = applyService.validateApply(item);
|
||||
if (validate.containsKey(false)) {
|
||||
return Result.error(String.format("%s \u9884\u7ea6\u5931\u8d25\uff1a%s", item.getReserveStartTime(), validate.get(false)));
|
||||
}
|
||||
}
|
||||
String yearlyBatchNo = YEARLY_BATCH_PREFIX + UUID.randomUUID();
|
||||
for (SiteCugApply item : applyList) {
|
||||
item.setBackOption(yearlyBatchNo);
|
||||
submitSingleApply(item);
|
||||
}
|
||||
return Result.success(String.format("\u5df2\u6210\u529f\u9884\u7ea6\u622a\u81f3%s\u5171%d\u4e2a\u65f6\u95f4\u6bb5", apply.getYearlyReserveEndDate(), applyList.size()));
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("\u67e5\u8be2\u9884\u7ea6\u9650\u5236\u914d\u7f6e")
|
||||
@SaCheckPermission(value = {"siteCug.apply", "h5.siteCug.apply"}, mode = SaMode.OR)
|
||||
public Result timeLimitConfig(@Param("siteId") String siteId) {
|
||||
if (StrUtil.isBlank(siteId)) {
|
||||
return Result.success(NutMap.NEW().addv("filterHolidays", false).addv("holidayList", new ArrayList<>()).addv("notApplyTimeList", new ArrayList<>()));
|
||||
}
|
||||
SiteCugInfo info = infoService.fetch(siteId);
|
||||
if (info == null) {
|
||||
return Result.success(NutMap.NEW().addv("filterHolidays", false).addv("holidayList", new ArrayList<>()).addv("notApplyTimeList", new ArrayList<>()));
|
||||
}
|
||||
List<String> holidayList = new ArrayList<>();
|
||||
if (Boolean.TRUE.equals(info.getFilterHolidays())) {
|
||||
int currentYear = Year.now().getValue();
|
||||
List<String> yearPrefixList = List.of(currentYear + "-", (currentYear + 1) + "-");
|
||||
List<SysHoliday> holidays = dao.query(SysHoliday.class, Cnd.NEW());
|
||||
holidayList = holidays.stream()
|
||||
.map(SysHoliday::getDay)
|
||||
.filter(day -> day != null && yearPrefixList.stream().anyMatch(day::startsWith))
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
return Result.success(NutMap.NEW()
|
||||
.addv("filterHolidays", Boolean.TRUE.equals(info.getFilterHolidays()))
|
||||
.addv("holidayList", holidayList)
|
||||
.addv("notApplyTimeList", info.getNotApplyTimeList() == null ? new ArrayList<>() : info.getNotApplyTimeList()));
|
||||
}
|
||||
|
||||
private List<SiteCugApply> buildYearlyApplyList(SiteCugApply apply) {
|
||||
if (apply == null || StrUtil.hasBlank(apply.getReserveStartTime(), apply.getReserveEndTime(), apply.getYearlyReserveEndDate())) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
DateTime start = DateUtil.parseDateTime(apply.getReserveStartTime());
|
||||
DateTime end = DateUtil.parseDateTime(apply.getReserveEndTime());
|
||||
if (!end.isAfter(start)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
DateTime reserveEndDate = parseReserveEndDate(apply.getYearlyReserveEndDate());
|
||||
if (reserveEndDate == null || reserveEndDate.isBefore(DateUtil.beginOfDay(start))) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
SiteCugInfo siteInfo = infoService.fetch(apply.getSiteId());
|
||||
if (siteInfo == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
List<String> holidayList = new ArrayList<>();
|
||||
if (Boolean.TRUE.equals(siteInfo.getFilterHolidays())) {
|
||||
int currentYear = start.year();
|
||||
List<String> yearPrefixList = List.of(currentYear + "-", (currentYear + 1) + "-");
|
||||
List<SysHoliday> holidays = dao.query(SysHoliday.class, Cnd.NEW());
|
||||
holidayList = holidays.stream()
|
||||
.map(SysHoliday::getDay)
|
||||
.filter(day -> day != null && yearPrefixList.stream().anyMatch(day::startsWith))
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
int targetWeek = start.dayOfWeek() - 1;
|
||||
int startHour = start.hour(true);
|
||||
int startMinute = start.minute();
|
||||
int startSecond = start.second();
|
||||
int endHour = end.hour(true);
|
||||
int endMinute = end.minute();
|
||||
int endSecond = end.second();
|
||||
Date current = DateUtil.beginOfDay(start);
|
||||
Date batchEndDate = DateUtil.endOfDay(reserveEndDate);
|
||||
List<SiteCugApply> result = new ArrayList<>();
|
||||
while (current.compareTo(batchEndDate) <= 0) {
|
||||
DateTime currentDate = DateUtil.date(current);
|
||||
String currentDay = DateUtil.formatDate(currentDate);
|
||||
if (currentDate.dayOfWeek() - 1 == targetWeek && !holidayList.contains(currentDay)) {
|
||||
SiteCugApply item = copyApply(apply);
|
||||
item.setId(null);
|
||||
item.setReserveStartTime(DateUtil.formatDateTime(buildDateTime(currentDate, startHour, startMinute, startSecond)));
|
||||
item.setReserveEndTime(DateUtil.formatDateTime(buildDateTime(currentDate, endHour, endMinute, endSecond)));
|
||||
result.add(item);
|
||||
}
|
||||
current = DateUtil.offsetDay(current, 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private DateTime parseReserveEndDate(String endDate) {
|
||||
if (StrUtil.isBlank(endDate)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return DateUtil.parseDate(endDate);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private DateTime buildDateTime(DateTime date, int hour, int minute, int second) {
|
||||
return DateUtil.parseDateTime(String.format("%s %02d:%02d:%02d", DateUtil.formatDate(date), hour, minute, second));
|
||||
}
|
||||
|
||||
private SiteCugApply copyApply(SiteCugApply apply) {
|
||||
return new SiteCugApply()
|
||||
.setSiteId(apply.getSiteId())
|
||||
.setApplyUserId(apply.getApplyUserId())
|
||||
.setApplyUserName(apply.getApplyUserName())
|
||||
.setApplySex(apply.getApplySex())
|
||||
.setApplyLoginName(apply.getApplyLoginName())
|
||||
.setApplyUnitId(apply.getApplyUnitId())
|
||||
.setApplyUnitName(apply.getApplyUnitName())
|
||||
.setReserveType(apply.getReserveType())
|
||||
.setApplyUnionId(apply.getApplyUnionId())
|
||||
.setApplyUnionName(apply.getApplyUnionName())
|
||||
.setClubId(apply.getClubId())
|
||||
.setClubName(apply.getClubName())
|
||||
.setApplyMobile(apply.getApplyMobile())
|
||||
.setReserveStartTime(apply.getReserveStartTime())
|
||||
.setReserveEndTime(apply.getReserveEndTime())
|
||||
.setJoinCount(apply.getJoinCount())
|
||||
.setApplyCause(apply.getApplyCause())
|
||||
.setBackOption(apply.getBackOption())
|
||||
.setYearlyReserveEndDate(apply.getYearlyReserveEndDate());
|
||||
}
|
||||
|
||||
private void submitSingleApply(SiteCugApply apply) {
|
||||
dao.insertOrUpdate(apply);
|
||||
|
||||
Dict args = Dict.create();
|
||||
args.set(FlowConst.SUBMIT_TYPE, ProcessSubmitTypeEnum.APPLY.getCode());
|
||||
args.set(FlowConst.FORM_DATA, apply);
|
||||
ProcessInstance instance = flowEngine.startProcessInstanceByKey("CDYY", apply.getId(), SecurityUtil.getUserId(), args);
|
||||
|
||||
List<ProcessTask> doingTaskList = flowEngine.processTaskService().getDoingTaskList(instance.getId(), null);
|
||||
for (ProcessTask task : doingTaskList) {
|
||||
flowEngine.executeProcessTask(task.getId(), SecurityUtil.getUserId(), args);
|
||||
}
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
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.result.Result;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugFunctionType;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.service.SiteCugFunctionTypeService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@IocBean
|
||||
@Ok("json:full")
|
||||
@Api(tags = "功能类型")
|
||||
@At("/platform/siteCug/function/type")
|
||||
public class SiteCugFunctionTypeController {
|
||||
|
||||
@Inject
|
||||
private SiteCugFunctionTypeService typeService;
|
||||
|
||||
@At("")
|
||||
@SaCheckPermission("siteCug.function.type")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/siteCug/type/index.html")
|
||||
public void index() {}
|
||||
|
||||
@At
|
||||
@ApiOperation("分页查询")
|
||||
@SaCheckPermission("siteCug.function.type")
|
||||
public Result pageData(PageForm pageForm) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
seg.or(SiteCugFunctionType::getName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
seg.or(SiteCugFunctionType::getCode, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
cnd.and(seg);
|
||||
}
|
||||
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||
cnd.asc("code");
|
||||
} else {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
}
|
||||
Pagination pagination = typeService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), cnd);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("新增/修改功能类型")
|
||||
@SaCheckPermission("siteCug.function.type")
|
||||
@SLog(tag = "场馆功能管理-功能类型", msg = "新增/修改功能类型")
|
||||
public Object submit(SiteCugFunctionType type) {
|
||||
typeService.insertOrUpdate(type);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("删除功能类型")
|
||||
@SaCheckPermission("siteCug.function.type")
|
||||
@SLog(tag = "场馆功能管理-功能类型", msg = "删除功能类型")
|
||||
public Object delete(String id) {
|
||||
typeService.delete(id);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("查询功能类型")
|
||||
@SaCheckLogin
|
||||
public Result queryFunctionType() {
|
||||
List<SiteCugFunctionType> list = typeService.query(Cnd.where(SiteCugFunctionType::getEnable, "=", true).asc(SiteCugFunctionType::getCode));
|
||||
return Result.success(list);
|
||||
}
|
||||
}
|
||||
+242
@@ -0,0 +1,242 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
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.result.Result;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugFunctionType;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugInfo;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.service.SiteCugInfoService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
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 org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@IocBean
|
||||
@Ok("json:full")
|
||||
@Api(tags = "siteCug manage")
|
||||
@At("/platform/siteCug/manage")
|
||||
public class SiteCugManageController {
|
||||
|
||||
@Inject
|
||||
private Dao dao;
|
||||
@Inject
|
||||
private SiteCugInfoService infoService;
|
||||
|
||||
@At("")
|
||||
@SaCheckPermission("siteCug.manage")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/siteCug/manage/index.html")
|
||||
public void index() {}
|
||||
|
||||
@At
|
||||
@ApiOperation("page data")
|
||||
@SaCheckPermission("siteCug.manage")
|
||||
public Result pageData(PageForm pageForm, @Param("type") String type) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX(SiteCugInfo::getTypeId, "=", type);
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
seg.or(SiteCugInfo::getName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
seg.or(SiteCugInfo::getAddress, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
cnd.and(seg);
|
||||
}
|
||||
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||
cnd.asc("sortNum * 1");
|
||||
} else {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
}
|
||||
Pagination pagination = infoService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), cnd);
|
||||
List<NutMap> listMap = pagination.getList(NutMap.class);
|
||||
|
||||
List<SiteCugFunctionType> typeList = dao.query(SiteCugFunctionType.class, Cnd.NEW());
|
||||
Map<String, String> typeMap = typeList.stream().collect(Collectors.toMap(SiteCugFunctionType::getId, SiteCugFunctionType::getName));
|
||||
|
||||
for (NutMap map : listMap) {
|
||||
map.put("typeName", typeMap.get(map.getString("typeId")));
|
||||
}
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("submit")
|
||||
@SaCheckPermission("siteCug.manage")
|
||||
@SLog(tag = "siteCug.manage", msg = "submit site")
|
||||
public Object submit(@Param("data") SiteCugInfo info) {
|
||||
List<NutMap> notApplyTimeList = info.getNotApplyTimeList();
|
||||
if (notApplyTimeList != null) {
|
||||
boolean invalid = notApplyTimeList.stream().anyMatch(item ->
|
||||
item == null
|
||||
|| StrUtil.isBlank(item.getString("date"))
|
||||
|| StrUtil.isBlank(item.getString("startTime"))
|
||||
|| StrUtil.isBlank(item.getString("endTime"))
|
||||
|| item.getString("startTime").compareTo(item.getString("endTime")) >= 0);
|
||||
if (invalid) {
|
||||
return Result.error("Invalid disabled time settings");
|
||||
}
|
||||
}
|
||||
|
||||
if (info.getReserveTimeType() == null) {
|
||||
info.setReserveTimeType(1);
|
||||
}
|
||||
List<NutMap> segmentedOpenHours = info.getSegmentedOpenHours();
|
||||
NutMap fullDayOpenHour = info.getFullDayOpenHour();
|
||||
if ((segmentedOpenHours == null || segmentedOpenHours.isEmpty()) && info.getReserveTimeType() == 1) {
|
||||
segmentedOpenHours = info.getOpenHours();
|
||||
}
|
||||
if ((fullDayOpenHour == null || fullDayOpenHour.isEmpty()) && info.getReserveTimeType() == 2 && info.getOpenHours() != null && !info.getOpenHours().isEmpty()) {
|
||||
fullDayOpenHour = info.getOpenHours().get(0);
|
||||
}
|
||||
if (info.getReserveTimeType() == 1) {
|
||||
if (segmentedOpenHours == null || segmentedOpenHours.isEmpty()) {
|
||||
return Result.error("Please add at least one booking slot");
|
||||
}
|
||||
boolean invalid = segmentedOpenHours.stream().anyMatch(item ->
|
||||
item == null
|
||||
|| StrUtil.isBlank(item.getString("startTime"))
|
||||
|| StrUtil.isBlank(item.getString("endTime"))
|
||||
|| item.getString("startTime").compareTo(item.getString("endTime")) >= 0
|
||||
|| !isPositiveNumber(item.get("timeUnit")));
|
||||
if (invalid) {
|
||||
return Result.error("Invalid segmented booking slot settings");
|
||||
}
|
||||
if (hasOverlap(segmentedOpenHours)) {
|
||||
return Result.error("Segmented booking slots cannot overlap");
|
||||
}
|
||||
segmentedOpenHours = segmentedOpenHours.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(this::normalizeOpenHourTimeUnit)
|
||||
.collect(Collectors.toList());
|
||||
info.setSegmentedOpenHours(segmentedOpenHours);
|
||||
info.setOpenHours(segmentedOpenHours);
|
||||
} else if (info.getReserveTimeType() == 2) {
|
||||
if (fullDayOpenHour == null || fullDayOpenHour.isEmpty()) {
|
||||
return Result.error("Please set the full-day booking time range");
|
||||
}
|
||||
NutMap item = fullDayOpenHour;
|
||||
if (item == null
|
||||
|| StrUtil.isBlank(item.getString("startTime"))
|
||||
|| StrUtil.isBlank(item.getString("endTime"))
|
||||
|| item.getString("startTime").compareTo(item.getString("endTime")) >= 0) {
|
||||
return Result.error("Invalid full-day booking time range");
|
||||
}
|
||||
if (!isPositiveNumber(item.get("timeUnit"))) {
|
||||
return Result.error("Invalid full-day booking time unit");
|
||||
}
|
||||
fullDayOpenHour = normalizeOpenHourTimeUnit(fullDayOpenHour);
|
||||
info.setFullDayOpenHour(fullDayOpenHour);
|
||||
info.setOpenHours(List.of(fullDayOpenHour));
|
||||
}
|
||||
|
||||
if (info.getFilterHolidays() == null) {
|
||||
info.setFilterHolidays(false);
|
||||
}
|
||||
infoService.insertOrUpdate(info);
|
||||
SiteCugInfo savedInfo = infoService.fetch(info.getId());
|
||||
return Result.success(savedInfo == null ? info : savedInfo);
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("delete")
|
||||
@SaCheckPermission("siteCug.manage")
|
||||
@SLog(tag = "siteCug.manage", msg = "delete site")
|
||||
public Object delete(String id) {
|
||||
infoService.delete(id);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("query sites")
|
||||
@SaCheckLogin
|
||||
public Result querySites() {
|
||||
List<SiteCugInfo> list = infoService.query(Cnd.where(SiteCugInfo::getState, "=", true).desc(SiteCugInfo::getSortNum));
|
||||
return Result.success(list);
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("query site info")
|
||||
@SaCheckLogin
|
||||
public Result info(String id) {
|
||||
SiteCugInfo info = infoService.fetch(id);
|
||||
if (info == null) {
|
||||
return Result.success(null);
|
||||
}
|
||||
NutMap map = Lang.obj2nutmap(info);
|
||||
SiteCugFunctionType type = dao.fetch(SiteCugFunctionType.class, info.getTypeId());
|
||||
map.put("typeName", type == null ? "" : type.getName());
|
||||
return Result.success(map);
|
||||
}
|
||||
|
||||
private boolean isPositiveNumber(Object value) {
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return Double.parseDouble(String.valueOf(value)) > 0;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private NutMap normalizeOpenHourTimeUnit(NutMap item) {
|
||||
if (item == null) {
|
||||
return null;
|
||||
}
|
||||
item.put("timeUnit", normalizeTimeUnitMinutes(item.get("timeUnit")));
|
||||
return item;
|
||||
}
|
||||
|
||||
private int normalizeTimeUnitMinutes(Object value) {
|
||||
if (value == null) {
|
||||
return 60;
|
||||
}
|
||||
try {
|
||||
double parsed = Double.parseDouble(String.valueOf(value));
|
||||
if (parsed <= 0) {
|
||||
return 60;
|
||||
}
|
||||
return (int) Math.round(parsed);
|
||||
} catch (Exception e) {
|
||||
return 60;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasOverlap(List<NutMap> openHours) {
|
||||
if (openHours == null || openHours.size() < 2) {
|
||||
return false;
|
||||
}
|
||||
List<NutMap> validHours = openHours.stream()
|
||||
.filter(item -> item != null
|
||||
&& StrUtil.isNotBlank(item.getString("startTime"))
|
||||
&& StrUtil.isNotBlank(item.getString("endTime"))
|
||||
&& item.getString("startTime").compareTo(item.getString("endTime")) < 0)
|
||||
.sorted((a, b) -> a.getString("startTime").compareTo(b.getString("startTime")))
|
||||
.collect(Collectors.toList());
|
||||
for (int i = 1; i < validHours.size(); i++) {
|
||||
NutMap prev = validHours.get(i - 1);
|
||||
NutMap current = validHours.get(i);
|
||||
if (current.getString("startTime").compareTo(prev.getString("endTime")) < 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+184
@@ -0,0 +1,184 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
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.result.Result;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.flow.engine.FlowEngine;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugApply;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.service.SiteCugApplyService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.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.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@IocBean
|
||||
@Ok("json:full")
|
||||
@Api(tags = "场地预约-我的预约")
|
||||
@At("/platform/siteCug/mine")
|
||||
public class SiteCugMineController {
|
||||
|
||||
private static final String YEARLY_BATCH_PREFIX = "YEARLY_BATCH:";
|
||||
|
||||
@Inject
|
||||
private FlowEngine flowEngine;
|
||||
@Inject
|
||||
private SiteCugApplyService applyService;
|
||||
|
||||
@At("/")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/siteCug/mine/index.html")
|
||||
@SaCheckPermission("siteCug.mine")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At("/h5")
|
||||
@Ok("beetl:/platform/zhghh5/dayofficework/siteCug/mine/index.html")
|
||||
@SaCheckPermission(value = {"siteCug.mine", "h5.siteCug.mine"}, mode = SaMode.OR)
|
||||
public void h5Index() {
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("分页查询我的预约")
|
||||
@SaCheckPermission(value = {"siteCug.mine", "h5.siteCug.mine"}, mode = SaMode.OR)
|
||||
public Result pageData(PageForm pageForm,
|
||||
@Param("siteType") String siteType,
|
||||
@Param("siteId") String siteId) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
info.*,
|
||||
si.name as siteName,
|
||||
ins.id AS instanceId,
|
||||
ins.businessNo,
|
||||
ins.state instanceState,
|
||||
ins.variable instanceVariable,
|
||||
ins.processDefineId instanceProcessDefineId,
|
||||
t.id taskId,
|
||||
t.taskName AS taskKey,
|
||||
t.displayName taskName,
|
||||
t.taskType,
|
||||
t.performType taskPerformType,
|
||||
t.taskState,
|
||||
t.finishTime,
|
||||
t.taskParentId,
|
||||
t.variable taskVariable,
|
||||
CASE WHEN info.reserveType = 'club' THEN info.clubName ELSE info.applyUnionName END AS reserveTargetName,
|
||||
CASE
|
||||
WHEN ins.state in (10, 20) AND (t.displayName LIKE '%校工会允许%' OR t.taskName = 'c8c03407-cf26-4e0b-82f1-b2afc9c79996')
|
||||
THEN 1
|
||||
ELSE 0
|
||||
END canCancel,
|
||||
IF((SELECT taskName FROM wf_process_task tt WHERE tt.id = t.taskParentId) = 'startTask', 1, 0) canRevoke,
|
||||
(select MAX(id) from wf_process_task where processInstanceId = ins.id and taskName = 'startTask') AS startTaskId,
|
||||
CASE WHEN info.backOption LIKE 'YEARLY_BATCH:%' THEN 1 ELSE 0 END AS yearlyBatch,
|
||||
CASE WHEN info.backOption LIKE 'YEARLY_BATCH:%' THEN (
|
||||
SELECT COUNT(1) FROM site_cug_apply batch_info WHERE batch_info.backOption = info.backOption AND batch_info.createdBy = info.createdBy
|
||||
) ELSE 1 END AS batchDeleteCount
|
||||
FROM
|
||||
site_cug_apply info
|
||||
LEFT JOIN site_cug_info si ON info.siteId = si.id
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||
LEFT JOIN wf_process_task t ON t.processInstanceId = ins.id AND t.taskState = 10
|
||||
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
seg.or(SiteCugApply::getApplyUserName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
seg.or(SiteCugApply::getApplyLoginName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
cnd.and(seg);
|
||||
}
|
||||
cnd.andEX("si.typeId", "=", siteType);
|
||||
cnd.andEX("info.siteId", "=", siteId);
|
||||
cnd.and("info.createdBy", "=", SecurityUtil.getUserId());
|
||||
|
||||
if (StrUtil.isNotBlank(pageForm.getPageOrderName()) && StrUtil.isNotBlank(pageForm.getPageOrderBy())) {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
} else {
|
||||
cnd.desc("info.createdAt");
|
||||
}
|
||||
cnd.groupBy("info.id");
|
||||
sql.setCondition(cnd);
|
||||
Pagination<NutMap> pagination = applyService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("取消我的预约")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission(value = {"siteCug.mine", "h5.siteCug.mine"}, mode = SaMode.OR)
|
||||
@SLog(tag = "场馆功能管理-我的预约", msg = "取消场地预约")
|
||||
public Result delete(@Param("id") String id) {
|
||||
SiteCugApply apply = applyService.fetch(id);
|
||||
if (apply == null) {
|
||||
return Result.error("预约记录不存在");
|
||||
}
|
||||
if (!StrUtil.equals(apply.getCreatedBy(), SecurityUtil.getUserId())) {
|
||||
return Result.error("无权取消该预约");
|
||||
}
|
||||
|
||||
List<String> deleteIds = new ArrayList<>();
|
||||
if (StrUtil.isNotBlank(apply.getBackOption()) && apply.getBackOption().startsWith(YEARLY_BATCH_PREFIX)) {
|
||||
List<SiteCugApply> batchList = applyService.query(Cnd.where("backOption", "=", apply.getBackOption()).and("createdBy", "=", SecurityUtil.getUserId()));
|
||||
deleteIds.addAll(batchList.stream().map(SiteCugApply::getId).toList());
|
||||
} else {
|
||||
deleteIds.add(id);
|
||||
}
|
||||
if (deleteIds.isEmpty()) {
|
||||
return Result.error("未找到可取消的预约记录");
|
||||
}
|
||||
|
||||
for (String deleteId : deleteIds) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
CASE
|
||||
WHEN ins.state in (10, 20) AND (t.displayName LIKE '%校工会允许%' OR t.taskName = 'c8c03407-cf26-4e0b-82f1-b2afc9c79996')
|
||||
THEN 1
|
||||
ELSE 0
|
||||
END canCancel
|
||||
FROM
|
||||
site_cug_apply info
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||
LEFT JOIN wf_process_task t ON t.processInstanceId = ins.id AND t.taskState = 10
|
||||
WHERE info.id = @id
|
||||
""");
|
||||
sql.params().set("id", deleteId);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
applyService.dao().execute(sql);
|
||||
List<NutMap> list = sql.getList(NutMap.class);
|
||||
boolean canCancel = list != null && !list.isEmpty() && list.get(0).getInt("canCancel", 0) == 1;
|
||||
if (!canCancel) {
|
||||
return Result.error("当前批次中存在不可取消的预约,无法整批删除");
|
||||
}
|
||||
}
|
||||
|
||||
for (String deleteId : deleteIds) {
|
||||
applyService.delete(deleteId);
|
||||
flowEngine.processInstanceService().deleteProcessInstanceByBusinessKey(deleteId);
|
||||
}
|
||||
if (deleteIds.size() > 1) {
|
||||
return Result.success("已取消该批次下全部预约记录");
|
||||
}
|
||||
return Result.success("取消成功");
|
||||
}
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.flow.engine.FlowEngine;
|
||||
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugApply;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.param.SiteCugRecordPageForm;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.service.SiteCugApplyService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
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.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
|
||||
@IocBean
|
||||
@Ok("json:full")
|
||||
@Api(tags = "场馆预约查询")
|
||||
@At("/platform/siteCug/record")
|
||||
public class SiteCugRecordController {
|
||||
|
||||
@Inject
|
||||
private FlowEngine flowEngine;
|
||||
@Inject
|
||||
private SiteCugApplyService applyService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/siteCug/record/index.html")
|
||||
@SaCheckPermission("siteCug.record")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("分页查询")
|
||||
@SaCheckPermission("siteCug.record")
|
||||
public Result pageData(SiteCugRecordPageForm pageForm) {
|
||||
// 查询页只负责调用 service 公共查询方法,controller 不再维护重复 SQL/Cnd 逻辑
|
||||
Sql sql = applyService.buildRecordSql();
|
||||
Cnd cnd = applyService.buildRecordCnd(pageForm);
|
||||
sql.setCondition(cnd);
|
||||
Pagination<NutMap> pageVO = applyService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
return Result.success(pageVO);
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("删除预约记录")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("siteCug.record")
|
||||
public Result delete(@Param("id") String id) {
|
||||
SiteCugApply apply = applyService.fetch(id);
|
||||
if (apply == null) {
|
||||
return Result.error("记录不存在");
|
||||
}
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
ins.state AS instanceState
|
||||
FROM
|
||||
site_cug_apply info
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||
WHERE info.id = @id
|
||||
""");
|
||||
sql.params().set("id", id);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
applyService.dao().execute(sql);
|
||||
List<NutMap> list = sql.getList(NutMap.class);
|
||||
Integer state = list != null && !list.isEmpty() ? list.get(0).getInt("instanceState") : null;
|
||||
// 预约查询页只展示审核结束数据,这里也只允许删除已完成/已拒绝的流程记录
|
||||
if (state == null || !List.of(ProcessInstanceStateEnum.FINISHED.getCode(), ProcessInstanceStateEnum.REJECT.getCode()).contains(state)) {
|
||||
return Result.error("仅可删除审核结束的预约记录");
|
||||
}
|
||||
|
||||
applyService.delete(id);
|
||||
flowEngine.processInstanceService().deleteProcessInstanceByBusinessKey(id);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@Ok("void")
|
||||
@ApiOperation("导出预约记录")
|
||||
@SaCheckPermission("siteCug.record")
|
||||
public void doExport(SiteCugRecordPageForm pageForm, HttpServletResponse response) {
|
||||
// 导出逻辑统一下沉到 service,导出结果和当前筛选条件保持一致
|
||||
applyService.exportRecord(pageForm, response);
|
||||
}
|
||||
}
|
||||
+245
@@ -0,0 +1,245 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
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.PageUtil;
|
||||
import com.budwk.app.flow.constant.FlowConst;
|
||||
import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||
import com.budwk.app.flow.service.FlowCommonService;
|
||||
import com.budwk.app.flow.service.ProcessTaskService;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugApply;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.service.SiteCugApplyService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
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.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.util.NutMap;
|
||||
import org.nutz.json.Json;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@IocBean
|
||||
@At("/platform/siteCug/schoolUnionAudit")
|
||||
@Api("场馆校工会审核")
|
||||
@Ok("json:full")
|
||||
public class SiteCugSchoolUnionAuditController {
|
||||
|
||||
private static final String YEARLY_BATCH_PREFIX = "YEARLY_BATCH:";
|
||||
|
||||
@Inject
|
||||
private SiteCugApplyService applyService;
|
||||
@Inject
|
||||
private ProcessTaskService processTaskService;
|
||||
@Inject
|
||||
private FlowCommonService flowCommonService;
|
||||
|
||||
@At("/")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/siteCug/schoolUnionAudit/index.html")
|
||||
@SaCheckPermission("siteCug.schoolUnionAudit")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At("/h5")
|
||||
@Ok("beetl:/platform/zhghh5/dayofficework/siteCug/schoolUnionAudit/index.html")
|
||||
@SaCheckPermission("h5.siteCug.schoolUnionAudit")
|
||||
public void h5Index() {
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("分页查询")
|
||||
@SaCheckPermission(value = {"siteCug.schoolUnionAudit", "h5.siteCug.schoolUnionAudit"}, mode = SaMode.OR)
|
||||
public Result pageData(PageForm pageForm,
|
||||
@Param("siteType") String siteType,
|
||||
@Param("siteId") String siteId,
|
||||
@Param("approval") Boolean approval) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
info.*,
|
||||
si.name as siteName,
|
||||
CASE WHEN info.reserveType = 'club' THEN info.clubName ELSE info.applyUnionName END AS reserveTargetName,
|
||||
ins.id AS instanceId,
|
||||
ins.businessNo,
|
||||
ins.state instanceState,
|
||||
ins.variable instanceVariable,
|
||||
ins.processDefineId instanceProcessDefineId,
|
||||
t.id taskId,
|
||||
t.taskName AS taskKey,
|
||||
t.displayName taskName,
|
||||
t.taskType,
|
||||
t.performType taskPerformType,
|
||||
t.taskState,
|
||||
t.finishTime,
|
||||
t.taskParentId,
|
||||
t.variable taskVariable,
|
||||
IFNULL(GROUP_CONCAT(DISTINCT nt.displayName),'结束') curTaskName,
|
||||
CASE WHEN EXISTS (
|
||||
SELECT 1 FROM wf_process_task rt
|
||||
WHERE rt.processInstanceId = ins.id AND rt.taskParentId = t.id
|
||||
) THEN 1 ELSE 0 END AS canRevoke,
|
||||
CASE WHEN info.backOption LIKE 'YEARLY_BATCH:%' THEN 1 ELSE 0 END AS yearlyBatch,
|
||||
CASE WHEN info.backOption LIKE 'YEARLY_BATCH:%' THEN (
|
||||
SELECT COUNT(1) FROM site_cug_apply batch_info WHERE batch_info.backOption = info.backOption AND batch_info.createdBy = info.createdBy
|
||||
) ELSE 1 END AS batchAuditCount
|
||||
FROM
|
||||
wf_process_task t
|
||||
LEFT JOIN wf_process_instance ins ON ins.id = t.processInstanceId
|
||||
LEFT JOIN site_cug_apply info ON info.id = ins.businessNo
|
||||
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id
|
||||
LEFT JOIN site_cug_info si ON info.siteId = si.id
|
||||
LEFT JOIN wf_process_task nt ON nt.processInstanceId = ins.id AND nt.taskState = 10
|
||||
LEFT JOIN wf_process_task rt ON rt.processInstanceId = ins.id AND rt.taskParentId = t.id
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
seg.or(SiteCugApply::getApplyUserName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
seg.or(SiteCugApply::getApplyLoginName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
cnd.and(seg);
|
||||
}
|
||||
cnd.andEX("si.typeId", "=", siteType);
|
||||
cnd.andEX("info.siteId", "=", siteId);
|
||||
cnd.and("t.taskName", "=", "c8c03407-cf26-4e0b-82f1-b2afc9c79996");
|
||||
if (!StpUtil.hasRole(RoleConstant.SYSADMIN.name())) {
|
||||
cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
|
||||
}
|
||||
if (Boolean.TRUE.equals(approval)) {
|
||||
cnd.and("t.taskState", "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.INTERRUPT.getCode()));
|
||||
} else {
|
||||
cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
|
||||
}
|
||||
|
||||
if (StrUtil.isNotBlank(pageForm.getPageOrderName()) && StrUtil.isNotBlank(pageForm.getPageOrderBy())) {
|
||||
cnd.orderBy(resolveOrderColumn(pageForm.getPageOrderName()), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
} else {
|
||||
cnd.desc("info.createdAt");
|
||||
}
|
||||
cnd.groupBy("t.id");
|
||||
sql.setCondition(cnd);
|
||||
Pagination<NutMap> pageVO = applyService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
return Result.success(pageVO);
|
||||
}
|
||||
|
||||
private String resolveOrderColumn(String pageOrderName) {
|
||||
if (StrUtil.isBlank(pageOrderName)) {
|
||||
return "info.createdAt";
|
||||
}
|
||||
switch (pageOrderName) {
|
||||
case "siteName":
|
||||
return "si.name";
|
||||
case "applyUserName":
|
||||
return "info.applyUserName";
|
||||
case "applyLoginName":
|
||||
return "info.applyLoginName";
|
||||
case "yearlyBatch":
|
||||
return "yearlyBatch";
|
||||
case "reserveTargetName":
|
||||
return "reserveTargetName";
|
||||
case "reserveStartTime":
|
||||
return "info.reserveStartTime";
|
||||
case "reserveEndTime":
|
||||
return "info.reserveEndTime";
|
||||
case "applyMobile":
|
||||
return "info.applyMobile";
|
||||
case "curTaskName":
|
||||
return "curTaskName";
|
||||
case "instanceState":
|
||||
return "ins.state";
|
||||
default:
|
||||
return "info.createdAt";
|
||||
}
|
||||
}
|
||||
|
||||
@At("/executeTask")
|
||||
@ApiOperation("执行审核任务")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission(value = {"siteCug.schoolUnionAudit", "h5.siteCug.schoolUnionAudit"}, mode = SaMode.OR)
|
||||
public Result executeTask(@Param("data") String data) {
|
||||
Dict args = Json.fromJson(Dict.class, data);
|
||||
Long processTaskId = args.getLong(FlowConst.PROCESS_TASK_ID_KEY);
|
||||
ProcessTask currentTask = processTaskService.getById(processTaskId);
|
||||
if (currentTask == null) {
|
||||
return Result.error("审核任务不存在");
|
||||
}
|
||||
|
||||
SiteCugApply apply = applyService.fetch(args.getStr("applyId"));
|
||||
if (apply == null) {
|
||||
return Result.error("预约记录不存在");
|
||||
}
|
||||
|
||||
List<ProcessTask> taskList = new ArrayList<>();
|
||||
if (StrUtil.isNotBlank(apply.getBackOption()) && apply.getBackOption().startsWith(YEARLY_BATCH_PREFIX)) {
|
||||
List<SiteCugApply> batchList = applyService.query(Cnd.where("backOption", "=", apply.getBackOption()).and("createdBy", "=", apply.getCreatedBy()));
|
||||
List<String> bizIds = batchList.stream().map(SiteCugApply::getId).toList();
|
||||
taskList = processTaskService.getDoingTaskByBizIdTaskName(bizIds, currentTask.getTaskName());
|
||||
}
|
||||
if (taskList.isEmpty()) {
|
||||
taskList.add(currentTask);
|
||||
}
|
||||
|
||||
for (ProcessTask task : taskList) {
|
||||
Dict cloneArgs = args.clone();
|
||||
cloneArgs.put(FlowConst.PROCESS_TASK_ID_KEY, task.getId());
|
||||
flowCommonService.executeTask(cloneArgs);
|
||||
}
|
||||
if (taskList.size() > 1) {
|
||||
return Result.success("已完成该全年预约批次的审核");
|
||||
}
|
||||
return Result.success("提交成功");
|
||||
}
|
||||
|
||||
|
||||
@At("/revokeTask")
|
||||
@ApiOperation("撤回审核任务")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission(value = {"siteCug.schoolUnionAudit", "h5.siteCug.schoolUnionAudit"}, mode = SaMode.OR)
|
||||
public Result revokeTask(@Param("taskId") Long taskId, @Param("applyId") String applyId) {
|
||||
ProcessTask currentTask = processTaskService.getById(taskId);
|
||||
if (currentTask == null) {
|
||||
return Result.error("撤回任务不存在");
|
||||
}
|
||||
|
||||
SiteCugApply apply = applyService.fetch(applyId);
|
||||
if (apply == null) {
|
||||
return Result.error("预约记录不存在");
|
||||
}
|
||||
|
||||
List<ProcessTask> taskList = new ArrayList<>();
|
||||
if (StrUtil.isNotBlank(apply.getBackOption()) && apply.getBackOption().startsWith(YEARLY_BATCH_PREFIX)) {
|
||||
List<SiteCugApply> batchList = applyService.query(Cnd.where("backOption", "=", apply.getBackOption()).and("createdBy", "=", apply.getCreatedBy()));
|
||||
List<String> bizIds = batchList.stream().map(SiteCugApply::getId).toList();
|
||||
taskList = processTaskService.getDoneTaskByBizIdTaskName(bizIds, currentTask.getTaskName());
|
||||
}
|
||||
if (taskList.isEmpty()) {
|
||||
taskList.add(currentTask);
|
||||
}
|
||||
|
||||
for (ProcessTask task : taskList) {
|
||||
flowCommonService.revokeTask(task.getId());
|
||||
}
|
||||
if (taskList.size() > 1) {
|
||||
return Result.success("已撤回该全年预约批次的审核任务");
|
||||
}
|
||||
return Result.success("撤回成功");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.model;
|
||||
|
||||
import com.budwk.app.base.model.BaseModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.nutz.dao.entity.annotation.*;
|
||||
import org.nutz.dao.interceptor.annotation.PrevInsert;
|
||||
|
||||
@Data
|
||||
@Comment("场地预约-场馆")
|
||||
@Accessors(chain = true)
|
||||
@Table("site_cug_apply")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SiteCugApply extends BaseModel {
|
||||
|
||||
@Name
|
||||
@Comment("ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@PrevInsert(uu32 = true)
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("场地id")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String siteId;
|
||||
|
||||
@Column
|
||||
@Comment("预约人")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String applyUserId;
|
||||
|
||||
@Column
|
||||
@Comment("预约人姓名")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
private String applyUserName;
|
||||
|
||||
@Column
|
||||
@Comment("性别")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 10)
|
||||
private String applySex;
|
||||
|
||||
@Column
|
||||
@Comment("预约人工号")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
private String applyLoginName;
|
||||
|
||||
@Column
|
||||
@Comment("预约人单位id")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String applyUnitId;
|
||||
|
||||
@Column
|
||||
@Comment("预约人单位")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String applyUnitName;
|
||||
|
||||
@Column
|
||||
@Comment("预约类型")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
private String reserveType;
|
||||
|
||||
@Column
|
||||
@Comment("分工会id")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String applyUnionId;
|
||||
|
||||
@Column
|
||||
@Comment("分工会名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String applyUnionName;
|
||||
|
||||
@Column
|
||||
@Comment("协会id")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String clubId;
|
||||
|
||||
@Column
|
||||
@Comment("协会名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String clubName;
|
||||
|
||||
@Column
|
||||
@Comment("预约人联系方式")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
private String applyMobile;
|
||||
|
||||
@Column
|
||||
@Comment("预约开始时间")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
private String reserveStartTime;
|
||||
|
||||
@Column
|
||||
@Comment("预约结束时间")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
private String reserveEndTime;
|
||||
|
||||
@Column
|
||||
@Comment("预约人数")
|
||||
@ColDefine(type = ColType.INT)
|
||||
private Integer joinCount;
|
||||
|
||||
@Column
|
||||
@Comment("预约事由")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 1000)
|
||||
private String applyCause;
|
||||
|
||||
@Column
|
||||
@Comment("反馈意见")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 200)
|
||||
private String backOption;
|
||||
|
||||
private String yearlyReserveEndDate;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.model;
|
||||
|
||||
import com.budwk.app.base.model.BaseModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.nutz.dao.entity.annotation.*;
|
||||
import org.nutz.dao.interceptor.annotation.PrevInsert;
|
||||
|
||||
@Data
|
||||
@Comment("功能类型")
|
||||
@Accessors(chain = true)
|
||||
@Table("site_cug_function_type")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SiteCugFunctionType extends BaseModel {
|
||||
|
||||
@Name
|
||||
@Comment("ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@PrevInsert(uu32 = true)
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
@Comment("类型编码")
|
||||
private String code;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
@Comment("类型名称")
|
||||
private String name;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Comment("是否启用")
|
||||
@Default("1")
|
||||
private Boolean enable;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.INT)
|
||||
@Comment("排序编号")
|
||||
private Integer sortNum;
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.model;
|
||||
|
||||
import com.budwk.app.base.model.BaseModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.nutz.dao.entity.annotation.*;
|
||||
import org.nutz.dao.interceptor.annotation.PrevInsert;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Comment("场地信息-场馆")
|
||||
@Accessors(chain = true)
|
||||
@Table("site_cug_info")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SiteCugInfo extends BaseModel {
|
||||
|
||||
@Name
|
||||
@Comment("ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@PrevInsert(uu32 = true)
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("创建人ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String createUserId;
|
||||
|
||||
@Column
|
||||
@Comment("创建人")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
private String createUserName;
|
||||
|
||||
@Column
|
||||
@Comment("排序编号")
|
||||
@ColDefine(type = ColType.INT)
|
||||
private Integer sortNum;
|
||||
|
||||
@Column
|
||||
@Comment("场地名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String name;
|
||||
|
||||
@Column
|
||||
@Comment("场地地址")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 255)
|
||||
private String address;
|
||||
|
||||
@Column
|
||||
@Comment("联系人")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String contactName;
|
||||
|
||||
@Column
|
||||
@Comment("联系电话")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
private String contactPhone;
|
||||
|
||||
@Column
|
||||
@Comment("可容纳人数")
|
||||
@ColDefine(type = ColType.INT)
|
||||
private Integer maxNum;
|
||||
|
||||
@Column
|
||||
@Comment("场地类型")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String typeId;
|
||||
|
||||
@Column
|
||||
@Comment("性别限制(0不限,1男,2女)")
|
||||
@ColDefine(type = ColType.INT)
|
||||
private Integer sexLimit;
|
||||
|
||||
@Column
|
||||
@Comment("场地的禁用时间")
|
||||
@ColDefine(type = ColType.MYSQL_JSON)
|
||||
private List<NutMap> notApplyTimeList;
|
||||
|
||||
@Column
|
||||
@Comment("预约时间段类型(1分段预约,2全天候预约)")
|
||||
@ColDefine(type = ColType.INT)
|
||||
@Default("1")
|
||||
private Integer reserveTimeType;
|
||||
|
||||
@Column
|
||||
@Comment("场次信息")
|
||||
@ColDefine(type = ColType.MYSQL_JSON)
|
||||
private List<NutMap> openHours;
|
||||
|
||||
@Column
|
||||
@Comment("分段预约场次信息")
|
||||
@ColDefine(type = ColType.MYSQL_JSON)
|
||||
private List<NutMap> segmentedOpenHours;
|
||||
|
||||
@Column
|
||||
@Comment("全天候预约时间段")
|
||||
@ColDefine(type = ColType.MYSQL_JSON)
|
||||
private NutMap fullDayOpenHour;
|
||||
|
||||
@Column
|
||||
@Comment("开启状态")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Default("1")
|
||||
private Boolean state;
|
||||
|
||||
@Column
|
||||
@Comment("排除节假日")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Default("0")
|
||||
private Boolean filterHolidays;
|
||||
|
||||
@Column
|
||||
@Comment("场地介绍")
|
||||
@ColDefine(type = ColType.TEXT)
|
||||
private String introduce;
|
||||
|
||||
@Column
|
||||
@Comment("场地照片")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 255)
|
||||
private String sitePhoto;
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.param;
|
||||
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@ApiModel("场馆预约查询参数")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class SiteCugRecordPageForm extends PageForm {
|
||||
|
||||
@ApiModelProperty("场地类型ID")
|
||||
private String siteType;
|
||||
|
||||
@ApiModelProperty("场地ID")
|
||||
private String siteId;
|
||||
|
||||
@ApiModelProperty("预约类型")
|
||||
private String reserveType;
|
||||
|
||||
@ApiModelProperty("预约单位关键字")
|
||||
private String reserveTargetKeyword;
|
||||
|
||||
@ApiModelProperty("预约时间开始")
|
||||
private String reserveTimeStart;
|
||||
|
||||
@ApiModelProperty("预约时间结束")
|
||||
private String reserveTimeEnd;
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugApply;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.param.SiteCugRecordPageForm;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.Map;
|
||||
|
||||
public interface SiteCugApplyService extends BaseService<SiteCugApply> {
|
||||
|
||||
Map<Boolean, String> validateApply(SiteCugApply apply);
|
||||
|
||||
// 场馆预约查询页和导出共用同一套查询字段定义,统一由 service 生成 SQL
|
||||
Sql buildRecordSql();
|
||||
|
||||
// 场馆预约查询页和导出的筛选条件统一由 service 组装,避免 controller 重复维护
|
||||
Cnd buildRecordCnd(SiteCugRecordPageForm pageForm);
|
||||
|
||||
// 场馆预约查询页的导出逻辑统一放在 service,controller 只负责接收请求
|
||||
void exportRecord(SiteCugRecordPageForm pageForm, HttpServletResponse response);
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugFunctionType;
|
||||
|
||||
public interface SiteCugFunctionTypeService extends BaseService<SiteCugFunctionType> {
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugInfo;
|
||||
|
||||
public interface SiteCugInfoService extends BaseService<SiteCugInfo> {
|
||||
}
|
||||
+323
@@ -0,0 +1,323 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.service.impl;
|
||||
|
||||
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.DateTime;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.flow.entity.ProcessInstance;
|
||||
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
|
||||
import com.budwk.app.sys.models.SysHoliday;
|
||||
import com.budwk.app.sys.models.Sys_union;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.club.model.SysClub;
|
||||
import com.budwk.app.zhgh.club.service.SysClubService;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugApply;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugInfo;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.param.SiteCugRecordPageForm;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.service.SiteCugApplyService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class SiteCugApplyServiceImpl extends BaseServiceImpl<SiteCugApply> implements SiteCugApplyService {
|
||||
|
||||
@Inject
|
||||
private SysClubService sysClubService;
|
||||
|
||||
public SiteCugApplyServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Boolean, String> validateApply(SiteCugApply apply) {
|
||||
// 预约类型校验和自动回填:
|
||||
// 1. 分工会预约时,强制读取当前登录人的分工会信息
|
||||
// 2. 协会预约时,只允许选择当前登录人实际管理的协会
|
||||
Map<Boolean, String> reserveTypeValidate = fillReserveTypeData(apply);
|
||||
if (reserveTypeValidate.containsKey(false)) {
|
||||
return reserveTypeValidate;
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(apply.getReserveStartTime()) || StrUtil.isBlank(apply.getReserveEndTime())) {
|
||||
return Map.of(false, "预约时间不能为空");
|
||||
}
|
||||
if (!DateUtil.parseDateTime(apply.getReserveEndTime()).isAfter(DateUtil.parseDateTime(apply.getReserveStartTime()))) {
|
||||
return Map.of(false, "结束时间必须晚于开始时间");
|
||||
}
|
||||
if (!DateUtil.parseDateTime(apply.getReserveStartTime()).isAfter(DateUtil.date())) {
|
||||
return Map.of(false, "预约开始时间必须晚于当前时间");
|
||||
}
|
||||
|
||||
SiteCugInfo siteInfo = dao().fetch(SiteCugInfo.class, apply.getSiteId());
|
||||
if (siteInfo == null) {
|
||||
return Map.of(false, "场地不存在");
|
||||
}
|
||||
if (!Boolean.TRUE.equals(siteInfo.getState())) {
|
||||
return Map.of(false, "该场地未开启预约");
|
||||
}
|
||||
if (apply.getJoinCount() == null || apply.getJoinCount() <= 0) {
|
||||
return Map.of(false, "预约人数必须大于0");
|
||||
}
|
||||
if (apply.getJoinCount() > siteInfo.getMaxNum()) {
|
||||
return Map.of(false, "预约人数最多为%s人".formatted(siteInfo.getMaxNum()));
|
||||
}
|
||||
// 周六、周日整天不可预约,避免只做前端限制被绕过
|
||||
if (containsWeekend(apply.getReserveStartTime(), apply.getReserveEndTime())) {
|
||||
return Map.of(false, "预约时间不能落在周六或周日");
|
||||
}
|
||||
// 开启排除节假日后,节假日整天不可预约
|
||||
if (Boolean.TRUE.equals(siteInfo.getFilterHolidays()) && containsHoliday(apply.getReserveStartTime(), apply.getReserveEndTime())) {
|
||||
return Map.of(false, "预约时间不能落在节假日");
|
||||
}
|
||||
// 只要预约时间范围和禁用时间段有交叉,就不允许预约
|
||||
if (intersectsDisabledTime(siteInfo, apply.getReserveStartTime(), apply.getReserveEndTime())) {
|
||||
return Map.of(false, "预约时间落在禁用时间内");
|
||||
}
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
select
|
||||
sa.*
|
||||
from
|
||||
site_cug_apply sa
|
||||
left join wf_process_instance ins on ins.businessNo = sa.id
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and(SiteCugApply::getSiteId, "=", apply.getSiteId());
|
||||
cnd.andEX("sa.id", "!=", apply.getId());
|
||||
List<Integer> stateList = List.of(ProcessInstanceStateEnum.DOING.getCode(), ProcessInstanceStateEnum.FINISHED.getCode(), ProcessInstanceStateEnum.PENDING.getCode());
|
||||
cnd.and(ProcessInstance::getState, "in", stateList);
|
||||
sql.setCondition(cnd);
|
||||
List<SiteCugApply> applyList = listEntity(sql);
|
||||
|
||||
// 只要已有预约和当前申请时间段有交叉,并且流程状态是待审核/办理中/已通过,就直接判定冲突
|
||||
for (SiteCugApply item : applyList) {
|
||||
boolean overlap = DateUtil.parseDateTime(item.getReserveStartTime()).isBefore(DateUtil.parseDateTime(apply.getReserveEndTime()))
|
||||
&& DateUtil.parseDateTime(item.getReserveEndTime()).isAfter(DateUtil.parseDateTime(apply.getReserveStartTime()));
|
||||
if (overlap) {
|
||||
if (StrUtil.isBlank(apply.getId()) && StrUtil.equals(item.getApplyUserId(), SecurityUtil.getUserId())) {
|
||||
return Map.of(false, "该时间段您已存在预约");
|
||||
}
|
||||
return Map.of(false, String.format("预约时间冲突,%s 至 %s 已被预约,请重新选择", item.getReserveStartTime(), item.getReserveEndTime()));
|
||||
}
|
||||
}
|
||||
return Map.of(true, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sql buildRecordSql() {
|
||||
// 场馆预约查询页和导出页共用同一套返回字段,统一在 service 中维护,避免 controller 重复拼 SQL
|
||||
return Sqls.create("""
|
||||
SELECT
|
||||
info.*,
|
||||
si.name AS siteName,
|
||||
ins.id AS instanceId,
|
||||
ins.processDefineId instanceProcessDefineId,
|
||||
CASE WHEN info.backOption LIKE 'YEARLY_BATCH:%' THEN 1 ELSE 0 END AS yearlyBatch,
|
||||
CASE WHEN info.reserveType = 'club' THEN '协会预约' ELSE '分工会预约' END AS reserveTypeName,
|
||||
CASE WHEN info.reserveType = 'club' THEN info.clubName ELSE info.applyUnionName END AS reserveTargetName,
|
||||
DATE_FORMAT(info.createdAt, '%Y-%m-%d %H:%i:%s') AS applyTime
|
||||
FROM
|
||||
site_cug_apply info
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||
LEFT JOIN site_cug_info si ON info.siteId = si.id
|
||||
$condition
|
||||
""");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cnd buildRecordCnd(SiteCugRecordPageForm pageForm) {
|
||||
// 场馆预约查询页和导出共用同一套筛选条件,保证列表看见什么,导出就拿到什么
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
seg.or(SiteCugApply::getApplyUserName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
seg.or(SiteCugApply::getApplyLoginName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
cnd.and(seg);
|
||||
}
|
||||
if (StrUtil.isNotBlank(pageForm.getReserveTargetKeyword())) {
|
||||
// 预约单位支持同时匹配分工会名称和协会名称,方便直接查某个预约主体的全部记录
|
||||
SqlExpressionGroup reserveTargetSeg = new SqlExpressionGroup();
|
||||
reserveTargetSeg.or("info.applyUnionName", "like", "%" + pageForm.getReserveTargetKeyword() + "%");
|
||||
reserveTargetSeg.or("info.clubName", "like", "%" + pageForm.getReserveTargetKeyword() + "%");
|
||||
cnd.and(reserveTargetSeg);
|
||||
}
|
||||
if (StrUtil.isNotBlank(pageForm.getReserveType())) {
|
||||
cnd.andEX("info.reserveType", "=", pageForm.getReserveType());
|
||||
}
|
||||
if (StrUtil.isNotBlank(pageForm.getReserveTimeStart())) {
|
||||
// 按预约时间查询时,开始边界取“预约结束时间大于等于筛选开始”,这样跨段预约也能查出来
|
||||
cnd.andEX("info.reserveEndTime", ">=", pageForm.getReserveTimeStart());
|
||||
}
|
||||
if (StrUtil.isNotBlank(pageForm.getReserveTimeEnd())) {
|
||||
// 按预约时间查询时,结束边界取“预约开始时间小于等于筛选结束”,保证时间段有交叉就能命中
|
||||
cnd.andEX("info.reserveStartTime", "<=", pageForm.getReserveTimeEnd());
|
||||
}
|
||||
cnd.andEX("si.typeId", "=", pageForm.getSiteType());
|
||||
cnd.andEX("info.siteId", "=", pageForm.getSiteId());
|
||||
// 预约查询页固定只看审核结束记录;导出复用同一条件,实现所见即所得
|
||||
cnd.and("ins.state", "in", List.of(ProcessInstanceStateEnum.FINISHED.getCode(), ProcessInstanceStateEnum.REJECT.getCode()));
|
||||
if (StrUtil.isNotBlank(pageForm.getPageOrderName()) && StrUtil.isNotBlank(pageForm.getPageOrderBy())) {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
} else {
|
||||
cnd.desc("info.createdAt");
|
||||
}
|
||||
cnd.groupBy("info.id");
|
||||
return cnd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exportRecord(SiteCugRecordPageForm pageForm, HttpServletResponse response) {
|
||||
// 导出直接复用列表同一套查询条件和字段定义,保证导出结果与当前列表查询结果一致
|
||||
Sql sql = buildRecordSql();
|
||||
Cnd cnd = buildRecordCnd(pageForm);
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
dao().execute(sql);
|
||||
List<NutMap> list = sql.getList(NutMap.class);
|
||||
ExportParams exportParams = new ExportParams();
|
||||
exportParams.setTitle("预约查询");
|
||||
exportParams.setSheetName("预约查询");
|
||||
exportParams.setType(ExcelType.XSSF);
|
||||
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, buildRecordExportEntities(), list);
|
||||
CommonDownloadUtil.download("场馆预约查询.xlsx", workbook, response);
|
||||
}
|
||||
|
||||
// 场馆预约查询导出字段统一在 service 中定义,并与当前列表展示字段保持一致
|
||||
private List<ExcelExportEntity> buildRecordExportEntities() {
|
||||
List<ExcelExportEntity> exportEntities = new ArrayList<>();
|
||||
exportEntities.add(new ExcelExportEntity("场地名称", "siteName", 20));
|
||||
exportEntities.add(new ExcelExportEntity("预约人", "applyUserName", 20));
|
||||
exportEntities.add(new ExcelExportEntity("预约类型", "reserveTypeName", 20));
|
||||
exportEntities.add(new ExcelExportEntity("预约单位", "reserveTargetName", 20));
|
||||
exportEntities.add(new ExcelExportEntity("所属单位", "applyUnitName", 20));
|
||||
exportEntities.add(new ExcelExportEntity("预约开始时间", "reserveStartTime", 24));
|
||||
exportEntities.add(new ExcelExportEntity("预约结束时间", "reserveEndTime", 24));
|
||||
exportEntities.add(new ExcelExportEntity("联系方式", "applyMobile", 20));
|
||||
return exportEntities;
|
||||
}
|
||||
|
||||
// 预约时间范围内只要包含周六或周日,就视为不可预约
|
||||
private boolean containsWeekend(String reserveStartTime, String reserveEndTime) {
|
||||
Date start = DateUtil.beginOfDay(DateUtil.parseDateTime(reserveStartTime));
|
||||
Date end = DateUtil.beginOfDay(DateUtil.parseDateTime(reserveEndTime));
|
||||
Date current = start;
|
||||
while (current.compareTo(end) <= 0) {
|
||||
DateTime currentDay = DateUtil.date(current);
|
||||
int week = currentDay.dayOfWeek() - 1;
|
||||
if (week == 0 || week == 6) {
|
||||
return true;
|
||||
}
|
||||
current = DateUtil.offsetDay(current, 1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 预约时间范围内只要包含节假日,就视为不可预约
|
||||
private boolean containsHoliday(String reserveStartTime, String reserveEndTime) {
|
||||
Date start = DateUtil.beginOfDay(DateUtil.parseDateTime(reserveStartTime));
|
||||
Date end = DateUtil.beginOfDay(DateUtil.parseDateTime(reserveEndTime));
|
||||
List<String> dayList = new ArrayList<>();
|
||||
Date current = start;
|
||||
while (current.compareTo(end) <= 0) {
|
||||
dayList.add(DateUtil.formatDate(current));
|
||||
current = DateUtil.offsetDay(current, 1);
|
||||
}
|
||||
if (dayList.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
List<SysHoliday> holidays = dao().query(SysHoliday.class, Cnd.NEW());
|
||||
Set<String> holidaySet = holidays.stream().map(SysHoliday::getDay).filter(StrUtil::isNotBlank).collect(Collectors.toSet());
|
||||
return dayList.stream().anyMatch(holidaySet::contains);
|
||||
}
|
||||
|
||||
// 预约时间范围只要与后台配置的禁用时间段有交叉,就直接拦截
|
||||
private boolean intersectsDisabledTime(SiteCugInfo siteInfo, String reserveStartTime, String reserveEndTime) {
|
||||
List<NutMap> timeRanges = siteInfo.getNotApplyTimeList();
|
||||
if (timeRanges == null || timeRanges.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
DateTime reserveStart = DateUtil.parseDateTime(reserveStartTime);
|
||||
DateTime reserveEnd = DateUtil.parseDateTime(reserveEndTime);
|
||||
for (NutMap range : timeRanges) {
|
||||
if (range == null || StrUtil.hasBlank(range.getString("date"), range.getString("startTime"), range.getString("endTime"))) {
|
||||
continue;
|
||||
}
|
||||
DateTime disabledStart = DateUtil.parseDateTime(range.getString("date") + " " + range.getString("startTime") + ":00");
|
||||
DateTime disabledEnd = DateUtil.parseDateTime(range.getString("date") + " " + range.getString("endTime") + ":00");
|
||||
boolean overlap = reserveStart.isBefore(disabledEnd) && reserveEnd.isAfter(disabledStart);
|
||||
if (overlap) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 按预约类型补齐最终落库数据,避免前端传错或被绕过
|
||||
private Map<Boolean, String> fillReserveTypeData(SiteCugApply apply) {
|
||||
if (StrUtil.isBlank(apply.getReserveType())) {
|
||||
return Map.of(false, "请选择预约类型");
|
||||
}
|
||||
if (StrUtil.equals(apply.getReserveType(), "union")) {
|
||||
String unionId = SecurityUtil.getUnionId();
|
||||
if (StrUtil.isBlank(unionId)) {
|
||||
return Map.of(false, "当前用户未关联分工会,不能发起分工会预约");
|
||||
}
|
||||
Sys_union union = dao().fetch(Sys_union.class, unionId);
|
||||
if (union == null) {
|
||||
return Map.of(false, "当前用户分工会信息不存在,请联系管理员核查");
|
||||
}
|
||||
apply.setApplyUnionId(union.getId());
|
||||
apply.setApplyUnionName(union.getName());
|
||||
apply.setClubId("");
|
||||
apply.setClubName("");
|
||||
return Map.of(true, "");
|
||||
}
|
||||
if (StrUtil.equals(apply.getReserveType(), "club")) {
|
||||
if (StrUtil.isBlank(apply.getClubId())) {
|
||||
return Map.of(false, "请选择协会");
|
||||
}
|
||||
// 协会预约直接复用项目现成能力;getMyManageClub() 对 SYSADMIN 已放开,因此超级管理员也能代任意协会预约
|
||||
List<SysClub> myManageClub = sysClubService.getMyManageClub();
|
||||
SysClub club = myManageClub.stream()
|
||||
.filter(item -> StrUtil.equals(item.getId(), apply.getClubId()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (club == null) {
|
||||
return Map.of(false, "所选协会不是您当前管理的协会");
|
||||
}
|
||||
apply.setClubName(club.getClubName());
|
||||
apply.setApplyUnionId("");
|
||||
apply.setApplyUnionName("");
|
||||
return Map.of(true, "");
|
||||
}
|
||||
return Map.of(false, "预约类型不合法");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.service.impl;
|
||||
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugFunctionType;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.service.SiteCugFunctionTypeService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
@Slf4j
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class SiteCugFunctionTypeServiceImpl extends BaseServiceImpl<SiteCugFunctionType> implements SiteCugFunctionTypeService {
|
||||
|
||||
public SiteCugFunctionTypeServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.service.impl;
|
||||
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugInfo;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.service.SiteCugInfoService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
@Slf4j
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class SiteCugInfoServiceImpl extends BaseServiceImpl<SiteCugInfo> implements SiteCugInfoService {
|
||||
|
||||
public SiteCugInfoServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
}
|
||||
+625
@@ -0,0 +1,625 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
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.sys.models.Sys_union;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourMatterService;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.ss.usermodel.BorderStyle;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.Font;
|
||||
import org.apache.poi.ss.usermodel.HorizontalAlignment;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.VerticalAlignment;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@IocBean
|
||||
@Ok("json:full")
|
||||
@At("/platform/tour/group")
|
||||
public class TourGroupController {
|
||||
|
||||
@Inject
|
||||
private TourMatterService tourMatterService;
|
||||
|
||||
@Inject
|
||||
private TourLedgerService tourLedgerService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/Tour/group/index.html")
|
||||
@SaCheckPermission("tour.group")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.group")
|
||||
public Result pageData(PageForm pageForm, Integer year, String lineName, String lineType, String unionId) {
|
||||
if (StrUtil.isBlank(pageForm.getPageOrderName())) {
|
||||
pageForm.defaultSortAsc("lineName");
|
||||
}
|
||||
Cnd cnd = buildQueryCnd(year, lineName, lineType, unionId);
|
||||
|
||||
Sql countSql = Sqls.create("""
|
||||
SELECT COUNT(1)
|
||||
FROM tour_matter m
|
||||
INNER JOIN tour_line l ON l.id = m.lineId
|
||||
LEFT JOIN sys_union u ON u.id = m.unionId
|
||||
$condition
|
||||
""");
|
||||
countSql.setCondition(cnd);
|
||||
countSql.setCallback(Sqls.callback.integer());
|
||||
tourMatterService.dao().execute(countSql);
|
||||
int count = countSql.getInt();
|
||||
|
||||
Sql listSql = Sqls.create("""
|
||||
SELECT
|
||||
m.id AS matterId,
|
||||
m.`year`,
|
||||
m.matterName,
|
||||
m.unionId,
|
||||
COALESCE(u.name, '校工会') AS unionName,
|
||||
m.lineId,
|
||||
l.lineName,
|
||||
l.lineType,
|
||||
l.directFamilyUnitLine,
|
||||
m.travelStartTime,
|
||||
m.travelEndTime,
|
||||
CASE
|
||||
WHEN IFNULL(m.travelStartTime, '') <> '' AND IFNULL(m.travelEndTime, '') <> ''
|
||||
THEN CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime)
|
||||
ELSE ''
|
||||
END AS travelPeriod,
|
||||
m.minGroupPeople,
|
||||
m.maxGroupPeople,
|
||||
IFNULL(sc.signupCount, 0) AS signupCount,
|
||||
CASE
|
||||
WHEN m.maxGroupPeople IS NOT NULL AND m.maxGroupPeople > 0 AND IFNULL(sc.signupCount, 0) > m.maxGroupPeople THEN 'over'
|
||||
WHEN m.minGroupPeople IS NOT NULL AND m.minGroupPeople > 0 AND IFNULL(sc.signupCount, 0) >= m.minGroupPeople THEN 'formed'
|
||||
ELSE 'unformed'
|
||||
END AS groupStatus,
|
||||
CASE
|
||||
WHEN m.maxGroupPeople IS NOT NULL AND m.maxGroupPeople > 0 AND IFNULL(sc.signupCount, 0) > m.maxGroupPeople THEN '超员'
|
||||
WHEN m.minGroupPeople IS NOT NULL AND m.minGroupPeople > 0 AND IFNULL(sc.signupCount, 0) >= m.minGroupPeople THEN '已成团'
|
||||
ELSE '未成团'
|
||||
END AS groupStatusName
|
||||
FROM tour_matter m
|
||||
INNER JOIN tour_line l ON l.id = m.lineId
|
||||
LEFT JOIN sys_union u ON u.id = m.unionId
|
||||
LEFT JOIN (
|
||||
SELECT t.matterId, SUM(1 + IFNULL(f.familyCount, 0)) AS signupCount
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN (
|
||||
SELECT ledgerId, COUNT(1) AS familyCount
|
||||
FROM tour_ledger_family
|
||||
WHERE delFlag = 0
|
||||
GROUP BY ledgerId
|
||||
) f ON f.ledgerId = t.id
|
||||
WHERE t.delFlag = 0
|
||||
AND t.matterId IS NOT NULL
|
||||
AND t.matterId <> ''
|
||||
GROUP BY t.matterId
|
||||
) sc ON sc.matterId = m.id
|
||||
$condition
|
||||
ORDER BY $orderColumn $orderBy, m.`year` DESC, m.travelStartTime ASC, l.lineName ASC, m.createdAt DESC
|
||||
""");
|
||||
listSql.setCondition(cnd);
|
||||
listSql.setVar("orderColumn", getOrderColumn(pageForm.getPageOrderName()));
|
||||
listSql.setVar("orderBy", "descending".equals(pageForm.getPageOrderBy()) ? "desc" : "asc");
|
||||
listSql.setPager(tourMatterService.dao().createPager(pageForm.getPageNumber(), pageForm.getPageSize()));
|
||||
listSql.setCallback(Sqls.callback.maps());
|
||||
tourMatterService.dao().execute(listSql);
|
||||
|
||||
Pagination<NutMap> pagination = new Pagination<>(pageForm.getPageNumber(), pageForm.getPageSize(), count, listSql.getList(NutMap.class));
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.group")
|
||||
public Result unionOptions() {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.asc("unionCode");
|
||||
cnd.asc("name");
|
||||
return Result.success(tourMatterService.dao().query(Sys_union.class, cnd));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.group")
|
||||
public Result lineTypeOptions(Integer year) {
|
||||
Cnd cnd = buildQueryCnd(year, null, null, null);
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT DISTINCT l.lineType
|
||||
FROM tour_matter m
|
||||
INNER JOIN tour_line l ON l.id = m.lineId
|
||||
LEFT JOIN sys_union u ON u.id = m.unionId
|
||||
$condition
|
||||
ORDER BY l.lineType ASC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourMatterService.dao().execute(sql);
|
||||
return Result.success(sql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.group")
|
||||
public Result signupPageData(PageForm pageForm, String matterId, String keyword, String unionId) {
|
||||
if (StrUtil.isBlank(matterId)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
if (StrUtil.isBlank(pageForm.getPageOrderName())) {
|
||||
pageForm.defaultSortDesc("signupTime");
|
||||
}
|
||||
Cnd cnd = buildSignupQueryCnd(matterId, keyword, unionId);
|
||||
Sql countSql = Sqls.create("""
|
||||
SELECT COUNT(1)
|
||||
FROM tour_ledger t
|
||||
INNER JOIN tour_matter m ON m.id = t.matterId
|
||||
INNER JOIN tour_line l ON l.id = m.lineId
|
||||
$condition
|
||||
""");
|
||||
countSql.setCondition(cnd);
|
||||
countSql.setCallback(Sqls.callback.integer());
|
||||
tourLedgerService.dao().execute(countSql);
|
||||
int count = countSql.getInt();
|
||||
|
||||
Sql listSql = Sqls.create("""
|
||||
SELECT
|
||||
t.id,
|
||||
t.jobNo,
|
||||
t.userName,
|
||||
'' AS mobile,
|
||||
t.idCard,
|
||||
t.unionId,
|
||||
t.unionName,
|
||||
t.signupTime
|
||||
FROM tour_ledger t
|
||||
INNER JOIN tour_matter m ON m.id = t.matterId
|
||||
INNER JOIN tour_line l ON l.id = m.lineId
|
||||
$condition
|
||||
ORDER BY $orderColumn $orderBy, t.signupTime DESC, t.createdAt DESC
|
||||
""");
|
||||
listSql.setCondition(cnd);
|
||||
listSql.setVar("orderColumn", getSignupOrderColumn(pageForm.getPageOrderName()));
|
||||
listSql.setVar("orderBy", "ascending".equals(pageForm.getPageOrderBy()) ? "asc" : "desc");
|
||||
listSql.setPager(tourLedgerService.dao().createPager(pageForm.getPageNumber(), pageForm.getPageSize()));
|
||||
listSql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(listSql);
|
||||
|
||||
List<NutMap> list = listSql.getList(NutMap.class);
|
||||
fillSignupMobile(list);
|
||||
Pagination<NutMap> pagination = new Pagination<>(pageForm.getPageNumber(), pageForm.getPageSize(), count, list);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@Ok("void")
|
||||
@SaCheckPermission("tour.group")
|
||||
public void exportParticipants(String matterId, HttpServletResponse response) {
|
||||
if (StrUtil.isBlank(matterId)) {
|
||||
return;
|
||||
}
|
||||
NutMap matter = fetchExportMatter(matterId);
|
||||
if (matter == null || matter.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<NutMap> list = queryExportParticipants(matterId);
|
||||
Workbook workbook = buildParticipantsWorkbook(matter, list);
|
||||
String lineName = StrUtil.blankToDefault(matter.getString("lineName", ""), "线路");
|
||||
CommonDownloadUtil.download(lineName + "参加人员名单.xls", workbook, response);
|
||||
}
|
||||
|
||||
private Cnd buildSignupQueryCnd(String matterId, String keyword, String unionId) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("t.delFlag", "=", false);
|
||||
cnd.and("t.matterId", "=", matterId);
|
||||
cnd.and("m.delFlag", "=", false);
|
||||
cnd.and("m.enabled", "=", true);
|
||||
cnd.and("m.lineId", "IS NOT", null);
|
||||
cnd.and("m.lineId", "<>", "");
|
||||
cnd.and("l.delFlag", "=", false);
|
||||
cnd.and("l.enabled", "=", true);
|
||||
if (StrUtil.isNotBlank(keyword)) {
|
||||
SqlExpressionGroup keywordGroup = new SqlExpressionGroup();
|
||||
keywordGroup.orLike("t.userName", keyword.trim());
|
||||
keywordGroup.orLike("t.jobNo", keyword.trim());
|
||||
cnd.and(keywordGroup);
|
||||
}
|
||||
cnd.andEX("t.unionId", "=", unionId);
|
||||
applyMatterDataScope(cnd);
|
||||
return cnd;
|
||||
}
|
||||
|
||||
private NutMap fetchExportMatter(String matterId) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("m.delFlag", "=", false);
|
||||
cnd.and("m.enabled", "=", true);
|
||||
cnd.and("m.id", "=", matterId);
|
||||
cnd.and("m.lineId", "IS NOT", null);
|
||||
cnd.and("m.lineId", "<>", "");
|
||||
cnd.and("l.delFlag", "=", false);
|
||||
cnd.and("l.enabled", "=", true);
|
||||
applyMatterDataScope(cnd);
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
m.id AS matterId,
|
||||
m.`year`,
|
||||
m.unionId,
|
||||
COALESCE(u.name, '校工会') AS unionName,
|
||||
l.lineName,
|
||||
l.lineType,
|
||||
m.travelStartTime,
|
||||
m.travelEndTime,
|
||||
CASE
|
||||
WHEN IFNULL(m.travelStartTime, '') <> '' AND IFNULL(m.travelEndTime, '') <> ''
|
||||
THEN CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime)
|
||||
ELSE ''
|
||||
END AS travelPeriod
|
||||
FROM tour_matter m
|
||||
INNER JOIN tour_line l ON l.id = m.lineId
|
||||
LEFT JOIN sys_union u ON u.id = m.unionId
|
||||
$condition
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.map());
|
||||
tourMatterService.dao().execute(sql);
|
||||
return sql.getObject(NutMap.class);
|
||||
}
|
||||
|
||||
private List<NutMap> queryExportParticipants(String matterId) {
|
||||
Cnd cnd = buildSignupQueryCnd(matterId, null, null);
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
t.id AS ledgerId,
|
||||
t.jobNo,
|
||||
t.userName,
|
||||
t.idCard,
|
||||
vu.mobile,
|
||||
t.unionName,
|
||||
l.lineName,
|
||||
CASE
|
||||
WHEN IFNULL(m.travelStartTime, '') <> '' AND IFNULL(m.travelEndTime, '') <> ''
|
||||
THEN CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime)
|
||||
ELSE ''
|
||||
END AS travelPeriod,
|
||||
t.signupTime
|
||||
FROM tour_ledger t
|
||||
INNER JOIN tour_matter m ON m.id = t.matterId
|
||||
INNER JOIN tour_line l ON l.id = m.lineId
|
||||
LEFT JOIN vw_user vu ON vu.loginname = t.jobNo
|
||||
$condition
|
||||
ORDER BY t.signupTime DESC, t.createdAt DESC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
List<NutMap> list = sql.getList(NutMap.class);
|
||||
fillExportFamilies(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
private void fillExportFamilies(List<NutMap> list) {
|
||||
if (list == null || list.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<String> ledgerIds = new ArrayList<>();
|
||||
for (NutMap item : list) {
|
||||
String ledgerId = item.getString("ledgerId", "");
|
||||
if (StrUtil.isNotBlank(ledgerId)) {
|
||||
ledgerIds.add(ledgerId);
|
||||
}
|
||||
}
|
||||
if (ledgerIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
ledgerId,
|
||||
familyName,
|
||||
relationship,
|
||||
idCard
|
||||
FROM tour_ledger_family
|
||||
WHERE delFlag = 0
|
||||
AND ledgerId IN (@ledgerIds)
|
||||
ORDER BY createdAt ASC
|
||||
""");
|
||||
sql.setParam("ledgerIds", ledgerIds.toArray(new String[0]));
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
|
||||
Map<String, List<NutMap>> familyMap = new HashMap<>();
|
||||
for (NutMap family : sql.getList(NutMap.class)) {
|
||||
familyMap.computeIfAbsent(family.getString("ledgerId", ""), key -> new ArrayList<>()).add(family);
|
||||
}
|
||||
for (NutMap item : list) {
|
||||
item.put("families", familyMap.getOrDefault(item.getString("ledgerId", ""), List.of()));
|
||||
}
|
||||
}
|
||||
|
||||
private Workbook buildParticipantsWorkbook(NutMap matter, List<NutMap> list) {
|
||||
Workbook workbook = new HSSFWorkbook();
|
||||
Sheet sheet = workbook.createSheet("参加人员名单");
|
||||
sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 10));
|
||||
sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, 10));
|
||||
|
||||
double[] widths = {6, 14, 12, 22, 16, 24, 34, 26, 12, 12, 16};
|
||||
for (int i = 0; i < widths.length; i++) {
|
||||
sheet.setColumnWidth(i, (int) (widths[i] * 256));
|
||||
}
|
||||
|
||||
CellStyle titleStyle = createStyle(workbook, "黑体", (short) 16, true, HorizontalAlignment.CENTER, false, false);
|
||||
CellStyle unionStyle = createStyle(workbook, "宋体", (short) 12, true, HorizontalAlignment.LEFT, false, false);
|
||||
CellStyle headerStyle = createStyle(workbook, "宋体", (short) 11, true, HorizontalAlignment.CENTER, true, true);
|
||||
CellStyle bodyStyle = createStyle(workbook, "宋体", (short) 11, false, HorizontalAlignment.CENTER, true, true);
|
||||
|
||||
Row titleRow = sheet.createRow(0);
|
||||
titleRow.setHeightInPoints(30);
|
||||
setCell(titleRow, 0, StrUtil.blankToDefault(matter.getString("lineName", ""), ""), titleStyle);
|
||||
fillMergedCells(titleRow, 1, 10, titleStyle);
|
||||
|
||||
Row unionRow = sheet.createRow(1);
|
||||
unionRow.setHeightInPoints(26);
|
||||
setCell(unionRow, 0, "分工会:" + StrUtil.blankToDefault(matter.getString("unionName", ""), ""), unionStyle);
|
||||
fillMergedCells(unionRow, 1, 10, unionStyle);
|
||||
|
||||
String[] headers = {"序号", "工号", "姓名", "身份证号码", "电话号码", "所属分工会", "所选线路名称", "疗休养时间", "亲属关系", "姓名", "备注"};
|
||||
Row headerRow = sheet.createRow(2);
|
||||
headerRow.setHeightInPoints(35);
|
||||
for (int i = 0; i < headers.length; i++) {
|
||||
setCell(headerRow, i, headers[i], headerStyle);
|
||||
}
|
||||
|
||||
int rowIndex = 3;
|
||||
int seq = 1;
|
||||
for (NutMap item : list == null ? List.<NutMap>of() : list) {
|
||||
Row staffRow = sheet.createRow(rowIndex++);
|
||||
staffRow.setHeightInPoints(24);
|
||||
setParticipantRow(staffRow, seq++, item.getString("jobNo", ""), item.getString("userName", ""),
|
||||
item.getString("idCard", ""), item.getString("mobile", ""), item.getString("unionName", ""),
|
||||
item.getString("lineName", matter.getString("lineName", "")), item.getString("travelPeriod", matter.getString("travelPeriod", "")),
|
||||
"", item.getString("userName", ""), bodyStyle);
|
||||
|
||||
Object familiesObj = item.get("families");
|
||||
if (familiesObj instanceof List<?> families) {
|
||||
for (Object obj : families) {
|
||||
if (!(obj instanceof NutMap family)) {
|
||||
continue;
|
||||
}
|
||||
Row familyRow = sheet.createRow(rowIndex++);
|
||||
familyRow.setHeightInPoints(24);
|
||||
setParticipantRow(familyRow, seq++, "", family.getString("familyName", ""),
|
||||
family.getString("idCard", ""), "", "",
|
||||
item.getString("lineName", matter.getString("lineName", "")),
|
||||
item.getString("travelPeriod", matter.getString("travelPeriod", "")),
|
||||
family.getString("relationship", ""), item.getString("userName", ""), bodyStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int minRows = Math.max(rowIndex, 23);
|
||||
while (rowIndex < minRows) {
|
||||
Row row = sheet.createRow(rowIndex++);
|
||||
row.setHeightInPoints(24);
|
||||
for (int i = 0; i < headers.length; i++) {
|
||||
setCell(row, i, "", bodyStyle);
|
||||
}
|
||||
}
|
||||
return workbook;
|
||||
}
|
||||
|
||||
private void setParticipantRow(Row row, int seq, String jobNo, String userName, String idCard, String mobile,
|
||||
String unionName, String lineName, String travelPeriod, String relationship,
|
||||
String participantName, CellStyle style) {
|
||||
setCell(row, 0, String.valueOf(seq), style);
|
||||
setCell(row, 1, jobNo, style);
|
||||
setCell(row, 2, userName, style);
|
||||
setCell(row, 3, idCard, style);
|
||||
setCell(row, 4, mobile, style);
|
||||
setCell(row, 5, unionName, style);
|
||||
setCell(row, 6, lineName, style);
|
||||
setCell(row, 7, travelPeriod, style);
|
||||
setCell(row, 8, relationship, style);
|
||||
setCell(row, 9, participantName, style);
|
||||
setCell(row, 10, "", style);
|
||||
}
|
||||
|
||||
private CellStyle createStyle(Workbook workbook, String fontName, short fontSize, boolean bold, HorizontalAlignment alignment, boolean wrap, boolean border) {
|
||||
Font font = workbook.createFont();
|
||||
font.setFontName(fontName);
|
||||
font.setFontHeightInPoints(fontSize);
|
||||
font.setBold(bold);
|
||||
|
||||
CellStyle style = workbook.createCellStyle();
|
||||
style.setFont(font);
|
||||
style.setAlignment(alignment);
|
||||
style.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
style.setWrapText(wrap);
|
||||
if (border) {
|
||||
style.setBorderLeft(BorderStyle.THIN);
|
||||
style.setBorderTop(BorderStyle.THIN);
|
||||
style.setBorderRight(BorderStyle.THIN);
|
||||
style.setBorderBottom(BorderStyle.THIN);
|
||||
}
|
||||
return style;
|
||||
}
|
||||
|
||||
private void setCell(Row row, int col, String value, CellStyle style) {
|
||||
Cell cell = row.createCell(col);
|
||||
cell.setCellValue(StrUtil.blankToDefault(value, ""));
|
||||
cell.setCellStyle(style);
|
||||
}
|
||||
|
||||
private void fillMergedCells(Row row, int startCol, int endCol, CellStyle style) {
|
||||
for (int i = startCol; i <= endCol; i++) {
|
||||
setCell(row, i, "", style);
|
||||
}
|
||||
}
|
||||
|
||||
private void fillSignupMobile(List<NutMap> list) {
|
||||
if (list == null || list.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<String> jobNos = new ArrayList<>();
|
||||
for (NutMap item : list) {
|
||||
String jobNo = item.getString("jobNo", "");
|
||||
if (StrUtil.isNotBlank(jobNo) && !jobNos.contains(jobNo)) {
|
||||
jobNos.add(jobNo);
|
||||
}
|
||||
}
|
||||
if (jobNos.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Sql sql = Sqls.create("SELECT loginname, mobile FROM vw_user WHERE loginname IN (@jobNos)");
|
||||
sql.setParam("jobNos", jobNos.toArray(new String[0]));
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
|
||||
Map<String, String> mobileMap = new HashMap<>();
|
||||
for (NutMap user : sql.getList(NutMap.class)) {
|
||||
mobileMap.put(user.getString("loginname", ""), user.getString("mobile", ""));
|
||||
}
|
||||
for (NutMap item : list) {
|
||||
item.put("mobile", mobileMap.getOrDefault(item.getString("jobNo", ""), ""));
|
||||
}
|
||||
}
|
||||
|
||||
private Cnd buildQueryCnd(Integer year, String lineName, String lineType, String unionId) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("m.delFlag", "=", false);
|
||||
cnd.and("m.enabled", "=", true);
|
||||
cnd.and("m.lineId", "IS NOT", null);
|
||||
cnd.and("m.lineId", "<>", "");
|
||||
cnd.and("l.delFlag", "=", false);
|
||||
cnd.and("l.enabled", "=", true);
|
||||
cnd.andEX("m.`year`", "=", year == null ? LocalDate.now().getYear() : year);
|
||||
cnd.and(Cnd.likeEX("l.lineName", lineName));
|
||||
cnd.andEX("l.lineType", "=", lineType);
|
||||
cnd.andEX("m.unionId", "=", unionId);
|
||||
applyMatterDataScope(cnd);
|
||||
return cnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* 线路成团按事项归属控制数据范围:校工会查看全部;分工会查看本工会事项;其它角色仅查看自己创建的事项。
|
||||
*/
|
||||
private void applyMatterDataScope(Cnd cnd) {
|
||||
if (hasSchoolUnionScope()) {
|
||||
return;
|
||||
}
|
||||
if (hasBranchUnionScope()) {
|
||||
cnd.and("m.unionId", "=", SecurityUtil.getUnionId());
|
||||
return;
|
||||
}
|
||||
SqlExpressionGroup creatorGroup = new SqlExpressionGroup();
|
||||
creatorGroup.or("m.creatorUserId", "=", SecurityUtil.getUserId());
|
||||
creatorGroup.or("m.createdBy", "=", SecurityUtil.getUserId());
|
||||
cnd.and(creatorGroup);
|
||||
}
|
||||
|
||||
private boolean hasSchoolUnionScope() {
|
||||
return AuthUtil.hasRole(RoleConstant.SYSADMIN.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.SCHOOL_UNION_ADMIN.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.SCHOOL_UNION_CHAIRMAN.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.SCHOOL_UNION_VICE_CHAIRMAN.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.SCHOOL_UNION_WELFARE_ADMIN.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.SCHOOL_UNION_MEMBER_ADMIN.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.SCHOOL_UNION_TC_ADMIN.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.SCHOOL_UNION_WC_ADMIN.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.SCHOOL_UNION_DC_ADMIN.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.SCHOOL_UNION_PROPOSAL_ADMIN.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.SCHOOL_UNION_CLUB_ADMIN.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.SCHOOL_UNION_ACTIVITY_ADMIN.name());
|
||||
}
|
||||
|
||||
private boolean hasBranchUnionScope() {
|
||||
return AuthUtil.hasRole(RoleConstant.BRANCH_UNION_ADMIN.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.BRANCH_UNION_CHAIRMAN.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.BRANCH_UNION_VICE_CHAIRMAN.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.BRANCH_UNION_OPERATOR.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.BRANCH_UNION_GROUP_LEADER.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.BRANCH_UNION_ARTICLE_WRITER.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.BRANCH_UNION_WY.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.BRANCH_UNION_ZUZHI_WY.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.BRANCH_UNION_XUANCHUAN_WY.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.BRANCH_UNION_NVGONG_WY.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.BRANCH_UNION_QINGNIAN_WY.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.BRANCH_UNION_WENTI_WY.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.BRANCH_UNION_SHENGGHUO_WY.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.BRANCH_UNION_TIAOJIE_WY.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.BRANCH_UNION_WENTI_SPORTS.name());
|
||||
}
|
||||
|
||||
private String getOrderColumn(String orderName) {
|
||||
if ("lineName".equals(orderName)) {
|
||||
return "l.lineName";
|
||||
}
|
||||
if ("travelPeriod".equals(orderName)) {
|
||||
return "m.travelStartTime";
|
||||
}
|
||||
if ("matterName".equals(orderName)) {
|
||||
return "m.matterName";
|
||||
}
|
||||
if ("unionName".equals(orderName)) {
|
||||
return "u.name";
|
||||
}
|
||||
if ("lineType".equals(orderName)) {
|
||||
return "l.lineType";
|
||||
}
|
||||
if ("signupCount".equals(orderName)) {
|
||||
return "signupCount";
|
||||
}
|
||||
if ("minGroupPeople".equals(orderName)) {
|
||||
return "m.minGroupPeople";
|
||||
}
|
||||
if ("maxGroupPeople".equals(orderName)) {
|
||||
return "m.maxGroupPeople";
|
||||
}
|
||||
if ("groupStatusName".equals(orderName)) {
|
||||
return "groupStatus";
|
||||
}
|
||||
return "l.lineName";
|
||||
}
|
||||
|
||||
private String getSignupOrderColumn(String orderName) {
|
||||
if ("jobNo".equals(orderName)) {
|
||||
return "t.jobNo";
|
||||
}
|
||||
if ("userName".equals(orderName)) {
|
||||
return "t.userName";
|
||||
}
|
||||
if ("idCard".equals(orderName)) {
|
||||
return "t.idCard";
|
||||
}
|
||||
if ("unionName".equals(orderName)) {
|
||||
return "t.unionName";
|
||||
}
|
||||
return "t.signupTime";
|
||||
}
|
||||
}
|
||||
+959
@@ -0,0 +1,959 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.controller;
|
||||
|
||||
import cn.afterturn.easypoi.excel.ExcelExportUtil;
|
||||
import cn.afterturn.easypoi.excel.ExcelImportUtil;
|
||||
import cn.afterturn.easypoi.excel.entity.ExportParams;
|
||||
import cn.afterturn.easypoi.excel.entity.ImportParams;
|
||||
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
|
||||
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
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.flow.enums.ProcessInstanceStateEnum;
|
||||
import com.budwk.app.sys.models.Sys_union;
|
||||
import com.budwk.app.sys.views.View_user;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.mode.TourLedgerImportExcelMode;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedger;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedgerDirectRelative;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedgerFamily;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLine;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourTravelAgency;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerDirectRelativeService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerFamilyService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerService;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.ss.usermodel.BorderStyle;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.FillPatternType;
|
||||
import org.apache.poi.ss.usermodel.Font;
|
||||
import org.apache.poi.ss.usermodel.HorizontalAlignment;
|
||||
import org.apache.poi.ss.usermodel.IndexedColors;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.VerticalAlignment;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Chain;
|
||||
import org.nutz.dao.Cnd;
|
||||
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.json.Json;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.mvc.annotation.AdaptBy;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
import org.nutz.mvc.upload.TempFile;
|
||||
import org.nutz.mvc.upload.UploadAdaptor;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
@IocBean
|
||||
@Ok("json:full")
|
||||
@At("/platform/tour/ledger")
|
||||
public class TourLedgerController {
|
||||
|
||||
@Inject
|
||||
private TourLedgerService tourLedgerService;
|
||||
|
||||
@Inject
|
||||
private TourLedgerFamilyService tourLedgerFamilyService;
|
||||
|
||||
@Inject
|
||||
private TourLedgerDirectRelativeService tourLedgerDirectRelativeService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/Tour/ledger/index.html")
|
||||
@SaCheckPermission("tour.ledger")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.ledger")
|
||||
public Result pageData(PageForm pageForm, Integer startYear, Integer endYear, String keyword, String unionId, String lineId, String travelPeriod, String lineType, Boolean directFamilyOnly, Boolean overCostOnly) {
|
||||
Cnd cnd = buildQueryCnd(startYear, endYear, keyword, unionId, lineId, travelPeriod, lineType, directFamilyOnly, overCostOnly);
|
||||
|
||||
Sql countSql = Sqls.create("""
|
||||
SELECT COUNT(DISTINCT t.id)
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = t.id
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
LEFT JOIN tour_ledger_direct_relative dr ON dr.ledgerId = t.id AND dr.delFlag = 0
|
||||
$condition
|
||||
""");
|
||||
countSql.setCondition(cnd);
|
||||
countSql.setCallback(Sqls.callback.integer());
|
||||
tourLedgerService.dao().execute(countSql);
|
||||
int count = countSql.getInt();
|
||||
|
||||
Sql listSql = Sqls.create("""
|
||||
SELECT
|
||||
t.*,
|
||||
ins.id AS instanceId,
|
||||
ins.state AS instanceState,
|
||||
ins.processDefineId AS instanceProcessDefineId,
|
||||
IF(IFNULL(l.directFamilyUnitLine, 0) = 1 OR dr.id IS NOT NULL, 1, 0) AS directFamilyUnitLine,
|
||||
dr.id AS directRelativeId,
|
||||
COALESCE(NULLIF(l.lineName, ''), t.lineName) AS currentLineName,
|
||||
IFNULL(f.familyCount, 0) AS familyCount,
|
||||
CASE
|
||||
WHEN IFNULL(m.travelStartTime, '') <> '' AND IFNULL(m.travelEndTime, '') <> ''
|
||||
THEN CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime)
|
||||
ELSE tp.travelPeriod
|
||||
END AS travelPeriod
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = t.id
|
||||
LEFT JOIN (
|
||||
SELECT ledgerId, COUNT(1) AS familyCount
|
||||
FROM tour_ledger_family
|
||||
WHERE delFlag = 0
|
||||
GROUP BY ledgerId
|
||||
) f ON f.ledgerId = t.id
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
LEFT JOIN tour_ledger_direct_relative dr ON dr.ledgerId = t.id AND dr.delFlag = 0
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
`year`,
|
||||
lineId,
|
||||
GROUP_CONCAT(
|
||||
DISTINCT CASE
|
||||
WHEN IFNULL(travelStartTime, '') <> '' AND IFNULL(travelEndTime, '') <> ''
|
||||
THEN CONCAT(travelStartTime, ' 至 ', travelEndTime)
|
||||
ELSE NULL
|
||||
END
|
||||
ORDER BY travelStartTime ASC
|
||||
SEPARATOR ';'
|
||||
) AS travelPeriod
|
||||
FROM tour_matter
|
||||
WHERE delFlag = 0
|
||||
AND lineId IS NOT NULL
|
||||
AND lineId <> ''
|
||||
GROUP BY `year`, lineId
|
||||
) tp ON (t.matterId IS NULL OR t.matterId = '') AND tp.`year` = t.`year` AND tp.lineId = t.lineId
|
||||
$condition
|
||||
GROUP BY t.id
|
||||
ORDER BY $orderColumn $orderBy, t.`year` DESC, t.signupTime DESC, t.createdAt DESC
|
||||
""");
|
||||
listSql.setCondition(cnd);
|
||||
listSql.setVar("orderColumn", getOrderColumn(pageForm.getPageOrderName()));
|
||||
listSql.setVar("orderBy", "descending".equals(pageForm.getPageOrderBy()) ? "desc" : "asc");
|
||||
listSql.setPager(tourLedgerService.dao().createPager(pageForm.getPageNumber(), pageForm.getPageSize()));
|
||||
listSql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(listSql);
|
||||
|
||||
var list = listSql.getList(NutMap.class);
|
||||
list.forEach(item -> item.put("lineName", item.getString("currentLineName")));
|
||||
Pagination<NutMap> pagination = new Pagination<>(pageForm.getPageNumber(), pageForm.getPageSize(), count, list);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.ledger")
|
||||
public Result detail(String id) {
|
||||
if (StrUtil.isBlank(id)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
TourLedger ledger = tourLedgerService.fetch(id);
|
||||
if (ledger == null) {
|
||||
return Result.error("台账记录不存在");
|
||||
}
|
||||
ledger.setLineName(getCurrentLineName(ledger));
|
||||
Cnd familyCnd = Cnd.NEW();
|
||||
familyCnd.and(TourLedgerFamily::getLedgerId, "=", id);
|
||||
familyCnd.and(TourLedgerFamily::getDelFlag, "=", false);
|
||||
familyCnd.asc(TourLedgerFamily::getCreatedAt);
|
||||
TourLedgerDirectRelative directRelative = tourLedgerDirectRelativeService.fetch(
|
||||
Cnd.where(TourLedgerDirectRelative::getDelFlag, "=", false)
|
||||
.and(TourLedgerDirectRelative::getLedgerId, "=", ledger.getId()));
|
||||
return Result.success(NutMap.NEW()
|
||||
.addv("ledger", ledger)
|
||||
.addv("travelPeriod", getTravelPeriod(ledger))
|
||||
.addv("families", tourLedgerFamilyService.query(familyCnd))
|
||||
.addv("directRelative", directRelative)
|
||||
.addv("fillBedInfo", isFillBedInfo(ledger))
|
||||
.addv("directFamilyUnitLine", isDirectFamilyUnitLine(ledger)));
|
||||
}
|
||||
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("tour.ledger")
|
||||
@SLog(type = "tour", tag = "疗休养台账", msg = "删除疗休养台账")
|
||||
public Result doDelete(String id) {
|
||||
if (StrUtil.isBlank(id)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
TourLedger ledger = tourLedgerService.fetch(id);
|
||||
if (ledger == null) {
|
||||
return Result.error("台账记录不存在");
|
||||
}
|
||||
tourLedgerFamilyService.clear(Cnd.where(TourLedgerFamily::getLedgerId, "=", id));
|
||||
tourLedgerService.delete(id);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("tour.ledger")
|
||||
@SLog(type = "tour", tag = "疗休养台账", msg = "设置参加人员")
|
||||
public Result setParticipants(@Param("ids") String ids) {
|
||||
List<String> idList = StrUtil.isBlank(ids) ? Collections.emptyList() : Json.fromJsonAsList(String.class, ids);
|
||||
if (idList.isEmpty()) {
|
||||
return Result.error("请选择要设置的参加人员");
|
||||
}
|
||||
tourLedgerService.dao().update(TourLedger.class, Chain.make("joined", true), Cnd.where("id", "in", idList));
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("tour.ledger")
|
||||
@SLog(type = "tour", tag = "疗休养台账", msg = "参加人员导入")
|
||||
@AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"})
|
||||
public Result importParticipants(@Param("file") TempFile file) {
|
||||
if (file == null) {
|
||||
return Result.error("请选择导入文件");
|
||||
}
|
||||
List<TourLedgerImportExcelMode> importRows = ExcelImportUtil.importExcel(file.getFile(), TourLedgerImportExcelMode.class, new ImportParams());
|
||||
ExcelImportRes<TourLedgerImportExcelMode> excelImportRes = new ExcelImportRes<>();
|
||||
excelImportRes.setTotalRecords(importRows.size());
|
||||
|
||||
for (int i = 0; i < importRows.size(); i++) {
|
||||
TourLedgerImportExcelMode row = importRows.get(i);
|
||||
if (!validateImportRow(row, i)) {
|
||||
continue;
|
||||
}
|
||||
Boolean joined = parseJoined(row.getJoined());
|
||||
if (joined == null) {
|
||||
row.setErrInfo("是否参加只能填写1、0、是、否、true、false、已参加、未参加", i);
|
||||
continue;
|
||||
}
|
||||
TourLine line = fetchImportLine(row);
|
||||
if (line == null) {
|
||||
row.setErrInfo("未找到唯一匹配的线路", i);
|
||||
continue;
|
||||
}
|
||||
List<TourLedger> ledgers = queryImportLedgerCandidates(row);
|
||||
if (ledgers.isEmpty()) {
|
||||
Result createResult = insertImportLedger(row, line, joined);
|
||||
if (createResult.isSuccess()) {
|
||||
continue;
|
||||
}
|
||||
row.setErrInfo(createResult.getMsg(), i);
|
||||
continue;
|
||||
}
|
||||
TourLedger ledger = resolveImportLedger(row, ledgers, line);
|
||||
if (ledger == null) {
|
||||
row.setErrInfo("匹配到多条台账记录,报名时间或线路未能唯一匹配,请核对年度、工号、报名时间、线路名称", i);
|
||||
continue;
|
||||
}
|
||||
Chain chain = Chain.make("joined", joined)
|
||||
.add("lineId", line.getId())
|
||||
.add("lineName", line.getLineName())
|
||||
.add("lineType", line.getLineType());
|
||||
String signupTime = normalizeSignupTime(row.getSignupTime());
|
||||
if (StrUtil.isNotBlank(signupTime)) {
|
||||
chain.add("signupTime", signupTime);
|
||||
}
|
||||
tourLedgerService.dao().update(TourLedger.class, chain, Cnd.where("id", "=", ledger.getId()));
|
||||
}
|
||||
|
||||
excelImportRes.setErrorDetails(importRows.stream().filter(s -> StrUtil.isNotBlank(s.getErrMsg())).collect(Collectors.toList()));
|
||||
excelImportRes.setFailedCount(excelImportRes.getErrorDetails().size());
|
||||
excelImportRes.setSuccessCount(Math.max(importRows.size() - excelImportRes.getFailedCount(), 0));
|
||||
return Result.success(excelImportRes);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.ledger")
|
||||
@Ok("void")
|
||||
public void downloadTemplate(HttpServletResponse response) {
|
||||
List<ExcelExportEntity> entities = new ArrayList<>();
|
||||
entities.add(new ExcelExportEntity("年度", "year", 12));
|
||||
entities.add(new ExcelExportEntity("工号", "jobNo", 18));
|
||||
entities.add(new ExcelExportEntity("姓名", "userName", 18));
|
||||
entities.add(new ExcelExportEntity("报名时间", "signupTime", 24));
|
||||
entities.add(new ExcelExportEntity("线路名称", "lineName", 30));
|
||||
entities.add(new ExcelExportEntity("线路类型", "lineType", 18));
|
||||
entities.add(new ExcelExportEntity("是否参加", "joined", 14));
|
||||
|
||||
ExportParams exportParams = new ExportParams();
|
||||
exportParams.setSheetName("tour_ledger");
|
||||
exportParams.setType(ExcelType.XSSF);
|
||||
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entities, Collections.emptyList());
|
||||
CommonDownloadUtil.download("参加人员导入模板.xlsx", workbook, response);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.ledger")
|
||||
@Ok("void")
|
||||
public void exportUnionSignupZip(Integer startYear, Integer endYear, String keyword, String unionId, String lineId,
|
||||
String travelPeriod, String lineType, Boolean directFamilyOnly, Boolean overCostOnly,
|
||||
HttpServletResponse response) throws Exception {
|
||||
List<NutMap> rows = queryUnionSignupRows(startYear, endYear, keyword, unionId, lineId, travelPeriod, lineType,
|
||||
directFamilyOnly, overCostOnly);
|
||||
Map<String, List<NutMap>> unionRows = groupRowsByUnion(rows);
|
||||
|
||||
String zipName = URLEncoder.encode("疗休养分工会报名汇总表.zip", StandardCharsets.UTF_8.toString());
|
||||
response.setContentType("application/zip");
|
||||
response.setHeader("Content-Disposition", "attachment;filename=" + zipName + ";filename*=UTF-8''" + zipName);
|
||||
try (ZipOutputStream zipOutputStream = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()))) {
|
||||
if (unionRows.isEmpty()) {
|
||||
zipOutputStream.putNextEntry(new ZipEntry("无数据报名汇总表.xls"));
|
||||
try (Workbook workbook = buildUnionSignupWorkbook("无数据", Collections.emptyList())) {
|
||||
workbook.write(zipOutputStream);
|
||||
}
|
||||
zipOutputStream.closeEntry();
|
||||
} else {
|
||||
for (Map.Entry<String, List<NutMap>> entry : unionRows.entrySet()) {
|
||||
String unionName = entry.getValue().isEmpty() ? entry.getKey() : entry.getValue().get(0).getString("unionName", entry.getKey());
|
||||
String fileName = safeFileName(unionName + "报名汇总表.xls");
|
||||
zipOutputStream.putNextEntry(new ZipEntry(fileName));
|
||||
try (Workbook workbook = buildUnionSignupWorkbook(unionName, entry.getValue())) {
|
||||
workbook.write(zipOutputStream);
|
||||
}
|
||||
zipOutputStream.closeEntry();
|
||||
}
|
||||
}
|
||||
zipOutputStream.flush();
|
||||
}
|
||||
}
|
||||
|
||||
private List<NutMap> queryUnionSignupRows(Integer startYear, Integer endYear, String keyword, String unionId, String lineId,
|
||||
String travelPeriod, String lineType, Boolean directFamilyOnly, Boolean overCostOnly) {
|
||||
Cnd cnd = buildQueryCnd(startYear, endYear, keyword, unionId, lineId, travelPeriod, lineType, directFamilyOnly, overCostOnly);
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
t.id,
|
||||
t.jobNo,
|
||||
t.userName,
|
||||
t.idCard,
|
||||
t.unionId,
|
||||
COALESCE(NULLIF(t.unionName, ''), su.name, vu.unionName, '') AS unionName,
|
||||
COALESCE(NULLIF(su.unionCode, ''), vu.unionCode, '') AS unionCode,
|
||||
COALESCE(NULLIF(vu.mobile, ''), '') AS mobile,
|
||||
COALESCE(NULLIF(l.lineName, ''), t.lineName, '') AS lineName,
|
||||
CASE
|
||||
WHEN IFNULL(m.travelStartTime, '') <> '' AND IFNULL(m.travelEndTime, '') <> ''
|
||||
THEN CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime)
|
||||
ELSE tp.travelPeriod
|
||||
END AS travelPeriod
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = t.id
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
LEFT JOIN tour_ledger_direct_relative dr ON dr.ledgerId = t.id AND dr.delFlag = 0
|
||||
LEFT JOIN vw_user vu ON vu.loginname = t.jobNo
|
||||
LEFT JOIN sys_union su ON su.id = t.unionId
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
`year`,
|
||||
lineId,
|
||||
GROUP_CONCAT(
|
||||
DISTINCT CASE
|
||||
WHEN IFNULL(travelStartTime, '') <> '' AND IFNULL(travelEndTime, '') <> ''
|
||||
THEN CONCAT(travelStartTime, ' 至 ', travelEndTime)
|
||||
ELSE NULL
|
||||
END
|
||||
ORDER BY travelStartTime ASC
|
||||
SEPARATOR ';'
|
||||
) AS travelPeriod
|
||||
FROM tour_matter
|
||||
WHERE delFlag = 0
|
||||
AND lineId IS NOT NULL
|
||||
AND lineId <> ''
|
||||
GROUP BY `year`, lineId
|
||||
) tp ON (t.matterId IS NULL OR t.matterId = '') AND tp.`year` = t.`year` AND tp.lineId = t.lineId
|
||||
$condition
|
||||
GROUP BY t.id
|
||||
ORDER BY unionCode ASC, unionName ASC, t.signupTime DESC, t.createdAt DESC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return sql.getList(NutMap.class);
|
||||
}
|
||||
|
||||
private Map<String, List<NutMap>> groupRowsByUnion(List<NutMap> rows) {
|
||||
Map<String, List<NutMap>> unionRows = new LinkedHashMap<>();
|
||||
for (NutMap row : rows) {
|
||||
String unionName = StrUtil.blankToDefault(row.getString("unionName"), "未分工会");
|
||||
String unionCode = StrUtil.blankToDefault(row.getString("unionCode"), "");
|
||||
String key = StrUtil.isBlank(unionCode) ? unionName : unionCode + "_" + unionName;
|
||||
unionRows.computeIfAbsent(key, item -> new ArrayList<>()).add(row);
|
||||
}
|
||||
return unionRows;
|
||||
}
|
||||
|
||||
private Workbook buildUnionSignupWorkbook(String unionName, List<NutMap> rows) {
|
||||
HSSFWorkbook workbook = new HSSFWorkbook();
|
||||
Sheet sheet = workbook.createSheet("报名汇总表");
|
||||
sheet.setColumnWidth(0, 8 * 256);
|
||||
sheet.setColumnWidth(1, 14 * 256);
|
||||
sheet.setColumnWidth(2, 14 * 256);
|
||||
sheet.setColumnWidth(3, 24 * 256);
|
||||
sheet.setColumnWidth(4, 16 * 256);
|
||||
sheet.setColumnWidth(5, 24 * 256);
|
||||
sheet.setColumnWidth(6, 36 * 256);
|
||||
sheet.setColumnWidth(7, 26 * 256);
|
||||
sheet.setColumnWidth(8, 18 * 256);
|
||||
|
||||
CellStyle titleStyle = createUnionSignupTitleStyle(workbook);
|
||||
CellStyle headerStyle = createUnionSignupHeaderStyle(workbook);
|
||||
CellStyle bodyStyle = createUnionSignupBodyStyle(workbook);
|
||||
|
||||
Row titleRow = sheet.createRow(0);
|
||||
titleRow.setHeightInPoints(28);
|
||||
Cell titleCell = titleRow.createCell(0);
|
||||
titleCell.setCellValue(StrUtil.blankToDefault(unionName, "未分工会") + "报名汇总表");
|
||||
titleCell.setCellStyle(titleStyle);
|
||||
sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 8));
|
||||
for (int i = 1; i <= 8; i++) {
|
||||
titleRow.createCell(i).setCellStyle(titleStyle);
|
||||
}
|
||||
|
||||
Row headerRow = sheet.createRow(1);
|
||||
headerRow.setHeightInPoints(24);
|
||||
String[] headers = {"序号", "工号", "姓名", "身份证号码", "电话号码", "所属分工会", "所选线路名称", "疗休养时间", "备注"};
|
||||
for (int i = 0; i < headers.length; i++) {
|
||||
setCell(headerRow, i, headers[i], headerStyle);
|
||||
}
|
||||
|
||||
int rowIndex = 2;
|
||||
int seq = 1;
|
||||
for (NutMap row : rows) {
|
||||
Row dataRow = sheet.createRow(rowIndex++);
|
||||
dataRow.setHeightInPoints(22);
|
||||
setCell(dataRow, 0, String.valueOf(seq++), bodyStyle);
|
||||
setCell(dataRow, 1, row.getString("jobNo", ""), bodyStyle);
|
||||
setCell(dataRow, 2, row.getString("userName", ""), bodyStyle);
|
||||
setCell(dataRow, 3, row.getString("idCard", ""), bodyStyle);
|
||||
setCell(dataRow, 4, row.getString("mobile", ""), bodyStyle);
|
||||
setCell(dataRow, 5, row.getString("unionName", ""), bodyStyle);
|
||||
setCell(dataRow, 6, row.getString("lineName", ""), bodyStyle);
|
||||
setCell(dataRow, 7, row.getString("travelPeriod", ""), bodyStyle);
|
||||
setCell(dataRow, 8, "", bodyStyle);
|
||||
}
|
||||
return workbook;
|
||||
}
|
||||
|
||||
private CellStyle createUnionSignupTitleStyle(Workbook workbook) {
|
||||
CellStyle style = workbook.createCellStyle();
|
||||
style.setAlignment(HorizontalAlignment.CENTER);
|
||||
style.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
style.setBorderTop(BorderStyle.THIN);
|
||||
style.setBorderRight(BorderStyle.THIN);
|
||||
style.setBorderBottom(BorderStyle.THIN);
|
||||
style.setBorderLeft(BorderStyle.THIN);
|
||||
Font font = workbook.createFont();
|
||||
font.setBold(true);
|
||||
font.setFontHeightInPoints((short) 16);
|
||||
style.setFont(font);
|
||||
return style;
|
||||
}
|
||||
|
||||
private CellStyle createUnionSignupHeaderStyle(Workbook workbook) {
|
||||
CellStyle style = createUnionSignupBodyStyle(workbook);
|
||||
style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
|
||||
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
||||
Font font = workbook.createFont();
|
||||
font.setBold(true);
|
||||
style.setFont(font);
|
||||
return style;
|
||||
}
|
||||
|
||||
private CellStyle createUnionSignupBodyStyle(Workbook workbook) {
|
||||
CellStyle style = workbook.createCellStyle();
|
||||
style.setAlignment(HorizontalAlignment.CENTER);
|
||||
style.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
style.setWrapText(true);
|
||||
style.setBorderTop(BorderStyle.THIN);
|
||||
style.setBorderRight(BorderStyle.THIN);
|
||||
style.setBorderBottom(BorderStyle.THIN);
|
||||
style.setBorderLeft(BorderStyle.THIN);
|
||||
return style;
|
||||
}
|
||||
|
||||
private void setCell(Row row, int index, String value, CellStyle style) {
|
||||
Cell cell = row.createCell(index);
|
||||
cell.setCellValue(StrUtil.blankToDefault(value, ""));
|
||||
cell.setCellStyle(style);
|
||||
}
|
||||
|
||||
private String safeFileName(String fileName) {
|
||||
String safeName = StrUtil.blankToDefault(fileName, "报名汇总表.xls")
|
||||
.replaceAll("[\\\\/:*?\"<>|]", "、");
|
||||
return safeName.length() > 120 ? safeName.substring(0, 120) : safeName;
|
||||
}
|
||||
|
||||
private boolean validateImportRow(TourLedgerImportExcelMode row, int index) {
|
||||
if (row.getYear() == null) {
|
||||
row.setErrInfo("年度为空", index);
|
||||
return false;
|
||||
}
|
||||
if (StrUtil.isBlank(row.getJobNo())) {
|
||||
row.setErrInfo("工号为空", index);
|
||||
return false;
|
||||
}
|
||||
if (StrUtil.isBlank(row.getLineName())) {
|
||||
row.setErrInfo("线路名称为空", index);
|
||||
return false;
|
||||
}
|
||||
if (StrUtil.isBlank(row.getLineType())) {
|
||||
row.setErrInfo("线路类型为空", index);
|
||||
return false;
|
||||
}
|
||||
if (StrUtil.isBlank(row.getJoined())) {
|
||||
row.setErrInfo("是否参加为空", index);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private TourLine fetchImportLine(TourLedgerImportExcelMode row) {
|
||||
Cnd cnd = Cnd.where(TourLine::getDelFlag, "=", false)
|
||||
.and(TourLine::getYear, "=", row.getYear())
|
||||
.and(TourLine::getLineName, "=", row.getLineName().trim())
|
||||
.and(TourLine::getLineType, "=", row.getLineType().trim());
|
||||
List<TourLine> lines = tourLedgerService.dao().query(TourLine.class, cnd);
|
||||
return lines.size() == 1 ? lines.get(0) : null;
|
||||
}
|
||||
|
||||
private List<TourLedger> queryImportLedgerCandidates(TourLedgerImportExcelMode row) {
|
||||
Cnd cnd = Cnd.where(TourLedger::getDelFlag, "=", false)
|
||||
.and(TourLedger::getYear, "=", row.getYear())
|
||||
.and(TourLedger::getJobNo, "=", row.getJobNo().trim());
|
||||
return tourLedgerService.query(cnd);
|
||||
}
|
||||
|
||||
private TourLedger resolveImportLedger(TourLedgerImportExcelMode row, List<TourLedger> ledgers, TourLine line) {
|
||||
if (ledgers.size() == 1) {
|
||||
return ledgers.get(0);
|
||||
}
|
||||
List<TourLedger> matched = ledgers;
|
||||
if (row.getSignupTime() != null) {
|
||||
String importSignupTime = normalizeSignupTime(row.getSignupTime());
|
||||
matched = matched.stream()
|
||||
.filter(item -> signupTimeEquals(importSignupTime, item.getSignupTime()))
|
||||
.collect(Collectors.toList());
|
||||
if (matched.size() == 1) {
|
||||
return matched.get(0);
|
||||
}
|
||||
}
|
||||
matched = ledgers.stream()
|
||||
.filter(item -> ledgerLineEquals(item, line))
|
||||
.collect(Collectors.toList());
|
||||
return matched.size() == 1 ? matched.get(0) : null;
|
||||
}
|
||||
|
||||
private boolean ledgerLineEquals(TourLedger ledger, TourLine line) {
|
||||
if (ledger == null || line == null) {
|
||||
return false;
|
||||
}
|
||||
if (StrUtil.isNotBlank(ledger.getLineId()) && ledger.getLineId().equals(line.getId())) {
|
||||
return true;
|
||||
}
|
||||
return StrUtil.equals(ledger.getLineName(), line.getLineName())
|
||||
&& StrUtil.equals(ledger.getLineType(), line.getLineType());
|
||||
}
|
||||
|
||||
private Result insertImportLedger(TourLedgerImportExcelMode row, TourLine line, Boolean joined) {
|
||||
View_user user = fetchImportUser(row.getJobNo());
|
||||
if (user == null) {
|
||||
return Result.error("系统用户中未找到该工号");
|
||||
}
|
||||
TourLedger ledger = new TourLedger();
|
||||
ledger.setYear(row.getYear());
|
||||
ledger.setJobNo(StrUtil.blankToDefault(user.getLoginname(), row.getJobNo().trim()));
|
||||
ledger.setUserName(StrUtil.blankToDefault(user.getUsername(), row.getUserName()));
|
||||
ledger.setGender(user.getSex());
|
||||
ledger.setIdCard(user.getIdCard());
|
||||
ledger.setUnitId(user.getUnitId());
|
||||
ledger.setUnitName(user.getUnitName());
|
||||
ledger.setUnionId(user.getUnionId());
|
||||
ledger.setUnionName(user.getUnionName());
|
||||
ledger.setSignupTime(normalizeSignupTime(row.getSignupTime()));
|
||||
ledger.setLineId(line.getId());
|
||||
ledger.setLineName(line.getLineName());
|
||||
ledger.setLineType(line.getLineType());
|
||||
ledger.setTravelAgencyId(line.getTravelAgencyId());
|
||||
ledger.setTravelAgencyName(getTravelAgencyName(line.getTravelAgencyId()));
|
||||
ledger.setHasFamily(false);
|
||||
ledger.setJoined(joined);
|
||||
ledger.setReimbursed(false);
|
||||
ledger.setOverCostReimbursed(false);
|
||||
tourLedgerService.insert(ledger);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
private View_user fetchImportUser(String jobNo) {
|
||||
if (StrUtil.isBlank(jobNo)) {
|
||||
return null;
|
||||
}
|
||||
return tourLedgerService.dao().fetch(View_user.class, Cnd.where(View_user::getLoginname, "=", jobNo.trim()));
|
||||
}
|
||||
|
||||
private String getTravelAgencyName(String travelAgencyId) {
|
||||
if (StrUtil.isBlank(travelAgencyId)) {
|
||||
return "";
|
||||
}
|
||||
TourTravelAgency agency = tourLedgerService.dao().fetch(TourTravelAgency.class, travelAgencyId);
|
||||
return agency == null ? "" : StrUtil.blankToDefault(agency.getAgencyName(), "");
|
||||
}
|
||||
|
||||
private boolean signupTimeEquals(String importSignupTime, String ledgerSignupTime) {
|
||||
if (StrUtil.isBlank(importSignupTime) || StrUtil.isBlank(ledgerSignupTime)) {
|
||||
return false;
|
||||
}
|
||||
String ledgerTime = normalizeSignupTime(ledgerSignupTime);
|
||||
if (importSignupTime.equals(ledgerTime)) {
|
||||
return true;
|
||||
}
|
||||
return importSignupTime.length() == 16 && ledgerTime.startsWith(importSignupTime)
|
||||
|| ledgerTime.length() == 16 && importSignupTime.startsWith(ledgerTime);
|
||||
}
|
||||
|
||||
private String normalizeSignupTime(Object value) {
|
||||
if (value instanceof Date date) {
|
||||
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
|
||||
}
|
||||
String text = StrUtil.trimToEmpty(value == null ? "" : String.valueOf(value)).replace('T', ' ');
|
||||
if (StrUtil.isBlank(text)) {
|
||||
return "";
|
||||
}
|
||||
text = text.replaceAll("\\.0$", "");
|
||||
String[] dateTimePatterns = {
|
||||
"yyyy-MM-dd HH:mm:ss",
|
||||
"yyyy-MM-dd HH:mm",
|
||||
"yyyy/M/d H:mm:ss",
|
||||
"yyyy/M/d H:mm",
|
||||
"M/d/yy H:mm:ss",
|
||||
"M/d/yy H:mm",
|
||||
"M/d/yyyy H:mm:ss",
|
||||
"M/d/yyyy H:mm"
|
||||
};
|
||||
for (String pattern : dateTimePatterns) {
|
||||
try {
|
||||
LocalDateTime dateTime = LocalDateTime.parse(text, DateTimeFormatter.ofPattern(pattern));
|
||||
return dateTime.format(DateTimeFormatter.ofPattern(pattern.contains(":ss") ? "yyyy-MM-dd HH:mm:ss" : "yyyy-MM-dd HH:mm"));
|
||||
} catch (DateTimeParseException ignored) {
|
||||
}
|
||||
}
|
||||
String[] datePatterns = {"yyyy-MM-dd", "yyyy/M/d", "M/d/yy", "M/d/yyyy"};
|
||||
for (String pattern : datePatterns) {
|
||||
try {
|
||||
LocalDate date = LocalDate.parse(text, DateTimeFormatter.ofPattern(pattern));
|
||||
return date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
||||
} catch (DateTimeParseException ignored) {
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
private Boolean parseJoined(String value) {
|
||||
String joined = StrUtil.trimToEmpty(value).toLowerCase();
|
||||
if ("1".equals(joined) || "1.0".equals(joined) || "是".equals(joined) || "true".equals(joined) || "已参加".equals(joined)) {
|
||||
return true;
|
||||
}
|
||||
if ("0".equals(joined) || "0.0".equals(joined) || "否".equals(joined) || "false".equals(joined) || "未参加".equals(joined)) {
|
||||
return false;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.ledger")
|
||||
public Result unionOptions() {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.asc("unionCode");
|
||||
cnd.asc("name");
|
||||
return Result.success(tourLedgerService.dao().query(Sys_union.class, cnd));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.ledger")
|
||||
public Result lineOptions(Integer startYear, Integer endYear, String travelPeriod, String lineType, String unionId, String keyword, Boolean directFamilyOnly, Boolean overCostOnly) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("t.delFlag", "=", false);
|
||||
cnd.andEX("t.`year`", ">=", startYear);
|
||||
cnd.andEX("t.`year`", "<=", endYear == null ? LocalDate.now().getYear() : endYear);
|
||||
cnd.and("t.lineName", "IS NOT", null);
|
||||
cnd.and("t.lineName", "<>", "");
|
||||
cnd.andEX("t.unionId", "=", unionId);
|
||||
cnd.andEX("t.lineType", "=", lineType);
|
||||
appendTravelPeriodFilter(cnd, travelPeriod);
|
||||
appendKeywordFilter(cnd, keyword);
|
||||
appendScopeFilter(cnd, directFamilyOnly, overCostOnly);
|
||||
appendApprovedWorkflowFilter(cnd);
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT DISTINCT
|
||||
CASE
|
||||
WHEN IFNULL(t.lineId, '') <> '' THEN t.lineId
|
||||
ELSE CONCAT('legacy:', t.lineName)
|
||||
END AS lineId,
|
||||
COALESCE(NULLIF(l.lineName, ''), t.lineName) AS lineName
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = t.id
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
LEFT JOIN tour_ledger_direct_relative dr ON dr.ledgerId = t.id AND dr.delFlag = 0
|
||||
$condition
|
||||
ORDER BY lineName ASC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return Result.success(sql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.ledger")
|
||||
public Result travelPeriodOptions(Integer startYear, Integer endYear, String lineId, String lineType, String unionId, String keyword, Boolean directFamilyOnly, Boolean overCostOnly) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("t.delFlag", "=", false);
|
||||
cnd.andEX("t.`year`", ">=", startYear);
|
||||
cnd.andEX("t.`year`", "<=", endYear == null ? LocalDate.now().getYear() : endYear);
|
||||
cnd.and("m.travelStartTime", "IS NOT", null);
|
||||
cnd.and("m.travelStartTime", "<>", "");
|
||||
cnd.and("m.travelEndTime", "IS NOT", null);
|
||||
cnd.and("m.travelEndTime", "<>", "");
|
||||
cnd.andEX("t.unionId", "=", unionId);
|
||||
cnd.andEX("t.lineType", "=", lineType);
|
||||
appendLineFilter(cnd, lineId);
|
||||
appendKeywordFilter(cnd, keyword);
|
||||
appendScopeFilter(cnd, directFamilyOnly, overCostOnly);
|
||||
appendApprovedWorkflowFilter(cnd);
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT DISTINCT CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime) AS travelPeriod
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = t.id
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
LEFT JOIN tour_ledger_direct_relative dr ON dr.ledgerId = t.id AND dr.delFlag = 0
|
||||
$condition
|
||||
ORDER BY travelPeriod ASC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return Result.success(sql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
private Cnd buildQueryCnd(Integer startYear, Integer endYear, String keyword, String unionId, String lineId, String travelPeriod, String lineType, Boolean directFamilyOnly, Boolean overCostOnly) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("t.delFlag", "=", false);
|
||||
cnd.andEX("t.`year`", ">=", startYear);
|
||||
cnd.andEX("t.`year`", "<=", endYear == null ? LocalDate.now().getYear() : endYear);
|
||||
cnd.andEX("t.unionId", "=", unionId);
|
||||
cnd.andEX("t.lineType", "=", lineType);
|
||||
appendLineFilter(cnd, lineId);
|
||||
appendTravelPeriodFilter(cnd, travelPeriod);
|
||||
appendKeywordFilter(cnd, keyword);
|
||||
appendScopeFilter(cnd, directFamilyOnly, overCostOnly);
|
||||
appendApprovedWorkflowFilter(cnd);
|
||||
return cnd;
|
||||
}
|
||||
|
||||
private void appendApprovedWorkflowFilter(Cnd cnd) {
|
||||
SqlExpressionGroup group = new SqlExpressionGroup();
|
||||
group.or("ins.id", "IS", null);
|
||||
group.or("ins.state", "=", ProcessInstanceStateEnum.FINISHED.getCode());
|
||||
cnd.and(group);
|
||||
}
|
||||
|
||||
private void appendScopeFilter(Cnd cnd, Boolean directFamilyOnly, Boolean overCostOnly) {
|
||||
if (Boolean.TRUE.equals(directFamilyOnly)) {
|
||||
cnd.and("IF(IFNULL(l.directFamilyUnitLine, 0) = 1 OR dr.id IS NOT NULL, 1, 0)", "=", 1);
|
||||
}
|
||||
if (Boolean.TRUE.equals(overCostOnly)) {
|
||||
cnd.and("t.overCostReimbursed", "=", true);
|
||||
}
|
||||
}
|
||||
|
||||
private void appendKeywordFilter(Cnd cnd, String keyword) {
|
||||
if (StrUtil.isNotBlank(keyword)) {
|
||||
SqlExpressionGroup group = new SqlExpressionGroup();
|
||||
group.orLike("t.userName", keyword.trim());
|
||||
group.orLike("t.jobNo", keyword.trim());
|
||||
cnd.and(group);
|
||||
}
|
||||
}
|
||||
|
||||
private String getOrderColumn(String orderName) {
|
||||
if ("year".equals(orderName)) {
|
||||
return "t.`year`";
|
||||
}
|
||||
if ("jobNo".equals(orderName)) {
|
||||
return "t.jobNo";
|
||||
}
|
||||
if ("userName".equals(orderName)) {
|
||||
return "t.userName";
|
||||
}
|
||||
if ("lineName".equals(orderName)) {
|
||||
return "COALESCE(NULLIF(l.lineName, ''), t.lineName)";
|
||||
}
|
||||
if ("travelPeriod".equals(orderName)) {
|
||||
return "COALESCE(m.travelStartTime, tp.travelPeriod)";
|
||||
}
|
||||
if ("lineType".equals(orderName)) {
|
||||
return "t.lineType";
|
||||
}
|
||||
if ("signupTime".equals(orderName)) {
|
||||
return "t.signupTime";
|
||||
}
|
||||
if ("familyCount".equals(orderName)) {
|
||||
return "familyCount";
|
||||
}
|
||||
if ("joined".equals(orderName)) {
|
||||
return "t.joined";
|
||||
}
|
||||
return "t.`year`";
|
||||
}
|
||||
|
||||
private String getTravelPeriod(TourLedger ledger) {
|
||||
if (ledger == null || ledger.getYear() == null || StrUtil.isBlank(ledger.getLineId())) {
|
||||
return "";
|
||||
}
|
||||
if (StrUtil.isNotBlank(ledger.getMatterId())) {
|
||||
Sql exactSql = Sqls.create("""
|
||||
SELECT CASE
|
||||
WHEN IFNULL(travelStartTime, '') <> '' AND IFNULL(travelEndTime, '') <> ''
|
||||
THEN CONCAT(travelStartTime, ' 至 ', travelEndTime)
|
||||
ELSE ''
|
||||
END AS travelPeriod
|
||||
FROM tour_matter
|
||||
WHERE delFlag = 0
|
||||
AND id = @matterId
|
||||
""");
|
||||
exactSql.setParam("matterId", ledger.getMatterId());
|
||||
exactSql.setCallback(Sqls.callback.str());
|
||||
tourLedgerService.dao().execute(exactSql);
|
||||
return exactSql.getString();
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT GROUP_CONCAT(
|
||||
DISTINCT CASE
|
||||
WHEN IFNULL(travelStartTime, '') <> '' AND IFNULL(travelEndTime, '') <> ''
|
||||
THEN CONCAT(travelStartTime, ' 至 ', travelEndTime)
|
||||
ELSE NULL
|
||||
END
|
||||
ORDER BY travelStartTime ASC
|
||||
SEPARATOR ';'
|
||||
) AS travelPeriod
|
||||
FROM tour_matter
|
||||
WHERE delFlag = 0
|
||||
AND `year` = @year
|
||||
AND lineId = @lineId
|
||||
""");
|
||||
sql.setParam("year", ledger.getYear());
|
||||
sql.setParam("lineId", ledger.getLineId());
|
||||
sql.setCallback(Sqls.callback.str());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return sql.getString();
|
||||
}
|
||||
|
||||
private boolean isDirectFamilyUnitLine(TourLedger ledger) {
|
||||
if (ledger == null || StrUtil.isBlank(ledger.getLineId())) {
|
||||
return false;
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT IFNULL(directFamilyUnitLine, 0)
|
||||
FROM tour_line
|
||||
WHERE delFlag = 0
|
||||
AND id = @lineId
|
||||
""");
|
||||
sql.setParam("lineId", ledger.getLineId());
|
||||
sql.setCallback(Sqls.callback.integer());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return sql.getInt() > 0;
|
||||
}
|
||||
|
||||
private boolean isFillBedInfo(TourLedger ledger) {
|
||||
if (ledger == null || StrUtil.isBlank(ledger.getMatterId())) {
|
||||
return true;
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT IFNULL(MAX(s.fillBedInfo), 1)
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_setting s ON s.id = m.settingId AND s.delFlag = 0
|
||||
WHERE t.id = @ledgerId
|
||||
""");
|
||||
sql.setParam("ledgerId", ledger.getId());
|
||||
sql.setCallback(Sqls.callback.integer());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return sql.getInt() > 0;
|
||||
}
|
||||
|
||||
private void appendTravelPeriodFilter(Cnd cnd, String travelPeriod) {
|
||||
if (StrUtil.isBlank(travelPeriod)) {
|
||||
return;
|
||||
}
|
||||
cnd.and("CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime)", "=", travelPeriod);
|
||||
}
|
||||
|
||||
private void appendLineFilter(Cnd cnd, String lineId) {
|
||||
if (StrUtil.isBlank(lineId)) {
|
||||
return;
|
||||
}
|
||||
if (lineId.startsWith("legacy:")) {
|
||||
SqlExpressionGroup legacyGroup = new SqlExpressionGroup();
|
||||
legacyGroup.or("t.lineId", "IS", null);
|
||||
legacyGroup.or("t.lineId", "=", "");
|
||||
cnd.and(legacyGroup);
|
||||
cnd.and("t.lineName", "=", lineId.substring("legacy:".length()));
|
||||
return;
|
||||
}
|
||||
cnd.and("t.lineId", "=", lineId);
|
||||
}
|
||||
|
||||
private String getCurrentLineName(TourLedger ledger) {
|
||||
if (ledger == null) {
|
||||
return "";
|
||||
}
|
||||
if (StrUtil.isBlank(ledger.getLineId())) {
|
||||
return ledger.getLineName();
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT lineName
|
||||
FROM tour_line
|
||||
WHERE delFlag = 0
|
||||
AND id = @lineId
|
||||
""");
|
||||
sql.setParam("lineId", ledger.getLineId());
|
||||
sql.setCallback(Sqls.callback.str());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return StrUtil.blankToDefault(sql.getString(), ledger.getLineName());
|
||||
}
|
||||
}
|
||||
+297
@@ -0,0 +1,297 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
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.sys.models.Sys_dict;
|
||||
import com.budwk.app.sys.services.SysDictService;
|
||||
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.dayofficework.tour.models.TourLine;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourTravelAgency;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLineService;
|
||||
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.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.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@IocBean
|
||||
@Ok("json:full")
|
||||
@At("/platform/tour/route")
|
||||
public class TourLineController {
|
||||
|
||||
@Inject
|
||||
private TourLineService tourLineService;
|
||||
|
||||
@Inject
|
||||
private SysDictService sysDictService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/Tour/route/index.html")
|
||||
@SaCheckPermission("tour.route")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.route")
|
||||
public Result pageData(PageForm pageForm, Integer year, String lineName, String lotId) {
|
||||
if (StrUtil.isBlank(pageForm.getPageOrderName())) {
|
||||
pageForm.defaultSortDesc("enabled");
|
||||
}
|
||||
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("l.delFlag", "=", false);
|
||||
cnd.andEX("l.`year`", "=", year);
|
||||
cnd.and(Cnd.likeEX("l.lineName", lineName));
|
||||
cnd.andEX("l.lotId", "=", lotId);
|
||||
boolean sysAdmin = AuthUtil.hasRole(RoleConstant.SYSADMIN.name());
|
||||
boolean branchUnionScope = !sysAdmin && AuthUtil.hasRole(RoleConstant.BRANCH_UNION_CHAIRMAN.name());
|
||||
applyDataScope(cnd, sysAdmin, branchUnionScope);
|
||||
String creatorJoin = branchUnionScope ? """
|
||||
LEFT JOIN sys_unit lineUnit ON lineUnit.id = l.unitId
|
||||
LEFT JOIN sys_user creatorUser ON creatorUser.id = COALESCE(NULLIF(l.creatorUserId, ''), l.createdBy)
|
||||
LEFT JOIN sys_unit creatorUnit ON creatorUnit.id = creatorUser.unitId
|
||||
""" : "";
|
||||
|
||||
Sql countSql = Sqls.create("""
|
||||
SELECT COUNT(1)
|
||||
FROM tour_line l
|
||||
$creatorJoin
|
||||
$condition
|
||||
""");
|
||||
countSql.setVar("creatorJoin", creatorJoin);
|
||||
countSql.setCondition(cnd);
|
||||
countSql.setCallback(Sqls.callback.integer());
|
||||
tourLineService.dao().execute(countSql);
|
||||
int count = countSql.getInt();
|
||||
|
||||
Sql listSql = Sqls.create("""
|
||||
SELECT
|
||||
l.*,
|
||||
a.agencyName AS travelAgencyName,
|
||||
lot.lotName AS lotName
|
||||
FROM tour_line l
|
||||
LEFT JOIN tour_travel_agency a ON a.id = l.travelAgencyId
|
||||
LEFT JOIN tour_setting_lot lot ON lot.id = l.lotId
|
||||
$creatorJoin
|
||||
$condition
|
||||
ORDER BY $orderColumn $orderBy, l.`year` DESC, l.lineCode ASC, l.createdAt DESC
|
||||
""");
|
||||
listSql.setVar("creatorJoin", creatorJoin);
|
||||
listSql.setCondition(cnd);
|
||||
listSql.setVar("orderColumn", getOrderColumn(pageForm.getPageOrderName()));
|
||||
listSql.setVar("orderBy", "descending".equals(pageForm.getPageOrderBy()) ? "desc" : "asc");
|
||||
listSql.setPager(tourLineService.dao().createPager(pageForm.getPageNumber(), pageForm.getPageSize()));
|
||||
listSql.setCallback(Sqls.callback.maps());
|
||||
tourLineService.dao().execute(listSql);
|
||||
|
||||
Pagination<NutMap> pagination = new Pagination<>(pageForm.getPageNumber(), pageForm.getPageSize(), count, listSql.getList(NutMap.class));
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.route")
|
||||
public Result detail(String id) {
|
||||
if (StrUtil.isBlank(id)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
TourLine line = tourLineService.fetch(id);
|
||||
return line == null ? Result.error("线路不存在") : Result.success(line);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.route")
|
||||
public Result travelAgencyOptions(Integer year) {
|
||||
Cnd cnd = Cnd.where(TourTravelAgency::getEnabled, "=", true);
|
||||
cnd.andEX(TourTravelAgency::getYear, "=", year);
|
||||
cnd.asc(TourTravelAgency::getAgencyCode).asc(TourTravelAgency::getAgencyName);
|
||||
return Result.success(tourLineService.dao().query(TourTravelAgency.class, cnd));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.route")
|
||||
public Result lotOptions(Integer year) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX("s.`year`", "=", year);
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT lot.id, lot.lotName, lot.lotValue, lot.activityCost
|
||||
FROM tour_setting_lot lot
|
||||
INNER JOIN tour_setting s ON s.id = lot.settingId
|
||||
$condition
|
||||
ORDER BY lot.lotValue DESC, lot.lotName ASC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourLineService.dao().execute(sql);
|
||||
return Result.success(sql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.route")
|
||||
public Result lineTypeOptions() {
|
||||
List<Sys_dict> list = sysDictService.getSubListByCode("lineType");
|
||||
if (list == null) {
|
||||
return Result.success(Collections.emptyList());
|
||||
}
|
||||
return Result.success(list.stream().filter(item -> !item.isDisabled()).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("tour.route")
|
||||
@SLog(type = "tour", tag = "线路管理", msg = "保存线路信息")
|
||||
public Result doSubmit(TourLine line) {
|
||||
Result checkResult = check(line);
|
||||
if (checkResult != null) {
|
||||
return checkResult;
|
||||
}
|
||||
|
||||
Cnd sameCodeCnd = Cnd.where(TourLine::getYear, "=", line.getYear())
|
||||
.and(TourLine::getLineCode, "=", line.getLineCode());
|
||||
if (StrUtil.isNotBlank(line.getId())) {
|
||||
sameCodeCnd.and(TourLine::getId, "<>", line.getId());
|
||||
}
|
||||
if (tourLineService.count(sameCodeCnd) > 0) {
|
||||
return Result.error("同年度下线路编号已存在");
|
||||
}
|
||||
if (line.getEnabled() == null) {
|
||||
line.setEnabled(true);
|
||||
}
|
||||
if (line.getOpenFlag() == null) {
|
||||
line.setOpenFlag(true);
|
||||
}
|
||||
if (line.getDirectFamilyUnitLine() == null) {
|
||||
line.setDirectFamilyUnitLine(false);
|
||||
}
|
||||
if (StrUtil.isBlank(line.getId())) {
|
||||
fillCreatorInfo(line, null);
|
||||
tourLineService.insert(line);
|
||||
} else {
|
||||
fillCreatorInfo(line, tourLineService.fetch(line.getId()));
|
||||
tourLineService.updateIgnoreNull(line);
|
||||
}
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("tour.route")
|
||||
@SLog(type = "tour", tag = "线路管理", msg = "删除线路信息")
|
||||
public Result doDelete(String id) {
|
||||
if (StrUtil.isBlank(id)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
tourLineService.delete(id);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
private Result check(TourLine line) {
|
||||
if (line == null) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
if (line.getYear() == null) {
|
||||
return Result.error("创建年度不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(line.getTravelAgencyId())) {
|
||||
return Result.error("旅行社名称不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(line.getLineName())) {
|
||||
return Result.error("线路名称不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(line.getLineCode())) {
|
||||
return Result.error("线路编号不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(line.getLineType())) {
|
||||
return Result.error("线路类型不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(line.getLotId())) {
|
||||
return Result.error("时间标段不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(line.getMobileThumb())) {
|
||||
return Result.error("移动端缩略图不能为空");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建人和所在单位由当前登录人生成,编辑时保留原创建信息。
|
||||
*/
|
||||
private void fillCreatorInfo(TourLine line, TourLine oldLine) {
|
||||
if (oldLine != null) {
|
||||
line.setCreatorUserId(defaultIfBlank(oldLine.getCreatorUserId(), SecurityUtil.getUserId()));
|
||||
line.setCreatorName(defaultIfBlank(oldLine.getCreatorName(), SecurityUtil.getUserUsername()));
|
||||
line.setUnitId(defaultIfBlank(oldLine.getUnitId(), SecurityUtil.getUnitId()));
|
||||
line.setUnitName(defaultIfBlank(oldLine.getUnitName(), getCurrentUnitName()));
|
||||
return;
|
||||
}
|
||||
line.setCreatorUserId(SecurityUtil.getUserId());
|
||||
line.setCreatorName(SecurityUtil.getUserUsername());
|
||||
line.setUnitId(SecurityUtil.getUnitId());
|
||||
line.setUnitName(getCurrentUnitName());
|
||||
}
|
||||
|
||||
private String getCurrentUnitName() {
|
||||
View_user user = tourLineService.dao().fetch(View_user.class, Cnd.where("id", "=", SecurityUtil.getUserId()));
|
||||
return user == null ? "" : defaultIfBlank(user.getUnitName(), "");
|
||||
}
|
||||
|
||||
private String defaultIfBlank(String value, String defaultValue) {
|
||||
return StrUtil.isBlank(value) ? defaultValue : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 线路数据范围:
|
||||
* SYSADMIN 可查看全部;分工会主席查看本工会创建的线路;其它角色保持原逻辑,仅查看自己创建的线路。
|
||||
*/
|
||||
private void applyDataScope(Cnd cnd, boolean sysAdmin, boolean branchUnionScope) {
|
||||
if (sysAdmin) {
|
||||
return;
|
||||
}
|
||||
if (branchUnionScope) {
|
||||
SqlExpressionGroup unionGroup = new SqlExpressionGroup();
|
||||
unionGroup.or("lineUnit.unionId", "=", SecurityUtil.getUnionId());
|
||||
unionGroup.or("creatorUnit.unionId", "=", SecurityUtil.getUnionId());
|
||||
cnd.and(unionGroup);
|
||||
return;
|
||||
}
|
||||
SqlExpressionGroup creatorGroup = new SqlExpressionGroup();
|
||||
creatorGroup.or("l.creatorUserId", "=", SecurityUtil.getUserId());
|
||||
creatorGroup.or("l.createdBy", "=", SecurityUtil.getUserId());
|
||||
cnd.and(creatorGroup);
|
||||
}
|
||||
|
||||
private String getOrderColumn(String orderName) {
|
||||
if ("year".equals(orderName)) {
|
||||
return "l.`year`";
|
||||
}
|
||||
if ("lineCode".equals(orderName)) {
|
||||
return "l.lineCode";
|
||||
}
|
||||
if ("lotName".equals(orderName)) {
|
||||
return "lot.lotName";
|
||||
}
|
||||
if ("lineType".equals(orderName)) {
|
||||
return "l.lineType";
|
||||
}
|
||||
if ("enabled".equals(orderName)) {
|
||||
return "l.enabled";
|
||||
}
|
||||
return "l.`year`";
|
||||
}
|
||||
}
|
||||
+441
@@ -0,0 +1,441 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
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.sys.models.Sys_dict;
|
||||
import com.budwk.app.sys.models.Sys_union;
|
||||
import com.budwk.app.sys.services.SysDictService;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedger;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourMatter;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourSetting;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourMatterService;
|
||||
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.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.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@IocBean
|
||||
@Ok("json:full")
|
||||
@At("/platform/tour/matter")
|
||||
public class TourMatterController {
|
||||
|
||||
private static final String MOBILE_PATTERN = "^1[3-9]\\d{9}$";
|
||||
|
||||
@Inject
|
||||
private TourMatterService tourMatterService;
|
||||
|
||||
@Inject
|
||||
private SysDictService sysDictService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/Tour/matter/index.html")
|
||||
@SaCheckPermission("tour.matter")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.matter")
|
||||
public Result pageData(PageForm pageForm, Integer year, String matterName, String unionId, String organizationType) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("m.delFlag", "=", false);
|
||||
cnd.andEX("m.`year`", "=", year);
|
||||
cnd.and(Cnd.likeEX("m.matterName", matterName));
|
||||
cnd.andEX("m.unionId", "=", unionId);
|
||||
cnd.andEX("m.organizationType", "=", organizationType);
|
||||
applyMatterDataScope(cnd);
|
||||
|
||||
Sql countSql = Sqls.create("""
|
||||
SELECT COUNT(1)
|
||||
FROM tour_matter m
|
||||
$condition
|
||||
""");
|
||||
countSql.setCondition(cnd);
|
||||
countSql.setCallback(Sqls.callback.integer());
|
||||
tourMatterService.dao().execute(countSql);
|
||||
int count = countSql.getInt();
|
||||
|
||||
Sql listSql = Sqls.create("""
|
||||
SELECT
|
||||
m.*,
|
||||
s.configName AS settingName,
|
||||
u.name AS unionName,
|
||||
d.name AS organizationTypeName,
|
||||
l.lineName AS lineName,
|
||||
l.lineType AS lineType,
|
||||
l.directFamilyUnitLine AS directFamilyUnitLine
|
||||
FROM tour_matter m
|
||||
LEFT JOIN tour_setting s ON s.id = m.settingId
|
||||
LEFT JOIN sys_union u ON u.id = m.unionId
|
||||
LEFT JOIN tour_line l ON l.id = m.lineId
|
||||
LEFT JOIN sys_dict d ON d.`code` = m.organizationType
|
||||
AND d.parentId = (SELECT id FROM sys_dict WHERE `code` = 'organizationType' LIMIT 1)
|
||||
$condition
|
||||
ORDER BY $orderColumn $orderBy, m.`year` DESC, m.createdAt DESC
|
||||
""");
|
||||
listSql.setCondition(cnd);
|
||||
listSql.setVar("orderColumn", getOrderColumn(pageForm.getPageOrderName()));
|
||||
listSql.setVar("orderBy", "descending".equals(pageForm.getPageOrderBy()) ? "desc" : "asc");
|
||||
listSql.setPager(tourMatterService.dao().createPager(pageForm.getPageNumber(), pageForm.getPageSize()));
|
||||
listSql.setCallback(Sqls.callback.maps());
|
||||
tourMatterService.dao().execute(listSql);
|
||||
|
||||
Pagination<NutMap> pagination = new Pagination<>(pageForm.getPageNumber(), pageForm.getPageSize(), count, listSql.getList(NutMap.class));
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.matter")
|
||||
public Result detail(String id) {
|
||||
if (StrUtil.isBlank(id)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
TourMatter matter = tourMatterService.fetch(id);
|
||||
return matter == null ? Result.error("事项不存在") : Result.success(matter);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.matter")
|
||||
public Result settingOptions(Integer year) {
|
||||
Cnd cnd = Cnd.where(TourSetting::getEnabled, "=", true);
|
||||
cnd.andEX(TourSetting::getYear, "=", year);
|
||||
cnd.desc(TourSetting::getCreatedAt);
|
||||
cnd.desc(TourSetting::getUpdatedAt);
|
||||
cnd.asc(TourSetting::getConfigName);
|
||||
return Result.success(tourMatterService.dao().query(TourSetting.class, cnd));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.matter")
|
||||
public Result unionOptions() {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.asc("unionCode");
|
||||
cnd.asc("name");
|
||||
return Result.success(tourMatterService.dao().query(Sys_union.class, cnd));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.matter")
|
||||
public Result lineOptions(Integer year) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("l.delFlag", "=", false);
|
||||
cnd.and("l.enabled", "=", true);
|
||||
cnd.and("l.openFlag", "=", true);
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
l.*,
|
||||
lot.lotName AS lotName,
|
||||
lot.lotValue AS lotValue,
|
||||
lot.lotValue AS lotDays,
|
||||
lot.activityCost AS activityCost
|
||||
FROM tour_line l
|
||||
LEFT JOIN tour_setting_lot lot ON lot.id = l.lotId
|
||||
$condition
|
||||
ORDER BY l.lineCode ASC, l.lineName ASC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourMatterService.dao().execute(sql);
|
||||
return Result.success(sql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.matter")
|
||||
public Result organizationTypeOptions() {
|
||||
List<Sys_dict> list = sysDictService.getSubListByCode("organizationType");
|
||||
if (list == null) {
|
||||
return Result.success(Collections.emptyList());
|
||||
}
|
||||
return Result.success(list.stream().filter(item -> !item.isDisabled()).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("tour.matter")
|
||||
@SLog(type = "tour", tag = "疗休养事项", msg = "保存疗休养事项")
|
||||
public Result doSubmit(TourMatter matter) {
|
||||
Result checkResult = check(matter);
|
||||
if (checkResult != null) {
|
||||
return checkResult;
|
||||
}
|
||||
|
||||
Cnd sameNameCnd = Cnd.where(TourMatter::getYear, "=", matter.getYear())
|
||||
.and(TourMatter::getMatterName, "=", matter.getMatterName());
|
||||
if (StrUtil.isNotBlank(matter.getId())) {
|
||||
sameNameCnd.and(TourMatter::getId, "<>", matter.getId());
|
||||
}
|
||||
if (tourMatterService.count(sameNameCnd) > 0) {
|
||||
return Result.error("同年度下事项名称已存在");
|
||||
}
|
||||
if (matter.getEnabled() == null) {
|
||||
matter.setEnabled(true);
|
||||
}
|
||||
fillCreatorAndUnion(matter);
|
||||
if (StrUtil.isBlank(matter.getId())) {
|
||||
tourMatterService.insert(matter);
|
||||
} else {
|
||||
tourMatterService.updateIgnoreNull(matter);
|
||||
}
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("tour.matter")
|
||||
@SLog(type = "tour", tag = "疗休养事项", msg = "删除疗休养事项")
|
||||
public Result doDelete(String id) {
|
||||
if (StrUtil.isBlank(id)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
TourMatter matter = tourMatterService.fetch(id);
|
||||
if (matter == null) {
|
||||
return Result.error("事项不存在");
|
||||
}
|
||||
long signupCount = countSignup(id);
|
||||
if (signupCount > 0) {
|
||||
return Result.error("当前事项对应线路已有人员报名,不能删除");
|
||||
}
|
||||
tourMatterService.delete(id);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.matter")
|
||||
public Result deleteInfo(String id) {
|
||||
if (StrUtil.isBlank(id)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
TourMatter matter = tourMatterService.fetch(id);
|
||||
if (matter == null) {
|
||||
return Result.error("事项不存在");
|
||||
}
|
||||
long signupCount = countSignup(id);
|
||||
return Result.success(NutMap.NEW()
|
||||
.addv("signupCount", signupCount)
|
||||
.addv("canDelete", signupCount <= 0)
|
||||
.addv("message", signupCount > 0 ? "当前事项已有人员报名,不能删除" : "当前事项暂无人员报名,可删除"));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.matter")
|
||||
public Result lineConfig(String matterId) {
|
||||
if (StrUtil.isBlank(matterId)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
TourMatter matter = tourMatterService.fetch(matterId);
|
||||
return matter == null ? Result.error("事项不存在") : Result.success(matter);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.matter")
|
||||
public Result settingPeople(String matterId) {
|
||||
if (StrUtil.isBlank(matterId)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
TourMatter matter = tourMatterService.fetch(matterId);
|
||||
if (matter == null || StrUtil.isBlank(matter.getSettingId())) {
|
||||
return Result.success(NutMap.NEW());
|
||||
}
|
||||
TourSetting setting = tourMatterService.dao().fetch(TourSetting.class, matter.getSettingId());
|
||||
if (setting == null) {
|
||||
return Result.success(NutMap.NEW());
|
||||
}
|
||||
return Result.success(NutMap.NEW()
|
||||
.addv("minGroupPeople", setting.getMinGroupPeople())
|
||||
.addv("maxGroupPeople", setting.getMaxGroupPeople()));
|
||||
}
|
||||
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("tour.matter")
|
||||
@SLog(type = "tour", tag = "疗休养事项", msg = "保存事项线路配置")
|
||||
public Result lineConfigDoSubmit(TourMatter matter) {
|
||||
Result checkResult = checkLineConfig(matter);
|
||||
if (checkResult != null) {
|
||||
return checkResult;
|
||||
}
|
||||
TourMatter oldMatter = tourMatterService.fetch(matter.getId());
|
||||
if (oldMatter == null) {
|
||||
return Result.error("事项不存在");
|
||||
}
|
||||
oldMatter.setLineId(matter.getLineId());
|
||||
oldMatter.setSignupStartTime(matter.getSignupStartTime());
|
||||
oldMatter.setSignupEndTime(matter.getSignupEndTime());
|
||||
oldMatter.setTravelStartTime(matter.getTravelStartTime());
|
||||
oldMatter.setTravelEndTime(matter.getTravelEndTime());
|
||||
oldMatter.setContactName(matter.getContactName());
|
||||
oldMatter.setContactPhone(matter.getContactPhone());
|
||||
oldMatter.setMinGroupPeople(matter.getMinGroupPeople());
|
||||
oldMatter.setMaxGroupPeople(matter.getMaxGroupPeople());
|
||||
oldMatter.setEstimatedCost(matter.getEstimatedCost());
|
||||
tourMatterService.update(oldMatter);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
private Result check(TourMatter matter) {
|
||||
if (matter == null) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
if (matter.getYear() == null) {
|
||||
return Result.error("年度不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(matter.getMatterName())) {
|
||||
return Result.error("事项名称不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(matter.getSettingId())) {
|
||||
return Result.error("疗休养配置不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(matter.getOrganizationType())) {
|
||||
return Result.error("组织形式不能为空");
|
||||
}
|
||||
if (!"schoolUnion".equals(matter.getOrganizationType()) && StrUtil.isBlank(matter.getUnionId())) {
|
||||
return Result.error("所属工会不能为空");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Result checkLineConfig(TourMatter matter) {
|
||||
if (matter == null) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
if (StrUtil.isBlank(matter.getId())) {
|
||||
return Result.error("事项不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(matter.getLineId())) {
|
||||
return Result.error("线路不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(matter.getSignupStartTime()) || StrUtil.isBlank(matter.getSignupEndTime())
|
||||
|| StrUtil.isBlank(matter.getTravelStartTime()) || StrUtil.isBlank(matter.getTravelEndTime())) {
|
||||
return Result.error("时间不能为空");
|
||||
}
|
||||
if (matter.getSignupStartTime().compareTo(matter.getSignupEndTime()) >= 0) {
|
||||
return Result.error("报名开始时间必须小于报名结束时间");
|
||||
}
|
||||
if (matter.getTravelStartTime().compareTo(matter.getTravelEndTime()) > 0) {
|
||||
return Result.error("出行开始时间不能晚于出行结束时间");
|
||||
}
|
||||
if (matter.getSignupEndTime().compareTo(matter.getTravelStartTime()) >= 0) {
|
||||
return Result.error("报名结束时间必须小于出行开始时间");
|
||||
}
|
||||
if (StrUtil.isBlank(matter.getContactName())) {
|
||||
return Result.error("联系人不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(matter.getContactPhone()) || !matter.getContactPhone().matches(MOBILE_PATTERN)) {
|
||||
return Result.error("联系方式格式不正确");
|
||||
}
|
||||
if (matter.getMinGroupPeople() == null || matter.getMinGroupPeople() <= 0) {
|
||||
return Result.error("最少成团人数必须大于0");
|
||||
}
|
||||
if (matter.getMaxGroupPeople() == null || matter.getMaxGroupPeople() <= 0) {
|
||||
return Result.error("最多成团人数必须大于0");
|
||||
}
|
||||
if (matter.getMinGroupPeople() > matter.getMaxGroupPeople()) {
|
||||
return Result.error("最少成团人数不能大于最多成团人数");
|
||||
}
|
||||
if (matter.getEstimatedCost() == null || matter.getEstimatedCost().signum() < 0) {
|
||||
return Result.error("预计费用不能小于0");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void fillCreatorAndUnion(TourMatter matter) {
|
||||
if (StrUtil.isBlank(matter.getId())) {
|
||||
matter.setCreatorUserId(SecurityUtil.getUserId());
|
||||
matter.setCreatorName(SecurityUtil.getUserUsername());
|
||||
} else {
|
||||
TourMatter oldMatter = tourMatterService.fetch(matter.getId());
|
||||
if (oldMatter != null) {
|
||||
matter.setCreatorUserId(oldMatter.getCreatorUserId());
|
||||
matter.setCreatorName(oldMatter.getCreatorName());
|
||||
}
|
||||
}
|
||||
if ("schoolUnion".equals(matter.getOrganizationType())) {
|
||||
matter.setUnionId("");
|
||||
}
|
||||
}
|
||||
|
||||
private long countSignup(String matterId) {
|
||||
return tourMatterService.dao().count(TourLedger.class, Cnd.where(TourLedger::getDelFlag, "=", false)
|
||||
.and(TourLedger::getMatterId, "=", matterId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 事项数据范围:SYSADMIN 查看全部;分工会主席查看本工会事项;其它角色仅查看自己创建的事项。
|
||||
*/
|
||||
private void applyMatterDataScope(Cnd cnd) {
|
||||
if (AuthUtil.hasRole(RoleConstant.SYSADMIN.name())) {
|
||||
return;
|
||||
}
|
||||
if (AuthUtil.hasRole(RoleConstant.BRANCH_UNION_CHAIRMAN.name())) {
|
||||
cnd.and("m.unionId", "=", SecurityUtil.getUnionId());
|
||||
return;
|
||||
}
|
||||
SqlExpressionGroup creatorGroup = new SqlExpressionGroup();
|
||||
creatorGroup.or("m.creatorUserId", "=", SecurityUtil.getUserId());
|
||||
creatorGroup.or("m.createdBy", "=", SecurityUtil.getUserId());
|
||||
cnd.and(creatorGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* 事项批次选择线路时沿用线路管理的数据范围,避免在事项页面选到权限外线路。
|
||||
*/
|
||||
private void applyLineDataScope(Cnd cnd, boolean sysAdmin, boolean branchUnionScope) {
|
||||
if (sysAdmin) {
|
||||
return;
|
||||
}
|
||||
if (branchUnionScope) {
|
||||
SqlExpressionGroup unionGroup = new SqlExpressionGroup();
|
||||
unionGroup.or("lineUnit.unionId", "=", SecurityUtil.getUnionId());
|
||||
unionGroup.or("creatorUnit.unionId", "=", SecurityUtil.getUnionId());
|
||||
cnd.and(unionGroup);
|
||||
return;
|
||||
}
|
||||
SqlExpressionGroup creatorGroup = new SqlExpressionGroup();
|
||||
creatorGroup.or("l.creatorUserId", "=", SecurityUtil.getUserId());
|
||||
creatorGroup.or("l.createdBy", "=", SecurityUtil.getUserId());
|
||||
cnd.and(creatorGroup);
|
||||
}
|
||||
|
||||
private String getOrderColumn(String orderName) {
|
||||
if ("year".equals(orderName)) {
|
||||
return "m.`year`";
|
||||
}
|
||||
if ("matterName".equals(orderName)) {
|
||||
return "m.matterName";
|
||||
}
|
||||
if ("unionName".equals(orderName)) {
|
||||
return "u.name";
|
||||
}
|
||||
if ("lineName".equals(orderName)) {
|
||||
return "l.lineName";
|
||||
}
|
||||
if ("settingName".equals(orderName)) {
|
||||
return "s.configName";
|
||||
}
|
||||
if ("organizationTypeName".equals(orderName)) {
|
||||
return "d.location";
|
||||
}
|
||||
if ("enabled".equals(orderName)) {
|
||||
return "m.enabled";
|
||||
}
|
||||
return "m.`year`";
|
||||
}
|
||||
}
|
||||
+1846
File diff suppressed because it is too large
Load Diff
+13
@@ -0,0 +1,13 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.controller;
|
||||
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
|
||||
/**
|
||||
* 分阶段建设的菜单占位入口。
|
||||
*/
|
||||
@IocBean
|
||||
@At("/platform/tour")
|
||||
public class TourPlaceholderController {
|
||||
|
||||
}
|
||||
+581
@@ -0,0 +1,581 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
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.flow.enums.ProcessTaskStateEnum;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedger;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedgerDirectRelative;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedgerFamily;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerDirectRelativeService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerFamilyService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerService;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@IocBean
|
||||
@Ok("json:full")
|
||||
@At("/platform/tour/schoolUnionApproval")
|
||||
public class TourSchoolUnionApprovalController {
|
||||
|
||||
private static final String WORKFLOW_KEY = "LXYBZXQSXL";
|
||||
private static final String TASK_DISPLAY_NAME = "校工会审核";
|
||||
|
||||
@Inject
|
||||
private TourLedgerService tourLedgerService;
|
||||
|
||||
@Inject
|
||||
private TourLedgerFamilyService tourLedgerFamilyService;
|
||||
|
||||
@Inject
|
||||
private TourLedgerDirectRelativeService tourLedgerDirectRelativeService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/Tour/schoolUnionApproval/index.html")
|
||||
@SaCheckPermission(value = {"tour.schoolUnionApproval", "h5.tour.schoolUnionApproval"}, mode = SaMode.OR)
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At("/h5")
|
||||
@Ok("beetl:/platform/zhghh5/dayofficework/tour/schoolUnionApproval/index.html")
|
||||
@SaCheckPermission(value = {"tour.schoolUnionApproval", "h5.tour.schoolUnionApproval"}, mode = SaMode.OR)
|
||||
public void h5() {
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission(value = {"tour.schoolUnionApproval", "h5.tour.schoolUnionApproval"}, mode = SaMode.OR)
|
||||
public Result pageData(PageForm pageForm, Boolean audit, Integer startYear, Integer endYear, String keyword, String unionId, String lineId, String travelPeriod, String lineType) {
|
||||
Cnd cnd = buildAuditCnd(audit, startYear, endYear, keyword, unionId, lineId, travelPeriod, lineType);
|
||||
|
||||
Sql countSql = Sqls.create("""
|
||||
SELECT COUNT(DISTINCT task.id)
|
||||
FROM wf_process_task task
|
||||
LEFT JOIN wf_process_instance ins ON ins.id = task.processInstanceId
|
||||
LEFT JOIN wf_process_define def ON def.id = ins.processDefineId
|
||||
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = task.id
|
||||
INNER JOIN tour_ledger t ON t.id = ins.businessNo
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
$condition
|
||||
""");
|
||||
countSql.setCondition(cnd);
|
||||
countSql.setCallback(Sqls.callback.integer());
|
||||
tourLedgerService.dao().execute(countSql);
|
||||
int count = countSql.getInt();
|
||||
|
||||
Sql listSql = Sqls.create("""
|
||||
SELECT
|
||||
t.*,
|
||||
ins.id AS instanceId,
|
||||
ins.businessNo,
|
||||
ins.state AS instanceState,
|
||||
ins.variable AS instanceVariable,
|
||||
ins.processDefineId AS instanceProcessDefineId,
|
||||
task.id AS taskId,
|
||||
task.taskName AS taskKey,
|
||||
task.displayName AS taskName,
|
||||
task.taskType,
|
||||
task.performType AS taskPerformType,
|
||||
task.taskState,
|
||||
task.finishTime,
|
||||
task.taskParentId,
|
||||
task.variable AS taskVariable,
|
||||
IFNULL(GROUP_CONCAT(DISTINCT nt.displayName), '结束') AS curTaskName,
|
||||
CASE
|
||||
WHEN m.id IS NULL THEN COALESCE(NULLIF(l.lineName, ''), t.lineName)
|
||||
ELSE CONCAT(
|
||||
COALESCE(NULLIF(l.lineName, ''), t.lineName),
|
||||
'(',
|
||||
CASE
|
||||
WHEN IFNULL(m.unionId, '') = '' THEN '校工会'
|
||||
ELSE IFNULL(mu.name, '')
|
||||
END,
|
||||
')'
|
||||
)
|
||||
END AS currentLineName,
|
||||
CASE
|
||||
WHEN IFNULL(m.travelStartTime, '') <> '' AND IFNULL(m.travelEndTime, '') <> ''
|
||||
THEN CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime)
|
||||
ELSE tp.travelPeriod
|
||||
END AS travelPeriod,
|
||||
IFNULL(f.familyCount, 0) AS familyCount
|
||||
FROM wf_process_task task
|
||||
LEFT JOIN wf_process_instance ins ON ins.id = task.processInstanceId
|
||||
LEFT JOIN wf_process_define def ON def.id = ins.processDefineId
|
||||
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = task.id
|
||||
INNER JOIN tour_ledger t ON t.id = ins.businessNo
|
||||
LEFT JOIN wf_process_task nt ON nt.processInstanceId = ins.id AND nt.taskState = 10
|
||||
LEFT JOIN (
|
||||
SELECT ledgerId, COUNT(1) AS familyCount
|
||||
FROM tour_ledger_family
|
||||
WHERE delFlag = 0
|
||||
GROUP BY ledgerId
|
||||
) f ON f.ledgerId = t.id
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
LEFT JOIN sys_union mu ON mu.id = m.unionId
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
`year`,
|
||||
lineId,
|
||||
GROUP_CONCAT(
|
||||
DISTINCT CASE
|
||||
WHEN IFNULL(travelStartTime, '') <> '' AND IFNULL(travelEndTime, '') <> ''
|
||||
THEN CONCAT(travelStartTime, ' 至 ', travelEndTime)
|
||||
ELSE NULL
|
||||
END
|
||||
ORDER BY travelStartTime ASC
|
||||
SEPARATOR ';'
|
||||
) AS travelPeriod
|
||||
FROM tour_matter
|
||||
WHERE delFlag = 0
|
||||
AND lineId IS NOT NULL
|
||||
AND lineId <> ''
|
||||
GROUP BY `year`, lineId
|
||||
) tp ON (t.matterId IS NULL OR t.matterId = '') AND tp.`year` = t.`year` AND tp.lineId = t.lineId
|
||||
$condition
|
||||
GROUP BY task.id
|
||||
ORDER BY $orderColumn $orderBy, task.createdAt DESC, t.signupTime DESC, t.createdAt DESC
|
||||
""");
|
||||
listSql.setCondition(cnd);
|
||||
listSql.setVar("orderColumn", getOrderColumn(pageForm.getPageOrderName()));
|
||||
listSql.setVar("orderBy", "ascending".equals(pageForm.getPageOrderBy()) ? "asc" : "desc");
|
||||
listSql.setPager(tourLedgerService.dao().createPager(pageForm.getPageNumber(), pageForm.getPageSize()));
|
||||
listSql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(listSql);
|
||||
|
||||
List<NutMap> list = listSql.getList(NutMap.class);
|
||||
list.forEach(item -> item.put("lineName", item.getString("currentLineName")));
|
||||
Pagination<NutMap> pagination = new Pagination<>(pageForm.getPageNumber(), pageForm.getPageSize(), count, list);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission(value = {"tour.schoolUnionApproval", "h5.tour.schoolUnionApproval"}, mode = SaMode.OR)
|
||||
public Result detail(String id) {
|
||||
TourLedger ledger = fetchAuditLedger(id);
|
||||
if (ledger == null) {
|
||||
return Result.error("报名记录不存在或无权查看");
|
||||
}
|
||||
ledger.setLineName(getCurrentLineName(ledger));
|
||||
Cnd familyCnd = Cnd.where(TourLedgerFamily::getLedgerId, "=", ledger.getId())
|
||||
.and(TourLedgerFamily::getDelFlag, "=", false);
|
||||
familyCnd.asc(TourLedgerFamily::getCreatedAt);
|
||||
TourLedgerDirectRelative directRelative = tourLedgerDirectRelativeService.fetch(
|
||||
Cnd.where(TourLedgerDirectRelative::getLedgerId, "=", ledger.getId())
|
||||
.and(TourLedgerDirectRelative::getDelFlag, "=", false));
|
||||
NutMap signupConfig = getSignupConfig(ledger);
|
||||
return Result.success(NutMap.NEW()
|
||||
.addv("ledger", ledger)
|
||||
.addv("travelPeriod", getTravelPeriod(ledger))
|
||||
.addv("families", tourLedgerFamilyService.query(familyCnd))
|
||||
.addv("directRelative", directRelative)
|
||||
.addv("allowFamily", signupConfig.getBoolean("allowFamily", false))
|
||||
.addv("fillBedInfo", signupConfig.getBoolean("fillBedInfo", true))
|
||||
.addv("directFamilyUnitLine", signupConfig.getBoolean("directFamilyUnitLine", false)));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission(value = {"tour.schoolUnionApproval", "h5.tour.schoolUnionApproval"}, mode = SaMode.OR)
|
||||
public Result unionOptions(Boolean audit, Integer startYear, Integer endYear, String keyword, String lineId, String travelPeriod, String lineType) {
|
||||
Cnd cnd = buildAuditCnd(audit, startYear, endYear, keyword, null, lineId, travelPeriod, lineType);
|
||||
cnd.and("t.unionId", "IS NOT", null);
|
||||
cnd.and("t.unionId", "<>", "");
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT DISTINCT
|
||||
t.unionId AS id,
|
||||
COALESCE(NULLIF(u.name, ''), t.unionName) AS name,
|
||||
u.unionCode
|
||||
FROM wf_process_task task
|
||||
LEFT JOIN wf_process_instance ins ON ins.id = task.processInstanceId
|
||||
LEFT JOIN wf_process_define def ON def.id = ins.processDefineId
|
||||
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = task.id
|
||||
INNER JOIN tour_ledger t ON t.id = ins.businessNo
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
LEFT JOIN sys_union u ON u.id = t.unionId
|
||||
$condition
|
||||
ORDER BY u.unionCode ASC, name ASC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return Result.success(sql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission(value = {"tour.schoolUnionApproval", "h5.tour.schoolUnionApproval"}, mode = SaMode.OR)
|
||||
public Result lineOptions(Boolean audit, Integer startYear, Integer endYear, String travelPeriod, String lineType, String unionId, String keyword) {
|
||||
Cnd cnd = buildAuditCnd(audit, startYear, endYear, keyword, unionId, null, travelPeriod, lineType);
|
||||
cnd.and("t.lineName", "IS NOT", null);
|
||||
cnd.and("t.lineName", "<>", "");
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT DISTINCT
|
||||
CASE
|
||||
WHEN IFNULL(t.lineId, '') <> '' THEN CONCAT(t.lineId, '|', IFNULL(m.unionId, ''))
|
||||
ELSE CONCAT('legacy:', t.lineName, '|', IFNULL(m.unionId, ''))
|
||||
END AS lineId,
|
||||
CASE
|
||||
WHEN m.id IS NULL THEN COALESCE(NULLIF(l.lineName, ''), t.lineName)
|
||||
ELSE CONCAT(
|
||||
COALESCE(NULLIF(l.lineName, ''), t.lineName),
|
||||
'(',
|
||||
CASE
|
||||
WHEN IFNULL(m.unionId, '') = '' THEN '校工会'
|
||||
ELSE IFNULL(mu.name, '')
|
||||
END,
|
||||
')'
|
||||
)
|
||||
END AS lineName
|
||||
FROM wf_process_task task
|
||||
LEFT JOIN wf_process_instance ins ON ins.id = task.processInstanceId
|
||||
LEFT JOIN wf_process_define def ON def.id = ins.processDefineId
|
||||
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = task.id
|
||||
INNER JOIN tour_ledger t ON t.id = ins.businessNo
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
LEFT JOIN sys_union mu ON mu.id = m.unionId
|
||||
$condition
|
||||
ORDER BY lineName ASC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return Result.success(sql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission(value = {"tour.schoolUnionApproval", "h5.tour.schoolUnionApproval"}, mode = SaMode.OR)
|
||||
public Result travelPeriodOptions(Boolean audit, Integer startYear, Integer endYear, String lineId, String lineType, String unionId, String keyword) {
|
||||
Cnd cnd = buildAuditCnd(audit, startYear, endYear, keyword, unionId, lineId, null, lineType);
|
||||
cnd.and("m.travelStartTime", "IS NOT", null);
|
||||
cnd.and("m.travelStartTime", "<>", "");
|
||||
cnd.and("m.travelEndTime", "IS NOT", null);
|
||||
cnd.and("m.travelEndTime", "<>", "");
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT DISTINCT CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime) AS travelPeriod
|
||||
FROM wf_process_task task
|
||||
LEFT JOIN wf_process_instance ins ON ins.id = task.processInstanceId
|
||||
LEFT JOIN wf_process_define def ON def.id = ins.processDefineId
|
||||
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = task.id
|
||||
INNER JOIN tour_ledger t ON t.id = ins.businessNo
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
$condition
|
||||
ORDER BY travelPeriod ASC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return Result.success(sql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission(value = {"tour.schoolUnionApproval", "h5.tour.schoolUnionApproval"}, mode = SaMode.OR)
|
||||
public Result lineTypeOptions(Boolean audit, Integer startYear, Integer endYear, String lineId, String travelPeriod, String unionId, String keyword) {
|
||||
Cnd cnd = buildAuditCnd(audit, startYear, endYear, keyword, unionId, lineId, travelPeriod, null);
|
||||
cnd.and("t.lineType", "IS NOT", null);
|
||||
cnd.and("t.lineType", "<>", "");
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT DISTINCT t.lineType
|
||||
FROM wf_process_task task
|
||||
LEFT JOIN wf_process_instance ins ON ins.id = task.processInstanceId
|
||||
LEFT JOIN wf_process_define def ON def.id = ins.processDefineId
|
||||
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = task.id
|
||||
INNER JOIN tour_ledger t ON t.id = ins.businessNo
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
$condition
|
||||
ORDER BY t.lineType ASC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return Result.success(sql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
private Cnd buildAuditCnd(Boolean audit, Integer startYear, Integer endYear, String keyword, String unionId, String lineId, String travelPeriod, String lineType) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("t.delFlag", "=", false);
|
||||
cnd.and("def.name", "=", WORKFLOW_KEY);
|
||||
cnd.and("task.displayName", "=", TASK_DISPLAY_NAME);
|
||||
cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
|
||||
appendAuditStateFilter(cnd, audit);
|
||||
cnd.andEX("t.`year`", ">=", startYear);
|
||||
cnd.andEX("t.`year`", "<=", endYear == null ? LocalDate.now().getYear() : endYear);
|
||||
cnd.andEX("t.unionId", "=", unionId);
|
||||
cnd.andEX("t.lineType", "=", lineType);
|
||||
appendLineFilter(cnd, lineId);
|
||||
appendTravelPeriodFilter(cnd, travelPeriod);
|
||||
appendKeywordFilter(cnd, keyword);
|
||||
return cnd;
|
||||
}
|
||||
|
||||
private void appendAuditStateFilter(Cnd cnd, Boolean audit) {
|
||||
if (Boolean.TRUE.equals(audit)) {
|
||||
cnd.and("task.taskState", "in", List.of(
|
||||
ProcessTaskStateEnum.FINISHED.getCode(),
|
||||
ProcessTaskStateEnum.WITHDRAW.getCode(),
|
||||
ProcessTaskStateEnum.INTERRUPT.getCode()));
|
||||
return;
|
||||
}
|
||||
cnd.and("task.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
|
||||
}
|
||||
|
||||
private void appendKeywordFilter(Cnd cnd, String keyword) {
|
||||
if (StrUtil.isBlank(keyword)) {
|
||||
return;
|
||||
}
|
||||
SqlExpressionGroup group = new SqlExpressionGroup();
|
||||
group.orLike("t.userName", keyword.trim());
|
||||
group.orLike("t.jobNo", keyword.trim());
|
||||
group.orLike("t.lineName", keyword.trim());
|
||||
group.orLike("l.lineName", keyword.trim());
|
||||
cnd.and(group);
|
||||
}
|
||||
|
||||
private void appendTravelPeriodFilter(Cnd cnd, String travelPeriod) {
|
||||
if (StrUtil.isBlank(travelPeriod)) {
|
||||
return;
|
||||
}
|
||||
cnd.and("CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime)", "=", travelPeriod);
|
||||
}
|
||||
|
||||
private void appendLineFilter(Cnd cnd, String lineId) {
|
||||
if (StrUtil.isBlank(lineId)) {
|
||||
return;
|
||||
}
|
||||
LineFilter lineFilter = parseLineFilter(lineId);
|
||||
if (lineFilter.getLineId().startsWith("legacy:")) {
|
||||
SqlExpressionGroup legacyGroup = new SqlExpressionGroup();
|
||||
legacyGroup.or("t.lineId", "IS", null);
|
||||
legacyGroup.or("t.lineId", "=", "");
|
||||
cnd.and(legacyGroup);
|
||||
cnd.and("t.lineName", "=", lineFilter.getLineId().substring("legacy:".length()));
|
||||
} else {
|
||||
cnd.and("t.lineId", "=", lineFilter.getLineId());
|
||||
}
|
||||
appendMatterUnionFilter(cnd, lineFilter.getUnionId());
|
||||
}
|
||||
|
||||
private LineFilter parseLineFilter(String value) {
|
||||
int delimiterIndex = value.indexOf("|");
|
||||
if (delimiterIndex < 0) {
|
||||
return new LineFilter(value, null);
|
||||
}
|
||||
return new LineFilter(value.substring(0, delimiterIndex), value.substring(delimiterIndex + 1));
|
||||
}
|
||||
|
||||
private void appendMatterUnionFilter(Cnd cnd, String unionId) {
|
||||
if (unionId == null) {
|
||||
return;
|
||||
}
|
||||
if (StrUtil.isBlank(unionId)) {
|
||||
SqlExpressionGroup group = new SqlExpressionGroup();
|
||||
group.or("m.unionId", "IS", null);
|
||||
group.or("m.unionId", "=", "");
|
||||
cnd.and(group);
|
||||
return;
|
||||
}
|
||||
cnd.and("m.unionId", "=", unionId);
|
||||
}
|
||||
|
||||
private String getOrderColumn(String orderName) {
|
||||
if ("jobNo".equals(orderName)) {
|
||||
return "t.jobNo";
|
||||
}
|
||||
if ("userName".equals(orderName)) {
|
||||
return "t.userName";
|
||||
}
|
||||
if ("lineName".equals(orderName)) {
|
||||
return """
|
||||
CASE
|
||||
WHEN m.id IS NULL THEN COALESCE(NULLIF(l.lineName, ''), t.lineName)
|
||||
ELSE CONCAT(
|
||||
COALESCE(NULLIF(l.lineName, ''), t.lineName),
|
||||
'(',
|
||||
CASE
|
||||
WHEN IFNULL(m.unionId, '') = '' THEN '校工会'
|
||||
ELSE IFNULL(mu.name, '')
|
||||
END,
|
||||
')'
|
||||
)
|
||||
END
|
||||
""";
|
||||
}
|
||||
if ("travelPeriod".equals(orderName)) {
|
||||
return "COALESCE(m.travelStartTime, tp.travelPeriod)";
|
||||
}
|
||||
if ("lineType".equals(orderName)) {
|
||||
return "t.lineType";
|
||||
}
|
||||
if ("signupTime".equals(orderName)) {
|
||||
return "t.signupTime";
|
||||
}
|
||||
if ("familyCount".equals(orderName)) {
|
||||
return "familyCount";
|
||||
}
|
||||
if ("instanceState".equals(orderName)) {
|
||||
return "ins.state";
|
||||
}
|
||||
return "task.createdAt";
|
||||
}
|
||||
|
||||
private TourLedger fetchAuditLedger(String id) {
|
||||
if (StrUtil.isBlank(id)) {
|
||||
return null;
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT COUNT(1)
|
||||
FROM wf_process_task task
|
||||
LEFT JOIN wf_process_instance ins ON ins.id = task.processInstanceId
|
||||
LEFT JOIN wf_process_define def ON def.id = ins.processDefineId
|
||||
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = task.id
|
||||
INNER JOIN tour_ledger t ON t.id = ins.businessNo
|
||||
WHERE t.delFlag = 0
|
||||
AND t.id = @id
|
||||
AND def.name = @workflowKey
|
||||
AND task.displayName = @taskDisplayName
|
||||
AND ta.actorId = @actorId
|
||||
""");
|
||||
sql.setParam("id", id);
|
||||
sql.setParam("workflowKey", WORKFLOW_KEY);
|
||||
sql.setParam("taskDisplayName", TASK_DISPLAY_NAME);
|
||||
sql.setParam("actorId", SecurityUtil.getUserId());
|
||||
sql.setCallback(Sqls.callback.integer());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return sql.getInt() > 0 ? tourLedgerService.fetch(id) : null;
|
||||
}
|
||||
|
||||
private String getCurrentLineName(TourLedger ledger) {
|
||||
if (ledger == null) {
|
||||
return "";
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT CASE
|
||||
WHEN m.id IS NULL THEN COALESCE(NULLIF(l.lineName, ''), t.lineName)
|
||||
ELSE CONCAT(
|
||||
COALESCE(NULLIF(l.lineName, ''), t.lineName),
|
||||
'(',
|
||||
CASE
|
||||
WHEN IFNULL(m.unionId, '') = '' THEN '校工会'
|
||||
ELSE IFNULL(mu.name, '')
|
||||
END,
|
||||
')'
|
||||
)
|
||||
END AS lineName
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
LEFT JOIN sys_union mu ON mu.id = m.unionId
|
||||
WHERE t.id = @ledgerId
|
||||
""");
|
||||
sql.setParam("ledgerId", ledger.getId());
|
||||
sql.setCallback(Sqls.callback.str());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return StrUtil.blankToDefault(sql.getString(), ledger.getLineName());
|
||||
}
|
||||
|
||||
private String getTravelPeriod(TourLedger ledger) {
|
||||
if (ledger == null || ledger.getYear() == null || StrUtil.isBlank(ledger.getLineId())) {
|
||||
return "";
|
||||
}
|
||||
if (StrUtil.isNotBlank(ledger.getMatterId())) {
|
||||
Sql exactSql = Sqls.create("""
|
||||
SELECT CASE
|
||||
WHEN IFNULL(travelStartTime, '') <> '' AND IFNULL(travelEndTime, '') <> ''
|
||||
THEN CONCAT(travelStartTime, ' 至 ', travelEndTime)
|
||||
ELSE ''
|
||||
END AS travelPeriod
|
||||
FROM tour_matter
|
||||
WHERE delFlag = 0
|
||||
AND id = @matterId
|
||||
""");
|
||||
exactSql.setParam("matterId", ledger.getMatterId());
|
||||
exactSql.setCallback(Sqls.callback.str());
|
||||
tourLedgerService.dao().execute(exactSql);
|
||||
return exactSql.getString();
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT GROUP_CONCAT(
|
||||
DISTINCT CASE
|
||||
WHEN IFNULL(travelStartTime, '') <> '' AND IFNULL(travelEndTime, '') <> ''
|
||||
THEN CONCAT(travelStartTime, ' 至 ', travelEndTime)
|
||||
ELSE NULL
|
||||
END
|
||||
ORDER BY travelStartTime ASC
|
||||
SEPARATOR ';'
|
||||
) AS travelPeriod
|
||||
FROM tour_matter
|
||||
WHERE delFlag = 0
|
||||
AND `year` = @year
|
||||
AND lineId = @lineId
|
||||
""");
|
||||
sql.setParam("year", ledger.getYear());
|
||||
sql.setParam("lineId", ledger.getLineId());
|
||||
sql.setCallback(Sqls.callback.str());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return sql.getString();
|
||||
}
|
||||
|
||||
private NutMap getSignupConfig(TourLedger ledger) {
|
||||
if (ledger == null || StrUtil.isBlank(ledger.getLineId())) {
|
||||
return NutMap.NEW().addv("allowFamily", false).addv("fillBedInfo", true).addv("directFamilyUnitLine", false);
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
IFNULL(s.allowFamily, 0) AS allowFamily,
|
||||
IFNULL(s.fillBedInfo, 1) AS fillBedInfo,
|
||||
IFNULL(l.directFamilyUnitLine, 0) AS directFamilyUnitLine
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_setting s ON s.id = m.settingId AND s.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
WHERE t.id = @ledgerId
|
||||
""");
|
||||
sql.setParam("ledgerId", ledger.getId());
|
||||
sql.setCallback(Sqls.callback.map());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
NutMap map = sql.getObject(NutMap.class);
|
||||
if (map == null || map.isEmpty()) {
|
||||
return NutMap.NEW().addv("allowFamily", false).addv("fillBedInfo", true).addv("directFamilyUnitLine", false);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private static class LineFilter {
|
||||
private final String lineId;
|
||||
private final String unionId;
|
||||
|
||||
private LineFilter(String lineId, String unionId) {
|
||||
this.lineId = lineId;
|
||||
this.unionId = unionId;
|
||||
}
|
||||
|
||||
private String getLineId() {
|
||||
return lineId;
|
||||
}
|
||||
|
||||
private String getUnionId() {
|
||||
return unionId;
|
||||
}
|
||||
}
|
||||
}
|
||||
+246
@@ -0,0 +1,246 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
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.result.Result;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourSetting;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourSettingLot;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourSettingService;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.json.Json;
|
||||
import org.nutz.lang.Lang;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@IocBean
|
||||
@Ok("json:full")
|
||||
@At("/platform/tour/setting")
|
||||
public class TourSettingController {
|
||||
|
||||
@Inject
|
||||
private TourSettingService tourSettingService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/Tour/setting/index.html")
|
||||
@SaCheckPermission("tour.setting")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.setting")
|
||||
public Result pageData(PageForm pageForm, Integer year, String configName) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX(TourSetting::getYear, "=", year);
|
||||
cnd.and(Cnd.likeEX(TourSetting::getConfigName, configName));
|
||||
|
||||
cnd.desc(TourSetting::getYear).asc(TourSetting::getSortNo).desc(TourSetting::getCreatedAt);
|
||||
Pagination<TourSetting> pagination = tourSettingService.listPage(
|
||||
pageForm.getPageNumber(),
|
||||
pageForm.getPageSize(),
|
||||
TourSetting.class,
|
||||
cnd
|
||||
);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.setting")
|
||||
public Result detail(String id) {
|
||||
if (StrUtil.isBlank(id)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
TourSetting tourSetting = tourSettingService.fetch(id);
|
||||
if (tourSetting == null) {
|
||||
return Result.error("配置不存在");
|
||||
}
|
||||
// 编辑页面需要一起带出标段,按标段值倒序保持与老疗休养配置一致。
|
||||
Cnd lotCnd = Cnd.NEW();
|
||||
lotCnd.desc(TourSettingLot::getLotValue);
|
||||
tourSettingService.dao().fetchLinks(tourSetting, "lots", lotCnd);
|
||||
return Result.success(tourSetting);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.setting")
|
||||
public Result previousYearInfo(Integer year) {
|
||||
if (year == null) {
|
||||
return Result.error("请先选择年度");
|
||||
}
|
||||
List<TourSetting> settings = tourSettingService.query(Cnd.where(TourSetting::getYear, "=", year - 1)
|
||||
.and(TourSetting::getDelFlag, "=", false)
|
||||
.desc(TourSetting::getUpdatedAt)
|
||||
.desc(TourSetting::getCreatedAt));
|
||||
if (Lang.isEmpty(settings)) {
|
||||
return Result.error("未找到上一年度配置");
|
||||
}
|
||||
TourSetting tourSetting = settings.get(0);
|
||||
Cnd lotCnd = Cnd.NEW();
|
||||
lotCnd.desc(TourSettingLot::getLotValue);
|
||||
tourSettingService.dao().fetchLinks(tourSetting, "lots", lotCnd);
|
||||
return Result.success(tourSetting);
|
||||
}
|
||||
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("tour.setting")
|
||||
@SLog(type = "tour", tag = "疗休养设置", msg = "保存疗休养配置")
|
||||
public Result doSubmit(TourSetting tourSetting,
|
||||
@Param(value = "lots") String lots,
|
||||
@Param(value = "lotDeleteList") String[] lotDeleteList) {
|
||||
Result checkResult = check(tourSetting);
|
||||
if (checkResult != null) {
|
||||
return checkResult;
|
||||
}
|
||||
|
||||
Cnd sameNameCnd = Cnd.where(TourSetting::getYear, "=", tourSetting.getYear())
|
||||
.and(TourSetting::getConfigName, "=", tourSetting.getConfigName());
|
||||
if (StrUtil.isNotBlank(tourSetting.getId())) {
|
||||
sameNameCnd.and(TourSetting::getId, "<>", tourSetting.getId());
|
||||
}
|
||||
if (tourSettingService.count(sameNameCnd) > 0) {
|
||||
return Result.error("同年度下配置名称已存在");
|
||||
}
|
||||
|
||||
// 布尔值给默认值,避免前端未传时出现空状态。
|
||||
if (tourSetting.getEnabled() == null) {
|
||||
tourSetting.setEnabled(true);
|
||||
}
|
||||
if (tourSetting.getAllowFamily() == null) {
|
||||
tourSetting.setAllowFamily(false);
|
||||
}
|
||||
if (tourSetting.getFillBedInfo() == null) {
|
||||
tourSetting.setFillBedInfo(true);
|
||||
}
|
||||
if (StrUtil.isBlank(tourSetting.getOutProvinceRatioType())) {
|
||||
tourSetting.setOutProvinceRatioType("当年报名人数");
|
||||
}
|
||||
if (!"固定人数".equals(tourSetting.getOutProvinceRatioType())) {
|
||||
tourSetting.setOutProvinceFixedPeople(0);
|
||||
}
|
||||
// 前端按项目既有约定把子表数组序列化提交,这里显式解析,避免自动绑定漏掉标段。
|
||||
if (StrUtil.isNotBlank(lots)) {
|
||||
try {
|
||||
tourSetting.setLots(Json.fromJsonAsList(TourSettingLot.class, lots));
|
||||
} catch (Exception e) {
|
||||
return Result.error("标段值和标段费用必须为整数");
|
||||
}
|
||||
}
|
||||
tourSetting.setLots(normalizeLots(tourSetting));
|
||||
Result lotCheckResult = checkLots(tourSetting.getLots());
|
||||
if (lotCheckResult != null) {
|
||||
return lotCheckResult;
|
||||
}
|
||||
if (StrUtil.isBlank(tourSetting.getId())) {
|
||||
if (Lang.isEmpty(tourSetting.getLots())) {
|
||||
tourSettingService.insert(tourSetting);
|
||||
} else {
|
||||
tourSettingService.insertWith(tourSetting, "lots");
|
||||
}
|
||||
} else {
|
||||
// 编辑时先处理页面删除的标段,再保存配置和当前标段行。
|
||||
if (Lang.isNotEmpty(lotDeleteList)) {
|
||||
tourSettingService.dao().clear(TourSettingLot.class, Cnd.where(TourSettingLot::getId, "in", lotDeleteList));
|
||||
}
|
||||
tourSettingService.updateIgnoreNull(tourSetting);
|
||||
saveLots(tourSetting);
|
||||
}
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("tour.setting")
|
||||
@SLog(type = "tour", tag = "疗休养设置", msg = "删除疗休养配置")
|
||||
public Result doDelete(String id) {
|
||||
if (StrUtil.isBlank(id)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
tourSettingService.dao().clear(TourSettingLot.class, Cnd.where(TourSettingLot::getSettingId, "=", id));
|
||||
tourSettingService.delete(id);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
private List<TourSettingLot> normalizeLots(TourSetting tourSetting) {
|
||||
if (tourSetting == null || Lang.isEmpty(tourSetting.getLots())) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 过滤前端空行,避免误写入只有ID或空字段的标段记录。
|
||||
return tourSetting.getLots().stream()
|
||||
.filter(item -> item != null
|
||||
&& (StrUtil.isNotBlank(item.getLotName())
|
||||
|| StrUtil.isNotBlank(item.getLotValue())
|
||||
|| item.getActivityCost() != null))
|
||||
.peek(item -> item.setSettingId(tourSetting.getId()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void saveLots(TourSetting tourSetting) {
|
||||
List<TourSettingLot> lots = tourSetting.getLots();
|
||||
if (Lang.isEmpty(lots)) {
|
||||
return;
|
||||
}
|
||||
lots.forEach(item -> item.setSettingId(tourSetting.getId()));
|
||||
tourSettingService.dao().insertOrUpdate(lots);
|
||||
}
|
||||
|
||||
private Result check(TourSetting tourSetting) {
|
||||
if (tourSetting == null) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
if (tourSetting.getYear() == null) {
|
||||
return Result.error("年度不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(tourSetting.getConfigName())) {
|
||||
return Result.error("配置名称不能为空");
|
||||
}
|
||||
if (tourSetting.getMinGroupPeople() != null && tourSetting.getMaxGroupPeople() != null
|
||||
&& tourSetting.getMinGroupPeople() > tourSetting.getMaxGroupPeople()) {
|
||||
return Result.error("最少成团人数不能大于最多成团人数");
|
||||
}
|
||||
if (tourSetting.getCycleStartYear() != null && tourSetting.getCycleEndYear() != null
|
||||
&& tourSetting.getCycleStartYear() > tourSetting.getCycleEndYear()) {
|
||||
return Result.error("周期开始年度不能大于周期结束年度");
|
||||
}
|
||||
if (StrUtil.isNotBlank(tourSetting.getOutProvinceRatioType())
|
||||
&& !"当年参加人数".equals(tourSetting.getOutProvinceRatioType())
|
||||
&& !"当年报名人数".equals(tourSetting.getOutProvinceRatioType())
|
||||
&& !"可参加教职工人数".equals(tourSetting.getOutProvinceRatioType())
|
||||
&& !"固定人数".equals(tourSetting.getOutProvinceRatioType())) {
|
||||
return Result.error("省外人数占比类型不正确");
|
||||
}
|
||||
if ("固定人数".equals(tourSetting.getOutProvinceRatioType())
|
||||
&& (tourSetting.getOutProvinceFixedPeople() == null || tourSetting.getOutProvinceFixedPeople() < 0)) {
|
||||
return Result.error("固定人数必须大于等于0");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Result checkLots(List<TourSettingLot> lots) {
|
||||
if (Lang.isEmpty(lots)) {
|
||||
return null;
|
||||
}
|
||||
for (int i = 0; i < lots.size(); i++) {
|
||||
TourSettingLot lot = lots.get(i);
|
||||
String rowNo = "第" + (i + 1) + "行";
|
||||
if (StrUtil.isBlank(lot.getLotValue()) || !lot.getLotValue().matches("^\\d+$")) {
|
||||
return Result.error(rowNo + "标段值必须为整数");
|
||||
}
|
||||
if (lot.getActivityCost() == null || lot.getActivityCost() < 0) {
|
||||
return Result.error(rowNo + "标段费用必须为整数");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+1487
File diff suppressed because it is too large
Load Diff
+160
@@ -0,0 +1,160 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
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.result.Result;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourTravelAgency;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourTravelAgencyService;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
|
||||
@IocBean
|
||||
@Ok("json:full")
|
||||
@At("/platform/tour/travelAgency")
|
||||
public class TourTravelAgencyController {
|
||||
|
||||
private static final String MOBILE_PATTERN = "^1[3-9]\\d{9}$";
|
||||
private static final String EMAIL_PATTERN = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$";
|
||||
|
||||
@Inject
|
||||
private TourTravelAgencyService travelAgencyService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/Tour/travelAgency/index.html")
|
||||
@SaCheckPermission("tour.travelAgency")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.travelAgency")
|
||||
public Result pageData(PageForm pageForm, Integer year, String agencyName, String contactName, String contactPhone) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX(TourTravelAgency::getYear, "=", year);
|
||||
cnd.and(Cnd.likeEX(TourTravelAgency::getAgencyName, agencyName));
|
||||
cnd.and(Cnd.likeEX(TourTravelAgency::getContactName, contactName));
|
||||
cnd.and(Cnd.likeEX(TourTravelAgency::getContactPhone, contactPhone));
|
||||
applyOrder(cnd, pageForm);
|
||||
Pagination<TourTravelAgency> pagination = travelAgencyService.listPage(
|
||||
pageForm.getPageNumber(),
|
||||
pageForm.getPageSize(),
|
||||
TourTravelAgency.class,
|
||||
cnd
|
||||
);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.travelAgency")
|
||||
public Result detail(String id) {
|
||||
if (StrUtil.isBlank(id)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
TourTravelAgency agency = travelAgencyService.fetch(id);
|
||||
return agency == null ? Result.error("旅行社不存在") : Result.success(agency);
|
||||
}
|
||||
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("tour.travelAgency")
|
||||
@SLog(type = "tour", tag = "旅行社管理", msg = "保存旅行社信息")
|
||||
public Result doSubmit(TourTravelAgency agency) {
|
||||
Result checkResult = check(agency);
|
||||
if (checkResult != null) {
|
||||
return checkResult;
|
||||
}
|
||||
|
||||
Cnd sameCodeCnd = Cnd.where(TourTravelAgency::getYear, "=", agency.getYear())
|
||||
.and(TourTravelAgency::getAgencyCode, "=", agency.getAgencyCode());
|
||||
if (StrUtil.isNotBlank(agency.getId())) {
|
||||
sameCodeCnd.and(TourTravelAgency::getId, "<>", agency.getId());
|
||||
}
|
||||
if (travelAgencyService.count(sameCodeCnd) > 0) {
|
||||
return Result.error("同年度下旅行社编号已存在");
|
||||
}
|
||||
if (agency.getEnabled() == null) {
|
||||
agency.setEnabled(true);
|
||||
}
|
||||
if (StrUtil.isBlank(agency.getId())) {
|
||||
travelAgencyService.insert(agency);
|
||||
} else {
|
||||
travelAgencyService.updateIgnoreNull(agency);
|
||||
}
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("tour.travelAgency")
|
||||
@SLog(type = "tour", tag = "旅行社管理", msg = "删除旅行社信息")
|
||||
public Result doDelete(String id) {
|
||||
if (StrUtil.isBlank(id)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
travelAgencyService.delete(id);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
private Result check(TourTravelAgency agency) {
|
||||
if (agency == null) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
if (agency.getYear() == null) {
|
||||
return Result.error("年度不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(agency.getAgencyName())) {
|
||||
return Result.error("旅行社名称不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(agency.getAgencyCode())) {
|
||||
return Result.error("旅行社编号不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(agency.getContactName())) {
|
||||
return Result.error("联系人不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(agency.getContactPhone())) {
|
||||
return Result.error("联系人手机不能为空");
|
||||
}
|
||||
if (!agency.getContactPhone().matches(MOBILE_PATTERN)) {
|
||||
return Result.error("联系人手机格式不正确");
|
||||
}
|
||||
if (StrUtil.isBlank(agency.getEmail())) {
|
||||
return Result.error("邮箱不能为空");
|
||||
}
|
||||
if (!agency.getEmail().matches(EMAIL_PATTERN)) {
|
||||
return Result.error("邮箱格式不正确");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void applyOrder(Cnd cnd, PageForm pageForm) {
|
||||
String orderName = pageForm.getPageOrderName();
|
||||
String orderBy = pageForm.getPageOrderBy();
|
||||
if (StrUtil.isBlank(orderName)) {
|
||||
cnd.asc(TourTravelAgency::getYear).asc(TourTravelAgency::getAgencyCode).desc(TourTravelAgency::getCreatedAt);
|
||||
return;
|
||||
}
|
||||
boolean descending = "descending".equals(orderBy);
|
||||
if ("year".equals(orderName)) {
|
||||
if (descending) {
|
||||
cnd.desc(TourTravelAgency::getYear);
|
||||
} else {
|
||||
cnd.asc(TourTravelAgency::getYear);
|
||||
}
|
||||
} else if ("agencyCode".equals(orderName)) {
|
||||
if (descending) {
|
||||
cnd.desc(TourTravelAgency::getAgencyCode);
|
||||
} else {
|
||||
cnd.asc(TourTravelAgency::getAgencyCode);
|
||||
}
|
||||
} else {
|
||||
cnd.asc(TourTravelAgency::getYear).asc(TourTravelAgency::getAgencyCode).desc(TourTravelAgency::getCreatedAt);
|
||||
}
|
||||
}
|
||||
}
|
||||
+581
@@ -0,0 +1,581 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
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.flow.enums.ProcessTaskStateEnum;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedger;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedgerDirectRelative;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedgerFamily;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerDirectRelativeService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerFamilyService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerService;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@IocBean
|
||||
@Ok("json:full")
|
||||
@At("/platform/tour/unionApproval")
|
||||
public class TourUnionApprovalController {
|
||||
|
||||
private static final String WORKFLOW_KEY = "LXYBZXQSXL";
|
||||
private static final String TASK_DISPLAY_NAME = "分工会审核";
|
||||
|
||||
@Inject
|
||||
private TourLedgerService tourLedgerService;
|
||||
|
||||
@Inject
|
||||
private TourLedgerFamilyService tourLedgerFamilyService;
|
||||
|
||||
@Inject
|
||||
private TourLedgerDirectRelativeService tourLedgerDirectRelativeService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/Tour/unionApproval/index.html")
|
||||
@SaCheckPermission(value = {"tour.unionApproval", "h5.tour.unionApproval"}, mode = SaMode.OR)
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At("/h5")
|
||||
@Ok("beetl:/platform/zhghh5/dayofficework/tour/unionApproval/index.html")
|
||||
@SaCheckPermission(value = {"tour.unionApproval", "h5.tour.unionApproval"}, mode = SaMode.OR)
|
||||
public void h5() {
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission(value = {"tour.unionApproval", "h5.tour.unionApproval"}, mode = SaMode.OR)
|
||||
public Result pageData(PageForm pageForm, Boolean audit, Integer startYear, Integer endYear, String keyword, String unionId, String lineId, String travelPeriod, String lineType) {
|
||||
Cnd cnd = buildAuditCnd(audit, startYear, endYear, keyword, unionId, lineId, travelPeriod, lineType);
|
||||
|
||||
Sql countSql = Sqls.create("""
|
||||
SELECT COUNT(DISTINCT task.id)
|
||||
FROM wf_process_task task
|
||||
LEFT JOIN wf_process_instance ins ON ins.id = task.processInstanceId
|
||||
LEFT JOIN wf_process_define def ON def.id = ins.processDefineId
|
||||
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = task.id
|
||||
INNER JOIN tour_ledger t ON t.id = ins.businessNo
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
$condition
|
||||
""");
|
||||
countSql.setCondition(cnd);
|
||||
countSql.setCallback(Sqls.callback.integer());
|
||||
tourLedgerService.dao().execute(countSql);
|
||||
int count = countSql.getInt();
|
||||
|
||||
Sql listSql = Sqls.create("""
|
||||
SELECT
|
||||
t.*,
|
||||
ins.id AS instanceId,
|
||||
ins.businessNo,
|
||||
ins.state AS instanceState,
|
||||
ins.variable AS instanceVariable,
|
||||
ins.processDefineId AS instanceProcessDefineId,
|
||||
task.id AS taskId,
|
||||
task.taskName AS taskKey,
|
||||
task.displayName AS taskName,
|
||||
task.taskType,
|
||||
task.performType AS taskPerformType,
|
||||
task.taskState,
|
||||
task.finishTime,
|
||||
task.taskParentId,
|
||||
task.variable AS taskVariable,
|
||||
IFNULL(GROUP_CONCAT(DISTINCT nt.displayName), '结束') AS curTaskName,
|
||||
CASE
|
||||
WHEN m.id IS NULL THEN COALESCE(NULLIF(l.lineName, ''), t.lineName)
|
||||
ELSE CONCAT(
|
||||
COALESCE(NULLIF(l.lineName, ''), t.lineName),
|
||||
'(',
|
||||
CASE
|
||||
WHEN IFNULL(m.unionId, '') = '' THEN '校工会'
|
||||
ELSE IFNULL(mu.name, '')
|
||||
END,
|
||||
')'
|
||||
)
|
||||
END AS currentLineName,
|
||||
CASE
|
||||
WHEN IFNULL(m.travelStartTime, '') <> '' AND IFNULL(m.travelEndTime, '') <> ''
|
||||
THEN CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime)
|
||||
ELSE tp.travelPeriod
|
||||
END AS travelPeriod,
|
||||
IFNULL(f.familyCount, 0) AS familyCount
|
||||
FROM wf_process_task task
|
||||
LEFT JOIN wf_process_instance ins ON ins.id = task.processInstanceId
|
||||
LEFT JOIN wf_process_define def ON def.id = ins.processDefineId
|
||||
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = task.id
|
||||
INNER JOIN tour_ledger t ON t.id = ins.businessNo
|
||||
LEFT JOIN wf_process_task nt ON nt.processInstanceId = ins.id AND nt.taskState = 10
|
||||
LEFT JOIN (
|
||||
SELECT ledgerId, COUNT(1) AS familyCount
|
||||
FROM tour_ledger_family
|
||||
WHERE delFlag = 0
|
||||
GROUP BY ledgerId
|
||||
) f ON f.ledgerId = t.id
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
LEFT JOIN sys_union mu ON mu.id = m.unionId
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
`year`,
|
||||
lineId,
|
||||
GROUP_CONCAT(
|
||||
DISTINCT CASE
|
||||
WHEN IFNULL(travelStartTime, '') <> '' AND IFNULL(travelEndTime, '') <> ''
|
||||
THEN CONCAT(travelStartTime, ' 至 ', travelEndTime)
|
||||
ELSE NULL
|
||||
END
|
||||
ORDER BY travelStartTime ASC
|
||||
SEPARATOR ';'
|
||||
) AS travelPeriod
|
||||
FROM tour_matter
|
||||
WHERE delFlag = 0
|
||||
AND lineId IS NOT NULL
|
||||
AND lineId <> ''
|
||||
GROUP BY `year`, lineId
|
||||
) tp ON (t.matterId IS NULL OR t.matterId = '') AND tp.`year` = t.`year` AND tp.lineId = t.lineId
|
||||
$condition
|
||||
GROUP BY task.id
|
||||
ORDER BY $orderColumn $orderBy, task.createdAt DESC, t.signupTime DESC, t.createdAt DESC
|
||||
""");
|
||||
listSql.setCondition(cnd);
|
||||
listSql.setVar("orderColumn", getOrderColumn(pageForm.getPageOrderName()));
|
||||
listSql.setVar("orderBy", "ascending".equals(pageForm.getPageOrderBy()) ? "asc" : "desc");
|
||||
listSql.setPager(tourLedgerService.dao().createPager(pageForm.getPageNumber(), pageForm.getPageSize()));
|
||||
listSql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(listSql);
|
||||
|
||||
List<NutMap> list = listSql.getList(NutMap.class);
|
||||
list.forEach(item -> item.put("lineName", item.getString("currentLineName")));
|
||||
Pagination<NutMap> pagination = new Pagination<>(pageForm.getPageNumber(), pageForm.getPageSize(), count, list);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission(value = {"tour.unionApproval", "h5.tour.unionApproval"}, mode = SaMode.OR)
|
||||
public Result detail(String id) {
|
||||
TourLedger ledger = fetchAuditLedger(id);
|
||||
if (ledger == null) {
|
||||
return Result.error("报名记录不存在或无权查看");
|
||||
}
|
||||
ledger.setLineName(getCurrentLineName(ledger));
|
||||
Cnd familyCnd = Cnd.where(TourLedgerFamily::getLedgerId, "=", ledger.getId())
|
||||
.and(TourLedgerFamily::getDelFlag, "=", false);
|
||||
familyCnd.asc(TourLedgerFamily::getCreatedAt);
|
||||
TourLedgerDirectRelative directRelative = tourLedgerDirectRelativeService.fetch(
|
||||
Cnd.where(TourLedgerDirectRelative::getLedgerId, "=", ledger.getId())
|
||||
.and(TourLedgerDirectRelative::getDelFlag, "=", false));
|
||||
NutMap signupConfig = getSignupConfig(ledger);
|
||||
return Result.success(NutMap.NEW()
|
||||
.addv("ledger", ledger)
|
||||
.addv("travelPeriod", getTravelPeriod(ledger))
|
||||
.addv("families", tourLedgerFamilyService.query(familyCnd))
|
||||
.addv("directRelative", directRelative)
|
||||
.addv("allowFamily", signupConfig.getBoolean("allowFamily", false))
|
||||
.addv("fillBedInfo", signupConfig.getBoolean("fillBedInfo", true))
|
||||
.addv("directFamilyUnitLine", signupConfig.getBoolean("directFamilyUnitLine", false)));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission(value = {"tour.unionApproval", "h5.tour.unionApproval"}, mode = SaMode.OR)
|
||||
public Result unionOptions(Boolean audit, Integer startYear, Integer endYear, String keyword, String lineId, String travelPeriod, String lineType) {
|
||||
Cnd cnd = buildAuditCnd(audit, startYear, endYear, keyword, null, lineId, travelPeriod, lineType);
|
||||
cnd.and("t.unionId", "IS NOT", null);
|
||||
cnd.and("t.unionId", "<>", "");
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT DISTINCT
|
||||
t.unionId AS id,
|
||||
COALESCE(NULLIF(u.name, ''), t.unionName) AS name,
|
||||
u.unionCode
|
||||
FROM wf_process_task task
|
||||
LEFT JOIN wf_process_instance ins ON ins.id = task.processInstanceId
|
||||
LEFT JOIN wf_process_define def ON def.id = ins.processDefineId
|
||||
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = task.id
|
||||
INNER JOIN tour_ledger t ON t.id = ins.businessNo
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
LEFT JOIN sys_union u ON u.id = t.unionId
|
||||
$condition
|
||||
ORDER BY u.unionCode ASC, name ASC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return Result.success(sql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission(value = {"tour.unionApproval", "h5.tour.unionApproval"}, mode = SaMode.OR)
|
||||
public Result lineOptions(Boolean audit, Integer startYear, Integer endYear, String travelPeriod, String lineType, String unionId, String keyword) {
|
||||
Cnd cnd = buildAuditCnd(audit, startYear, endYear, keyword, unionId, null, travelPeriod, lineType);
|
||||
cnd.and("t.lineName", "IS NOT", null);
|
||||
cnd.and("t.lineName", "<>", "");
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT DISTINCT
|
||||
CASE
|
||||
WHEN IFNULL(t.lineId, '') <> '' THEN CONCAT(t.lineId, '|', IFNULL(m.unionId, ''))
|
||||
ELSE CONCAT('legacy:', t.lineName, '|', IFNULL(m.unionId, ''))
|
||||
END AS lineId,
|
||||
CASE
|
||||
WHEN m.id IS NULL THEN COALESCE(NULLIF(l.lineName, ''), t.lineName)
|
||||
ELSE CONCAT(
|
||||
COALESCE(NULLIF(l.lineName, ''), t.lineName),
|
||||
'(',
|
||||
CASE
|
||||
WHEN IFNULL(m.unionId, '') = '' THEN '校工会'
|
||||
ELSE IFNULL(mu.name, '')
|
||||
END,
|
||||
')'
|
||||
)
|
||||
END AS lineName
|
||||
FROM wf_process_task task
|
||||
LEFT JOIN wf_process_instance ins ON ins.id = task.processInstanceId
|
||||
LEFT JOIN wf_process_define def ON def.id = ins.processDefineId
|
||||
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = task.id
|
||||
INNER JOIN tour_ledger t ON t.id = ins.businessNo
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
LEFT JOIN sys_union mu ON mu.id = m.unionId
|
||||
$condition
|
||||
ORDER BY lineName ASC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return Result.success(sql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission(value = {"tour.unionApproval", "h5.tour.unionApproval"}, mode = SaMode.OR)
|
||||
public Result travelPeriodOptions(Boolean audit, Integer startYear, Integer endYear, String lineId, String lineType, String unionId, String keyword) {
|
||||
Cnd cnd = buildAuditCnd(audit, startYear, endYear, keyword, unionId, lineId, null, lineType);
|
||||
cnd.and("m.travelStartTime", "IS NOT", null);
|
||||
cnd.and("m.travelStartTime", "<>", "");
|
||||
cnd.and("m.travelEndTime", "IS NOT", null);
|
||||
cnd.and("m.travelEndTime", "<>", "");
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT DISTINCT CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime) AS travelPeriod
|
||||
FROM wf_process_task task
|
||||
LEFT JOIN wf_process_instance ins ON ins.id = task.processInstanceId
|
||||
LEFT JOIN wf_process_define def ON def.id = ins.processDefineId
|
||||
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = task.id
|
||||
INNER JOIN tour_ledger t ON t.id = ins.businessNo
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
$condition
|
||||
ORDER BY travelPeriod ASC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return Result.success(sql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission(value = {"tour.unionApproval", "h5.tour.unionApproval"}, mode = SaMode.OR)
|
||||
public Result lineTypeOptions(Boolean audit, Integer startYear, Integer endYear, String lineId, String travelPeriod, String unionId, String keyword) {
|
||||
Cnd cnd = buildAuditCnd(audit, startYear, endYear, keyword, unionId, lineId, travelPeriod, null);
|
||||
cnd.and("t.lineType", "IS NOT", null);
|
||||
cnd.and("t.lineType", "<>", "");
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT DISTINCT t.lineType
|
||||
FROM wf_process_task task
|
||||
LEFT JOIN wf_process_instance ins ON ins.id = task.processInstanceId
|
||||
LEFT JOIN wf_process_define def ON def.id = ins.processDefineId
|
||||
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = task.id
|
||||
INNER JOIN tour_ledger t ON t.id = ins.businessNo
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
$condition
|
||||
ORDER BY t.lineType ASC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return Result.success(sql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
private Cnd buildAuditCnd(Boolean audit, Integer startYear, Integer endYear, String keyword, String unionId, String lineId, String travelPeriod, String lineType) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("t.delFlag", "=", false);
|
||||
cnd.and("def.name", "=", WORKFLOW_KEY);
|
||||
cnd.and("task.displayName", "=", TASK_DISPLAY_NAME);
|
||||
cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
|
||||
appendAuditStateFilter(cnd, audit);
|
||||
cnd.andEX("t.`year`", ">=", startYear);
|
||||
cnd.andEX("t.`year`", "<=", endYear == null ? LocalDate.now().getYear() : endYear);
|
||||
cnd.andEX("t.unionId", "=", unionId);
|
||||
cnd.andEX("t.lineType", "=", lineType);
|
||||
appendLineFilter(cnd, lineId);
|
||||
appendTravelPeriodFilter(cnd, travelPeriod);
|
||||
appendKeywordFilter(cnd, keyword);
|
||||
return cnd;
|
||||
}
|
||||
|
||||
private void appendAuditStateFilter(Cnd cnd, Boolean audit) {
|
||||
if (Boolean.TRUE.equals(audit)) {
|
||||
cnd.and("task.taskState", "in", List.of(
|
||||
ProcessTaskStateEnum.FINISHED.getCode(),
|
||||
ProcessTaskStateEnum.WITHDRAW.getCode(),
|
||||
ProcessTaskStateEnum.INTERRUPT.getCode()));
|
||||
return;
|
||||
}
|
||||
cnd.and("task.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
|
||||
}
|
||||
|
||||
private void appendKeywordFilter(Cnd cnd, String keyword) {
|
||||
if (StrUtil.isBlank(keyword)) {
|
||||
return;
|
||||
}
|
||||
SqlExpressionGroup group = new SqlExpressionGroup();
|
||||
group.orLike("t.userName", keyword.trim());
|
||||
group.orLike("t.jobNo", keyword.trim());
|
||||
group.orLike("t.lineName", keyword.trim());
|
||||
group.orLike("l.lineName", keyword.trim());
|
||||
cnd.and(group);
|
||||
}
|
||||
|
||||
private void appendTravelPeriodFilter(Cnd cnd, String travelPeriod) {
|
||||
if (StrUtil.isBlank(travelPeriod)) {
|
||||
return;
|
||||
}
|
||||
cnd.and("CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime)", "=", travelPeriod);
|
||||
}
|
||||
|
||||
private void appendLineFilter(Cnd cnd, String lineId) {
|
||||
if (StrUtil.isBlank(lineId)) {
|
||||
return;
|
||||
}
|
||||
LineFilter lineFilter = parseLineFilter(lineId);
|
||||
if (lineFilter.getLineId().startsWith("legacy:")) {
|
||||
SqlExpressionGroup legacyGroup = new SqlExpressionGroup();
|
||||
legacyGroup.or("t.lineId", "IS", null);
|
||||
legacyGroup.or("t.lineId", "=", "");
|
||||
cnd.and(legacyGroup);
|
||||
cnd.and("t.lineName", "=", lineFilter.getLineId().substring("legacy:".length()));
|
||||
} else {
|
||||
cnd.and("t.lineId", "=", lineFilter.getLineId());
|
||||
}
|
||||
appendMatterUnionFilter(cnd, lineFilter.getUnionId());
|
||||
}
|
||||
|
||||
private LineFilter parseLineFilter(String value) {
|
||||
int delimiterIndex = value.indexOf("|");
|
||||
if (delimiterIndex < 0) {
|
||||
return new LineFilter(value, null);
|
||||
}
|
||||
return new LineFilter(value.substring(0, delimiterIndex), value.substring(delimiterIndex + 1));
|
||||
}
|
||||
|
||||
private void appendMatterUnionFilter(Cnd cnd, String unionId) {
|
||||
if (unionId == null) {
|
||||
return;
|
||||
}
|
||||
if (StrUtil.isBlank(unionId)) {
|
||||
SqlExpressionGroup group = new SqlExpressionGroup();
|
||||
group.or("m.unionId", "IS", null);
|
||||
group.or("m.unionId", "=", "");
|
||||
cnd.and(group);
|
||||
return;
|
||||
}
|
||||
cnd.and("m.unionId", "=", unionId);
|
||||
}
|
||||
|
||||
private String getOrderColumn(String orderName) {
|
||||
if ("jobNo".equals(orderName)) {
|
||||
return "t.jobNo";
|
||||
}
|
||||
if ("userName".equals(orderName)) {
|
||||
return "t.userName";
|
||||
}
|
||||
if ("lineName".equals(orderName)) {
|
||||
return """
|
||||
CASE
|
||||
WHEN m.id IS NULL THEN COALESCE(NULLIF(l.lineName, ''), t.lineName)
|
||||
ELSE CONCAT(
|
||||
COALESCE(NULLIF(l.lineName, ''), t.lineName),
|
||||
'(',
|
||||
CASE
|
||||
WHEN IFNULL(m.unionId, '') = '' THEN '校工会'
|
||||
ELSE IFNULL(mu.name, '')
|
||||
END,
|
||||
')'
|
||||
)
|
||||
END
|
||||
""";
|
||||
}
|
||||
if ("travelPeriod".equals(orderName)) {
|
||||
return "COALESCE(m.travelStartTime, tp.travelPeriod)";
|
||||
}
|
||||
if ("lineType".equals(orderName)) {
|
||||
return "t.lineType";
|
||||
}
|
||||
if ("signupTime".equals(orderName)) {
|
||||
return "t.signupTime";
|
||||
}
|
||||
if ("familyCount".equals(orderName)) {
|
||||
return "familyCount";
|
||||
}
|
||||
if ("instanceState".equals(orderName)) {
|
||||
return "ins.state";
|
||||
}
|
||||
return "task.createdAt";
|
||||
}
|
||||
|
||||
private TourLedger fetchAuditLedger(String id) {
|
||||
if (StrUtil.isBlank(id)) {
|
||||
return null;
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT COUNT(1)
|
||||
FROM wf_process_task task
|
||||
LEFT JOIN wf_process_instance ins ON ins.id = task.processInstanceId
|
||||
LEFT JOIN wf_process_define def ON def.id = ins.processDefineId
|
||||
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = task.id
|
||||
INNER JOIN tour_ledger t ON t.id = ins.businessNo
|
||||
WHERE t.delFlag = 0
|
||||
AND t.id = @id
|
||||
AND def.name = @workflowKey
|
||||
AND task.displayName = @taskDisplayName
|
||||
AND ta.actorId = @actorId
|
||||
""");
|
||||
sql.setParam("id", id);
|
||||
sql.setParam("workflowKey", WORKFLOW_KEY);
|
||||
sql.setParam("taskDisplayName", TASK_DISPLAY_NAME);
|
||||
sql.setParam("actorId", SecurityUtil.getUserId());
|
||||
sql.setCallback(Sqls.callback.integer());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return sql.getInt() > 0 ? tourLedgerService.fetch(id) : null;
|
||||
}
|
||||
|
||||
private String getCurrentLineName(TourLedger ledger) {
|
||||
if (ledger == null) {
|
||||
return "";
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT CASE
|
||||
WHEN m.id IS NULL THEN COALESCE(NULLIF(l.lineName, ''), t.lineName)
|
||||
ELSE CONCAT(
|
||||
COALESCE(NULLIF(l.lineName, ''), t.lineName),
|
||||
'(',
|
||||
CASE
|
||||
WHEN IFNULL(m.unionId, '') = '' THEN '校工会'
|
||||
ELSE IFNULL(mu.name, '')
|
||||
END,
|
||||
')'
|
||||
)
|
||||
END AS lineName
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
LEFT JOIN sys_union mu ON mu.id = m.unionId
|
||||
WHERE t.id = @ledgerId
|
||||
""");
|
||||
sql.setParam("ledgerId", ledger.getId());
|
||||
sql.setCallback(Sqls.callback.str());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return StrUtil.blankToDefault(sql.getString(), ledger.getLineName());
|
||||
}
|
||||
|
||||
private String getTravelPeriod(TourLedger ledger) {
|
||||
if (ledger == null || ledger.getYear() == null || StrUtil.isBlank(ledger.getLineId())) {
|
||||
return "";
|
||||
}
|
||||
if (StrUtil.isNotBlank(ledger.getMatterId())) {
|
||||
Sql exactSql = Sqls.create("""
|
||||
SELECT CASE
|
||||
WHEN IFNULL(travelStartTime, '') <> '' AND IFNULL(travelEndTime, '') <> ''
|
||||
THEN CONCAT(travelStartTime, ' 至 ', travelEndTime)
|
||||
ELSE ''
|
||||
END AS travelPeriod
|
||||
FROM tour_matter
|
||||
WHERE delFlag = 0
|
||||
AND id = @matterId
|
||||
""");
|
||||
exactSql.setParam("matterId", ledger.getMatterId());
|
||||
exactSql.setCallback(Sqls.callback.str());
|
||||
tourLedgerService.dao().execute(exactSql);
|
||||
return exactSql.getString();
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT GROUP_CONCAT(
|
||||
DISTINCT CASE
|
||||
WHEN IFNULL(travelStartTime, '') <> '' AND IFNULL(travelEndTime, '') <> ''
|
||||
THEN CONCAT(travelStartTime, ' 至 ', travelEndTime)
|
||||
ELSE NULL
|
||||
END
|
||||
ORDER BY travelStartTime ASC
|
||||
SEPARATOR ';'
|
||||
) AS travelPeriod
|
||||
FROM tour_matter
|
||||
WHERE delFlag = 0
|
||||
AND `year` = @year
|
||||
AND lineId = @lineId
|
||||
""");
|
||||
sql.setParam("year", ledger.getYear());
|
||||
sql.setParam("lineId", ledger.getLineId());
|
||||
sql.setCallback(Sqls.callback.str());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return sql.getString();
|
||||
}
|
||||
|
||||
private NutMap getSignupConfig(TourLedger ledger) {
|
||||
if (ledger == null || StrUtil.isBlank(ledger.getLineId())) {
|
||||
return NutMap.NEW().addv("allowFamily", false).addv("fillBedInfo", true).addv("directFamilyUnitLine", false);
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
IFNULL(s.allowFamily, 0) AS allowFamily,
|
||||
IFNULL(s.fillBedInfo, 1) AS fillBedInfo,
|
||||
IFNULL(l.directFamilyUnitLine, 0) AS directFamilyUnitLine
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_setting s ON s.id = m.settingId AND s.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
WHERE t.id = @ledgerId
|
||||
""");
|
||||
sql.setParam("ledgerId", ledger.getId());
|
||||
sql.setCallback(Sqls.callback.map());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
NutMap map = sql.getObject(NutMap.class);
|
||||
if (map == null || map.isEmpty()) {
|
||||
return NutMap.NEW().addv("allowFamily", false).addv("fillBedInfo", true).addv("directFamilyUnitLine", false);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private static class LineFilter {
|
||||
private final String lineId;
|
||||
private final String unionId;
|
||||
|
||||
private LineFilter(String lineId, String unionId) {
|
||||
this.lineId = lineId;
|
||||
this.unionId = unionId;
|
||||
}
|
||||
|
||||
private String getLineId() {
|
||||
return lineId;
|
||||
}
|
||||
|
||||
private String getUnionId() {
|
||||
return unionId;
|
||||
}
|
||||
}
|
||||
}
|
||||
+905
@@ -0,0 +1,905 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
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.result.Result;
|
||||
import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||
import com.budwk.app.sys.models.Sys_union;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedger;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedgerDirectRelative;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedgerFamily;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerDirectRelativeService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerFamilyService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerService;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.ss.usermodel.BorderStyle;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.Font;
|
||||
import org.apache.poi.ss.usermodel.HorizontalAlignment;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.VerticalAlignment;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
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.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.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.List;
|
||||
|
||||
@IocBean
|
||||
@Ok("json:full")
|
||||
@At("/platform/tour/unionledger")
|
||||
public class TourUnionLedgerController {
|
||||
|
||||
@Inject
|
||||
private TourLedgerService tourLedgerService;
|
||||
|
||||
@Inject
|
||||
private TourLedgerFamilyService tourLedgerFamilyService;
|
||||
|
||||
@Inject
|
||||
private TourLedgerDirectRelativeService tourLedgerDirectRelativeService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/Tour/unionledger/index.html")
|
||||
@SaCheckPermission("tour.unionledger")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.unionledger")
|
||||
public Result pageData(PageForm pageForm, Integer startYear, Integer endYear, String keyword, String unionId, String lineId, String travelPeriod, String lineType, String scopeType, Boolean overCostOnly) {
|
||||
String currentUnionId = currentUnionId();
|
||||
if (StrUtil.isBlank(currentUnionId)) {
|
||||
return Result.error("当前登录人所属工会不能为空");
|
||||
}
|
||||
Cnd cnd = buildQueryCnd(currentUnionId, startYear, endYear, keyword, unionId, lineId, travelPeriod, lineType, scopeType, overCostOnly);
|
||||
|
||||
Sql countSql = Sqls.create("""
|
||||
SELECT COUNT(DISTINCT t.id)
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = t.id
|
||||
LEFT JOIN wf_process_task task ON task.processInstanceId = ins.id AND task.taskState = 10
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
$condition
|
||||
""");
|
||||
countSql.setCondition(cnd);
|
||||
countSql.setCallback(Sqls.callback.integer());
|
||||
tourLedgerService.dao().execute(countSql);
|
||||
int count = countSql.getInt();
|
||||
|
||||
Sql listSql = Sqls.create("""
|
||||
SELECT
|
||||
t.*,
|
||||
ins.id AS instanceId,
|
||||
ins.state AS instanceState,
|
||||
ins.processDefineId AS instanceProcessDefineId,
|
||||
IFNULL(l.directFamilyUnitLine, 0) AS directFamilyUnitLine,
|
||||
IFNULL(GROUP_CONCAT(DISTINCT task.displayName), IF(ins.id IS NULL, '', '结束')) AS curTaskName,
|
||||
CASE
|
||||
WHEN m.id IS NULL THEN COALESCE(NULLIF(l.lineName, ''), t.lineName)
|
||||
ELSE CONCAT(
|
||||
COALESCE(NULLIF(l.lineName, ''), t.lineName),
|
||||
'(',
|
||||
CASE
|
||||
WHEN IFNULL(m.unionId, '') = '' THEN '校工会'
|
||||
ELSE IFNULL(mu.name, '')
|
||||
END,
|
||||
')'
|
||||
)
|
||||
END AS currentLineName,
|
||||
IFNULL(f.familyCount, 0) AS familyCount,
|
||||
CASE
|
||||
WHEN IFNULL(m.travelStartTime, '') <> '' AND IFNULL(m.travelEndTime, '') <> ''
|
||||
THEN CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime)
|
||||
ELSE tp.travelPeriod
|
||||
END AS travelPeriod
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = t.id
|
||||
LEFT JOIN wf_process_task task ON task.processInstanceId = ins.id AND task.taskState = 10
|
||||
LEFT JOIN (
|
||||
SELECT ledgerId, COUNT(1) AS familyCount
|
||||
FROM tour_ledger_family
|
||||
WHERE delFlag = 0
|
||||
GROUP BY ledgerId
|
||||
) f ON f.ledgerId = t.id
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
LEFT JOIN sys_union mu ON mu.id = m.unionId
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
`year`,
|
||||
lineId,
|
||||
GROUP_CONCAT(
|
||||
DISTINCT CASE
|
||||
WHEN IFNULL(travelStartTime, '') <> '' AND IFNULL(travelEndTime, '') <> ''
|
||||
THEN CONCAT(travelStartTime, ' 至 ', travelEndTime)
|
||||
ELSE NULL
|
||||
END
|
||||
ORDER BY travelStartTime ASC
|
||||
SEPARATOR ';'
|
||||
) AS travelPeriod
|
||||
FROM tour_matter
|
||||
WHERE delFlag = 0
|
||||
AND lineId IS NOT NULL
|
||||
AND lineId <> ''
|
||||
GROUP BY `year`, lineId
|
||||
) tp ON (t.matterId IS NULL OR t.matterId = '') AND tp.`year` = t.`year` AND tp.lineId = t.lineId
|
||||
$condition
|
||||
GROUP BY t.id
|
||||
ORDER BY $orderColumn $orderBy, t.`year` DESC, t.signupTime DESC, t.createdAt DESC
|
||||
""");
|
||||
listSql.setCondition(cnd);
|
||||
listSql.setVar("orderColumn", getOrderColumn(pageForm.getPageOrderName()));
|
||||
listSql.setVar("orderBy", "descending".equals(pageForm.getPageOrderBy()) ? "desc" : "asc");
|
||||
listSql.setPager(tourLedgerService.dao().createPager(pageForm.getPageNumber(), pageForm.getPageSize()));
|
||||
listSql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(listSql);
|
||||
|
||||
var list = listSql.getList(NutMap.class);
|
||||
list.forEach(item -> item.put("lineName", item.getString("currentLineName")));
|
||||
Pagination<NutMap> pagination = new Pagination<>(pageForm.getPageNumber(), pageForm.getPageSize(), count, list);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@Ok("void")
|
||||
@SaCheckPermission("tour.unionledger")
|
||||
public void exportOverCostSummary(PageForm pageForm, Integer startYear, Integer endYear, String keyword, String unionId, String lineId, String travelPeriod, String lineType, String scopeType, HttpServletResponse response) {
|
||||
String currentUnionId = currentUnionId();
|
||||
if (StrUtil.isBlank(currentUnionId)) {
|
||||
return;
|
||||
}
|
||||
Cnd cnd = buildQueryCnd(currentUnionId, startYear, endYear, keyword, unionId, lineId, travelPeriod, lineType, scopeType, true);
|
||||
List<NutMap> list = queryOverCostSummaryList(cnd, pageForm);
|
||||
Workbook workbook = buildOverCostSummaryWorkbook(currentUnionName(), list);
|
||||
CommonDownloadUtil.download("5天外超出部分疗休养费用由单位承担申请人员汇总表.xls", workbook, response);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.unionledger")
|
||||
public Result detail(String id) {
|
||||
TourLedger ledger = fetchScopedLedger(id);
|
||||
if (ledger == null) {
|
||||
return Result.error("台账记录不存在或无权查看");
|
||||
}
|
||||
ledger.setLineName(getCurrentLineName(ledger));
|
||||
Cnd familyCnd = Cnd.where(TourLedgerFamily::getLedgerId, "=", id)
|
||||
.and(TourLedgerFamily::getDelFlag, "=", false);
|
||||
familyCnd.asc(TourLedgerFamily::getCreatedAt);
|
||||
TourLedgerDirectRelative directRelative = tourLedgerDirectRelativeService.fetch(
|
||||
Cnd.where(TourLedgerDirectRelative::getDelFlag, "=", false)
|
||||
.and(TourLedgerDirectRelative::getLedgerId, "=", ledger.getId()));
|
||||
return Result.success(NutMap.NEW()
|
||||
.addv("ledger", ledger)
|
||||
.addv("travelPeriod", getTravelPeriod(ledger))
|
||||
.addv("families", tourLedgerFamilyService.query(familyCnd))
|
||||
.addv("directRelative", directRelative)
|
||||
.addv("fillBedInfo", isFillBedInfo(ledger))
|
||||
.addv("directFamilyUnitLine", isDirectFamilyUnitLine(ledger)));
|
||||
}
|
||||
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("tour.unionledger")
|
||||
@SLog(type = "tour", tag = "分工会疗休养台账", msg = "删除分工会疗休养台账")
|
||||
public Result doDelete(String id) {
|
||||
TourLedger ledger = fetchScopedLedger(id);
|
||||
if (ledger == null) {
|
||||
return Result.error("台账记录不存在或无权删除");
|
||||
}
|
||||
tourLedgerFamilyService.clear(Cnd.where(TourLedgerFamily::getLedgerId, "=", ledger.getId()));
|
||||
tourLedgerService.clear(Cnd.where(TourLedger::getId, "=", ledger.getId()));
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.unionledger")
|
||||
public Result unionOptions(Integer startYear, Integer endYear) {
|
||||
String currentUnionId = currentUnionId();
|
||||
if (StrUtil.isBlank(currentUnionId)) {
|
||||
return Result.error("当前登录人所属工会不能为空");
|
||||
}
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("t.delFlag", "=", false);
|
||||
cnd.andEX("t.`year`", ">=", startYear);
|
||||
cnd.andEX("t.`year`", "<=", endYear == null ? LocalDate.now().getYear() : endYear);
|
||||
cnd.and("t.unionId", "IS NOT", null);
|
||||
cnd.and("t.unionId", "<>", "");
|
||||
applyUnionLedgerScope(cnd, currentUnionId);
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT DISTINCT
|
||||
t.unionId AS id,
|
||||
COALESCE(NULLIF(u.name, ''), t.unionName) AS name,
|
||||
u.unionCode
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN sys_union u ON u.id = t.unionId
|
||||
$condition
|
||||
ORDER BY
|
||||
CASE WHEN t.unionId = @currentUnionId THEN 0 ELSE 1 END,
|
||||
u.unionCode ASC,
|
||||
name ASC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setParam("currentUnionId", currentUnionId);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return Result.success(sql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.unionledger")
|
||||
public Result lineOptions(Integer startYear, Integer endYear, String travelPeriod, String lineType, String unionId, String keyword, String scopeType) {
|
||||
String currentUnionId = currentUnionId();
|
||||
if (StrUtil.isBlank(currentUnionId)) {
|
||||
return Result.error("当前登录人所属工会不能为空");
|
||||
}
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("t.delFlag", "=", false);
|
||||
cnd.andEX("t.`year`", ">=", startYear);
|
||||
cnd.andEX("t.`year`", "<=", endYear == null ? LocalDate.now().getYear() : endYear);
|
||||
cnd.and("t.lineName", "IS NOT", null);
|
||||
cnd.and("t.lineName", "<>", "");
|
||||
cnd.andEX("t.unionId", "=", unionId);
|
||||
cnd.andEX("t.lineType", "=", lineType);
|
||||
appendTravelPeriodFilter(cnd, travelPeriod);
|
||||
appendScopeFilter(cnd, currentUnionId, scopeType);
|
||||
appendKeywordFilter(cnd, keyword);
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT DISTINCT
|
||||
CASE
|
||||
WHEN IFNULL(t.lineId, '') <> '' THEN CONCAT(t.lineId, '|', IFNULL(m.unionId, ''))
|
||||
ELSE CONCAT('legacy:', t.lineName, '|', IFNULL(m.unionId, ''))
|
||||
END AS lineId,
|
||||
CASE
|
||||
WHEN m.id IS NULL THEN COALESCE(NULLIF(l.lineName, ''), t.lineName)
|
||||
ELSE CONCAT(
|
||||
COALESCE(NULLIF(l.lineName, ''), t.lineName),
|
||||
'(',
|
||||
CASE
|
||||
WHEN IFNULL(m.unionId, '') = '' THEN '校工会'
|
||||
ELSE IFNULL(mu.name, '')
|
||||
END,
|
||||
')'
|
||||
)
|
||||
END AS lineName
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
LEFT JOIN sys_union mu ON mu.id = m.unionId
|
||||
$condition
|
||||
ORDER BY lineName ASC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return Result.success(sql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.unionledger")
|
||||
public Result travelPeriodOptions(Integer startYear, Integer endYear, String lineId, String lineType, String unionId, String keyword, String scopeType) {
|
||||
String currentUnionId = currentUnionId();
|
||||
if (StrUtil.isBlank(currentUnionId)) {
|
||||
return Result.error("当前登录人所属工会不能为空");
|
||||
}
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("t.delFlag", "=", false);
|
||||
cnd.andEX("t.`year`", ">=", startYear);
|
||||
cnd.andEX("t.`year`", "<=", endYear == null ? LocalDate.now().getYear() : endYear);
|
||||
cnd.and("m.travelStartTime", "IS NOT", null);
|
||||
cnd.and("m.travelStartTime", "<>", "");
|
||||
cnd.and("m.travelEndTime", "IS NOT", null);
|
||||
cnd.and("m.travelEndTime", "<>", "");
|
||||
cnd.andEX("t.unionId", "=", unionId);
|
||||
cnd.andEX("t.lineType", "=", lineType);
|
||||
appendLineFilter(cnd, lineId);
|
||||
appendScopeFilter(cnd, currentUnionId, scopeType);
|
||||
appendKeywordFilter(cnd, keyword);
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT DISTINCT CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime) AS travelPeriod
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
$condition
|
||||
ORDER BY travelPeriod ASC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return Result.success(sql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.unionledger")
|
||||
public Result lineTypeOptions(Integer startYear, Integer endYear, String lineId, String travelPeriod, String unionId, String keyword, String scopeType) {
|
||||
String currentUnionId = currentUnionId();
|
||||
if (StrUtil.isBlank(currentUnionId)) {
|
||||
return Result.error("当前登录人所属工会不能为空");
|
||||
}
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("t.delFlag", "=", false);
|
||||
cnd.andEX("t.`year`", ">=", startYear);
|
||||
cnd.andEX("t.`year`", "<=", endYear == null ? LocalDate.now().getYear() : endYear);
|
||||
cnd.and("t.lineType", "IS NOT", null);
|
||||
cnd.and("t.lineType", "<>", "");
|
||||
cnd.andEX("t.unionId", "=", unionId);
|
||||
appendLineFilter(cnd, lineId);
|
||||
appendTravelPeriodFilter(cnd, travelPeriod);
|
||||
appendScopeFilter(cnd, currentUnionId, scopeType);
|
||||
appendKeywordFilter(cnd, keyword);
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT DISTINCT t.lineType
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
$condition
|
||||
ORDER BY t.lineType ASC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return Result.success(sql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.unionledger")
|
||||
public Result summaryStats(Integer startYear, Integer endYear, String unionId, String lineId, String travelPeriod, String lineType) {
|
||||
String currentUnionId = currentUnionId();
|
||||
if (StrUtil.isBlank(currentUnionId)) {
|
||||
return Result.error("当前登录人所属工会不能为空");
|
||||
}
|
||||
Cnd ownCnd = buildSummaryCnd(currentUnionId, startYear, endYear, unionId, lineId, travelPeriod, lineType, "ownUnionJoined");
|
||||
Cnd organizedCnd = buildSummaryCnd(currentUnionId, startYear, endYear, unionId, lineId, travelPeriod, lineType, "organizedLineJoined");
|
||||
|
||||
Sql ownSql = Sqls.create("""
|
||||
SELECT COUNT(1)
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
$condition
|
||||
""");
|
||||
ownSql.setCondition(ownCnd);
|
||||
ownSql.setCallback(Sqls.callback.integer());
|
||||
tourLedgerService.dao().execute(ownSql);
|
||||
|
||||
Sql organizedSql = Sqls.create("""
|
||||
SELECT CAST(IFNULL(SUM(1 + IFNULL(f.familyCount, 0)), 0) AS SIGNED)
|
||||
FROM tour_ledger t
|
||||
INNER JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN (
|
||||
SELECT ledgerId, COUNT(1) AS familyCount
|
||||
FROM tour_ledger_family
|
||||
WHERE delFlag = 0
|
||||
GROUP BY ledgerId
|
||||
) f ON f.ledgerId = t.id
|
||||
$condition
|
||||
""");
|
||||
organizedSql.setCondition(organizedCnd);
|
||||
organizedSql.setCallback(Sqls.callback.integer());
|
||||
tourLedgerService.dao().execute(organizedSql);
|
||||
|
||||
return Result.success(NutMap.NEW()
|
||||
.addv("ownUnionJoinedStaffCount", ownSql.getInt())
|
||||
.addv("organizedLineJoinedTotalCount", organizedSql.getInt()));
|
||||
}
|
||||
|
||||
private List<NutMap> queryOverCostSummaryList(Cnd cnd, PageForm pageForm) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
t.id,
|
||||
t.userName,
|
||||
t.idCard,
|
||||
t.unionName,
|
||||
vu.mobile,
|
||||
m.travelStartTime,
|
||||
m.travelEndTime,
|
||||
m.estimatedCost,
|
||||
CASE
|
||||
WHEN IFNULL(m.travelStartTime, '') <> '' AND IFNULL(m.travelEndTime, '') <> ''
|
||||
THEN CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime)
|
||||
ELSE tp.travelPeriod
|
||||
END AS travelPeriod,
|
||||
CASE
|
||||
WHEN m.id IS NULL THEN COALESCE(NULLIF(l.lineName, ''), t.lineName)
|
||||
ELSE CONCAT(
|
||||
COALESCE(NULLIF(l.lineName, ''), t.lineName),
|
||||
'(',
|
||||
CASE
|
||||
WHEN IFNULL(m.unionId, '') = '' THEN '校工会'
|
||||
ELSE IFNULL(mu.name, '')
|
||||
END,
|
||||
')'
|
||||
)
|
||||
END AS currentLineName
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
LEFT JOIN sys_union mu ON mu.id = m.unionId
|
||||
LEFT JOIN vw_user vu ON vu.loginname = t.jobNo
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
`year`,
|
||||
lineId,
|
||||
GROUP_CONCAT(
|
||||
DISTINCT CASE
|
||||
WHEN IFNULL(travelStartTime, '') <> '' AND IFNULL(travelEndTime, '') <> ''
|
||||
THEN CONCAT(travelStartTime, ' 至 ', travelEndTime)
|
||||
ELSE NULL
|
||||
END
|
||||
ORDER BY travelStartTime ASC
|
||||
SEPARATOR ';'
|
||||
) AS travelPeriod
|
||||
FROM tour_matter
|
||||
WHERE delFlag = 0
|
||||
AND lineId IS NOT NULL
|
||||
AND lineId <> ''
|
||||
GROUP BY `year`, lineId
|
||||
) tp ON (t.matterId IS NULL OR t.matterId = '') AND tp.`year` = t.`year` AND tp.lineId = t.lineId
|
||||
$condition
|
||||
ORDER BY $orderColumn $orderBy, t.`year` DESC, t.signupTime DESC, t.createdAt DESC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setVar("orderColumn", getOrderColumn(pageForm == null ? null : pageForm.getPageOrderName()));
|
||||
sql.setVar("orderBy", pageForm != null && "ascending".equals(pageForm.getPageOrderBy()) ? "asc" : "desc");
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
List<NutMap> list = sql.getList(NutMap.class);
|
||||
for (NutMap item : list) {
|
||||
item.put("lineName", item.getString("currentLineName"));
|
||||
item.put("totalDays", calcDays(item.getString("travelStartTime", ""), item.getString("travelEndTime", "")));
|
||||
item.put("estimatedCostText", formatAmount(item.get("estimatedCost")));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private Workbook buildOverCostSummaryWorkbook(String unionName, List<NutMap> list) {
|
||||
Workbook workbook = new HSSFWorkbook();
|
||||
Sheet sheet = workbook.createSheet("汇总表");
|
||||
sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 9));
|
||||
sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, 9));
|
||||
sheet.addMergedRegion(new CellRangeAddress(2, 2, 0, 9));
|
||||
|
||||
double[] widths = {5.14, 14.14, 21.29, 15.71, 27, 40, 50.43, 13.71, 22.57, 15.43};
|
||||
for (int i = 0; i < widths.length; i++) {
|
||||
sheet.setColumnWidth(i, (int) (widths[i] * 256));
|
||||
}
|
||||
|
||||
CellStyle attachStyle = createStyle(workbook, "宋体", (short) 12, false, HorizontalAlignment.LEFT, false, false);
|
||||
CellStyle titleStyle = createStyle(workbook, "黑体", (short) 18, true, HorizontalAlignment.CENTER, false, false);
|
||||
CellStyle unionStyle = createStyle(workbook, "仿宋_GB2312", (short) 14, true, HorizontalAlignment.LEFT, false, false);
|
||||
unionStyle.setBorderBottom(BorderStyle.THIN);
|
||||
CellStyle headerStyle = createStyle(workbook, "宋体", (short) 12, true, HorizontalAlignment.CENTER, true, true);
|
||||
CellStyle bodyStyle = createStyle(workbook, "宋体", (short) 12, false, HorizontalAlignment.CENTER, false, true);
|
||||
|
||||
Row row1 = sheet.createRow(0);
|
||||
row1.setHeightInPoints(32);
|
||||
setCell(row1, 0, "附件12", attachStyle);
|
||||
fillMergedCells(row1, 1, 9, attachStyle);
|
||||
|
||||
Row row2 = sheet.createRow(1);
|
||||
row2.setHeightInPoints(32);
|
||||
setCell(row2, 0, "5天外超出部分疗休养费用由单位承担申请人员汇总表", titleStyle);
|
||||
fillMergedCells(row2, 1, 9, titleStyle);
|
||||
|
||||
Row row3 = sheet.createRow(2);
|
||||
row3.setHeightInPoints(32);
|
||||
setCell(row3, 0, "分工会:" + StrUtil.blankToDefault(unionName, ""), unionStyle);
|
||||
fillMergedCells(row3, 1, 9, unionStyle);
|
||||
|
||||
String[] headers = {"序号", "姓名", "身份证号码", "电话号码", "所属分工会", "所选线路名称", "疗休养时间", "疗休养时长", "疗休养费用总额(元)", "备注"};
|
||||
Row header = sheet.createRow(3);
|
||||
header.setHeightInPoints(43);
|
||||
for (int i = 0; i < headers.length; i++) {
|
||||
setCell(header, i, headers[i], headerStyle);
|
||||
}
|
||||
|
||||
int rowCount = Math.max(list == null ? 0 : list.size(), 20);
|
||||
for (int i = 0; i < rowCount; i++) {
|
||||
Row row = sheet.createRow(i + 4);
|
||||
row.setHeightInPoints(25);
|
||||
NutMap item = list != null && i < list.size() ? list.get(i) : null;
|
||||
setCell(row, 0, String.valueOf(i + 1), bodyStyle);
|
||||
setCell(row, 1, item == null ? "" : item.getString("userName", ""), bodyStyle);
|
||||
setCell(row, 2, item == null ? "" : item.getString("idCard", ""), bodyStyle);
|
||||
setCell(row, 3, item == null ? "" : item.getString("mobile", ""), bodyStyle);
|
||||
setCell(row, 4, item == null ? "" : item.getString("unionName", ""), bodyStyle);
|
||||
setCell(row, 5, item == null ? "" : item.getString("lineName", ""), bodyStyle);
|
||||
setCell(row, 6, item == null ? "" : item.getString("travelPeriod", ""), bodyStyle);
|
||||
setCell(row, 7, item == null ? "" : item.getString("totalDays", ""), bodyStyle);
|
||||
setCell(row, 8, item == null ? "" : item.getString("estimatedCostText", ""), bodyStyle);
|
||||
setCell(row, 9, "", bodyStyle);
|
||||
}
|
||||
return workbook;
|
||||
}
|
||||
|
||||
private CellStyle createStyle(Workbook workbook, String fontName, short fontSize, boolean bold, HorizontalAlignment alignment, boolean wrap, boolean border) {
|
||||
Font font = workbook.createFont();
|
||||
font.setFontName(fontName);
|
||||
font.setFontHeightInPoints(fontSize);
|
||||
font.setBold(bold);
|
||||
|
||||
CellStyle style = workbook.createCellStyle();
|
||||
style.setFont(font);
|
||||
style.setAlignment(alignment);
|
||||
style.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
style.setWrapText(wrap);
|
||||
if (border) {
|
||||
style.setBorderLeft(BorderStyle.THIN);
|
||||
style.setBorderTop(BorderStyle.THIN);
|
||||
style.setBorderRight(BorderStyle.THIN);
|
||||
style.setBorderBottom(BorderStyle.THIN);
|
||||
}
|
||||
return style;
|
||||
}
|
||||
|
||||
private void setCell(Row row, int col, String value, CellStyle style) {
|
||||
Cell cell = row.createCell(col);
|
||||
cell.setCellValue(StrUtil.blankToDefault(value, ""));
|
||||
cell.setCellStyle(style);
|
||||
}
|
||||
|
||||
private void fillMergedCells(Row row, int startCol, int endCol, CellStyle style) {
|
||||
for (int i = startCol; i <= endCol; i++) {
|
||||
setCell(row, i, "", style);
|
||||
}
|
||||
}
|
||||
|
||||
private Integer calcDays(String start, String end) {
|
||||
if (StrUtil.isBlank(start) || StrUtil.isBlank(end)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
LocalDate startDate = LocalDate.parse(start.substring(0, 10));
|
||||
LocalDate endDate = LocalDate.parse(end.substring(0, 10));
|
||||
return Math.toIntExact(ChronoUnit.DAYS.between(startDate, endDate) + 1);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String formatAmount(Object value) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
try {
|
||||
BigDecimal amount = new BigDecimal(String.valueOf(value));
|
||||
return amount.stripTrailingZeros().toPlainString();
|
||||
} catch (Exception e) {
|
||||
return String.valueOf(value);
|
||||
}
|
||||
}
|
||||
|
||||
private Cnd buildQueryCnd(String currentUnionId, Integer startYear, Integer endYear, String keyword, String unionId, String lineId, String travelPeriod, String lineType, String scopeType, Boolean overCostOnly) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("t.delFlag", "=", false);
|
||||
cnd.andEX("t.`year`", ">=", startYear);
|
||||
cnd.andEX("t.`year`", "<=", endYear == null ? LocalDate.now().getYear() : endYear);
|
||||
cnd.andEX("t.unionId", "=", unionId);
|
||||
cnd.andEX("t.lineType", "=", lineType);
|
||||
if (Boolean.TRUE.equals(overCostOnly)) {
|
||||
cnd.and("t.overCostReimbursed", "=", true);
|
||||
}
|
||||
appendLineFilter(cnd, lineId);
|
||||
appendTravelPeriodFilter(cnd, travelPeriod);
|
||||
appendScopeFilter(cnd, currentUnionId, scopeType);
|
||||
appendKeywordFilter(cnd, keyword);
|
||||
return cnd;
|
||||
}
|
||||
|
||||
private Cnd buildSummaryCnd(String currentUnionId, Integer startYear, Integer endYear, String unionId, String lineId, String travelPeriod, String lineType, String scopeType) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("t.delFlag", "=", false);
|
||||
cnd.andEX("t.`year`", ">=", startYear);
|
||||
cnd.andEX("t.`year`", "<=", endYear == null ? LocalDate.now().getYear() : endYear);
|
||||
cnd.andEX("t.unionId", "=", unionId);
|
||||
cnd.andEX("t.lineType", "=", lineType);
|
||||
appendLineFilter(cnd, lineId);
|
||||
appendTravelPeriodFilter(cnd, travelPeriod);
|
||||
appendScopeFilter(cnd, currentUnionId, scopeType);
|
||||
return cnd;
|
||||
}
|
||||
|
||||
private void appendKeywordFilter(Cnd cnd, String keyword) {
|
||||
if (StrUtil.isNotBlank(keyword)) {
|
||||
SqlExpressionGroup group = new SqlExpressionGroup();
|
||||
group.orLike("t.userName", keyword.trim());
|
||||
group.orLike("t.jobNo", keyword.trim());
|
||||
cnd.and(group);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyUnionLedgerScope(Cnd cnd, String currentUnionId) {
|
||||
SqlExpressionGroup group = new SqlExpressionGroup();
|
||||
group.or("t.unionId", "=", currentUnionId);
|
||||
group.or("m.unionId", "=", currentUnionId);
|
||||
cnd.and(group);
|
||||
}
|
||||
|
||||
private void appendScopeFilter(Cnd cnd, String currentUnionId, String scopeType) {
|
||||
if ("ownUnionJoined".equals(scopeType)) {
|
||||
cnd.and("t.unionId", "=", currentUnionId);
|
||||
return;
|
||||
}
|
||||
if ("organizedLineJoined".equals(scopeType)) {
|
||||
cnd.and("m.unionId", "=", currentUnionId);
|
||||
return;
|
||||
}
|
||||
applyUnionLedgerScope(cnd, currentUnionId);
|
||||
}
|
||||
|
||||
private String buildYearCondition(Integer startYear, Integer endYear) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (startYear != null) {
|
||||
builder.append(" AND t.`year` >= ").append(startYear);
|
||||
}
|
||||
if (endYear != null) {
|
||||
builder.append(" AND t.`year` <= ").append(endYear);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private TourLedger fetchScopedLedger(String id) {
|
||||
if (StrUtil.isBlank(id) || StrUtil.isBlank(currentUnionId())) {
|
||||
return null;
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT COUNT(1)
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
WHERE t.delFlag = 0
|
||||
AND t.id = @id
|
||||
AND (t.unionId = @unionId OR m.unionId = @unionId)
|
||||
""");
|
||||
sql.setParam("id", id);
|
||||
sql.setParam("unionId", currentUnionId());
|
||||
sql.setCallback(Sqls.callback.integer());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return sql.getInt() > 0 ? tourLedgerService.fetch(id) : null;
|
||||
}
|
||||
|
||||
private String getTravelPeriod(TourLedger ledger) {
|
||||
if (ledger == null || ledger.getYear() == null || StrUtil.isBlank(ledger.getLineId())) {
|
||||
return "";
|
||||
}
|
||||
if (StrUtil.isNotBlank(ledger.getMatterId())) {
|
||||
Sql exactSql = Sqls.create("""
|
||||
SELECT CASE
|
||||
WHEN IFNULL(travelStartTime, '') <> '' AND IFNULL(travelEndTime, '') <> ''
|
||||
THEN CONCAT(travelStartTime, ' 至 ', travelEndTime)
|
||||
ELSE ''
|
||||
END AS travelPeriod
|
||||
FROM tour_matter
|
||||
WHERE delFlag = 0
|
||||
AND id = @matterId
|
||||
""");
|
||||
exactSql.setParam("matterId", ledger.getMatterId());
|
||||
exactSql.setCallback(Sqls.callback.str());
|
||||
tourLedgerService.dao().execute(exactSql);
|
||||
return exactSql.getString();
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT GROUP_CONCAT(
|
||||
DISTINCT CASE
|
||||
WHEN IFNULL(travelStartTime, '') <> '' AND IFNULL(travelEndTime, '') <> ''
|
||||
THEN CONCAT(travelStartTime, ' 至 ', travelEndTime)
|
||||
ELSE NULL
|
||||
END
|
||||
ORDER BY travelStartTime ASC
|
||||
SEPARATOR ';'
|
||||
) AS travelPeriod
|
||||
FROM tour_matter
|
||||
WHERE delFlag = 0
|
||||
AND `year` = @year
|
||||
AND lineId = @lineId
|
||||
""");
|
||||
sql.setParam("year", ledger.getYear());
|
||||
sql.setParam("lineId", ledger.getLineId());
|
||||
sql.setCallback(Sqls.callback.str());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return sql.getString();
|
||||
}
|
||||
|
||||
private boolean isDirectFamilyUnitLine(TourLedger ledger) {
|
||||
if (ledger == null || StrUtil.isBlank(ledger.getLineId())) {
|
||||
return false;
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT IFNULL(directFamilyUnitLine, 0)
|
||||
FROM tour_line
|
||||
WHERE delFlag = 0
|
||||
AND id = @lineId
|
||||
""");
|
||||
sql.setParam("lineId", ledger.getLineId());
|
||||
sql.setCallback(Sqls.callback.integer());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return sql.getInt() > 0;
|
||||
}
|
||||
|
||||
private boolean isFillBedInfo(TourLedger ledger) {
|
||||
if (ledger == null || StrUtil.isBlank(ledger.getMatterId())) {
|
||||
return true;
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT IFNULL(MAX(s.fillBedInfo), 1)
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_setting s ON s.id = m.settingId AND s.delFlag = 0
|
||||
WHERE t.id = @ledgerId
|
||||
""");
|
||||
sql.setParam("ledgerId", ledger.getId());
|
||||
sql.setCallback(Sqls.callback.integer());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return sql.getInt() > 0;
|
||||
}
|
||||
|
||||
private void appendTravelPeriodFilter(Cnd cnd, String travelPeriod) {
|
||||
if (StrUtil.isBlank(travelPeriod)) {
|
||||
return;
|
||||
}
|
||||
cnd.and("CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime)", "=", travelPeriod);
|
||||
}
|
||||
|
||||
private void appendLineFilter(Cnd cnd, String lineId) {
|
||||
if (StrUtil.isBlank(lineId)) {
|
||||
return;
|
||||
}
|
||||
LineFilter lineFilter = parseLineFilter(lineId);
|
||||
if (lineFilter.getLineId().startsWith("legacy:")) {
|
||||
SqlExpressionGroup legacyGroup = new SqlExpressionGroup();
|
||||
legacyGroup.or("t.lineId", "IS", null);
|
||||
legacyGroup.or("t.lineId", "=", "");
|
||||
cnd.and(legacyGroup);
|
||||
cnd.and("t.lineName", "=", lineFilter.getLineId().substring("legacy:".length()));
|
||||
} else {
|
||||
cnd.and("t.lineId", "=", lineFilter.getLineId());
|
||||
}
|
||||
appendMatterUnionFilter(cnd, lineFilter.getUnionId());
|
||||
}
|
||||
|
||||
private LineFilter parseLineFilter(String value) {
|
||||
int delimiterIndex = value.indexOf("|");
|
||||
if (delimiterIndex < 0) {
|
||||
return new LineFilter(value, null);
|
||||
}
|
||||
return new LineFilter(value.substring(0, delimiterIndex), value.substring(delimiterIndex + 1));
|
||||
}
|
||||
|
||||
private void appendMatterUnionFilter(Cnd cnd, String unionId) {
|
||||
if (unionId == null) {
|
||||
return;
|
||||
}
|
||||
if (StrUtil.isBlank(unionId)) {
|
||||
SqlExpressionGroup group = new SqlExpressionGroup();
|
||||
group.or("m.unionId", "IS", null);
|
||||
group.or("m.unionId", "=", "");
|
||||
cnd.and(group);
|
||||
return;
|
||||
}
|
||||
cnd.and("m.unionId", "=", unionId);
|
||||
}
|
||||
|
||||
private String getCurrentLineName(TourLedger ledger) {
|
||||
if (ledger == null) {
|
||||
return "";
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT CASE
|
||||
WHEN m.id IS NULL THEN COALESCE(NULLIF(l.lineName, ''), t.lineName)
|
||||
ELSE CONCAT(
|
||||
COALESCE(NULLIF(l.lineName, ''), t.lineName),
|
||||
'(',
|
||||
CASE
|
||||
WHEN IFNULL(m.unionId, '') = '' THEN '校工会'
|
||||
ELSE IFNULL(mu.name, '')
|
||||
END,
|
||||
')'
|
||||
)
|
||||
END AS lineName
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
LEFT JOIN sys_union mu ON mu.id = m.unionId
|
||||
WHERE t.id = @ledgerId
|
||||
""");
|
||||
sql.setParam("ledgerId", ledger.getId());
|
||||
sql.setCallback(Sqls.callback.str());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return StrUtil.blankToDefault(sql.getString(), ledger.getLineName());
|
||||
}
|
||||
|
||||
private static class LineFilter {
|
||||
private final String lineId;
|
||||
private final String unionId;
|
||||
|
||||
private LineFilter(String lineId, String unionId) {
|
||||
this.lineId = lineId;
|
||||
this.unionId = unionId;
|
||||
}
|
||||
|
||||
private String getLineId() {
|
||||
return lineId;
|
||||
}
|
||||
|
||||
private String getUnionId() {
|
||||
return unionId;
|
||||
}
|
||||
}
|
||||
|
||||
private String currentUnionId() {
|
||||
return SecurityUtil.getUnionId();
|
||||
}
|
||||
|
||||
private String currentUnionName() {
|
||||
String unionId = currentUnionId();
|
||||
if (StrUtil.isBlank(unionId)) {
|
||||
return "";
|
||||
}
|
||||
Sys_union union = tourLedgerService.dao().fetch(Sys_union.class, unionId);
|
||||
return union == null ? "" : StrUtil.blankToDefault(union.getName(), "");
|
||||
}
|
||||
|
||||
private String getOrderColumn(String orderName) {
|
||||
if ("year".equals(orderName)) {
|
||||
return "t.`year`";
|
||||
}
|
||||
if ("jobNo".equals(orderName)) {
|
||||
return "t.jobNo";
|
||||
}
|
||||
if ("userName".equals(orderName)) {
|
||||
return "t.userName";
|
||||
}
|
||||
if ("lineName".equals(orderName)) {
|
||||
return """
|
||||
CASE
|
||||
WHEN m.id IS NULL THEN COALESCE(NULLIF(l.lineName, ''), t.lineName)
|
||||
ELSE CONCAT(
|
||||
COALESCE(NULLIF(l.lineName, ''), t.lineName),
|
||||
'(',
|
||||
CASE
|
||||
WHEN IFNULL(m.unionId, '') = '' THEN '校工会'
|
||||
ELSE IFNULL(mu.name, '')
|
||||
END,
|
||||
')'
|
||||
)
|
||||
END
|
||||
""";
|
||||
}
|
||||
if ("travelPeriod".equals(orderName)) {
|
||||
return "COALESCE(m.travelStartTime, tp.travelPeriod)";
|
||||
}
|
||||
if ("lineType".equals(orderName)) {
|
||||
return "t.lineType";
|
||||
}
|
||||
if ("signupTime".equals(orderName)) {
|
||||
return "t.signupTime";
|
||||
}
|
||||
if ("familyCount".equals(orderName)) {
|
||||
return "familyCount";
|
||||
}
|
||||
if ("joined".equals(orderName)) {
|
||||
return "t.joined";
|
||||
}
|
||||
return "t.`year`";
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.mode;
|
||||
|
||||
import cn.afterturn.easypoi.excel.annotation.Excel;
|
||||
import com.budwk.app.base.model.ExcelImportError;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class TourLedgerImportExcelMode extends ExcelImportError {
|
||||
|
||||
@Excel(name = "年度")
|
||||
private Integer year;
|
||||
|
||||
@Excel(name = "工号")
|
||||
private String jobNo;
|
||||
|
||||
@Excel(name = "姓名")
|
||||
private String userName;
|
||||
|
||||
@Excel(name = "报名时间", format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date signupTime;
|
||||
|
||||
@Excel(name = "线路名称")
|
||||
private String lineName;
|
||||
|
||||
@Excel(name = "线路类型")
|
||||
private String lineType;
|
||||
|
||||
@Excel(name = "是否参加")
|
||||
private String joined;
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.models;
|
||||
|
||||
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;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 疗休养教职工报名台账。
|
||||
* 后续报名模块完成后,将已报名或已参加的教职工写入本表,台账页负责跨年度查询和详情查看。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Table("tour_ledger")
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("普惠疗休养台账")
|
||||
public class TourLedger extends BaseModel implements Serializable {
|
||||
|
||||
@Column
|
||||
@Name
|
||||
@Comment("ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@PrevInsert(uu32 = true)
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("年度")
|
||||
@ColDefine(type = ColType.INT, width = 4)
|
||||
private Integer year;
|
||||
|
||||
@Column
|
||||
@Comment("工号")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String jobNo;
|
||||
|
||||
@Column
|
||||
@Comment("姓名")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String userName;
|
||||
|
||||
@Column
|
||||
@Comment("性别")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
private String gender;
|
||||
|
||||
@Column
|
||||
@Comment("身份证号")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
private String idCard;
|
||||
|
||||
@Column
|
||||
@Comment("所在单位ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String unitId;
|
||||
|
||||
@Column
|
||||
@Comment("所在单位")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String unitName;
|
||||
|
||||
@Column
|
||||
@Comment("所在工会ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String unionId;
|
||||
|
||||
@Column
|
||||
@Comment("所在工会")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String unionName;
|
||||
|
||||
@Column
|
||||
@Comment("报名时间")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
private String signupTime;
|
||||
|
||||
@Column
|
||||
@Comment("报名事项ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String matterId;
|
||||
|
||||
@Column
|
||||
@Comment("报名线路ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String lineId;
|
||||
|
||||
@Column
|
||||
@Comment("报名线路")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String lineName;
|
||||
|
||||
@Column
|
||||
@Comment("线路类型")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String lineType;
|
||||
|
||||
@Column
|
||||
@Comment("报名酒店")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String hotelName;
|
||||
|
||||
@Column
|
||||
@Comment("旅行社ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String travelAgencyId;
|
||||
|
||||
@Column
|
||||
@Comment("旅行社")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String travelAgencyName;
|
||||
|
||||
@Column
|
||||
@Comment("是否携带家属")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Default("0")
|
||||
private Boolean hasFamily;
|
||||
|
||||
@Column
|
||||
@Comment("意向拼床人")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String intendedRoommate;
|
||||
|
||||
@Column
|
||||
@Comment("床型")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String bedType;
|
||||
|
||||
@Column
|
||||
@Comment("床位信息")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String bedInfo;
|
||||
|
||||
@Column
|
||||
@Comment("是否参加")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Default("0")
|
||||
private Boolean joined;
|
||||
|
||||
@Column
|
||||
@Comment("是否报销")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Default("0")
|
||||
private Boolean reimbursed;
|
||||
|
||||
@Column
|
||||
@Comment("报销超出费用")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Default("0")
|
||||
private Boolean overCostReimbursed;
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.models;
|
||||
|
||||
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;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 直系亲属线路报名信息。
|
||||
* 与普通携带亲属信息分表存放,用于直系亲属线路的专属申请信息。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Table("tour_ledger_direct_relative")
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("普惠疗休养直系亲属线路报名信息")
|
||||
public class TourLedgerDirectRelative extends BaseModel implements Serializable {
|
||||
|
||||
@Column
|
||||
@Name
|
||||
@Comment("ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@PrevInsert(uu32 = true)
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("台账ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String ledgerId;
|
||||
|
||||
@Column
|
||||
@Comment("亲属姓名")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String relativeName;
|
||||
|
||||
@Column
|
||||
@Comment("所在单位")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String unitName;
|
||||
|
||||
@Column
|
||||
@Comment("亲属关系编码")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String relationshipCode;
|
||||
|
||||
@Column
|
||||
@Comment("亲属关系")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String relationshipName;
|
||||
|
||||
@Column
|
||||
@Comment("线路ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String lineId;
|
||||
|
||||
@Column
|
||||
@Comment("线路名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String lineName;
|
||||
|
||||
@Column
|
||||
@Comment("出行开始日期")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
private String travelStartTime;
|
||||
|
||||
@Column
|
||||
@Comment("出行结束日期")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
private String travelEndTime;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.models;
|
||||
|
||||
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;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 疗休养台账家属信息。
|
||||
* 与教职工台账通过 ledgerId 关联,用于查看教职工携带家属的历史记录。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Table("tour_ledger_family")
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("普惠疗休养台账家属信息")
|
||||
public class TourLedgerFamily extends BaseModel implements Serializable {
|
||||
|
||||
@Column
|
||||
@Name
|
||||
@Comment("ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@PrevInsert(uu32 = true)
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("台账ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String ledgerId;
|
||||
|
||||
@Column
|
||||
@Comment("教职工工号")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String staffJobNo;
|
||||
|
||||
@Column
|
||||
@Comment("教职工姓名")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String staffName;
|
||||
|
||||
@Column
|
||||
@Comment("家属姓名")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String familyName;
|
||||
|
||||
@Column
|
||||
@Comment("性别")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
private String gender;
|
||||
|
||||
@Column
|
||||
@Comment("身份证号码")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
private String idCard;
|
||||
|
||||
@Column
|
||||
@Comment("年龄")
|
||||
@ColDefine(type = ColType.INT, width = 3)
|
||||
private Integer age;
|
||||
|
||||
@Column
|
||||
@Comment("床型")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String bedType;
|
||||
|
||||
@Column
|
||||
@Comment("床位")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String bedInfo;
|
||||
|
||||
@Column
|
||||
@Comment("意向拼床人")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String intendedRoommate;
|
||||
|
||||
@Column
|
||||
@Comment("关系")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String relationship;
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.models;
|
||||
|
||||
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;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 疗休养线路管理。
|
||||
* 当前阶段先维护线路基础信息,后续报名、台账等模块可通过线路ID继续关联。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Table("tour_line")
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("普惠疗休养线路")
|
||||
public class TourLine extends BaseModel implements Serializable {
|
||||
|
||||
@Column
|
||||
@Name
|
||||
@Comment("ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@PrevInsert(uu32 = true)
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("创建年度")
|
||||
@ColDefine(type = ColType.INT, width = 4)
|
||||
private Integer year;
|
||||
|
||||
@Column
|
||||
@Comment("线路编号")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String lineCode;
|
||||
|
||||
@Column
|
||||
@Comment("线路名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String lineName;
|
||||
|
||||
@Column
|
||||
@Comment("旅行社ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String travelAgencyId;
|
||||
|
||||
@Column
|
||||
@Comment("创建人ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String creatorUserId;
|
||||
|
||||
@Column
|
||||
@Comment("创建人")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String creatorName;
|
||||
|
||||
@Column
|
||||
@Comment("所在单位ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String unitId;
|
||||
|
||||
@Column
|
||||
@Comment("所在单位")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String unitName;
|
||||
|
||||
@Column
|
||||
@Comment("线路类型")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String lineType;
|
||||
|
||||
@Column
|
||||
@Comment("时间标段ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String lotId;
|
||||
|
||||
@Column
|
||||
@Comment("线路内容")
|
||||
@ColDefine(type = ColType.TEXT)
|
||||
private String lineContent;
|
||||
|
||||
@Column
|
||||
@Comment("移动端缩略图")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 500)
|
||||
private String mobileThumb;
|
||||
|
||||
@Column
|
||||
@Comment("是否对外开放")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Default("1")
|
||||
private Boolean openFlag;
|
||||
|
||||
@Column
|
||||
@Comment("是否直系亲属线路")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Default("0")
|
||||
private Boolean directFamilyUnitLine;
|
||||
|
||||
@Column
|
||||
@Comment("激活状态")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Default("1")
|
||||
private Boolean enabled;
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.models;
|
||||
|
||||
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;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 疗休养事项。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Table("tour_matter")
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("普惠疗休养事项")
|
||||
public class TourMatter extends BaseModel implements Serializable {
|
||||
|
||||
@Column
|
||||
@Name
|
||||
@Comment("ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@PrevInsert(uu32 = true)
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("年度")
|
||||
@ColDefine(type = ColType.INT, width = 4)
|
||||
private Integer year;
|
||||
|
||||
@Column
|
||||
@Comment("事项名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String matterName;
|
||||
|
||||
@Column
|
||||
@Comment("疗休养配置ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String settingId;
|
||||
|
||||
@Column
|
||||
@Comment("创建人ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String creatorUserId;
|
||||
|
||||
@Column
|
||||
@Comment("创建人")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String creatorName;
|
||||
|
||||
@Column
|
||||
@Comment("所属工会ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String unionId;
|
||||
|
||||
@Column
|
||||
@Comment("组织形式")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String organizationType;
|
||||
|
||||
@Column
|
||||
@Comment("移动端缩略图")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 500)
|
||||
private String mobileThumb;
|
||||
|
||||
@Column
|
||||
@Comment("线路ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String lineId;
|
||||
|
||||
@Column
|
||||
@Comment("报名开始时间")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
private String signupStartTime;
|
||||
|
||||
@Column
|
||||
@Comment("报名结束时间")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
private String signupEndTime;
|
||||
|
||||
@Column
|
||||
@Comment("出行开始时间")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
private String travelStartTime;
|
||||
|
||||
@Column
|
||||
@Comment("出行结束时间")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
private String travelEndTime;
|
||||
|
||||
@Column
|
||||
@Comment("联系人")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
private String contactName;
|
||||
|
||||
@Column
|
||||
@Comment("联系方式")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
private String contactPhone;
|
||||
|
||||
@Column
|
||||
@Comment("最少成团人数")
|
||||
@ColDefine(type = ColType.INT)
|
||||
private Integer minGroupPeople;
|
||||
|
||||
@Column
|
||||
@Comment("最多成团人数")
|
||||
@ColDefine(type = ColType.INT)
|
||||
private Integer maxGroupPeople;
|
||||
|
||||
@Column
|
||||
@Comment("预计费用")
|
||||
@ColDefine(customType = "decimal(10,2)")
|
||||
private BigDecimal estimatedCost;
|
||||
|
||||
@Column
|
||||
@Comment("事项状态")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Default("1")
|
||||
private Boolean enabled;
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.models;
|
||||
|
||||
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;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 疗休养基础配置。
|
||||
* 这里先沉淀创建事项会复用的基础字段,后续线路、报名等阶段可以继续通过配置ID关联扩展。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Table("tour_setting")
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("普惠疗休养配置")
|
||||
public class TourSetting extends BaseModel implements Serializable {
|
||||
|
||||
@Column
|
||||
@Name
|
||||
@Comment("ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@PrevInsert(uu32 = true)
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("年度")
|
||||
@ColDefine(type = ColType.INT, width = 4)
|
||||
private Integer year;
|
||||
|
||||
@Column
|
||||
@Comment("疗休养配置名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String configName;
|
||||
|
||||
@Column
|
||||
@Comment("疗休养类型")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String tourType;
|
||||
|
||||
@Column
|
||||
@Comment("可参加人员范围ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String activityGroupId;
|
||||
|
||||
@Column
|
||||
@Comment("排序编号")
|
||||
@ColDefine(type = ColType.INT)
|
||||
private Integer sortNo;
|
||||
|
||||
@Column
|
||||
@Comment("最少成团人数")
|
||||
@ColDefine(type = ColType.INT)
|
||||
private Integer minGroupPeople;
|
||||
|
||||
@Column
|
||||
@Comment("最多成团人数")
|
||||
@ColDefine(type = ColType.INT)
|
||||
private Integer maxGroupPeople;
|
||||
|
||||
@Column
|
||||
@Comment("省外几年去一次")
|
||||
@ColDefine(type = ColType.INT)
|
||||
private Integer outProvinceYears;
|
||||
|
||||
@Column
|
||||
@Comment("省外人数占比")
|
||||
@ColDefine(customType = "decimal(10,2)")
|
||||
private BigDecimal outProvinceRatio;
|
||||
|
||||
@Column
|
||||
@Comment("省外人数占比类型")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String outProvinceRatioType;
|
||||
|
||||
@Column
|
||||
@Comment("省外固定人数")
|
||||
@ColDefine(type = ColType.INT)
|
||||
private Integer outProvinceFixedPeople;
|
||||
|
||||
@Column
|
||||
@Comment("周期开始年度")
|
||||
@ColDefine(type = ColType.INT, width = 4)
|
||||
private Integer cycleStartYear;
|
||||
|
||||
@Column
|
||||
@Comment("周期结束年度")
|
||||
@ColDefine(type = ColType.INT, width = 4)
|
||||
private Integer cycleEndYear;
|
||||
|
||||
@Column
|
||||
@Comment("周期内总费用")
|
||||
@ColDefine(type = ColType.INT)
|
||||
private Integer cycleTotalCost;
|
||||
|
||||
@Column
|
||||
@Comment("周期允许次数")
|
||||
@ColDefine(type = ColType.INT)
|
||||
private Integer cycleAllowedTimes;
|
||||
|
||||
@Column
|
||||
@Comment("是否允许携带家属")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Default("0")
|
||||
private Boolean allowFamily;
|
||||
|
||||
@Column
|
||||
@Comment("是否填报床位信息")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Default("1")
|
||||
private Boolean fillBedInfo;
|
||||
|
||||
@Column
|
||||
@Comment("是否启用")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Default("1")
|
||||
private Boolean enabled;
|
||||
|
||||
/**
|
||||
* 标段管理沿用老疗休养配置的子表设计,后续线路、旅行社等模块可通过标段ID继续关联。
|
||||
*/
|
||||
@Many(field = "settingId")
|
||||
private List<TourSettingLot> lots;
|
||||
|
||||
@Column
|
||||
@Comment("服务须知")
|
||||
@ColDefine(type = ColType.TEXT)
|
||||
private String serviceNotice;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.models;
|
||||
|
||||
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;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 疗休养配置标段。
|
||||
* 标段从基础配置中拆成子表,便于后续线路、目的地、报名等模块复用同一标段口径。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Table("tour_setting_lot")
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("普惠疗休养配置标段")
|
||||
public class TourSettingLot extends BaseModel implements Serializable {
|
||||
|
||||
@Column
|
||||
@Name
|
||||
@Comment("ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@PrevInsert(uu32 = true)
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("所属配置ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String settingId;
|
||||
|
||||
@Column
|
||||
@Comment("标段名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String lotName;
|
||||
|
||||
@Column
|
||||
@Comment("标段值")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String lotValue;
|
||||
|
||||
@Column
|
||||
@Comment("标段费用")
|
||||
@ColDefine(type = ColType.INT)
|
||||
private Integer activityCost;
|
||||
|
||||
@Column
|
||||
@Comment("允许超出报销")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
private Boolean allowOverReimbursement;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.models;
|
||||
|
||||
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;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 旅行社管理。
|
||||
* 先维护疗休养线路创建会复用的旅行社基础信息,后续线路模块可通过旅行社ID关联。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Table("tour_travel_agency")
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("普惠疗休养旅行社")
|
||||
public class TourTravelAgency extends BaseModel implements Serializable {
|
||||
|
||||
@Column
|
||||
@Name
|
||||
@Comment("ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@PrevInsert(uu32 = true)
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("年度")
|
||||
@ColDefine(type = ColType.INT, width = 4)
|
||||
private Integer year;
|
||||
|
||||
@Column
|
||||
@Comment("旅行社编号")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String agencyCode;
|
||||
|
||||
@Column
|
||||
@Comment("旅行社名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String agencyName;
|
||||
|
||||
@Column
|
||||
@Comment("联系人")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
private String contactName;
|
||||
|
||||
@Column
|
||||
@Comment("联系人手机")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
private String contactPhone;
|
||||
|
||||
@Column
|
||||
@Comment("邮箱")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String email;
|
||||
|
||||
@Column
|
||||
@Comment("备注")
|
||||
@ColDefine(type = ColType.TEXT)
|
||||
private String remark;
|
||||
|
||||
@Column
|
||||
@Comment("移动端缩略图")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 500)
|
||||
private String mobileThumb;
|
||||
|
||||
@Column
|
||||
@Comment("激活状态")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Default("1")
|
||||
private Boolean enabled;
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedgerDirectRelative;
|
||||
|
||||
public interface TourLedgerDirectRelativeService extends BaseService<TourLedgerDirectRelative> {
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedgerFamily;
|
||||
|
||||
public interface TourLedgerFamilyService extends BaseService<TourLedgerFamily> {
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedger;
|
||||
|
||||
public interface TourLedgerService extends BaseService<TourLedger> {
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLine;
|
||||
|
||||
public interface TourLineService extends BaseService<TourLine> {
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourMatter;
|
||||
|
||||
public interface TourMatterService extends BaseService<TourMatter> {
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourSetting;
|
||||
|
||||
public interface TourSettingService extends BaseService<TourSetting> {
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourTravelAgency;
|
||||
|
||||
public interface TourTravelAgencyService extends BaseService<TourTravelAgency> {
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.service.impl;
|
||||
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedgerDirectRelative;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerDirectRelativeService;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class TourLedgerDirectRelativeServiceImpl extends BaseServiceImpl<TourLedgerDirectRelative> implements TourLedgerDirectRelativeService {
|
||||
|
||||
public TourLedgerDirectRelativeServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.service.impl;
|
||||
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedgerFamily;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerFamilyService;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class TourLedgerFamilyServiceImpl extends BaseServiceImpl<TourLedgerFamily> implements TourLedgerFamilyService {
|
||||
|
||||
public TourLedgerFamilyServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.service.impl;
|
||||
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedger;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerService;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class TourLedgerServiceImpl extends BaseServiceImpl<TourLedger> implements TourLedgerService {
|
||||
|
||||
public TourLedgerServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.service.impl;
|
||||
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLine;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLineService;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class TourLineServiceImpl extends BaseServiceImpl<TourLine> implements TourLineService {
|
||||
|
||||
public TourLineServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.service.impl;
|
||||
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourMatter;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourMatterService;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class TourMatterServiceImpl extends BaseServiceImpl<TourMatter> implements TourMatterService {
|
||||
|
||||
public TourMatterServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.service.impl;
|
||||
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourSetting;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourSettingService;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class TourSettingServiceImpl extends BaseServiceImpl<TourSetting> implements TourSettingService {
|
||||
|
||||
public TourSettingServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.service.impl;
|
||||
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourTravelAgency;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourTravelAgencyService;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class TourTravelAgencyServiceImpl extends BaseServiceImpl<TourTravelAgency> implements TourTravelAgencyService {
|
||||
|
||||
public TourTravelAgencyServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user