1
This commit is contained in:
@@ -309,9 +309,9 @@ public class SysUserServiceImpl extends BaseServiceImpl<Sys_user> implements Sys
|
||||
String decodePwd = Base64Decoder.decodeStr(passowrd);
|
||||
String hashedPassword = PwdUtil.getPassword(decodePwd, user.getSalt());
|
||||
if (!Strings.sNull(hashedPassword).equalsIgnoreCase(user.getPassword())) {
|
||||
if (Globals.sso) {
|
||||
// if (Globals.sso) {
|
||||
throw new BaseException("用户名或者密码不正确");
|
||||
}
|
||||
// }
|
||||
}
|
||||
user = this.fetchLinks(user, "unit");
|
||||
if (Lang.isNotEmpty(user.getUnit()) && StrUtil.isNotBlank(user.getUnit().getUnionId())) {
|
||||
|
||||
+2
-2
@@ -115,7 +115,7 @@ public class ActivityBasicScopeController {
|
||||
""");
|
||||
try {
|
||||
Cnd cnd = getCnd(pageForm);
|
||||
cnd.and("u.member", "=", 1);
|
||||
// cnd.and("u.member", "=", 1);
|
||||
sql.setCondition(cnd);
|
||||
Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
return Result.success(pagination);
|
||||
@@ -393,7 +393,7 @@ public class ActivityBasicScopeController {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
cnd.and("u.member", "=", 1);
|
||||
// cnd.and("u.member", "=", 1);
|
||||
return cnd;
|
||||
|
||||
}
|
||||
|
||||
+115
-12
@@ -169,16 +169,53 @@ public class TourGroupController {
|
||||
return Result.success(sql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前事项线路下已经写入疗休养台账的成团信息,供线路成团查看页展示团标签。
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("tour.group")
|
||||
public Result signupPageData(PageForm pageForm, String matterId, String keyword, String unionId) {
|
||||
public Result groupOptions(String matterId) {
|
||||
if (StrUtil.isBlank(matterId)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
Cnd cnd = buildGroupOptionCnd(matterId);
|
||||
return Result.success(tourLedgerService.queryGroupOptions(cnd));
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动将当前事项线路下未成团的报名人员按最大成团人数分配成团。
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("tour.group")
|
||||
public Result assignGroup(String matterId) {
|
||||
if (StrUtil.isBlank(matterId)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
return tourLedgerService.assignGroup(matterId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将勾选的教职工报名台账调整到指定成团中,家属随教职工一起调整。
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("tour.group")
|
||||
public Result adjustGroup(String matterId, String groupCode, String ledgerIds) {
|
||||
if (StrUtil.isBlank(matterId) || StrUtil.isBlank(groupCode) || StrUtil.isBlank(ledgerIds)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
return tourLedgerService.adjustGroup(matterId, groupCode, ledgerIds);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.group")
|
||||
public Result signupPageData(PageForm pageForm, String matterId, String keyword, String unionId, String groupCode) {
|
||||
if (StrUtil.isBlank(matterId)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
if (StrUtil.isBlank(pageForm.getPageOrderName())) {
|
||||
pageForm.defaultSortDesc("signupTime");
|
||||
pageForm.defaultSortAsc("groupCode");
|
||||
}
|
||||
Cnd cnd = buildSignupQueryCnd(matterId, keyword, unionId);
|
||||
Cnd cnd = buildSignupQueryCnd(matterId, keyword, unionId, groupCode);
|
||||
Sql countSql = Sqls.create("""
|
||||
SELECT COUNT(1)
|
||||
FROM tour_ledger t
|
||||
@@ -196,16 +233,27 @@ public class TourGroupController {
|
||||
t.id,
|
||||
t.jobNo,
|
||||
t.userName,
|
||||
t.gender,
|
||||
'' AS mobile,
|
||||
t.idCard,
|
||||
t.unionId,
|
||||
t.unionName,
|
||||
t.signupTime
|
||||
t.signupTime,
|
||||
t.groupCode,
|
||||
t.groupName,
|
||||
IFNULL(f.familyCount, 0) AS familyCount,
|
||||
1 + IFNULL(f.familyCount, 0) AS totalPeople
|
||||
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 (
|
||||
SELECT ledgerId, COUNT(1) AS familyCount
|
||||
FROM tour_ledger_family
|
||||
WHERE delFlag = 0
|
||||
GROUP BY ledgerId
|
||||
) f ON f.ledgerId = t.id
|
||||
$condition
|
||||
ORDER BY $orderColumn $orderBy, t.signupTime DESC, t.createdAt DESC
|
||||
ORDER BY $orderColumn $orderBy, t.signupTime ASC, t.createdAt ASC
|
||||
""");
|
||||
listSql.setCondition(cnd);
|
||||
listSql.setVar("orderColumn", getSignupOrderColumn(pageForm.getPageOrderName()));
|
||||
@@ -216,11 +264,30 @@ public class TourGroupController {
|
||||
|
||||
List<NutMap> list = listSql.getList(NutMap.class);
|
||||
fillSignupMobile(list);
|
||||
fillSignupFamilies(list);
|
||||
flattenSignupFamilies(list);
|
||||
Pagination<NutMap> pagination = new Pagination<>(pageForm.getPageNumber(), pageForm.getPageSize(), count, list);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造成团标签查询条件:只取当前事项线路已分配成团编码的台账,并保持与列表一致的数据权限。
|
||||
*/
|
||||
private Cnd buildGroupOptionCnd(String matterId) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("t.delFlag", "=", false);
|
||||
cnd.and("t.matterId", "=", matterId);
|
||||
cnd.and("t.groupCode", "IS NOT", null);
|
||||
cnd.and("t.groupCode", "<>", "");
|
||||
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);
|
||||
applyMatterDataScope(cnd);
|
||||
return cnd;
|
||||
}
|
||||
|
||||
@At
|
||||
@Ok("void")
|
||||
@SaCheckPermission("tour.group")
|
||||
@@ -238,7 +305,7 @@ public class TourGroupController {
|
||||
CommonDownloadUtil.download(lineName + "参加人员名单.xls", workbook, response);
|
||||
}
|
||||
|
||||
private Cnd buildSignupQueryCnd(String matterId, String keyword, String unionId) {
|
||||
private Cnd buildSignupQueryCnd(String matterId, String keyword, String unionId, String groupCode) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("t.delFlag", "=", false);
|
||||
cnd.and("t.matterId", "=", matterId);
|
||||
@@ -255,6 +322,8 @@ public class TourGroupController {
|
||||
cnd.and(keywordGroup);
|
||||
}
|
||||
cnd.andEX("t.unionId", "=", unionId);
|
||||
// 团标签联动查询时只筛选当前团;未选择团标签时默认查询全部报名人员。
|
||||
cnd.andEX("t.groupCode", "=", groupCode);
|
||||
applyMatterDataScope(cnd);
|
||||
return cnd;
|
||||
}
|
||||
@@ -297,7 +366,7 @@ public class TourGroupController {
|
||||
}
|
||||
|
||||
private List<NutMap> queryExportParticipants(String matterId) {
|
||||
Cnd cnd = buildSignupQueryCnd(matterId, null, null);
|
||||
Cnd cnd = buildSignupQueryCnd(matterId, null, null, null);
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
t.id AS ledgerId,
|
||||
@@ -515,9 +584,9 @@ public class TourGroupController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看成团报名人员时按台账ID带出家属子列表,避免前端逐行请求家属信息。
|
||||
* 查看成团报名人员时将教职工和家属平铺在同一个列表,便于前端统一展示。
|
||||
*/
|
||||
private void fillSignupFamilies(List<NutMap> list) {
|
||||
private void flattenSignupFamilies(List<NutMap> list) {
|
||||
if (list == null || list.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@@ -535,8 +604,9 @@ public class TourGroupController {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
ledgerId,
|
||||
staffJobNo AS jobNo,
|
||||
'' AS jobNo,
|
||||
familyName AS userName,
|
||||
gender,
|
||||
'' AS mobile,
|
||||
idCard,
|
||||
relationship
|
||||
@@ -551,11 +621,35 @@ public class TourGroupController {
|
||||
|
||||
Map<String, List<NutMap>> familyMap = new HashMap<>();
|
||||
for (NutMap family : sql.getList(NutMap.class)) {
|
||||
family.put("staffRow", false);
|
||||
family.put("selectable", false);
|
||||
family.put("rowTypeName", "家属");
|
||||
family.put("unionName", "");
|
||||
family.put("groupCode", "");
|
||||
family.put("groupName", "");
|
||||
family.put("totalPeople", "");
|
||||
familyMap.computeIfAbsent(family.getString("ledgerId", ""), key -> new ArrayList<>()).add(family);
|
||||
}
|
||||
List<NutMap> flatList = new ArrayList<>();
|
||||
for (NutMap item : list) {
|
||||
item.put("families", familyMap.getOrDefault(item.getString("id", ""), List.of()));
|
||||
// 教职工是后续人员调整的最小可选单位,家属随教职工一起分配。
|
||||
item.put("staffRow", true);
|
||||
item.put("selectable", true);
|
||||
item.put("rowTypeName", "教职工");
|
||||
item.put("relationship", "");
|
||||
item.put("relatedStaffName", item.getString("userName", ""));
|
||||
flatList.add(item);
|
||||
List<NutMap> families = familyMap.getOrDefault(item.getString("id", ""), List.of());
|
||||
for (NutMap family : families) {
|
||||
// 家属行通过关联教职工名称标明所属教职工,便于单层列表中识别家庭关系。
|
||||
family.put("relatedStaffName", item.getString("userName", ""));
|
||||
family.put("groupCode", item.getString("groupCode", ""));
|
||||
family.put("groupName", item.getString("groupName", ""));
|
||||
}
|
||||
flatList.addAll(families);
|
||||
}
|
||||
list.clear();
|
||||
list.addAll(flatList);
|
||||
}
|
||||
|
||||
private Cnd buildQueryCnd(Integer year, String lineName, String lineType, String unionId) {
|
||||
@@ -662,12 +756,21 @@ public class TourGroupController {
|
||||
if ("userName".equals(orderName)) {
|
||||
return "t.userName";
|
||||
}
|
||||
if ("gender".equals(orderName)) {
|
||||
return "t.gender";
|
||||
}
|
||||
if ("idCard".equals(orderName)) {
|
||||
return "t.idCard";
|
||||
}
|
||||
if ("unionName".equals(orderName)) {
|
||||
return "t.unionName";
|
||||
}
|
||||
if ("groupCode".equals(orderName) || "groupName".equals(orderName)) {
|
||||
return "t.groupCode";
|
||||
}
|
||||
if ("totalPeople".equals(orderName)) {
|
||||
return "totalPeople";
|
||||
}
|
||||
return "t.signupTime";
|
||||
}
|
||||
}
|
||||
|
||||
+86
-6
@@ -1,5 +1,9 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.controller;
|
||||
|
||||
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.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
@@ -7,6 +11,7 @@ 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_dict;
|
||||
import com.budwk.app.sys.services.SysDictService;
|
||||
import com.budwk.app.sys.views.View_user;
|
||||
@@ -26,7 +31,10 @@ 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.apache.poi.ss.usermodel.Workbook;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -36,8 +44,6 @@ import java.util.stream.Collectors;
|
||||
@At("/platform/tour/route")
|
||||
public class TourLineController {
|
||||
|
||||
private static final String SORT_CODE_PATTERN = "^\\d+$";
|
||||
|
||||
@Inject
|
||||
private TourLineService tourLineService;
|
||||
|
||||
@@ -52,7 +58,7 @@ public class TourLineController {
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.route")
|
||||
public Result pageData(PageForm pageForm, Integer year, String lineName, String lotId) {
|
||||
public Result pageData(PageForm pageForm, Integer year, String lineName, String lotId, String lineType) {
|
||||
if (StrUtil.isBlank(pageForm.getPageOrderName())) {
|
||||
pageForm.defaultSortAsc("lineCode");
|
||||
}
|
||||
@@ -62,6 +68,8 @@ public class TourLineController {
|
||||
cnd.andEX("l.`year`", "=", year);
|
||||
cnd.and(Cnd.likeEX("l.lineName", lineName));
|
||||
cnd.andEX("l.lotId", "=", lotId);
|
||||
// 线路类型查询使用线路表保存的字典名称,和新增/编辑线路时的取值保持一致。
|
||||
cnd.andEX("l.lineType", "=", lineType);
|
||||
boolean sysAdmin = AuthUtil.hasRole(RoleConstant.SYSADMIN.name());
|
||||
boolean branchUnionScope = !sysAdmin && AuthUtil.hasRole(RoleConstant.BRANCH_UNION_CHAIRMAN.name());
|
||||
applyDataScope(cnd, sysAdmin, branchUnionScope);
|
||||
@@ -107,6 +115,78 @@ public class TourLineController {
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出线路关联事项数据,导出范围复用线路管理列表的筛选条件和数据权限。
|
||||
*/
|
||||
@At
|
||||
@Ok("void")
|
||||
@SaCheckPermission("tour.route")
|
||||
public void exportData(Integer year, String lineName, String lotId, String lineType, HttpServletResponse response) {
|
||||
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);
|
||||
// 导出范围复用列表筛选条件,线路类型也要同步过滤。
|
||||
cnd.andEX("l.lineType", "=", lineType);
|
||||
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 sql = Sqls.create("""
|
||||
SELECT
|
||||
l.`year`,
|
||||
l.lineName,
|
||||
lot.lotName,
|
||||
l.lineType,
|
||||
m.matterName,
|
||||
CASE
|
||||
WHEN IFNULL(m.signupStartTime, '') <> '' AND IFNULL(m.signupEndTime, '') <> ''
|
||||
THEN CONCAT(m.signupStartTime, ' 至 ', m.signupEndTime)
|
||||
ELSE ''
|
||||
END AS signupTime,
|
||||
CASE
|
||||
WHEN IFNULL(m.travelStartTime, '') <> '' AND IFNULL(m.travelEndTime, '') <> ''
|
||||
THEN CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime)
|
||||
ELSE ''
|
||||
END AS travelTime,
|
||||
m.contactName,
|
||||
m.contactPhone
|
||||
FROM tour_line l
|
||||
LEFT JOIN tour_setting_lot lot ON lot.id = l.lotId
|
||||
LEFT JOIN tour_matter m ON l.id = m.lineId AND m.delFlag = 0
|
||||
$creatorJoin
|
||||
$condition
|
||||
ORDER BY CAST(l.lineCode AS UNSIGNED) ASC, l.lineCode ASC, m.matterName ASC, l.lineName ASC
|
||||
""");
|
||||
sql.setVar("creatorJoin", creatorJoin);
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourLineService.dao().execute(sql);
|
||||
|
||||
List<ExcelExportEntity> entities = new ArrayList<>();
|
||||
entities.add(new ExcelExportEntity("创建年度", "year", 14));
|
||||
entities.add(new ExcelExportEntity("线路名称", "lineName", 30));
|
||||
entities.add(new ExcelExportEntity("时间标段", "lotName", 18));
|
||||
entities.add(new ExcelExportEntity("路线类型", "lineType", 18));
|
||||
entities.add(new ExcelExportEntity("事项名称", "matterName", 30));
|
||||
entities.add(new ExcelExportEntity("报名时间", "signupTime", 34));
|
||||
entities.add(new ExcelExportEntity("出行时间", "travelTime", 24));
|
||||
entities.add(new ExcelExportEntity("联系人", "contactName", 16));
|
||||
entities.add(new ExcelExportEntity("联系方式", "contactPhone", 18));
|
||||
|
||||
ExportParams exportParams = new ExportParams();
|
||||
exportParams.setType(ExcelType.XSSF);
|
||||
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entities, sql.getList(NutMap.class));
|
||||
CommonDownloadUtil.download("线路事项数据.xlsx", workbook, response);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.route")
|
||||
public Result detail(String id) {
|
||||
@@ -253,11 +333,11 @@ public class TourLineController {
|
||||
if (StrUtil.isBlank(line.getLineName())) {
|
||||
return Result.error("线路名称不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(line.getLineCode())) {
|
||||
if (line.getLineCode() == null) {
|
||||
return Result.error("排序编号不能为空");
|
||||
}
|
||||
if (!line.getLineCode().matches(SORT_CODE_PATTERN)) {
|
||||
return Result.error("排序编号必须为整数");
|
||||
if (line.getLineCode() < 0) {
|
||||
return Result.error("排序编号不能小于0");
|
||||
}
|
||||
if (StrUtil.isBlank(line.getLineType())) {
|
||||
return Result.error("线路类型不能为空");
|
||||
|
||||
+155
-23
@@ -1,12 +1,17 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
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.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.base.utils.CommonDownloadUtil;
|
||||
import com.budwk.app.sys.models.Sys_dict;
|
||||
import com.budwk.app.sys.models.Sys_union;
|
||||
import com.budwk.app.sys.services.SysDictService;
|
||||
@@ -27,7 +32,10 @@ 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.apache.poi.ss.usermodel.Workbook;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -53,18 +61,13 @@ public class TourMatterController {
|
||||
|
||||
@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);
|
||||
public Result pageData(PageForm pageForm, Integer year, String matterName, String unionId, String organizationType, String lineType) {
|
||||
Cnd cnd = buildMatterPageCnd(year, matterName, unionId, organizationType, lineType);
|
||||
|
||||
Sql countSql = Sqls.create("""
|
||||
SELECT COUNT(1)
|
||||
FROM tour_matter m
|
||||
LEFT JOIN tour_line l ON l.id = m.lineId
|
||||
$condition
|
||||
""");
|
||||
countSql.setCondition(cnd);
|
||||
@@ -91,7 +94,7 @@ public class TourMatterController {
|
||||
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
|
||||
ORDER BY $orderColumn $orderBy, CAST(l.lineCode AS UNSIGNED) ASC, m.`year` DESC, m.createdAt DESC
|
||||
""");
|
||||
listSql.setCondition(cnd);
|
||||
listSql.setVar("orderColumn", getOrderColumn(pageForm.getPageOrderName()));
|
||||
@@ -104,6 +107,109 @@ public class TourMatterController {
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出疗休养事项列表,导出范围复用页面查询条件和事项数据权限。
|
||||
*/
|
||||
@At
|
||||
@Ok("void")
|
||||
@SaCheckPermission("tour.matter")
|
||||
public void exportData(Integer year, String matterName, String unionId, String organizationType, String lineType,
|
||||
HttpServletResponse response) {
|
||||
Cnd cnd = buildMatterPageCnd(year, matterName, unionId, organizationType, lineType);
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
m.`year`,
|
||||
m.matterName,
|
||||
l.lineName,
|
||||
CASE
|
||||
WHEN IFNULL(m.signupStartTime, '') <> '' AND IFNULL(m.signupEndTime, '') <> ''
|
||||
THEN CONCAT(m.signupStartTime, ' 至 ', m.signupEndTime)
|
||||
ELSE ''
|
||||
END AS signupTime,
|
||||
CASE
|
||||
WHEN IFNULL(m.travelStartTime, '') <> '' AND IFNULL(m.travelEndTime, '') <> ''
|
||||
THEN CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime)
|
||||
ELSE ''
|
||||
END AS travelTime,
|
||||
d.name AS organizationTypeName,
|
||||
m.contactName,
|
||||
m.contactPhone,
|
||||
CASE WHEN m.enabled = 1 THEN '启用' ELSE '禁用' END AS enabledName
|
||||
FROM tour_matter m
|
||||
LEFT JOIN tour_line l ON l.id = m.lineId
|
||||
LEFT JOIN sys_union u ON u.id = m.unionId
|
||||
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 CAST(l.lineCode AS UNSIGNED) ASC, m.`year` DESC, m.createdAt DESC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourMatterService.dao().execute(sql);
|
||||
|
||||
List<NutMap> rows = sql.getList(NutMap.class);
|
||||
for (int i = 0; i < rows.size(); i++) {
|
||||
rows.get(i).put("index", i + 1);
|
||||
}
|
||||
|
||||
List<ExcelExportEntity> entities = new ArrayList<>();
|
||||
entities.add(new ExcelExportEntity("序号", "index", 8));
|
||||
entities.add(new ExcelExportEntity("年度", "year", 12));
|
||||
entities.add(new ExcelExportEntity("事项名称", "matterName", 30));
|
||||
entities.add(new ExcelExportEntity("线路名称", "lineName", 30));
|
||||
entities.add(new ExcelExportEntity("报名时间", "signupTime", 34));
|
||||
entities.add(new ExcelExportEntity("出行时间", "travelTime", 24));
|
||||
entities.add(new ExcelExportEntity("组织形式", "organizationTypeName", 16));
|
||||
entities.add(new ExcelExportEntity("联系人", "contactName", 16));
|
||||
entities.add(new ExcelExportEntity("联系方式", "contactPhone", 18));
|
||||
entities.add(new ExcelExportEntity("事项状态", "enabledName", 12));
|
||||
|
||||
ExportParams exportParams = new ExportParams();
|
||||
exportParams.setType(ExcelType.XSSF);
|
||||
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entities, rows);
|
||||
CommonDownloadUtil.download("疗休养事项数据.xlsx", workbook, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按当前事项列表查询条件统一赋值报名时间,更新前端筛选范围内的全部事项。
|
||||
*/
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("tour.matter")
|
||||
@SLog(type = "tour", tag = "疗休养事项", msg = "统一赋值报名时间")
|
||||
public Result assignSignupTime(Integer year, String matterName, String unionId, String organizationType, String lineType,
|
||||
String signupStartTime, String signupEndTime) {
|
||||
if (StrUtil.isBlank(signupStartTime) || StrUtil.isBlank(signupEndTime)) {
|
||||
return Result.error("报名开始时间和报名结束时间不能为空");
|
||||
}
|
||||
if (signupStartTime.compareTo(signupEndTime) >= 0) {
|
||||
return Result.error("报名开始时间必须小于报名结束时间");
|
||||
}
|
||||
|
||||
// 批量赋值必须严格复用事项列表查询条件,确保“查询哪些数据就赋值哪些事项”。
|
||||
Cnd cnd = buildMatterPageCnd(year, matterName, unionId, organizationType, lineType);
|
||||
Sql idSql = Sqls.create("""
|
||||
SELECT m.id
|
||||
FROM tour_matter m
|
||||
LEFT JOIN tour_line l ON l.id = m.lineId
|
||||
$condition
|
||||
""");
|
||||
idSql.setCondition(cnd);
|
||||
idSql.setCallback(Sqls.callback.maps());
|
||||
tourMatterService.dao().execute(idSql);
|
||||
List<String> ids = idSql.getList(NutMap.class).stream()
|
||||
.map(item -> item.getString("id"))
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.collect(Collectors.toList());
|
||||
if (ids.isEmpty()) {
|
||||
return Result.success("当前查询条件下暂无可赋值事项");
|
||||
}
|
||||
|
||||
// 只更新报名时间字段,不影响事项的线路、联系人、成团人数等其他配置。
|
||||
int updateCount = tourMatterService.assignSignupTime(ids, signupStartTime, signupEndTime);
|
||||
return Result.success("赋值成功,共更新" + updateCount + "条事项");
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.matter")
|
||||
public Result detail(String id) {
|
||||
@@ -142,17 +248,20 @@ public class TourMatterController {
|
||||
cnd.and("l.enabled", "=", true);
|
||||
cnd.and("l.openFlag", "=", true);
|
||||
|
||||
// 事项选择线路下拉需要展示线路类型和旅行社,因此这里补充旅行社名称返回给前端拼接显示。
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
l.*,
|
||||
a.agencyName AS travelAgencyName,
|
||||
lot.lotName AS lotName,
|
||||
lot.lotValue AS lotValue,
|
||||
lot.lotValue AS lotDays,
|
||||
lot.activityCost AS activityCost
|
||||
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
|
||||
$condition
|
||||
ORDER BY l.lineCode ASC, l.lineName ASC
|
||||
ORDER BY CAST(l.lineCode AS UNSIGNED) ASC, l.lineName ASC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
@@ -199,6 +308,17 @@ public class TourMatterController {
|
||||
return Result.success(list.stream().filter(item -> !item.isDisabled()).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.matter")
|
||||
public Result lineTypeOptions() {
|
||||
// 事项列表线路类型查询复用线路管理的 lineType 字典,保证筛选值与线路保存值一致。
|
||||
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.matter")
|
||||
@@ -348,16 +468,14 @@ public class TourMatterController {
|
||||
if (setting == null) {
|
||||
return;
|
||||
}
|
||||
if (setting.getMinGroupPeople() != null) {
|
||||
// 配置只作为弹窗缺省值,不能覆盖用户在选择线路页面已经提交的成团人数和报名时间。
|
||||
if (matter.getMinGroupPeople() == null && setting.getMinGroupPeople() != null) {
|
||||
matter.setMinGroupPeople(setting.getMinGroupPeople());
|
||||
}
|
||||
if (setting.getMaxGroupPeople() != null) {
|
||||
matter.setMaxGroupPeople(setting.getMaxGroupPeople());
|
||||
}
|
||||
if (StrUtil.isNotBlank(setting.getSignupStartTime())) {
|
||||
if (StrUtil.isBlank(matter.getSignupStartTime()) && StrUtil.isNotBlank(setting.getSignupStartTime())) {
|
||||
matter.setSignupStartTime(setting.getSignupStartTime());
|
||||
}
|
||||
if (StrUtil.isNotBlank(setting.getSignupEndTime())) {
|
||||
if (StrUtil.isBlank(matter.getSignupEndTime()) && StrUtil.isNotBlank(setting.getSignupEndTime())) {
|
||||
matter.setSignupEndTime(setting.getSignupEndTime());
|
||||
}
|
||||
}
|
||||
@@ -429,12 +547,6 @@ public class TourMatterController {
|
||||
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");
|
||||
}
|
||||
@@ -462,6 +574,22 @@ public class TourMatterController {
|
||||
.and(TourLedger::getMatterId, "=", matterId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建事项列表查询条件,批量赋值报名时间时复用该条件保证更新范围与列表查询一致。
|
||||
*/
|
||||
private Cnd buildMatterPageCnd(Integer year, String matterName, String unionId, String organizationType, String lineType) {
|
||||
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);
|
||||
// 事项列表和批量赋值报名时间共用该条件,按线路类型筛选时必须关联线路表字段。
|
||||
cnd.andEX("l.lineType", "=", lineType);
|
||||
applyMatterDataScope(cnd);
|
||||
return cnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* 事项数据范围:SYSADMIN 查看全部;分工会主席查看本工会事项;其它角色仅查看自己创建的事项。
|
||||
*/
|
||||
@@ -512,6 +640,10 @@ public class TourMatterController {
|
||||
if ("lineName".equals(orderName)) {
|
||||
return "l.lineName";
|
||||
}
|
||||
if ("lineCode".equals(orderName)) {
|
||||
// 线路序号按数字排序,避免 10 排在 2 前面。
|
||||
return "CAST(l.lineCode AS UNSIGNED)";
|
||||
}
|
||||
if ("settingName".equals(orderName)) {
|
||||
return "s.configName";
|
||||
}
|
||||
@@ -521,6 +653,6 @@ public class TourMatterController {
|
||||
if ("enabled".equals(orderName)) {
|
||||
return "m.enabled";
|
||||
}
|
||||
return "m.`year`";
|
||||
return "CAST(l.lineCode AS UNSIGNED)";
|
||||
}
|
||||
}
|
||||
|
||||
-44
@@ -444,10 +444,6 @@ public class TourMySignupController {
|
||||
if (ruleResult != null) {
|
||||
return ruleResult;
|
||||
}
|
||||
Result maxPeopleResult = checkMaxGroupPeople(matter, oldLedger, familyList);
|
||||
if (maxPeopleResult != null) {
|
||||
return maxPeopleResult;
|
||||
}
|
||||
TourLine line = tourLedgerService.dao().fetch(TourLine.class, matter.getLineId());
|
||||
boolean directFamilyLine = line != null && Boolean.TRUE.equals(line.getDirectFamilyUnitLine());
|
||||
TourSetting setting = tourLedgerService.dao().fetch(TourSetting.class, matter.getSettingId());
|
||||
@@ -985,46 +981,6 @@ public class TourMySignupController {
|
||||
&& idCard.matches("^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[\\dX]$");
|
||||
}
|
||||
|
||||
private Result checkMaxGroupPeople(TourMatter matter, TourLedger oldLedger, List<TourLedgerFamily> familyList) {
|
||||
if (matter == null || matter.getMaxGroupPeople() == null || matter.getMaxGroupPeople() <= 0) {
|
||||
return null;
|
||||
}
|
||||
int currentPeople = 1 + (Lang.isEmpty(familyList) ? 0 : familyList.size());
|
||||
int signedPeople = countSignupPeople(matter.getId(), oldLedger == null ? null : oldLedger.getId());
|
||||
int totalPeople = signedPeople + currentPeople;
|
||||
if (totalPeople > matter.getMaxGroupPeople()) {
|
||||
return Result.error("当前报名人数 " + signedPeople + " 人,本次报名 " + currentPeople
|
||||
+ " 人,最多成团人数 " + matter.getMaxGroupPeople() + " 人,报名后将超过人数上限,不能提交");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private int countSignupPeople(String matterId, String excludeLedgerId) {
|
||||
if (StrUtil.isBlank(matterId)) {
|
||||
return 0;
|
||||
}
|
||||
String excludeSql = StrUtil.isBlank(excludeLedgerId) ? "" : " AND t.id <> @excludeLedgerId";
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT IFNULL(SUM(1 + IFNULL(f.familyCount, 0)), 0) AS signupPeople
|
||||
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 = @matterId
|
||||
""" + excludeSql);
|
||||
sql.setParam("matterId", matterId);
|
||||
if (StrUtil.isNotBlank(excludeLedgerId)) {
|
||||
sql.setParam("excludeLedgerId", excludeLedgerId);
|
||||
}
|
||||
sql.setCallback(Sqls.callback.integer());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return sql.getInt();
|
||||
}
|
||||
|
||||
private String buildSelectedLineMessage(TourLedger ledger) {
|
||||
String selectedLineName = getLedgerLineName(ledger);
|
||||
return "您已经选择【" + selectedLineName + "】,取消后再重新选择。";
|
||||
|
||||
-4
@@ -205,10 +205,6 @@ public class TourSettingController {
|
||||
if (StrUtil.isBlank(tourSetting.getConfigName())) {
|
||||
return Result.error("配置名称不能为空");
|
||||
}
|
||||
if (tourSetting.getMinGroupPeople() != null && tourSetting.getMaxGroupPeople() != null
|
||||
&& tourSetting.getMinGroupPeople() > tourSetting.getMaxGroupPeople()) {
|
||||
return Result.error("最少成团人数不能大于最多成团人数");
|
||||
}
|
||||
if (StrUtil.isBlank(tourSetting.getSignupStartTime()) || StrUtil.isBlank(tourSetting.getSignupEndTime())) {
|
||||
return Result.error("报名时间不能为空");
|
||||
}
|
||||
|
||||
+9
-49
@@ -136,7 +136,7 @@ public class TourSignupController {
|
||||
@SaCheckPermission(value = {"tour.signup", "h5.tour.signup"}, mode = SaMode.OR)
|
||||
public Result h5PageData(PageForm pageForm, Integer year, String lineName, String lineType, String unionId, Boolean directFamilyUnitLine) {
|
||||
if (StrUtil.isBlank(pageForm.getPageOrderName())) {
|
||||
pageForm.defaultSortAsc("lineName");
|
||||
pageForm.defaultSortAsc("lineCode");
|
||||
}
|
||||
Cnd cnd = buildQueryCnd(year, lineName, lineType, unionId);
|
||||
cnd.andEX("l.directFamilyUnitLine", "=", directFamilyUnitLine);
|
||||
@@ -222,7 +222,7 @@ public class TourSignupController {
|
||||
GROUP BY t.matterId, t.jobNo
|
||||
) my ON my.matterId = m.id
|
||||
$condition
|
||||
ORDER BY $orderColumn $orderBy, m.`year` DESC, m.travelStartTime ASC, l.lineName ASC, m.createdAt DESC
|
||||
ORDER BY $orderColumn $orderBy, CAST(l.lineCode AS UNSIGNED) ASC, m.`year` DESC, m.travelStartTime ASC, l.lineName ASC, m.createdAt DESC
|
||||
""");
|
||||
listSql.setCondition(cnd);
|
||||
listSql.setParam("currentJobNo", currentJobNo);
|
||||
@@ -241,7 +241,7 @@ public class TourSignupController {
|
||||
@SaCheckPermission(value = {"tour.signup", "h5.tour.signup"}, mode = SaMode.OR)
|
||||
public Result pageData(PageForm pageForm, Integer year, String lineName, String lineType, String unionId) {
|
||||
if (StrUtil.isBlank(pageForm.getPageOrderName())) {
|
||||
pageForm.defaultSortAsc("lineName");
|
||||
pageForm.defaultSortAsc("lineCode");
|
||||
}
|
||||
Cnd cnd = buildQueryCnd(year, lineName, lineType, unionId);
|
||||
String currentJobNo = currentJobNo();
|
||||
@@ -325,7 +325,7 @@ public class TourSignupController {
|
||||
GROUP BY t.matterId, t.jobNo
|
||||
) my ON my.matterId = m.id
|
||||
$condition
|
||||
ORDER BY $orderColumn $orderBy, m.`year` DESC, m.travelStartTime ASC, l.lineName ASC, m.createdAt DESC
|
||||
ORDER BY $orderColumn $orderBy, CAST(l.lineCode AS UNSIGNED) ASC, m.`year` DESC, m.travelStartTime ASC, l.lineName ASC, m.createdAt DESC
|
||||
""");
|
||||
listSql.setCondition(cnd);
|
||||
listSql.setParam("currentJobNo", currentJobNo);
|
||||
@@ -751,10 +751,6 @@ public class TourSignupController {
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
Result maxPeopleResult = checkMaxGroupPeople(matter, oldLedger, familyList);
|
||||
if (maxPeopleResult != null) {
|
||||
return maxPeopleResult;
|
||||
}
|
||||
TourLine line = tourLedgerService.dao().fetch(TourLine.class, matter.getLineId());
|
||||
boolean directFamilyLine = line != null && Boolean.TRUE.equals(line.getDirectFamilyUnitLine());
|
||||
TourSetting setting = tourLedgerService.dao().fetch(TourSetting.class, matter.getSettingId());
|
||||
@@ -962,20 +958,6 @@ public class TourSignupController {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Result checkMaxGroupPeople(TourMatter matter, TourLedger oldLedger, List<TourLedgerFamily> familyList) {
|
||||
if (matter == null || matter.getMaxGroupPeople() == null || matter.getMaxGroupPeople() <= 0) {
|
||||
return null;
|
||||
}
|
||||
int currentPeople = 1 + (Lang.isEmpty(familyList) ? 0 : familyList.size());
|
||||
int signedPeople = countSignupPeople(matter.getId(), oldLedger == null ? null : oldLedger.getId());
|
||||
int totalPeople = signedPeople + currentPeople;
|
||||
if (totalPeople > matter.getMaxGroupPeople()) {
|
||||
return Result.error("当前报名人数 " + signedPeople + " 人,本次报名 " + currentPeople
|
||||
+ " 人,最多成团人数 " + matter.getMaxGroupPeople() + " 人,报名后将超过人数上限,不能提交");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isValidIdCard(String idCard) {
|
||||
return StrUtil.isNotBlank(idCard)
|
||||
&& idCard.matches("^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[\\dX]$");
|
||||
@@ -1252,32 +1234,6 @@ public class TourSignupController {
|
||||
return sql.getInt();
|
||||
}
|
||||
|
||||
private int countSignupPeople(String matterId, String excludeLedgerId) {
|
||||
if (StrUtil.isBlank(matterId)) {
|
||||
return 0;
|
||||
}
|
||||
String excludeSql = StrUtil.isBlank(excludeLedgerId) ? "" : " AND t.id <> @excludeLedgerId";
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT IFNULL(SUM(1 + IFNULL(f.familyCount, 0)), 0) AS signupPeople
|
||||
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 = @matterId
|
||||
""" + excludeSql);
|
||||
sql.setParam("matterId", matterId);
|
||||
if (StrUtil.isNotBlank(excludeLedgerId)) {
|
||||
sql.setParam("excludeLedgerId", excludeLedgerId);
|
||||
}
|
||||
sql.setCallback(Sqls.callback.integer());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return sql.getInt();
|
||||
}
|
||||
|
||||
private String buildSelectedLineMessage(TourLedger ledger) {
|
||||
String selectedLineName = getLedgerLineName(ledger);
|
||||
return "您已经选择【" + selectedLineName + "】,取消后再重新选择。";
|
||||
@@ -1537,6 +1493,10 @@ public class TourSignupController {
|
||||
}
|
||||
|
||||
private String getOrderColumn(String orderName) {
|
||||
if ("lineCode".equals(orderName)) {
|
||||
// 线路序号按数字排序,避免字符串排序导致 10 排在 2 前面。
|
||||
return "CAST(l.lineCode AS UNSIGNED)";
|
||||
}
|
||||
if ("lineName".equals(orderName)) {
|
||||
return "l.lineName";
|
||||
}
|
||||
@@ -1561,6 +1521,6 @@ public class TourSignupController {
|
||||
if ("signupCount".equals(orderName)) {
|
||||
return "signupCount";
|
||||
}
|
||||
return "l.lineName";
|
||||
return "CAST(l.lineCode AS UNSIGNED)";
|
||||
}
|
||||
}
|
||||
|
||||
+108
-88
@@ -9,7 +9,6 @@ import com.budwk.app.base.result.Result;
|
||||
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.models.TourMatter;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourMatterService;
|
||||
import org.nutz.dao.Cnd;
|
||||
@@ -61,7 +60,17 @@ public class TourUndertakeController {
|
||||
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
|
||||
INNER JOIN (
|
||||
SELECT
|
||||
t.matterId,
|
||||
t.groupCode,
|
||||
MAX(t.undertakeUnionId) AS undertakeUnionId
|
||||
FROM tour_ledger t
|
||||
WHERE t.delFlag = 0
|
||||
AND t.groupCode IS NOT NULL
|
||||
AND t.groupCode <> ''
|
||||
GROUP BY t.matterId, t.groupCode
|
||||
) gs ON gs.matterId = m.id
|
||||
$condition
|
||||
""");
|
||||
countSql.setCondition(cnd);
|
||||
@@ -74,14 +83,14 @@ public class TourUndertakeController {
|
||||
m.id AS matterId,
|
||||
m.`year`,
|
||||
m.matterName,
|
||||
m.unionId,
|
||||
gs.undertakeUnionId AS unionId,
|
||||
COALESCE(NULLIF(gs.undertakeUnionName, ''), uu.name, '') AS unionName,
|
||||
CASE
|
||||
WHEN IFNULL(NULLIF(m.undertakeStatus, ''), 'unclaimed') = 'claimed' THEN COALESCE(u.name, '校工会')
|
||||
ELSE ''
|
||||
END AS unionName,
|
||||
IFNULL(NULLIF(m.undertakeStatus, ''), 'unclaimed') AS undertakeStatus,
|
||||
WHEN IFNULL(NULLIF(gs.undertakeUnionId, ''), '') <> '' THEN 'claimed'
|
||||
ELSE 'unclaimed'
|
||||
END AS undertakeStatus,
|
||||
CASE
|
||||
WHEN IFNULL(NULLIF(m.undertakeStatus, ''), 'unclaimed') = 'claimed' THEN '已领'
|
||||
WHEN IFNULL(NULLIF(gs.undertakeUnionId, ''), '') <> '' THEN '已领'
|
||||
ELSE '未领'
|
||||
END AS undertakeStatusName,
|
||||
m.lineId,
|
||||
@@ -95,25 +104,20 @@ public class TourUndertakeController {
|
||||
THEN CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime)
|
||||
ELSE ''
|
||||
END AS travelPeriod,
|
||||
m.minGroupPeople,
|
||||
m.maxGroupPeople,
|
||||
IFNULL(sc.signupCount, 0) AS signupCount,
|
||||
IFNULL(usc.currentUnionSignupCount, 0) AS currentUnionSignupCount,
|
||||
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
|
||||
gs.groupCode,
|
||||
gs.groupName,
|
||||
gs.signupCount,
|
||||
IFNULL(ugs.currentUnionSignupCount, 0) AS currentUnionSignupCount
|
||||
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
|
||||
INNER JOIN (
|
||||
SELECT
|
||||
t.matterId,
|
||||
t.groupCode,
|
||||
MAX(t.groupName) AS groupName,
|
||||
MAX(t.undertakeUnionId) AS undertakeUnionId,
|
||||
MAX(t.undertakeUnionName) AS undertakeUnionName,
|
||||
SUM(1 + IFNULL(f.familyCount, 0)) AS signupCount
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN (
|
||||
SELECT ledgerId, COUNT(1) AS familyCount
|
||||
@@ -122,12 +126,16 @@ public class TourUndertakeController {
|
||||
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
|
||||
AND t.groupCode IS NOT NULL
|
||||
AND t.groupCode <> ''
|
||||
GROUP BY t.matterId, t.groupCode
|
||||
) gs ON gs.matterId = m.id
|
||||
LEFT JOIN sys_union uu ON uu.id = gs.undertakeUnionId
|
||||
LEFT JOIN (
|
||||
SELECT t.matterId, SUM(1 + IFNULL(f.familyCount, 0)) AS currentUnionSignupCount
|
||||
SELECT
|
||||
t.matterId,
|
||||
t.groupCode,
|
||||
SUM(1 + IFNULL(f.familyCount, 0)) AS currentUnionSignupCount
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN (
|
||||
SELECT ledgerId, COUNT(1) AS familyCount
|
||||
@@ -136,13 +144,13 @@ public class TourUndertakeController {
|
||||
GROUP BY ledgerId
|
||||
) f ON f.ledgerId = t.id
|
||||
WHERE t.delFlag = 0
|
||||
AND t.matterId IS NOT NULL
|
||||
AND t.matterId <> ''
|
||||
AND t.groupCode IS NOT NULL
|
||||
AND t.groupCode <> ''
|
||||
AND t.unionId = @currentUnionId
|
||||
GROUP BY t.matterId
|
||||
) usc ON usc.matterId = m.id
|
||||
GROUP BY t.matterId, t.groupCode
|
||||
) ugs ON ugs.matterId = m.id AND ugs.groupCode = gs.groupCode
|
||||
$condition
|
||||
ORDER BY $orderColumn $orderBy, m.`year` DESC, m.travelStartTime ASC, l.lineName ASC, m.createdAt DESC
|
||||
ORDER BY $orderColumn $orderBy, m.`year` DESC, m.travelStartTime ASC, l.lineName ASC, gs.groupCode ASC, m.createdAt DESC
|
||||
""");
|
||||
listSql.setCondition(cnd);
|
||||
listSql.setParam("currentUnionId", currentUnionId);
|
||||
@@ -180,49 +188,35 @@ public class TourUndertakeController {
|
||||
return Result.success(unionInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 领办当前成团行,接口必须同时接收事项ID和成团编码,避免按事项误领办全部团。
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("tour.undertake")
|
||||
public Result undertakeLine(String matterId) {
|
||||
if (StrUtil.isBlank(matterId)) {
|
||||
public Result undertakeLine(String matterId, String groupCode) {
|
||||
if (StrUtil.isBlank(matterId) || StrUtil.isBlank(groupCode)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
NutMap unionInfo = currentUnionInfo();
|
||||
if (unionInfo.isEmpty()) {
|
||||
return Result.error("未获取到当前登录人工会");
|
||||
}
|
||||
TourMatter matter = tourMatterService.fetch(matterId);
|
||||
if (matter == null || Boolean.TRUE.equals(matter.getDelFlag())) {
|
||||
return Result.error("事项不存在");
|
||||
}
|
||||
if ("claimed".equals(matter.getUndertakeStatus())) {
|
||||
return Result.error("当前线路已领办,不允许修改");
|
||||
}
|
||||
matter.setUnionId(unionInfo.getString("unionId"));
|
||||
matter.setUndertakeStatus("claimed");
|
||||
tourMatterService.update(matter);
|
||||
return Result.success(unionInfo);
|
||||
return tourLedgerService.undertakeGroup(matterId, groupCode, unionInfo.getString("unionId"), unionInfo.getString("unionName"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 解除当前成团行的领办信息,清空范围只限定到当前事项的当前团。
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("tour.undertake")
|
||||
public Result releaseUndertakeLine(String matterId) {
|
||||
public Result releaseUndertakeLine(String matterId, String groupCode) {
|
||||
if (!AuthUtil.hasRole(RoleConstant.SYSADMIN.name())) {
|
||||
return Result.error("仅系统管理员可以解除领办");
|
||||
}
|
||||
if (StrUtil.isBlank(matterId)) {
|
||||
if (StrUtil.isBlank(matterId) || StrUtil.isBlank(groupCode)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
TourMatter matter = tourMatterService.fetch(matterId);
|
||||
if (matter == null || Boolean.TRUE.equals(matter.getDelFlag())) {
|
||||
return Result.error("事项不存在");
|
||||
}
|
||||
if (!"claimed".equals(matter.getUndertakeStatus())) {
|
||||
return Result.error("当前线路未领办,无需解除");
|
||||
}
|
||||
matter.setUnionId("");
|
||||
matter.setUndertakeStatus("unclaimed");
|
||||
tourMatterService.update(matter);
|
||||
return Result.success();
|
||||
return tourLedgerService.releaseUndertakeGroup(matterId, groupCode);
|
||||
}
|
||||
|
||||
@At
|
||||
@@ -259,14 +253,14 @@ public class TourUndertakeController {
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.undertake")
|
||||
public Result signupPageData(PageForm pageForm, String matterId, String keyword, String unionId) {
|
||||
if (StrUtil.isBlank(matterId)) {
|
||||
public Result signupPageData(PageForm pageForm, String matterId, String keyword, String unionId, String groupCode) {
|
||||
if (StrUtil.isBlank(matterId) || StrUtil.isBlank(groupCode)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
if (StrUtil.isBlank(pageForm.getPageOrderName())) {
|
||||
pageForm.defaultSortDesc("signupTime");
|
||||
pageForm.defaultSortAsc("signupTime");
|
||||
}
|
||||
Cnd cnd = buildSignupQueryCnd(matterId, keyword, unionId);
|
||||
Cnd cnd = buildSignupQueryCnd(matterId, keyword, unionId, groupCode);
|
||||
Sql countSql = Sqls.create("""
|
||||
SELECT COUNT(1)
|
||||
FROM tour_ledger t
|
||||
@@ -284,16 +278,19 @@ public class TourUndertakeController {
|
||||
t.id,
|
||||
t.jobNo,
|
||||
t.userName,
|
||||
t.gender,
|
||||
'' AS mobile,
|
||||
t.idCard,
|
||||
t.unionId,
|
||||
t.unionName,
|
||||
t.signupTime
|
||||
t.signupTime,
|
||||
t.groupCode,
|
||||
t.groupName
|
||||
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
|
||||
ORDER BY $orderColumn $orderBy, t.signupTime ASC, t.createdAt ASC
|
||||
""");
|
||||
listSql.setCondition(cnd);
|
||||
listSql.setVar("orderColumn", getSignupOrderColumn(pageForm.getPageOrderName()));
|
||||
@@ -304,15 +301,19 @@ public class TourUndertakeController {
|
||||
|
||||
List<NutMap> list = listSql.getList(NutMap.class);
|
||||
fillSignupMobile(list);
|
||||
fillSignupFamilies(list);
|
||||
flattenSignupFamilies(list);
|
||||
Pagination<NutMap> pagination = new Pagination<>(pageForm.getPageNumber(), pageForm.getPageSize(), count, list);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
private Cnd buildSignupQueryCnd(String matterId, String keyword, String unionId) {
|
||||
/**
|
||||
* 领办线路查看以团为单位,报名人员查询必须固定到当前点击的成团编码。
|
||||
*/
|
||||
private Cnd buildSignupQueryCnd(String matterId, String keyword, String unionId, String groupCode) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("t.delFlag", "=", false);
|
||||
cnd.and("t.matterId", "=", matterId);
|
||||
cnd.and("t.groupCode", "=", groupCode);
|
||||
cnd.and("m.delFlag", "=", false);
|
||||
cnd.and("m.enabled", "=", true);
|
||||
cnd.and("m.lineId", "IS NOT", null);
|
||||
@@ -360,9 +361,9 @@ public class TourUndertakeController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看成团报名人员时按台账ID带出家属子列表,避免前端逐行请求家属信息。
|
||||
* 查看单个团报名人员时将教职工和家属平铺到同一列表,便于领办线路复用线路成团的展示方式。
|
||||
*/
|
||||
private void fillSignupFamilies(List<NutMap> list) {
|
||||
private void flattenSignupFamilies(List<NutMap> list) {
|
||||
if (list == null || list.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@@ -380,8 +381,9 @@ public class TourUndertakeController {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
ledgerId,
|
||||
staffJobNo AS jobNo,
|
||||
'' AS jobNo,
|
||||
familyName AS userName,
|
||||
gender,
|
||||
'' AS mobile,
|
||||
idCard,
|
||||
relationship
|
||||
@@ -396,11 +398,29 @@ public class TourUndertakeController {
|
||||
|
||||
Map<String, List<NutMap>> familyMap = new HashMap<>();
|
||||
for (NutMap family : sql.getList(NutMap.class)) {
|
||||
family.put("staffRow", false);
|
||||
family.put("rowTypeName", "家属");
|
||||
family.put("unionName", "");
|
||||
familyMap.computeIfAbsent(family.getString("ledgerId", ""), key -> new ArrayList<>()).add(family);
|
||||
}
|
||||
List<NutMap> flatList = new ArrayList<>();
|
||||
for (NutMap item : list) {
|
||||
item.put("families", familyMap.getOrDefault(item.getString("id", ""), List.of()));
|
||||
item.put("staffRow", true);
|
||||
item.put("rowTypeName", "教职工");
|
||||
item.put("relationship", "");
|
||||
item.put("relatedStaffName", item.getString("userName", ""));
|
||||
flatList.add(item);
|
||||
List<NutMap> families = familyMap.getOrDefault(item.getString("id", ""), List.of());
|
||||
for (NutMap family : families) {
|
||||
// 家属行继承教职工成团信息,并标明关联教职工名称。
|
||||
family.put("relatedStaffName", item.getString("userName", ""));
|
||||
family.put("groupCode", item.getString("groupCode", ""));
|
||||
family.put("groupName", item.getString("groupName", ""));
|
||||
}
|
||||
flatList.addAll(families);
|
||||
}
|
||||
list.clear();
|
||||
list.addAll(flatList);
|
||||
}
|
||||
|
||||
private Cnd buildQueryCnd(Integer year, String lineName, String lineType, String unionId, String undertakeStatus) {
|
||||
@@ -414,14 +434,14 @@ public class TourUndertakeController {
|
||||
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);
|
||||
cnd.andEX("gs.undertakeUnionId", "=", unionId);
|
||||
if ("claimed".equals(undertakeStatus)) {
|
||||
cnd.and("m.undertakeStatus", "=", "claimed");
|
||||
cnd.and("gs.undertakeUnionId", "IS NOT", null);
|
||||
cnd.and("gs.undertakeUnionId", "<>", "");
|
||||
} else if ("unclaimed".equals(undertakeStatus)) {
|
||||
SqlExpressionGroup statusGroup = new SqlExpressionGroup();
|
||||
statusGroup.or("m.undertakeStatus", "=", "unclaimed");
|
||||
statusGroup.or("m.undertakeStatus", "IS", null);
|
||||
statusGroup.or("m.undertakeStatus", "=", "");
|
||||
statusGroup.or("gs.undertakeUnionId", "IS", null);
|
||||
statusGroup.or("gs.undertakeUnionId", "=", "");
|
||||
cnd.and(statusGroup);
|
||||
}
|
||||
applyMatterDataScope(cnd);
|
||||
@@ -489,7 +509,7 @@ public class TourUndertakeController {
|
||||
return "m.matterName";
|
||||
}
|
||||
if ("unionName".equals(orderName)) {
|
||||
return "u.name";
|
||||
return "unionName";
|
||||
}
|
||||
if ("undertakeStatusName".equals(orderName)) {
|
||||
return "undertakeStatus";
|
||||
@@ -498,16 +518,10 @@ public class TourUndertakeController {
|
||||
return "l.lineType";
|
||||
}
|
||||
if ("signupCount".equals(orderName)) {
|
||||
return "signupCount";
|
||||
return "gs.signupCount";
|
||||
}
|
||||
if ("minGroupPeople".equals(orderName)) {
|
||||
return "m.minGroupPeople";
|
||||
}
|
||||
if ("maxGroupPeople".equals(orderName)) {
|
||||
return "m.maxGroupPeople";
|
||||
}
|
||||
if ("groupStatusName".equals(orderName)) {
|
||||
return "groupStatus";
|
||||
if ("groupName".equals(orderName) || "groupCode".equals(orderName)) {
|
||||
return "gs.groupCode";
|
||||
}
|
||||
return "l.lineName";
|
||||
}
|
||||
@@ -519,12 +533,18 @@ public class TourUndertakeController {
|
||||
if ("userName".equals(orderName)) {
|
||||
return "t.userName";
|
||||
}
|
||||
if ("gender".equals(orderName)) {
|
||||
return "t.gender";
|
||||
}
|
||||
if ("idCard".equals(orderName)) {
|
||||
return "t.idCard";
|
||||
}
|
||||
if ("unionName".equals(orderName)) {
|
||||
return "t.unionName";
|
||||
}
|
||||
if ("groupName".equals(orderName)) {
|
||||
return "t.groupCode";
|
||||
}
|
||||
return "t.signupTime";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,6 +101,32 @@ public class TourLedger extends BaseModel implements Serializable {
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String lineType;
|
||||
|
||||
@Column
|
||||
@Comment("成团编码")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
private String groupCode;
|
||||
|
||||
@Column
|
||||
@Comment("成团名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String groupName;
|
||||
|
||||
/**
|
||||
* 领办工会编码按团回填到台账,避免领办动作再修改事项归属工会。
|
||||
*/
|
||||
@Column
|
||||
@Comment("领办工会编码")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String undertakeUnionId;
|
||||
|
||||
/**
|
||||
* 领办工会名称与编码一起落台账,列表按团展示时直接读取当前团领办信息。
|
||||
*/
|
||||
@Column
|
||||
@Comment("领办工会")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String undertakeUnionName;
|
||||
|
||||
@Column
|
||||
@Comment("报名酒店")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
|
||||
@@ -33,8 +33,8 @@ public class TourLine extends BaseModel implements Serializable {
|
||||
|
||||
@Column
|
||||
@Comment("排序编号")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String lineCode;
|
||||
@ColDefine(type = ColType.INT, width = 11)
|
||||
private Integer lineCode;
|
||||
|
||||
@Column
|
||||
@Comment("线路名称")
|
||||
|
||||
@@ -1,7 +1,58 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedger;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface TourLedgerService extends BaseService<TourLedger> {
|
||||
|
||||
/**
|
||||
* 按查询条件获取疗休养台账中已分配的成团编码和成团名称,返回值已按成团信息去重。
|
||||
*
|
||||
* @param cnd 已包含事项、线路、台账状态和数据权限的查询条件
|
||||
* @return 去重后的成团信息列表
|
||||
*/
|
||||
List<NutMap> queryGroupOptions(Cnd cnd);
|
||||
|
||||
/**
|
||||
* 按事项最大成团人数,将当前事项下未成团的报名教职工及家属整体自动分配到成团中。
|
||||
*
|
||||
* @param matterId 疗休养事项ID
|
||||
* @return 分配结果,包含成功提示或具体业务校验错误
|
||||
*/
|
||||
Result assignGroup(String matterId);
|
||||
|
||||
/**
|
||||
* 将选中的教职工报名台账调整到指定成团中,并校验调整后目标团人数不超过事项最大成团人数。
|
||||
*
|
||||
* @param matterId 当前疗休养事项ID
|
||||
* @param groupCode 目标成团编码
|
||||
* @param ledgerIds 选中的教职工台账ID,多个ID使用逗号分隔
|
||||
* @return 调整结果,包含成功提示或具体业务校验错误
|
||||
*/
|
||||
Result adjustGroup(String matterId, String groupCode, String ledgerIds);
|
||||
|
||||
/**
|
||||
* 按事项和成团编码领办当前团,只回填当前团台账的领办工会信息,不修改事项表归属工会。
|
||||
*
|
||||
* @param matterId 当前疗休养事项ID
|
||||
* @param groupCode 当前成团编码
|
||||
* @param unionId 当前登录人所属工会编码
|
||||
* @param unionName 当前登录人所属工会名称
|
||||
* @return 领办结果,包含参数、重复领办和有效团数据校验
|
||||
*/
|
||||
Result undertakeGroup(String matterId, String groupCode, String unionId, String unionName);
|
||||
|
||||
/**
|
||||
* 按事项和成团编码解除当前团领办,只清空当前团台账的领办工会信息。
|
||||
*
|
||||
* @param matterId 当前疗休养事项ID
|
||||
* @param groupCode 当前成团编码
|
||||
* @return 解除结果,包含参数和当前团是否已领办校验
|
||||
*/
|
||||
Result releaseUndertakeGroup(String matterId, String groupCode);
|
||||
}
|
||||
|
||||
@@ -3,5 +3,17 @@ package com.budwk.app.zhgh.dayofficework.tour.service;
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourMatter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface TourMatterService extends BaseService<TourMatter> {
|
||||
|
||||
/**
|
||||
* 按事项ID批量更新报名起止时间,仅处理报名时间字段。
|
||||
*
|
||||
* @param ids 当前查询条件命中的事项ID集合
|
||||
* @param signupStartTime 报名开始时间
|
||||
* @param signupEndTime 报名结束时间
|
||||
* @return 实际更新数量
|
||||
*/
|
||||
int assignSignupTime(List<String> ids, String signupStartTime, String signupEndTime);
|
||||
}
|
||||
|
||||
+591
@@ -1,10 +1,28 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.service.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
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.service.TourLedgerService;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Chain;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class TourLedgerServiceImpl extends BaseServiceImpl<TourLedger> implements TourLedgerService {
|
||||
@@ -12,4 +30,577 @@ public class TourLedgerServiceImpl extends BaseServiceImpl<TourLedger> implement
|
||||
public TourLedgerServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据传入条件查询台账中已经存在的成团信息,按成团编码和成团名称去重后返回给页面展示。
|
||||
*/
|
||||
@Override
|
||||
public List<NutMap> queryGroupOptions(Cnd cnd) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT DISTINCT
|
||||
t.groupCode,
|
||||
t.groupName
|
||||
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 t.groupCode ASC, t.groupName ASC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
dao().execute(sql);
|
||||
return sql.getList(NutMap.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动分配当前事项下未成团的教职工台账,分配过程中出现容量不合法时整体中止。
|
||||
*/
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result assignGroup(String matterId) {
|
||||
if (StrUtil.isBlank(matterId)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
NutMap matter = fetchAssignMatter(matterId);
|
||||
if (matter == null || matter.isEmpty()) {
|
||||
return Result.error("事项不存在或线路信息不完整");
|
||||
}
|
||||
int maxGroupPeople = mapInt(matter, "maxGroupPeople");
|
||||
if (maxGroupPeople <= 0) {
|
||||
return Result.error("未配置最大成团人数,无法分配成团");
|
||||
}
|
||||
|
||||
List<GroupBucket> groups = queryGroupBuckets(matterId);
|
||||
List<SignupUnit> signupUnits = queryUnassignedSignupUnits(matterId);
|
||||
if (signupUnits.isEmpty()) {
|
||||
return Result.success("暂无未成团人员需要分配");
|
||||
}
|
||||
for (SignupUnit unit : signupUnits) {
|
||||
if (unit.peopleCount > maxGroupPeople) {
|
||||
return Result.error(unit.userName + "含家属共" + unit.peopleCount + "人,超过最大成团人数" + maxGroupPeople + "人,无法分配");
|
||||
}
|
||||
}
|
||||
|
||||
int nextGroupIndex = nextGroupIndex(groups);
|
||||
int assignCount = 0;
|
||||
for (SignupUnit unit : signupUnits) {
|
||||
GroupBucket targetGroup = findAvailableGroup(groups, unit.peopleCount, maxGroupPeople);
|
||||
if (targetGroup == null) {
|
||||
targetGroup = createGroupBucket(nextGroupIndex++);
|
||||
groups.add(targetGroup);
|
||||
}
|
||||
updateLedgerGroup(unit.ledgerId, targetGroup.groupCode, targetGroup.groupName);
|
||||
targetGroup.peopleCount += unit.peopleCount;
|
||||
assignCount++;
|
||||
}
|
||||
return Result.success("分配成功,共分配" + assignCount + "名教职工");
|
||||
}
|
||||
|
||||
/**
|
||||
* 将选中的教职工台账调整到目标团,家属随教职工一起计入目标团人数。
|
||||
*/
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result adjustGroup(String matterId, String groupCode, String ledgerIds) {
|
||||
if (StrUtil.isBlank(matterId) || StrUtil.isBlank(groupCode)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
List<String> ledgerIdList = parseLedgerIds(ledgerIds);
|
||||
if (ledgerIdList.isEmpty()) {
|
||||
return Result.error("请选择需要调整的教职工");
|
||||
}
|
||||
|
||||
NutMap matter = fetchAssignMatter(matterId);
|
||||
if (matter == null || matter.isEmpty()) {
|
||||
return Result.error("事项不存在或线路信息不完整");
|
||||
}
|
||||
int maxGroupPeople = mapInt(matter, "maxGroupPeople");
|
||||
if (maxGroupPeople <= 0) {
|
||||
return Result.error("未配置最大成团人数,无法调整成团");
|
||||
}
|
||||
|
||||
NutMap targetGroup = fetchTargetGroup(matterId, groupCode);
|
||||
if (targetGroup == null || targetGroup.isEmpty()) {
|
||||
return Result.error("请选择有效的成团信息");
|
||||
}
|
||||
List<SignupUnit> selectedUnits = querySelectedSignupUnits(matterId, ledgerIdList);
|
||||
if (selectedUnits.size() != ledgerIdList.size()) {
|
||||
return Result.error("所选人员信息无效,请刷新后重试");
|
||||
}
|
||||
|
||||
int selectedPeopleCount = selectedUnits.stream().mapToInt(unit -> unit.peopleCount).sum();
|
||||
int targetPeopleCount = countTargetGroupPeople(matterId, groupCode, ledgerIdList);
|
||||
if (targetPeopleCount + selectedPeopleCount > maxGroupPeople) {
|
||||
return Result.error("调整后目标团共" + (targetPeopleCount + selectedPeopleCount)
|
||||
+ "人,超过最大成团人数" + maxGroupPeople + "人,无法调整");
|
||||
}
|
||||
|
||||
updateLedgerGroup(matterId, ledgerIdList, groupCode, targetGroup.getString("groupName", ""));
|
||||
return Result.success("调整成功,共调整" + selectedUnits.size() + "名教职工");
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询事项基础信息,最大成团人数是自动分配的核心容量上限。
|
||||
*/
|
||||
/**
|
||||
* 当前领办以团为单位执行,写入范围限定为同一事项、同一成团编码下的有效台账。
|
||||
*/
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result undertakeGroup(String matterId, String groupCode, String unionId, String unionName) {
|
||||
if (StrUtil.isBlank(matterId) || StrUtil.isBlank(groupCode) || StrUtil.isBlank(unionId)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
NutMap group = fetchUndertakeGroup(matterId, groupCode);
|
||||
if (group == null || group.isEmpty()) {
|
||||
return Result.error("当前团不存在或未成团,无法领办");
|
||||
}
|
||||
if (StrUtil.isNotBlank(group.getString("undertakeUnionId", ""))) {
|
||||
return Result.error("当前团已领办,不允许修改");
|
||||
}
|
||||
Cnd cnd = buildUndertakeGroupCnd(matterId, groupCode);
|
||||
Chain chain = Chain.make("undertakeUnionId", unionId)
|
||||
.add("undertakeUnionName", StrUtil.blankToDefault(unionName, ""));
|
||||
dao().update(TourLedger.class, chain, cnd);
|
||||
return Result.success(NutMap.NEW().addv("unionId", unionId).addv("unionName", StrUtil.blankToDefault(unionName, "")));
|
||||
}
|
||||
|
||||
/**
|
||||
* 解除领办同样按团处理,仅清空当前团台账领办字段,保留事项表原有归属信息。
|
||||
*/
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result releaseUndertakeGroup(String matterId, String groupCode) {
|
||||
if (StrUtil.isBlank(matterId) || StrUtil.isBlank(groupCode)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
NutMap group = fetchUndertakeGroup(matterId, groupCode);
|
||||
if (group == null || group.isEmpty()) {
|
||||
return Result.error("当前团不存在或未成团,无法解除");
|
||||
}
|
||||
if (StrUtil.isBlank(group.getString("undertakeUnionId", ""))) {
|
||||
return Result.error("当前团未领办,无需解除");
|
||||
}
|
||||
Cnd cnd = buildUndertakeGroupCnd(matterId, groupCode);
|
||||
dao().update(TourLedger.class, Chain.make("undertakeUnionId", "").add("undertakeUnionName", ""), cnd);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
private NutMap fetchAssignMatter(String matterId) {
|
||||
Cnd cnd = buildAssignMatterCnd(matterId);
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
m.id,
|
||||
m.maxGroupPeople
|
||||
FROM tour_matter m
|
||||
INNER JOIN tour_line l ON l.id = m.lineId
|
||||
$condition
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.map());
|
||||
dao().execute(sql);
|
||||
return sql.getObject(NutMap.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前事项下已存在的目标成团信息,人员调整只能选择当前线路台账中已有的团。
|
||||
*/
|
||||
private NutMap fetchTargetGroup(String matterId, String groupCode) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
t.groupCode,
|
||||
MAX(t.groupName) AS groupName
|
||||
FROM tour_ledger t
|
||||
WHERE t.delFlag = 0
|
||||
AND t.matterId = @matterId
|
||||
AND t.groupCode = @groupCode
|
||||
GROUP BY t.groupCode
|
||||
""");
|
||||
sql.setParam("matterId", matterId);
|
||||
sql.setParam("groupCode", groupCode);
|
||||
sql.setCallback(Sqls.callback.map());
|
||||
dao().execute(sql);
|
||||
return sql.getObject(NutMap.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造自动分配事项查询条件,确保自动分配的数据范围与线路成团查看列表保持一致。
|
||||
*/
|
||||
/**
|
||||
* 查询当前事项下指定团的领办字段,供领办和解除领办前置校验使用。
|
||||
*/
|
||||
private NutMap fetchUndertakeGroup(String matterId, String groupCode) {
|
||||
Cnd cnd = buildAssignMatterCnd(matterId);
|
||||
cnd.and("t.delFlag", "=", false);
|
||||
cnd.and("t.groupCode", "=", groupCode);
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
t.groupCode,
|
||||
MAX(t.groupName) AS groupName,
|
||||
MAX(t.undertakeUnionId) AS undertakeUnionId,
|
||||
MAX(t.undertakeUnionName) AS undertakeUnionName
|
||||
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
|
||||
GROUP BY t.groupCode
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.map());
|
||||
dao().execute(sql);
|
||||
return sql.getObject(NutMap.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造当前团领办字段更新范围,避免同一事项下其它团被误更新。
|
||||
*/
|
||||
private Cnd buildUndertakeGroupCnd(String matterId, String groupCode) {
|
||||
return Cnd.where("matterId", "=", matterId)
|
||||
.and("groupCode", "=", groupCode)
|
||||
.and("delFlag", "=", false);
|
||||
}
|
||||
|
||||
private Cnd buildAssignMatterCnd(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);
|
||||
return cnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询已存在成团及当前占用人数,后续未成团人员优先从最早团开始补足。
|
||||
*/
|
||||
private List<GroupBucket> queryGroupBuckets(String matterId) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
t.groupCode,
|
||||
MAX(t.groupName) AS groupName,
|
||||
SUM(1 + IFNULL(f.familyCount, 0)) AS peopleCount
|
||||
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 = @matterId
|
||||
AND t.groupCode IS NOT NULL
|
||||
AND t.groupCode <> ''
|
||||
GROUP BY t.groupCode
|
||||
ORDER BY t.groupCode ASC
|
||||
""");
|
||||
sql.setParam("matterId", matterId);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
dao().execute(sql);
|
||||
|
||||
List<GroupBucket> groups = new ArrayList<>();
|
||||
for (NutMap item : sql.getList(NutMap.class)) {
|
||||
GroupBucket group = new GroupBucket();
|
||||
group.groupCode = item.getString("groupCode", "");
|
||||
group.groupName = item.getString("groupName", "");
|
||||
group.peopleCount = mapInt(item, "peopleCount");
|
||||
groups.add(group);
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询未成团教职工台账,并合并家属人数,保证教职工和家属作为一个整体分配。
|
||||
*/
|
||||
private List<SignupUnit> queryUnassignedSignupUnits(String matterId) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
t.id AS ledgerId,
|
||||
t.userName,
|
||||
1 + IFNULL(f.familyCount, 0) AS peopleCount
|
||||
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 = @matterId
|
||||
AND (t.groupCode IS NULL OR t.groupCode = '')
|
||||
ORDER BY t.signupTime ASC, t.createdAt ASC
|
||||
""");
|
||||
sql.setParam("matterId", matterId);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
dao().execute(sql);
|
||||
|
||||
List<SignupUnit> signupUnits = new ArrayList<>();
|
||||
for (NutMap item : sql.getList(NutMap.class)) {
|
||||
SignupUnit unit = new SignupUnit();
|
||||
unit.ledgerId = item.getString("ledgerId", "");
|
||||
unit.userName = item.getString("userName", "");
|
||||
unit.peopleCount = mapInt(item, "peopleCount");
|
||||
signupUnits.add(unit);
|
||||
}
|
||||
return signupUnits;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询选中教职工台账及其家属人数,确保只调整当前事项下有效的教职工报名记录。
|
||||
*/
|
||||
private List<SignupUnit> querySelectedSignupUnits(String matterId, List<String> ledgerIds) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
t.id AS ledgerId,
|
||||
t.userName,
|
||||
1 + IFNULL(f.familyCount, 0) AS peopleCount
|
||||
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 = @matterId
|
||||
AND t.id IN (@ledgerIds)
|
||||
ORDER BY t.signupTime ASC, t.createdAt ASC
|
||||
""");
|
||||
sql.setParam("matterId", matterId);
|
||||
sql.setParam("ledgerIds", ledgerIds.toArray(new String[0]));
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
dao().execute(sql);
|
||||
|
||||
List<SignupUnit> signupUnits = new ArrayList<>();
|
||||
for (NutMap item : sql.getList(NutMap.class)) {
|
||||
SignupUnit unit = new SignupUnit();
|
||||
unit.ledgerId = item.getString("ledgerId", "");
|
||||
unit.userName = item.getString("userName", "");
|
||||
unit.peopleCount = mapInt(item, "peopleCount");
|
||||
signupUnits.add(unit);
|
||||
}
|
||||
return signupUnits;
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计目标团调整前人数,排除本次选中人员,避免原本已在目标团的人员被重复计数。
|
||||
*/
|
||||
private int countTargetGroupPeople(String matterId, String groupCode, List<String> excludeLedgerIds) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT IFNULL(SUM(1 + IFNULL(f.familyCount, 0)), 0) AS peopleCount
|
||||
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 = @matterId
|
||||
AND t.groupCode = @groupCode
|
||||
AND t.id NOT IN (@excludeLedgerIds)
|
||||
""");
|
||||
sql.setParam("matterId", matterId);
|
||||
sql.setParam("groupCode", groupCode);
|
||||
sql.setParam("excludeLedgerIds", excludeLedgerIds.toArray(new String[0]));
|
||||
sql.setCallback(Sqls.callback.map());
|
||||
dao().execute(sql);
|
||||
return mapInt(sql.getObject(NutMap.class), "peopleCount");
|
||||
}
|
||||
|
||||
/**
|
||||
* 从最早的团开始查找可容纳当前报名单位的团,避免前面团未满但后面新建团的情况。
|
||||
*/
|
||||
private GroupBucket findAvailableGroup(List<GroupBucket> groups, int peopleCount, int maxGroupPeople) {
|
||||
for (GroupBucket group : groups) {
|
||||
if (group.peopleCount + peopleCount <= maxGroupPeople) {
|
||||
return group;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据现有最大团序号生成下一个团序号,兼容已有非标准团编码。
|
||||
*/
|
||||
private int nextGroupIndex(List<GroupBucket> groups) {
|
||||
int maxIndex = 0;
|
||||
for (GroupBucket group : groups) {
|
||||
maxIndex = Math.max(maxIndex, parseGroupIndex(group.groupCode));
|
||||
}
|
||||
return maxIndex + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建新的成团桶,编码使用T001递增,名称使用中文序号加“团”。
|
||||
*/
|
||||
private GroupBucket createGroupBucket(int index) {
|
||||
GroupBucket group = new GroupBucket();
|
||||
group.groupCode = String.format("T%03d", index);
|
||||
group.groupName = toChineseNumber(index) + "团";
|
||||
group.peopleCount = 0;
|
||||
return group;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动分配按事项归属控制数据范围:校工会查看全部;分工会查看本工会事项;其它角色仅处理自己创建的事项。
|
||||
*/
|
||||
private void applyMatterDataScope(Cnd cnd) {
|
||||
if (hasSchoolUnionScope() || AuthUtil.hasRole(RoleConstant.BRANCH_UNION_CHAIRMAN.name())) {
|
||||
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 void updateLedgerGroup(String ledgerId, String groupCode, String groupName) {
|
||||
dao().update(TourLedger.class, Chain.make("groupCode", groupCode).add("groupName", groupName), Cnd.where("id", "=", ledgerId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新选中的教职工台账成团信息,人员调整只写教职工台账,家属展示继续继承教职工。
|
||||
*/
|
||||
private void updateLedgerGroup(String matterId, List<String> ledgerIds, String groupCode, String groupName) {
|
||||
Cnd cnd = Cnd.where("id", "in", ledgerIds)
|
||||
.and("matterId", "=", matterId)
|
||||
.and("delFlag", "=", false);
|
||||
dao().update(TourLedger.class, Chain.make("groupCode", groupCode).add("groupName", groupName), cnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析前端逗号分隔的台账ID,去重并过滤空值,避免重复计数和重复更新。
|
||||
*/
|
||||
private List<String> parseLedgerIds(String ledgerIds) {
|
||||
Set<String> idSet = new LinkedHashSet<>();
|
||||
if (StrUtil.isBlank(ledgerIds)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
for (String id : ledgerIds.split(",")) {
|
||||
if (StrUtil.isNotBlank(id)) {
|
||||
idSet.add(id.trim());
|
||||
}
|
||||
}
|
||||
return new ArrayList<>(idSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析T001这类标准团编码中的数字序号,非标准编码返回0。
|
||||
*/
|
||||
private int parseGroupIndex(String groupCode) {
|
||||
if (StrUtil.isBlank(groupCode) || !groupCode.startsWith("T")) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
return Integer.parseInt(groupCode.substring(1));
|
||||
} catch (NumberFormatException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数字序号转为中文团名序号,支持常见的两位和多位团序号展示。
|
||||
*/
|
||||
private String toChineseNumber(int number) {
|
||||
String[] digits = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九"};
|
||||
if (number <= 0) {
|
||||
return String.valueOf(number);
|
||||
}
|
||||
if (number < 10) {
|
||||
return "第" + digits[number];
|
||||
}
|
||||
if (number < 100) {
|
||||
int ten = number / 10;
|
||||
int one = number % 10;
|
||||
String prefix = ten == 1 ? "十" : digits[ten] + "十";
|
||||
return "第" + prefix + (one == 0 ? "" : digits[one]);
|
||||
}
|
||||
String value = String.valueOf(number);
|
||||
StringBuilder builder = new StringBuilder("第");
|
||||
for (int i = 0; i < value.length(); i++) {
|
||||
builder.append(digits[value.charAt(i) - '0']);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全读取SQL返回的整数值,避免不同数据库驱动返回Number或字符串时转换失败。
|
||||
*/
|
||||
private int mapInt(NutMap map, String key) {
|
||||
Object value = map == null ? null : map.get(key);
|
||||
if (value instanceof Number number) {
|
||||
return number.intValue();
|
||||
}
|
||||
if (value == null || StrUtil.isBlank(String.valueOf(value))) {
|
||||
return 0;
|
||||
}
|
||||
return Integer.parseInt(String.valueOf(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* 已有成团容量桶,记录每个团当前人数以及后续分配后的占用人数。
|
||||
*/
|
||||
private static class GroupBucket {
|
||||
private String groupCode;
|
||||
private String groupName;
|
||||
private int peopleCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* 待分配报名单位,教职工及其家属作为不可拆分的最小分配单位。
|
||||
*/
|
||||
private static class SignupUnit {
|
||||
private String ledgerId;
|
||||
private String userName;
|
||||
private int peopleCount;
|
||||
}
|
||||
}
|
||||
|
||||
+22
@@ -3,13 +3,35 @@ 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.Chain;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class TourMatterServiceImpl extends BaseServiceImpl<TourMatter> implements TourMatterService {
|
||||
|
||||
public TourMatterServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按事项ID批量更新报名起止时间,供事项列表“一键赋值报名时间”使用。
|
||||
*
|
||||
* @param ids 当前查询条件命中的事项ID集合
|
||||
* @param signupStartTime 报名开始时间
|
||||
* @param signupEndTime 报名结束时间
|
||||
* @return 实际更新数量
|
||||
*/
|
||||
@Override
|
||||
public int assignSignupTime(List<String> ids, String signupStartTime, String signupEndTime) {
|
||||
if (ids == null || ids.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
return dao().update(TourMatter.class,
|
||||
Chain.make("signupStartTime", signupStartTime).add("signupEndTime", signupEndTime),
|
||||
Cnd.where("id", "in", ids));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
-- 疗休养台账增加成团信息字段,用于线路成团自动分配和人员调整。
|
||||
ALTER TABLE `tour_ledger`
|
||||
ADD COLUMN `groupCode` varchar(20) DEFAULT NULL COMMENT '成团编码' AFTER `lineType`,
|
||||
ADD COLUMN `groupName` varchar(50) DEFAULT NULL COMMENT '成团名称' AFTER `groupCode`;
|
||||
|
||||
ALTER TABLE `tour_ledger`
|
||||
ADD KEY `idx_tour_ledger_matter_line_group` (`matterId`, `lineId`, `groupCode`, `delFlag`);
|
||||
@@ -0,0 +1,5 @@
|
||||
ALTER TABLE tour_ledger
|
||||
ADD COLUMN undertakeUnionId VARCHAR(32) NULL COMMENT '领办工会编码' AFTER groupName,
|
||||
ADD COLUMN undertakeUnionName VARCHAR(100) NULL COMMENT '领办工会' AFTER undertakeUnionId;
|
||||
|
||||
CREATE INDEX idx_tour_ledger_undertake_union ON tour_ledger (matterId, groupCode, undertakeUnionId);
|
||||
@@ -0,0 +1,9 @@
|
||||
-- Convert tour line sort code to numeric type for stable numeric ascending order.
|
||||
UPDATE tour_line
|
||||
SET lineCode = '0'
|
||||
WHERE lineCode IS NULL
|
||||
OR TRIM(lineCode) = ''
|
||||
OR lineCode NOT REGEXP '^[0-9]+$';
|
||||
|
||||
ALTER TABLE tour_line
|
||||
MODIFY COLUMN lineCode INT(11) NOT NULL DEFAULT 0 COMMENT '排序编号';
|
||||
@@ -56,31 +56,16 @@ layout("/layouts/platform.html"){
|
||||
<el-table-column label="线路名称" prop="lineName" min-width="220" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="出行时段" prop="travelPeriod" width="260" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="事项名称" prop="matterName" min-width="200" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="所属工会" prop="unionName" min-width="180" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column v-if="false" label="所属工会" prop="unionName" min-width="180" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="线路类型" prop="lineType" width="140" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="最少成团人数" prop="minGroupPeople" width="140" sortable="custom" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
{{ row.minGroupPeople || 0 }}人
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="最多成团人数" prop="maxGroupPeople" width="140" sortable="custom" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
{{ row.maxGroupPeople || 0 }}人
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="报名人数" prop="signupCount" width="120" sortable="custom" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
<el-tag size="mini" :type="Number(row.signupCount || 0) > 0 ? 'success' : 'info'">{{ row.signupCount || 0 }}人</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="成团状态" prop="groupStatusName" width="120" sortable="custom" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
<el-tag size="mini" :type="groupStatusType(row.groupStatus)">{{ row.groupStatusName || '未成团' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="160" align="center" header-align="center" fixed="right">
|
||||
<template slot-scope="{row}">
|
||||
<el-button size="mini" type="primary" @click="openView(row)">查看</el-button>
|
||||
<el-button size="mini" type="primary" @click="openView(row)">组团</el-button>
|
||||
<el-button size="mini" type="primary" @click="exportLine(row)">导出</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -120,33 +105,48 @@ layout("/layouts/platform.html"){
|
||||
</el-card>
|
||||
|
||||
<el-card class="mt10" shadow="never">
|
||||
<div class="tour-group-view-title">报名人员列表</div>
|
||||
<div class="tour-group-view-header">
|
||||
<div class="tour-group-view-title">报名人员列表</div>
|
||||
<div class="tour-group-options">
|
||||
<el-tag
|
||||
v-for="item in viewGroupOptions"
|
||||
:key="item.groupCode"
|
||||
:class="['tour-group-option', viewForm.groupCode === item.groupCode ? 'is-active' : '']"
|
||||
size="small"
|
||||
:type="viewForm.groupCode === item.groupCode ? 'success' : 'primary'"
|
||||
@click="toggleGroupFilter(item)">
|
||||
{{ formatGroupOption(item) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="tour-group-actions">
|
||||
<el-button size="mini" type="primary" :loading="assignGroupLoading" @click="confirmAssignGroup">分配成团</el-button>
|
||||
<el-button size="mini" type="primary" @click="openAdjustGroup">人员调整</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table
|
||||
ref="viewTable"
|
||||
v-loading="viewLoading"
|
||||
:data="viewTableData"
|
||||
:size="tableSize"
|
||||
border
|
||||
@selection-change="viewSelectionChange"
|
||||
@sort-change="viewPageOrder">
|
||||
<el-table-column type="expand" width="50">
|
||||
<template slot-scope="{row}">
|
||||
<div v-if="row.families && row.families.length > 0" class="tour-family-list">
|
||||
<el-table :data="row.families" :size="tableSize" border>
|
||||
<el-table-column label="工号" prop="jobNo" width="130" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="姓名" prop="userName" width="120" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="亲属关系" prop="relationship" width="120" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="手机号" prop="mobile" width="140" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="身份证号" prop="idCard" min-width="190" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div v-else class="tour-family-empty">暂无亲属信息</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column type="selection" width="50" align="center" header-align="center" :selectable="isViewRowSelectable"></el-table-column>
|
||||
<el-table-column label="序号" type="index" :index="viewIndexMethod" width="80" align="center" header-align="center"></el-table-column>
|
||||
<el-table-column label="工号" prop="jobNo" width="130" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="姓名" prop="userName" width="120" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="性别" prop="gender" width="90" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="手机号码" prop="mobile" width="140" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="身份证号" prop="idCard" min-width="190" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="所属工会" prop="unionName" min-width="180" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="人员类型" prop="rowTypeName" width="90" align="center" header-align="center"></el-table-column>
|
||||
<el-table-column label="亲属关系" prop="relationship" width="120" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="成团信息" prop="groupName" width="160" sortable="custom" align="center" header-align="center" show-overflow-tooltip>
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ formatGroupInfo(row) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="关联教职工名称" prop="relatedStaffName" width="150" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
</el-table>
|
||||
<el-row class="el-pagination-container tour-group-view-pagination">
|
||||
<el-pagination
|
||||
@@ -163,6 +163,31 @@ layout("/layouts/platform.html"){
|
||||
</el-card>
|
||||
</div>
|
||||
</el-drawer>
|
||||
|
||||
<el-dialog
|
||||
title="人员调整"
|
||||
:visible.sync="adjustVisible"
|
||||
width="420px"
|
||||
append-to-body
|
||||
:close-on-click-modal="false"
|
||||
@closed="resetAdjustForm">
|
||||
<el-form :model="adjustForm" label-width="90px">
|
||||
<el-form-item label="成团信息" required>
|
||||
<el-select v-model="adjustForm.groupCode" filterable placeholder="请选择成团信息" style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in viewGroupOptions"
|
||||
:key="item.groupCode"
|
||||
:label="formatGroupOption(item)"
|
||||
:value="item.groupCode">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="adjustVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="adjustLoading" @click="submitAdjustGroup">确认</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</guava>
|
||||
</div>
|
||||
|
||||
@@ -181,6 +206,15 @@ layout("/layouts/platform.html"){
|
||||
viewTitle: "",
|
||||
viewRow: {},
|
||||
viewTableData: [],
|
||||
viewGroupOptions: [],
|
||||
viewSelection: [],
|
||||
syncingFamilySelection: false,
|
||||
assignGroupLoading: false,
|
||||
adjustVisible: false,
|
||||
adjustLoading: false,
|
||||
adjustForm: {
|
||||
groupCode: ""
|
||||
},
|
||||
pageForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
@@ -196,10 +230,11 @@ layout("/layouts/platform.html"){
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
pageOrderName: "signupTime",
|
||||
pageOrderBy: "descending",
|
||||
pageOrderName: "groupCode",
|
||||
pageOrderBy: "ascending",
|
||||
keyword: "",
|
||||
unionId: ""
|
||||
unionId: "",
|
||||
groupCode: ""
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -226,6 +261,14 @@ layout("/layouts/platform.html"){
|
||||
|| row.directFamilyUnitLine === 1
|
||||
|| row.directFamilyUnitLine === "1"
|
||||
},
|
||||
formatGroupInfo(row) {
|
||||
if (!row || !row.groupCode) return "未成团"
|
||||
return row.groupName ? row.groupCode + " " + row.groupName : row.groupCode
|
||||
},
|
||||
formatGroupOption(item) {
|
||||
if (!item || !item.groupCode) return ""
|
||||
return item.groupName ? item.groupCode + " " + item.groupName : item.groupCode
|
||||
},
|
||||
openView(row) {
|
||||
this.viewRow = row || {}
|
||||
this.viewTitle = this.viewRow.lineName || "报名人员"
|
||||
@@ -233,11 +276,17 @@ layout("/layouts/platform.html"){
|
||||
this.viewForm.pageNumber = 1
|
||||
this.viewForm.pageSize = 10
|
||||
this.viewForm.totalCount = 0
|
||||
this.viewForm.pageOrderName = "signupTime"
|
||||
this.viewForm.pageOrderBy = "descending"
|
||||
this.viewForm.pageOrderName = "groupCode"
|
||||
this.viewForm.pageOrderBy = "ascending"
|
||||
this.viewForm.keyword = ""
|
||||
this.viewForm.unionId = ""
|
||||
this.viewForm.groupCode = ""
|
||||
this.viewTableData = []
|
||||
this.viewGroupOptions = []
|
||||
this.viewSelection = []
|
||||
this.assignGroupLoading = false
|
||||
this.resetAdjustForm()
|
||||
this.loadViewGroupOptions()
|
||||
this.loadViewData()
|
||||
},
|
||||
viewSearch() {
|
||||
@@ -247,12 +296,118 @@ layout("/layouts/platform.html"){
|
||||
viewReset() {
|
||||
this.viewForm.keyword = ""
|
||||
this.viewForm.unionId = ""
|
||||
this.viewForm.groupCode = ""
|
||||
this.viewForm.pageNumber = 1
|
||||
this.loadViewData()
|
||||
},
|
||||
toggleGroupFilter(item) {
|
||||
const groupCode = item && item.groupCode ? item.groupCode : ""
|
||||
this.viewForm.groupCode = this.viewForm.groupCode === groupCode ? "" : groupCode
|
||||
this.viewForm.pageNumber = 1
|
||||
this.loadViewData()
|
||||
},
|
||||
viewIndexMethod(index) {
|
||||
return (this.viewForm.pageNumber - 1) * this.viewForm.pageSize + index + 1
|
||||
},
|
||||
isViewRowSelectable(row) {
|
||||
return !!(row && row.selectable)
|
||||
},
|
||||
viewSelectionChange(selection) {
|
||||
this.viewSelection = selection || []
|
||||
this.syncFamilySelection(selection || [])
|
||||
},
|
||||
syncFamilySelection(selection) {
|
||||
if (this.syncingFamilySelection || !this.$refs.viewTable) {
|
||||
return
|
||||
}
|
||||
this.syncingFamilySelection = true
|
||||
const selectedStaffIds = selection.filter(item => item && item.staffRow).map(item => item.id)
|
||||
this.viewTableData.forEach(row => {
|
||||
if (!row || row.staffRow || !row.ledgerId) {
|
||||
return
|
||||
}
|
||||
this.$refs.viewTable.toggleRowSelection(row, selectedStaffIds.indexOf(row.ledgerId) !== -1)
|
||||
})
|
||||
this.$nextTick(() => {
|
||||
this.syncingFamilySelection = false
|
||||
})
|
||||
},
|
||||
confirmAssignGroup() {
|
||||
if (!this.viewRow || !this.viewRow.matterId) {
|
||||
this.$message.warning("线路信息不完整")
|
||||
return
|
||||
}
|
||||
this.$confirm("确认要自动分配未成团人员吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.doAssignGroup()
|
||||
}).catch(() => {})
|
||||
},
|
||||
doAssignGroup() {
|
||||
this.assignGroupLoading = true
|
||||
this.$axios.post(loc() + "/assignGroup", {
|
||||
matterId: this.viewRow.matterId
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success(res.msg || "分配成功")
|
||||
this.loadViewGroupOptions()
|
||||
this.loadViewData()
|
||||
this.pageData()
|
||||
} else {
|
||||
this.$message.warning(res.msg || "分配失败")
|
||||
}
|
||||
}).finally(() => {
|
||||
this.assignGroupLoading = false
|
||||
})
|
||||
},
|
||||
openAdjustGroup() {
|
||||
if (!this.viewSelection.length) {
|
||||
this.$message.warning("请选择需要调整的教职工")
|
||||
return
|
||||
}
|
||||
if (!this.viewGroupOptions.length) {
|
||||
this.$message.warning("暂无可调整的成团信息")
|
||||
return
|
||||
}
|
||||
this.adjustVisible = true
|
||||
},
|
||||
submitAdjustGroup() {
|
||||
if (!this.adjustForm.groupCode) {
|
||||
this.$message.warning("请选择成团信息")
|
||||
return
|
||||
}
|
||||
const ledgerIds = this.viewSelection.filter(item => item && item.staffRow).map(item => item.id).filter(id => id).join(",")
|
||||
if (!ledgerIds) {
|
||||
this.$message.warning("请选择需要调整的教职工")
|
||||
return
|
||||
}
|
||||
this.adjustLoading = true
|
||||
this.$axios.post(loc() + "/adjustGroup", {
|
||||
matterId: this.viewRow.matterId,
|
||||
groupCode: this.adjustForm.groupCode,
|
||||
ledgerIds: ledgerIds
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success(res.msg || "调整成功")
|
||||
this.adjustVisible = false
|
||||
this.loadViewGroupOptions()
|
||||
this.loadViewData()
|
||||
this.pageData()
|
||||
} else {
|
||||
this.$message.warning(res.msg || "调整失败")
|
||||
}
|
||||
}).finally(() => {
|
||||
this.adjustLoading = false
|
||||
})
|
||||
},
|
||||
resetAdjustForm() {
|
||||
this.adjustLoading = false
|
||||
this.adjustForm = {
|
||||
groupCode: ""
|
||||
}
|
||||
},
|
||||
viewSizeChange(size) {
|
||||
this.viewForm.pageSize = size
|
||||
this.viewForm.pageNumber = 1
|
||||
@@ -271,6 +426,7 @@ layout("/layouts/platform.html"){
|
||||
loadViewData() {
|
||||
if (!this.viewRow || !this.viewRow.matterId) {
|
||||
this.viewTableData = []
|
||||
this.viewSelection = []
|
||||
this.viewForm.totalCount = 0
|
||||
return
|
||||
}
|
||||
@@ -280,6 +436,7 @@ layout("/layouts/platform.html"){
|
||||
matterId: this.viewRow.matterId,
|
||||
keyword: this.viewForm.keyword,
|
||||
unionId: this.viewForm.unionId,
|
||||
groupCode: this.viewForm.groupCode,
|
||||
pageNumber: this.viewForm.pageNumber,
|
||||
pageSize: this.viewForm.pageSize,
|
||||
pageOrderName: this.viewForm.pageOrderName,
|
||||
@@ -289,6 +446,12 @@ layout("/layouts/platform.html"){
|
||||
if (res.code === 0) {
|
||||
const data = res.data || {}
|
||||
this.viewTableData = data.list || []
|
||||
this.viewSelection = []
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.viewTable) {
|
||||
this.$refs.viewTable.clearSelection()
|
||||
}
|
||||
})
|
||||
this.viewForm.totalCount = data.totalCount || 0
|
||||
} else {
|
||||
this.$message.warning(res.msg || "查询失败")
|
||||
@@ -299,6 +462,21 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
})
|
||||
},
|
||||
loadViewGroupOptions() {
|
||||
if (!this.viewRow || !this.viewRow.matterId) {
|
||||
this.viewGroupOptions = []
|
||||
return
|
||||
}
|
||||
this.$axios.post(loc() + "/groupOptions", {
|
||||
matterId: this.viewRow.matterId
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.viewGroupOptions = res.data || []
|
||||
} else {
|
||||
this.$message.warning(res.msg || "查询成团信息失败")
|
||||
}
|
||||
})
|
||||
},
|
||||
exportLine(row) {
|
||||
if (!row || !row.matterId) {
|
||||
this.$message.warning("线路信息不完整")
|
||||
@@ -347,21 +525,52 @@ layout("/layouts/platform.html"){
|
||||
margin-top: 12px;
|
||||
text-align: right;
|
||||
}
|
||||
.tour-group-view-header {
|
||||
align-items: flex-start;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
justify-content: flex-start;
|
||||
margin-bottom: 12px;
|
||||
max-width: 100%;
|
||||
}
|
||||
.tour-group-view-title {
|
||||
border-left: 4px solid #0079c2;
|
||||
color: #0079c2;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 16px;
|
||||
margin-bottom: 12px;
|
||||
padding-left: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.tour-family-list {
|
||||
padding: 8px 32px;
|
||||
.tour-group-options {
|
||||
display: flex;
|
||||
flex: 0 1 820px;
|
||||
flex-wrap: nowrap;
|
||||
gap: 8px;
|
||||
justify-content: flex-start;
|
||||
max-width: calc(100% - 120px);
|
||||
min-width: 0;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
.tour-family-empty {
|
||||
color: #909399;
|
||||
padding: 8px 32px;
|
||||
.tour-group-actions {
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
gap: 8px;
|
||||
margin-left: auto;
|
||||
}
|
||||
.tour-group-option {
|
||||
cursor: pointer;
|
||||
flex: 0 0 auto;
|
||||
max-width: 180px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.tour-group-option.is-active {
|
||||
border-color: #67c23a;
|
||||
font-weight: 600;
|
||||
}
|
||||
.el-table .direct-family-row > td,
|
||||
.el-table .direct-family-row > td .cell {
|
||||
|
||||
@@ -108,6 +108,12 @@ layout("/layouts/platform.html"){
|
||||
<el-table-column label="报名线路" prop="lineName" min-width="220" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="出行时段" prop="travelPeriod" min-width="260" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="线路类型" prop="lineType" width="130" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="成团信息" prop="groupName" width="160" align="center" header-align="center" show-overflow-tooltip>
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ formatGroupInfo(row) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="领办工会" prop="undertakeUnionName" min-width="160" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="报名时间" prop="signupTime" width="170" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="携带家属" prop="familyCount" width="120" sortable="custom" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
@@ -380,6 +386,10 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
formatGroupInfo(row) {
|
||||
if (!row || !row.groupCode) return ""
|
||||
return row.groupName ? row.groupCode + " " + row.groupName : row.groupCode
|
||||
},
|
||||
toBoolean(value) {
|
||||
return value === true || value === 1 || value === "1" || value === "true" || value === "TRUE"
|
||||
},
|
||||
|
||||
@@ -34,6 +34,11 @@ layout("/layouts/platform.html"){
|
||||
<el-option v-for="item in organizationTypeOptions" :key="item.code" :label="item.name" :value="item.code"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="线路类型">
|
||||
<el-select v-model="pageForm.lineType" clearable filterable placeholder="请选择线路类型" style="width: 100%">
|
||||
<el-option v-for="item in lineTypeOptions" :key="item.code" :label="item.name" :value="item.name"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<div class="search-query" style="margin-left: auto;">
|
||||
<el-button size="medium" type="primary" icon="el-icon-search" @click="doSearch">搜索</el-button>
|
||||
<el-button size="medium" @click="resetSearch">重置</el-button>
|
||||
@@ -43,10 +48,33 @@ layout("/layouts/platform.html"){
|
||||
|
||||
<el-card class="mt10" shadow="never">
|
||||
<table-tool :app="this" label="事项列表">
|
||||
<div class="tour-matter-signup-tool">
|
||||
<el-date-picker
|
||||
v-model="batchSignupTimeForm.signupStartTime"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="报名开始时间"
|
||||
size="medium">
|
||||
</el-date-picker>
|
||||
<span>-</span>
|
||||
<el-date-picker
|
||||
v-model="batchSignupTimeForm.signupEndTime"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="报名结束时间"
|
||||
size="medium">
|
||||
</el-date-picker>
|
||||
<el-button
|
||||
size="medium"
|
||||
type="primary"
|
||||
:loading="batchSignupTimeLoading"
|
||||
@click="assignSignupTime">一键赋值报名时间</el-button>
|
||||
</div>
|
||||
<el-button @click="openAdd" size="medium" type="primary">
|
||||
<i class="el-icon-plus"></i>
|
||||
新增
|
||||
</el-button>
|
||||
<el-button @click="exportData" size="medium" type="primary" icon="el-icon-download">导出</el-button>
|
||||
</table-tool>
|
||||
|
||||
<el-table
|
||||
@@ -54,13 +82,24 @@ layout("/layouts/platform.html"){
|
||||
:data="tableData"
|
||||
:size="tableSize"
|
||||
border
|
||||
:default-sort="{prop: 'lineCode', order: 'ascending'}"
|
||||
:row-class-name="tableRowClassName"
|
||||
@sort-change="pageOrder">
|
||||
<el-table-column label="序号" type="index" :index="indexMethod" width="80" align="center" header-align="center"></el-table-column>
|
||||
<el-table-column label="年度" prop="year" width="110" sortable="custom" align="center" header-align="center"></el-table-column>
|
||||
<el-table-column label="事项名称" prop="matterName" min-width="240" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="所属工会" prop="unionName" min-width="160" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column v-if="false" label="所属工会" prop="unionName" min-width="160" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="线路名称" prop="lineName" min-width="260" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="报名时间" min-width="300" align="center" header-align="center" show-overflow-tooltip>
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ formatTimeRange(row.signupStartTime, row.signupEndTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="出行时间" min-width="220" align="center" header-align="center" show-overflow-tooltip>
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ formatTimeRange(row.travelStartTime, row.travelEndTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="组织形式" prop="organizationTypeName" width="130" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="联系人" prop="contactName" width="130" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="联系方式" prop="contactPhone" width="150" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
@@ -201,7 +240,7 @@ layout("/layouts/platform.html"){
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="最多成团人数" prop="maxGroupPeople">
|
||||
<el-input-number v-model="batchForm.maxGroupPeople" :min="1" :precision="0" controls-position="right" style="width: 100%" @change="peopleChange"></el-input-number>
|
||||
<el-input-number v-model="batchForm.maxGroupPeople" :precision="0" controls-position="right" style="width: 100%" @change="peopleChange"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -218,6 +257,15 @@ layout("/layouts/platform.html"){
|
||||
.el-table .direct-family-row > td .cell {
|
||||
color: #f56c6c;
|
||||
}
|
||||
.tour-matter-signup-tool {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-right: 12px;
|
||||
}
|
||||
.tour-matter-signup-tool .el-date-editor {
|
||||
width: 210px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
@@ -257,9 +305,6 @@ layout("/layouts/platform.html"){
|
||||
const validatePeople = (rule, value, callback) => {
|
||||
if (!value || value <= 0) {
|
||||
callback(new Error("人数必须大于0"))
|
||||
} else if (this.batchForm.minGroupPeople && this.batchForm.maxGroupPeople
|
||||
&& this.batchForm.minGroupPeople > this.batchForm.maxGroupPeople) {
|
||||
callback(new Error("最少人数不能大于最多人数"))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
@@ -292,9 +337,15 @@ layout("/layouts/platform.html"){
|
||||
batchFormVisible: false,
|
||||
batchSubDis: false,
|
||||
batchTitle: "",
|
||||
batchSignupTimeLoading: false,
|
||||
batchSignupTimeForm: {
|
||||
signupStartTime: "",
|
||||
signupEndTime: ""
|
||||
},
|
||||
currentMatter: {},
|
||||
batchForm: {},
|
||||
lineOptions: [],
|
||||
lineTypeOptions: [],
|
||||
settingOptions: [],
|
||||
unionOptions: [],
|
||||
organizationTypeOptions: [],
|
||||
@@ -302,10 +353,13 @@ layout("/layouts/platform.html"){
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
pageOrderName: "lineCode",
|
||||
pageOrderBy: "ascending",
|
||||
year: currentYear,
|
||||
matterName: "",
|
||||
unionId: "",
|
||||
organizationType: ""
|
||||
organizationType: "",
|
||||
lineType: ""
|
||||
},
|
||||
formData: {},
|
||||
formRules: {
|
||||
@@ -324,7 +378,6 @@ layout("/layouts/platform.html"){
|
||||
contactName: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
|
||||
contactPhone: [{ validator: validateMobile, trigger: ["blur", "change"] }],
|
||||
minGroupPeople: [{ validator: validatePeople, trigger: ["blur", "change"] }],
|
||||
maxGroupPeople: [{ validator: validatePeople, trigger: ["blur", "change"] }],
|
||||
estimatedCost: [{ validator: validateMoney, trigger: ["blur", "change"] }]
|
||||
}
|
||||
}
|
||||
@@ -355,9 +408,65 @@ layout("/layouts/platform.html"){
|
||||
this.pageForm.matterName = ""
|
||||
this.pageForm.unionId = ""
|
||||
this.pageForm.organizationType = ""
|
||||
this.pageForm.lineType = ""
|
||||
this.loadSettings(this.pageForm.year)
|
||||
this.doSearch()
|
||||
},
|
||||
formatTimeRange(startTime, endTime) {
|
||||
if (!startTime && !endTime) return ""
|
||||
if (!startTime) return endTime || ""
|
||||
if (!endTime) return startTime || ""
|
||||
return startTime + " 至 " + endTime
|
||||
},
|
||||
exportData() {
|
||||
const params = new URLSearchParams()
|
||||
;["year", "matterName", "unionId", "organizationType", "lineType"].forEach(key => {
|
||||
const value = this.pageForm[key]
|
||||
if (value !== undefined && value !== null && value !== "") {
|
||||
params.append(key, value)
|
||||
}
|
||||
})
|
||||
window.location.href = loc() + "/exportData?" + params.toString()
|
||||
},
|
||||
// 按当前筛选条件批量更新事项报名时间,提交前必须让用户确认更新范围。
|
||||
assignSignupTime() {
|
||||
const startTime = this.batchSignupTimeForm.signupStartTime
|
||||
const endTime = this.batchSignupTimeForm.signupEndTime
|
||||
if (!startTime || !endTime) {
|
||||
this.$message.warning("请选择报名开始时间和报名结束时间")
|
||||
return
|
||||
}
|
||||
if (startTime >= endTime) {
|
||||
this.$message.warning("报名开始时间必须小于报名结束时间")
|
||||
return
|
||||
}
|
||||
this.$confirm("确认将当前查询条件下的事项报名时间统一赋值为:" + startTime + " 至 " + endTime + "?", "提示", {
|
||||
confirmButtonText: "确认",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.batchSignupTimeLoading = true
|
||||
this.$axios.post(loc() + "/assignSignupTime", {
|
||||
year: this.pageForm.year,
|
||||
matterName: this.pageForm.matterName,
|
||||
unionId: this.pageForm.unionId,
|
||||
organizationType: this.pageForm.organizationType,
|
||||
lineType: this.pageForm.lineType,
|
||||
signupStartTime: startTime,
|
||||
signupEndTime: endTime
|
||||
}).then((res) => {
|
||||
this.batchSignupTimeLoading = false
|
||||
if (res.code === 0) {
|
||||
this.$message.success(res.msg || "赋值成功")
|
||||
this.pageData()
|
||||
} else {
|
||||
this.$message.warning(res.msg || "赋值失败")
|
||||
}
|
||||
}).catch(() => {
|
||||
this.batchSignupTimeLoading = false
|
||||
})
|
||||
}).catch(() => {})
|
||||
},
|
||||
tableRowClassName({ row }) {
|
||||
return this.isDirectFamilyLine(row) ? "direct-family-row" : ""
|
||||
},
|
||||
@@ -478,6 +587,13 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
})
|
||||
},
|
||||
loadLineTypes() {
|
||||
this.$axios.post(loc() + "/lineTypeOptions").then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.lineTypeOptions = res.data || []
|
||||
}
|
||||
})
|
||||
},
|
||||
emptyBatchForm() {
|
||||
return {
|
||||
id: this.currentMatter.id || "",
|
||||
@@ -530,7 +646,9 @@ layout("/layouts/platform.html"){
|
||||
if (!item) return ""
|
||||
const lineName = this.lineField(item, "lineName") || ""
|
||||
const lineType = this.lineField(item, "lineType") || ""
|
||||
return lineType ? lineName + "(" + lineType + ")" : lineName
|
||||
const travelAgencyName = this.lineField(item, "travelAgencyName") || ""
|
||||
const lineDesc = [lineType, travelAgencyName].filter(item => item).join("/")
|
||||
return lineDesc ? lineName + "(" + lineDesc + ")" : lineName
|
||||
},
|
||||
lineChange() {
|
||||
this.applySelectedLineDefaults(true)
|
||||
@@ -589,10 +707,12 @@ layout("/layouts/platform.html"){
|
||||
},
|
||||
applySettingSignupTime(data) {
|
||||
if (!data) return
|
||||
if (data.signupStartTime) {
|
||||
// 已保存线路配置时保留事项自身报名时间,避免配置默认值覆盖用户修改。
|
||||
const hasSavedLineConfig = !!this.batchForm.lineId
|
||||
if (!hasSavedLineConfig && data.signupStartTime) {
|
||||
this.$set(this.batchForm, "signupStartTime", data.signupStartTime)
|
||||
}
|
||||
if (data.signupEndTime) {
|
||||
if (!hasSavedLineConfig && data.signupEndTime) {
|
||||
this.$set(this.batchForm, "signupEndTime", data.signupEndTime)
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
@@ -603,10 +723,12 @@ layout("/layouts/platform.html"){
|
||||
},
|
||||
applySettingPeople(data) {
|
||||
if (!data) return
|
||||
if (data.minGroupPeople !== null && data.minGroupPeople !== undefined && data.minGroupPeople !== "") {
|
||||
// 已保存线路配置时保留事项自身成团人数,配置人数只作为首次选择线路的默认值。
|
||||
const hasSavedLineConfig = !!this.batchForm.lineId
|
||||
if (!hasSavedLineConfig && data.minGroupPeople !== null && data.minGroupPeople !== undefined && data.minGroupPeople !== "") {
|
||||
this.$set(this.batchForm, "minGroupPeople", data.minGroupPeople)
|
||||
}
|
||||
if (data.maxGroupPeople !== null && data.maxGroupPeople !== undefined && data.maxGroupPeople !== "") {
|
||||
if (!hasSavedLineConfig && data.maxGroupPeople !== null && data.maxGroupPeople !== undefined && data.maxGroupPeople !== "") {
|
||||
this.$set(this.batchForm, "maxGroupPeople", data.maxGroupPeople)
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
@@ -731,6 +853,7 @@ layout("/layouts/platform.html"){
|
||||
this.loadSettings(this.pageForm.year)
|
||||
this.loadUnions()
|
||||
this.loadOrganizationTypes()
|
||||
this.loadLineTypes()
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -29,6 +29,11 @@ layout("/layouts/platform.html"){
|
||||
<el-option v-for="item in lotOptions" :key="item.id" :label="item.lotName" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="线路类型">
|
||||
<el-select v-model="pageForm.lineType" clearable filterable placeholder="请选择线路类型" style="width: 100%">
|
||||
<el-option v-for="item in lineTypeOptions" :key="item.code" :label="item.name" :value="item.name"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<div class="search-query" style="margin-left: auto;">
|
||||
<el-button size="medium" type="primary" icon="el-icon-search" @click="doSearch">搜索</el-button>
|
||||
<el-button size="medium" @click="resetSearch">重置</el-button>
|
||||
@@ -42,6 +47,7 @@ layout("/layouts/platform.html"){
|
||||
<i class="el-icon-plus"></i>
|
||||
新增
|
||||
</el-button>
|
||||
<el-button @click="exportData" size="medium" type="primary" icon="el-icon-download">导出</el-button>
|
||||
</table-tool>
|
||||
|
||||
<el-table
|
||||
@@ -323,7 +329,7 @@ layout("/layouts/platform.html"){
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="最多成团人数" prop="maxGroupPeople">
|
||||
<el-input-number v-model="batchForm.maxGroupPeople" :min="1" :precision="0" controls-position="right" style="width: 100%" @change="matterPeopleChange"></el-input-number>
|
||||
<el-input-number v-model="batchForm.maxGroupPeople" :precision="0" controls-position="right" style="width: 100%" @change="matterPeopleChange"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -386,9 +392,6 @@ layout("/layouts/platform.html"){
|
||||
const validateMatterPeople = (rule, value, callback) => {
|
||||
if (!value || value <= 0) {
|
||||
callback(new Error("人数必须大于0"))
|
||||
} else if (this.batchForm.minGroupPeople && this.batchForm.maxGroupPeople
|
||||
&& this.batchForm.minGroupPeople > this.batchForm.maxGroupPeople) {
|
||||
callback(new Error("最少人数不能大于最多人数"))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
@@ -438,7 +441,8 @@ layout("/layouts/platform.html"){
|
||||
pageOrderBy: "ascending",
|
||||
year: currentYear,
|
||||
lineName: "",
|
||||
lotId: ""
|
||||
lotId: "",
|
||||
lineType: ""
|
||||
},
|
||||
formData: {},
|
||||
matterForm: {},
|
||||
@@ -468,7 +472,6 @@ layout("/layouts/platform.html"){
|
||||
contactName: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
|
||||
contactPhone: [{ validator: validateMatterMobile, trigger: ["blur", "change"] }],
|
||||
minGroupPeople: [{ validator: validateMatterPeople, trigger: ["blur", "change"] }],
|
||||
maxGroupPeople: [{ validator: validateMatterPeople, trigger: ["blur", "change"] }],
|
||||
estimatedCost: [{ validator: validateMatterMoney, trigger: ["blur", "change"] }]
|
||||
}
|
||||
}
|
||||
@@ -478,9 +481,20 @@ layout("/layouts/platform.html"){
|
||||
this.pageForm.year = moment().format("YYYY")
|
||||
this.pageForm.lineName = ""
|
||||
this.pageForm.lotId = ""
|
||||
this.pageForm.lineType = ""
|
||||
this.loadOptions(this.pageForm.year)
|
||||
this.doSearch()
|
||||
},
|
||||
exportData() {
|
||||
const params = new URLSearchParams()
|
||||
;["year", "lineName", "lotId", "lineType"].forEach(key => {
|
||||
const value = this.pageForm[key]
|
||||
if (value !== undefined && value !== null && value !== "") {
|
||||
params.append(key, value)
|
||||
}
|
||||
})
|
||||
window.location.href = loc() + "/exportData?" + params.toString()
|
||||
},
|
||||
tableRowClassName({ row }) {
|
||||
return this.isDirectFamilyLine(row) ? "direct-family-row" : ""
|
||||
},
|
||||
@@ -767,10 +781,11 @@ layout("/layouts/platform.html"){
|
||||
},
|
||||
applyMatterSettingPeople(data) {
|
||||
if (!data) return
|
||||
const hasSavedLineConfig = !!this.batchForm.lineId
|
||||
if (data.minGroupPeople !== null && data.minGroupPeople !== undefined && data.minGroupPeople !== "") {
|
||||
this.$set(this.batchForm, "minGroupPeople", data.minGroupPeople)
|
||||
}
|
||||
if (data.maxGroupPeople !== null && data.maxGroupPeople !== undefined && data.maxGroupPeople !== "") {
|
||||
if (!hasSavedLineConfig && data.maxGroupPeople !== null && data.maxGroupPeople !== undefined && data.maxGroupPeople !== "") {
|
||||
this.$set(this.batchForm, "maxGroupPeople", data.maxGroupPeople)
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
|
||||
@@ -313,15 +313,6 @@ layout("/layouts/platform.html"){
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
data() {
|
||||
// 前端先做成团人数区间校验,后端也会再兜底校验一次。
|
||||
const checkGroupPeople = (rule, value, callback) => {
|
||||
if (this.formData.minGroupPeople !== null && this.formData.maxGroupPeople !== null
|
||||
&& this.formData.minGroupPeople > this.formData.maxGroupPeople) {
|
||||
callback(new Error("最少成团人数不能大于最多成团人数"))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
const checkSignupTime = (rule, value, callback) => {
|
||||
if (!value) {
|
||||
callback(new Error("必填"))
|
||||
@@ -369,8 +360,6 @@ layout("/layouts/platform.html"){
|
||||
formRules: {
|
||||
year: [{required: true, message: "必填", trigger: ["blur", "change"]}],
|
||||
configName: [{required: true, message: "必填", trigger: ["blur", "change"]}],
|
||||
minGroupPeople: [{validator: checkGroupPeople, trigger: ["blur", "change"]}],
|
||||
maxGroupPeople: [{validator: checkGroupPeople, trigger: ["blur", "change"]}],
|
||||
signupStartTime: [{validator: checkSignupTime, trigger: ["blur", "change"]}],
|
||||
signupEndTime: [{validator: checkSignupTime, trigger: ["blur", "change"]}],
|
||||
outProvinceRatioType: [{required: true, message: "必填", trigger: ["blur", "change"]}],
|
||||
|
||||
@@ -49,7 +49,7 @@ layout("/layouts/platform.html"){
|
||||
:data="tableData"
|
||||
:size="tableSize"
|
||||
border
|
||||
:default-sort="{prop: 'lineName', order: 'ascending'}"
|
||||
:default-sort="{prop: 'lineCode', order: 'ascending'}"
|
||||
:row-class-name="tableRowClassName"
|
||||
@sort-change="pageOrder">
|
||||
<el-table-column label="序号" type="index" :index="indexMethod" width="80" align="center" header-align="center"></el-table-column>
|
||||
@@ -624,7 +624,7 @@ layout("/layouts/platform.html"){
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
pageOrderName: "lineName",
|
||||
pageOrderName: "lineCode",
|
||||
pageOrderBy: "ascending",
|
||||
year: currentYear,
|
||||
lineName: "",
|
||||
|
||||
@@ -29,8 +29,8 @@ layout("/layouts/platform.html"){
|
||||
<el-option v-for="item in lineTypeOptions" :key="item.lineType" :label="item.lineType" :value="item.lineType"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="所属工会">
|
||||
<el-select v-model="pageForm.unionId" clearable filterable placeholder="请选择所属工会" style="width: 100%">
|
||||
<search-item label="领办工会">
|
||||
<el-select v-model="pageForm.unionId" clearable filterable placeholder="请选择领办工会" style="width: 100%">
|
||||
<el-option v-for="item in unionOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
@@ -61,35 +61,25 @@ layout("/layouts/platform.html"){
|
||||
<el-table-column label="线路名称" prop="lineName" min-width="220" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="出行时段" prop="travelPeriod" width="260" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column v-if="false" label="事项名称" prop="matterName" min-width="200" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="所属工会" prop="unionName" min-width="180" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="领办工会" prop="unionName" min-width="180" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="领办状态" prop="undertakeStatusName" width="150" sortable="custom" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
<el-button size="mini" :type="isClaimed(row) ? 'info' : 'primary'" plain>{{ row.undertakeStatusName || '未领' }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="线路类型" prop="lineType" width="140" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="最少成团人数" prop="minGroupPeople" width="140" sortable="custom" align="center" header-align="center">
|
||||
<el-table-column label="成团信息" prop="groupName" width="160" align="center" header-align="center" show-overflow-tooltip>
|
||||
<template slot-scope="{row}">
|
||||
{{ row.minGroupPeople || 0 }}人
|
||||
<span>{{ formatGroupInfo(row) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="最多成团人数" prop="maxGroupPeople" width="140" sortable="custom" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
{{ row.maxGroupPeople || 0 }}人
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="报名人数" prop="signupCount" width="160" sortable="custom" align="center" header-align="center">
|
||||
<el-table-column label="报名人数" prop="signupCount" width="160" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
<el-tag size="mini" :type="Number(row.signupCount || 0) > 0 ? 'success' : 'info'">
|
||||
{{ row.signupCount || 0 }}人<span v-if="row.showCurrentUnionSignupCount">({{ row.currentUnionSignupCount || 0 }}人)</span>
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="成团状态" prop="groupStatusName" width="120" sortable="custom" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
<el-tag size="mini" :type="groupStatusType(row.groupStatus)">{{ row.groupStatusName || '未成团' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="220" align="center" header-align="center" fixed="right">
|
||||
<template slot-scope="{row}">
|
||||
<el-button size="mini" type="primary" @click="openView(row)">查看</el-button>
|
||||
@@ -141,26 +131,21 @@ layout("/layouts/platform.html"){
|
||||
:size="tableSize"
|
||||
border
|
||||
@sort-change="viewPageOrder">
|
||||
<el-table-column type="expand" width="50">
|
||||
<template slot-scope="{row}">
|
||||
<div v-if="row.families && row.families.length > 0" class="tour-family-list">
|
||||
<el-table :data="row.families" :size="tableSize" border>
|
||||
<el-table-column label="工号" prop="jobNo" width="130" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="姓名" prop="userName" width="120" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="亲属关系" prop="relationship" width="120" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="手机号" prop="mobile" width="140" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="身份证号" prop="idCard" min-width="190" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div v-else class="tour-family-empty">暂无亲属信息</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="序号" type="index" :index="viewIndexMethod" width="80" align="center" header-align="center"></el-table-column>
|
||||
<el-table-column label="工号" prop="jobNo" width="130" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="姓名" prop="userName" width="120" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="性别" prop="gender" width="90" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="手机号码" prop="mobile" width="140" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="身份证号" prop="idCard" min-width="190" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="所属工会" prop="unionName" min-width="180" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="人员类型" prop="rowTypeName" width="90" align="center" header-align="center"></el-table-column>
|
||||
<el-table-column label="亲属关系" prop="relationship" width="120" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="成团信息" prop="groupName" width="160" sortable="custom" align="center" header-align="center" show-overflow-tooltip>
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ formatGroupInfo(row) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="关联教职工名称" prop="relatedStaffName" width="150" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
</el-table>
|
||||
<el-row class="el-pagination-container tour-group-view-pagination">
|
||||
<el-pagination
|
||||
@@ -194,6 +179,7 @@ layout("/layouts/platform.html"){
|
||||
viewRequestSeq: 0,
|
||||
viewTitle: "",
|
||||
viewRow: {},
|
||||
viewGroup: {},
|
||||
viewTableData: [],
|
||||
currentUnionInfo: null,
|
||||
pageForm: {
|
||||
@@ -213,9 +199,10 @@ layout("/layouts/platform.html"){
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
pageOrderName: "signupTime",
|
||||
pageOrderBy: "descending",
|
||||
pageOrderBy: "ascending",
|
||||
keyword: "",
|
||||
unionId: ""
|
||||
unionId: "",
|
||||
groupCode: ""
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -233,11 +220,6 @@ layout("/layouts/platform.html"){
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageData()
|
||||
},
|
||||
groupStatusType(status) {
|
||||
if (status === "formed") return "success"
|
||||
if (status === "over") return "danger"
|
||||
return "info"
|
||||
},
|
||||
tableRowClassName({ row }) {
|
||||
return this.isDirectFamilyLine(row) ? "direct-family-row" : ""
|
||||
},
|
||||
@@ -250,17 +232,30 @@ layout("/layouts/platform.html"){
|
||||
isClaimed(row) {
|
||||
return row && row.undertakeStatus === "claimed"
|
||||
},
|
||||
formatGroupInfo(row) {
|
||||
if (!row || !row.groupCode) return "未成团"
|
||||
return row.groupName ? row.groupCode + " " + row.groupName : row.groupCode
|
||||
},
|
||||
openView(row) {
|
||||
if (!row || !row.groupCode) {
|
||||
this.$message.warning("成团信息不完整")
|
||||
return
|
||||
}
|
||||
this.viewRow = row || {}
|
||||
this.viewTitle = this.viewRow.lineName || "报名人员"
|
||||
this.viewGroup = {
|
||||
groupCode: row.groupCode,
|
||||
groupName: row.groupName
|
||||
}
|
||||
this.viewTitle = (this.viewRow.lineName || "报名人员") + " - " + (this.viewGroup.groupName || this.viewGroup.groupCode)
|
||||
this.viewVisible = true
|
||||
this.viewForm.pageNumber = 1
|
||||
this.viewForm.pageSize = 10
|
||||
this.viewForm.totalCount = 0
|
||||
this.viewForm.pageOrderName = "signupTime"
|
||||
this.viewForm.pageOrderBy = "descending"
|
||||
this.viewForm.pageOrderBy = "ascending"
|
||||
this.viewForm.keyword = ""
|
||||
this.viewForm.unionId = ""
|
||||
this.viewForm.groupCode = this.viewGroup.groupCode || ""
|
||||
this.viewTableData = []
|
||||
this.loadViewData()
|
||||
},
|
||||
@@ -278,24 +273,26 @@ layout("/layouts/platform.html"){
|
||||
})
|
||||
},
|
||||
undertakeLine(row) {
|
||||
if (!row || !row.matterId) {
|
||||
this.$message.warning("线路信息不完整")
|
||||
if (!row || !row.matterId || !row.groupCode) {
|
||||
this.$message.warning("线路成团信息不完整")
|
||||
return
|
||||
}
|
||||
if (this.isClaimed(row)) {
|
||||
this.$message.warning("当前线路已领办,不允许修改")
|
||||
this.$message.warning("当前团已领办,不允许修改")
|
||||
return
|
||||
}
|
||||
this.loadCurrentUnion().then((union) => {
|
||||
const lineName = row.lineName || "当前线路"
|
||||
const groupName = this.formatGroupInfo(row)
|
||||
const unionName = (union && union.unionName) || ""
|
||||
return this.$confirm(lineName + "由" + unionName + "领办,领办后,系统不允许修改,请确认。", "提示", {
|
||||
return this.$confirm(lineName + "【" + groupName + "】由" + unionName + "领办,领办后,系统不允许修改,请确认。", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
return this.$axios.post(loc() + "/undertakeLine", {
|
||||
matterId: row.matterId
|
||||
matterId: row.matterId,
|
||||
groupCode: row.groupCode
|
||||
})
|
||||
})
|
||||
}).then((res) => {
|
||||
@@ -309,22 +306,24 @@ layout("/layouts/platform.html"){
|
||||
}).catch(() => {})
|
||||
},
|
||||
releaseUndertakeLine(row) {
|
||||
if (!row || !row.matterId) {
|
||||
this.$message.warning("线路信息不完整")
|
||||
if (!row || !row.matterId || !row.groupCode) {
|
||||
this.$message.warning("线路成团信息不完整")
|
||||
return
|
||||
}
|
||||
if (!this.isClaimed(row)) {
|
||||
this.$message.warning("当前线路未领办,无需解除")
|
||||
this.$message.warning("当前团未领办,无需解除")
|
||||
return
|
||||
}
|
||||
const lineName = row.lineName || "当前线路"
|
||||
this.$confirm("确认解除【" + lineName + "】的领办状态吗?解除后该线路将变为未领。", "提示", {
|
||||
const groupName = this.formatGroupInfo(row)
|
||||
this.$confirm("确认解除【" + lineName + "】" + groupName + "的领办状态吗?解除后该团将变为未领。", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
return this.$axios.post(loc() + "/releaseUndertakeLine", {
|
||||
matterId: row.matterId
|
||||
matterId: row.matterId,
|
||||
groupCode: row.groupCode
|
||||
})
|
||||
}).then((res) => {
|
||||
if (!res) return
|
||||
@@ -344,6 +343,7 @@ layout("/layouts/platform.html"){
|
||||
this.viewForm.keyword = ""
|
||||
this.viewForm.unionId = ""
|
||||
this.viewForm.pageNumber = 1
|
||||
this.viewForm.groupCode = this.viewGroup.groupCode || ""
|
||||
this.loadViewData()
|
||||
},
|
||||
viewIndexMethod(index) {
|
||||
@@ -360,12 +360,12 @@ layout("/layouts/platform.html"){
|
||||
},
|
||||
viewPageOrder({ prop, order }) {
|
||||
this.viewForm.pageOrderName = prop || "signupTime"
|
||||
this.viewForm.pageOrderBy = order || "descending"
|
||||
this.viewForm.pageOrderBy = order || "ascending"
|
||||
this.viewForm.pageNumber = 1
|
||||
this.loadViewData()
|
||||
},
|
||||
loadViewData() {
|
||||
if (!this.viewRow || !this.viewRow.matterId) {
|
||||
if (!this.viewRow || !this.viewRow.matterId || !this.viewForm.groupCode) {
|
||||
this.viewTableData = []
|
||||
this.viewForm.totalCount = 0
|
||||
return
|
||||
@@ -376,6 +376,7 @@ layout("/layouts/platform.html"){
|
||||
matterId: this.viewRow.matterId,
|
||||
keyword: this.viewForm.keyword,
|
||||
unionId: this.viewForm.unionId,
|
||||
groupCode: this.viewForm.groupCode,
|
||||
pageNumber: this.viewForm.pageNumber,
|
||||
pageSize: this.viewForm.pageSize,
|
||||
pageOrderName: this.viewForm.pageOrderName,
|
||||
@@ -445,13 +446,6 @@ layout("/layouts/platform.html"){
|
||||
margin-bottom: 12px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
.tour-family-list {
|
||||
padding: 8px 32px;
|
||||
}
|
||||
.tour-family-empty {
|
||||
color: #909399;
|
||||
padding: 8px 32px;
|
||||
}
|
||||
.tour-undertake-tip {
|
||||
margin-top: 8px;
|
||||
color: #f56c6c;
|
||||
|
||||
@@ -534,7 +534,7 @@ layout("/layouts/platform_h5.html"){
|
||||
lineType: "省内线路",
|
||||
unionId: "",
|
||||
directFamilyUnitLine: null,
|
||||
pageOrderName: "lineName",
|
||||
pageOrderName: "lineCode",
|
||||
pageOrderBy: "ascending"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user