疗休养模块优化整改
This commit is contained in:
+5
-2
@@ -83,7 +83,10 @@ public class TourGroupController {
|
||||
m.`year`,
|
||||
m.matterName,
|
||||
m.unionId,
|
||||
COALESCE(u.name, '校工会') AS unionName,
|
||||
CASE
|
||||
WHEN IFNULL(NULLIF(m.undertakeStatus, ''), 'unclaimed') = 'claimed' THEN COALESCE(u.name, '校工会')
|
||||
ELSE ''
|
||||
END AS unionName,
|
||||
m.lineId,
|
||||
l.lineName,
|
||||
l.lineType,
|
||||
@@ -632,7 +635,7 @@ public class TourGroupController {
|
||||
return "m.matterName";
|
||||
}
|
||||
if ("unionName".equals(orderName)) {
|
||||
return "u.name";
|
||||
return "CASE WHEN IFNULL(NULLIF(m.undertakeStatus, ''), 'unclaimed') = 'claimed' THEN COALESCE(u.name, '校工会') ELSE '' END";
|
||||
}
|
||||
if ("lineType".equals(orderName)) {
|
||||
return "l.lineType";
|
||||
|
||||
+47
-5
@@ -36,6 +36,8 @@ 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 +54,7 @@ public class TourLineController {
|
||||
@SaCheckPermission("tour.route")
|
||||
public Result pageData(PageForm pageForm, Integer year, String lineName, String lotId) {
|
||||
if (StrUtil.isBlank(pageForm.getPageOrderName())) {
|
||||
pageForm.defaultSortDesc("enabled");
|
||||
pageForm.defaultSortAsc("lineCode");
|
||||
}
|
||||
|
||||
Cnd cnd = Cnd.NEW();
|
||||
@@ -91,7 +93,7 @@ public class TourLineController {
|
||||
LEFT JOIN tour_setting_lot lot ON lot.id = l.lotId
|
||||
$creatorJoin
|
||||
$condition
|
||||
ORDER BY $orderColumn $orderBy, l.`year` DESC, l.lineCode ASC, l.createdAt DESC
|
||||
ORDER BY $orderColumn $orderBy, l.`year` DESC, CAST(l.lineCode AS UNSIGNED) ASC, l.createdAt DESC
|
||||
""");
|
||||
listSql.setVar("creatorJoin", creatorJoin);
|
||||
listSql.setCondition(cnd);
|
||||
@@ -168,7 +170,7 @@ public class TourLineController {
|
||||
sameCodeCnd.and(TourLine::getId, "<>", line.getId());
|
||||
}
|
||||
if (tourLineService.count(sameCodeCnd) > 0) {
|
||||
return Result.error("同年度下线路编号已存在");
|
||||
return Result.error("同年度下排序编号已存在");
|
||||
}
|
||||
if (line.getEnabled() == null) {
|
||||
line.setEnabled(true);
|
||||
@@ -197,10 +199,47 @@ public class TourLineController {
|
||||
if (StrUtil.isBlank(id)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
TourLine line = tourLineService.fetch(id);
|
||||
if (line == null) {
|
||||
return Result.error("线路不存在");
|
||||
}
|
||||
if (countLineSignup(id) > 0) {
|
||||
return Result.error("当前线路已有人员报名,不能删除");
|
||||
}
|
||||
if (countLineMatter(id) > 0) {
|
||||
return Result.error("当前线路已关联事项,不能删除");
|
||||
}
|
||||
tourLineService.delete(id);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
private int countLineSignup(String lineId) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT COUNT(1)
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId
|
||||
WHERE t.delFlag = 0
|
||||
AND (t.lineId = @lineId OR m.lineId = @lineId)
|
||||
""");
|
||||
sql.setParam("lineId", lineId);
|
||||
sql.setCallback(Sqls.callback.integer());
|
||||
tourLineService.dao().execute(sql);
|
||||
return sql.getInt();
|
||||
}
|
||||
|
||||
private int countLineMatter(String lineId) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT COUNT(1)
|
||||
FROM tour_matter
|
||||
WHERE delFlag = 0
|
||||
AND lineId = @lineId
|
||||
""");
|
||||
sql.setParam("lineId", lineId);
|
||||
sql.setCallback(Sqls.callback.integer());
|
||||
tourLineService.dao().execute(sql);
|
||||
return sql.getInt();
|
||||
}
|
||||
|
||||
private Result check(TourLine line) {
|
||||
if (line == null) {
|
||||
return Result.error("参数错误");
|
||||
@@ -215,7 +254,10 @@ public class TourLineController {
|
||||
return Result.error("线路名称不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(line.getLineCode())) {
|
||||
return Result.error("线路编号不能为空");
|
||||
return Result.error("排序编号不能为空");
|
||||
}
|
||||
if (!line.getLineCode().matches(SORT_CODE_PATTERN)) {
|
||||
return Result.error("排序编号必须为整数");
|
||||
}
|
||||
if (StrUtil.isBlank(line.getLineType())) {
|
||||
return Result.error("线路类型不能为空");
|
||||
@@ -281,7 +323,7 @@ public class TourLineController {
|
||||
return "l.`year`";
|
||||
}
|
||||
if ("lineCode".equals(orderName)) {
|
||||
return "l.lineCode";
|
||||
return "CAST(l.lineCode AS UNSIGNED)";
|
||||
}
|
||||
if ("lotName".equals(orderName)) {
|
||||
return "lot.lotName";
|
||||
|
||||
+97
-12
@@ -76,7 +76,10 @@ public class TourMatterController {
|
||||
SELECT
|
||||
m.*,
|
||||
s.configName AS settingName,
|
||||
u.name AS unionName,
|
||||
CASE
|
||||
WHEN IFNULL(NULLIF(m.undertakeStatus, ''), 'unclaimed') = 'claimed' THEN COALESCE(u.name, '校工会')
|
||||
ELSE ''
|
||||
END AS unionName,
|
||||
d.name AS organizationTypeName,
|
||||
l.lineName AS lineName,
|
||||
l.lineType AS lineType,
|
||||
@@ -157,6 +160,35 @@ public class TourMatterController {
|
||||
return Result.success(sql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.matter")
|
||||
public Result lineInfo(String lineId) {
|
||||
if (StrUtil.isBlank(lineId)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("l.delFlag", "=", false);
|
||||
cnd.and("l.enabled", "=", true);
|
||||
cnd.and("l.id", "=", lineId);
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
l.*,
|
||||
lot.lotName AS lotName,
|
||||
lot.lotValue AS lotValue,
|
||||
lot.lotValue AS lotDays,
|
||||
lot.activityCost AS activityCost
|
||||
FROM tour_line l
|
||||
LEFT JOIN tour_setting_lot lot ON lot.id = l.lotId
|
||||
$condition
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.map());
|
||||
tourMatterService.dao().execute(sql);
|
||||
NutMap line = sql.getObject(NutMap.class);
|
||||
return line == null || line.isEmpty() ? Result.error("线路不存在") : Result.success(line);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.matter")
|
||||
public Result organizationTypeOptions() {
|
||||
@@ -194,7 +226,7 @@ public class TourMatterController {
|
||||
} else {
|
||||
tourMatterService.updateIgnoreNull(matter);
|
||||
}
|
||||
return Result.success();
|
||||
return Result.success(NutMap.NEW().addv("id", matter.getId()));
|
||||
}
|
||||
|
||||
@At
|
||||
@@ -246,21 +278,31 @@ public class TourMatterController {
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.matter")
|
||||
public Result settingPeople(String matterId) {
|
||||
if (StrUtil.isBlank(matterId)) {
|
||||
public Result settingPeople(String matterId, Integer year) {
|
||||
if (StrUtil.isBlank(matterId) && year == null) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
TourMatter matter = tourMatterService.fetch(matterId);
|
||||
if (matter == null || StrUtil.isBlank(matter.getSettingId())) {
|
||||
return Result.success(NutMap.NEW());
|
||||
return Result.success(settingDefaults(year, matterId));
|
||||
}
|
||||
|
||||
private NutMap settingDefaults(Integer year, String matterId) {
|
||||
TourMatter matter = null;
|
||||
if (StrUtil.isNotBlank(matterId)) {
|
||||
matter = tourMatterService.fetch(matterId);
|
||||
}
|
||||
Integer settingYear = year != null ? year : (matter == null ? null : matter.getYear());
|
||||
TourSetting setting = fetchSettingByYear(settingYear);
|
||||
if (setting == null && matter != null && StrUtil.isNotBlank(matter.getSettingId())) {
|
||||
setting = tourMatterService.dao().fetch(TourSetting.class, matter.getSettingId());
|
||||
}
|
||||
TourSetting setting = tourMatterService.dao().fetch(TourSetting.class, matter.getSettingId());
|
||||
if (setting == null) {
|
||||
return Result.success(NutMap.NEW());
|
||||
return NutMap.NEW();
|
||||
}
|
||||
return Result.success(NutMap.NEW()
|
||||
return NutMap.NEW()
|
||||
.addv("minGroupPeople", setting.getMinGroupPeople())
|
||||
.addv("maxGroupPeople", setting.getMaxGroupPeople()));
|
||||
.addv("maxGroupPeople", setting.getMaxGroupPeople())
|
||||
.addv("signupStartTime", setting.getSignupStartTime())
|
||||
.addv("signupEndTime", setting.getSignupEndTime());
|
||||
}
|
||||
|
||||
@At
|
||||
@@ -268,6 +310,7 @@ public class TourMatterController {
|
||||
@SaCheckPermission("tour.matter")
|
||||
@SLog(type = "tour", tag = "疗休养事项", msg = "保存事项线路配置")
|
||||
public Result lineConfigDoSubmit(TourMatter matter) {
|
||||
fillLineConfigFromSetting(matter);
|
||||
Result checkResult = checkLineConfig(matter);
|
||||
if (checkResult != null) {
|
||||
return checkResult;
|
||||
@@ -290,6 +333,48 @@ public class TourMatterController {
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
private void fillLineConfigFromSetting(TourMatter matter) {
|
||||
if (matter == null || StrUtil.isBlank(matter.getId())) {
|
||||
return;
|
||||
}
|
||||
TourMatter oldMatter = tourMatterService.fetch(matter.getId());
|
||||
if (oldMatter == null) {
|
||||
return;
|
||||
}
|
||||
TourSetting setting = fetchSettingByYear(oldMatter.getYear());
|
||||
if (setting == null && StrUtil.isNotBlank(oldMatter.getSettingId())) {
|
||||
setting = tourMatterService.dao().fetch(TourSetting.class, oldMatter.getSettingId());
|
||||
}
|
||||
if (setting == null) {
|
||||
return;
|
||||
}
|
||||
if (setting.getMinGroupPeople() != null) {
|
||||
matter.setMinGroupPeople(setting.getMinGroupPeople());
|
||||
}
|
||||
if (setting.getMaxGroupPeople() != null) {
|
||||
matter.setMaxGroupPeople(setting.getMaxGroupPeople());
|
||||
}
|
||||
if (StrUtil.isNotBlank(setting.getSignupStartTime())) {
|
||||
matter.setSignupStartTime(setting.getSignupStartTime());
|
||||
}
|
||||
if (StrUtil.isNotBlank(setting.getSignupEndTime())) {
|
||||
matter.setSignupEndTime(setting.getSignupEndTime());
|
||||
}
|
||||
}
|
||||
|
||||
private TourSetting fetchSettingByYear(Integer year) {
|
||||
if (year == null) {
|
||||
return null;
|
||||
}
|
||||
Cnd cnd = Cnd.where(TourSetting::getEnabled, "=", true);
|
||||
cnd.and("delFlag", "=", false);
|
||||
cnd.and(TourSetting::getYear, "=", year);
|
||||
cnd.desc(TourSetting::getCreatedAt);
|
||||
cnd.desc(TourSetting::getUpdatedAt);
|
||||
cnd.asc(TourSetting::getConfigName);
|
||||
return tourMatterService.dao().fetch(TourSetting.class, cnd);
|
||||
}
|
||||
|
||||
private Result check(TourMatter matter) {
|
||||
if (matter == null) {
|
||||
return Result.error("参数错误");
|
||||
@@ -422,7 +507,7 @@ public class TourMatterController {
|
||||
return "m.matterName";
|
||||
}
|
||||
if ("unionName".equals(orderName)) {
|
||||
return "u.name";
|
||||
return "CASE WHEN IFNULL(NULLIF(m.undertakeStatus, ''), 'unclaimed') = 'claimed' THEN COALESCE(u.name, '校工会') ELSE '' END";
|
||||
}
|
||||
if ("lineName".equals(orderName)) {
|
||||
return "l.lineName";
|
||||
|
||||
+45
-70
@@ -55,7 +55,6 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
@@ -146,6 +145,10 @@ public class TourMySignupController {
|
||||
IFNULL(GROUP_CONCAT(DISTINCT task.displayName), IF(ins.id IS NULL, '', '结束')) AS curTaskName,
|
||||
IFNULL(f.familyCount, 0) AS familyCount,
|
||||
COALESCE(m.travelEndTime, tp.travelEndTime) AS travelEndTime,
|
||||
CASE
|
||||
WHEN IFNULL(NULLIF(m.undertakeStatus, ''), 'unclaimed') = 'claimed' THEN COALESCE(u.name, '校工会')
|
||||
ELSE ''
|
||||
END AS matterUnionName,
|
||||
CASE
|
||||
WHEN IFNULL(m.travelStartTime, '') <> '' AND IFNULL(m.travelEndTime, '') <> ''
|
||||
THEN CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime)
|
||||
@@ -163,6 +166,7 @@ public class TourMySignupController {
|
||||
GROUP BY ledgerId
|
||||
) f ON f.ledgerId = t.id
|
||||
LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0
|
||||
LEFT JOIN sys_union u ON u.id = m.unionId
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
`year`,
|
||||
@@ -213,7 +217,7 @@ public class TourMySignupController {
|
||||
.and(TourLedgerDirectRelative::getLedgerId, "=", ledger.getId()));
|
||||
NutMap signupConfig = getSignupConfig(ledger);
|
||||
return Result.success(NutMap.NEW()
|
||||
.addv("ledger", ledger)
|
||||
.addv("ledger", buildLedgerView(ledger))
|
||||
.addv("travelPeriod", getTravelPeriod(ledger))
|
||||
.addv("families", tourLedgerFamilyService.query(familyCnd))
|
||||
.addv("directRelative", directRelative)
|
||||
@@ -326,11 +330,18 @@ public class TourMySignupController {
|
||||
.and(TourLedgerDirectRelative::getLedgerId, "=", ledger.getId()));
|
||||
return Result.success(NutMap.NEW()
|
||||
.addv("matter", matter)
|
||||
.addv("ledger", ledger)
|
||||
.addv("ledger", buildLedgerView(ledger))
|
||||
.addv("families", tourLedgerFamilyService.query(familyCnd))
|
||||
.addv("directRelative", directRelative));
|
||||
}
|
||||
|
||||
private NutMap buildLedgerView(TourLedger ledger) {
|
||||
NutMap map = Lang.obj2nutmap(ledger);
|
||||
View_user user = tourLedgerService.dao().fetch(View_user.class, Cnd.where("loginname", "=", ledger.getJobNo()));
|
||||
map.addv("mobile", defaultIfBlank(ledger.getMobile(), user == null ? "" : defaultIfBlank(user.getMobile(), "")));
|
||||
return map;
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission(value = {"tour.mysignup", "h5.tour.mysignup"}, mode = SaMode.OR)
|
||||
public Result directRelativeOptions() {
|
||||
@@ -587,6 +598,9 @@ public class TourMySignupController {
|
||||
if (StrUtil.isBlank(ledger.getLineName())) {
|
||||
return Result.error("报名线路不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(ledger.getIdCard())) {
|
||||
return Result.error("身份证号不能为空");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -612,14 +626,16 @@ public class TourMySignupController {
|
||||
if (activityGroupId == null || !activityBasicScopeService.isUserInGroup(activityGroupId, SecurityUtil.getUserId())) {
|
||||
return Result.error("您不在本次疗休养报名范围内");
|
||||
}
|
||||
if (StrUtil.isBlank(matter.getSignupStartTime()) || StrUtil.isBlank(matter.getSignupEndTime())) {
|
||||
String signupStartTime = defaultIfBlank(setting.getSignupStartTime(), matter.getSignupStartTime());
|
||||
String signupEndTime = defaultIfBlank(setting.getSignupEndTime(), matter.getSignupEndTime());
|
||||
if (StrUtil.isBlank(signupStartTime) || StrUtil.isBlank(signupEndTime)) {
|
||||
return Result.error("报名时间未配置");
|
||||
}
|
||||
String now = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
if (now.compareTo(normalizeDateTime(matter.getSignupStartTime(), false)) < 0) {
|
||||
if (now.compareTo(normalizeDateTime(signupStartTime, false)) < 0) {
|
||||
return Result.error("报名未开始");
|
||||
}
|
||||
if (now.compareTo(normalizeDateTime(matter.getSignupEndTime(), true)) > 0) {
|
||||
if (now.compareTo(normalizeDateTime(signupEndTime, true)) > 0) {
|
||||
return Result.error("报名已结束");
|
||||
}
|
||||
CycleAllowedTimes cycleAllowedTimes = calculateCycleAllowedTimes(matter, setting, oldLedger);
|
||||
@@ -794,76 +810,35 @@ public class TourMySignupController {
|
||||
}
|
||||
|
||||
private OutProvinceQuota calculateOutProvinceQuota(TourMatter matter, TourSetting setting, TourLedger oldLedger) {
|
||||
String ratioType = normalizeOutProvinceRatioType(setting == null ? null : setting.getOutProvinceRatioType());
|
||||
BigDecimal originalRatio = setting == null ? null : setting.getOutProvinceRatio();
|
||||
boolean oneThirdRatio = isOneThirdRatio(originalRatio);
|
||||
BigDecimal ratio = oneThirdRatio ? BigDecimal.ONE.divide(BigDecimal.valueOf(3), 12, RoundingMode.HALF_UP)
|
||||
: (originalRatio == null ? BigDecimal.ZERO : originalRatio);
|
||||
int year = matter == null || matter.getYear() == null ? LocalDate.now().getYear() : matter.getYear();
|
||||
String excludeLedgerId = oldLedger == null ? null : oldLedger.getId();
|
||||
int totalSignupPeople = countYearSignupPeople(year, excludeLedgerId);
|
||||
int domesticSignupPeople = countYearDomesticSignupPeople(year, excludeLedgerId);
|
||||
int outProvinceSignupPeople = countYearOutProvinceSignupPeople(year, excludeLedgerId);
|
||||
int basePeople;
|
||||
if ("可参加教职工人数".equals(ratioType)) {
|
||||
Integer groupId = parseInteger(setting == null ? null : setting.getActivityGroupId());
|
||||
basePeople = countActivityGroupPeople(groupId);
|
||||
} else if ("固定人数".equals(ratioType)) {
|
||||
basePeople = setting == null || setting.getOutProvinceFixedPeople() == null ? 0 : setting.getOutProvinceFixedPeople();
|
||||
} else {
|
||||
basePeople = totalSignupPeople;
|
||||
}
|
||||
int quotaPeople = oneThirdRatio
|
||||
? basePeople / 3
|
||||
: ratio.multiply(BigDecimal.valueOf(basePeople)).setScale(0, RoundingMode.FLOOR).intValue();
|
||||
int allowPeople = quotaPeople - outProvinceSignupPeople;
|
||||
return new OutProvinceQuota(ratioType, ratio, basePeople, totalSignupPeople, outProvinceSignupPeople, allowPeople);
|
||||
}
|
||||
|
||||
private boolean isOneThirdRatio(BigDecimal ratio) {
|
||||
if (ratio == null) {
|
||||
return false;
|
||||
}
|
||||
return ratio.compareTo(BigDecimal.valueOf(0.33)) >= 0 && ratio.compareTo(BigDecimal.valueOf(0.3333)) <= 0;
|
||||
}
|
||||
|
||||
private String normalizeOutProvinceRatioType(String ratioType) {
|
||||
if ("当年参加人数".equals(ratioType) || StrUtil.isBlank(ratioType)) {
|
||||
return "当年报名人数";
|
||||
}
|
||||
if ("可参加教职工人数".equals(ratioType) || "固定人数".equals(ratioType)) {
|
||||
return ratioType;
|
||||
}
|
||||
return "当年报名人数";
|
||||
int allowPeople = domesticSignupPeople / 2 - outProvinceSignupPeople;
|
||||
return new OutProvinceQuota("当年省内报名人数", domesticSignupPeople,
|
||||
domesticSignupPeople + outProvinceSignupPeople, outProvinceSignupPeople, allowPeople);
|
||||
}
|
||||
|
||||
private String buildOutProvinceQuotaNotice(OutProvinceQuota quota) {
|
||||
String suffix = quota.canApply() ? "您可以报名,或您稍后报名" : "请稍后报名";
|
||||
if ("当年报名人数".equals(quota.ratioType())) {
|
||||
return "当前报名人数是" + quota.totalSignupPeople() + "人,已经报名省外线路人数是"
|
||||
+ quota.outProvinceSignupPeople() + "人,按照省外人数不超过" + quota.ratioText()
|
||||
+ "的规则,当前时间允许报名人数是" + quota.allowPeople() + "人," + suffix;
|
||||
}
|
||||
if ("可参加教职工人数".equals(quota.ratioType())) {
|
||||
return "今年有权限报名人数是" + quota.basePeople() + "人,已经报名省外线路人数是"
|
||||
+ quota.outProvinceSignupPeople() + "人,按照省外人数不超过" + quota.ratioText()
|
||||
+ "的规则,当前时间允许报名人数是" + quota.allowPeople() + "人," + suffix;
|
||||
}
|
||||
return "按照省外人数不超过" + quota.ratioText()
|
||||
return "当前报省内线路教职工有效人数是" + quota.basePeople() + "人,已经报名省外线路教职工有效人数是"
|
||||
+ quota.outProvinceSignupPeople() + "人,按照省外人数不超过出行人数的1/3规则"
|
||||
+ "的规则,当前时间允许报名人数是" + quota.allowPeople() + "人," + suffix;
|
||||
}
|
||||
|
||||
private int countYearSignupPeople(int year, String excludeLedgerId) {
|
||||
private int countYearDomesticSignupPeople(int year, String excludeLedgerId) {
|
||||
String excludeSql = StrUtil.isBlank(excludeLedgerId) ? "" : " AND t.id <> @excludeLedgerId";
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT COUNT(1)
|
||||
SELECT COUNT(DISTINCT t.id)
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = t.id
|
||||
WHERE t.delFlag = 0
|
||||
AND t.`year` = @year
|
||||
AND (ins.id IS NULL OR ins.state = @finishedState)
|
||||
AND t.lineType IN ('省内线路', '省内', '国内线路', '国内')
|
||||
AND (ins.id IS NULL OR ins.state <> @abandonState)
|
||||
""" + excludeSql);
|
||||
sql.setParam("year", year);
|
||||
sql.setParam("finishedState", ProcessInstanceStateEnum.FINISHED.getCode());
|
||||
sql.setParam("abandonState", ProcessInstanceStateEnum.ABANDON.getCode());
|
||||
if (StrUtil.isNotBlank(excludeLedgerId)) {
|
||||
sql.setParam("excludeLedgerId", excludeLedgerId);
|
||||
}
|
||||
@@ -875,16 +850,16 @@ public class TourMySignupController {
|
||||
private int countYearOutProvinceSignupPeople(int year, String excludeLedgerId) {
|
||||
String excludeSql = StrUtil.isBlank(excludeLedgerId) ? "" : " AND t.id <> @excludeLedgerId";
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT COUNT(1)
|
||||
SELECT COUNT(DISTINCT t.id)
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = t.id
|
||||
WHERE t.delFlag = 0
|
||||
AND t.`year` = @year
|
||||
AND t.lineType IN ('省外线路', '省外')
|
||||
AND (ins.id IS NULL OR ins.state = @finishedState)
|
||||
AND (ins.id IS NULL OR ins.state <> @abandonState)
|
||||
""" + excludeSql);
|
||||
sql.setParam("year", year);
|
||||
sql.setParam("finishedState", ProcessInstanceStateEnum.FINISHED.getCode());
|
||||
sql.setParam("abandonState", ProcessInstanceStateEnum.ABANDON.getCode());
|
||||
if (StrUtil.isNotBlank(excludeLedgerId)) {
|
||||
sql.setParam("excludeLedgerId", excludeLedgerId);
|
||||
}
|
||||
@@ -1089,7 +1064,6 @@ public class TourMySignupController {
|
||||
}
|
||||
|
||||
private record OutProvinceQuota(String ratioType,
|
||||
BigDecimal ratio,
|
||||
int basePeople,
|
||||
int totalSignupPeople,
|
||||
int outProvinceSignupPeople,
|
||||
@@ -1099,14 +1073,7 @@ public class TourMySignupController {
|
||||
}
|
||||
|
||||
String ratioText() {
|
||||
if (ratio == null || BigDecimal.ZERO.compareTo(ratio) == 0) {
|
||||
return "0";
|
||||
}
|
||||
BigDecimal oneThird = BigDecimal.ONE.divide(BigDecimal.valueOf(3), 8, RoundingMode.HALF_UP);
|
||||
if (ratio.subtract(oneThird).abs().compareTo(BigDecimal.valueOf(0.01)) <= 0) {
|
||||
return "1/3";
|
||||
}
|
||||
return ratio.stripTrailingZeros().toPlainString();
|
||||
return "floor(省内有效人数/2)-省外有效人数";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1338,6 +1305,7 @@ public class TourMySignupController {
|
||||
.addv("applyDate", firstNotBlank(approvalTimes.getString("applyDate", ""), ledger.getSignupTime()))
|
||||
.addv("unionAuditorName", approvalTimes.getString("unionAuditorName", ""))
|
||||
.addv("unionAuditDate", approvalTimes.getString("unionAuditDate", ""))
|
||||
.addv("schoolUnionAuditorName", approvalTimes.getString("schoolUnionAuditorName", ""))
|
||||
.addv("schoolUnionAuditDate", approvalTimes.getString("schoolUnionAuditDate", ""));
|
||||
}
|
||||
|
||||
@@ -1389,6 +1357,7 @@ public class TourMySignupController {
|
||||
.addv("applyDate", firstNotBlank(approvalTimes.getString("applyDate", ""), ledger.getSignupTime()))
|
||||
.addv("unionAuditorName", approvalTimes.getString("unionAuditorName", ""))
|
||||
.addv("unionAuditDate", approvalTimes.getString("unionAuditDate", ""))
|
||||
.addv("schoolUnionAuditorName", approvalTimes.getString("schoolUnionAuditorName", ""))
|
||||
.addv("schoolUnionAuditDate", approvalTimes.getString("schoolUnionAuditDate", ""))
|
||||
.addv("relativeUnitAuditDate", "");
|
||||
}
|
||||
@@ -1444,6 +1413,7 @@ public class TourMySignupController {
|
||||
result.put("unionAuditorName", parseTaskUserName(item.getString("variable", "")));
|
||||
} else if ("校工会审核".equals(displayName)) {
|
||||
result.put("schoolUnionAuditDate", finishDate);
|
||||
result.put("schoolUnionAuditorName", parseTaskUserName(item.getString("variable", "")));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -1580,6 +1550,7 @@ public class TourMySignupController {
|
||||
drawPlainDateLine(writer, data.getString("unionAuditDate", ""), 330, paragraphEndY - 163, 18);
|
||||
|
||||
writer.text("学校工会:盖章", 18, 300, paragraphEndY - 190, false);
|
||||
writer.text(data.getString("schoolUnionAuditorName", ""), 18, 410, paragraphEndY - 190, false);
|
||||
drawPlainDateLine(writer, data.getString("schoolUnionAuditDate", ""), 330, paragraphEndY - 217, 18);
|
||||
}
|
||||
document.save(out);
|
||||
@@ -1644,6 +1615,7 @@ public class TourMySignupController {
|
||||
|
||||
signY -= 78;
|
||||
writer.text("学校工会:盖章", 15, signX + 20, signY, false);
|
||||
writer.text(data.getString("schoolUnionAuditorName", ""), 15, signX + 135, signY, false);
|
||||
drawPlainDateLine(writer, data.getString("schoolUnionAuditDate", ""), signX + 45, signY - 31, 15);
|
||||
|
||||
signY -= 78;
|
||||
@@ -1823,6 +1795,9 @@ public class TourMySignupController {
|
||||
if ("travelPeriod".equals(orderName)) {
|
||||
return "COALESCE(m.travelStartTime, tp.travelPeriod)";
|
||||
}
|
||||
if ("matterUnionName".equals(orderName)) {
|
||||
return "matterUnionName";
|
||||
}
|
||||
if ("lineType".equals(orderName)) {
|
||||
return "t.lineType";
|
||||
}
|
||||
|
||||
+10
-1
@@ -7,6 +7,7 @@ import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||
import com.budwk.app.sys.views.View_user;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedger;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedgerDirectRelative;
|
||||
@@ -20,6 +21,7 @@ import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Lang;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
@@ -180,7 +182,7 @@ public class TourSchoolUnionApprovalController {
|
||||
.and(TourLedgerDirectRelative::getDelFlag, "=", false));
|
||||
NutMap signupConfig = getSignupConfig(ledger);
|
||||
return Result.success(NutMap.NEW()
|
||||
.addv("ledger", ledger)
|
||||
.addv("ledger", buildLedgerView(ledger))
|
||||
.addv("travelPeriod", getTravelPeriod(ledger))
|
||||
.addv("families", tourLedgerFamilyService.query(familyCnd))
|
||||
.addv("directRelative", directRelative)
|
||||
@@ -189,6 +191,13 @@ public class TourSchoolUnionApprovalController {
|
||||
.addv("directFamilyUnitLine", signupConfig.getBoolean("directFamilyUnitLine", false)));
|
||||
}
|
||||
|
||||
private NutMap buildLedgerView(TourLedger ledger) {
|
||||
NutMap map = Lang.obj2nutmap(ledger);
|
||||
View_user user = tourLedgerService.dao().fetch(View_user.class, Cnd.where("loginname", "=", ledger.getJobNo()));
|
||||
map.addv("mobile", StrUtil.blankToDefault(ledger.getMobile(), user == null ? "" : StrUtil.blankToDefault(user.getMobile(), "")));
|
||||
return map;
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission(value = {"tour.schoolUnionApproval", "h5.tour.schoolUnionApproval"}, mode = SaMode.OR)
|
||||
public Result unionOptions(Boolean audit, Integer startYear, Integer endYear, String keyword, String lineId, String travelPeriod, String lineType) {
|
||||
|
||||
+6
@@ -209,6 +209,12 @@ public class TourSettingController {
|
||||
&& tourSetting.getMinGroupPeople() > tourSetting.getMaxGroupPeople()) {
|
||||
return Result.error("最少成团人数不能大于最多成团人数");
|
||||
}
|
||||
if (StrUtil.isBlank(tourSetting.getSignupStartTime()) || StrUtil.isBlank(tourSetting.getSignupEndTime())) {
|
||||
return Result.error("报名时间不能为空");
|
||||
}
|
||||
if (tourSetting.getSignupStartTime().compareTo(tourSetting.getSignupEndTime()) >= 0) {
|
||||
return Result.error("开始报名时间必须小于结束报名时间");
|
||||
}
|
||||
if (tourSetting.getCycleStartYear() != null && tourSetting.getCycleEndYear() != null
|
||||
&& tourSetting.getCycleStartYear() > tourSetting.getCycleEndYear()) {
|
||||
return Result.error("周期开始年度不能大于周期结束年度");
|
||||
|
||||
+163
-84
@@ -34,6 +34,7 @@ import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
@@ -44,8 +45,6 @@ import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
@@ -368,6 +367,63 @@ public class TourSignupController {
|
||||
return Result.success(sql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.signup")
|
||||
public Result signupPageData(PageForm pageForm, String matterId, String keyword, String unionId) {
|
||||
return querySignupPageData(pageForm, matterId, keyword, unionId);
|
||||
}
|
||||
|
||||
@At("/h5/signupPageData")
|
||||
@SaCheckPermission(value = {"tour.signup", "h5.tour.signup"}, mode = SaMode.OR)
|
||||
public Result h5SignupPageData(PageForm pageForm, String matterId, String keyword, String unionId) {
|
||||
return querySignupPageData(pageForm, matterId, keyword, unionId);
|
||||
}
|
||||
|
||||
private Result querySignupPageData(PageForm pageForm, String matterId, String keyword, String unionId) {
|
||||
if (StrUtil.isBlank(matterId)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
if (StrUtil.isBlank(pageForm.getPageOrderName())) {
|
||||
pageForm.defaultSortDesc("signupTime");
|
||||
}
|
||||
Cnd cnd = buildSignupQueryCnd(matterId, keyword, unionId);
|
||||
Sql countSql = Sqls.create("""
|
||||
SELECT COUNT(DISTINCT t.id)
|
||||
FROM tour_ledger t
|
||||
INNER JOIN tour_matter m ON m.id = t.matterId
|
||||
INNER JOIN tour_line l ON l.id = m.lineId
|
||||
$condition
|
||||
""");
|
||||
countSql.setCondition(cnd);
|
||||
countSql.setCallback(Sqls.callback.integer());
|
||||
tourLedgerService.dao().execute(countSql);
|
||||
int count = countSql.getInt();
|
||||
|
||||
Sql listSql = Sqls.create("""
|
||||
SELECT
|
||||
t.id,
|
||||
t.jobNo,
|
||||
t.userName,
|
||||
t.unionId,
|
||||
t.unionName,
|
||||
t.signupTime
|
||||
FROM tour_ledger t
|
||||
INNER JOIN tour_matter m ON m.id = t.matterId
|
||||
INNER JOIN tour_line l ON l.id = m.lineId
|
||||
$condition
|
||||
ORDER BY $orderColumn $orderBy, t.signupTime DESC, t.createdAt DESC
|
||||
""");
|
||||
listSql.setCondition(cnd);
|
||||
listSql.setVar("orderColumn", getSignupOrderColumn(pageForm.getPageOrderName()));
|
||||
listSql.setVar("orderBy", "ascending".equals(pageForm.getPageOrderBy()) ? "asc" : "desc");
|
||||
listSql.setPager(tourLedgerService.dao().createPager(pageForm.getPageNumber(), pageForm.getPageSize()));
|
||||
listSql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(listSql);
|
||||
|
||||
Pagination<NutMap> pagination = new Pagination<>(pageForm.getPageNumber(), pageForm.getPageSize(), count, listSql.getList(NutMap.class));
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission(value = {"tour.signup", "h5.tour.signup"}, mode = SaMode.OR)
|
||||
public Result lineDetail(String lineId) {
|
||||
@@ -395,7 +451,7 @@ public class TourSignupController {
|
||||
|
||||
@At
|
||||
@SaCheckPermission(value = {"tour.signup", "h5.tour.signup"}, mode = SaMode.OR)
|
||||
public Result signupDetail(String matterId) {
|
||||
public Result signupDetail(String matterId, Boolean noticeChecked) {
|
||||
if (StrUtil.isBlank(matterId)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
@@ -420,6 +476,8 @@ public class TourSignupController {
|
||||
l.travelAgencyId,
|
||||
a.agencyName AS travelAgencyName,
|
||||
IFNULL(lot.allowOverReimbursement, 0) AS allowOverReimbursement,
|
||||
IFNULL(sc.signupCount, 0) AS signupCount,
|
||||
IFNULL(sc.familyCount, 0) AS familyCount,
|
||||
s.allowFamily,
|
||||
IFNULL(s.fillBedInfo, 1) AS fillBedInfo
|
||||
FROM tour_matter m
|
||||
@@ -427,6 +485,23 @@ public class TourSignupController {
|
||||
LEFT JOIN tour_travel_agency a ON a.id = l.travelAgencyId
|
||||
LEFT JOIN tour_setting_lot lot ON lot.id = l.lotId
|
||||
LEFT JOIN tour_setting s ON s.id = m.settingId
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
t.matterId,
|
||||
COUNT(1) + SUM(IFNULL(f.familyCount, 0)) AS signupCount,
|
||||
SUM(IFNULL(f.familyCount, 0)) AS familyCount
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN (
|
||||
SELECT ledgerId, COUNT(1) AS familyCount
|
||||
FROM tour_ledger_family
|
||||
WHERE delFlag = 0
|
||||
GROUP BY ledgerId
|
||||
) f ON f.ledgerId = t.id
|
||||
WHERE t.delFlag = 0
|
||||
AND t.matterId IS NOT NULL
|
||||
AND t.matterId <> ''
|
||||
GROUP BY t.matterId
|
||||
) sc ON sc.matterId = m.id
|
||||
WHERE m.delFlag = 0
|
||||
AND m.enabled = 1
|
||||
AND m.id = @matterId
|
||||
@@ -461,9 +536,11 @@ public class TourSignupController {
|
||||
ruleLedger.setMatterId(matter.getString("matterId"));
|
||||
ruleLedger.setLineId(matter.getString("lineId"));
|
||||
ruleLedger.setLineName(matter.getString("lineName"));
|
||||
Result ruleResult = checkSignupRule(ruleLedger, matterEntity, ledger);
|
||||
if (ruleResult != null) {
|
||||
return ruleResult;
|
||||
if (!Boolean.TRUE.equals(noticeChecked)) {
|
||||
Result ruleResult = checkSignupRule(ruleLedger, matterEntity, ledger);
|
||||
if (ruleResult != null) {
|
||||
return ruleResult;
|
||||
}
|
||||
}
|
||||
List<TourLedgerFamily> families = Collections.emptyList();
|
||||
TourLedgerDirectRelative directRelative = null;
|
||||
@@ -591,26 +668,39 @@ public class TourSignupController {
|
||||
@At
|
||||
@SaCheckPermission(value = {"tour.signup", "h5.tour.signup"}, mode = SaMode.OR)
|
||||
public Result directRelativeOptions() {
|
||||
List<Sys_dict> list = sysDictService.getSubListByCode("directRelative");
|
||||
if (list == null) {
|
||||
return Result.success(Collections.emptyList());
|
||||
}
|
||||
return Result.success(list.stream().filter(item -> !item.isDisabled()).collect(Collectors.toList()));
|
||||
return Result.success(getEnabledDictOptions("directRelative"));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission(value = {"tour.signup", "h5.tour.signup"}, mode = SaMode.OR)
|
||||
public Result signupOptions() {
|
||||
return Result.success(NutMap.NEW()
|
||||
.addv("bedTypeOptions", getEnabledDictOptions("bedType"))
|
||||
.addv("familyRelationshipOptions", getFamilyRelationshipOptions())
|
||||
.addv("directRelativeOptions", getEnabledDictOptions("directRelative")));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission(value = {"tour.signup", "h5.tour.signup"}, mode = SaMode.OR)
|
||||
public Result bedTypeOptions() {
|
||||
List<Sys_dict> list = sysDictService.getSubListByCode("bedType");
|
||||
if (list == null) {
|
||||
return Result.success(Collections.emptyList());
|
||||
}
|
||||
return Result.success(list.stream().filter(item -> !item.isDisabled()).collect(Collectors.toList()));
|
||||
return Result.success(getEnabledDictOptions("bedType"));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission(value = {"tour.signup", "h5.tour.signup"}, mode = SaMode.OR)
|
||||
public Result familyRelationshipOptions() {
|
||||
return Result.success(getFamilyRelationshipOptions());
|
||||
}
|
||||
|
||||
private List<Sys_dict> getEnabledDictOptions(String code) {
|
||||
List<Sys_dict> list = sysDictService.getSubListByCode(code);
|
||||
if (list == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return list.stream().filter(item -> !item.isDisabled()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<Sys_dict> getFamilyRelationshipOptions() {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT d.*
|
||||
FROM sys_dict p
|
||||
@@ -624,7 +714,7 @@ public class TourSignupController {
|
||||
sql.setCallback(Sqls.callback.entities());
|
||||
sql.setEntity(tourLedgerService.dao().getEntity(Sys_dict.class));
|
||||
tourLedgerService.dao().execute(sql);
|
||||
return Result.success(sql.getList(Sys_dict.class));
|
||||
return sql.getList(Sys_dict.class);
|
||||
}
|
||||
|
||||
@At
|
||||
@@ -772,6 +862,26 @@ public class TourSignupController {
|
||||
return cnd;
|
||||
}
|
||||
|
||||
private Cnd buildSignupQueryCnd(String matterId, String keyword, String unionId) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("t.delFlag", "=", false);
|
||||
cnd.and("t.matterId", "=", matterId);
|
||||
cnd.and("m.delFlag", "=", false);
|
||||
cnd.and("m.enabled", "=", true);
|
||||
cnd.and("m.lineId", "IS NOT", null);
|
||||
cnd.and("m.lineId", "<>", "");
|
||||
cnd.and("l.delFlag", "=", false);
|
||||
cnd.and("l.enabled", "=", true);
|
||||
if (StrUtil.isNotBlank(keyword)) {
|
||||
SqlExpressionGroup keywordGroup = new SqlExpressionGroup();
|
||||
keywordGroup.orLike("t.userName", keyword.trim());
|
||||
keywordGroup.orLike("t.jobNo", keyword.trim());
|
||||
cnd.and(keywordGroup);
|
||||
}
|
||||
cnd.andEX("t.unionId", "=", unionId);
|
||||
return cnd;
|
||||
}
|
||||
|
||||
private Result checkSignup(TourLedger ledger) {
|
||||
if (ledger == null) {
|
||||
return Result.error("参数错误");
|
||||
@@ -788,6 +898,9 @@ public class TourSignupController {
|
||||
if (StrUtil.isBlank(ledger.getLineName())) {
|
||||
return Result.error("报名线路不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(ledger.getIdCard())) {
|
||||
return Result.error("身份证号不能为空");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -887,14 +1000,16 @@ public class TourSignupController {
|
||||
if (activityGroupId == null || !activityBasicScopeService.isUserInGroup(activityGroupId, SecurityUtil.getUserId())) {
|
||||
return Result.error("您不在本次疗休养报名范围内");
|
||||
}
|
||||
if (StrUtil.isBlank(matter.getSignupStartTime()) || StrUtil.isBlank(matter.getSignupEndTime())) {
|
||||
String signupStartTime = defaultIfBlank(setting.getSignupStartTime(), matter.getSignupStartTime());
|
||||
String signupEndTime = defaultIfBlank(setting.getSignupEndTime(), matter.getSignupEndTime());
|
||||
if (StrUtil.isBlank(signupStartTime) || StrUtil.isBlank(signupEndTime)) {
|
||||
return Result.error("报名时间未配置");
|
||||
}
|
||||
String now = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
if (now.compareTo(normalizeDateTime(matter.getSignupStartTime(), false)) < 0) {
|
||||
if (now.compareTo(normalizeDateTime(signupStartTime, false)) < 0) {
|
||||
return Result.error("报名未开始");
|
||||
}
|
||||
if (now.compareTo(normalizeDateTime(matter.getSignupEndTime(), true)) > 0) {
|
||||
if (now.compareTo(normalizeDateTime(signupEndTime, true)) > 0) {
|
||||
return Result.error("报名已结束");
|
||||
}
|
||||
CycleAllowedTimes cycleAllowedTimes = calculateCycleAllowedTimes(matter, setting, oldLedger);
|
||||
@@ -1069,76 +1184,35 @@ public class TourSignupController {
|
||||
}
|
||||
|
||||
private OutProvinceQuota calculateOutProvinceQuota(TourMatter matter, TourSetting setting, TourLedger oldLedger) {
|
||||
String ratioType = normalizeOutProvinceRatioType(setting == null ? null : setting.getOutProvinceRatioType());
|
||||
BigDecimal originalRatio = setting == null ? null : setting.getOutProvinceRatio();
|
||||
boolean oneThirdRatio = isOneThirdRatio(originalRatio);
|
||||
BigDecimal ratio = oneThirdRatio ? BigDecimal.ONE.divide(BigDecimal.valueOf(3), 12, RoundingMode.HALF_UP)
|
||||
: (originalRatio == null ? BigDecimal.ZERO : originalRatio);
|
||||
int year = matter == null || matter.getYear() == null ? LocalDate.now().getYear() : matter.getYear();
|
||||
String excludeLedgerId = oldLedger == null ? null : oldLedger.getId();
|
||||
int totalSignupPeople = countYearSignupPeople(year, excludeLedgerId);
|
||||
int domesticSignupPeople = countYearDomesticSignupPeople(year, excludeLedgerId);
|
||||
int outProvinceSignupPeople = countYearOutProvinceSignupPeople(year, excludeLedgerId);
|
||||
int basePeople;
|
||||
if ("可参加教职工人数".equals(ratioType)) {
|
||||
Integer groupId = parseInteger(setting == null ? null : setting.getActivityGroupId());
|
||||
basePeople = countActivityGroupPeople(groupId);
|
||||
} else if ("固定人数".equals(ratioType)) {
|
||||
basePeople = setting == null || setting.getOutProvinceFixedPeople() == null ? 0 : setting.getOutProvinceFixedPeople();
|
||||
} else {
|
||||
basePeople = totalSignupPeople;
|
||||
}
|
||||
int quotaPeople = oneThirdRatio
|
||||
? basePeople / 3
|
||||
: ratio.multiply(BigDecimal.valueOf(basePeople)).setScale(0, RoundingMode.FLOOR).intValue();
|
||||
int allowPeople = quotaPeople - outProvinceSignupPeople;
|
||||
return new OutProvinceQuota(ratioType, ratio, basePeople, totalSignupPeople, outProvinceSignupPeople, allowPeople);
|
||||
}
|
||||
|
||||
private boolean isOneThirdRatio(BigDecimal ratio) {
|
||||
if (ratio == null) {
|
||||
return false;
|
||||
}
|
||||
return ratio.compareTo(BigDecimal.valueOf(0.33)) >= 0 && ratio.compareTo(BigDecimal.valueOf(0.3333)) <= 0;
|
||||
}
|
||||
|
||||
private String normalizeOutProvinceRatioType(String ratioType) {
|
||||
if ("当年参加人数".equals(ratioType) || StrUtil.isBlank(ratioType)) {
|
||||
return "当年报名人数";
|
||||
}
|
||||
if ("可参加教职工人数".equals(ratioType) || "固定人数".equals(ratioType)) {
|
||||
return ratioType;
|
||||
}
|
||||
return "当年报名人数";
|
||||
int allowPeople = domesticSignupPeople / 2 - outProvinceSignupPeople;
|
||||
return new OutProvinceQuota("当年省内报名人数", domesticSignupPeople,
|
||||
domesticSignupPeople + outProvinceSignupPeople, outProvinceSignupPeople, allowPeople);
|
||||
}
|
||||
|
||||
private String buildOutProvinceQuotaNotice(OutProvinceQuota quota) {
|
||||
String suffix = quota.canApply() ? "您可以报名,或您稍后报名" : "请稍后报名";
|
||||
if ("当年报名人数".equals(quota.ratioType())) {
|
||||
return "当前报名人数是" + quota.totalSignupPeople() + "人,已经报名省外线路人数是"
|
||||
+ quota.outProvinceSignupPeople() + "人,按照省外人数不超过" + quota.ratioText()
|
||||
+ "的规则,当前时间允许报名人数是" + quota.allowPeople() + "人," + suffix;
|
||||
}
|
||||
if ("可参加教职工人数".equals(quota.ratioType())) {
|
||||
return "今年有权限报名人数是" + quota.basePeople() + "人,已经报名省外线路人数是"
|
||||
+ quota.outProvinceSignupPeople() + "人,按照省外人数不超过" + quota.ratioText()
|
||||
+ "的规则,当前时间允许报名人数是" + quota.allowPeople() + "人," + suffix;
|
||||
}
|
||||
return "按照省外人数不超过" + quota.ratioText()
|
||||
return "当前报省内线路教职工有效人数是" + quota.basePeople() + "人,已经报名省外线路教职工有效人数是"
|
||||
+ quota.outProvinceSignupPeople() + "人,按照省外人数不超过出行人数的1/3规则"
|
||||
+ "的规则,当前时间允许报名人数是" + quota.allowPeople() + "人," + suffix;
|
||||
}
|
||||
|
||||
private int countYearSignupPeople(int year, String excludeLedgerId) {
|
||||
private int countYearDomesticSignupPeople(int year, String excludeLedgerId) {
|
||||
String excludeSql = StrUtil.isBlank(excludeLedgerId) ? "" : " AND t.id <> @excludeLedgerId";
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT COUNT(1)
|
||||
SELECT COUNT(DISTINCT t.id)
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = t.id
|
||||
WHERE t.delFlag = 0
|
||||
AND t.`year` = @year
|
||||
AND (ins.id IS NULL OR ins.state = @finishedState)
|
||||
AND t.lineType IN ('省内线路', '省内', '国内线路', '国内')
|
||||
AND (ins.id IS NULL OR ins.state <> @abandonState)
|
||||
""" + excludeSql);
|
||||
sql.setParam("year", year);
|
||||
sql.setParam("finishedState", ProcessInstanceStateEnum.FINISHED.getCode());
|
||||
sql.setParam("abandonState", ProcessInstanceStateEnum.ABANDON.getCode());
|
||||
if (StrUtil.isNotBlank(excludeLedgerId)) {
|
||||
sql.setParam("excludeLedgerId", excludeLedgerId);
|
||||
}
|
||||
@@ -1150,16 +1224,16 @@ public class TourSignupController {
|
||||
private int countYearOutProvinceSignupPeople(int year, String excludeLedgerId) {
|
||||
String excludeSql = StrUtil.isBlank(excludeLedgerId) ? "" : " AND t.id <> @excludeLedgerId";
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT COUNT(1)
|
||||
SELECT COUNT(DISTINCT t.id)
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = t.id
|
||||
WHERE t.delFlag = 0
|
||||
AND t.`year` = @year
|
||||
AND t.lineType IN ('省外线路', '省外')
|
||||
AND (ins.id IS NULL OR ins.state = @finishedState)
|
||||
AND (ins.id IS NULL OR ins.state <> @abandonState)
|
||||
""" + excludeSql);
|
||||
sql.setParam("year", year);
|
||||
sql.setParam("finishedState", ProcessInstanceStateEnum.FINISHED.getCode());
|
||||
sql.setParam("abandonState", ProcessInstanceStateEnum.ABANDON.getCode());
|
||||
if (StrUtil.isNotBlank(excludeLedgerId)) {
|
||||
sql.setParam("excludeLedgerId", excludeLedgerId);
|
||||
}
|
||||
@@ -1267,7 +1341,6 @@ public class TourSignupController {
|
||||
}
|
||||
|
||||
private record OutProvinceQuota(String ratioType,
|
||||
BigDecimal ratio,
|
||||
int basePeople,
|
||||
int totalSignupPeople,
|
||||
int outProvinceSignupPeople,
|
||||
@@ -1277,14 +1350,7 @@ public class TourSignupController {
|
||||
}
|
||||
|
||||
String ratioText() {
|
||||
if (ratio == null || BigDecimal.ZERO.compareTo(ratio) == 0) {
|
||||
return "0";
|
||||
}
|
||||
BigDecimal oneThird = BigDecimal.ONE.divide(BigDecimal.valueOf(3), 8, RoundingMode.HALF_UP);
|
||||
if (ratio.subtract(oneThird).abs().compareTo(BigDecimal.valueOf(0.01)) <= 0) {
|
||||
return "1/3";
|
||||
}
|
||||
return ratio.stripTrailingZeros().toPlainString();
|
||||
return "floor(省内有效人数/2)-省外有效人数";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1457,6 +1523,19 @@ public class TourSignupController {
|
||||
return user == null ? SecurityUtil.getUserLoginname() : defaultIfBlank(user.getLoginname(), SecurityUtil.getUserLoginname());
|
||||
}
|
||||
|
||||
private String getSignupOrderColumn(String orderName) {
|
||||
if ("jobNo".equals(orderName)) {
|
||||
return "t.jobNo";
|
||||
}
|
||||
if ("userName".equals(orderName)) {
|
||||
return "t.userName";
|
||||
}
|
||||
if ("unionName".equals(orderName)) {
|
||||
return "t.unionName";
|
||||
}
|
||||
return "t.signupTime";
|
||||
}
|
||||
|
||||
private String getOrderColumn(String orderName) {
|
||||
if ("lineName".equals(orderName)) {
|
||||
return "l.lineName";
|
||||
|
||||
+6
-2
@@ -23,6 +23,7 @@ public class TourTravelAgencyController {
|
||||
|
||||
private static final String MOBILE_PATTERN = "^1[3-9]\\d{9}$";
|
||||
private static final String EMAIL_PATTERN = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$";
|
||||
private static final String SORT_CODE_PATTERN = "^\\d+$";
|
||||
|
||||
@Inject
|
||||
private TourTravelAgencyService travelAgencyService;
|
||||
@@ -77,7 +78,7 @@ public class TourTravelAgencyController {
|
||||
sameCodeCnd.and(TourTravelAgency::getId, "<>", agency.getId());
|
||||
}
|
||||
if (travelAgencyService.count(sameCodeCnd) > 0) {
|
||||
return Result.error("同年度下旅行社编号已存在");
|
||||
return Result.error("同年度下排序编号已存在");
|
||||
}
|
||||
if (agency.getEnabled() == null) {
|
||||
agency.setEnabled(true);
|
||||
@@ -113,7 +114,10 @@ public class TourTravelAgencyController {
|
||||
return Result.error("旅行社名称不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(agency.getAgencyCode())) {
|
||||
return Result.error("旅行社编号不能为空");
|
||||
return Result.error("排序编号不能为空");
|
||||
}
|
||||
if (!agency.getAgencyCode().matches(SORT_CODE_PATTERN)) {
|
||||
return Result.error("排序编号必须为整数");
|
||||
}
|
||||
if (StrUtil.isBlank(agency.getContactName())) {
|
||||
return Result.error("联系人不能为空");
|
||||
|
||||
+530
@@ -0,0 +1,530 @@
|
||||
package com.budwk.app.zhgh.dayofficework.tour.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.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;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@IocBean
|
||||
@Ok("json:full")
|
||||
@At("/platform/tour/undertake")
|
||||
public class TourUndertakeController {
|
||||
|
||||
@Inject
|
||||
private TourMatterService tourMatterService;
|
||||
|
||||
@Inject
|
||||
private TourLedgerService tourLedgerService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/Tour/undertake/index.html")
|
||||
@SaCheckPermission("tour.undertake")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.undertake")
|
||||
public Result pageData(PageForm pageForm, Integer year, String lineName, String lineType, String unionId, String undertakeStatus) {
|
||||
if (StrUtil.isBlank(pageForm.getPageOrderName())) {
|
||||
pageForm.defaultSortAsc("lineName");
|
||||
}
|
||||
Cnd cnd = buildQueryCnd(year, lineName, lineType, unionId, undertakeStatus);
|
||||
boolean sysAdmin = AuthUtil.hasRole(RoleConstant.SYSADMIN.name());
|
||||
boolean showCurrentUnionSignupCount = !AuthUtil.hasRole(RoleConstant.SYSADMIN.name())
|
||||
&& StrUtil.isNotBlank(SecurityUtil.getUnionId());
|
||||
String currentUnionId = showCurrentUnionSignupCount ? SecurityUtil.getUnionId() : "";
|
||||
|
||||
Sql countSql = Sqls.create("""
|
||||
SELECT COUNT(1)
|
||||
FROM tour_matter m
|
||||
INNER JOIN tour_line l ON l.id = m.lineId
|
||||
LEFT JOIN sys_union u ON u.id = m.unionId
|
||||
$condition
|
||||
""");
|
||||
countSql.setCondition(cnd);
|
||||
countSql.setCallback(Sqls.callback.integer());
|
||||
tourMatterService.dao().execute(countSql);
|
||||
int count = countSql.getInt();
|
||||
|
||||
Sql listSql = Sqls.create("""
|
||||
SELECT
|
||||
m.id AS matterId,
|
||||
m.`year`,
|
||||
m.matterName,
|
||||
m.unionId,
|
||||
CASE
|
||||
WHEN IFNULL(NULLIF(m.undertakeStatus, ''), 'unclaimed') = 'claimed' THEN COALESCE(u.name, '校工会')
|
||||
ELSE ''
|
||||
END AS unionName,
|
||||
IFNULL(NULLIF(m.undertakeStatus, ''), 'unclaimed') AS undertakeStatus,
|
||||
CASE
|
||||
WHEN IFNULL(NULLIF(m.undertakeStatus, ''), 'unclaimed') = 'claimed' THEN '已领'
|
||||
ELSE '未领'
|
||||
END AS undertakeStatusName,
|
||||
m.lineId,
|
||||
l.lineName,
|
||||
l.lineType,
|
||||
l.directFamilyUnitLine,
|
||||
m.travelStartTime,
|
||||
m.travelEndTime,
|
||||
CASE
|
||||
WHEN IFNULL(m.travelStartTime, '') <> '' AND IFNULL(m.travelEndTime, '') <> ''
|
||||
THEN CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime)
|
||||
ELSE ''
|
||||
END AS travelPeriod,
|
||||
m.minGroupPeople,
|
||||
m.maxGroupPeople,
|
||||
IFNULL(sc.signupCount, 0) AS signupCount,
|
||||
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
|
||||
FROM tour_matter m
|
||||
INNER JOIN tour_line l ON l.id = m.lineId
|
||||
LEFT JOIN sys_union u ON u.id = m.unionId
|
||||
LEFT JOIN (
|
||||
SELECT t.matterId, SUM(1 + IFNULL(f.familyCount, 0)) AS signupCount
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN (
|
||||
SELECT ledgerId, COUNT(1) AS familyCount
|
||||
FROM tour_ledger_family
|
||||
WHERE delFlag = 0
|
||||
GROUP BY ledgerId
|
||||
) f ON f.ledgerId = t.id
|
||||
WHERE t.delFlag = 0
|
||||
AND t.matterId IS NOT NULL
|
||||
AND t.matterId <> ''
|
||||
GROUP BY t.matterId
|
||||
) sc ON sc.matterId = m.id
|
||||
LEFT JOIN (
|
||||
SELECT t.matterId, SUM(1 + IFNULL(f.familyCount, 0)) AS currentUnionSignupCount
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN (
|
||||
SELECT ledgerId, COUNT(1) AS familyCount
|
||||
FROM tour_ledger_family
|
||||
WHERE delFlag = 0
|
||||
GROUP BY ledgerId
|
||||
) f ON f.ledgerId = t.id
|
||||
WHERE t.delFlag = 0
|
||||
AND t.matterId IS NOT NULL
|
||||
AND t.matterId <> ''
|
||||
AND t.unionId = @currentUnionId
|
||||
GROUP BY t.matterId
|
||||
) usc ON usc.matterId = m.id
|
||||
$condition
|
||||
ORDER BY $orderColumn $orderBy, m.`year` DESC, m.travelStartTime ASC, l.lineName ASC, m.createdAt DESC
|
||||
""");
|
||||
listSql.setCondition(cnd);
|
||||
listSql.setParam("currentUnionId", currentUnionId);
|
||||
listSql.setVar("orderColumn", getOrderColumn(pageForm.getPageOrderName()));
|
||||
listSql.setVar("orderBy", "descending".equals(pageForm.getPageOrderBy()) ? "desc" : "asc");
|
||||
listSql.setPager(tourMatterService.dao().createPager(pageForm.getPageNumber(), pageForm.getPageSize()));
|
||||
listSql.setCallback(Sqls.callback.maps());
|
||||
tourMatterService.dao().execute(listSql);
|
||||
|
||||
List<NutMap> list = listSql.getList(NutMap.class);
|
||||
for (NutMap item : list) {
|
||||
item.put("showCurrentUnionSignupCount", showCurrentUnionSignupCount);
|
||||
item.put("canRelease", sysAdmin && "claimed".equals(item.getString("undertakeStatus", "")));
|
||||
}
|
||||
Pagination<NutMap> pagination = new Pagination<>(pageForm.getPageNumber(), pageForm.getPageSize(), count, list);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.undertake")
|
||||
public Result unionOptions() {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.asc("unionCode");
|
||||
cnd.asc("name");
|
||||
return Result.success(tourMatterService.dao().query(Sys_union.class, cnd));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.undertake")
|
||||
public Result currentUnion() {
|
||||
NutMap unionInfo = currentUnionInfo();
|
||||
if (unionInfo.isEmpty()) {
|
||||
return Result.error("未获取到当前登录人工会");
|
||||
}
|
||||
return Result.success(unionInfo);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.undertake")
|
||||
public Result undertakeLine(String matterId) {
|
||||
if (StrUtil.isBlank(matterId)) {
|
||||
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);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.undertake")
|
||||
public Result releaseUndertakeLine(String matterId) {
|
||||
if (!AuthUtil.hasRole(RoleConstant.SYSADMIN.name())) {
|
||||
return Result.error("仅系统管理员可以解除领办");
|
||||
}
|
||||
if (StrUtil.isBlank(matterId)) {
|
||||
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();
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.undertake")
|
||||
public Result lineTypeOptions(Integer year) {
|
||||
Cnd cnd = buildQueryCnd(year, null, null, null, null);
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT DISTINCT l.lineType
|
||||
FROM tour_matter m
|
||||
INNER JOIN tour_line l ON l.id = m.lineId
|
||||
LEFT JOIN sys_union u ON u.id = m.unionId
|
||||
$condition
|
||||
ORDER BY l.lineType ASC
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourMatterService.dao().execute(sql);
|
||||
return Result.success(sql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
private NutMap currentUnionInfo() {
|
||||
String unionId = SecurityUtil.getUnionId();
|
||||
if (StrUtil.isBlank(unionId)) {
|
||||
return NutMap.NEW();
|
||||
}
|
||||
Sys_union union = tourMatterService.dao().fetch(Sys_union.class, unionId);
|
||||
if (union == null) {
|
||||
return NutMap.NEW();
|
||||
}
|
||||
return NutMap.NEW()
|
||||
.addv("unionId", union.getId())
|
||||
.addv("unionName", union.getName());
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tour.undertake")
|
||||
public Result signupPageData(PageForm pageForm, String matterId, String keyword, String unionId) {
|
||||
if (StrUtil.isBlank(matterId)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
if (StrUtil.isBlank(pageForm.getPageOrderName())) {
|
||||
pageForm.defaultSortDesc("signupTime");
|
||||
}
|
||||
Cnd cnd = buildSignupQueryCnd(matterId, keyword, unionId);
|
||||
Sql countSql = Sqls.create("""
|
||||
SELECT COUNT(1)
|
||||
FROM tour_ledger t
|
||||
INNER JOIN tour_matter m ON m.id = t.matterId
|
||||
INNER JOIN tour_line l ON l.id = m.lineId
|
||||
$condition
|
||||
""");
|
||||
countSql.setCondition(cnd);
|
||||
countSql.setCallback(Sqls.callback.integer());
|
||||
tourLedgerService.dao().execute(countSql);
|
||||
int count = countSql.getInt();
|
||||
|
||||
Sql listSql = Sqls.create("""
|
||||
SELECT
|
||||
t.id,
|
||||
t.jobNo,
|
||||
t.userName,
|
||||
'' AS mobile,
|
||||
t.idCard,
|
||||
t.unionId,
|
||||
t.unionName,
|
||||
t.signupTime
|
||||
FROM tour_ledger t
|
||||
INNER JOIN tour_matter m ON m.id = t.matterId
|
||||
INNER JOIN tour_line l ON l.id = m.lineId
|
||||
$condition
|
||||
ORDER BY $orderColumn $orderBy, t.signupTime DESC, t.createdAt DESC
|
||||
""");
|
||||
listSql.setCondition(cnd);
|
||||
listSql.setVar("orderColumn", getSignupOrderColumn(pageForm.getPageOrderName()));
|
||||
listSql.setVar("orderBy", "ascending".equals(pageForm.getPageOrderBy()) ? "asc" : "desc");
|
||||
listSql.setPager(tourLedgerService.dao().createPager(pageForm.getPageNumber(), pageForm.getPageSize()));
|
||||
listSql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(listSql);
|
||||
|
||||
List<NutMap> list = listSql.getList(NutMap.class);
|
||||
fillSignupMobile(list);
|
||||
fillSignupFamilies(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) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("t.delFlag", "=", false);
|
||||
cnd.and("t.matterId", "=", matterId);
|
||||
cnd.and("m.delFlag", "=", false);
|
||||
cnd.and("m.enabled", "=", true);
|
||||
cnd.and("m.lineId", "IS NOT", null);
|
||||
cnd.and("m.lineId", "<>", "");
|
||||
cnd.and("l.delFlag", "=", false);
|
||||
cnd.and("l.enabled", "=", true);
|
||||
if (StrUtil.isNotBlank(keyword)) {
|
||||
SqlExpressionGroup keywordGroup = new SqlExpressionGroup();
|
||||
keywordGroup.orLike("t.userName", keyword.trim());
|
||||
keywordGroup.orLike("t.jobNo", keyword.trim());
|
||||
cnd.and(keywordGroup);
|
||||
}
|
||||
cnd.andEX("t.unionId", "=", unionId);
|
||||
applyMatterDataScope(cnd);
|
||||
return cnd;
|
||||
}
|
||||
|
||||
private void fillSignupMobile(List<NutMap> list) {
|
||||
if (list == null || list.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<String> jobNos = new ArrayList<>();
|
||||
for (NutMap item : list) {
|
||||
String jobNo = item.getString("jobNo", "");
|
||||
if (StrUtil.isNotBlank(jobNo) && !jobNos.contains(jobNo)) {
|
||||
jobNos.add(jobNo);
|
||||
}
|
||||
}
|
||||
if (jobNos.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Sql sql = Sqls.create("SELECT loginname, mobile FROM vw_user WHERE loginname IN (@jobNos)");
|
||||
sql.setParam("jobNos", jobNos.toArray(new String[0]));
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
|
||||
Map<String, String> mobileMap = new HashMap<>();
|
||||
for (NutMap user : sql.getList(NutMap.class)) {
|
||||
mobileMap.put(user.getString("loginname", ""), user.getString("mobile", ""));
|
||||
}
|
||||
for (NutMap item : list) {
|
||||
item.put("mobile", mobileMap.getOrDefault(item.getString("jobNo", ""), ""));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看成团报名人员时按台账ID带出家属子列表,避免前端逐行请求家属信息。
|
||||
*/
|
||||
private void fillSignupFamilies(List<NutMap> list) {
|
||||
if (list == null || list.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<String> ledgerIds = new ArrayList<>();
|
||||
for (NutMap item : list) {
|
||||
String ledgerId = item.getString("id", "");
|
||||
if (StrUtil.isNotBlank(ledgerId) && !ledgerIds.contains(ledgerId)) {
|
||||
ledgerIds.add(ledgerId);
|
||||
}
|
||||
}
|
||||
if (ledgerIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
ledgerId,
|
||||
staffJobNo AS jobNo,
|
||||
familyName AS userName,
|
||||
'' AS mobile,
|
||||
idCard,
|
||||
relationship
|
||||
FROM tour_ledger_family
|
||||
WHERE delFlag = 0
|
||||
AND ledgerId IN (@ledgerIds)
|
||||
ORDER BY createdAt ASC
|
||||
""");
|
||||
sql.setParam("ledgerIds", ledgerIds.toArray(new String[0]));
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
tourLedgerService.dao().execute(sql);
|
||||
|
||||
Map<String, List<NutMap>> familyMap = new HashMap<>();
|
||||
for (NutMap family : sql.getList(NutMap.class)) {
|
||||
familyMap.computeIfAbsent(family.getString("ledgerId", ""), key -> new ArrayList<>()).add(family);
|
||||
}
|
||||
for (NutMap item : list) {
|
||||
item.put("families", familyMap.getOrDefault(item.getString("id", ""), List.of()));
|
||||
}
|
||||
}
|
||||
|
||||
private Cnd buildQueryCnd(Integer year, String lineName, String lineType, String unionId, String undertakeStatus) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("m.delFlag", "=", false);
|
||||
cnd.and("m.enabled", "=", true);
|
||||
cnd.and("m.lineId", "IS NOT", null);
|
||||
cnd.and("m.lineId", "<>", "");
|
||||
cnd.and("l.delFlag", "=", false);
|
||||
cnd.and("l.enabled", "=", true);
|
||||
cnd.andEX("m.`year`", "=", year == null ? LocalDate.now().getYear() : year);
|
||||
cnd.and(Cnd.likeEX("l.lineName", lineName));
|
||||
cnd.andEX("l.lineType", "=", lineType);
|
||||
cnd.andEX("m.unionId", "=", unionId);
|
||||
if ("claimed".equals(undertakeStatus)) {
|
||||
cnd.and("m.undertakeStatus", "=", "claimed");
|
||||
} else if ("unclaimed".equals(undertakeStatus)) {
|
||||
SqlExpressionGroup statusGroup = new SqlExpressionGroup();
|
||||
statusGroup.or("m.undertakeStatus", "=", "unclaimed");
|
||||
statusGroup.or("m.undertakeStatus", "IS", null);
|
||||
statusGroup.or("m.undertakeStatus", "=", "");
|
||||
cnd.and(statusGroup);
|
||||
}
|
||||
applyMatterDataScope(cnd);
|
||||
return cnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* 线路成团按事项归属控制数据范围:校工会查看全部;分工会查看本工会事项;其它角色仅查看自己创建的事项。
|
||||
*/
|
||||
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 String getOrderColumn(String orderName) {
|
||||
if ("lineName".equals(orderName)) {
|
||||
return "l.lineName";
|
||||
}
|
||||
if ("travelPeriod".equals(orderName)) {
|
||||
return "m.travelStartTime";
|
||||
}
|
||||
if ("matterName".equals(orderName)) {
|
||||
return "m.matterName";
|
||||
}
|
||||
if ("unionName".equals(orderName)) {
|
||||
return "u.name";
|
||||
}
|
||||
if ("undertakeStatusName".equals(orderName)) {
|
||||
return "undertakeStatus";
|
||||
}
|
||||
if ("lineType".equals(orderName)) {
|
||||
return "l.lineType";
|
||||
}
|
||||
if ("signupCount".equals(orderName)) {
|
||||
return "signupCount";
|
||||
}
|
||||
if ("minGroupPeople".equals(orderName)) {
|
||||
return "m.minGroupPeople";
|
||||
}
|
||||
if ("maxGroupPeople".equals(orderName)) {
|
||||
return "m.maxGroupPeople";
|
||||
}
|
||||
if ("groupStatusName".equals(orderName)) {
|
||||
return "groupStatus";
|
||||
}
|
||||
return "l.lineName";
|
||||
}
|
||||
|
||||
private String getSignupOrderColumn(String orderName) {
|
||||
if ("jobNo".equals(orderName)) {
|
||||
return "t.jobNo";
|
||||
}
|
||||
if ("userName".equals(orderName)) {
|
||||
return "t.userName";
|
||||
}
|
||||
if ("idCard".equals(orderName)) {
|
||||
return "t.idCard";
|
||||
}
|
||||
if ("unionName".equals(orderName)) {
|
||||
return "t.unionName";
|
||||
}
|
||||
return "t.signupTime";
|
||||
}
|
||||
}
|
||||
+10
-1
@@ -7,6 +7,7 @@ import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||
import com.budwk.app.sys.views.View_user;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedger;
|
||||
import com.budwk.app.zhgh.dayofficework.tour.models.TourLedgerDirectRelative;
|
||||
@@ -20,6 +21,7 @@ import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Lang;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
@@ -180,7 +182,7 @@ public class TourUnionApprovalController {
|
||||
.and(TourLedgerDirectRelative::getDelFlag, "=", false));
|
||||
NutMap signupConfig = getSignupConfig(ledger);
|
||||
return Result.success(NutMap.NEW()
|
||||
.addv("ledger", ledger)
|
||||
.addv("ledger", buildLedgerView(ledger))
|
||||
.addv("travelPeriod", getTravelPeriod(ledger))
|
||||
.addv("families", tourLedgerFamilyService.query(familyCnd))
|
||||
.addv("directRelative", directRelative)
|
||||
@@ -189,6 +191,13 @@ public class TourUnionApprovalController {
|
||||
.addv("directFamilyUnitLine", signupConfig.getBoolean("directFamilyUnitLine", false)));
|
||||
}
|
||||
|
||||
private NutMap buildLedgerView(TourLedger ledger) {
|
||||
NutMap map = Lang.obj2nutmap(ledger);
|
||||
View_user user = tourLedgerService.dao().fetch(View_user.class, Cnd.where("loginname", "=", ledger.getJobNo()));
|
||||
map.addv("mobile", StrUtil.blankToDefault(ledger.getMobile(), user == null ? "" : StrUtil.blankToDefault(user.getMobile(), "")));
|
||||
return map;
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission(value = {"tour.unionApproval", "h5.tour.unionApproval"}, mode = SaMode.OR)
|
||||
public Result unionOptions(Boolean audit, Integer startYear, Integer endYear, String keyword, String lineId, String travelPeriod, String lineType) {
|
||||
|
||||
@@ -51,6 +51,11 @@ public class TourLedger extends BaseModel implements Serializable {
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
private String idCard;
|
||||
|
||||
@Column
|
||||
@Comment("手机号")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
private String mobile;
|
||||
|
||||
@Column
|
||||
@Comment("所在单位ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
|
||||
@@ -32,7 +32,7 @@ public class TourLine extends BaseModel implements Serializable {
|
||||
private Integer year;
|
||||
|
||||
@Column
|
||||
@Comment("线路编号")
|
||||
@Comment("排序编号")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String lineCode;
|
||||
|
||||
|
||||
@@ -56,6 +56,12 @@ public class TourMatter extends BaseModel implements Serializable {
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String unionId;
|
||||
|
||||
@Column
|
||||
@Comment("领办状态")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
@Default("unclaimed")
|
||||
private String undertakeStatus;
|
||||
|
||||
@Column
|
||||
@Comment("组织形式")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
|
||||
@@ -63,6 +63,16 @@ public class TourSetting extends BaseModel implements Serializable {
|
||||
@ColDefine(type = ColType.INT)
|
||||
private Integer maxGroupPeople;
|
||||
|
||||
@Column
|
||||
@Comment("报名开始时间")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
private String signupStartTime;
|
||||
|
||||
@Column
|
||||
@Comment("报名结束时间")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
private String signupEndTime;
|
||||
|
||||
@Column
|
||||
@Comment("省外几年去一次")
|
||||
@ColDefine(type = ColType.INT)
|
||||
|
||||
@@ -32,7 +32,7 @@ public class TourTravelAgency extends BaseModel implements Serializable {
|
||||
private Integer year;
|
||||
|
||||
@Column
|
||||
@Comment("旅行社编号")
|
||||
@Comment("排序编号")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String agencyCode;
|
||||
|
||||
|
||||
@@ -99,6 +99,12 @@ FROM sys_menu p
|
||||
WHERE p.permission = 'tour'
|
||||
AND NOT EXISTS (SELECT 1 FROM (SELECT id FROM sys_menu WHERE permission = 'tour.group') t);
|
||||
|
||||
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 'b7c63f0c73a44a9a8c4f3d3bb1a10013', p.id, CONCAT(p.path, '0012'), '领办线路', 'Tour Undertake', 'menu', '/platform/tour/undertake', 'data-pjax', '', 1, 0, 'tour.undertake', NULL, 12, 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.undertake') t);
|
||||
|
||||
-- 给系统管理员默认授权,其他角色可在角色管理中按需分配。
|
||||
INSERT INTO sys_role_menu (roleId, menuId)
|
||||
SELECT r.id, m.id
|
||||
@@ -111,6 +117,7 @@ JOIN sys_menu m ON m.permission IN (
|
||||
'tour.matter',
|
||||
'tour.signup',
|
||||
'tour.group',
|
||||
'tour.undertake',
|
||||
'tour.mysignup',
|
||||
'tour.unionledger',
|
||||
'tour.unionApproval',
|
||||
@@ -120,3 +127,14 @@ JOIN sys_menu m ON m.permission IN (
|
||||
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;
|
||||
|
||||
INSERT INTO sys_role_menu (roleId, menuId)
|
||||
SELECT r.id, m.id
|
||||
FROM sys_role r
|
||||
JOIN sys_menu m ON m.permission IN (
|
||||
'tour',
|
||||
'tour.undertake'
|
||||
)
|
||||
LEFT JOIN sys_role_menu rm ON rm.roleId = r.id AND rm.menuId = m.id
|
||||
WHERE r.code = 'BRANCH_UNION_CHAIRMAN'
|
||||
AND rm.roleId IS NULL;
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `tour_ledger`
|
||||
ADD COLUMN `mobile` varchar(30) DEFAULT NULL COMMENT '手机号' AFTER `idCard`;
|
||||
@@ -0,0 +1,6 @@
|
||||
ALTER TABLE `tour_matter`
|
||||
ADD COLUMN `undertakeStatus` varchar(20) DEFAULT 'unclaimed' COMMENT '领办状态 claimed已领 unclaimed未领' AFTER `unionId`;
|
||||
|
||||
UPDATE `tour_matter`
|
||||
SET `undertakeStatus` = 'unclaimed'
|
||||
WHERE `undertakeStatus` IS NULL OR `undertakeStatus` = '';
|
||||
@@ -7,6 +7,7 @@ CREATE TABLE IF NOT EXISTS `tour_matter` (
|
||||
`creatorUserId` varchar(32) DEFAULT NULL COMMENT '创建人ID',
|
||||
`creatorName` varchar(100) DEFAULT NULL COMMENT '创建人',
|
||||
`unionId` varchar(32) DEFAULT NULL COMMENT '所属工会ID',
|
||||
`undertakeStatus` varchar(20) DEFAULT 'unclaimed' COMMENT '领办状态 claimed已领 unclaimed未领',
|
||||
`organizationType` varchar(100) DEFAULT NULL COMMENT '组织形式',
|
||||
`mobileThumb` varchar(500) DEFAULT NULL COMMENT '移动端缩略图',
|
||||
`enabled` tinyint(1) DEFAULT 1 COMMENT '事项状态',
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
-- 疗休养配置增加全局报名时间字段。
|
||||
ALTER TABLE `tour_setting`
|
||||
ADD COLUMN `signupStartTime` varchar(20) DEFAULT NULL COMMENT '报名开始时间' AFTER `maxGroupPeople`,
|
||||
ADD COLUMN `signupEndTime` varchar(20) DEFAULT NULL COMMENT '报名结束时间' AFTER `signupStartTime`;
|
||||
@@ -9,6 +9,8 @@ CREATE TABLE IF NOT EXISTS `tour_setting` (
|
||||
`sortNo` int DEFAULT NULL COMMENT '排序编号',
|
||||
`minGroupPeople` int DEFAULT NULL COMMENT '最少成团人数',
|
||||
`maxGroupPeople` int DEFAULT NULL COMMENT '最多成团人数',
|
||||
`signupStartTime` varchar(20) DEFAULT NULL COMMENT '报名开始时间',
|
||||
`signupEndTime` varchar(20) DEFAULT NULL COMMENT '报名结束时间',
|
||||
`outProvinceYears` int DEFAULT NULL COMMENT '省外几年去一次',
|
||||
`outProvinceRatio` decimal(10,2) DEFAULT NULL COMMENT '省外人数占比',
|
||||
`outProvinceRatioType` varchar(50) DEFAULT '当年报名人数' COMMENT '省外人数占比类型',
|
||||
@@ -116,6 +118,7 @@ CREATE TABLE IF NOT EXISTS `tour_matter` (
|
||||
`creatorUserId` varchar(32) DEFAULT NULL COMMENT '创建人ID',
|
||||
`creatorName` varchar(100) DEFAULT NULL COMMENT '创建人',
|
||||
`unionId` varchar(32) DEFAULT NULL COMMENT '所属工会ID',
|
||||
`undertakeStatus` varchar(20) DEFAULT 'unclaimed' COMMENT '领办状态 claimed已领 unclaimed未领',
|
||||
`organizationType` varchar(100) DEFAULT NULL COMMENT '组织形式',
|
||||
`mobileThumb` varchar(500) DEFAULT NULL COMMENT '移动端缩略图',
|
||||
`enabled` tinyint(1) DEFAULT 1 COMMENT '事项状态',
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
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 'b7c63f0c73a44a9a8c4f3d3bb1a10013', p.id, CONCAT(p.path, '0012'), '领办线路', 'Tour Undertake', 'menu', '/platform/tour/undertake', 'data-pjax', '', 1, 0, 'tour.undertake', NULL, 12, 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.undertake') t);
|
||||
|
||||
INSERT INTO sys_role_menu (roleId, menuId)
|
||||
SELECT r.id, m.id
|
||||
FROM sys_role r
|
||||
JOIN sys_menu m ON m.permission IN (
|
||||
'tour',
|
||||
'tour.undertake'
|
||||
)
|
||||
LEFT JOIN sys_role_menu rm ON rm.roleId = r.id AND rm.menuId = m.id
|
||||
WHERE r.code IN ('SYSADMIN', 'BRANCH_UNION_CHAIRMAN')
|
||||
AND rm.roleId IS NULL;
|
||||
@@ -173,8 +173,8 @@ layout("/layouts/platform.html"){
|
||||
<el-descriptions-item label="报名时间">{{ detail.signupTime || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="报名线路">{{ detail.lineName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="线路类型">{{ detail.lineType || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="报名酒店">{{ detail.hotelName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="报名旅行社">{{ detail.travelAgencyName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item v-if="false" label="报名酒店">{{ detail.hotelName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item v-if="false" label="报名旅行社">{{ detail.travelAgencyName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="出行时间">{{ detail.travelPeriod || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item v-if="fillBedInfo" label="床型">{{ detail.bedType || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item v-if="fillBedInfo" label="床位信息">{{ detail.bedInfo || '' }}</el-descriptions-item>
|
||||
|
||||
@@ -58,13 +58,13 @@ layout("/layouts/platform.html"){
|
||||
@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="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="lineName" min-width="220" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="组织形式" prop="organizationTypeName" width="150" sortable="custom" align="center" header-align="center" show-overflow-tooltip></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 label="线路名称" prop="lineName" min-width="260" sortable="custom" align="center" header-align="center" show-overflow-tooltip></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>
|
||||
<el-table-column label="事项状态" prop="enabled" width="160" align="center" header-align="center">
|
||||
<el-table-column label="事项状态" prop="enabled" width="140" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
<el-switch
|
||||
v-model="row.enabled"
|
||||
@@ -74,7 +74,7 @@ layout("/layouts/platform.html"){
|
||||
</el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="260" align="center" header-align="center">
|
||||
<el-table-column label="操作" width="260" fixed="right" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
<el-button size="mini" type="primary" @click="openBatchForm(row)">选择线路</el-button>
|
||||
<el-button size="mini" type="primary" @click="openEdit(row)">编辑</el-button>
|
||||
@@ -116,7 +116,7 @@ layout("/layouts/platform.html"){
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="事项名称" prop="matterName">
|
||||
<el-input v-model="formData.matterName" maxlength="30" show-word-limit placeholder="请输入事项名称"></el-input>
|
||||
<el-input v-model="formData.matterName" maxlength="30" show-word-limit placeholder="如恩施大峡谷五日第一批次"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建人">
|
||||
<el-input v-model="formData.creatorName" readonly placeholder="当前登录人"></el-input>
|
||||
@@ -504,12 +504,10 @@ layout("/layouts/platform.html"){
|
||||
this.batchForm.travelStartTime = this.dateOnly(this.batchForm.travelStartTime)
|
||||
this.batchForm.travelEndTime = this.dateOnly(this.batchForm.travelEndTime)
|
||||
this.applySelectedLineDefaults(false)
|
||||
if (!this.batchForm.minGroupPeople || !this.batchForm.maxGroupPeople) {
|
||||
this.loadSettingPeople((data) => {
|
||||
this.batchForm.minGroupPeople = data.minGroupPeople || null
|
||||
this.batchForm.maxGroupPeople = data.maxGroupPeople || null
|
||||
})
|
||||
}
|
||||
this.loadSettingDefaults((data) => {
|
||||
this.applySettingPeople(data)
|
||||
this.applySettingSignupTime(data)
|
||||
})
|
||||
this.batchFormVisible = true
|
||||
this.$nextTick(() => {
|
||||
this.applySelectedLineDefaults(true)
|
||||
@@ -589,8 +587,39 @@ layout("/layouts/platform.html"){
|
||||
if (!value) return ""
|
||||
return String(value).substring(0, 10)
|
||||
},
|
||||
loadSettingPeople(callback) {
|
||||
this.$axios.post(loc() + "/settingPeople", { matterId: this.currentMatter.id }).then((res) => {
|
||||
applySettingSignupTime(data) {
|
||||
if (!data) return
|
||||
if (data.signupStartTime) {
|
||||
this.$set(this.batchForm, "signupStartTime", data.signupStartTime)
|
||||
}
|
||||
if (data.signupEndTime) {
|
||||
this.$set(this.batchForm, "signupEndTime", data.signupEndTime)
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.batchFormRef) {
|
||||
this.$refs.batchFormRef.validateField(["signupStartTime", "signupEndTime"])
|
||||
}
|
||||
})
|
||||
},
|
||||
applySettingPeople(data) {
|
||||
if (!data) return
|
||||
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 !== "") {
|
||||
this.$set(this.batchForm, "maxGroupPeople", data.maxGroupPeople)
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.batchFormRef) {
|
||||
this.$refs.batchFormRef.validateField(["minGroupPeople", "maxGroupPeople"])
|
||||
}
|
||||
})
|
||||
},
|
||||
loadSettingDefaults(callback) {
|
||||
this.$axios.post(loc() + "/settingPeople", {
|
||||
matterId: this.currentMatter.id,
|
||||
year: this.currentMatter.year
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
const data = res.data || {}
|
||||
callback && callback(data)
|
||||
|
||||
@@ -50,7 +50,8 @@ layout("/layouts/platform.html"){
|
||||
<el-table-column v-if="false" label="所在单位" prop="unitName" min-width="180" 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="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="matterUnionName" min-width="180" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column v-if="false" label="线路类型" prop="lineType" width="130" sortable="custom" 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}">
|
||||
@@ -79,7 +80,7 @@ layout("/layouts/platform.html"){
|
||||
<el-button v-if="canModify(row) || isTravelEnded(row)" size="mini" type="primary" :disabled="isTravelEnded(row)" @click="openSignup(row)">修改</el-button>
|
||||
<el-button v-if="canRevoke(row)" size="mini" type="danger" @click="revokeSignup(row)">撤回</el-button>
|
||||
<el-button v-if="showExport(row)" size="mini" type="primary" :disabled="!canExport(row)" @click="exportSignup(row)">报销申请</el-button>
|
||||
<el-button v-if="showDirectRelativeExport(row)" size="mini" type="primary" :disabled="!canDirectRelativeExport(row)" @click="exportDirectRelative(row)">亲属线路申请</el-button>
|
||||
<el-button v-if="showDirectRelativeExport(row)" size="mini" type="primary" :disabled="!canDirectRelativeExport(row)" @click="exportDirectRelative(row)">下载亲属线路申请</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -113,8 +114,8 @@ layout("/layouts/platform.html"){
|
||||
<el-descriptions-item label="报名时间">{{ detail.signupTime || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="报名线路">{{ detail.lineName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="线路类型">{{ detail.lineType || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="报名酒店">{{ detail.hotelName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="报名旅行社">{{ detail.travelAgencyName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item v-if="false" label="报名酒店">{{ detail.hotelName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item v-if="false" label="报名旅行社">{{ detail.travelAgencyName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="出行时间">{{ detail.travelPeriod || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item v-if="detailFillBedInfo" label="床型">{{ detail.bedType || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item v-if="detailFillBedInfo" label="床位信息">{{ detail.bedInfo || '' }}</el-descriptions-item>
|
||||
@@ -249,12 +250,12 @@ layout("/layouts/platform.html"){
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-col v-if="false" :span="8">
|
||||
<el-form-item label="报名酒店">
|
||||
<el-input v-model="signupForm.hotelName" :disabled="isDirectFamilyLine(signupForm)" maxlength="100" placeholder="请输入报名酒店"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-col v-if="false" :span="8">
|
||||
<el-form-item label="报名旅行社">
|
||||
<el-input v-model="signupForm.travelAgencyName" :disabled="isDirectFamilyLine(signupForm)" readonly></el-input>
|
||||
</el-form-item>
|
||||
@@ -469,7 +470,7 @@ layout("/layouts/platform.html"){
|
||||
<div class="tour-export-date">时间:<span class="tour-export-sign-date">{{ formatDate(exportForm.unionAuditDate) }}</span></div>
|
||||
</div>
|
||||
<div class="tour-export-sign school">
|
||||
<div>学校工会:盖章</div>
|
||||
<div>学校工会:盖章<span class="tour-export-sign-value">{{ exportForm.schoolUnionAuditorName }}</span></div>
|
||||
<div class="tour-export-date">时间:<span class="tour-export-sign-date">{{ formatDate(exportForm.schoolUnionAuditDate) }}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -491,7 +492,7 @@ layout("/layouts/platform.html"){
|
||||
<div class="tour-export-date">时间:<span class="tour-export-sign-date">{{ formatDate(directRelativeExportForm.unionAuditDate) }}</span></div>
|
||||
</div>
|
||||
<div class="tour-export-sign tour-export-direct-sign">
|
||||
<div>学校工会:盖章</div>
|
||||
<div>学校工会:盖章<span class="tour-export-sign-value">{{ directRelativeExportForm.schoolUnionAuditorName }}</span></div>
|
||||
<div class="tour-export-date">时间:<span class="tour-export-sign-date">{{ formatDate(directRelativeExportForm.schoolUnionAuditDate) }}</span></div>
|
||||
</div>
|
||||
<div class="tour-export-sign tour-export-direct-sign">
|
||||
@@ -772,6 +773,7 @@ layout("/layouts/platform.html"){
|
||||
applyDate: "",
|
||||
unionAuditorName: "",
|
||||
unionAuditDate: "",
|
||||
schoolUnionAuditorName: "",
|
||||
schoolUnionAuditDate: ""
|
||||
},
|
||||
directRelativeExportForm: {
|
||||
@@ -790,6 +792,7 @@ layout("/layouts/platform.html"){
|
||||
applyDate: "",
|
||||
unionAuditorName: "",
|
||||
unionAuditDate: "",
|
||||
schoolUnionAuditorName: "",
|
||||
schoolUnionAuditDate: "",
|
||||
relativeUnitAuditDate: ""
|
||||
},
|
||||
|
||||
@@ -49,16 +49,16 @@ layout("/layouts/platform.html"){
|
||||
:data="tableData"
|
||||
:size="tableSize"
|
||||
border
|
||||
:default-sort="{prop: 'enabled', order: 'descending'}"
|
||||
: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="120" sortable="custom" align="center" header-align="center"></el-table-column>
|
||||
<el-table-column label="线路编号" prop="lineCode" width="140" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="线路名称" prop="lineName" min-width="220" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="时间标段" prop="lotName" width="140" 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="creatorName" width="140" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="排序编号" prop="lineCode" width="140" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="是否对外开放" prop="openFlag" width="160" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
<el-switch
|
||||
@@ -79,9 +79,10 @@ layout("/layouts/platform.html"){
|
||||
</el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="260" align="center" header-align="center">
|
||||
<el-table-column label="操作" width="340" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
<el-button size="mini" type="primary" @click="openView(row)">查看</el-button>
|
||||
<el-button size="mini" type="primary" @click="createMatter(row)">新建事项</el-button>
|
||||
<el-button size="mini" type="primary" @click="openEdit(row)">编辑</el-button>
|
||||
<el-button size="mini" type="danger" @click="doDelete(row)">删除</el-button>
|
||||
</template>
|
||||
@@ -136,8 +137,8 @@ layout("/layouts/platform.html"){
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="线路编号" prop="lineCode">
|
||||
<el-input v-model="formData.lineCode" maxlength="50" placeholder="建议年度加序号,如202601"></el-input>
|
||||
<el-form-item label="排序编号" prop="lineCode">
|
||||
<el-input-number v-model="formData.lineCode" :controls="false" :min="0" :precision="0" placeholder="请输入排序编号" style="width: 100%"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
@@ -206,6 +207,132 @@ layout("/layouts/platform.html"){
|
||||
<el-button v-if="!viewMode" type="primary" :loading="submitLoading" @click="doSubmit">保存</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
title="新建事项"
|
||||
:visible.sync="matterDialogVisible"
|
||||
:close-on-click-modal="false"
|
||||
width="64%">
|
||||
<el-form :model="matterForm" :rules="matterFormRules" label-width="110px" ref="matterFormRef">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="年度" prop="year">
|
||||
<el-date-picker
|
||||
v-model="matterForm.year"
|
||||
type="year"
|
||||
value-format="yyyy"
|
||||
placeholder="请选择年度"
|
||||
style="width: 100%"
|
||||
@change="matterYearChange">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="事项状态" prop="enabled">
|
||||
<el-radio-group v-model="matterForm.enabled">
|
||||
<el-radio :label="true">启用</el-radio>
|
||||
<el-radio :label="false">禁用</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="事项名称" prop="matterName">
|
||||
<el-input v-model="matterForm.matterName" maxlength="30" show-word-limit placeholder="请输入事项名称"></el-input>
|
||||
<div class="tour-matter-name-tip">建议事项名称:{{ matterNameTip() }}</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建人">
|
||||
<el-input v-model="matterForm.creatorName" readonly placeholder="当前登录人"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="疗休养配置" prop="settingId">
|
||||
<el-select v-model="matterForm.settingId" clearable filterable placeholder="请选择配置" style="width: 100%">
|
||||
<el-option v-for="item in matterSettingOptions" :key="item.id" :label="item.configName" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="组织形式" prop="organizationType">
|
||||
<el-select v-model="matterForm.organizationType" clearable filterable placeholder="请选择组织形式" style="width: 100%" @change="matterOrganizationTypeChange">
|
||||
<el-option v-for="item in matterOrganizationTypeOptions" :key="item.code" :label="item.name" :value="item.code"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属工会" prop="unionId">
|
||||
<el-select v-model="matterForm.unionId" clearable filterable placeholder="请选择所属工会" style="width: 100%" :disabled="isMatterUnionDisabled()">
|
||||
<el-option v-for="item in matterUnionOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="matterDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="matterSubDis" @click="submitMatterStep">下一步</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
title="选择线路"
|
||||
:visible.sync="lineConfigDialogVisible"
|
||||
:close-on-click-modal="false"
|
||||
width="74%">
|
||||
<el-form :model="batchForm" :rules="batchRules" label-width="110px" ref="batchFormRef">
|
||||
<el-form-item label="线路" prop="lineId">
|
||||
<el-select v-model="batchForm.lineId" disabled filterable placeholder="请选择线路" style="width: 100%">
|
||||
<el-option v-for="item in matterLineOptions" :key="item.id" :label="matterLineOptionLabel(item)" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="报名开始时间" prop="signupStartTime">
|
||||
<el-date-picker v-model="batchForm.signupStartTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" placeholder="选择时间" style="width: 100%"></el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="报名结束时间" prop="signupEndTime">
|
||||
<el-date-picker v-model="batchForm.signupEndTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" placeholder="选择时间" style="width: 100%"></el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="出行开始时间" prop="travelStartTime">
|
||||
<el-date-picker v-model="batchForm.travelStartTime" type="date" value-format="yyyy-MM-dd" placeholder="选择日期" style="width: 100%" @change="matterTravelStartChange"></el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="出行结束时间" prop="travelEndTime">
|
||||
<el-date-picker v-model="batchForm.travelEndTime" type="date" value-format="yyyy-MM-dd" placeholder="选择日期" style="width: 100%" @change="validateMatterTravelFields"></el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="联系人" prop="contactName">
|
||||
<el-input v-model="batchForm.contactName" maxlength="10" placeholder="请输入联系人"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="联系方式" prop="contactPhone">
|
||||
<el-input v-model="batchForm.contactPhone" maxlength="11" placeholder="请输入联系方式"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="预计费用" prop="estimatedCost">
|
||||
<el-input v-model="batchForm.estimatedCost" maxlength="10" placeholder="请输入预计费用"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="最少成团人数" prop="minGroupPeople">
|
||||
<el-input-number v-model="batchForm.minGroupPeople" :min="1" :precision="0" controls-position="right" style="width: 100%" @change="matterPeopleChange"></el-input-number>
|
||||
</el-form-item>
|
||||
</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-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="backToMatterStep">上一步</el-button>
|
||||
<el-button type="primary" :loading="batchSubDis" @click="submitMatterLineConfig">保存</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
@@ -213,6 +340,13 @@ layout("/layouts/platform.html"){
|
||||
.el-table .direct-family-row > td .cell {
|
||||
color: #f56c6c;
|
||||
}
|
||||
.tour-matter-name-tip {
|
||||
margin-top: 6px;
|
||||
color: #f56c6c;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
user-select: text;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
@@ -222,25 +356,93 @@ layout("/layouts/platform.html"){
|
||||
mixins: [initTableMixins],
|
||||
data() {
|
||||
const currentYear = moment().format("YYYY")
|
||||
const validateMatterUnion = (rule, value, callback) => {
|
||||
if (this.matterForm.organizationType === "schoolUnion" || value) {
|
||||
callback()
|
||||
} else {
|
||||
callback(new Error("必填"))
|
||||
}
|
||||
}
|
||||
const validateMatterMobile = (rule, value, callback) => {
|
||||
const mobileReg = /^1[3-9]\d{9}$/
|
||||
if (!value) {
|
||||
callback(new Error("必填"))
|
||||
} else if (!mobileReg.test(value)) {
|
||||
callback(new Error("手机号码格式不正确"))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
const validateMatterMoney = (rule, value, callback) => {
|
||||
const moneyReg = /^(0|[1-9]\d*)(\.\d{1,2})?$/
|
||||
if (value === "" || value === null || value === undefined) {
|
||||
callback(new Error("必填"))
|
||||
} else if (!moneyReg.test(String(value))) {
|
||||
callback(new Error("请输入非负金额,最多两位小数"))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
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()
|
||||
}
|
||||
}
|
||||
const validateMatterTime = (rule, value, callback) => {
|
||||
if (!value) {
|
||||
callback(new Error("必填"))
|
||||
return
|
||||
}
|
||||
const form = this.batchForm
|
||||
if (form.signupStartTime && form.signupEndTime && form.signupStartTime >= form.signupEndTime) {
|
||||
callback(new Error("报名开始时间必须小于报名结束时间"))
|
||||
return
|
||||
}
|
||||
if (form.travelStartTime && form.travelEndTime && form.travelStartTime > form.travelEndTime) {
|
||||
callback(new Error("出行开始时间不能晚于出行结束时间"))
|
||||
return
|
||||
}
|
||||
if (form.signupEndTime && form.travelStartTime && form.signupEndTime >= form.travelStartTime) {
|
||||
callback(new Error("报名结束时间必须小于出行开始时间"))
|
||||
return
|
||||
}
|
||||
callback()
|
||||
}
|
||||
return {
|
||||
title: "",
|
||||
dialogVisible: false,
|
||||
viewMode: false,
|
||||
submitLoading: false,
|
||||
matterDialogVisible: false,
|
||||
matterSubDis: false,
|
||||
lineConfigDialogVisible: false,
|
||||
batchSubDis: false,
|
||||
selectedMatterLine: {},
|
||||
travelAgencyOptions: [],
|
||||
lotOptions: [],
|
||||
lineTypeOptions: [],
|
||||
matterSettingOptions: [],
|
||||
matterUnionOptions: [],
|
||||
matterOrganizationTypeOptions: [],
|
||||
matterLineOptions: [],
|
||||
pageForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
pageOrderName: "enabled",
|
||||
pageOrderBy: "descending",
|
||||
pageOrderName: "lineCode",
|
||||
pageOrderBy: "ascending",
|
||||
year: currentYear,
|
||||
lineName: "",
|
||||
lotId: ""
|
||||
},
|
||||
formData: {},
|
||||
matterForm: {},
|
||||
batchForm: {},
|
||||
formRules: {
|
||||
year: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
|
||||
travelAgencyId: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
|
||||
@@ -249,6 +451,25 @@ layout("/layouts/platform.html"){
|
||||
lineType: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
|
||||
lotId: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
|
||||
mobileThumb: [{ required: true, message: "请上传移动端缩略图", trigger: ["blur", "change"] }]
|
||||
},
|
||||
matterFormRules: {
|
||||
year: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
|
||||
matterName: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
|
||||
settingId: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
|
||||
unionId: [{ validator: validateMatterUnion, trigger: ["blur", "change"] }],
|
||||
organizationType: [{ required: true, message: "必填", trigger: ["blur", "change"] }]
|
||||
},
|
||||
batchRules: {
|
||||
lineId: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
|
||||
signupStartTime: [{ validator: validateMatterTime, trigger: ["blur", "change"] }],
|
||||
signupEndTime: [{ validator: validateMatterTime, trigger: ["blur", "change"] }],
|
||||
travelStartTime: [{ validator: validateMatterTime, trigger: ["blur", "change"] }],
|
||||
travelEndTime: [{ validator: validateMatterTime, trigger: ["blur", "change"] }],
|
||||
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"] }]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -307,6 +528,291 @@ layout("/layouts/platform.html"){
|
||||
this.viewMode = true
|
||||
this.loadDetail(row.id)
|
||||
},
|
||||
createMatter(row) {
|
||||
if (!row || !row.id) {
|
||||
this.$message.warning("Line info is incomplete")
|
||||
return
|
||||
}
|
||||
this.selectedMatterLine = row
|
||||
this.matterForm = this.emptyMatterForm()
|
||||
this.batchForm = {}
|
||||
this.matterLineOptions = []
|
||||
this.loadMatterUnions()
|
||||
this.loadMatterOrganizationTypes()
|
||||
this.$axios.post(this.matterBasePath() + "/lineInfo", { lineId: row.id }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.selectedMatterLine = Object.assign({}, row, res.data || {})
|
||||
if (this.selectedMatterLine.year) {
|
||||
this.matterForm.year = String(this.selectedMatterLine.year)
|
||||
}
|
||||
this.loadMatterSettings(this.matterForm.year, true)
|
||||
} else {
|
||||
this.$message.warning(res.msg || "线路信息查询失败")
|
||||
this.loadMatterSettings(this.matterForm.year, true)
|
||||
}
|
||||
this.matterDialogVisible = true
|
||||
this.$nextTick(() => this.$refs.matterFormRef && this.$refs.matterFormRef.clearValidate())
|
||||
})
|
||||
},
|
||||
matterBasePath() {
|
||||
return "/platform/tour/matter"
|
||||
},
|
||||
emptyMatterForm() {
|
||||
const user = (this.$store && this.$store.state && this.$store.state.user) || {}
|
||||
return {
|
||||
year: moment().format("YYYY"),
|
||||
matterName: "",
|
||||
settingId: "",
|
||||
creatorUserId: user.id || "",
|
||||
creatorName: user.username || "",
|
||||
unionId: "",
|
||||
organizationType: "",
|
||||
enabled: true
|
||||
}
|
||||
},
|
||||
matterNameTip() {
|
||||
const lineName = this.selectedMatterLine && this.selectedMatterLine.lineName ? this.selectedMatterLine.lineName : "线路名称"
|
||||
return lineName + "第一批次"
|
||||
},
|
||||
emptyMatterBatchForm(matterId) {
|
||||
return {
|
||||
id: matterId || "",
|
||||
lineId: this.selectedMatterLine.id || "",
|
||||
signupStartTime: "",
|
||||
signupEndTime: "",
|
||||
travelStartTime: "",
|
||||
travelEndTime: "",
|
||||
contactName: "",
|
||||
contactPhone: "",
|
||||
minGroupPeople: null,
|
||||
maxGroupPeople: null,
|
||||
estimatedCost: ""
|
||||
}
|
||||
},
|
||||
matterYearChange(year) {
|
||||
this.matterForm.settingId = ""
|
||||
this.loadMatterSettings(year, true)
|
||||
},
|
||||
matterOrganizationTypeChange() {
|
||||
this.applyMatterOrganizationTypeRule()
|
||||
this.$nextTick(() => this.$refs.matterFormRef && this.$refs.matterFormRef.validateField("unionId"))
|
||||
},
|
||||
applyMatterOrganizationTypeRule() {
|
||||
if (this.matterForm.organizationType === "schoolUnion") {
|
||||
this.matterForm.unionId = ""
|
||||
return
|
||||
}
|
||||
if (this.matterForm.organizationType === "branchUnion" || this.matterForm.organizationType === "personal") {
|
||||
const union = this.currentUserUnion()
|
||||
this.matterForm.unionId = union.id || ""
|
||||
this.ensureMatterUnionOption(union)
|
||||
}
|
||||
},
|
||||
currentUserUnion() {
|
||||
const user = (this.$store && this.$store.state && this.$store.state.user) || {}
|
||||
return user.union || {}
|
||||
},
|
||||
ensureMatterUnionOption(union) {
|
||||
if (!union || !union.id) return
|
||||
const exists = this.matterUnionOptions.some(item => item.id === union.id)
|
||||
if (!exists) {
|
||||
this.matterUnionOptions.push({ id: union.id, name: union.name || "" })
|
||||
}
|
||||
},
|
||||
isMatterUnionDisabled() {
|
||||
return ["schoolUnion", "branchUnion", "personal"].includes(this.matterForm.organizationType)
|
||||
},
|
||||
loadMatterSettings(year, autoSelectLatest) {
|
||||
this.$axios.post(this.matterBasePath() + "/settingOptions", { year }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.matterSettingOptions = res.data || []
|
||||
if (autoSelectLatest && !this.matterForm.settingId && this.matterSettingOptions.length > 0) {
|
||||
this.matterForm.settingId = this.matterSettingOptions[0].id
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
loadMatterUnions() {
|
||||
this.$axios.post(this.matterBasePath() + "/unionOptions").then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.matterUnionOptions = res.data || []
|
||||
}
|
||||
})
|
||||
},
|
||||
loadMatterOrganizationTypes() {
|
||||
this.$axios.post(this.matterBasePath() + "/organizationTypeOptions").then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.matterOrganizationTypeOptions = res.data || []
|
||||
}
|
||||
})
|
||||
},
|
||||
submitMatterStep() {
|
||||
this.$refs.matterFormRef.validate((valid) => {
|
||||
if (!valid) return
|
||||
this.matterSubDis = true
|
||||
this.$axios.post(this.matterBasePath() + "/doSubmit", this.matterForm).then((res) => {
|
||||
this.matterSubDis = false
|
||||
if (res.code === 0) {
|
||||
const data = res.data || {}
|
||||
const matterId = data.id || this.matterForm.id || ""
|
||||
this.matterForm.id = matterId
|
||||
this.matterDialogVisible = false
|
||||
this.openMatterLineConfig(matterId)
|
||||
} else {
|
||||
this.$message.warning(res.msg || "保存失败")
|
||||
}
|
||||
}).catch(() => {
|
||||
this.matterSubDis = false
|
||||
})
|
||||
})
|
||||
},
|
||||
openMatterLineConfig(matterId) {
|
||||
this.batchForm = this.emptyMatterBatchForm(matterId)
|
||||
this.matterLineOptions = [this.selectedMatterLine]
|
||||
this.$axios.post(this.matterBasePath() + "/lineConfig", { matterId }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.batchForm = Object.assign(this.emptyMatterBatchForm(matterId), res.data || {})
|
||||
this.batchForm.id = matterId
|
||||
this.batchForm.lineId = this.selectedMatterLine.id || this.batchForm.lineId
|
||||
this.batchForm.travelStartTime = this.dateOnly(this.batchForm.travelStartTime)
|
||||
this.batchForm.travelEndTime = this.dateOnly(this.batchForm.travelEndTime)
|
||||
this.applyMatterSelectedLineDefaults(false)
|
||||
this.loadMatterSettingDefaults((data) => {
|
||||
this.applyMatterSettingPeople(data)
|
||||
this.applyMatterSettingSignupTime(data)
|
||||
})
|
||||
this.lineConfigDialogVisible = true
|
||||
this.$nextTick(() => {
|
||||
this.applyMatterSelectedLineDefaults(true)
|
||||
this.$refs.batchFormRef && this.$refs.batchFormRef.clearValidate()
|
||||
})
|
||||
} else {
|
||||
this.$message.warning(res.msg || "事项信息查询失败")
|
||||
}
|
||||
})
|
||||
},
|
||||
backToMatterStep() {
|
||||
this.lineConfigDialogVisible = false
|
||||
this.matterDialogVisible = true
|
||||
this.$nextTick(() => this.$refs.matterFormRef && this.$refs.matterFormRef.clearValidate())
|
||||
},
|
||||
matterLineOptionLabel(item) {
|
||||
if (!item) return ""
|
||||
const lineName = this.matterLineField(item, "lineName") || ""
|
||||
const lineType = this.matterLineField(item, "lineType") || ""
|
||||
return lineType ? lineName + " (" + lineType + ")" : lineName
|
||||
},
|
||||
matterSelectedLine() {
|
||||
return (this.matterLineOptions || []).find((item) => this.matterLineField(item, "id") === this.batchForm.lineId) || null
|
||||
},
|
||||
applyMatterSelectedLineDefaults(recalculateEnd) {
|
||||
const line = this.matterSelectedLine()
|
||||
if (!line) return
|
||||
const activityCost = this.matterLineField(line, "activityCost")
|
||||
if (activityCost !== null && activityCost !== undefined && activityCost !== "") {
|
||||
this.batchForm.estimatedCost = activityCost
|
||||
}
|
||||
if (recalculateEnd) {
|
||||
this.fillMatterTravelEndByLot()
|
||||
}
|
||||
},
|
||||
matterTravelStartChange() {
|
||||
this.fillMatterTravelEndByLot()
|
||||
},
|
||||
fillMatterTravelEndByLot() {
|
||||
const line = this.matterSelectedLine()
|
||||
const days = this.matterLineLotDays(line)
|
||||
if (!this.batchForm.travelStartTime || !days) return
|
||||
this.$set(this.batchForm, "travelEndTime", moment(this.batchForm.travelStartTime).add(days - 1, "days").format("YYYY-MM-DD"))
|
||||
this.validateMatterTravelFields()
|
||||
},
|
||||
matterLineLotDays(line) {
|
||||
if (!line) return null
|
||||
const lotDays = this.matterLineField(line, "lotDays") || this.matterLineField(line, "lotValue")
|
||||
if (!/^\d+$/.test(String(lotDays || ""))) return null
|
||||
const days = parseInt(lotDays, 10)
|
||||
return days > 0 ? days : null
|
||||
},
|
||||
matterLineField(line, field) {
|
||||
if (!line) return null
|
||||
if (line[field] !== undefined) return line[field]
|
||||
const lowerField = field.toLowerCase()
|
||||
const matchedKey = Object.keys(line).find((key) => key.toLowerCase() === lowerField)
|
||||
return matchedKey ? line[matchedKey] : null
|
||||
},
|
||||
validateMatterTravelFields() {
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.batchFormRef) {
|
||||
this.$refs.batchFormRef.validateField(["travelStartTime", "travelEndTime"])
|
||||
}
|
||||
})
|
||||
},
|
||||
dateOnly(value) {
|
||||
if (!value) return ""
|
||||
return String(value).substring(0, 10)
|
||||
},
|
||||
applyMatterSettingSignupTime(data) {
|
||||
if (!data) return
|
||||
if (data.signupStartTime) {
|
||||
this.$set(this.batchForm, "signupStartTime", data.signupStartTime)
|
||||
}
|
||||
if (data.signupEndTime) {
|
||||
this.$set(this.batchForm, "signupEndTime", data.signupEndTime)
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.batchFormRef) {
|
||||
this.$refs.batchFormRef.validateField(["signupStartTime", "signupEndTime"])
|
||||
}
|
||||
})
|
||||
},
|
||||
applyMatterSettingPeople(data) {
|
||||
if (!data) return
|
||||
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 !== "") {
|
||||
this.$set(this.batchForm, "maxGroupPeople", data.maxGroupPeople)
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.batchFormRef) {
|
||||
this.$refs.batchFormRef.validateField(["minGroupPeople", "maxGroupPeople"])
|
||||
}
|
||||
})
|
||||
},
|
||||
loadMatterSettingDefaults(callback) {
|
||||
this.$axios.post(this.matterBasePath() + "/settingPeople", {
|
||||
matterId: this.matterForm.id,
|
||||
year: this.matterForm.year
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
callback && callback(res.data || {})
|
||||
}
|
||||
})
|
||||
},
|
||||
matterPeopleChange() {
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.batchFormRef) {
|
||||
this.$refs.batchFormRef.validateField(["minGroupPeople", "maxGroupPeople"])
|
||||
}
|
||||
})
|
||||
},
|
||||
submitMatterLineConfig() {
|
||||
this.$refs.batchFormRef.validate((valid) => {
|
||||
if (!valid) return
|
||||
this.batchSubDis = true
|
||||
this.$axios.post(this.matterBasePath() + "/lineConfigDoSubmit", this.batchForm).then((res) => {
|
||||
this.batchSubDis = false
|
||||
if (res.code === 0) {
|
||||
this.$message.success("保存成功")
|
||||
this.lineConfigDialogVisible = false
|
||||
} else {
|
||||
this.$message.warning(res.msg || "保存失败")
|
||||
}
|
||||
}).catch(() => {
|
||||
this.batchSubDis = false
|
||||
})
|
||||
})
|
||||
},
|
||||
loadDetail(id) {
|
||||
this.$axios.post(loc() + "/detail", { id }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
|
||||
+2
-2
@@ -190,8 +190,8 @@ layout("/layouts/platform.html"){
|
||||
<el-descriptions-item label="报名线路">{{ detail.lineName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="出行时段">{{ detail.travelPeriod || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="线路类型">{{ detail.lineType || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="报名酒店">{{ detail.hotelName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="旅行社">{{ detail.travelAgencyName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item v-if="false" label="报名酒店">{{ detail.hotelName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item v-if="false" label="旅行社">{{ detail.travelAgencyName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="是否携带家属">
|
||||
{{ familyText() }}
|
||||
</el-descriptions-item>
|
||||
|
||||
@@ -107,7 +107,7 @@ layout("/layouts/platform.html"){
|
||||
<el-input v-model="formData.configName" maxlength="100" placeholder="请输入配置名称"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-col v-if="false" :span="12">
|
||||
<el-form-item label="疗休养类型" prop="tourType">
|
||||
<el-select v-model="formData.tourType" clearable allow-create filterable placeholder="请选择或输入类型" style="width: 100%">
|
||||
<el-option label="省内疗休养" value="省内疗休养"></el-option>
|
||||
@@ -145,6 +145,28 @@ layout("/layouts/platform.html"){
|
||||
<el-input-number v-model="formData.maxGroupPeople" :controls="false" :min="0" :precision="0" placeholder="请输入最多成团人数" style="width: 100%"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="开始报名时间" prop="signupStartTime">
|
||||
<el-date-picker
|
||||
v-model="formData.signupStartTime"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="请选择开始报名时间"
|
||||
style="width: 100%">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="结束报名时间" prop="signupEndTime">
|
||||
<el-date-picker
|
||||
v-model="formData.signupEndTime"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="请选择结束报名时间"
|
||||
style="width: 100%">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<div class="tour-setting-basic-divider"></div>
|
||||
</el-col>
|
||||
@@ -155,7 +177,7 @@ layout("/layouts/platform.html"){
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="省外人数占比" prop="outProvinceRatio">
|
||||
<el-input-number v-model="formData.outProvinceRatio" :controls="false" :min="0" :max="100" :precision="2" placeholder="请输入省外人数占比" style="width: 100%"></el-input-number>
|
||||
<el-input-number v-model="formData.outProvinceRatio" :controls="false" :min="0" :max="100" :precision="2" disabled placeholder="请输入省外人数占比" style="width: 100%"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
@@ -300,6 +322,18 @@ layout("/layouts/platform.html"){
|
||||
callback()
|
||||
}
|
||||
}
|
||||
const checkSignupTime = (rule, value, callback) => {
|
||||
if (!value) {
|
||||
callback(new Error("必填"))
|
||||
return
|
||||
}
|
||||
if (this.formData.signupStartTime && this.formData.signupEndTime
|
||||
&& this.formData.signupStartTime >= this.formData.signupEndTime) {
|
||||
callback(new Error("开始报名时间必须小于结束报名时间"))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
const checkCycleYear = (rule, value, callback) => {
|
||||
const startYear = parseInt(this.formData.cycleStartYear, 10)
|
||||
const endYear = parseInt(this.formData.cycleEndYear, 10)
|
||||
@@ -337,6 +371,8 @@ layout("/layouts/platform.html"){
|
||||
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"]}],
|
||||
outProvinceFixedPeople: [{validator: checkOutProvinceFixedPeople, trigger: ["blur", "change"]}],
|
||||
cycleStartYear: [{validator: checkCycleYear, trigger: ["blur", "change"]}],
|
||||
@@ -382,6 +418,8 @@ layout("/layouts/platform.html"){
|
||||
sortNo: 0,
|
||||
minGroupPeople: 0,
|
||||
maxGroupPeople: 0,
|
||||
signupStartTime: "",
|
||||
signupEndTime: "",
|
||||
outProvinceYears: 0,
|
||||
outProvinceRatio: 0,
|
||||
outProvinceRatioType: "当年报名人数",
|
||||
@@ -466,6 +504,8 @@ layout("/layouts/platform.html"){
|
||||
activityGroupId: "",
|
||||
outProvinceRatioType: "当年报名人数",
|
||||
outProvinceFixedPeople: 0,
|
||||
signupStartTime: "",
|
||||
signupEndTime: "",
|
||||
cycleStartYear: "",
|
||||
cycleEndYear: "",
|
||||
cycleTotalCost: null,
|
||||
|
||||
@@ -54,11 +54,13 @@ layout("/layouts/platform.html"){
|
||||
@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="lineName" min-width="220" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="出行时段" prop="travelPeriod" width="330" 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>
|
||||
<!-- 临时屏蔽事项名称列,保留代码便于后续恢复
|
||||
<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 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}">
|
||||
@@ -75,10 +77,11 @@ layout("/layouts/platform.html"){
|
||||
<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="操作" width="260" align="center" header-align="center">
|
||||
<el-table-column label="操作" width="300" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
<el-button size="mini" type="primary" @click="openLineView(row)">查看线路</el-button>
|
||||
<el-button size="mini" :type="signupActionType(row)" :disabled="signupActionDisabled(row)" @click="handleSignupAction(row)">{{ signupActionText(row) }}</el-button>
|
||||
<el-button size="mini" type="primary" @click="openLineView(row)">查看线路</el-button>
|
||||
<el-button size="mini" type="primary" @click="openPeopleView(row)">查看人员</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -148,16 +151,22 @@ layout("/layouts/platform.html"){
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<!-- 临时屏蔽报名酒店字段,保留代码便于后续恢复
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="报名酒店">
|
||||
<el-input v-model="signupForm.hotelName" :disabled="isDirectFamilyLine(signupForm)" maxlength="100" placeholder="请输入报名酒店"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
-->
|
||||
<!-- 临时屏蔽报名旅行社字段,保留代码便于后续恢复
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="报名旅行社">
|
||||
<el-input v-model="signupForm.travelAgencyName" :disabled="isDirectFamilyLine(signupForm)" readonly></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
-->
|
||||
<el-col :span="8">
|
||||
<el-form-item label="出行时间">
|
||||
<el-input v-model="signupForm.travelPeriod" :disabled="isDirectFamilyLine(signupForm)" readonly></el-input>
|
||||
@@ -369,11 +378,72 @@ layout("/layouts/platform.html"){
|
||||
|
||||
<div class="tour-signup-section">
|
||||
<div class="tour-signup-title">线路内容</div>
|
||||
<div ref="lineContent" class="tour-line-content" v-html="lineContentHtml" @click="handleLineContentClick"></div>
|
||||
<div ref="lineContent" class="tour-line-content" v-html="lineContentHtml"></div>
|
||||
</div>
|
||||
</div>
|
||||
</el-drawer>
|
||||
|
||||
<el-drawer
|
||||
:title="peopleViewTitle"
|
||||
:visible.sync="peopleViewVisible"
|
||||
direction="rtl"
|
||||
size="72%"
|
||||
custom-class="tour-group-view-drawer"
|
||||
:close-on-click-modal="false">
|
||||
<div class="tour-group-view">
|
||||
<el-card shadow="never">
|
||||
<search :is-search-button="false">
|
||||
<search-item label="姓名/工号">
|
||||
<el-input
|
||||
v-model="peopleViewForm.keyword"
|
||||
clearable
|
||||
placeholder="请输入姓名或工号"
|
||||
style="width: 100%"
|
||||
@keyup.enter.native="peopleViewSearch">
|
||||
</el-input>
|
||||
</search-item>
|
||||
<search-item label="所属工会">
|
||||
<el-select v-model="peopleViewForm.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>
|
||||
<div class="search-query" style="margin-left: auto;">
|
||||
<el-button size="medium" type="primary" icon="el-icon-search" @click="peopleViewSearch">搜索</el-button>
|
||||
<el-button size="medium" @click="peopleViewReset">重置</el-button>
|
||||
</div>
|
||||
</search>
|
||||
</el-card>
|
||||
|
||||
<el-card class="mt10" shadow="never">
|
||||
<div class="tour-group-view-title">报名人员列表</div>
|
||||
<el-table
|
||||
v-loading="peopleViewLoading"
|
||||
:data="peopleViewTableData"
|
||||
:size="tableSize"
|
||||
border
|
||||
@sort-change="peopleViewPageOrder">
|
||||
<el-table-column label="序号" type="index" :index="peopleViewIndexMethod" 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="unionName" min-width="180" sortable="custom" 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>
|
||||
<el-row class="el-pagination-container tour-group-view-pagination">
|
||||
<el-pagination
|
||||
background
|
||||
:current-page="peopleViewForm.pageNumber"
|
||||
:page-size="peopleViewForm.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:total="peopleViewForm.totalCount"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="peopleViewSizeChange"
|
||||
@current-change="peopleViewCurrentChange">
|
||||
</el-pagination>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</div>
|
||||
</el-drawer>
|
||||
|
||||
</div>
|
||||
|
||||
<style>
|
||||
@@ -416,21 +486,76 @@ layout("/layouts/platform.html"){
|
||||
.tour-line-content .tour-file-preview {
|
||||
border: 1px solid #dcdfe6;
|
||||
display: block;
|
||||
min-height: 520px;
|
||||
height: 620px;
|
||||
width: 100%;
|
||||
}
|
||||
.tour-line-content .tour-pdf-preview {
|
||||
.tour-line-content .tour-file-preview-box {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.tour-line-content .tour-file-link {
|
||||
color: #0079c2;
|
||||
text-decoration: underline;
|
||||
.tour-line-content .tour-pdf-lazy-preview {
|
||||
border: 1px solid #dcdfe6;
|
||||
background: #f5f7fa;
|
||||
min-height: 180px;
|
||||
margin-top: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.tour-line-content .tour-file-loading {
|
||||
.tour-line-content .tour-pdf-lazy-toolbar {
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
color: #606266;
|
||||
font-size: 13px;
|
||||
line-height: 36px;
|
||||
padding: 0 12px;
|
||||
}
|
||||
.tour-line-content .tour-pdf-page-placeholder {
|
||||
align-items: center;
|
||||
background: #f5f7fa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
color: #909399;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
min-height: 220px;
|
||||
}
|
||||
.tour-line-content .tour-pdf-page-placeholder canvas {
|
||||
background: #fff;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
.tour-line-content .tour-image-preview {
|
||||
border: 1px solid #dcdfe6;
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
max-height: 680px;
|
||||
object-fit: contain;
|
||||
width: 100%;
|
||||
}
|
||||
.tour-line-content .tour-file-unpreviewable {
|
||||
align-items: center;
|
||||
border: 1px solid #dcdfe6;
|
||||
color: #909399;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
min-height: 160px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.tour-group-view-drawer .el-drawer__body {
|
||||
background: #f5f7fa;
|
||||
padding: 12px;
|
||||
overflow: auto;
|
||||
}
|
||||
.tour-group-view-pagination {
|
||||
margin-top: 12px;
|
||||
text-align: right;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
.el-table .direct-family-row > td,
|
||||
.el-table .direct-family-row > td .cell {
|
||||
@@ -461,6 +586,9 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="${base!}/assets/platform/plugins/pdfJs/h5/pdf.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="${base!}/assets/platform/plugins/pdfJs/h5/pdf.worker.js" type="text/javascript" charset="utf-8"></script>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
@@ -484,6 +612,14 @@ layout("/layouts/platform.html"){
|
||||
lineVisible: false,
|
||||
lineDetail: {},
|
||||
lineContentHtml: "",
|
||||
linePdfPreviews: [],
|
||||
linePdfObserver: null,
|
||||
peopleViewVisible: false,
|
||||
peopleViewLoading: false,
|
||||
peopleViewRequestSeq: 0,
|
||||
peopleViewTitle: "",
|
||||
peopleViewRow: {},
|
||||
peopleViewTableData: [],
|
||||
pageForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
@@ -494,6 +630,15 @@ layout("/layouts/platform.html"){
|
||||
lineName: "",
|
||||
lineType: "",
|
||||
unionId: ""
|
||||
},
|
||||
peopleViewForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
pageOrderName: "signupTime",
|
||||
pageOrderBy: "descending",
|
||||
keyword: "",
|
||||
unionId: ""
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -535,6 +680,10 @@ layout("/layouts/platform.html"){
|
||||
this.revokeSignup(row)
|
||||
return
|
||||
}
|
||||
if (row && row.signed) {
|
||||
this.loadSignupDetail(row)
|
||||
return
|
||||
}
|
||||
this.openSignup(row)
|
||||
},
|
||||
isApprovalSignup(row) {
|
||||
@@ -570,6 +719,79 @@ layout("/layouts/platform.html"){
|
||||
|| row.directFamilyUnitLine === 1
|
||||
|| row.directFamilyUnitLine === "1"
|
||||
},
|
||||
openPeopleView(row) {
|
||||
this.peopleViewRow = row || {}
|
||||
this.peopleViewTitle = (this.peopleViewRow.lineName || "报名人员") + " - 报名人员"
|
||||
this.peopleViewVisible = true
|
||||
this.peopleViewForm.pageNumber = 1
|
||||
this.peopleViewForm.pageSize = 10
|
||||
this.peopleViewForm.totalCount = 0
|
||||
this.peopleViewForm.pageOrderName = "signupTime"
|
||||
this.peopleViewForm.pageOrderBy = "descending"
|
||||
this.peopleViewForm.keyword = ""
|
||||
this.peopleViewForm.unionId = ""
|
||||
this.peopleViewTableData = []
|
||||
this.loadPeopleViewData()
|
||||
},
|
||||
peopleViewSearch() {
|
||||
this.peopleViewForm.pageNumber = 1
|
||||
this.loadPeopleViewData()
|
||||
},
|
||||
peopleViewReset() {
|
||||
this.peopleViewForm.keyword = ""
|
||||
this.peopleViewForm.unionId = ""
|
||||
this.peopleViewForm.pageNumber = 1
|
||||
this.loadPeopleViewData()
|
||||
},
|
||||
peopleViewIndexMethod(index) {
|
||||
return (this.peopleViewForm.pageNumber - 1) * this.peopleViewForm.pageSize + index + 1
|
||||
},
|
||||
peopleViewSizeChange(size) {
|
||||
this.peopleViewForm.pageSize = size
|
||||
this.peopleViewForm.pageNumber = 1
|
||||
this.loadPeopleViewData()
|
||||
},
|
||||
peopleViewCurrentChange(page) {
|
||||
this.peopleViewForm.pageNumber = page
|
||||
this.loadPeopleViewData()
|
||||
},
|
||||
peopleViewPageOrder({ prop, order }) {
|
||||
this.peopleViewForm.pageOrderName = prop || "signupTime"
|
||||
this.peopleViewForm.pageOrderBy = order || "descending"
|
||||
this.peopleViewForm.pageNumber = 1
|
||||
this.loadPeopleViewData()
|
||||
},
|
||||
loadPeopleViewData() {
|
||||
if (!this.peopleViewRow || !this.peopleViewRow.matterId) {
|
||||
this.peopleViewTableData = []
|
||||
this.peopleViewForm.totalCount = 0
|
||||
return
|
||||
}
|
||||
this.peopleViewLoading = true
|
||||
const requestSeq = ++this.peopleViewRequestSeq
|
||||
this.$axios.post(loc() + "/signupPageData", {
|
||||
matterId: this.peopleViewRow.matterId,
|
||||
keyword: this.peopleViewForm.keyword,
|
||||
unionId: this.peopleViewForm.unionId,
|
||||
pageNumber: this.peopleViewForm.pageNumber,
|
||||
pageSize: this.peopleViewForm.pageSize,
|
||||
pageOrderName: this.peopleViewForm.pageOrderName,
|
||||
pageOrderBy: this.peopleViewForm.pageOrderBy
|
||||
}).then((res) => {
|
||||
if (requestSeq !== this.peopleViewRequestSeq) return
|
||||
if (res.code === 0) {
|
||||
const data = res.data || {}
|
||||
this.peopleViewTableData = data.list || []
|
||||
this.peopleViewForm.totalCount = data.totalCount || 0
|
||||
} else {
|
||||
this.$message.warning(res.msg || "查询失败")
|
||||
}
|
||||
}).finally(() => {
|
||||
if (requestSeq === this.peopleViewRequestSeq) {
|
||||
this.peopleViewLoading = false
|
||||
}
|
||||
})
|
||||
},
|
||||
canApplyOverReimbursement(row) {
|
||||
if (!row) return false
|
||||
return row.allowOverReimbursement === true
|
||||
@@ -580,15 +802,51 @@ layout("/layouts/platform.html"){
|
||||
this.$axios.post(loc() + "/lineDetail", { lineId: row.lineId }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.lineDetail = res.data || {}
|
||||
this.lineContentHtml = this.buildLineContentHtml(this.lineDetail.lineContent)
|
||||
this.lineContentHtml = ""
|
||||
this.lineVisible = true
|
||||
this.$nextTick(() => this.loadPdfPreviews())
|
||||
this.buildLineContentHtmlAsync(this.lineDetail.lineContent).then((html) => {
|
||||
this.lineContentHtml = html
|
||||
this.$nextTick(() => {
|
||||
this.initLinePdfPreviews()
|
||||
})
|
||||
})
|
||||
} else {
|
||||
this.$message.warning(res.msg || "查询失败")
|
||||
}
|
||||
})
|
||||
},
|
||||
buildLineContentHtml(content) {
|
||||
buildLineContentHtmlAsync(content) {
|
||||
const ids = this.extractLineFileIds(content)
|
||||
if (!ids.length) {
|
||||
return Promise.resolve(this.buildLineContentHtml(content, {}))
|
||||
}
|
||||
return this.$axios.post("/platform/sys/file/previewFileData", {ids: JSON.stringify(ids)}).then((res) => {
|
||||
const fileMap = {}
|
||||
if (res.code === 0 && Array.isArray(res.data)) {
|
||||
res.data.forEach((file) => {
|
||||
if (file && file.id) {
|
||||
file.suffix = (file.suffix || "").toLowerCase()
|
||||
fileMap[file.id] = file
|
||||
}
|
||||
})
|
||||
}
|
||||
return this.buildLineContentHtml(content, fileMap)
|
||||
}).catch(() => this.buildLineContentHtml(content, {}))
|
||||
},
|
||||
extractLineFileIds(content) {
|
||||
if (!content) return []
|
||||
const wrap = document.createElement("div")
|
||||
wrap.innerHTML = content
|
||||
const ids = []
|
||||
Array.prototype.slice.call(wrap.querySelectorAll("a[href]")).forEach((anchor) => {
|
||||
const id = this.getFileIdFromUrl(anchor.getAttribute("href") || "")
|
||||
if (id && !ids.includes(id)) {
|
||||
ids.push(id)
|
||||
}
|
||||
})
|
||||
return ids
|
||||
},
|
||||
buildLineContentHtml(content, fileMap) {
|
||||
if (!content) return "暂无线路内容"
|
||||
const wrap = document.createElement("div")
|
||||
wrap.innerHTML = content
|
||||
@@ -596,63 +854,226 @@ layout("/layouts/platform.html"){
|
||||
anchors.forEach((anchor) => {
|
||||
const href = anchor.getAttribute("href") || ""
|
||||
const text = anchor.textContent || href
|
||||
const cleanHref = href.split("#")[0].split("?")[0]
|
||||
const lowerHref = cleanHref.toLowerCase()
|
||||
const lowerText = text.toLowerCase()
|
||||
anchor.removeAttribute("download")
|
||||
anchor.setAttribute("target", "_blank")
|
||||
anchor.setAttribute("rel", "noopener noreferrer")
|
||||
anchor.classList.add("tour-file-link")
|
||||
if (/\.pdf$/.test(lowerHref) || /\.pdf$/.test(lowerText) || lowerText.indexOf(".pdf") > -1) {
|
||||
const box = document.createElement("div")
|
||||
box.className = "tour-pdf-preview"
|
||||
box.setAttribute("data-pdf-url", encodeURIComponent(href))
|
||||
box.innerHTML = '<div class="tour-file-preview tour-file-loading">PDF加载中...</div>'
|
||||
anchor.parentNode.insertBefore(box, anchor.nextSibling)
|
||||
} else if (/\.(jpg|jpeg|png|gif|bmp|webp)$/.test(lowerHref)) {
|
||||
const img = document.createElement("img")
|
||||
img.src = href
|
||||
img.alt = text
|
||||
img.style.display = "block"
|
||||
img.style.marginTop = "10px"
|
||||
anchor.parentNode.insertBefore(img, anchor.nextSibling)
|
||||
const fileId = this.getFileIdFromUrl(href)
|
||||
const file = fileId && fileMap ? fileMap[fileId] : null
|
||||
const fileType = this.detectPreviewFileType(href, text, file)
|
||||
if (!fileType) {
|
||||
return
|
||||
}
|
||||
const preview = this.createLineFilePreview(href, fileType, file)
|
||||
if (anchor.parentNode && preview) {
|
||||
anchor.parentNode.replaceChild(preview, anchor)
|
||||
}
|
||||
})
|
||||
return wrap.innerHTML
|
||||
},
|
||||
isPdfLink(anchor) {
|
||||
if (!anchor) return false
|
||||
const href = anchor.getAttribute("href") || ""
|
||||
const text = anchor.textContent || href
|
||||
const lowerHref = href.split("#")[0].split("?")[0].toLowerCase()
|
||||
const lowerText = text.toLowerCase()
|
||||
return /\.pdf$/.test(lowerHref) || /\.pdf$/.test(lowerText) || lowerText.indexOf(".pdf") > -1
|
||||
detectPreviewFileType(href, text, file) {
|
||||
const suffix = file && file.suffix ? file.suffix.toLowerCase() : ""
|
||||
if (["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(suffix)) {
|
||||
return "image"
|
||||
}
|
||||
if (suffix === "pdf") {
|
||||
return "pdf"
|
||||
}
|
||||
if (["doc", "docx", "xls", "xlsx"].includes(suffix)) {
|
||||
return "office"
|
||||
}
|
||||
const lowerHref = (href || "").split("#")[0].split("?")[0].toLowerCase()
|
||||
const lowerText = (text || "").toLowerCase()
|
||||
const value = lowerHref + " " + lowerText
|
||||
if (/\.(jpg|jpeg|png|gif|bmp|webp)(\s|$)/.test(value)) {
|
||||
return "image"
|
||||
}
|
||||
if (/\.pdf(\s|$)/.test(value)) {
|
||||
return "pdf"
|
||||
}
|
||||
if (/\.(doc|docx|xls|xlsx)(\s|$)/.test(value)) {
|
||||
return "office"
|
||||
}
|
||||
return ""
|
||||
},
|
||||
previewPdf(url, callback) {
|
||||
fetch(url, { credentials: "include" }).then((res) => {
|
||||
if (!res.ok) throw new Error("PDF加载失败")
|
||||
return res.blob()
|
||||
}).then((blob) => {
|
||||
const previewUrl = URL.createObjectURL(new Blob([blob], { type: "application/pdf" }))
|
||||
callback(previewUrl)
|
||||
}).catch(() => {
|
||||
callback(url)
|
||||
})
|
||||
createLineFilePreview(href, fileType, file) {
|
||||
if (fileType === "image") {
|
||||
const img = document.createElement("img")
|
||||
img.className = "tour-image-preview"
|
||||
img.src = file && file.downloadPath ? file.downloadPath : href
|
||||
img.alt = ""
|
||||
return img
|
||||
}
|
||||
const previewUrl = this.buildLinePreviewUrl(href, fileType, file)
|
||||
if (!previewUrl) {
|
||||
const tip = document.createElement("div")
|
||||
tip.className = "tour-file-unpreviewable"
|
||||
tip.textContent = "当前文件暂不支持预览"
|
||||
return tip
|
||||
}
|
||||
const box = document.createElement("div")
|
||||
box.className = "tour-file-preview-box"
|
||||
const preview = document.createElement("div")
|
||||
preview.className = "tour-pdf-lazy-preview"
|
||||
preview.setAttribute("data-pdf-url", previewUrl)
|
||||
preview.innerHTML = "<div class=\"tour-pdf-lazy-toolbar\">PDF预览加载中...</div>"
|
||||
box.appendChild(preview)
|
||||
return box
|
||||
},
|
||||
loadPdfPreviews() {
|
||||
buildLinePreviewUrl(href, fileType, file) {
|
||||
if (fileType === "office") {
|
||||
const id = file && file.id ? file.id : this.getFileIdFromUrl(href)
|
||||
return id ? "/platform/sys/file/convertPDF?id=" + id : ""
|
||||
}
|
||||
if (fileType === "pdf") {
|
||||
return file && file.downloadPath ? file.downloadPath : href
|
||||
}
|
||||
return ""
|
||||
},
|
||||
getPdfLib() {
|
||||
return window.pdfjsLib || window["pdfjs-dist/build/pdf"]
|
||||
},
|
||||
initLinePdfPreviews() {
|
||||
this.cleanupLinePdfPreviews()
|
||||
const root = this.$refs.lineContent
|
||||
if (!root) return
|
||||
const boxes = Array.prototype.slice.call(root.querySelectorAll(".tour-pdf-preview[data-pdf-url]"))
|
||||
boxes.forEach((box) => {
|
||||
const url = decodeURIComponent(box.getAttribute("data-pdf-url") || "")
|
||||
if (!url) return
|
||||
this.previewPdf(url, (previewUrl) => {
|
||||
box.innerHTML = '<object class="tour-file-preview" data="' + previewUrl + '#toolbar=1&navpanes=0" type="application/pdf">'
|
||||
+ '<embed class="tour-file-preview" src="' + previewUrl + '#toolbar=1&navpanes=0" type="application/pdf" />'
|
||||
+ '</object>'
|
||||
const previews = root ? Array.prototype.slice.call(root.querySelectorAll(".tour-pdf-lazy-preview")) : []
|
||||
if (!previews.length) {
|
||||
return
|
||||
}
|
||||
const pdfLib = this.getPdfLib()
|
||||
if (!pdfLib || !pdfLib.getDocument) {
|
||||
previews.forEach((el) => {
|
||||
el.innerHTML = "<div class=\"tour-file-unpreviewable\">PDF预览组件加载失败</div>"
|
||||
})
|
||||
return
|
||||
}
|
||||
if (pdfLib.GlobalWorkerOptions) {
|
||||
pdfLib.GlobalWorkerOptions.workerSrc = "/assets/platform/plugins/pdfJs/h5/pdf.worker.js"
|
||||
}
|
||||
if (window.IntersectionObserver) {
|
||||
this.linePdfObserver = new IntersectionObserver((entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (!entry.isIntersecting) {
|
||||
return
|
||||
}
|
||||
this.renderLazyPdfPage(entry.target)
|
||||
this.linePdfObserver && this.linePdfObserver.unobserve(entry.target)
|
||||
})
|
||||
}, {
|
||||
root: null,
|
||||
rootMargin: "420px 0px",
|
||||
threshold: 0.01
|
||||
})
|
||||
}
|
||||
previews.forEach((el) => {
|
||||
this.initLazyPdfPreview(el, pdfLib)
|
||||
})
|
||||
},
|
||||
initLazyPdfPreview(el, pdfLib) {
|
||||
const url = el.getAttribute("data-pdf-url")
|
||||
if (!url) {
|
||||
el.innerHTML = "<div class=\"tour-file-unpreviewable\">当前文件暂不支持预览</div>"
|
||||
return
|
||||
}
|
||||
const task = pdfLib.getDocument({
|
||||
url: url,
|
||||
disableAutoFetch: true,
|
||||
disableStream: true,
|
||||
disableRange: false
|
||||
})
|
||||
const state = {
|
||||
el: el,
|
||||
doc: null,
|
||||
task: task,
|
||||
rendered: {},
|
||||
rendering: {}
|
||||
}
|
||||
this.linePdfPreviews.push(state)
|
||||
task.promise.then((pdf) => {
|
||||
state.doc = pdf
|
||||
const count = pdf.numPages || 0
|
||||
const toolbar = el.querySelector(".tour-pdf-lazy-toolbar")
|
||||
if (toolbar) {
|
||||
toolbar.textContent = "PDF预览:共 " + count + " 页,已优先加载第 1 页"
|
||||
}
|
||||
for (let i = 1; i <= count; i++) {
|
||||
const page = document.createElement("div")
|
||||
page.className = "tour-pdf-page-placeholder"
|
||||
page.setAttribute("data-page-number", i)
|
||||
page.textContent = i === 1 ? "正在加载第 1 页..." : "第 " + i + " 页,滚动到此处加载"
|
||||
el.appendChild(page)
|
||||
}
|
||||
const firstPage = el.querySelector("[data-page-number='1']")
|
||||
if (firstPage) {
|
||||
this.renderLazyPdfPage(firstPage)
|
||||
}
|
||||
Array.prototype.slice.call(el.querySelectorAll(".tour-pdf-page-placeholder")).forEach((page) => {
|
||||
if (page.getAttribute("data-page-number") !== "1" && this.linePdfObserver) {
|
||||
this.linePdfObserver.observe(page)
|
||||
}
|
||||
})
|
||||
}).catch(() => {
|
||||
el.innerHTML = "<div class=\"tour-file-unpreviewable\">PDF加载失败,请稍后重试</div>"
|
||||
})
|
||||
},
|
||||
renderLazyPdfPage(pageEl) {
|
||||
const previewEl = pageEl.closest(".tour-pdf-lazy-preview")
|
||||
const state = this.linePdfPreviews.find((item) => item.el === previewEl)
|
||||
if (!state || !state.doc) {
|
||||
return
|
||||
}
|
||||
const pageNumber = Number(pageEl.getAttribute("data-page-number") || 0)
|
||||
if (!pageNumber || state.rendered[pageNumber] || state.rendering[pageNumber]) {
|
||||
return
|
||||
}
|
||||
state.rendering[pageNumber] = true
|
||||
pageEl.textContent = "正在加载第 " + pageNumber + " 页..."
|
||||
state.doc.getPage(pageNumber).then((page) => {
|
||||
const containerWidth = Math.max(previewEl.clientWidth - 24, 420)
|
||||
const baseViewport = page.getViewport({scale: 1})
|
||||
const cssScale = containerWidth / baseViewport.width
|
||||
const outputScale = Math.min(window.devicePixelRatio || 1, 2)
|
||||
const viewport = page.getViewport({scale: cssScale})
|
||||
const canvas = document.createElement("canvas")
|
||||
const context = canvas.getContext("2d")
|
||||
canvas.width = Math.floor(viewport.width * outputScale)
|
||||
canvas.height = Math.floor(viewport.height * outputScale)
|
||||
canvas.style.width = Math.floor(viewport.width) + "px"
|
||||
canvas.style.height = Math.floor(viewport.height) + "px"
|
||||
pageEl.innerHTML = ""
|
||||
pageEl.appendChild(canvas)
|
||||
return page.render({
|
||||
canvasContext: context,
|
||||
viewport: viewport,
|
||||
transform: outputScale !== 1 ? [outputScale, 0, 0, outputScale, 0, 0] : null
|
||||
}).promise.then(() => {
|
||||
state.rendered[pageNumber] = true
|
||||
state.rendering[pageNumber] = false
|
||||
})
|
||||
}).catch(() => {
|
||||
state.rendering[pageNumber] = false
|
||||
pageEl.textContent = "第 " + pageNumber + " 页加载失败"
|
||||
})
|
||||
},
|
||||
cleanupLinePdfPreviews() {
|
||||
if (this.linePdfObserver) {
|
||||
this.linePdfObserver.disconnect()
|
||||
this.linePdfObserver = null
|
||||
}
|
||||
this.linePdfPreviews.forEach((item) => {
|
||||
if (item.task && item.task.destroy) {
|
||||
try {
|
||||
item.task.destroy()
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
})
|
||||
this.linePdfPreviews = []
|
||||
},
|
||||
getFileIdFromUrl(href) {
|
||||
if (!href) return ""
|
||||
const idMatch = href.match(/[?&]id=([^&#]+)/)
|
||||
if (idMatch) {
|
||||
return decodeURIComponent(idMatch[1])
|
||||
}
|
||||
return ""
|
||||
},
|
||||
revokeSignup(row) {
|
||||
if (!this.canRevokeSignup(row)) {
|
||||
this.$message.warning("当前报名申请暂不支持撤回")
|
||||
@@ -676,16 +1097,6 @@ layout("/layouts/platform.html"){
|
||||
})
|
||||
}).catch(() => {})
|
||||
},
|
||||
handleLineContentClick(event) {
|
||||
const anchor = event.target.closest && event.target.closest("a[href]")
|
||||
if (!anchor || !this.$refs.lineContent || !this.$refs.lineContent.contains(anchor)) return
|
||||
if (!this.isPdfLink(anchor)) return
|
||||
event.preventDefault()
|
||||
const href = anchor.getAttribute("href")
|
||||
this.previewPdf(href, (previewUrl) => {
|
||||
window.open(previewUrl, "_blank", "noopener,noreferrer")
|
||||
})
|
||||
},
|
||||
openSignup(row) {
|
||||
this.$axios.post(loc() + "/signupEligibilityNotice", { matterId: row.matterId }).then((res) => {
|
||||
if (res.code !== 0) {
|
||||
@@ -769,10 +1180,7 @@ layout("/layouts/platform.html"){
|
||||
hasFamily: ledger.hasFamily === true || ledger.hasFamily === 1 || ledger.hasFamily === "1"
|
||||
})
|
||||
this.directRelativeForm = Object.assign(this.emptyDirectRelative(), {
|
||||
lineId: matter.lineId || "",
|
||||
lineName: matter.lineName || "",
|
||||
travelStartTime: matter.travelStartTime || "",
|
||||
travelEndTime: matter.travelEndTime || ""
|
||||
lineId: matter.lineId || ""
|
||||
}, directRelative)
|
||||
this.familyData = (data.families || []).map(item => Object.assign(this.emptyFamily(), item))
|
||||
if (this.familyData.length > 0) {
|
||||
@@ -815,9 +1223,9 @@ layout("/layouts/platform.html"){
|
||||
relationshipCode: "",
|
||||
relationshipName: "",
|
||||
lineId: this.signupForm.lineId || "",
|
||||
lineName: this.signupForm.lineName || "",
|
||||
travelStartTime: this.signupForm.travelStartTime || "",
|
||||
travelEndTime: this.signupForm.travelEndTime || ""
|
||||
lineName: "",
|
||||
travelStartTime: "",
|
||||
travelEndTime: ""
|
||||
}
|
||||
},
|
||||
directRelativeChange(code) {
|
||||
@@ -949,6 +1357,7 @@ layout("/layouts/platform.html"){
|
||||
this.cancelLoading = false
|
||||
},
|
||||
destroyLineView() {
|
||||
this.cleanupLinePdfPreviews()
|
||||
this.lineDetail = {}
|
||||
this.lineContentHtml = ""
|
||||
},
|
||||
|
||||
@@ -62,13 +62,14 @@ layout("/layouts/platform.html"){
|
||||
:data="tableData"
|
||||
:size="tableSize"
|
||||
border
|
||||
:default-sort="{prop: 'agencyCode', order: 'ascending'}"
|
||||
@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="agencyCode" width="120" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="旅行社名称" prop="agencyName" min-width="220" 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>
|
||||
<el-table-column label="排序编号" prop="agencyCode" width="120" sortable="custom" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="激活状态" prop="enabled" width="160" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
<el-switch
|
||||
@@ -117,11 +118,6 @@ layout("/layouts/platform.html"){
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="旅行社编号" prop="agencyCode">
|
||||
<el-input v-model="formData.agencyCode" maxlength="50" placeholder="请输入旅行社编号"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="激活状态" prop="enabled">
|
||||
<el-radio-group v-model="formData.enabled">
|
||||
@@ -144,6 +140,11 @@ layout("/layouts/platform.html"){
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="排序编号" prop="agencyCode">
|
||||
<el-input-number v-model="formData.agencyCode" :controls="false" :min="0" :precision="0" placeholder="请输入排序编号" style="width: 100%"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="邮箱" prop="email">
|
||||
<el-input v-model="formData.email" maxlength="100" placeholder="请输入邮箱"></el-input>
|
||||
@@ -213,7 +214,9 @@ layout("/layouts/platform.html"){
|
||||
year: currentYear,
|
||||
agencyName: "",
|
||||
contactName: "",
|
||||
contactPhone: ""
|
||||
contactPhone: "",
|
||||
pageOrderName: "agencyCode",
|
||||
pageOrderBy: "ascending"
|
||||
},
|
||||
formData: {},
|
||||
formRules: {
|
||||
|
||||
@@ -0,0 +1,470 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<guava ref="guava">
|
||||
<el-card shadow="never">
|
||||
<search :is-search-button="false">
|
||||
<search-item label="年度">
|
||||
<el-date-picker
|
||||
v-model="pageForm.year"
|
||||
type="year"
|
||||
value-format="yyyy"
|
||||
placeholder="请选择年度"
|
||||
style="width: 100%">
|
||||
</el-date-picker>
|
||||
</search-item>
|
||||
<search-item label="线路名称">
|
||||
<el-input
|
||||
v-model="pageForm.lineName"
|
||||
clearable
|
||||
placeholder="请输入线路名称"
|
||||
style="width: 100%"
|
||||
@keyup.enter.native="doSearch">
|
||||
</el-input>
|
||||
</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.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%">
|
||||
<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" 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>
|
||||
</div>
|
||||
</search>
|
||||
</el-card>
|
||||
|
||||
<el-card class="mt10" shadow="never">
|
||||
<table-tool :app="this" label="领办线路列表">
|
||||
<el-radio-group class="mr5" size="small" v-model="pageForm.undertakeStatus" @change="changeUndertakeStatus">
|
||||
<el-radio-button label="claimed">已领</el-radio-button>
|
||||
<el-radio-button label="unclaimed">未领</el-radio-button>
|
||||
</el-radio-group>
|
||||
</table-tool>
|
||||
|
||||
<el-table
|
||||
v-loading="tableLoading"
|
||||
:data="tableData"
|
||||
:size="tableSize"
|
||||
border
|
||||
:default-sort="{prop: 'lineName', 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="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="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">
|
||||
<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="160" 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 }}人<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>
|
||||
<el-button size="mini" type="primary" :disabled="isClaimed(row)" @click="undertakeLine(row)">领办</el-button>
|
||||
<el-button v-if="row.canRelease" size="mini" type="danger" plain @click="releaseUndertakeLine(row)">解除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
<div class="tour-undertake-tip">温馨提醒:列表中报名人数字段括号内的数字是本工会所报其线路的人数。</div>
|
||||
</el-card>
|
||||
|
||||
<el-drawer
|
||||
:title="viewTitle"
|
||||
:visible.sync="viewVisible"
|
||||
direction="rtl"
|
||||
size="72%"
|
||||
custom-class="tour-group-view-drawer"
|
||||
:close-on-click-modal="false">
|
||||
<div class="tour-group-view">
|
||||
<el-card shadow="never">
|
||||
<search :is-search-button="false">
|
||||
<search-item label="姓名/工号">
|
||||
<el-input
|
||||
v-model="viewForm.keyword"
|
||||
clearable
|
||||
placeholder="请输入姓名或工号"
|
||||
style="width: 100%"
|
||||
@keyup.enter.native="viewSearch">
|
||||
</el-input>
|
||||
</search-item>
|
||||
<search-item label="所属工会">
|
||||
<el-select v-model="viewForm.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>
|
||||
<div class="search-query" style="margin-left: auto;">
|
||||
<el-button size="medium" type="primary" icon="el-icon-search" @click="viewSearch">搜索</el-button>
|
||||
<el-button size="medium" @click="viewReset">重置</el-button>
|
||||
</div>
|
||||
</search>
|
||||
</el-card>
|
||||
|
||||
<el-card class="mt10" shadow="never">
|
||||
<div class="tour-group-view-title">报名人员列表</div>
|
||||
<el-table
|
||||
v-loading="viewLoading"
|
||||
:data="viewTableData"
|
||||
: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="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>
|
||||
<el-row class="el-pagination-container tour-group-view-pagination">
|
||||
<el-pagination
|
||||
background
|
||||
:current-page="viewForm.pageNumber"
|
||||
:page-size="viewForm.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:total="viewForm.totalCount"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="viewSizeChange"
|
||||
@current-change="viewCurrentChange">
|
||||
</el-pagination>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</guava>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
data() {
|
||||
const currentYear = moment().format("YYYY")
|
||||
return {
|
||||
unionOptions: [],
|
||||
lineTypeOptions: [],
|
||||
viewVisible: false,
|
||||
viewLoading: false,
|
||||
viewRequestSeq: 0,
|
||||
viewTitle: "",
|
||||
viewRow: {},
|
||||
viewTableData: [],
|
||||
currentUnionInfo: null,
|
||||
pageForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
pageOrderName: "lineName",
|
||||
pageOrderBy: "ascending",
|
||||
year: currentYear,
|
||||
lineName: "",
|
||||
lineType: "",
|
||||
unionId: "",
|
||||
undertakeStatus: "unclaimed"
|
||||
},
|
||||
viewForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
pageOrderName: "signupTime",
|
||||
pageOrderBy: "descending",
|
||||
keyword: "",
|
||||
unionId: ""
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
resetSearch() {
|
||||
this.pageForm.year = moment().format("YYYY")
|
||||
this.pageForm.lineName = ""
|
||||
this.pageForm.lineType = ""
|
||||
this.pageForm.unionId = ""
|
||||
this.pageForm.undertakeStatus = "unclaimed"
|
||||
this.loadLineTypeOptions()
|
||||
this.doSearch()
|
||||
},
|
||||
changeUndertakeStatus() {
|
||||
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" : ""
|
||||
},
|
||||
isDirectFamilyLine(row) {
|
||||
if (!row) return false
|
||||
return row.directFamilyUnitLine === true
|
||||
|| row.directFamilyUnitLine === 1
|
||||
|| row.directFamilyUnitLine === "1"
|
||||
},
|
||||
isClaimed(row) {
|
||||
return row && row.undertakeStatus === "claimed"
|
||||
},
|
||||
openView(row) {
|
||||
this.viewRow = row || {}
|
||||
this.viewTitle = this.viewRow.lineName || "报名人员"
|
||||
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.keyword = ""
|
||||
this.viewForm.unionId = ""
|
||||
this.viewTableData = []
|
||||
this.loadViewData()
|
||||
},
|
||||
loadCurrentUnion() {
|
||||
if (this.currentUnionInfo) {
|
||||
return Promise.resolve(this.currentUnionInfo)
|
||||
}
|
||||
return this.$axios.post(loc() + "/currentUnion").then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.currentUnionInfo = res.data || {}
|
||||
return this.currentUnionInfo
|
||||
}
|
||||
this.$message.warning(res.msg || "未获取到当前登录人工会")
|
||||
return Promise.reject(new Error(res.msg || "未获取到当前登录人工会"))
|
||||
})
|
||||
},
|
||||
undertakeLine(row) {
|
||||
if (!row || !row.matterId) {
|
||||
this.$message.warning("线路信息不完整")
|
||||
return
|
||||
}
|
||||
if (this.isClaimed(row)) {
|
||||
this.$message.warning("当前线路已领办,不允许修改")
|
||||
return
|
||||
}
|
||||
this.loadCurrentUnion().then((union) => {
|
||||
const lineName = row.lineName || "当前线路"
|
||||
const unionName = (union && union.unionName) || ""
|
||||
return this.$confirm(lineName + "由" + unionName + "领办,领办后,系统不允许修改,请确认。", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
return this.$axios.post(loc() + "/undertakeLine", {
|
||||
matterId: row.matterId
|
||||
})
|
||||
})
|
||||
}).then((res) => {
|
||||
if (!res) return
|
||||
if (res.code === 0) {
|
||||
this.$message.success("领办成功")
|
||||
this.pageData()
|
||||
} else {
|
||||
this.$message.warning(res.msg || "领办失败")
|
||||
}
|
||||
}).catch(() => {})
|
||||
},
|
||||
releaseUndertakeLine(row) {
|
||||
if (!row || !row.matterId) {
|
||||
this.$message.warning("线路信息不完整")
|
||||
return
|
||||
}
|
||||
if (!this.isClaimed(row)) {
|
||||
this.$message.warning("当前线路未领办,无需解除")
|
||||
return
|
||||
}
|
||||
const lineName = row.lineName || "当前线路"
|
||||
this.$confirm("确认解除【" + lineName + "】的领办状态吗?解除后该线路将变为未领。", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
return this.$axios.post(loc() + "/releaseUndertakeLine", {
|
||||
matterId: row.matterId
|
||||
})
|
||||
}).then((res) => {
|
||||
if (!res) return
|
||||
if (res.code === 0) {
|
||||
this.$message.success("解除成功")
|
||||
this.pageData()
|
||||
} else {
|
||||
this.$message.warning(res.msg || "解除失败")
|
||||
}
|
||||
}).catch(() => {})
|
||||
},
|
||||
viewSearch() {
|
||||
this.viewForm.pageNumber = 1
|
||||
this.loadViewData()
|
||||
},
|
||||
viewReset() {
|
||||
this.viewForm.keyword = ""
|
||||
this.viewForm.unionId = ""
|
||||
this.viewForm.pageNumber = 1
|
||||
this.loadViewData()
|
||||
},
|
||||
viewIndexMethod(index) {
|
||||
return (this.viewForm.pageNumber - 1) * this.viewForm.pageSize + index + 1
|
||||
},
|
||||
viewSizeChange(size) {
|
||||
this.viewForm.pageSize = size
|
||||
this.viewForm.pageNumber = 1
|
||||
this.loadViewData()
|
||||
},
|
||||
viewCurrentChange(page) {
|
||||
this.viewForm.pageNumber = page
|
||||
this.loadViewData()
|
||||
},
|
||||
viewPageOrder({ prop, order }) {
|
||||
this.viewForm.pageOrderName = prop || "signupTime"
|
||||
this.viewForm.pageOrderBy = order || "descending"
|
||||
this.viewForm.pageNumber = 1
|
||||
this.loadViewData()
|
||||
},
|
||||
loadViewData() {
|
||||
if (!this.viewRow || !this.viewRow.matterId) {
|
||||
this.viewTableData = []
|
||||
this.viewForm.totalCount = 0
|
||||
return
|
||||
}
|
||||
this.viewLoading = true
|
||||
const requestSeq = ++this.viewRequestSeq
|
||||
this.$axios.post(loc() + "/signupPageData", {
|
||||
matterId: this.viewRow.matterId,
|
||||
keyword: this.viewForm.keyword,
|
||||
unionId: this.viewForm.unionId,
|
||||
pageNumber: this.viewForm.pageNumber,
|
||||
pageSize: this.viewForm.pageSize,
|
||||
pageOrderName: this.viewForm.pageOrderName,
|
||||
pageOrderBy: this.viewForm.pageOrderBy
|
||||
}).then((res) => {
|
||||
if (requestSeq !== this.viewRequestSeq) return
|
||||
if (res.code === 0) {
|
||||
const data = res.data || {}
|
||||
this.viewTableData = data.list || []
|
||||
this.viewForm.totalCount = data.totalCount || 0
|
||||
} else {
|
||||
this.$message.warning(res.msg || "查询失败")
|
||||
}
|
||||
}).finally(() => {
|
||||
if (requestSeq === this.viewRequestSeq) {
|
||||
this.viewLoading = false
|
||||
}
|
||||
})
|
||||
},
|
||||
loadUnionOptions() {
|
||||
this.$axios.post(loc() + "/unionOptions").then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.unionOptions = res.data || []
|
||||
}
|
||||
})
|
||||
},
|
||||
loadLineTypeOptions() {
|
||||
this.$axios.post(loc() + "/lineTypeOptions", {
|
||||
year: this.pageForm.year
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.lineTypeOptions = (res.data || []).filter(item => item.lineType)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadUnionOptions()
|
||||
this.loadLineTypeOptions()
|
||||
this.pageData()
|
||||
},
|
||||
watch: {
|
||||
"pageForm.year"() {
|
||||
this.pageForm.lineType = ""
|
||||
this.loadLineTypeOptions()
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.tour-group-view-drawer .el-drawer__body {
|
||||
background: #f5f7fa;
|
||||
padding: 12px;
|
||||
overflow: auto;
|
||||
}
|
||||
.tour-group-view-pagination {
|
||||
margin-top: 12px;
|
||||
text-align: right;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
.tour-family-list {
|
||||
padding: 8px 32px;
|
||||
}
|
||||
.tour-family-empty {
|
||||
color: #909399;
|
||||
padding: 8px 32px;
|
||||
}
|
||||
.tour-undertake-tip {
|
||||
margin-top: 8px;
|
||||
color: #f56c6c;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
.el-table .direct-family-row > td,
|
||||
.el-table .direct-family-row > td .cell {
|
||||
color: #f56c6c;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -190,8 +190,8 @@ layout("/layouts/platform.html"){
|
||||
<el-descriptions-item label="报名线路">{{ detail.lineName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="出行时段">{{ detail.travelPeriod || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="线路类型">{{ detail.lineType || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="报名酒店">{{ detail.hotelName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="旅行社">{{ detail.travelAgencyName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item v-if="false" label="报名酒店">{{ detail.hotelName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item v-if="false" label="旅行社">{{ detail.travelAgencyName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="是否携带家属">
|
||||
{{ familyText() }}
|
||||
</el-descriptions-item>
|
||||
|
||||
@@ -163,8 +163,8 @@ layout("/layouts/platform.html"){
|
||||
<el-descriptions-item label="报名时间">{{ detail.signupTime || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="报名线路">{{ detail.lineName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="线路类型">{{ detail.lineType || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="报名酒店">{{ detail.hotelName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="报名旅行社">{{ detail.travelAgencyName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item v-if="false" label="报名酒店">{{ detail.hotelName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item v-if="false" label="报名旅行社">{{ detail.travelAgencyName || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="出行时间">{{ detail.travelPeriod || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item v-if="fillBedInfo" label="床型">{{ detail.bedType || '' }}</el-descriptions-item>
|
||||
<el-descriptions-item v-if="fillBedInfo" label="床位信息">{{ detail.bedInfo || '' }}</el-descriptions-item>
|
||||
|
||||
@@ -380,7 +380,7 @@ layout("/layouts/platform_h5.html"){
|
||||
<van-button v-if="canRevoke(row)" size="small" type="danger" plain @click="revokeSignup(row)">撤回</van-button>
|
||||
<van-button v-if="showCancel(row)" size="small" type="danger" plain :disabled="isTravelEnded(row)" @click="cancelByRow(row)">取消报名</van-button>
|
||||
<van-button v-if="showExport(row)" size="small" type="info" plain :disabled="!canExport(row)" @click="downloadExport(row, 'cost')">报销申请</van-button>
|
||||
<van-button v-if="showDirectRelativeExport(row)" size="small" type="info" plain :disabled="!canDirectRelativeExport(row)" @click="downloadExport(row, 'direct')">亲属线路申请</van-button>
|
||||
<van-button v-if="showDirectRelativeExport(row)" size="small" type="info" plain :disabled="!canDirectRelativeExport(row)" @click="downloadExport(row, 'direct')">下载亲属线路申请</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</van-list>
|
||||
@@ -416,6 +416,7 @@ layout("/layouts/platform_h5.html"){
|
||||
<van-cell title="姓名" :value="detail.userName || ''"></van-cell>
|
||||
<van-cell title="性别" :value="detail.gender || ''"></van-cell>
|
||||
<van-cell title="身份证号" :value="detail.idCard || ''"></van-cell>
|
||||
<van-cell title="手机号" :value="detail.mobile || ''"></van-cell>
|
||||
<van-cell title="所在单位" :value="detail.unitName || ''"></van-cell>
|
||||
<van-cell title="所在工会" :value="detail.unionName || ''"></van-cell>
|
||||
</div>
|
||||
@@ -424,8 +425,8 @@ layout("/layouts/platform_h5.html"){
|
||||
<van-cell title="报名线路" :value="detail.lineName || ''"></van-cell>
|
||||
<van-cell title="线路类型" :value="detail.lineType || ''"></van-cell>
|
||||
<van-cell title="出行时间" :value="detail.travelPeriod || ''"></van-cell>
|
||||
<van-cell title="报名酒店" :value="detail.hotelName || ''"></van-cell>
|
||||
<van-cell title="旅行社" :value="detail.travelAgencyName || ''"></van-cell>
|
||||
<van-cell v-if="false" title="报名酒店" :value="detail.hotelName || ''"></van-cell>
|
||||
<van-cell v-if="false" title="旅行社" :value="detail.travelAgencyName || ''"></van-cell>
|
||||
<van-cell v-if="detailFillBedInfo" title="床型" :value="detail.bedType || ''"></van-cell>
|
||||
<van-cell v-if="detailFillBedInfo" title="床位信息" :value="detail.bedInfo || ''"></van-cell>
|
||||
<van-cell v-if="detailFillBedInfo" title="意向拼床人" :value="detail.intendedRoommate || ''"></van-cell>
|
||||
@@ -469,7 +470,8 @@ layout("/layouts/platform_h5.html"){
|
||||
<div class="tour-section-title">教职工信息</div>
|
||||
<van-field label="姓名" readonly v-model="signupForm.userName"></van-field>
|
||||
<van-field label="工号" readonly v-model="signupForm.jobNo"></van-field>
|
||||
<van-field label="身份证号" v-model="signupForm.idCard" maxlength="30" placeholder="请填写身份证号"></van-field>
|
||||
<van-field required label="身份证号" v-model="signupForm.idCard" maxlength="30" placeholder="请填写身份证号"></van-field>
|
||||
<van-field required label="手机号" v-model="signupForm.mobile" type="tel" maxlength="30" placeholder="请填写手机号"></van-field>
|
||||
<van-field label="所在工会" readonly v-model="signupForm.unionName"></van-field>
|
||||
</div>
|
||||
|
||||
@@ -478,7 +480,7 @@ layout("/layouts/platform_h5.html"){
|
||||
<van-field label="报名线路" readonly v-model="signupForm.lineName"></van-field>
|
||||
<van-field label="线路类型" readonly v-model="signupForm.lineType"></van-field>
|
||||
<van-field label="出行时间" readonly v-model="signupForm.travelPeriod"></van-field>
|
||||
<van-field label="报名酒店" v-model="signupForm.hotelName" maxlength="100" placeholder="请输入报名酒店"></van-field>
|
||||
<van-field v-if="false" label="报名酒店" v-model="signupForm.hotelName" maxlength="100" placeholder="请输入报名酒店"></van-field>
|
||||
<van-field v-if="fillBedInfo" readonly clickable is-link label="床型" v-model="signupForm.bedType" placeholder="请选择床型" @click="openBedPicker('self')"></van-field>
|
||||
<van-field v-if="fillBedInfo" label="床位信息" v-model="signupForm.bedInfo" maxlength="100" placeholder="请输入床位信息"></van-field>
|
||||
<van-field v-if="fillBedInfo" label="意向拼床人" v-model="signupForm.intendedRoommate" maxlength="100" placeholder="请输入意向拼床人"></van-field>
|
||||
@@ -783,6 +785,7 @@ layout("/layouts/platform_h5.html"){
|
||||
userName: "",
|
||||
gender: "",
|
||||
idCard: "",
|
||||
mobile: "",
|
||||
unitId: "",
|
||||
unitName: "",
|
||||
unionId: "",
|
||||
@@ -821,12 +824,9 @@ layout("/layouts/platform_h5.html"){
|
||||
overCostReimbursed: ledger.overCostReimbursed === true || ledger.overCostReimbursed === 1 || ledger.overCostReimbursed === "1",
|
||||
hasFamily: ledger.hasFamily === true || ledger.hasFamily === 1 || ledger.hasFamily === "1"
|
||||
})
|
||||
this.directRelativeForm = Object.assign(this.emptyDirectRelative(), directRelative, {
|
||||
lineId: matter.lineId || "",
|
||||
lineName: matter.lineName || "",
|
||||
travelStartTime: matter.travelStartTime || "",
|
||||
travelEndTime: matter.travelEndTime || ""
|
||||
})
|
||||
this.directRelativeForm = Object.assign(this.emptyDirectRelative(), {
|
||||
lineId: matter.lineId || ""
|
||||
}, directRelative)
|
||||
this.familyData = (data.families || []).map(item => Object.assign(this.emptyFamily(), item))
|
||||
if (this.familyData.length > 0) {
|
||||
this.signupForm.hasFamily = true
|
||||
@@ -861,9 +861,9 @@ layout("/layouts/platform_h5.html"){
|
||||
relationshipCode: "",
|
||||
relationshipName: "",
|
||||
lineId: this.signupForm.lineId || "",
|
||||
lineName: this.signupForm.lineName || "",
|
||||
travelStartTime: this.signupForm.travelStartTime || "",
|
||||
travelEndTime: this.signupForm.travelEndTime || ""
|
||||
lineName: "",
|
||||
travelStartTime: "",
|
||||
travelEndTime: ""
|
||||
}
|
||||
},
|
||||
addFamily() {
|
||||
@@ -956,8 +956,19 @@ layout("/layouts/platform_h5.html"){
|
||||
}
|
||||
return true
|
||||
},
|
||||
validateSelfInfo() {
|
||||
if (!String(this.signupForm.idCard || "").trim()) {
|
||||
vant.Toast("请输入身份证号")
|
||||
return false
|
||||
}
|
||||
if (!String(this.signupForm.mobile || "").trim()) {
|
||||
vant.Toast("请输入手机号")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
submitSignup() {
|
||||
if (!this.validateFamilies() || !this.validateDirectRelative()) return
|
||||
if (!this.validateSelfInfo() || !this.validateFamilies() || !this.validateDirectRelative()) return
|
||||
const families = this.allowFamily && this.signupForm.hasFamily ? this.familyData : []
|
||||
const form = Object.assign({}, this.signupForm, {
|
||||
families: JSON.stringify(families),
|
||||
|
||||
+3
-2
@@ -205,6 +205,7 @@ layout("/layouts/platform_h5.html"){
|
||||
<van-cell title="姓名" :value="detail.userName || ''"></van-cell>
|
||||
<van-cell title="性别" :value="detail.gender || ''"></van-cell>
|
||||
<van-cell title="身份证号" :value="detail.idCard || ''"></van-cell>
|
||||
<van-cell title="手机号" :value="detail.mobile || ''"></van-cell>
|
||||
<van-cell title="所在单位" :value="detail.unitName || ''"></van-cell>
|
||||
<van-cell title="所在工会" :value="detail.unionName || ''"></van-cell>
|
||||
</div>
|
||||
@@ -215,8 +216,8 @@ layout("/layouts/platform_h5.html"){
|
||||
<van-cell title="线路类型" :value="detail.lineType || ''"></van-cell>
|
||||
<van-cell title="出行时段" :value="detail.travelPeriod || ''"></van-cell>
|
||||
<van-cell title="报名时间" :value="detail.signupTime || ''"></van-cell>
|
||||
<van-cell title="报名酒店" :value="detail.hotelName || ''"></van-cell>
|
||||
<van-cell title="旅行社" :value="detail.travelAgencyName || ''"></van-cell>
|
||||
<van-cell v-if="false" title="报名酒店" :value="detail.hotelName || ''"></van-cell>
|
||||
<van-cell v-if="false" title="旅行社" :value="detail.travelAgencyName || ''"></van-cell>
|
||||
<van-cell v-if="fillBedInfo" title="床型" :value="detail.bedType || ''"></van-cell>
|
||||
<van-cell v-if="fillBedInfo" title="床位信息" :value="detail.bedInfo || ''"></van-cell>
|
||||
<van-cell v-if="fillBedInfo" title="意向拼床人" :value="detail.intendedRoommate || ''"></van-cell>
|
||||
|
||||
@@ -109,8 +109,8 @@ layout("/layouts/platform_h5.html"){
|
||||
<div class="tour-apply-title">教职工信息</div>
|
||||
<van-field label="姓名" readonly v-model="signupForm.userName"></van-field>
|
||||
<van-field label="工号" readonly v-model="signupForm.jobNo"></van-field>
|
||||
<van-field label="身份证号码" v-model="signupForm.idCard" maxlength="30" placeholder="请填写身份证号码"></van-field>
|
||||
<van-field label="手机号" v-model="signupForm.mobile" type="tel" maxlength="30" placeholder="请填写手机号"></van-field>
|
||||
<van-field required label="身份证号码" v-model="signupForm.idCard" maxlength="30" placeholder="请填写身份证号码"></van-field>
|
||||
<van-field required label="手机号" v-model="signupForm.mobile" type="tel" maxlength="30" placeholder="请填写手机号"></van-field>
|
||||
<van-field label="所属工会" readonly v-model="signupForm.unionName"></van-field>
|
||||
</div>
|
||||
|
||||
@@ -119,7 +119,7 @@ layout("/layouts/platform_h5.html"){
|
||||
<van-field label="报名线路" readonly v-model="signupForm.lineName"></van-field>
|
||||
<van-field label="线路类型" readonly v-model="signupForm.lineType"></van-field>
|
||||
<van-field v-if="signupForm.travelPeriod" label="出行时间" readonly v-model="signupForm.travelPeriod"></van-field>
|
||||
<van-field label="报名酒店" v-model="signupForm.hotelName" maxlength="100" placeholder="请输入报名酒店"></van-field>
|
||||
<van-field v-if="false" label="报名酒店" v-model="signupForm.hotelName" maxlength="100" placeholder="请输入报名酒店"></van-field>
|
||||
<van-field
|
||||
v-if="fillBedInfo"
|
||||
label="床型"
|
||||
@@ -256,7 +256,8 @@ layout("/layouts/platform_h5.html"){
|
||||
relationshipPickerVisible: false,
|
||||
directRelativePickerVisible: false,
|
||||
bedPickerTarget: "self",
|
||||
matterId: GetQueryString("matterId") || ""
|
||||
matterId: GetQueryString("matterId") || "",
|
||||
noticeChecked: GetQueryString("noticeChecked") === "1"
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -280,25 +281,42 @@ layout("/layouts/platform_h5.html"){
|
||||
this.pageLoading = false
|
||||
return
|
||||
}
|
||||
Promise.all([this.loadOptions(), this.loadSignupDetail()]).finally(() => {
|
||||
this.loadOptions().catch(() => {})
|
||||
this.loadSignupDetail().finally(() => {
|
||||
this.pageLoading = false
|
||||
})
|
||||
},
|
||||
loadOptions() {
|
||||
return Promise.all([
|
||||
this.$axios.post("/platform/tour/signup/bedTypeOptions").then(res => {
|
||||
if (res.code === 0) this.bedTypeOptions = res.data || []
|
||||
}),
|
||||
this.$axios.post("/platform/tour/signup/familyRelationshipOptions").then(res => {
|
||||
if (res.code === 0) this.familyRelationshipOptions = res.data || []
|
||||
}),
|
||||
this.$axios.post("/platform/tour/signup/directRelativeOptions").then(res => {
|
||||
if (res.code === 0) this.directRelativeOptions = res.data || []
|
||||
})
|
||||
])
|
||||
const cacheKey = "tourSignupOptions"
|
||||
try {
|
||||
const cached = JSON.parse(sessionStorage.getItem(cacheKey) || "null")
|
||||
if (cached && cached.data) {
|
||||
this.applyOptions(cached.data)
|
||||
return Promise.resolve(cached.data)
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
return this.$axios.post("/platform/tour/signup/signupOptions").then(res => {
|
||||
if (res.code === 0) {
|
||||
const data = res.data || {}
|
||||
this.applyOptions(data)
|
||||
try {
|
||||
sessionStorage.setItem(cacheKey, JSON.stringify({data: data}))
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
applyOptions(data) {
|
||||
this.bedTypeOptions = data.bedTypeOptions || []
|
||||
this.familyRelationshipOptions = data.familyRelationshipOptions || []
|
||||
this.directRelativeOptions = data.directRelativeOptions || []
|
||||
},
|
||||
loadSignupDetail() {
|
||||
return this.$axios.post("/platform/tour/signup/signupDetail", { matterId: this.matterId }).then((res) => {
|
||||
return this.$axios.post("/platform/tour/signup/signupDetail", {
|
||||
matterId: this.matterId,
|
||||
noticeChecked: this.noticeChecked
|
||||
}).then((res) => {
|
||||
if (res.code !== 0) {
|
||||
vant.Dialog.alert({
|
||||
title: "提示",
|
||||
@@ -361,10 +379,7 @@ layout("/layouts/platform_h5.html"){
|
||||
hasFamily: ledger.hasFamily === true || ledger.hasFamily === 1 || ledger.hasFamily === "1"
|
||||
})
|
||||
this.directRelativeForm = Object.assign(this.emptyDirectRelative(), {
|
||||
lineId: matter.lineId || "",
|
||||
lineName: matter.lineName || "",
|
||||
travelStartTime: matter.travelStartTime || "",
|
||||
travelEndTime: matter.travelEndTime || ""
|
||||
lineId: matter.lineId || ""
|
||||
}, directRelative)
|
||||
this.familyData = (data.families || []).map(item => Object.assign(this.emptyFamily(), item))
|
||||
if (this.familyData.length > 0) {
|
||||
@@ -398,9 +413,9 @@ layout("/layouts/platform_h5.html"){
|
||||
relationshipCode: "",
|
||||
relationshipName: "",
|
||||
lineId: this.signupForm.lineId || "",
|
||||
lineName: this.signupForm.lineName || "",
|
||||
travelStartTime: this.signupForm.travelStartTime || "",
|
||||
travelEndTime: this.signupForm.travelEndTime || ""
|
||||
lineName: "",
|
||||
travelStartTime: "",
|
||||
travelEndTime: ""
|
||||
}
|
||||
},
|
||||
isDirectFamilyLine(row) {
|
||||
@@ -512,8 +527,20 @@ layout("/layouts/platform_h5.html"){
|
||||
}
|
||||
return true
|
||||
},
|
||||
validateSelfInfo() {
|
||||
if (!String(this.signupForm.idCard || "").trim()) {
|
||||
vant.Toast("请输入身份证号码")
|
||||
return false
|
||||
}
|
||||
if (!String(this.signupForm.mobile || "").trim()) {
|
||||
vant.Toast("请输入手机号")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
submitSignup() {
|
||||
if (this.pageLoading || this.submitLoading) return
|
||||
if (!this.validateSelfInfo()) return
|
||||
if (!this.validateFamilies()) return
|
||||
if (!this.validateDirectRelative()) return
|
||||
const families = this.allowFamily && this.signupForm.hasFamily ? this.familyData : []
|
||||
|
||||
@@ -153,7 +153,7 @@ layout("/layouts/platform_h5.html"){
|
||||
</div>
|
||||
|
||||
<div class="tour-signup-footer">
|
||||
<van-button block type="info" color="#0f74bc" round @click="confirmRead">我已阅读</van-button>
|
||||
<van-button block type="info" color="#0f74bc" round :loading="readLoading" :disabled="readLoading" loading-text="进入中..." @click="confirmRead">我已阅读</van-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -167,6 +167,7 @@ layout("/layouts/platform_h5.html"){
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
readLoading: false,
|
||||
currentYear: new Date().getFullYear(),
|
||||
serviceNoticeKey: "",
|
||||
bannerList: [
|
||||
@@ -196,7 +197,15 @@ layout("/layouts/platform_h5.html"){
|
||||
})
|
||||
},
|
||||
confirmRead() {
|
||||
window.location.href = "/platform/tour/signup/h5/signup"
|
||||
if (this.readLoading) {
|
||||
return
|
||||
}
|
||||
this.readLoading = true
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
window.location.href = "/platform/tour/signup/h5/signup"
|
||||
}, 80)
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
+568
-147
@@ -81,6 +81,14 @@ layout("/layouts/platform_h5.html"){
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.tour-signup-people-link {
|
||||
margin-left: 4px;
|
||||
color: #d40000;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
.tour-detail-section {
|
||||
margin-top: 10px;
|
||||
min-height: 0;
|
||||
@@ -105,9 +113,16 @@ layout("/layouts/platform_h5.html"){
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.tour-detail-content /deep/ img {
|
||||
.tour-detail-content {
|
||||
color: #334155;
|
||||
font-size: 14px;
|
||||
line-height: 1.75;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.tour-detail-content /deep/ img,
|
||||
.tour-detail-content /deep/ iframe {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.tour-detail-section-scroll {
|
||||
@@ -117,39 +132,73 @@ layout("/layouts/platform_h5.html"){
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.tour-pdf-preview {
|
||||
min-height: 220px;
|
||||
.tour-detail-content /deep/ .tour-line-file-preview-box {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.tour-pdf-status {
|
||||
padding: 16px 0;
|
||||
color: #64748b;
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tour-pdf-toolbar {
|
||||
margin-bottom: 8px;
|
||||
color: #64748b;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.tour-pdf-pages {
|
||||
.tour-detail-content /deep/ .tour-pdf-lazy-preview {
|
||||
margin-top: 10px;
|
||||
min-height: 180px;
|
||||
}
|
||||
|
||||
.tour-pdf-page {
|
||||
margin-bottom: 10px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #dcdfe6;
|
||||
overflow: hidden;
|
||||
background: #f8fafc;
|
||||
box-shadow: 0 1px 4px rgba(15, 23, 42, 0.08);
|
||||
}
|
||||
|
||||
.tour-pdf-page canvas {
|
||||
width: 100%;
|
||||
.tour-detail-content /deep/ .tour-pdf-lazy-toolbar {
|
||||
padding: 0 10px;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
color: #64748b;
|
||||
font-size: 12px;
|
||||
line-height: 32px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.tour-detail-content /deep/ .tour-pdf-page-placeholder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 180px;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
color: #94a3b8;
|
||||
font-size: 13px;
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.tour-detail-content /deep/ .tour-pdf-page-placeholder canvas {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
margin: 0 auto;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.tour-detail-content /deep/ .tour-line-file-preview {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 70vh;
|
||||
min-height: 420px;
|
||||
border: 1px solid #dcdfe6;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.tour-detail-content /deep/ .tour-line-image-preview {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-height: 70vh;
|
||||
height: auto;
|
||||
margin-top: 10px;
|
||||
border: 1px solid #dcdfe6;
|
||||
object-fit: contain;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.tour-detail-content /deep/ .tour-line-file-unpreviewable {
|
||||
margin-top: 10px;
|
||||
padding: 12px;
|
||||
border: 1px solid #e5e7eb;
|
||||
color: #94a3b8;
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.tour-detail-empty {
|
||||
@@ -170,6 +219,99 @@ layout("/layouts/platform_h5.html"){
|
||||
background: #ffffff;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.tour-people-popup {
|
||||
height: 72vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #ffffff;
|
||||
overflow: hidden;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.tour-people-popup-title {
|
||||
flex-shrink: 0;
|
||||
padding: 14px 16px 8px;
|
||||
color: #0f172a;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 22px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tour-people-search {
|
||||
flex-shrink: 0;
|
||||
padding: 0 10px 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
border-bottom: 1px solid #edf0f4;
|
||||
}
|
||||
|
||||
.tour-people-search /deep/ .van-search {
|
||||
flex: 1;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.tour-people-search-btns {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.tour-people-table {
|
||||
min-height: 0;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tour-people-table-head,
|
||||
.tour-people-table-row {
|
||||
display: grid;
|
||||
grid-template-columns: 54px minmax(88px, 1fr) minmax(128px, 1.25fr);
|
||||
align-items: center;
|
||||
min-height: 42px;
|
||||
border-bottom: 1px solid #edf0f4;
|
||||
color: #0f172a;
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.tour-people-table-head {
|
||||
flex-shrink: 0;
|
||||
background: #f8fafc;
|
||||
color: #334155;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.tour-people-table-cell {
|
||||
min-width: 0;
|
||||
padding: 9px 8px;
|
||||
text-align: center;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.tour-people-sort {
|
||||
color: #0b75bd;
|
||||
}
|
||||
|
||||
.tour-people-table-body {
|
||||
min-height: 0;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.tour-people-empty {
|
||||
padding: 22px 0;
|
||||
color: #94a3b8;
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app">
|
||||
@@ -192,7 +334,10 @@ layout("/layouts/platform_h5.html"){
|
||||
</div>
|
||||
<div class="tour-detail-meta-row">
|
||||
<span class="tour-detail-meta-label"><span>已报人数</span><span>:</span></span>
|
||||
<span class="tour-detail-meta-value">{{ signupDetail.signupCount || 0 }}(家属{{ signupDetail.familyCount || 0 }}人)</span>
|
||||
<span class="tour-detail-meta-value">
|
||||
{{ signupDetail.signupCount || 0 }}(家属{{ signupDetail.familyCount || 0 }}人)
|
||||
<span class="tour-signup-people-link" @click.stop="openPeoplePopup">查看</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="tour-detail-meta-row">
|
||||
<span class="tour-detail-meta-label"><span>联系人</span><span>:</span></span>
|
||||
@@ -207,20 +352,7 @@ layout("/layouts/platform_h5.html"){
|
||||
<div class="tour-detail-section">
|
||||
<div class="tour-detail-section-title">线路介绍</div>
|
||||
<div class="tour-detail-section-scroll">
|
||||
<div v-if="lineDetail.lineContent && lineContentHref" class="tour-pdf-preview">
|
||||
<div v-if="pdfPageCount" class="tour-pdf-toolbar">
|
||||
已加载 {{ pdfRenderedPages }} / {{ pdfPageCount }} 页
|
||||
</div>
|
||||
<div ref="pdfPreviewContainer" class="tour-pdf-pages"></div>
|
||||
<div v-if="pdfLoading && pdfRenderedPages === 0" class="tour-pdf-status">
|
||||
<van-loading size="22px" vertical>正在加载第一页...</van-loading>
|
||||
</div>
|
||||
<div v-else-if="pdfLoading" class="tour-pdf-status">
|
||||
正在继续加载后续页面...
|
||||
</div>
|
||||
<div v-if="pdfError" class="tour-pdf-status">{{ pdfError }}</div>
|
||||
</div>
|
||||
<div v-else-if="lineDetail.lineContent" class="tour-detail-content" v-html="lineDetail.lineContent">
|
||||
<div v-if="lineDetail.lineContent" class="tour-detail-content" v-html="lineContentHtml">
|
||||
</div>
|
||||
<div v-else class="tour-detail-empty">暂无线路介绍</div>
|
||||
</div>
|
||||
@@ -229,10 +361,51 @@ layout("/layouts/platform_h5.html"){
|
||||
</div>
|
||||
|
||||
<div class="tour-detail-footer">
|
||||
<van-button :type="detailActionType()" block round :disabled="detailActionDisabled()" @click="handleDetailAction">
|
||||
<van-button :type="detailActionType()" block round :loading="applyLoading" :disabled="detailActionDisabled() || applyLoading" @click="handleDetailAction">
|
||||
{{ detailActionText() }}
|
||||
</van-button>
|
||||
</div>
|
||||
|
||||
<van-popup v-model="peopleVisible" position="bottom" round>
|
||||
<div class="tour-people-popup">
|
||||
<div class="tour-people-popup-title">报名人员</div>
|
||||
<div class="tour-people-search">
|
||||
<van-search
|
||||
v-model="peopleForm.keyword"
|
||||
shape="round"
|
||||
placeholder="请输入姓名或工号"
|
||||
@search="peopleSearch">
|
||||
</van-search>
|
||||
<div class="tour-people-search-btns">
|
||||
<van-button size="small" type="info" @click="peopleSearch">搜索</van-button>
|
||||
<van-button size="small" plain @click="peopleReset">重置</van-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tour-people-table">
|
||||
<div class="tour-people-table-head">
|
||||
<div class="tour-people-table-cell">序号</div>
|
||||
<div class="tour-people-table-cell">姓名</div>
|
||||
<div class="tour-people-table-cell tour-people-sort" @click="togglePeopleUnionSort">
|
||||
所属工会{{ peopleSortText() }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="tour-people-table-body">
|
||||
<van-list
|
||||
v-model="peopleLoading"
|
||||
:finished="peopleFinished"
|
||||
finished-text="没有更多了"
|
||||
@load="loadPeople">
|
||||
<div v-for="item in peopleList" :key="item.id" class="tour-people-table-row">
|
||||
<div class="tour-people-table-cell">{{ item.displayIndex }}</div>
|
||||
<div class="tour-people-table-cell">{{ item.userName || '' }}</div>
|
||||
<div class="tour-people-table-cell">{{ item.unionName || '' }}</div>
|
||||
</div>
|
||||
</van-list>
|
||||
<div v-if="!peopleLoading && peopleList.length === 0" class="tour-people-empty">暂无报名人员</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
@@ -242,16 +415,25 @@ layout("/layouts/platform_h5.html"){
|
||||
data() {
|
||||
return {
|
||||
detailLoading: true,
|
||||
applyLoading: false,
|
||||
lineDetail: {},
|
||||
signupDetail: {},
|
||||
lineContentHref: "",
|
||||
pdfDoc: null,
|
||||
pdfLoadingTask: null,
|
||||
pdfLoading: false,
|
||||
pdfError: "",
|
||||
pdfPageCount: 0,
|
||||
pdfRenderedPages: 0,
|
||||
pdfRenderToken: 0,
|
||||
lineContentHtml: "",
|
||||
linePdfPreviews: [],
|
||||
linePdfObserver: null,
|
||||
peopleVisible: false,
|
||||
peopleLoading: false,
|
||||
peopleFinished: true,
|
||||
peopleList: [],
|
||||
peopleForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
totalCount: 0,
|
||||
pageOrderName: "signupTime",
|
||||
pageOrderBy: "descending",
|
||||
keyword: "",
|
||||
unionId: ""
|
||||
},
|
||||
matterId: GetQueryString("matterId") || "",
|
||||
lineId: GetQueryString("lineId") || ""
|
||||
}
|
||||
@@ -314,6 +496,94 @@ layout("/layouts/platform_h5.html"){
|
||||
detailActionDisabled() {
|
||||
return this.isSigned() && this.isApprovalSignup() && (this.isFinishedSignup() || this.isRejectedSignup() || (!this.canRevokeSignup() && !this.canModifySignup()))
|
||||
},
|
||||
peopleSortText() {
|
||||
if (this.peopleForm.pageOrderName !== "unionName") {
|
||||
return ""
|
||||
}
|
||||
return this.peopleForm.pageOrderBy === "ascending" ? "↑" : "↓"
|
||||
},
|
||||
resetPeopleData() {
|
||||
this.peopleForm.pageNumber = 1
|
||||
this.peopleForm.totalCount = 0
|
||||
this.peopleList = []
|
||||
this.peopleFinished = false
|
||||
},
|
||||
openPeoplePopup() {
|
||||
if (!this.matterId) {
|
||||
vant.Toast("报名事项信息不完整")
|
||||
return
|
||||
}
|
||||
this.peopleVisible = true
|
||||
this.peopleForm.keyword = ""
|
||||
this.peopleForm.pageOrderName = "signupTime"
|
||||
this.peopleForm.pageOrderBy = "descending"
|
||||
this.resetPeopleData()
|
||||
this.$nextTick(() => {
|
||||
this.loadPeople()
|
||||
})
|
||||
},
|
||||
peopleSearch() {
|
||||
this.resetPeopleData()
|
||||
this.loadPeople()
|
||||
},
|
||||
peopleReset() {
|
||||
this.peopleForm.keyword = ""
|
||||
this.peopleForm.pageOrderName = "signupTime"
|
||||
this.peopleForm.pageOrderBy = "descending"
|
||||
this.resetPeopleData()
|
||||
this.loadPeople()
|
||||
},
|
||||
togglePeopleUnionSort() {
|
||||
if (this.peopleForm.pageOrderName === "unionName") {
|
||||
this.peopleForm.pageOrderBy = this.peopleForm.pageOrderBy === "ascending" ? "descending" : "ascending"
|
||||
} else {
|
||||
this.peopleForm.pageOrderName = "unionName"
|
||||
this.peopleForm.pageOrderBy = "ascending"
|
||||
}
|
||||
this.resetPeopleData()
|
||||
this.loadPeople()
|
||||
},
|
||||
loadPeople() {
|
||||
if (!this.matterId || this.peopleLoading || this.peopleFinished) {
|
||||
return
|
||||
}
|
||||
this.peopleLoading = true
|
||||
this.$axios.post("/platform/tour/signup/h5/signupPageData", {
|
||||
matterId: this.matterId,
|
||||
keyword: this.peopleForm.keyword,
|
||||
unionId: this.peopleForm.unionId,
|
||||
pageNumber: this.peopleForm.pageNumber,
|
||||
pageSize: this.peopleForm.pageSize,
|
||||
pageOrderName: this.peopleForm.pageOrderName,
|
||||
pageOrderBy: this.peopleForm.pageOrderBy
|
||||
}).then((res) => {
|
||||
if (res.code !== 0) {
|
||||
vant.Toast(res.msg || "报名人员加载失败")
|
||||
this.peopleFinished = true
|
||||
return
|
||||
}
|
||||
const data = res.data || {}
|
||||
const rows = data.list || []
|
||||
const startIndex = this.peopleList.length
|
||||
const normalizedRows = rows.map((item, index) => {
|
||||
return Object.assign({}, item, {
|
||||
displayIndex: startIndex + index + 1
|
||||
})
|
||||
})
|
||||
this.peopleForm.totalCount = data.totalCount || 0
|
||||
this.peopleList = this.peopleList.concat(normalizedRows)
|
||||
if (this.peopleList.length >= this.peopleForm.totalCount || rows.length < this.peopleForm.pageSize) {
|
||||
this.peopleFinished = true
|
||||
} else {
|
||||
this.peopleForm.pageNumber += 1
|
||||
}
|
||||
}).catch(() => {
|
||||
vant.Toast("报名人员加载失败")
|
||||
this.peopleFinished = true
|
||||
}).finally(() => {
|
||||
this.peopleLoading = false
|
||||
})
|
||||
},
|
||||
handleDetailAction() {
|
||||
if (this.detailActionDisabled()) {
|
||||
return
|
||||
@@ -322,134 +592,269 @@ layout("/layouts/platform_h5.html"){
|
||||
this.revokeSignup()
|
||||
return
|
||||
}
|
||||
if (this.isSigned()) {
|
||||
this.onApply(true)
|
||||
return
|
||||
}
|
||||
this.onApply()
|
||||
},
|
||||
parseLineContentHref(content) {
|
||||
if (!content) {
|
||||
return ""
|
||||
buildLineContentHtmlAsync(content) {
|
||||
const ids = this.extractLineFileIds(content)
|
||||
if (!ids.length) {
|
||||
return Promise.resolve(this.buildLineContentHtml(content, {}))
|
||||
}
|
||||
try {
|
||||
const parser = new DOMParser()
|
||||
const doc = parser.parseFromString(content, "text/html")
|
||||
const link = doc.querySelector("a[href]")
|
||||
return link ? link.getAttribute("href") : ""
|
||||
} catch (e) {
|
||||
return ""
|
||||
return this.$axios.post("/platform/sys/file/previewFileData", {ids: JSON.stringify(ids)}).then((res) => {
|
||||
const fileMap = {}
|
||||
if (res.code === 0 && Array.isArray(res.data)) {
|
||||
res.data.forEach((file) => {
|
||||
if (file && file.id) {
|
||||
file.suffix = (file.suffix || "").toLowerCase()
|
||||
fileMap[file.id] = file
|
||||
}
|
||||
})
|
||||
}
|
||||
return this.buildLineContentHtml(content, fileMap)
|
||||
}).catch(() => this.buildLineContentHtml(content, {}))
|
||||
},
|
||||
extractLineFileIds(content) {
|
||||
if (!content) return []
|
||||
const wrap = document.createElement("div")
|
||||
wrap.innerHTML = content
|
||||
const ids = []
|
||||
Array.prototype.slice.call(wrap.querySelectorAll("a[href]")).forEach((anchor) => {
|
||||
const id = this.getFileIdFromUrl(anchor.getAttribute("href") || "")
|
||||
if (id && !ids.includes(id)) {
|
||||
ids.push(id)
|
||||
}
|
||||
})
|
||||
return ids
|
||||
},
|
||||
buildLineContentHtml(content, fileMap) {
|
||||
if (!content) return ""
|
||||
const wrap = document.createElement("div")
|
||||
wrap.innerHTML = content
|
||||
const anchors = Array.prototype.slice.call(wrap.querySelectorAll("a[href]"))
|
||||
anchors.forEach((anchor) => {
|
||||
const href = anchor.getAttribute("href") || ""
|
||||
const text = anchor.textContent || href
|
||||
const fileId = this.getFileIdFromUrl(href)
|
||||
const file = fileId && fileMap ? fileMap[fileId] : null
|
||||
const fileType = this.detectPreviewFileType(href, text, file)
|
||||
if (!fileType) {
|
||||
return
|
||||
}
|
||||
const preview = this.createLineFilePreview(href, fileType, file)
|
||||
if (anchor.parentNode && preview) {
|
||||
anchor.parentNode.replaceChild(preview, anchor)
|
||||
}
|
||||
})
|
||||
return wrap.innerHTML
|
||||
},
|
||||
detectPreviewFileType(href, text, file) {
|
||||
const suffix = file && file.suffix ? file.suffix.toLowerCase() : ""
|
||||
if (["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(suffix)) {
|
||||
return "image"
|
||||
}
|
||||
if (suffix === "pdf") {
|
||||
return "pdf"
|
||||
}
|
||||
if (["doc", "docx", "xls", "xlsx"].includes(suffix)) {
|
||||
return "office"
|
||||
}
|
||||
const lowerHref = (href || "").split("#")[0].split("?")[0].toLowerCase()
|
||||
const lowerText = (text || "").toLowerCase()
|
||||
const value = lowerHref + " " + lowerText
|
||||
if (/\.(jpg|jpeg|png|gif|bmp|webp)(\s|$)/.test(value)) {
|
||||
return "image"
|
||||
}
|
||||
if (/\.pdf(\s|$)/.test(value)) {
|
||||
return "pdf"
|
||||
}
|
||||
if (/\.(doc|docx|xls|xlsx)(\s|$)/.test(value)) {
|
||||
return "office"
|
||||
}
|
||||
return ""
|
||||
},
|
||||
createLineFilePreview(href, fileType, file) {
|
||||
if (fileType === "image") {
|
||||
const img = document.createElement("img")
|
||||
img.className = "tour-line-image-preview"
|
||||
img.src = file && file.downloadPath ? file.downloadPath : href
|
||||
img.alt = ""
|
||||
return img
|
||||
}
|
||||
const previewUrl = this.buildLinePreviewUrl(href, fileType, file)
|
||||
if (!previewUrl) {
|
||||
const tip = document.createElement("div")
|
||||
tip.className = "tour-line-file-unpreviewable"
|
||||
tip.textContent = "当前文件暂不支持预览"
|
||||
return tip
|
||||
}
|
||||
const box = document.createElement("div")
|
||||
box.className = "tour-line-file-preview-box"
|
||||
const preview = document.createElement("div")
|
||||
preview.className = "tour-pdf-lazy-preview"
|
||||
preview.setAttribute("data-pdf-url", previewUrl)
|
||||
preview.innerHTML = "<div class=\"tour-pdf-lazy-toolbar\">PDF预览加载中...</div>"
|
||||
box.appendChild(preview)
|
||||
return box
|
||||
},
|
||||
buildLinePreviewUrl(href, fileType, file) {
|
||||
if (fileType === "office") {
|
||||
const id = file && file.id ? file.id : this.getFileIdFromUrl(href)
|
||||
return id ? "/platform/sys/file/convertPDF?id=" + id : ""
|
||||
}
|
||||
if (fileType === "pdf") {
|
||||
return file && file.downloadPath ? file.downloadPath : href
|
||||
}
|
||||
return ""
|
||||
},
|
||||
getPdfLib() {
|
||||
return window.pdfjsLib || window["pdfjs-dist/build/pdf"]
|
||||
},
|
||||
clearPdfPreview() {
|
||||
this.pdfRenderToken += 1
|
||||
this.pdfDoc = null
|
||||
this.pdfLoading = false
|
||||
this.pdfError = ""
|
||||
this.pdfPageCount = 0
|
||||
this.pdfRenderedPages = 0
|
||||
if (this.pdfLoadingTask && this.pdfLoadingTask.destroy) {
|
||||
try {
|
||||
this.pdfLoadingTask.destroy()
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
this.pdfLoadingTask = null
|
||||
if (this.$refs.pdfPreviewContainer) {
|
||||
this.$refs.pdfPreviewContainer.innerHTML = ""
|
||||
}
|
||||
},
|
||||
renderLinePdf() {
|
||||
this.clearPdfPreview()
|
||||
if (!this.lineContentHref) {
|
||||
initLinePdfPreviews() {
|
||||
this.cleanupLinePdfPreviews()
|
||||
const pdfLib = this.getPdfLib()
|
||||
const previews = Array.prototype.slice.call(document.querySelectorAll(".tour-pdf-lazy-preview"))
|
||||
if (!previews.length) {
|
||||
return
|
||||
}
|
||||
const pdfLib = this.getPdfLib()
|
||||
if (!pdfLib || !pdfLib.getDocument) {
|
||||
this.pdfError = "PDF预览组件加载失败"
|
||||
previews.forEach((el) => {
|
||||
el.innerHTML = "<div class=\"tour-line-file-unpreviewable\">PDF预览组件加载失败</div>"
|
||||
})
|
||||
return
|
||||
}
|
||||
if (pdfLib.GlobalWorkerOptions) {
|
||||
pdfLib.GlobalWorkerOptions.workerSrc = "/assets/platform/plugins/pdfJs/h5/pdf.worker.js"
|
||||
}
|
||||
const token = this.pdfRenderToken
|
||||
this.pdfLoading = true
|
||||
this.pdfLoadingTask = pdfLib.getDocument({
|
||||
url: this.lineContentHref,
|
||||
disableAutoFetch: false,
|
||||
disableStream: false,
|
||||
disableRange: false
|
||||
})
|
||||
this.pdfLoadingTask.promise.then((pdf) => {
|
||||
if (token !== this.pdfRenderToken) {
|
||||
return
|
||||
}
|
||||
this.pdfDoc = pdf
|
||||
this.pdfPageCount = pdf.numPages || 0
|
||||
return this.renderPdfPage(1, token)
|
||||
}).then(() => {
|
||||
if (token !== this.pdfRenderToken) {
|
||||
return
|
||||
}
|
||||
this.renderRestPdfPages(2, token)
|
||||
}).catch(() => {
|
||||
if (token !== this.pdfRenderToken) {
|
||||
return
|
||||
}
|
||||
this.pdfLoading = false
|
||||
this.pdfError = "PDF加载失败,请稍后重试"
|
||||
if (window.IntersectionObserver) {
|
||||
this.linePdfObserver = new IntersectionObserver((entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (!entry.isIntersecting) {
|
||||
return
|
||||
}
|
||||
this.renderLazyPdfPage(entry.target)
|
||||
this.linePdfObserver && this.linePdfObserver.unobserve(entry.target)
|
||||
})
|
||||
}, {
|
||||
root: null,
|
||||
rootMargin: "360px 0px",
|
||||
threshold: 0.01
|
||||
})
|
||||
}
|
||||
previews.forEach((el) => {
|
||||
this.initLazyPdfPreview(el, pdfLib)
|
||||
})
|
||||
},
|
||||
renderPdfPage(pageNumber, token) {
|
||||
if (!this.pdfDoc || token !== this.pdfRenderToken || pageNumber > this.pdfPageCount) {
|
||||
return Promise.resolve()
|
||||
initLazyPdfPreview(el, pdfLib) {
|
||||
const url = el.getAttribute("data-pdf-url")
|
||||
if (!url) {
|
||||
el.innerHTML = "<div class=\"tour-line-file-unpreviewable\">当前文件暂不支持预览</div>"
|
||||
return
|
||||
}
|
||||
return this.pdfDoc.getPage(pageNumber).then((page) => {
|
||||
if (token !== this.pdfRenderToken || !this.$refs.pdfPreviewContainer) {
|
||||
return
|
||||
const task = pdfLib.getDocument({
|
||||
url: url,
|
||||
disableAutoFetch: true,
|
||||
disableStream: true,
|
||||
disableRange: false
|
||||
})
|
||||
const state = {
|
||||
el: el,
|
||||
doc: null,
|
||||
task: task,
|
||||
rendered: {},
|
||||
rendering: {}
|
||||
}
|
||||
this.linePdfPreviews.push(state)
|
||||
task.promise.then((pdf) => {
|
||||
state.doc = pdf
|
||||
const count = pdf.numPages || 0
|
||||
const toolbar = el.querySelector(".tour-pdf-lazy-toolbar")
|
||||
if (toolbar) {
|
||||
toolbar.textContent = "PDF预览:共 " + count + " 页,已优先加载第 1 页"
|
||||
}
|
||||
const container = this.$refs.pdfPreviewContainer
|
||||
for (let i = 1; i <= count; i++) {
|
||||
const page = document.createElement("div")
|
||||
page.className = "tour-pdf-page-placeholder"
|
||||
page.setAttribute("data-page-number", i)
|
||||
page.textContent = i === 1 ? "正在加载第 1 页..." : "第 " + i + " 页,滚动到此处加载"
|
||||
el.appendChild(page)
|
||||
}
|
||||
const firstPage = el.querySelector("[data-page-number='1']")
|
||||
if (firstPage) {
|
||||
this.renderLazyPdfPage(firstPage)
|
||||
}
|
||||
Array.prototype.slice.call(el.querySelectorAll(".tour-pdf-page-placeholder")).forEach((page) => {
|
||||
if (page.getAttribute("data-page-number") !== "1" && this.linePdfObserver) {
|
||||
this.linePdfObserver.observe(page)
|
||||
}
|
||||
})
|
||||
}).catch(() => {
|
||||
el.innerHTML = "<div class=\"tour-line-file-unpreviewable\">PDF加载失败,请稍后重试</div>"
|
||||
})
|
||||
},
|
||||
renderLazyPdfPage(pageEl) {
|
||||
const previewEl = pageEl.closest(".tour-pdf-lazy-preview")
|
||||
const state = this.linePdfPreviews.find((item) => item.el === previewEl)
|
||||
if (!state || !state.doc) {
|
||||
return
|
||||
}
|
||||
const pageNumber = Number(pageEl.getAttribute("data-page-number") || 0)
|
||||
if (!pageNumber || state.rendered[pageNumber] || state.rendering[pageNumber]) {
|
||||
return
|
||||
}
|
||||
state.rendering[pageNumber] = true
|
||||
pageEl.textContent = "正在加载第 " + pageNumber + " 页..."
|
||||
state.doc.getPage(pageNumber).then((page) => {
|
||||
const containerWidth = Math.max(previewEl.clientWidth - 16, 260)
|
||||
const baseViewport = page.getViewport({scale: 1})
|
||||
const containerWidth = Math.max(container.clientWidth || 0, window.innerWidth - 44)
|
||||
const cssScale = containerWidth / baseViewport.width
|
||||
const outputScale = Math.min(window.devicePixelRatio || 1, 2)
|
||||
const viewport = page.getViewport({scale: cssScale})
|
||||
const pageEl = document.createElement("div")
|
||||
pageEl.className = "tour-pdf-page"
|
||||
const canvas = document.createElement("canvas")
|
||||
const context = canvas.getContext("2d")
|
||||
canvas.width = Math.floor(viewport.width * outputScale)
|
||||
canvas.height = Math.floor(viewport.height * outputScale)
|
||||
canvas.style.width = Math.floor(viewport.width) + "px"
|
||||
canvas.style.height = Math.floor(viewport.height) + "px"
|
||||
pageEl.innerHTML = ""
|
||||
pageEl.appendChild(canvas)
|
||||
container.appendChild(pageEl)
|
||||
const renderContext = {
|
||||
return page.render({
|
||||
canvasContext: context,
|
||||
viewport: viewport,
|
||||
transform: outputScale !== 1 ? [outputScale, 0, 0, outputScale, 0, 0] : null
|
||||
}
|
||||
return page.render(renderContext).promise.then(() => {
|
||||
if (token === this.pdfRenderToken) {
|
||||
this.pdfRenderedPages = Math.max(this.pdfRenderedPages, pageNumber)
|
||||
}
|
||||
}).promise.then(() => {
|
||||
state.rendered[pageNumber] = true
|
||||
state.rendering[pageNumber] = false
|
||||
})
|
||||
}).catch(() => {
|
||||
state.rendering[pageNumber] = false
|
||||
pageEl.textContent = "第 " + pageNumber + " 页加载失败"
|
||||
})
|
||||
},
|
||||
renderRestPdfPages(pageNumber, token) {
|
||||
if (token !== this.pdfRenderToken || !this.pdfDoc || pageNumber > this.pdfPageCount) {
|
||||
this.pdfLoading = false
|
||||
return
|
||||
cleanupLinePdfPreviews() {
|
||||
if (this.linePdfObserver) {
|
||||
this.linePdfObserver.disconnect()
|
||||
this.linePdfObserver = null
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.renderPdfPage(pageNumber, token).then(() => {
|
||||
this.renderRestPdfPages(pageNumber + 1, token)
|
||||
}).catch(() => {
|
||||
if (token === this.pdfRenderToken) {
|
||||
this.pdfLoading = false
|
||||
this.pdfError = "部分页面加载失败"
|
||||
this.linePdfPreviews.forEach((item) => {
|
||||
if (item.task && item.task.destroy) {
|
||||
try {
|
||||
item.task.destroy()
|
||||
} catch (e) {
|
||||
}
|
||||
})
|
||||
}, 120)
|
||||
}
|
||||
})
|
||||
this.linePdfPreviews = []
|
||||
},
|
||||
getFileIdFromUrl(href) {
|
||||
if (!href) return ""
|
||||
const idMatch = href.match(/[?&]id=([^&#]+)/)
|
||||
if (idMatch) {
|
||||
return decodeURIComponent(idMatch[1])
|
||||
}
|
||||
return ""
|
||||
},
|
||||
loadDetail() {
|
||||
if (!this.matterId || !this.lineId) {
|
||||
@@ -470,9 +875,12 @@ layout("/layouts/platform_h5.html"){
|
||||
vant.Toast(lineRes.msg || "线路详情加载失败")
|
||||
} else {
|
||||
this.lineDetail = lineRes.data || {}
|
||||
this.lineContentHref = this.parseLineContentHref(this.lineDetail.lineContent)
|
||||
this.$nextTick(() => {
|
||||
this.renderLinePdf()
|
||||
this.lineContentHtml = ""
|
||||
this.buildLineContentHtmlAsync(this.lineDetail.lineContent).then((html) => {
|
||||
this.lineContentHtml = html
|
||||
this.$nextTick(() => {
|
||||
this.initLinePdfPreviews()
|
||||
})
|
||||
})
|
||||
}
|
||||
if (signupRes.code !== 0) {
|
||||
@@ -489,20 +897,27 @@ layout("/layouts/platform_h5.html"){
|
||||
vant.Toast("线路详情加载失败")
|
||||
})
|
||||
},
|
||||
onApply() {
|
||||
onApply(skipNotice) {
|
||||
if (!this.matterId) {
|
||||
vant.Toast("报名事项信息不完整")
|
||||
return
|
||||
}
|
||||
const goApply = () => {
|
||||
window.location.href = "/platform/tour/signup/h5/apply?matterId=" + encodeURIComponent(this.matterId)
|
||||
window.location.href = "/platform/tour/signup/h5/apply?matterId=" + encodeURIComponent(this.matterId) + "¬iceChecked=1"
|
||||
}
|
||||
if (skipNotice) {
|
||||
goApply()
|
||||
return
|
||||
}
|
||||
this.applyLoading = true
|
||||
this.$axios.post("/platform/tour/signup/signupEligibilityNotice", { matterId: this.matterId }).then((res) => {
|
||||
if (res.code !== 0) {
|
||||
vant.Dialog.alert({
|
||||
title: "温馨提醒",
|
||||
message: res.msg || "当前不能报名",
|
||||
confirmButtonColor: "#1867b0"
|
||||
}).then(() => {
|
||||
this.applyLoading = false
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -518,14 +933,20 @@ layout("/layouts/platform_h5.html"){
|
||||
confirmButtonText: "继续报名",
|
||||
cancelButtonText: "稍后报名",
|
||||
confirmButtonColor: "#1867b0"
|
||||
}).then(goApply).catch(() => {})
|
||||
}).then(goApply).catch(() => {
|
||||
this.applyLoading = false
|
||||
})
|
||||
} else {
|
||||
vant.Dialog.alert({
|
||||
title: "温馨提醒",
|
||||
message: data.message || "当前不能报名",
|
||||
confirmButtonColor: "#1867b0"
|
||||
}).then(() => {
|
||||
this.applyLoading = false
|
||||
})
|
||||
}
|
||||
}).catch(() => {
|
||||
this.applyLoading = false
|
||||
})
|
||||
},
|
||||
revokeSignup() {
|
||||
@@ -549,7 +970,7 @@ layout("/layouts/platform_h5.html"){
|
||||
this.loadDetail()
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.clearPdfPreview()
|
||||
this.cleanupLinePdfPreviews()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -476,9 +476,9 @@ layout("/layouts/platform_h5.html"){
|
||||
'tour-line-action--danger': canRevokeSignup(row),
|
||||
'tour-line-action--disabled': signupActionDisabled(row)
|
||||
}"
|
||||
:disabled="signupActionDisabled(row)"
|
||||
:disabled="signupActionDisabled(row) || signupCheckingMatterId === row.matterId"
|
||||
@click.stop="handleSignupAction(row)">
|
||||
{{ signupActionText(row) }}
|
||||
{{ signupCheckingMatterId === row.matterId ? '进入中...' : signupActionText(row) }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -520,17 +520,18 @@ layout("/layouts/platform_h5.html"){
|
||||
loading: false,
|
||||
finished: false,
|
||||
lineChecking: false,
|
||||
signupCheckingMatterId: "",
|
||||
showUnionPopup: false,
|
||||
unionList: [
|
||||
{id: "", name: "全部分工会"}
|
||||
],
|
||||
pageForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
pageSize: 5,
|
||||
totalCount: 0,
|
||||
year: new Date().getFullYear(),
|
||||
lineName: "",
|
||||
lineType: "",
|
||||
lineType: "省内线路",
|
||||
unionId: "",
|
||||
directFamilyUnitLine: null,
|
||||
pageOrderName: "lineName",
|
||||
@@ -604,22 +605,34 @@ layout("/layouts/platform_h5.html"){
|
||||
this.revokeSignup(row)
|
||||
return
|
||||
}
|
||||
if (this.isSigned(row)) {
|
||||
this.goApply(row, true)
|
||||
return
|
||||
}
|
||||
this.goApply(row)
|
||||
},
|
||||
goApply(row) {
|
||||
goApply(row, skipNotice) {
|
||||
if (!row || !row.matterId) {
|
||||
vant.Toast("报名事项信息不完整")
|
||||
return
|
||||
}
|
||||
const go = () => {
|
||||
window.location.href = "/platform/tour/signup/h5/apply?matterId=" + encodeURIComponent(row.matterId)
|
||||
window.location.href = "/platform/tour/signup/h5/apply?matterId=" + encodeURIComponent(row.matterId) + "¬iceChecked=1"
|
||||
}
|
||||
if (skipNotice) {
|
||||
this.signupCheckingMatterId = row.matterId
|
||||
go()
|
||||
return
|
||||
}
|
||||
this.signupCheckingMatterId = row.matterId
|
||||
this.$axios.post("/platform/tour/signup/signupEligibilityNotice", { matterId: row.matterId }).then((res) => {
|
||||
if (res.code !== 0) {
|
||||
vant.Dialog.alert({
|
||||
title: "温馨提醒",
|
||||
message: res.msg || "当前不能报名",
|
||||
confirmButtonColor: "#1867b0"
|
||||
}).then(() => {
|
||||
this.signupCheckingMatterId = ""
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -635,14 +648,20 @@ layout("/layouts/platform_h5.html"){
|
||||
confirmButtonText: "继续报名",
|
||||
cancelButtonText: "稍后报名",
|
||||
confirmButtonColor: "#1867b0"
|
||||
}).then(go).catch(() => {})
|
||||
}).then(go).catch(() => {
|
||||
this.signupCheckingMatterId = ""
|
||||
})
|
||||
} else {
|
||||
vant.Dialog.alert({
|
||||
title: "温馨提醒",
|
||||
message: data.message || "当前不能报名",
|
||||
confirmButtonColor: "#1867b0"
|
||||
}).then(() => {
|
||||
this.signupCheckingMatterId = ""
|
||||
})
|
||||
}
|
||||
}).catch(() => {
|
||||
this.signupCheckingMatterId = ""
|
||||
})
|
||||
},
|
||||
revokeSignup(row) {
|
||||
|
||||
+3
-2
@@ -203,6 +203,7 @@ layout("/layouts/platform_h5.html"){
|
||||
<van-cell title="姓名" :value="detail.userName || ''"></van-cell>
|
||||
<van-cell title="性别" :value="detail.gender || ''"></van-cell>
|
||||
<van-cell title="身份证号" :value="detail.idCard || ''"></van-cell>
|
||||
<van-cell title="手机号" :value="detail.mobile || ''"></van-cell>
|
||||
<van-cell title="所在单位" :value="detail.unitName || ''"></van-cell>
|
||||
<van-cell title="所在工会" :value="detail.unionName || ''"></van-cell>
|
||||
</div>
|
||||
@@ -213,8 +214,8 @@ layout("/layouts/platform_h5.html"){
|
||||
<van-cell title="线路类型" :value="detail.lineType || ''"></van-cell>
|
||||
<van-cell title="出行时段" :value="detail.travelPeriod || ''"></van-cell>
|
||||
<van-cell title="报名时间" :value="detail.signupTime || ''"></van-cell>
|
||||
<van-cell title="报名酒店" :value="detail.hotelName || ''"></van-cell>
|
||||
<van-cell title="旅行社" :value="detail.travelAgencyName || ''"></van-cell>
|
||||
<van-cell v-if="false" title="报名酒店" :value="detail.hotelName || ''"></van-cell>
|
||||
<van-cell v-if="false" title="旅行社" :value="detail.travelAgencyName || ''"></van-cell>
|
||||
<van-cell v-if="fillBedInfo" title="床型" :value="detail.bedType || ''"></van-cell>
|
||||
<van-cell v-if="fillBedInfo" title="床位信息" :value="detail.bedInfo || ''"></van-cell>
|
||||
<van-cell v-if="fillBedInfo" title="意向拼床人" :value="detail.intendedRoommate || ''"></van-cell>
|
||||
|
||||
Reference in New Issue
Block a user