疗休养人员名单
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())) {
|
||||
|
||||
+6
@@ -26,6 +26,7 @@ import com.budwk.app.zhgh.dayofficework.tour.models.TourTravelAgency;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerDirectRelativeService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerFamilyService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourParticipantRosterService;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.ss.usermodel.BorderStyle;
|
||||
@@ -90,6 +91,9 @@ public class TourLedgerController {
|
||||
@Inject
|
||||
private TourLedgerDirectRelativeService tourLedgerDirectRelativeService;
|
||||
|
||||
@Inject
|
||||
private TourParticipantRosterService tourParticipantRosterService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/Tour/ledger/index.html")
|
||||
@SaCheckPermission("tour.ledger")
|
||||
@@ -216,6 +220,8 @@ public class TourLedgerController {
|
||||
if (ledger == null) {
|
||||
return Result.error("台账记录不存在");
|
||||
}
|
||||
// Reset the participant roster before deleting the ledger record from the admin ledger page.
|
||||
tourParticipantRosterService.markNotJoinedByLedger(ledger);
|
||||
tourLedgerFamilyService.clear(Cnd.where(TourLedgerFamily::getLedgerId, "=", id));
|
||||
tourLedgerService.delete(id);
|
||||
return Result.success();
|
||||
|
||||
+10
@@ -31,6 +31,7 @@ import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerDirectRelativeSer
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerFamilyService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourMatterService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourParticipantRosterService;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Sqls;
|
||||
@@ -83,6 +84,9 @@ public class TourMySignupController {
|
||||
@Inject
|
||||
private TourMatterService tourMatterService;
|
||||
|
||||
@Inject
|
||||
private TourParticipantRosterService tourParticipantRosterService;
|
||||
|
||||
@Inject
|
||||
private SysDictService sysDictService;
|
||||
|
||||
@@ -507,6 +511,8 @@ public class TourMySignupController {
|
||||
return workflowResult;
|
||||
}
|
||||
}
|
||||
// Signup modification keeps the staff member joined and refreshes the linked ledger id.
|
||||
tourParticipantRosterService.markJoinedByLedger(ledger);
|
||||
return Result.success().addMsg(approvalRequired ? "修改已提交,等待审核" : "修改成功");
|
||||
}
|
||||
|
||||
@@ -529,6 +535,8 @@ public class TourMySignupController {
|
||||
if (signupEndResult != null) {
|
||||
return signupEndResult;
|
||||
}
|
||||
// Reset the roster before deleting the ledger record, because the ledger still carries setting linkage here.
|
||||
tourParticipantRosterService.markNotJoinedByLedger(ledger);
|
||||
tourLedgerFamilyService.clear(Cnd.where(TourLedgerFamily::getLedgerId, "=", ledger.getId()));
|
||||
tourLedgerDirectRelativeService.clear(Cnd.where(TourLedgerDirectRelative::getLedgerId, "=", ledger.getId()));
|
||||
tourLedgerService.clear(Cnd.where(TourLedger::getId, "=", ledger.getId()));
|
||||
@@ -548,6 +556,8 @@ public class TourMySignupController {
|
||||
if (signupEndResult != null) {
|
||||
return signupEndResult;
|
||||
}
|
||||
// Reset the roster before deleting the ledger record, because the ledger still carries setting linkage here.
|
||||
tourParticipantRosterService.markNotJoinedByLedger(ledger);
|
||||
tourLedgerFamilyService.clear(Cnd.where(TourLedgerFamily::getLedgerId, "=", ledger.getId()));
|
||||
tourLedgerDirectRelativeService.clear(Cnd.where(TourLedgerDirectRelative::getLedgerId, "=", ledger.getId()));
|
||||
tourLedgerService.clear(Cnd.where(TourLedger::getId, "=", ledger.getId()));
|
||||
|
||||
+366
@@ -0,0 +1,366 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourParticipantRosterService;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.json.Json;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 疗休养人员名单统计查询控制器。
|
||||
* 名单表保存可参与人员基础信息,报名线路、成团等信息通过台账补充读取。
|
||||
*/
|
||||
@IocBean
|
||||
@Ok("json:full")
|
||||
@At("/platform/tour/participantRoster")
|
||||
public class TourParticipantRosterController {
|
||||
|
||||
@Inject
|
||||
private TourParticipantRosterService tourParticipantRosterService;
|
||||
|
||||
/**
|
||||
* 打开 PC 端疗休养人员名单查询页面。
|
||||
*/
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/Tour/participantRoster/index.html")
|
||||
@SaCheckPermission("tour.participantRoster")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 按年度范围和可选报名维度查询人员名单。
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("tour.participantRoster")
|
||||
public Result pageData(PageForm pageForm, Integer startYear, Integer endYear, String settingId, String matterId,
|
||||
String keyword, String unitName, String unionId, Boolean joined, String lineType,
|
||||
String groupCode, String undertakeUnionId) {
|
||||
Result yearResult = checkYearRange(startYear, endYear);
|
||||
if (yearResult != null) {
|
||||
return yearResult;
|
||||
}
|
||||
Cnd cnd = buildQueryCnd(startYear, endYear, settingId, matterId, keyword, unitName, unionId, joined,
|
||||
lineType, groupCode, undertakeUnionId);
|
||||
|
||||
Sql countSql = Sqls.create("""
|
||||
SELECT COUNT(1)
|
||||
FROM tour_participant_roster r
|
||||
INNER JOIN tour_setting s ON s.id = r.settingId AND s.delFlag = 0
|
||||
LEFT JOIN tour_ledger t ON t.id = r.ledgerId AND t.delFlag = 0
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
$condition
|
||||
""");
|
||||
countSql.setCondition(cnd);
|
||||
countSql.setCallback(Sqls.callback.integer());
|
||||
tourParticipantRosterService.dao().execute(countSql);
|
||||
|
||||
Sql listSql = Sqls.create("""
|
||||
SELECT
|
||||
r.id,
|
||||
s.`year`,
|
||||
s.configName,
|
||||
r.jobNo,
|
||||
r.userName,
|
||||
r.unitId,
|
||||
r.unitName,
|
||||
r.unionId,
|
||||
r.unionName,
|
||||
r.joined,
|
||||
r.ledgerId,
|
||||
t.lineType,
|
||||
COALESCE(NULLIF(l.lineName, ''), t.lineName) AS lineName,
|
||||
m.matterName,
|
||||
CASE
|
||||
WHEN IFNULL(m.travelStartTime, '') <> '' AND IFNULL(m.travelEndTime, '') <> ''
|
||||
THEN CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime)
|
||||
ELSE ''
|
||||
END AS travelPeriod,
|
||||
t.groupCode,
|
||||
t.groupName,
|
||||
t.undertakeUnionId,
|
||||
t.undertakeUnionName,
|
||||
t.signupTime
|
||||
FROM tour_participant_roster r
|
||||
INNER JOIN tour_setting s ON s.id = r.settingId AND s.delFlag = 0
|
||||
LEFT JOIN tour_ledger t ON t.id = r.ledgerId AND t.delFlag = 0
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN tour_line l ON l.id = t.lineId AND l.delFlag = 0
|
||||
$condition
|
||||
ORDER BY $orderColumn $orderBy, s.`year` DESC, r.unionName ASC, r.unitName ASC, r.jobNo ASC
|
||||
""");
|
||||
listSql.setCondition(cnd);
|
||||
listSql.setVar("orderColumn", getOrderColumn(pageForm.getPageOrderName()));
|
||||
listSql.setVar("orderBy", "descending".equals(pageForm.getPageOrderBy()) ? "desc" : "asc");
|
||||
listSql.setPager(tourParticipantRosterService.dao().createPager(pageForm.getPageNumber(), pageForm.getPageSize()));
|
||||
listSql.setCallback(Sqls.callback.maps());
|
||||
tourParticipantRosterService.dao().execute(listSql);
|
||||
|
||||
Pagination<NutMap> pagination = new Pagination<>(
|
||||
pageForm.getPageNumber(),
|
||||
pageForm.getPageSize(),
|
||||
countSql.getInt(),
|
||||
listSql.getList(NutMap.class)
|
||||
);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据年度范围加载疗休养配置下拉选项。
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("tour.participantRoster")
|
||||
public Result settingOptions(Integer startYear, Integer endYear) {
|
||||
Result yearResult = checkYearRange(startYear, endYear);
|
||||
if (yearResult != null) {
|
||||
return yearResult;
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT id, configName, `year`
|
||||
FROM tour_setting
|
||||
WHERE delFlag = 0
|
||||
AND `year` >= @startYear
|
||||
AND `year` <= @endYear
|
||||
ORDER BY `year` DESC, sortNo ASC, createdAt DESC
|
||||
""");
|
||||
sql.setParam("startYear", startYear);
|
||||
sql.setParam("endYear", endYear);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourParticipantRosterService.dao().execute(sql);
|
||||
return Result.success(sql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载线路选择器使用的疗休养事项选项。
|
||||
* 未选择配置时加载年度范围内全部事项,选择配置后只加载当前配置下事项。
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("tour.participantRoster")
|
||||
public Result lineOptions(Integer startYear, Integer endYear, String settingId) {
|
||||
Result yearResult = checkYearRange(startYear, endYear);
|
||||
if (yearResult != null) {
|
||||
return yearResult;
|
||||
}
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("s.delFlag", "=", false);
|
||||
cnd.and("m.delFlag", "=", false);
|
||||
cnd.and("m.lineId", "IS NOT", null);
|
||||
cnd.and("m.lineId", "<>", "");
|
||||
cnd.and("s.`year`", ">=", startYear);
|
||||
cnd.and("s.`year`", "<=", endYear);
|
||||
cnd.andEX("s.id", "=", settingId);
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
m.id AS matterId,
|
||||
m.matterName,
|
||||
s.id AS settingId,
|
||||
s.configName,
|
||||
s.`year`,
|
||||
l.id AS lineId,
|
||||
l.lineName,
|
||||
l.lineType,
|
||||
CONCAT(s.configName, '【', s.`year`, '】 / ', m.matterName) AS label
|
||||
FROM tour_matter m
|
||||
INNER JOIN tour_setting s ON s.id = m.settingId
|
||||
LEFT JOIN tour_line l ON l.id = m.lineId AND l.delFlag = 0
|
||||
$condition
|
||||
ORDER BY s.`year` DESC, s.sortNo ASC, m.travelStartTime ASC, m.createdAt DESC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourParticipantRosterService.dao().execute(sql);
|
||||
return Result.success(sql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* 从年度范围内的人员名单加载工会下拉选项。
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("tour.participantRoster")
|
||||
public Result unionOptions(Integer startYear, Integer endYear) {
|
||||
Result yearResult = checkYearRange(startYear, endYear);
|
||||
if (yearResult != null) {
|
||||
return yearResult;
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT DISTINCT r.unionId AS id, r.unionName AS name
|
||||
FROM tour_participant_roster r
|
||||
INNER JOIN tour_setting s ON s.id = r.settingId AND s.delFlag = 0
|
||||
WHERE r.delFlag = 0
|
||||
AND IFNULL(r.unionId, '') <> ''
|
||||
AND s.`year` >= @startYear
|
||||
AND s.`year` <= @endYear
|
||||
ORDER BY r.unionName ASC
|
||||
""");
|
||||
sql.setParam("startYear", startYear);
|
||||
sql.setParam("endYear", endYear);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourParticipantRosterService.dao().execute(sql);
|
||||
return Result.success(sql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据参与人员范围和现有报名台账重新生成所选配置的人员名单。
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("tour.participantRoster")
|
||||
public Result rebuildRoster(Integer startYear, Integer endYear, @Param("settingIds") String settingIds) {
|
||||
Result yearResult = checkYearRange(startYear, endYear);
|
||||
if (yearResult != null) {
|
||||
return yearResult;
|
||||
}
|
||||
List<String> settingIdList = parseSettingIds(settingIds);
|
||||
if (settingIdList.isEmpty()) {
|
||||
return Result.error("请选择需要重新生成的疗休养配置");
|
||||
}
|
||||
Result settingResult = checkSettingsInYearRange(startYear, endYear, settingIdList);
|
||||
if (settingResult != null) {
|
||||
return settingResult;
|
||||
}
|
||||
tourParticipantRosterService.rebuildSettingRosters(settingIdList);
|
||||
return Result.success().addMsg("人员名单重新生成成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验年度范围是否完整且顺序合法。
|
||||
*/
|
||||
private Result checkYearRange(Integer startYear, Integer endYear) {
|
||||
if (startYear == null || endYear == null) {
|
||||
return Result.error("年度范围不能为空");
|
||||
}
|
||||
if (startYear > endYear) {
|
||||
return Result.error("开始年度不能大于结束年度");
|
||||
}
|
||||
int nextYear = LocalDate.now().getYear() + 1;
|
||||
if (startYear < 1900 || endYear > nextYear) {
|
||||
return Result.error("年度范围不合法");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析前端多选配置 ID,并过滤空值和重复值。
|
||||
*/
|
||||
private List<String> parseSettingIds(String settingIds) {
|
||||
if (StrUtil.isBlank(settingIds)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
List<String> rawList = Json.fromJsonAsList(String.class, settingIds);
|
||||
Set<String> idSet = new LinkedHashSet<>();
|
||||
for (String id : rawList) {
|
||||
if (StrUtil.isNotBlank(id)) {
|
||||
idSet.add(id.trim());
|
||||
}
|
||||
}
|
||||
return new ArrayList<>(idSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验所选疗休养配置是否仍属于页面提交的年度范围。
|
||||
*/
|
||||
private Result checkSettingsInYearRange(Integer startYear, Integer endYear, List<String> settingIds) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT COUNT(1)
|
||||
FROM tour_setting
|
||||
WHERE delFlag = 0
|
||||
AND id IN (@settingIds)
|
||||
AND `year` >= @startYear
|
||||
AND `year` <= @endYear
|
||||
""");
|
||||
sql.setParam("settingIds", settingIds.toArray(new String[0]));
|
||||
sql.setParam("startYear", startYear);
|
||||
sql.setParam("endYear", endYear);
|
||||
sql.setCallback(Sqls.callback.integer());
|
||||
tourParticipantRosterService.dao().execute(sql);
|
||||
if (sql.getInt() != settingIds.size()) {
|
||||
return Result.error("所选疗休养配置与年度范围不匹配,请刷新后重试");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造总数查询和列表查询共用的 SQL 条件。
|
||||
*/
|
||||
private Cnd buildQueryCnd(Integer startYear, Integer endYear, String settingId, String matterId, String keyword,
|
||||
String unitName, String unionId, Boolean joined, String lineType,
|
||||
String groupCode, String undertakeUnionId) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("r.delFlag", "=", false);
|
||||
cnd.and("s.`year`", ">=", startYear);
|
||||
cnd.and("s.`year`", "<=", endYear);
|
||||
cnd.andEX("r.settingId", "=", settingId);
|
||||
cnd.andEX("t.matterId", "=", matterId);
|
||||
cnd.andEX("r.unionId", "=", unionId);
|
||||
cnd.andEX("r.unitName", "like", StrUtil.isBlank(unitName) ? null : "%" + unitName.trim() + "%");
|
||||
cnd.andEX("t.lineType", "=", lineType);
|
||||
cnd.andEX("t.undertakeUnionId", "=", undertakeUnionId);
|
||||
appendKeywordFilter(cnd, keyword);
|
||||
return cnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加工号和姓名模糊查询条件。
|
||||
*/
|
||||
private void appendKeywordFilter(Cnd cnd, String keyword) {
|
||||
if (StrUtil.isBlank(keyword)) {
|
||||
return;
|
||||
}
|
||||
SqlExpressionGroup group = new SqlExpressionGroup();
|
||||
group.orLike("r.jobNo", keyword.trim());
|
||||
group.orLike("r.userName", keyword.trim());
|
||||
cnd.and(group);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将前端排序字段映射为安全的 SQL 排序列。
|
||||
*/
|
||||
private String getOrderColumn(String orderName) {
|
||||
if ("year".equals(orderName)) {
|
||||
return "s.`year`";
|
||||
}
|
||||
if ("jobNo".equals(orderName)) {
|
||||
return "r.jobNo";
|
||||
}
|
||||
if ("userName".equals(orderName)) {
|
||||
return "r.userName";
|
||||
}
|
||||
if ("unitName".equals(orderName)) {
|
||||
return "r.unitName";
|
||||
}
|
||||
if ("unionName".equals(orderName)) {
|
||||
return "r.unionName";
|
||||
}
|
||||
if ("joined".equals(orderName)) {
|
||||
return "r.joined";
|
||||
}
|
||||
if ("lineType".equals(orderName)) {
|
||||
return "t.lineType";
|
||||
}
|
||||
if ("lineName".equals(orderName)) {
|
||||
return "COALESCE(NULLIF(l.lineName, ''), t.lineName)";
|
||||
}
|
||||
if ("signupTime".equals(orderName)) {
|
||||
return "t.signupTime";
|
||||
}
|
||||
return "s.`year`";
|
||||
}
|
||||
}
|
||||
+8
@@ -8,6 +8,7 @@ import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourSetting;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourSettingLot;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourParticipantRosterService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourSettingService;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
@@ -32,6 +33,9 @@ public class TourSettingController {
|
||||
@Inject
|
||||
private TourSettingService tourSettingService;
|
||||
|
||||
@Inject
|
||||
private TourParticipantRosterService tourParticipantRosterService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/Tour/setting/index.html")
|
||||
@SaCheckPermission("tour.setting")
|
||||
@@ -156,6 +160,8 @@ public class TourSettingController {
|
||||
tourSettingService.updateWithNullableSignupTime(tourSetting);
|
||||
saveLots(tourSetting);
|
||||
}
|
||||
// Initialize the participant roster only once; existing roster data is preserved on later setting edits.
|
||||
tourParticipantRosterService.syncSettingRosterIfEmpty(tourSetting.getId());
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@@ -168,6 +174,8 @@ public class TourSettingController {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
tourSettingService.dao().clear(TourSettingLot.class, Cnd.where(TourSettingLot::getSettingId, "=", id));
|
||||
// Remove roster rows for the deleted setting so later statistics ignore obsolete data.
|
||||
tourParticipantRosterService.clearSettingRoster(id);
|
||||
tourSettingService.delete(id);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
+8
@@ -35,6 +35,7 @@ import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerDirectRelativeSer
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerFamilyService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourMatterService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourParticipantRosterService;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Sqls;
|
||||
@@ -79,6 +80,9 @@ public class TourSignupController {
|
||||
@Inject
|
||||
private TourLedgerDirectRelativeService tourLedgerDirectRelativeService;
|
||||
|
||||
@Inject
|
||||
private TourParticipantRosterService tourParticipantRosterService;
|
||||
|
||||
@Inject
|
||||
private SysDictService sysDictService;
|
||||
|
||||
@@ -798,6 +802,8 @@ public class TourSignupController {
|
||||
return workflowResult;
|
||||
}
|
||||
}
|
||||
// Signup and modification both mean the staff member is counted as joined for this setting.
|
||||
tourParticipantRosterService.markJoinedByLedger(ledger);
|
||||
return Result.success().addMsg(approvalRequired ? (update ? "修改已提交,等待审核" : "申请已提交,等待审核") : (update ? "修改成功" : "报名成功"));
|
||||
}
|
||||
|
||||
@@ -828,6 +834,8 @@ public class TourSignupController {
|
||||
if (signupTimeResult != null) {
|
||||
return signupTimeResult;
|
||||
}
|
||||
// Reset the roster before deleting the ledger record, because the ledger still carries setting linkage here.
|
||||
tourParticipantRosterService.markNotJoinedByLedger(ledger);
|
||||
tourLedgerFamilyService.clear(Cnd.where(TourLedgerFamily::getLedgerId, "=", ledger.getId()));
|
||||
tourLedgerDirectRelativeService.clear(Cnd.where(TourLedgerDirectRelative::getLedgerId, "=", ledger.getId()));
|
||||
tourLedgerService.clear(Cnd.where(TourLedger::getId, "=", ledger.getId()));
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.models;
|
||||
|
||||
import com.budwk.app.base.model.BaseModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.nutz.dao.entity.annotation.ColDefine;
|
||||
import org.nutz.dao.entity.annotation.ColType;
|
||||
import org.nutz.dao.entity.annotation.Column;
|
||||
import org.nutz.dao.entity.annotation.Comment;
|
||||
import org.nutz.dao.entity.annotation.Default;
|
||||
import org.nutz.dao.entity.annotation.Name;
|
||||
import org.nutz.dao.entity.annotation.Table;
|
||||
import org.nutz.dao.entity.annotation.TableMeta;
|
||||
import org.nutz.dao.interceptor.annotation.PrevInsert;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Tour participant roster stores every eligible staff member for a tour setting.
|
||||
* It is used for joined/not-joined statistics and links to tour_ledger only when the user has a signup record.
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Table("tour_participant_roster")
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("疗休养人员名单")
|
||||
public class TourParticipantRoster extends BaseModel implements Serializable {
|
||||
|
||||
@Column
|
||||
@Name
|
||||
@Comment("ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@PrevInsert(uu32 = true)
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("疗休养配置ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String settingId;
|
||||
|
||||
@Column
|
||||
@Comment("工号")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String jobNo;
|
||||
|
||||
@Column
|
||||
@Comment("姓名")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String userName;
|
||||
|
||||
@Column
|
||||
@Comment("所在单位ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String unitId;
|
||||
|
||||
@Column
|
||||
@Comment("所在单位")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String unitName;
|
||||
|
||||
@Column
|
||||
@Comment("所在工会ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String unionId;
|
||||
|
||||
@Column
|
||||
@Comment("所在工会")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String unionName;
|
||||
|
||||
@Column
|
||||
@Comment("是否参加")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Default("0")
|
||||
private Boolean joined;
|
||||
|
||||
@Column
|
||||
@Comment("疗休养台账ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String ledgerId;
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedger;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourParticipantRoster;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Service for maintaining the tour participant roster used by yearly joined/not-joined statistics.
|
||||
*/
|
||||
public interface TourParticipantRosterService extends BaseService<TourParticipantRoster> {
|
||||
|
||||
/**
|
||||
* Synchronizes eligible staff of one tour setting into the roster table.
|
||||
*
|
||||
* @param settingId tour setting id whose activity group defines the eligible staff scope.
|
||||
*/
|
||||
void syncSettingRoster(String settingId);
|
||||
|
||||
/**
|
||||
* Synchronizes the setting roster only when no roster rows exist for that setting.
|
||||
*
|
||||
* @param settingId tour setting id whose roster should be lazily initialized.
|
||||
*/
|
||||
void syncSettingRosterIfEmpty(String settingId);
|
||||
|
||||
/**
|
||||
* Rebuilds selected setting rosters from eligible staff scopes and existing tour ledgers.
|
||||
*
|
||||
* @param settingIds selected tour setting ids.
|
||||
*/
|
||||
void rebuildSettingRosters(List<String> settingIds);
|
||||
|
||||
/**
|
||||
* Clears roster rows when a tour setting is deleted.
|
||||
*
|
||||
* @param settingId deleted tour setting id.
|
||||
*/
|
||||
void clearSettingRoster(String settingId);
|
||||
|
||||
/**
|
||||
* Marks the roster row as joined and links it with the newest tour ledger.
|
||||
*
|
||||
* @param ledger signup ledger created or modified successfully.
|
||||
*/
|
||||
void markJoinedByLedger(TourLedger ledger);
|
||||
|
||||
/**
|
||||
* Marks the roster row as not joined and clears the linked ledger id.
|
||||
*
|
||||
* @param ledger signup ledger that is being cancelled or deleted.
|
||||
*/
|
||||
void markNotJoinedByLedger(TourLedger ledger);
|
||||
}
|
||||
+288
@@ -0,0 +1,288 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.sys.views.View_user;
|
||||
import com.budwk.app.zhgh.activity.basic.service.ActivityBasicScopeService;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedger;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourMatter;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourParticipantRoster;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourSetting;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.service.TourParticipantRosterService;
|
||||
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.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Default implementation that keeps tour participant roster data in sync with settings and signup ledgers.
|
||||
*/
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class TourParticipantRosterServiceImpl extends BaseServiceImpl<TourParticipantRoster> implements TourParticipantRosterService {
|
||||
|
||||
private static final int USER_QUERY_BATCH_SIZE = 500;
|
||||
|
||||
@Inject
|
||||
private ActivityBasicScopeService activityBasicScopeService;
|
||||
|
||||
public TourParticipantRosterServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads eligible users from the setting activity group and upserts roster rows without resetting joined status.
|
||||
*/
|
||||
@Override
|
||||
public void syncSettingRoster(String settingId) {
|
||||
if (StrUtil.isBlank(settingId)) {
|
||||
return;
|
||||
}
|
||||
TourSetting setting = dao().fetch(TourSetting.class, settingId);
|
||||
if (setting == null || StrUtil.isBlank(setting.getActivityGroupId())) {
|
||||
return;
|
||||
}
|
||||
Integer groupId = parseGroupId(setting.getActivityGroupId());
|
||||
if (groupId == null) {
|
||||
return;
|
||||
}
|
||||
List<String> userIds = activityBasicScopeService.listGroupUserIds(groupId);
|
||||
if (CollUtil.isEmpty(userIds)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (View_user user : queryUsers(userIds)) {
|
||||
if (user == null || StrUtil.isBlank(user.getLoginname())) {
|
||||
continue;
|
||||
}
|
||||
upsertRosterUser(settingId, user);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Keeps normal setting save lightweight: once a setting has roster rows, editing the setting will not reload users.
|
||||
*/
|
||||
@Override
|
||||
public void syncSettingRosterIfEmpty(String settingId) {
|
||||
if (StrUtil.isBlank(settingId)) {
|
||||
return;
|
||||
}
|
||||
int rosterCount = count(Cnd.where("settingId", "=", settingId));
|
||||
if (rosterCount > 0) {
|
||||
return;
|
||||
}
|
||||
syncSettingRoster(settingId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuilds rosters in one transaction: clear old rows, reload eligible staff, then mark users with active ledgers as joined.
|
||||
*/
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void rebuildSettingRosters(List<String> settingIds) {
|
||||
if (CollUtil.isEmpty(settingIds)) {
|
||||
return;
|
||||
}
|
||||
for (String settingId : settingIds) {
|
||||
if (StrUtil.isBlank(settingId)) {
|
||||
continue;
|
||||
}
|
||||
clear(Cnd.where("settingId", "=", settingId));
|
||||
syncSettingRoster(settingId);
|
||||
replayLedgerJoinedState(settingId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes roster rows that belong to a deleted setting so statistics do not keep obsolete setting data.
|
||||
*/
|
||||
@Override
|
||||
public void clearSettingRoster(String settingId) {
|
||||
if (StrUtil.isBlank(settingId)) {
|
||||
return;
|
||||
}
|
||||
clear(Cnd.where("settingId", "=", settingId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Signup success and signup modification both keep the roster row joined and point it at the effective ledger.
|
||||
*/
|
||||
@Override
|
||||
public void markJoinedByLedger(TourLedger ledger) {
|
||||
String settingId = resolveSettingId(ledger);
|
||||
if (StrUtil.isBlank(settingId) || ledger == null || StrUtil.isBlank(ledger.getJobNo())) {
|
||||
return;
|
||||
}
|
||||
TourParticipantRoster roster = fetchRoster(settingId, ledger.getJobNo());
|
||||
if (roster == null) {
|
||||
roster = new TourParticipantRoster();
|
||||
roster.setSettingId(settingId);
|
||||
roster.setJobNo(ledger.getJobNo());
|
||||
roster.setJoined(true);
|
||||
fillRosterFromLedger(roster, ledger);
|
||||
insert(roster);
|
||||
return;
|
||||
}
|
||||
Chain chain = Chain.make("joined", true)
|
||||
.add("ledgerId", StrUtil.blankToDefault(ledger.getId(), ""))
|
||||
.add("userName", StrUtil.blankToDefault(ledger.getUserName(), roster.getUserName()))
|
||||
.add("unitId", StrUtil.blankToDefault(ledger.getUnitId(), roster.getUnitId()))
|
||||
.add("unitName", StrUtil.blankToDefault(ledger.getUnitName(), roster.getUnitName()))
|
||||
.add("unionId", StrUtil.blankToDefault(ledger.getUnionId(), roster.getUnionId()))
|
||||
.add("unionName", StrUtil.blankToDefault(ledger.getUnionName(), roster.getUnionName()));
|
||||
dao().update(TourParticipantRoster.class, chain, Cnd.where("id", "=", roster.getId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancellation only resets the current user's roster row; historical ledger data remains in tour_ledger deletion history.
|
||||
*/
|
||||
@Override
|
||||
public void markNotJoinedByLedger(TourLedger ledger) {
|
||||
String settingId = resolveSettingId(ledger);
|
||||
if (StrUtil.isBlank(settingId) || ledger == null || StrUtil.isBlank(ledger.getJobNo())) {
|
||||
return;
|
||||
}
|
||||
TourParticipantRoster roster = fetchRoster(settingId, ledger.getJobNo());
|
||||
if (roster == null) {
|
||||
roster = new TourParticipantRoster();
|
||||
roster.setSettingId(settingId);
|
||||
roster.setJobNo(ledger.getJobNo());
|
||||
roster.setJoined(false);
|
||||
fillRosterFromLedger(roster, ledger);
|
||||
roster.setLedgerId("");
|
||||
insert(roster);
|
||||
return;
|
||||
}
|
||||
dao().update(TourParticipantRoster.class,
|
||||
Chain.make("joined", false).add("ledgerId", ""),
|
||||
Cnd.where("id", "=", roster.getId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the setting activity group id stored as text into an integer accepted by the activity scope service.
|
||||
*/
|
||||
private Integer parseGroupId(String activityGroupId) {
|
||||
try {
|
||||
return Integer.parseInt(activityGroupId);
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries the user view in batches so large participant scopes do not generate an oversized SQL IN clause.
|
||||
*/
|
||||
private List<View_user> queryUsers(List<String> userIds) {
|
||||
List<View_user> users = new ArrayList<>();
|
||||
for (int i = 0; i < userIds.size(); i += USER_QUERY_BATCH_SIZE) {
|
||||
int end = Math.min(i + USER_QUERY_BATCH_SIZE, userIds.size());
|
||||
List<String> batch = userIds.subList(i, end);
|
||||
users.addAll(dao().query(View_user.class, Cnd.where("id", "in", batch)));
|
||||
}
|
||||
return users;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts new eligible users and refreshes basic organization data for existing rows.
|
||||
*/
|
||||
private void upsertRosterUser(String settingId, View_user user) {
|
||||
TourParticipantRoster roster = fetchRoster(settingId, user.getLoginname());
|
||||
if (roster == null) {
|
||||
roster = new TourParticipantRoster();
|
||||
roster.setSettingId(settingId);
|
||||
roster.setJobNo(user.getLoginname());
|
||||
roster.setJoined(false);
|
||||
fillRosterFromUser(roster, user);
|
||||
insert(roster);
|
||||
return;
|
||||
}
|
||||
dao().update(TourParticipantRoster.class,
|
||||
Chain.make("userName", StrUtil.blankToDefault(user.getUsername(), ""))
|
||||
.add("unitId", StrUtil.blankToDefault(user.getUnitId(), ""))
|
||||
.add("unitName", StrUtil.blankToDefault(user.getUnitName(), ""))
|
||||
.add("unionId", StrUtil.blankToDefault(user.getUnionId(), ""))
|
||||
.add("unionName", StrUtil.blankToDefault(user.getUnionName(), "")),
|
||||
Cnd.where("id", "=", roster.getId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Replays active tour ledgers under one setting so rebuilt rosters keep the current signup state.
|
||||
*/
|
||||
private void replayLedgerJoinedState(String settingId) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT t.*
|
||||
FROM tour_ledger t
|
||||
INNER JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
WHERE t.delFlag = 0
|
||||
AND m.settingId = @settingId
|
||||
AND IFNULL(t.jobNo, '') <> ''
|
||||
ORDER BY t.signupTime DESC, t.createdAt DESC
|
||||
""");
|
||||
sql.setParam("settingId", settingId);
|
||||
sql.setEntity(dao().getEntity(TourLedger.class));
|
||||
sql.setCallback(Sqls.callback.entities());
|
||||
dao().execute(sql);
|
||||
|
||||
Set<String> handledJobNos = new HashSet<>();
|
||||
for (TourLedger ledger : sql.getList(TourLedger.class)) {
|
||||
if (ledger == null || StrUtil.isBlank(ledger.getJobNo()) || handledJobNos.contains(ledger.getJobNo())) {
|
||||
continue;
|
||||
}
|
||||
handledJobNos.add(ledger.getJobNo());
|
||||
markJoinedByLedger(ledger);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an active roster row by setting and job number, which is the logical unique key.
|
||||
*/
|
||||
private TourParticipantRoster fetchRoster(String settingId, String jobNo) {
|
||||
return fetch(Cnd.where("settingId", "=", settingId)
|
||||
.and("jobNo", "=", jobNo)
|
||||
.and("delFlag", "=", false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves setting id through the ledger matter because tour_ledger intentionally does not store settingId.
|
||||
*/
|
||||
private String resolveSettingId(TourLedger ledger) {
|
||||
if (ledger == null || StrUtil.isBlank(ledger.getMatterId())) {
|
||||
return "";
|
||||
}
|
||||
TourMatter matter = dao().fetch(TourMatter.class, ledger.getMatterId());
|
||||
return matter == null ? "" : matter.getSettingId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies staff base data from the user view into the roster row.
|
||||
*/
|
||||
private void fillRosterFromUser(TourParticipantRoster roster, View_user user) {
|
||||
roster.setUserName(StrUtil.blankToDefault(user.getUsername(), ""));
|
||||
roster.setUnitId(StrUtil.blankToDefault(user.getUnitId(), ""));
|
||||
roster.setUnitName(StrUtil.blankToDefault(user.getUnitName(), ""));
|
||||
roster.setUnionId(StrUtil.blankToDefault(user.getUnionId(), ""));
|
||||
roster.setUnionName(StrUtil.blankToDefault(user.getUnionName(), ""));
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies staff and organization data from the ledger when roster sync has not created the row yet.
|
||||
*/
|
||||
private void fillRosterFromLedger(TourParticipantRoster roster, TourLedger ledger) {
|
||||
roster.setUserName(StrUtil.blankToDefault(ledger.getUserName(), ""));
|
||||
roster.setUnitId(StrUtil.blankToDefault(ledger.getUnitId(), ""));
|
||||
roster.setUnitName(StrUtil.blankToDefault(ledger.getUnitName(), ""));
|
||||
roster.setUnionId(StrUtil.blankToDefault(ledger.getUnionId(), ""));
|
||||
roster.setUnionName(StrUtil.blankToDefault(ledger.getUnionName(), ""));
|
||||
roster.setLedgerId(StrUtil.blankToDefault(ledger.getId(), ""));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
CREATE TABLE IF NOT EXISTS `tour_participant_roster`
|
||||
(
|
||||
`id` varchar(32) NOT NULL COMMENT 'ID',
|
||||
`settingId` varchar(32) NOT NULL COMMENT '疗休养配置ID',
|
||||
`jobNo` varchar(50) NOT NULL COMMENT '工号',
|
||||
`userName` varchar(100) DEFAULT NULL COMMENT '姓名',
|
||||
`unitId` varchar(32) DEFAULT NULL COMMENT '所在单位ID',
|
||||
`unitName` varchar(100) DEFAULT NULL COMMENT '所在单位',
|
||||
`unionId` varchar(32) DEFAULT NULL COMMENT '所在工会ID',
|
||||
`unionName` varchar(100) DEFAULT NULL COMMENT '所在工会',
|
||||
`joined` tinyint(1) DEFAULT 0 COMMENT '是否参加:0否,1是',
|
||||
`ledgerId` varchar(32) DEFAULT NULL COMMENT '疗休养台账ID',
|
||||
`createdBy` varchar(32) DEFAULT NULL COMMENT '创建人',
|
||||
`createdAt` bigint DEFAULT NULL COMMENT '创建时间',
|
||||
`updatedBy` varchar(32) DEFAULT NULL COMMENT '修改人',
|
||||
`updatedAt` bigint DEFAULT NULL COMMENT '修改时间',
|
||||
`delFlag` tinyint(1) DEFAULT 0 COMMENT '删除标记',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_tour_participant_roster_setting_job` (`settingId`, `jobNo`),
|
||||
KEY `idx_tour_participant_roster_setting` (`settingId`),
|
||||
KEY `idx_tour_participant_roster_job` (`jobNo`),
|
||||
KEY `idx_tour_participant_roster_joined` (`joined`),
|
||||
KEY `idx_tour_participant_roster_ledger` (`ledgerId`),
|
||||
KEY `idx_tour_participant_roster_union` (`unionId`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT ='疗休养人员名单';
|
||||
@@ -0,0 +1,15 @@
|
||||
-- 疗休养人员名单查询菜单。
|
||||
INSERT INTO sys_menu (id, parentId, path, name, aliasName, type, href, target, icon, showit, disabled, permission, note, location, hasChildren, createdBy, createdAt, updatedBy, updatedAt, delFlag, platform, moduleId, picIcon, initialPinyinName, isRecommendApp, isRecommendService)
|
||||
SELECT 'b7c63f0c73a44a9a8c4f3d3bb1a10014', p.id, CONCAT(p.path, '0013'), '疗休养人员名单', 'Tour Participant Roster', 'menu', '/platform/tour/participantRoster', 'data-pjax', '', 1, 0, 'tour.participantRoster', NULL, 13, 0, '', UNIX_TIMESTAMP(NOW()) * 1000, '', UNIX_TIMESTAMP(NOW()) * 1000, 0, 'PC', NULL, NULL, 'l', 0, 0
|
||||
FROM sys_menu p
|
||||
WHERE p.permission = 'tour'
|
||||
AND NOT EXISTS (SELECT 1 FROM (SELECT id FROM sys_menu WHERE permission = 'tour.participantRoster') t);
|
||||
|
||||
-- 默认给系统管理员授权,其它角色可以在角色管理中按需分配。
|
||||
INSERT INTO sys_role_menu (roleId, menuId)
|
||||
SELECT r.id, m.id
|
||||
FROM sys_role r
|
||||
JOIN sys_menu m ON m.permission = 'tour.participantRoster'
|
||||
LEFT JOIN sys_role_menu rm ON rm.roleId = r.id AND rm.menuId = m.id
|
||||
WHERE r.code = 'SYSADMIN'
|
||||
AND rm.roleId IS NULL;
|
||||
@@ -0,0 +1,67 @@
|
||||
const tourTableHeightMixins = {
|
||||
data() {
|
||||
return {
|
||||
tourTableHeight: Math.max(120, window.innerHeight - 378),
|
||||
tourTableResizeTimer: null,
|
||||
tourTableHeightReady: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateTourTableHeight() {
|
||||
this.$nextTick(() => {
|
||||
const table = this.$refs.tourMainTable || this.$refs.tableRef || this.$refs.table
|
||||
const tableEl = table && table.$el ? table.$el : null
|
||||
if (!tableEl) {
|
||||
return
|
||||
}
|
||||
|
||||
// 根据当前屏幕、表格位置、分页区域动态计算主列表高度,避免整页被数据行撑出滚动条。
|
||||
const mainContent = document.querySelector(".sub-app-container-main-content")
|
||||
const viewportBottom = mainContent ? mainContent.getBoundingClientRect().bottom : window.innerHeight
|
||||
const tableTop = tableEl.getBoundingClientRect().top
|
||||
const pagination = this.$el.querySelector(".el-pagination-container")
|
||||
const paginationHeight = pagination ? pagination.getBoundingClientRect().height : 46
|
||||
const reserveHeight = Number(this.tourTableReserveHeight || 42)
|
||||
const minHeight = Number(this.tourTableMinHeight || 120)
|
||||
const height = Math.floor(viewportBottom - tableTop - paginationHeight - reserveHeight)
|
||||
this.tourTableHeight = height > minHeight ? height : minHeight
|
||||
this.tourTableHeightReady = true
|
||||
|
||||
// Element 表格高度变化后需要重新布局,否则固定列和表头可能错位。
|
||||
this.$nextTick(() => {
|
||||
if (table && table.doLayout) {
|
||||
table.doLayout()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
handleTourTableResize() {
|
||||
if (this.tourTableResizeTimer) {
|
||||
clearTimeout(this.tourTableResizeTimer)
|
||||
}
|
||||
this.tourTableResizeTimer = setTimeout(() => {
|
||||
this.updateTourTableHeight()
|
||||
this.tourTableResizeTimer = null
|
||||
}, 120)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.updateTourTableHeight()
|
||||
window.addEventListener("resize", this.handleTourTableResize)
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.tourTableResizeTimer) {
|
||||
clearTimeout(this.tourTableResizeTimer)
|
||||
this.tourTableResizeTimer = null
|
||||
}
|
||||
window.removeEventListener("resize", this.handleTourTableResize)
|
||||
},
|
||||
watch: {
|
||||
tableData() {
|
||||
this.updateTourTableHeight()
|
||||
},
|
||||
"pageForm.pageSize"() {
|
||||
this.updateTourTableHeight()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,6 +87,7 @@
|
||||
<script src="${base!}/assets/platform/js/util/coordinateUtil.js"></script>
|
||||
<script src="${base!}/assets/platform/js/main.js"></script>
|
||||
<script src="${base!}/assets/platform/js/mixin/initTableMixins.js"></script>
|
||||
<script src="${base!}/assets/platform/js/mixin/tourTableHeightMixins.js?v=2026072103"></script>
|
||||
<script src="${base!}/assets/platform/js/mixin/styleMixin.js"></script>
|
||||
<script src="${base!}/assets/platform/js/mixin/flowMixins.js"></script>
|
||||
<script src="${base!}/assets/platform/js/tool/businessTool.js"></script>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!--#
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
@@ -51,7 +51,9 @@ layout("/layouts/platform.html"){
|
||||
border
|
||||
:default-sort="{prop: 'lineName', order: 'ascending'}"
|
||||
:row-class-name="tableRowClassName"
|
||||
@sort-change="pageOrder">
|
||||
@sort-change="pageOrder"
|
||||
ref="tourMainTable"
|
||||
:height="tourTableHeight">
|
||||
<el-table-column label="序号" type="index" :index="indexMethod" width="80" align="center" header-align="center"></el-table-column>
|
||||
<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>
|
||||
@@ -194,7 +196,7 @@ layout("/layouts/platform.html"){
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
mixins: [initTableMixins, tourTableHeightMixins],
|
||||
data() {
|
||||
const currentYear = moment().format("YYYY")
|
||||
return {
|
||||
|
||||
@@ -99,7 +99,8 @@ layout("/layouts/platform.html"){
|
||||
row-key="id"
|
||||
:row-class-name="tableRowClassName"
|
||||
@selection-change="handleSelectionChange"
|
||||
@sort-change="pageOrder">
|
||||
@sort-change="pageOrder"
|
||||
:height="tourTableHeight">
|
||||
<el-table-column type="selection" width="55" align="center" header-align="center"></el-table-column>
|
||||
<el-table-column label="序号" type="index" :index="indexMethod" 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>
|
||||
@@ -348,7 +349,7 @@ layout("/layouts/platform.html"){
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
mixins: [initTableMixins, tourTableHeightMixins],
|
||||
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
|
||||
data() {
|
||||
const currentYear = moment().format("YYYY")
|
||||
|
||||
@@ -84,7 +84,9 @@ layout("/layouts/platform.html"){
|
||||
border
|
||||
:default-sort="{prop: 'lineCode', order: 'ascending'}"
|
||||
:row-class-name="tableRowClassName"
|
||||
@sort-change="pageOrder">
|
||||
@sort-change="pageOrder"
|
||||
ref="tourMainTable"
|
||||
:height="tourTableHeight">
|
||||
<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>
|
||||
@@ -279,7 +281,7 @@ layout("/layouts/platform.html"){
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
mixins: [initTableMixins],
|
||||
mixins: [initTableMixins, tourTableHeightMixins],
|
||||
data() {
|
||||
const currentYear = moment().format("YYYY")
|
||||
const validateUnion = (rule, value, callback) => {
|
||||
|
||||
@@ -43,7 +43,9 @@ layout("/layouts/platform.html"){
|
||||
:data="tableData"
|
||||
:size="tableSize"
|
||||
border
|
||||
@sort-change="pageOrder">
|
||||
@sort-change="pageOrder"
|
||||
ref="tourMainTable"
|
||||
:height="tourTableHeight">
|
||||
<el-table-column label="序号" type="index" :index="indexMethod" 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>
|
||||
@@ -730,7 +732,7 @@ layout("/layouts/platform.html"){
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
mixins: [initTableMixins, tourTableHeightMixins],
|
||||
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
|
||||
data() {
|
||||
return {
|
||||
|
||||
+488
@@ -0,0 +1,488 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<guava ref="guava">
|
||||
<el-card shadow="never">
|
||||
<search :is-search-button="false">
|
||||
<search-item label="年度">
|
||||
<div class="tour-year-range">
|
||||
<el-date-picker
|
||||
v-model="pageForm.startYear"
|
||||
type="year"
|
||||
value-format="yyyy"
|
||||
placeholder="开始年度"
|
||||
class="tour-year-picker">
|
||||
</el-date-picker>
|
||||
<span class="tour-year-separator">-</span>
|
||||
<el-date-picker
|
||||
v-model="pageForm.endYear"
|
||||
type="year"
|
||||
value-format="yyyy"
|
||||
placeholder="结束年度"
|
||||
class="tour-year-picker">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</search-item>
|
||||
<search-item label="疗休养配置">
|
||||
<el-select
|
||||
v-model="pageForm.settingId"
|
||||
clearable
|
||||
filterable
|
||||
placeholder="请选择疗休养配置"
|
||||
style="width: 100%"
|
||||
@change="settingChange">
|
||||
<el-option
|
||||
v-for="item in settingOptions"
|
||||
:key="item.id"
|
||||
:label="settingOptionLabel(item)"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="线路">
|
||||
<el-select
|
||||
v-model="pageForm.matterId"
|
||||
clearable
|
||||
filterable
|
||||
placeholder="请选择线路"
|
||||
style="width: 100%"
|
||||
@visible-change="lineVisibleChange">
|
||||
<el-option
|
||||
v-for="item in lineOptions"
|
||||
:key="item.matterId"
|
||||
:label="item.label"
|
||||
:value="item.matterId">
|
||||
<span>{{ item.label }}</span>
|
||||
<span class="tour-line-option">{{ item.lineName }}</span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="姓名/工号">
|
||||
<el-input
|
||||
v-model="pageForm.keyword"
|
||||
clearable
|
||||
placeholder="请输入姓名或工号"
|
||||
style="width: 100%"
|
||||
@keyup.enter.native="doSearch">
|
||||
</el-input>
|
||||
</search-item>
|
||||
<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>
|
||||
<search-item label="线路类型">
|
||||
<dict-select
|
||||
v-model="pageForm.lineType"
|
||||
code="lineType"
|
||||
option_value="name"
|
||||
placeholder="请选择线路类型">
|
||||
</dict-select>
|
||||
</search-item>
|
||||
<search-item label="领办工会">
|
||||
<el-select v-model="pageForm.undertakeUnionId" 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>
|
||||
<div class="search-query">
|
||||
<el-button size="medium" type="primary" icon="el-icon-search" @click="doSearch">搜索</el-button>
|
||||
<el-button size="medium" @click="resetSearch">重置</el-button>
|
||||
</div>
|
||||
</search>
|
||||
</el-card>
|
||||
|
||||
<el-card class="mt10" shadow="never">
|
||||
<div class="tour-roster-toolbar">
|
||||
<table-tool :app="this" label="疗休养人员名单"></table-tool>
|
||||
<el-button size="medium" type="primary" icon="el-icon-refresh" @click="openRebuildDialog">重新生成名单</el-button>
|
||||
</div>
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
v-loading="tableLoading"
|
||||
:data="tableData"
|
||||
:size="tableSize"
|
||||
border
|
||||
row-key="id"
|
||||
@sort-change="pageOrder"
|
||||
:height="tourTableHeight">
|
||||
<el-table-column label="序号" type="index" :index="indexMethod" 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="unitName" min-width="180" 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 label="是否参加" prop="joined" width="110" sortable="custom" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
<el-tag size="mini" :type="toBoolean(row.joined) ? 'success' : 'info'">{{ toBoolean(row.joined) ? '已参加' : '未参加' }}</el-tag>
|
||||
</template>
|
||||
</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="lineName" min-width="220" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="疗休养事项" prop="matterName" min-width="180" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="出行时段" prop="travelPeriod" min-width="220" 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>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
</el-card>
|
||||
</guava>
|
||||
|
||||
<el-dialog
|
||||
title="重新生成名单"
|
||||
:visible.sync="rebuildDialogVisible"
|
||||
:close-on-click-modal="false"
|
||||
width="620px">
|
||||
<el-form :model="rebuildForm" label-width="110px" size="medium">
|
||||
<el-form-item label="开始年度" required>
|
||||
<el-date-picker
|
||||
v-model="rebuildForm.startYear"
|
||||
type="year"
|
||||
value-format="yyyy"
|
||||
placeholder="请选择开始年度"
|
||||
style="width: 100%"
|
||||
@change="rebuildYearChange">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="结束年度" required>
|
||||
<el-date-picker
|
||||
v-model="rebuildForm.endYear"
|
||||
type="year"
|
||||
value-format="yyyy"
|
||||
placeholder="请选择结束年度"
|
||||
style="width: 100%"
|
||||
@change="rebuildYearChange">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="疗休养配置" required>
|
||||
<el-select
|
||||
v-model="rebuildForm.settingIds"
|
||||
multiple
|
||||
clearable
|
||||
filterable
|
||||
placeholder="请选择疗休养配置"
|
||||
style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in rebuildSettingOptions"
|
||||
:key="item.id"
|
||||
:label="settingOptionLabel(item)"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="rebuildDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submitRebuildRoster">确认</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.tour-roster-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.tour-year-range {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tour-year-picker {
|
||||
width: 112px;
|
||||
}
|
||||
|
||||
.tour-year-separator {
|
||||
padding: 0 8px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.tour-line-option {
|
||||
float: right;
|
||||
color: #8492a6;
|
||||
font-size: 12px;
|
||||
max-width: 45%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins, tourTableHeightMixins],
|
||||
data() {
|
||||
const currentYear = moment().format("YYYY")
|
||||
return {
|
||||
settingOptions: [],
|
||||
rebuildSettingOptions: [],
|
||||
lineOptions: [],
|
||||
unionOptions: [],
|
||||
optionTimer: null,
|
||||
rebuildDialogVisible: false,
|
||||
rebuildForm: {
|
||||
startYear: currentYear,
|
||||
endYear: currentYear,
|
||||
settingIds: []
|
||||
},
|
||||
pageForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
pageOrderName: "year",
|
||||
pageOrderBy: "descending",
|
||||
startYear: currentYear,
|
||||
endYear: currentYear,
|
||||
settingId: "",
|
||||
matterId: "",
|
||||
keyword: "",
|
||||
unitName: "",
|
||||
unionId: "",
|
||||
joined: "",
|
||||
lineType: "",
|
||||
groupCode: "",
|
||||
undertakeUnionId: ""
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toBoolean(value) {
|
||||
return value === true || value === 1 || value === "1" || value === "true" || value === "TRUE"
|
||||
},
|
||||
settingOptionLabel(item) {
|
||||
if (!item) {
|
||||
return ""
|
||||
}
|
||||
return (item.configName || "") + "【" + (item.year || "") + "】"
|
||||
},
|
||||
formatGroupInfo(row) {
|
||||
if (!row || !row.groupCode) {
|
||||
return ""
|
||||
}
|
||||
return row.groupName ? row.groupCode + " " + row.groupName : row.groupCode
|
||||
},
|
||||
checkYearRange() {
|
||||
if (!this.pageForm.startYear || !this.pageForm.endYear) {
|
||||
this.$message.warning("年度范围不能为空")
|
||||
return false
|
||||
}
|
||||
if (Number(this.pageForm.startYear) > Number(this.pageForm.endYear)) {
|
||||
this.$message.warning("开始年度不能大于结束年度")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
optionParams() {
|
||||
return {
|
||||
startYear: this.pageForm.startYear,
|
||||
endYear: this.pageForm.endYear,
|
||||
settingId: this.pageForm.settingId
|
||||
}
|
||||
},
|
||||
loadSettingOptions() {
|
||||
if (!this.checkYearRange()) {
|
||||
return
|
||||
}
|
||||
this.$axios.post(loc() + "/settingOptions", {
|
||||
startYear: this.pageForm.startYear,
|
||||
endYear: this.pageForm.endYear
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.settingOptions = res.data || []
|
||||
if (this.pageForm.settingId && !this.settingOptions.some(item => item.id === this.pageForm.settingId)) {
|
||||
this.pageForm.settingId = ""
|
||||
}
|
||||
} else {
|
||||
this.$message.warning(res.msg || "疗休养配置加载失败")
|
||||
}
|
||||
})
|
||||
},
|
||||
loadLineOptions() {
|
||||
if (!this.checkYearRange()) {
|
||||
return
|
||||
}
|
||||
this.$axios.post(loc() + "/lineOptions", this.optionParams()).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.lineOptions = res.data || []
|
||||
if (this.pageForm.matterId && !this.lineOptions.some(item => item.matterId === this.pageForm.matterId)) {
|
||||
this.pageForm.matterId = ""
|
||||
}
|
||||
} else {
|
||||
this.$message.warning(res.msg || "线路加载失败")
|
||||
}
|
||||
})
|
||||
},
|
||||
loadUnionOptions() {
|
||||
if (!this.checkYearRange()) {
|
||||
return
|
||||
}
|
||||
this.$axios.post(loc() + "/unionOptions", {
|
||||
startYear: this.pageForm.startYear,
|
||||
endYear: this.pageForm.endYear
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.unionOptions = res.data || []
|
||||
if (this.pageForm.unionId && !this.unionOptions.some(item => item.id === this.pageForm.unionId)) {
|
||||
this.pageForm.unionId = ""
|
||||
}
|
||||
if (this.pageForm.undertakeUnionId && !this.unionOptions.some(item => item.id === this.pageForm.undertakeUnionId)) {
|
||||
this.pageForm.undertakeUnionId = ""
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
loadOptions() {
|
||||
this.loadSettingOptions()
|
||||
this.loadLineOptions()
|
||||
this.loadUnionOptions()
|
||||
},
|
||||
loadRebuildSettingOptions() {
|
||||
if (!this.checkRebuildYearRange()) {
|
||||
this.rebuildSettingOptions = []
|
||||
return
|
||||
}
|
||||
this.$axios.post(loc() + "/settingOptions", {
|
||||
startYear: this.rebuildForm.startYear,
|
||||
endYear: this.rebuildForm.endYear
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.rebuildSettingOptions = res.data || []
|
||||
} else {
|
||||
this.rebuildSettingOptions = []
|
||||
this.$message.warning(res.msg || "疗休养配置加载失败")
|
||||
}
|
||||
})
|
||||
},
|
||||
checkRebuildYearRange() {
|
||||
if (!this.rebuildForm.startYear || !this.rebuildForm.endYear) {
|
||||
this.$message.warning("年度范围不能为空")
|
||||
return false
|
||||
}
|
||||
if (Number(this.rebuildForm.startYear) > Number(this.rebuildForm.endYear)) {
|
||||
this.$message.warning("开始年度不能大于结束年度")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
openRebuildDialog() {
|
||||
const currentYear = moment().format("YYYY")
|
||||
this.rebuildForm.startYear = currentYear
|
||||
this.rebuildForm.endYear = currentYear
|
||||
this.rebuildForm.settingIds = []
|
||||
this.rebuildDialogVisible = true
|
||||
this.loadRebuildSettingOptions()
|
||||
},
|
||||
rebuildYearChange() {
|
||||
this.rebuildForm.settingIds = []
|
||||
this.loadRebuildSettingOptions()
|
||||
},
|
||||
submitRebuildRoster() {
|
||||
if (!this.checkRebuildYearRange()) {
|
||||
return
|
||||
}
|
||||
if (!this.rebuildForm.settingIds.length) {
|
||||
this.$message.warning("请选择需要重新生成的疗休养配置")
|
||||
return
|
||||
}
|
||||
this.$confirm("重新生成后将删除所选配置下已有人员名单,并根据可参与人员范围和现有疗休养台账重新生成,是否继续?", "提示", {
|
||||
confirmButtonText: "确认生成",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.$axios.post(loc() + "/rebuildRoster", {
|
||||
startYear: this.rebuildForm.startYear,
|
||||
endYear: this.rebuildForm.endYear,
|
||||
settingIds: JSON.stringify(this.rebuildForm.settingIds)
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success(res.msg || "人员名单重新生成成功")
|
||||
this.rebuildDialogVisible = false
|
||||
this.pageData()
|
||||
this.loadOptions()
|
||||
} else {
|
||||
this.$message.warning(res.msg || "人员名单重新生成失败")
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
scheduleLoadOptions() {
|
||||
if (this.optionTimer) {
|
||||
clearTimeout(this.optionTimer)
|
||||
}
|
||||
this.optionTimer = setTimeout(() => {
|
||||
this.loadOptions()
|
||||
this.optionTimer = null
|
||||
}, 80)
|
||||
},
|
||||
lineVisibleChange(visible) {
|
||||
if (!visible) {
|
||||
return
|
||||
}
|
||||
if (!this.checkYearRange()) {
|
||||
return
|
||||
}
|
||||
if (!this.lineOptions.length) {
|
||||
this.$message.warning(this.pageForm.settingId ? "当前配置下暂无可选线路" : "当前年度范围下暂无可选线路")
|
||||
}
|
||||
},
|
||||
settingChange() {
|
||||
this.pageForm.matterId = ""
|
||||
this.loadLineOptions()
|
||||
},
|
||||
doSearch() {
|
||||
if (!this.checkYearRange()) {
|
||||
return
|
||||
}
|
||||
this.tableKey = new Date().getTime()
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageData()
|
||||
this.scheduleLoadOptions()
|
||||
},
|
||||
resetSearch() {
|
||||
const currentYear = moment().format("YYYY")
|
||||
this.pageForm.startYear = currentYear
|
||||
this.pageForm.endYear = currentYear
|
||||
this.pageForm.settingId = ""
|
||||
this.pageForm.matterId = ""
|
||||
this.pageForm.keyword = ""
|
||||
this.pageForm.unitName = ""
|
||||
this.pageForm.unionId = ""
|
||||
this.pageForm.joined = ""
|
||||
this.pageForm.lineType = ""
|
||||
this.pageForm.groupCode = ""
|
||||
this.pageForm.undertakeUnionId = ""
|
||||
this.doSearch()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadOptions()
|
||||
this.pageData()
|
||||
},
|
||||
watch: {
|
||||
"pageForm.startYear"() {
|
||||
this.pageForm.settingId = ""
|
||||
this.pageForm.matterId = ""
|
||||
this.scheduleLoadOptions()
|
||||
},
|
||||
"pageForm.endYear"() {
|
||||
this.pageForm.settingId = ""
|
||||
this.pageForm.matterId = ""
|
||||
this.scheduleLoadOptions()
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -57,7 +57,9 @@ layout("/layouts/platform.html"){
|
||||
border
|
||||
:default-sort="{prop: 'lineCode', order: 'ascending'}"
|
||||
:row-class-name="tableRowClassName"
|
||||
@sort-change="pageOrder">
|
||||
@sort-change="pageOrder"
|
||||
ref="tourMainTable"
|
||||
:height="tourTableHeight">
|
||||
<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="120" sortable="custom" align="center" header-align="center"></el-table-column>
|
||||
<el-table-column label="线路名称" prop="lineName" min-width="220" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
@@ -366,7 +368,7 @@ layout("/layouts/platform.html"){
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
mixins: [initTableMixins],
|
||||
mixins: [initTableMixins, tourTableHeightMixins],
|
||||
data() {
|
||||
const currentYear = moment().format("YYYY")
|
||||
const validateMatterUnion = (rule, value, callback) => {
|
||||
|
||||
+4
-2
@@ -72,7 +72,9 @@ layout("/layouts/platform.html"){
|
||||
:data="tableData"
|
||||
:size="tableSize"
|
||||
border
|
||||
@sort-change="pageOrder">
|
||||
@sort-change="pageOrder"
|
||||
ref="tourMainTable"
|
||||
:height="tourTableHeight">
|
||||
<el-table-column label="序号" type="index" :index="indexMethod" 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>
|
||||
@@ -413,7 +415,7 @@ layout("/layouts/platform.html"){
|
||||
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
mixins: [initTableMixins, tourTableHeightMixins],
|
||||
data() {
|
||||
const currentYear = moment().format("YYYY")
|
||||
return {
|
||||
|
||||
@@ -48,7 +48,7 @@ layout("/layouts/platform.html"){
|
||||
row-key="id"
|
||||
v-loading="tableLoading"
|
||||
@sort-change="pageOrder"
|
||||
>
|
||||
:height="tourTableHeight">
|
||||
<el-table-column label="序号" type="index" :index="indexMethod" width="70" align="center" header-align="center"></el-table-column>
|
||||
<el-table-column label="年度" prop="year" width="100" align="center" header-align="center"></el-table-column>
|
||||
<el-table-column label="疗休养配置名称" prop="configName" min-width="260" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
@@ -311,7 +311,7 @@ layout("/layouts/platform.html"){
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
mixins: [initTableMixins, tourTableHeightMixins],
|
||||
data() {
|
||||
const checkSignupTime = (rule, value, callback) => {
|
||||
if (this.formData.signupStartTime && this.formData.signupEndTime
|
||||
@@ -369,11 +369,12 @@ layout("/layouts/platform.html"){
|
||||
"drawer-user-scope": httpVueLoader("/components/module/activity/DrawerUserScope.vue")
|
||||
},
|
||||
methods: {
|
||||
async getActivityGroup() {
|
||||
const {data} = await this.$axios.post("/platform/activity/basic/scope/getActivityUserScopeGroup")
|
||||
this.activityGroupList = (data || []).map((item) => {
|
||||
return Object.assign({}, item, {
|
||||
groupId: item.groupId === null || item.groupId === undefined ? "" : String(item.groupId)
|
||||
getActivityGroup() {
|
||||
return this.$axios.post("/platform/activity/basic/scope/getActivityUserScopeGroup").then((res) => {
|
||||
this.activityGroupList = ((res && res.data) || []).map((item) => {
|
||||
return Object.assign({}, item, {
|
||||
groupId: item.groupId === null || item.groupId === undefined ? "" : String(item.groupId)
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
@@ -383,11 +384,11 @@ layout("/layouts/platform.html"){
|
||||
this.$refs.drawerUserScope.userScopeDialog = true
|
||||
}
|
||||
},
|
||||
async handleActivityGroupChange() {
|
||||
handleActivityGroupChange() {
|
||||
if (this.formData.activityGroupId !== null && this.formData.activityGroupId !== undefined) {
|
||||
this.formData.activityGroupId = String(this.formData.activityGroupId)
|
||||
}
|
||||
await this.getActivityGroup()
|
||||
this.getActivityGroup()
|
||||
},
|
||||
resetSearch() {
|
||||
this.pageForm.year = ""
|
||||
|
||||
@@ -54,7 +54,9 @@ layout("/layouts/platform.html"){
|
||||
border
|
||||
:default-sort="{prop: 'lineCode', order: 'ascending'}"
|
||||
:row-class-name="tableRowClassName"
|
||||
@sort-change="pageOrder">
|
||||
@sort-change="pageOrder"
|
||||
ref="tourMainTable"
|
||||
:height="tourTableHeight">
|
||||
<el-table-column label="序号" type="index" :index="indexMethod" width="80" align="center" header-align="center"></el-table-column>
|
||||
<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="240" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
@@ -631,7 +633,7 @@ layout("/layouts/platform.html"){
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
mixins: [initTableMixins, tourTableHeightMixins],
|
||||
data() {
|
||||
const currentYear = moment().format("YYYY")
|
||||
return {
|
||||
|
||||
@@ -63,7 +63,9 @@ layout("/layouts/platform.html"){
|
||||
:size="tableSize"
|
||||
border
|
||||
:default-sort="{prop: 'agencyCode', order: 'ascending'}"
|
||||
@sort-change="pageOrder">
|
||||
@sort-change="pageOrder"
|
||||
ref="tourMainTable"
|
||||
:height="tourTableHeight">
|
||||
<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="agencyName" min-width="220" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
@@ -179,7 +181,7 @@ layout("/layouts/platform.html"){
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
mixins: [initTableMixins, tourTableHeightMixins],
|
||||
data() {
|
||||
const currentYear = moment().format("YYYY")
|
||||
const validateMobile = (rule, value, callback) => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!--#
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
@@ -56,7 +56,9 @@ layout("/layouts/platform.html"){
|
||||
border
|
||||
:default-sort="{prop: 'lineName', order: 'ascending'}"
|
||||
:row-class-name="tableRowClassName"
|
||||
@sort-change="pageOrder">
|
||||
@sort-change="pageOrder"
|
||||
ref="tourMainTable"
|
||||
:height="tourTableHeight">
|
||||
<el-table-column label="序号" type="index" :index="indexMethod" width="80" align="center" header-align="center"></el-table-column>
|
||||
<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>
|
||||
@@ -171,7 +173,7 @@ layout("/layouts/platform.html"){
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
mixins: [initTableMixins, tourTableHeightMixins],
|
||||
data() {
|
||||
const currentYear = moment().format("YYYY")
|
||||
return {
|
||||
|
||||
@@ -72,7 +72,9 @@ layout("/layouts/platform.html"){
|
||||
:data="tableData"
|
||||
:size="tableSize"
|
||||
border
|
||||
@sort-change="pageOrder">
|
||||
@sort-change="pageOrder"
|
||||
ref="tourMainTable"
|
||||
:height="tourTableHeight">
|
||||
<el-table-column label="序号" type="index" :index="indexMethod" 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>
|
||||
@@ -413,7 +415,7 @@ layout("/layouts/platform.html"){
|
||||
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
mixins: [initTableMixins, tourTableHeightMixins],
|
||||
data() {
|
||||
const currentYear = moment().format("YYYY")
|
||||
return {
|
||||
|
||||
@@ -102,7 +102,9 @@ layout("/layouts/platform.html"){
|
||||
:data="tableData"
|
||||
:size="tableSize"
|
||||
border
|
||||
@sort-change="pageOrder">
|
||||
@sort-change="pageOrder"
|
||||
ref="tourMainTable"
|
||||
:height="tourTableHeight">
|
||||
<el-table-column label="序号" type="index" :index="indexMethod" 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>
|
||||
@@ -310,7 +312,7 @@ layout("/layouts/platform.html"){
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
mixins: [initTableMixins, tourTableHeightMixins],
|
||||
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
|
||||
data() {
|
||||
const currentYear = moment().format("YYYY")
|
||||
|
||||
Reference in New Issue
Block a user