diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourGroupController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourGroupController.java index 13232d43..cf63afa9 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourGroupController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourGroupController.java @@ -1,5 +1,7 @@ package com.budwk.app.zhgh.dayofficework.tour.controller; +import cn.afterturn.easypoi.excel.entity.ExportParams; +import cn.afterturn.easypoi.excel.entity.enmus.ExcelType; import cn.dev33.satoken.annotation.SaCheckPermission; import cn.hutool.core.util.StrUtil; import com.budwk.app.base.constant.RoleConstant; @@ -12,7 +14,7 @@ import com.budwk.app.web.commons.auth.utils.AuthUtil; import com.budwk.app.web.commons.auth.utils.SecurityUtil; import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerService; import com.budwk.app.zhgh.dayofficework.tour.service.TourMatterService; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.ss.usermodel.BorderStyle; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; @@ -193,7 +195,7 @@ public class TourGroupController { t.id, t.jobNo, t.userName, - '' AS mobile, + COALESCE(NULLIF(t.mobile, ''), NULLIF(vu.mobile, ''), '') AS mobile, t.idCard, t.unionId, t.unionName, @@ -201,6 +203,7 @@ public class TourGroupController { FROM tour_ledger t INNER JOIN tour_matter m ON m.id = t.matterId INNER JOIN tour_line l ON l.id = m.lineId + LEFT JOIN vw_user vu ON vu.loginname = t.jobNo $condition ORDER BY $orderColumn $orderBy, t.signupTime DESC, t.createdAt DESC """); @@ -212,7 +215,6 @@ public class TourGroupController { tourLedgerService.dao().execute(listSql); List list = listSql.getList(NutMap.class); - fillSignupMobile(list); Pagination pagination = new Pagination<>(pageForm.getPageNumber(), pageForm.getPageSize(), count, list); return Result.success(pagination); } @@ -231,7 +233,7 @@ public class TourGroupController { List list = queryExportParticipants(matterId); Workbook workbook = buildParticipantsWorkbook(matter, list); String lineName = StrUtil.blankToDefault(matter.getString("lineName", ""), "线路"); - CommonDownloadUtil.download(lineName + "参加人员名单.xls", workbook, response); + CommonDownloadUtil.download(lineName + "参加人员名单.xlsx", workbook, response); } private Cnd buildSignupQueryCnd(String matterId, String keyword, String unionId) { @@ -300,7 +302,7 @@ public class TourGroupController { t.jobNo, t.userName, t.idCard, - vu.mobile, + COALESCE(NULLIF(t.mobile, ''), NULLIF(vu.mobile, ''), '') AS mobile, t.unionName, l.lineName, CASE @@ -343,7 +345,8 @@ public class TourGroupController { ledgerId, familyName, relationship, - idCard + idCard, + mobile FROM tour_ledger_family WHERE delFlag = 0 AND ledgerId IN (@ledgerIds) @@ -363,7 +366,9 @@ public class TourGroupController { } private Workbook buildParticipantsWorkbook(NutMap matter, List list) { - Workbook workbook = new HSSFWorkbook(); + ExportParams exportParams = new ExportParams(); + exportParams.setType(ExcelType.XSSF); + Workbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet("参加人员名单"); sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 10)); sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, 10)); @@ -414,7 +419,7 @@ public class TourGroupController { Row familyRow = sheet.createRow(rowIndex++); familyRow.setHeightInPoints(24); setParticipantRow(familyRow, seq++, "", family.getString("familyName", ""), - family.getString("idCard", ""), "", "", + family.getString("idCard", ""), family.getString("mobile", ""), "", item.getString("lineName", matter.getString("lineName", "")), item.getString("travelPeriod", matter.getString("travelPeriod", "")), family.getString("relationship", ""), item.getString("userName", ""), bodyStyle); @@ -481,35 +486,6 @@ public class TourGroupController { } } - private void fillSignupMobile(List list) { - if (list == null || list.isEmpty()) { - return; - } - List 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 mobileMap = new HashMap<>(); - for (NutMap user : sql.getList(NutMap.class)) { - mobileMap.put(user.getString("loginname", ""), user.getString("mobile", "")); - } - for (NutMap item : list) { - item.put("mobile", mobileMap.getOrDefault(item.getString("jobNo", ""), "")); - } - } - private Cnd buildQueryCnd(Integer year, String lineName, String lineType, String unionId) { Cnd cnd = Cnd.NEW(); cnd.and("m.delFlag", "=", false); diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourLedgerController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourLedgerController.java index 7bbbbdf4..c44045ac 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourLedgerController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourLedgerController.java @@ -27,7 +27,7 @@ import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerDirectRelativeSer import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerFamilyService; import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerService; import org.apache.poi.ss.usermodel.Workbook; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.ss.usermodel.BorderStyle; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; @@ -183,7 +183,7 @@ public class TourLedgerController { if (StrUtil.isBlank(id)) { return Result.error("参数错误"); } - TourLedger ledger = tourLedgerService.fetch(id); + TourLedger ledger = tourLedgerService.fillMobileFallback(tourLedgerService.fetch(id)); if (ledger == null) { return Result.error("台账记录不存在"); } @@ -328,7 +328,7 @@ public class TourLedgerController { response.setHeader("Content-Disposition", "attachment;filename=" + zipName + ";filename*=UTF-8''" + zipName); try (ZipOutputStream zipOutputStream = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()))) { if (unionRows.isEmpty()) { - zipOutputStream.putNextEntry(new ZipEntry("无数据报名汇总表.xls")); + zipOutputStream.putNextEntry(new ZipEntry("无数据报名汇总表.xlsx")); try (Workbook workbook = buildUnionSignupWorkbook("无数据", Collections.emptyList())) { workbook.write(zipOutputStream); } @@ -336,7 +336,7 @@ public class TourLedgerController { } else { for (Map.Entry> entry : unionRows.entrySet()) { String unionName = entry.getValue().isEmpty() ? entry.getKey() : entry.getValue().get(0).getString("unionName", entry.getKey()); - String fileName = safeFileName(unionName + "报名汇总表.xls"); + String fileName = safeFileName(unionName + "报名汇总表.xlsx"); zipOutputStream.putNextEntry(new ZipEntry(fileName)); try (Workbook workbook = buildUnionSignupWorkbook(unionName, entry.getValue())) { workbook.write(zipOutputStream); @@ -360,7 +360,7 @@ public class TourLedgerController { t.unionId, COALESCE(NULLIF(t.unionName, ''), su.name, vu.unionName, '') AS unionName, COALESCE(NULLIF(su.unionCode, ''), vu.unionCode, '') AS unionCode, - COALESCE(NULLIF(vu.mobile, ''), '') AS mobile, + COALESCE(NULLIF(t.mobile, ''), NULLIF(vu.mobile, ''), '') AS mobile, COALESCE(NULLIF(l.lineName, ''), t.lineName, '') AS lineName, CASE WHEN IFNULL(m.travelStartTime, '') <> '' AND IFNULL(m.travelEndTime, '') <> '' @@ -415,7 +415,9 @@ public class TourLedgerController { } private Workbook buildUnionSignupWorkbook(String unionName, List rows) { - HSSFWorkbook workbook = new HSSFWorkbook(); + ExportParams exportParams = new ExportParams(); + exportParams.setType(ExcelType.XSSF); + XSSFWorkbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet("报名汇总表"); sheet.setColumnWidth(0, 8 * 256); sheet.setColumnWidth(1, 14 * 256); diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourMySignupController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourMySignupController.java index 02913aec..78ad0b3b 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourMySignupController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourMySignupController.java @@ -407,6 +407,14 @@ public class TourMySignupController { return Result.success(sql.getList(Sys_dict.class)); } + /** + * 修改本人疗休养报名。 + * + * @param ledger 报名台账,包含报名人身份证号码和手机号 + * @param families 亲属信息JSON数组,包含姓名、年龄、性别、关系及联系方式 + * @param directRelative 直系亲属线路信息JSON,非直系亲属线路可为空 + * @return Result,成功时返回修改结果,校验失败时返回具体业务提示 + */ @At @Aop(TransAop.READ_COMMITTED) @SaCheckPermission("tour.mysignup") @@ -571,9 +579,9 @@ public class TourMySignupController { if (StrUtil.isBlank(id)) { return null; } - return tourLedgerService.fetch(Cnd.where(TourLedger::getDelFlag, "=", false) + return tourLedgerService.fillMobileFallback(tourLedgerService.fetch(Cnd.where(TourLedger::getDelFlag, "=", false) .and(TourLedger::getId, "=", id) - .and(TourLedger::getJobNo, "=", currentJobNo())); + .and(TourLedger::getJobNo, "=", currentJobNo()))); } private Result checkSignup(TourLedger ledger) { @@ -592,6 +600,12 @@ public class TourMySignupController { if (StrUtil.isBlank(ledger.getLineName())) { return Result.error("报名线路不能为空"); } + if (StrUtil.isBlank(ledger.getIdCard())) { + return Result.error("身份证号码不能为空"); + } + if (StrUtil.isBlank(ledger.getMobile())) { + return Result.error("手机号不能为空"); + } return null; } @@ -1005,15 +1019,20 @@ public class TourMySignupController { if (family == null) { continue; } - if (StrUtil.isBlank(family.getFamilyName()) || StrUtil.isBlank(family.getGender()) - || StrUtil.isBlank(family.getIdCard()) || StrUtil.isBlank(family.getRelationship())) { - return Result.error("请完善亲属姓名、性别、身份证号码和关系"); + if (StrUtil.isBlank(family.getFamilyName()) || family.getAge() == null + || StrUtil.isBlank(family.getGender()) || StrUtil.isBlank(family.getRelationship())) { + return Result.error("请完善亲属姓名、年龄、性别和与本人关系"); } - String idCard = family.getIdCard().trim().toUpperCase(); - if (!isValidIdCard(idCard)) { + // 年满16周岁的亲属必须提供身份证号码和手机号;未满16周岁时两项允许为空。 + if (family.getAge() >= 16 && (StrUtil.isBlank(family.getIdCard()) || StrUtil.isBlank(family.getMobile()))) { + return Result.error("年满16周岁的亲属必须填写身份证号码和手机号"); + } + if (StrUtil.isNotBlank(family.getIdCard()) && !isValidIdCard(family.getIdCard().trim().toUpperCase())) { return Result.error("请输入正确的身份证号码"); } - family.setIdCard(idCard); + if (StrUtil.isNotBlank(family.getIdCard())) { + family.setIdCard(family.getIdCard().trim().toUpperCase()); + } } return null; } diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourSchoolUnionApprovalController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourSchoolUnionApprovalController.java index 616fcbc1..dabdecba 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourSchoolUnionApprovalController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourSchoolUnionApprovalController.java @@ -461,7 +461,7 @@ public class TourSchoolUnionApprovalController { sql.setParam("actorId", SecurityUtil.getUserId()); sql.setCallback(Sqls.callback.integer()); tourLedgerService.dao().execute(sql); - return sql.getInt() > 0 ? tourLedgerService.fetch(id) : null; + return sql.getInt() > 0 ? tourLedgerService.fillMobileFallback(tourLedgerService.fetch(id)) : null; } private String getCurrentLineName(TourLedger ledger) { diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourSignupController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourSignupController.java index 57d5f74a..e0269cb9 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourSignupController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourSignupController.java @@ -472,7 +472,7 @@ public class TourSignupController { .and(TourLedger::getMatterId, "=", matter.getString("matterId")) .and(TourLedger::getJobNo, "=", staff.getString("jobNo")); ledgerCnd.desc(TourLedger::getCreatedAt); - TourLedger ledger = tourLedgerService.fetch(ledgerCnd); + TourLedger ledger = tourLedgerService.fillMobileFallback(tourLedgerService.fetch(ledgerCnd)); TourMatter matterEntity = tourMatterService.fetch(matter.getString("matterId")); TourLedger ruleLedger = new TourLedger(); ruleLedger.setId(ledger == null ? null : ledger.getId()); @@ -661,10 +661,19 @@ public class TourSignupController { return Result.success(sql.getList(Sys_dict.class)); } + /** + * 保存疗休养报名。 + * + * @param ledger 报名台账基础信息,包含线路、事项、报名人身份证号码和手机号等内容 + * @param families 亲属信息JSON数组;每项包含姓名、性别、身份证号码、手机号和关系 + * @param directRelative 直系亲属线路信息JSON;非直系亲属线路可传空字符串 + * @return Result,成功时返回报名及流程结果,校验失败时返回具体缺失字段提示 + */ @At @Aop(TransAop.READ_COMMITTED) @SaCheckPermission("tour.signup") - public Result doSignup(TourLedger ledger, @Param("families") String families, @Param("directRelative") String directRelative) { + public Result doSignup(TourLedger ledger, @Param("families") String families, + @Param("directRelative") String directRelative) { Result checkResult = checkSignup(ledger); if (checkResult != null) { return checkResult; @@ -826,6 +835,12 @@ public class TourSignupController { if (StrUtil.isBlank(ledger.getLineName())) { return Result.error("报名线路不能为空"); } + if (StrUtil.isBlank(ledger.getIdCard())) { + return Result.error("身份证号码不能为空"); + } + if (StrUtil.isBlank(ledger.getMobile())) { + return Result.error("手机号不能为空"); + } return null; } @@ -874,15 +889,20 @@ public class TourSignupController { if (family == null) { continue; } - if (StrUtil.isBlank(family.getFamilyName()) || StrUtil.isBlank(family.getGender()) - || StrUtil.isBlank(family.getIdCard()) || StrUtil.isBlank(family.getRelationship())) { - return Result.error("请完善亲属姓名、性别、身份证号码和关系"); + if (StrUtil.isBlank(family.getFamilyName()) || family.getAge() == null + || StrUtil.isBlank(family.getGender()) || StrUtil.isBlank(family.getRelationship())) { + return Result.error("请完善亲属姓名、年龄、性别和与本人关系"); } - String idCard = family.getIdCard().trim().toUpperCase(); - if (!isValidIdCard(idCard)) { + // 年满16周岁的亲属必须提供身份证号码和手机号;未满16周岁时两项允许为空。 + if (family.getAge() >= 16 && (StrUtil.isBlank(family.getIdCard()) || StrUtil.isBlank(family.getMobile()))) { + return Result.error("年满16周岁的亲属必须填写身份证号码和手机号"); + } + if (StrUtil.isNotBlank(family.getIdCard()) && !isValidIdCard(family.getIdCard().trim().toUpperCase())) { return Result.error("请输入正确的身份证号码"); } - family.setIdCard(idCard); + if (StrUtil.isNotBlank(family.getIdCard())) { + family.setIdCard(family.getIdCard().trim().toUpperCase()); + } } return null; } diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourUnionApprovalController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourUnionApprovalController.java index 4fe44e27..15644be8 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourUnionApprovalController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourUnionApprovalController.java @@ -461,7 +461,7 @@ public class TourUnionApprovalController { sql.setParam("actorId", SecurityUtil.getUserId()); sql.setCallback(Sqls.callback.integer()); tourLedgerService.dao().execute(sql); - return sql.getInt() > 0 ? tourLedgerService.fetch(id) : null; + return sql.getInt() > 0 ? tourLedgerService.fillMobileFallback(tourLedgerService.fetch(id)) : null; } private String getCurrentLineName(TourLedger ledger) { diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourUnionLedgerController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourUnionLedgerController.java index 068f047e..822f252b 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourUnionLedgerController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourUnionLedgerController.java @@ -1,5 +1,7 @@ package com.budwk.app.zhgh.dayofficework.tour.controller; +import cn.afterturn.easypoi.excel.entity.ExportParams; +import cn.afterturn.easypoi.excel.entity.enmus.ExcelType; import cn.dev33.satoken.annotation.SaCheckPermission; import cn.hutool.core.util.StrUtil; import com.budwk.app.base.annotation.SLog; @@ -15,7 +17,7 @@ import com.budwk.app.zhgh.dayofficework.tour.models.TourLedgerFamily; import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerDirectRelativeService; import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerFamilyService; import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerService; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.ss.usermodel.BorderStyle; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; @@ -171,7 +173,7 @@ public class TourUnionLedgerController { Cnd cnd = buildQueryCnd(currentUnionId, startYear, endYear, keyword, unionId, lineId, travelPeriod, lineType, scopeType, true); List list = queryOverCostSummaryList(cnd, pageForm); Workbook workbook = buildOverCostSummaryWorkbook(currentUnionName(), list); - CommonDownloadUtil.download("5天外超出部分疗休养费用由单位承担申请人员汇总表.xls", workbook, response); + CommonDownloadUtil.download("5天外超出部分疗休养费用由单位承担申请人员汇总表.xlsx", workbook, response); } @At @@ -411,7 +413,7 @@ public class TourUnionLedgerController { t.userName, t.idCard, t.unionName, - vu.mobile, + COALESCE(NULLIF(t.mobile, ''), NULLIF(vu.mobile, ''), '') AS mobile, m.travelStartTime, m.travelEndTime, m.estimatedCost, @@ -474,7 +476,9 @@ public class TourUnionLedgerController { } private Workbook buildOverCostSummaryWorkbook(String unionName, List list) { - Workbook workbook = new HSSFWorkbook(); + ExportParams exportParams = new ExportParams(); + exportParams.setType(ExcelType.XSSF); + Workbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet("汇总表"); sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 9)); sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, 9)); @@ -675,7 +679,7 @@ public class TourUnionLedgerController { sql.setParam("unionId", currentUnionId()); sql.setCallback(Sqls.callback.integer()); tourLedgerService.dao().execute(sql); - return sql.getInt() > 0 ? tourLedgerService.fetch(id) : null; + return sql.getInt() > 0 ? tourLedgerService.fillMobileFallback(tourLedgerService.fetch(id)) : null; } private String getTravelPeriod(TourLedger ledger) { diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourLedger.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourLedger.java index eada8569..dea38f2e 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourLedger.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourLedger.java @@ -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) diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourLedgerFamily.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourLedgerFamily.java index 87c18078..e0965bb9 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourLedgerFamily.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourLedgerFamily.java @@ -56,6 +56,11 @@ public class TourLedgerFamily 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("年龄") @ColDefine(type = ColType.INT, width = 3) diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/service/TourLedgerService.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/service/TourLedgerService.java index 296c95dc..28bff4ea 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/service/TourLedgerService.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/service/TourLedgerService.java @@ -8,6 +8,14 @@ import com.budwk.app.zhgh.dayofficework.tour.models.TourLedger; */ public interface TourLedgerService extends BaseService { + /** + * 补充报名台账手机号。台账已保存手机号时保持原值,仅在台账手机号为空时按工号读取用户视图手机号。 + * + * @param ledger 待补充手机号的报名台账,允许为空 + * @return 原报名台账对象;参数为空时返回空 + */ + TourLedger fillMobileFallback(TourLedger ledger); + /** * 校验当前人员在省内间隔周期内是否已经实际参加过省内线路。 * diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/service/impl/TourLedgerServiceImpl.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/service/impl/TourLedgerServiceImpl.java index 0b63a786..83d96c37 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/service/impl/TourLedgerServiceImpl.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/service/impl/TourLedgerServiceImpl.java @@ -26,6 +26,18 @@ public class TourLedgerServiceImpl extends BaseServiceImpl implement super(dao); } + @Override + public TourLedger fillMobileFallback(TourLedger ledger) { + if (ledger == null || StrUtil.isNotBlank(ledger.getMobile()) || StrUtil.isBlank(ledger.getJobNo())) { + return ledger; + } + View_user user = dao().fetch(View_user.class, Cnd.where(View_user::getLoginname, "=", ledger.getJobNo())); + if (user != null) { + ledger.setMobile(user.getMobile()); + } + return ledger; + } + @Override public String checkInProvinceParticipation(String jobNo, Integer inProvinceYears, diff --git a/src/main/resources/db/tour_ledger_add_mobile.sql b/src/main/resources/db/tour_ledger_add_mobile.sql new file mode 100644 index 00000000..926e1dee --- /dev/null +++ b/src/main/resources/db/tour_ledger_add_mobile.sql @@ -0,0 +1,6 @@ +-- 疗休养报名手机号仅由业务代码控制必填,数据库字段保持可空以兼容历史数据。 +ALTER TABLE `tour_ledger` + ADD COLUMN `mobile` varchar(30) NULL COMMENT '手机号' AFTER `idCard`; + +ALTER TABLE `tour_ledger_family` + ADD COLUMN `mobile` varchar(30) NULL COMMENT '手机号' AFTER `idCard`; diff --git a/src/main/resources/static/assets/platform/images/tour/tour-h5-empty-v3.png b/src/main/resources/static/assets/platform/images/tour/tour-h5-empty-v3.png new file mode 100644 index 00000000..8cb08ea0 Binary files /dev/null and b/src/main/resources/static/assets/platform/images/tour/tour-h5-empty-v3.png differ diff --git a/src/main/resources/static/assets/platform/images/tour/tour-h5-hero-v3.png b/src/main/resources/static/assets/platform/images/tour/tour-h5-hero-v3.png new file mode 100644 index 00000000..7af1bf78 Binary files /dev/null and b/src/main/resources/static/assets/platform/images/tour/tour-h5-hero-v3.png differ diff --git a/src/main/resources/views/layouts/platform_h5.html b/src/main/resources/views/layouts/platform_h5.html index a60659b3..d4f9233a 100644 --- a/src/main/resources/views/layouts/platform_h5.html +++ b/src/main/resources/views/layouts/platform_h5.html @@ -254,6 +254,7 @@ }) $(document).on("pjax:send", function () { window.h5HistoryLayerManager.reset() + showH5PageSkeleton() NProgress.start() window.customStyleList = document.querySelectorAll('style[id^="style-"]') }) @@ -268,6 +269,7 @@ window.customStyleList = null } NProgress.done() + hideH5PageSkeleton() toggleShowBar() }) @@ -292,6 +294,13 @@ })() function pjaxReplace(url, data = null) { + showH5PageSkeleton(url) + // 疗休养报名页面使用独立 H5 布局,其中包含图片懒加载等专用初始化逻辑。 + // 禁止通过公共 PJAX 只替换页面片段,否则专用布局脚本不会执行,首次进入会出现图片懒加载指令未注册。 + if (url && url.indexOf("/platform/tour/signup/h5") === 0) { + window.location.href = url + return + } return $.pjax({ url: url, container: "#container", @@ -304,6 +313,24 @@ }) } + // 仅在疗休养 H5 页面切换期间显示骨架,避免影响共用布局下的其他业务模块。 + const showH5PageSkeleton = (targetUrl) => { + const pageUrl = targetUrl || window.location.pathname + if (pageUrl.indexOf("/platform/tour/") !== 0) return + const skeleton = document.getElementById("tour-page-transition-skeleton") + if (skeleton) skeleton.classList.add("is-visible") + } + + const hideH5PageSkeleton = () => { + const skeleton = document.getElementById("tour-page-transition-skeleton") + if (skeleton) skeleton.classList.remove("is-visible") + } + + // 从疗休养完整页面返回公共 H5 页面时可能命中 BFCache,需要清除离开前保留的骨架状态。 + window.addEventListener("pageshow", () => { + hideH5PageSkeleton() + }) + let h5GlobalLoading = null let h5PendingRequestCount = 0 @@ -373,6 +400,7 @@ } function historyBack(func) { + showH5PageSkeleton() if (window.history.length > 1) { window.history.back() } else { @@ -618,6 +646,8 @@ Vue.prototype.$axios = commonUtil.axiosService() Vue.prototype.$downLoad = commonUtil.downLoadService.bind(commonUtil) Vue.prototype.$pjaxReplace = pjaxReplace + Vue.prototype.$showH5PageSkeleton = showH5PageSkeleton + Vue.prototype.$hideH5PageSkeleton = hideH5PageSkeleton + +
${layoutContent}
diff --git a/src/main/resources/views/platform/zhgh/dayofficework/Tour/ledger/index.html b/src/main/resources/views/platform/zhgh/dayofficework/Tour/ledger/index.html index d1f021c9..bbe46abd 100644 --- a/src/main/resources/views/platform/zhgh/dayofficework/Tour/ledger/index.html +++ b/src/main/resources/views/platform/zhgh/dayofficework/Tour/ledger/index.html @@ -159,6 +159,7 @@ layout("/layouts/platform.html"){ {{ detail.userName || '' }} {{ detail.gender || '' }} {{ detail.idCard || '' }} + {{ detail.mobile || '' }} {{ detail.unitName || '' }} {{ detail.unionName || '' }} @@ -205,6 +206,7 @@ layout("/layouts/platform.html"){ + diff --git a/src/main/resources/views/platform/zhgh/dayofficework/Tour/mysignup/index.html b/src/main/resources/views/platform/zhgh/dayofficework/Tour/mysignup/index.html index 260fcb3f..fbf10c68 100644 --- a/src/main/resources/views/platform/zhgh/dayofficework/Tour/mysignup/index.html +++ b/src/main/resources/views/platform/zhgh/dayofficework/Tour/mysignup/index.html @@ -99,6 +99,7 @@ layout("/layouts/platform.html"){ {{ detail.userName || '' }} {{ detail.gender || '' }} {{ detail.idCard || '' }} + {{ detail.mobile || '' }} {{ detail.unitName || '' }} {{ detail.unionName || '' }} @@ -145,6 +146,7 @@ layout("/layouts/platform.html"){ + @@ -229,6 +231,13 @@ layout("/layouts/platform.html"){ + + + + + + +
报名信息
@@ -387,7 +396,12 @@ layout("/layouts/platform.html"){ + + + @@ -1181,6 +1195,7 @@ layout("/layouts/platform.html"){ familyName: "", gender: "", idCard: "", + mobile: "", age: null, bedType: "", bedInfo: "", @@ -1222,18 +1237,27 @@ layout("/layouts/platform.html"){ this.$message.warning("请添加亲属信息") return false } - const invalid = this.familyData.some(item => !item.familyName || !item.gender || !item.idCard || !item.relationship) - if (invalid) { - this.$message.warning("请完善亲属姓名、性别、身份证号码和关系") + const invalidBase = this.familyData.some(item => !item.familyName || item.age === null || item.age === undefined + || !item.gender || !item.relationship) + if (invalidBase) { + this.$message.warning("请完善亲属姓名、年龄、性别和与本人关系") return false } - const invalidIdCard = this.familyData.some(item => !this.isValidIdCard(item.idCard)) + const invalidContact = this.familyData.some(item => this.familyContactRequired(item) && (!item.idCard || !item.mobile)) + if (invalidContact) { + this.$message.warning("年满16周岁的亲属必须填写身份证号码和手机号") + return false + } + const invalidIdCard = this.familyData.some(item => item.idCard && !this.isValidIdCard(item.idCard)) if (invalidIdCard) { this.$message.warning("请输入正确的身份证号码") return false } return true }, + familyContactRequired(family) { + return family && family.age !== null && family.age !== undefined && Number(family.age) >= 16 + }, normalizeFamilyIdCard(row) { if (!row || !row.idCard) return row.idCard = String(row.idCard).trim().toUpperCase() @@ -1272,6 +1296,10 @@ layout("/layouts/platform.html"){ return true }, submitSignup() { + if (!this.signupForm.idCard || !this.signupForm.mobile) { + this.$message.warning("请完善报名人身份证号码和手机号") + return + } if (!this.validateFamilies()) return if (!this.validateDirectRelative()) return const families = this.allowFamily && this.signupForm.hasFamily ? this.familyData : [] @@ -1281,7 +1309,6 @@ layout("/layouts/platform.html"){ }) this.signupLoading = true this.$axios.post(loc() + "/doSignup", form).then((res) => { - this.signupLoading = false if (res.code === 0) { this.$message.success(res.msg || "修改成功") this.signupVisible = false @@ -1291,6 +1318,7 @@ layout("/layouts/platform.html"){ this.$message.warning(res.msg || "修改失败") } }).catch(() => { + }).finally(() => { this.signupLoading = false }) }, diff --git a/src/main/resources/views/platform/zhgh/dayofficework/Tour/schoolUnionApproval/index.html b/src/main/resources/views/platform/zhgh/dayofficework/Tour/schoolUnionApproval/index.html index 160eb76a..e9824e2b 100644 --- a/src/main/resources/views/platform/zhgh/dayofficework/Tour/schoolUnionApproval/index.html +++ b/src/main/resources/views/platform/zhgh/dayofficework/Tour/schoolUnionApproval/index.html @@ -184,6 +184,7 @@ layout("/layouts/platform.html"){ {{ detail.userName || '' }} {{ detail.gender || '' }} {{ detail.idCard || '' }} + {{ detail.mobile || '' }} {{ detail.unitName || '' }} {{ detail.unionName || '' }} {{ detail.signupTime || '' }} @@ -220,6 +221,7 @@ layout("/layouts/platform.html"){ + diff --git a/src/main/resources/views/platform/zhgh/dayofficework/Tour/signup/index.html b/src/main/resources/views/platform/zhgh/dayofficework/Tour/signup/index.html index abc1eedd..5fc5fc79 100644 --- a/src/main/resources/views/platform/zhgh/dayofficework/Tour/signup/index.html +++ b/src/main/resources/views/platform/zhgh/dayofficework/Tour/signup/index.html @@ -128,6 +128,13 @@ layout("/layouts/platform.html"){ + + + + + + + @@ -286,7 +293,12 @@ layout("/layouts/platform.html"){ + + + @@ -799,6 +811,7 @@ layout("/layouts/platform.html"){ familyName: "", gender: "", idCard: "", + mobile: "", age: null, bedType: "", bedInfo: "", @@ -840,18 +853,27 @@ layout("/layouts/platform.html"){ this.$message.warning("请添加亲属信息") return false } - const invalid = this.familyData.some(item => !item.familyName || !item.gender || !item.idCard || !item.relationship) - if (invalid) { - this.$message.warning("请完善亲属姓名、性别、身份证号码和关系") + const invalidBase = this.familyData.some(item => !item.familyName || item.age === null || item.age === undefined + || !item.gender || !item.relationship) + if (invalidBase) { + this.$message.warning("请完善亲属姓名、年龄、性别和与本人关系") return false } - const invalidIdCard = this.familyData.some(item => !this.isValidIdCard(item.idCard)) + const invalidContact = this.familyData.some(item => this.familyContactRequired(item) && (!item.idCard || !item.mobile)) + if (invalidContact) { + this.$message.warning("年满16周岁的亲属必须填写身份证号码和手机号") + return false + } + const invalidIdCard = this.familyData.some(item => item.idCard && !this.isValidIdCard(item.idCard)) if (invalidIdCard) { this.$message.warning("请输入正确的身份证号码") return false } return true }, + familyContactRequired(family) { + return family && family.age !== null && family.age !== undefined && Number(family.age) >= 16 + }, normalizeFamilyIdCard(row) { if (!row || !row.idCard) return row.idCard = String(row.idCard).trim().toUpperCase() @@ -890,6 +912,10 @@ layout("/layouts/platform.html"){ return true }, submitSignup() { + if (!this.signupForm.idCard || !this.signupForm.mobile) { + this.$message.warning("请完善报名人身份证号码和手机号") + return + } if (!this.validateFamilies()) return if (!this.validateDirectRelative()) return const families = this.allowFamily && this.signupForm.hasFamily ? this.familyData : [] @@ -899,7 +925,6 @@ layout("/layouts/platform.html"){ }) this.signupLoading = true this.$axios.post(loc() + "/doSignup", form).then((res) => { - this.signupLoading = false if (res.code === 0) { this.$message.success(res.msg || "报名成功") this.signupVisible = false @@ -908,6 +933,7 @@ layout("/layouts/platform.html"){ this.$message.warning(res.msg || "报名失败") } }).catch(() => { + }).finally(() => { this.signupLoading = false }) }, diff --git a/src/main/resources/views/platform/zhgh/dayofficework/Tour/unionApproval/index.html b/src/main/resources/views/platform/zhgh/dayofficework/Tour/unionApproval/index.html index 115edb96..40975bbc 100644 --- a/src/main/resources/views/platform/zhgh/dayofficework/Tour/unionApproval/index.html +++ b/src/main/resources/views/platform/zhgh/dayofficework/Tour/unionApproval/index.html @@ -184,6 +184,7 @@ layout("/layouts/platform.html"){ {{ detail.userName || '' }} {{ detail.gender || '' }} {{ detail.idCard || '' }} + {{ detail.mobile || '' }} {{ detail.unitName || '' }} {{ detail.unionName || '' }} {{ detail.signupTime || '' }} @@ -220,6 +221,7 @@ layout("/layouts/platform.html"){ + diff --git a/src/main/resources/views/platform/zhgh/dayofficework/Tour/unionledger/index.html b/src/main/resources/views/platform/zhgh/dayofficework/Tour/unionledger/index.html index 46ae1e88..da058256 100644 --- a/src/main/resources/views/platform/zhgh/dayofficework/Tour/unionledger/index.html +++ b/src/main/resources/views/platform/zhgh/dayofficework/Tour/unionledger/index.html @@ -149,6 +149,7 @@ layout("/layouts/platform.html"){ {{ detail.userName || '' }} {{ detail.gender || '' }} {{ detail.idCard || '' }} + {{ detail.mobile || '' }} {{ detail.unitName || '' }} {{ detail.unionName || '' }} @@ -195,6 +196,7 @@ layout("/layouts/platform.html"){ + diff --git a/src/main/resources/views/platform/zhghh5/dayofficework/tour/common/theme.css b/src/main/resources/views/platform/zhghh5/dayofficework/tour/common/theme.css new file mode 100644 index 00000000..84fec380 --- /dev/null +++ b/src/main/resources/views/platform/zhghh5/dayofficework/tour/common/theme.css @@ -0,0 +1,283 @@ +/* 疗休养移动端统一视觉主题:仅使用 tour-h5-theme 下的业务类,避免影响其他 H5 模块。 */ +body { + background-color: #f3f7fd; +} + +[v-cloak] { + display: none; +} + +.tour-h5-theme { + min-height: 100vh; + color: #263548; + background-color: #f3f7fd; + box-sizing: border-box; +} + +/* 页面接口首次加载时使用结构化骨架,避免先显示空字段或旧列表。 */ +.tour-content-skeleton { + padding: 12px; + background: #f3f7fd; + box-sizing: border-box; +} + +.tour-content-skeleton__cover, +.tour-content-skeleton__title, +.tour-content-skeleton__row, +.tour-content-skeleton__card { + background: linear-gradient(90deg, #edf2f8 25%, #f8fbff 37%, #edf2f8 63%); + background-size: 400% 100%; + animation: tour-content-skeleton-loading 1.35s ease infinite; +} + +.tour-content-skeleton__cover { height: 168px; border-radius: 14px; } +.tour-content-skeleton__title { width: 46%; height: 18px; margin: 16px 2px 10px; border-radius: 9px; } +.tour-content-skeleton__row { width: 76%; height: 13px; margin: 10px 2px; border-radius: 7px; } +.tour-content-skeleton__card { height: 126px; margin-top: 12px; border-radius: 14px; } + +@keyframes tour-content-skeleton-loading { + 0% { background-position: 100% 50%; } + 100% { background-position: 0 50%; } +} + +.tour-h5-theme .van-nav-bar { + background-color: #fff; +} + +.tour-h5-theme .van-nav-bar__title { + color: #172033; + font-size: 16px; + font-weight: 600; +} + +.tour-h5-theme .van-nav-bar .van-icon, +.tour-h5-theme .van-nav-bar__text { + color: #1989fa; +} + +.tour-h5-theme .van-nav-bar::after, +.tour-h5-theme .van-hairline--bottom::after { + border-bottom-color: #edf2f8; +} + +.tour-h5-card { + overflow: hidden; + border-radius: 12px; + background-color: #fff; + box-shadow: 0 7px 20px rgba(55, 85, 126, .08); +} + +.tour-h5-section-title { + position: relative; + display: flex; + min-height: 46px; + padding: 0 14px 0 20px; + align-items: center; + justify-content: space-between; + color: #202938; + font-size: 16px; + line-height: 22px; + font-weight: 600; + box-sizing: border-box; +} + +.tour-h5-section-title::before { + position: absolute; + top: 15px; + bottom: 15px; + left: 10px; + width: 3px; + border-radius: 2px; + background-color: #1989fa; + content: ""; +} + +.tour-h5-tag { + display: inline-flex; + min-height: 22px; + padding: 2px 8px; + align-items: center; + justify-content: center; + border-radius: 11px; + color: #1989fa; + background-color: #eaf4ff; + font-size: 11px; + line-height: 18px; + box-sizing: border-box; + white-space: nowrap; +} + +.tour-h5-tag.is-success { + color: #20a765; + background-color: #e9f8f0; +} + +.tour-h5-tag.is-warning { + color: #e98018; + background-color: #fff3e4; +} + +.tour-h5-tag.is-muted { + color: #7c899b; + background-color: #f0f2f5; +} + +.tour-h5-search { + margin: 0 0 8px; + padding: 0; + overflow: hidden; + border-radius: 12px; + background-color: #fff; + box-shadow: 0 5px 16px rgba(43, 73, 112, .1); +} + +.tour-h5-search .van-search__content { + height: 42px; + padding-left: 12px; + align-items: center; + border-radius: 12px; + background-color: #fff; +} + +.tour-h5-search .van-field__control { + color: #263548; + font-size: 14px; +} + +.tour-h5-search .van-field__control::placeholder { + color: #a7b0bf; +} + +.tour-h5-filter { + overflow: hidden; + border-radius: 10px; + background-color: #fff; + box-shadow: 0 5px 16px rgba(43, 73, 112, .08); +} + +.tour-h5-filter .van-dropdown-menu__bar, +.tour-h5-filter .van-dropdown-menu__item, +.tour-h5-filter .van-dropdown-menu__title { + height: 44px; +} + +.tour-h5-filter .van-dropdown-menu__bar { + box-shadow: none; +} + +.tour-h5-filter .van-dropdown-menu__title { + color: #66758a; + font-size: 14px; +} + +.tour-h5-filter .van-dropdown-menu__title--active, +.tour-h5-filter .van-dropdown-item__option--active, +.tour-h5-filter .van-dropdown-item__option--active .van-dropdown-item__icon { + color: #1989fa; +} + +.tour-h5-filter .van-dropdown-item__content { + width: calc(100% - 24px); + margin: 0 12px; + overflow: hidden; + border-radius: 0 0 12px 12px; + box-shadow: 0 10px 24px rgba(31, 65, 108, .14); +} + +.tour-h5-empty { + display: flex; + min-height: 290px; + padding: 40px 18px 32px; + align-items: center; + justify-content: center; + flex-direction: column; + box-sizing: border-box; + text-align: center; +} + +.tour-h5-empty img { + display: block; + width: 60%; + max-width: 190px; + height: auto; + object-fit: contain; +} + +.tour-h5-empty__title { + margin-top: 8px; + color: #50627a; + font-size: 15px; + line-height: 22px; + font-weight: 600; +} + +.tour-h5-empty__hint { + margin-top: 5px; + color: #9aa7b8; + font-size: 12px; + line-height: 18px; +} + +.tour-h5-fixed-bar { + position: fixed; + right: 0; + bottom: 0; + left: 0; + z-index: 30; + display: flex; + gap: 10px; + padding: 10px 12px calc(10px + env(safe-area-inset-bottom)); + border-top: 1px solid #edf1f6; + background-color: rgba(255, 255, 255, .98); + box-shadow: 0 -6px 18px rgba(38, 66, 103, .08); + box-sizing: border-box; +} + +.tour-h5-fixed-bar .van-button { + height: 42px; + border-radius: 8px; + font-size: 15px; + font-weight: 600; +} + +.tour-h5-theme .van-cell { + min-height: 48px; + padding: 13px 14px; + color: #35445a; + font-size: 14px; +} + +.tour-h5-theme .van-cell__title { + color: #65748a; +} + +.tour-h5-theme .van-cell__value { + color: #263548; +} + +.tour-h5-theme .van-field__label { + color: #65748a; +} + +.tour-h5-theme .van-field__control { + color: #263548; +} + +.tour-h5-theme .van-button--info, +.tour-h5-theme .van-button--primary { + border-color: #0f7bf3; + background-color: #0f7bf3; +} + +.tour-h5-theme .van-button--plain.van-button--info { + color: #0f7bf3; + background-color: #fff; +} + +@media (max-width: 350px) { + .tour-h5-fixed-bar { + gap: 7px; + padding-right: 10px; + padding-left: 10px; + } +} diff --git a/src/main/resources/views/platform/zhghh5/dayofficework/tour/mysignup/index.html b/src/main/resources/views/platform/zhghh5/dayofficework/tour/mysignup/index.html index dfbe0a38..df0d13b7 100644 --- a/src/main/resources/views/platform/zhghh5/dayofficework/tour/mysignup/index.html +++ b/src/main/resources/views/platform/zhghh5/dayofficework/tour/mysignup/index.html @@ -27,6 +27,10 @@ layout("/layouts/platform_h5.html"){ box-sizing: border-box; } + .tour-list-refresh { + min-height: 100%; + } + .tour-search-row { width: 100%; display: flex; @@ -298,6 +302,147 @@ layout("/layouts/platform_h5.html"){ font-weight: 700; } + .tour-family-title-row { + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; + } + + .tour-family-actions { + margin-left: auto; + display: flex; + align-items: center; + gap: 8px; + flex-shrink: 0; + } + + .tour-family-actions .van-button { + height: 29px; + border-radius: 6px; + } + + .tour-family-tabs { + padding-top: 8px; + } + + .tour-family-tabs-shell { + position: relative; + } + + .tour-family-tab-arrow { + position: absolute; + top: 14px; + z-index: 2; + width: 28px; + height: 28px; + padding: 0; + border: 1px solid #d7e7fb; + border-radius: 50%; + color: #1989fa; + background-color: rgba(255, 255, 255, .94); + font-size: 15px; + line-height: 26px; + text-align: center; + box-shadow: 0 2px 8px rgba(43, 73, 112, .1); + box-sizing: border-box; + } + + .tour-family-tab-arrow.is-left { + left: 7px; + } + + .tour-family-tab-arrow.is-right { + right: 7px; + } + + .tour-family-tab-arrow:disabled { + border-color: #edf1f6; + color: #c5ceda; + background-color: #f8fafc; + box-shadow: none; + } + + .tour-family-tabs.is-single { + padding-top: 0; + } + + /* 只有一位亲属时直接展示表单,不显示没有切换意义的页签标题栏。 */ + .tour-family-tabs.is-single .van-tabs__wrap { + display: none; + } + + .tour-family-tabs .van-tabs__wrap { + height: 40px; + padding: 0 12px; + } + + .tour-family-tabs .van-tabs__nav { + background-color: #f6f9fd; + border-radius: 8px; + } + + /* 页签标题栏使用原生惯性滚动,亲属表单本身不参与左右拖动。 */ + .tour-family-tabs .van-tabs__wrap--scrollable .van-tabs__nav { + overflow-x: auto; + overflow-y: hidden; + width: 100%; + justify-content: flex-start; + scroll-behavior: smooth; + overscroll-behavior-x: contain; + touch-action: pan-x; + -webkit-overflow-scrolling: touch; + box-sizing: border-box; + } + + .tour-family-tabs .van-tabs__wrap--scrollable .van-tab { + -webkit-box-flex: 0 !important; + -webkit-flex: 0 0 auto !important; + flex: 0 0 auto !important; + min-width: 88px; + padding: 0 14px; + color: #718198; + font-size: 13px; + transition: color .2s ease, background-color .2s ease; + } + + .tour-family-tabs .van-tab--active { + color: #1989fa; + font-weight: 600; + } + + .tour-family-tabs .van-tabs__line { + width: 26px; + height: 3px; + border-radius: 2px; + background-color: #1989fa; + transition-timing-function: cubic-bezier(.22, .61, .36, 1); + } + + .tour-family-tabs .van-tabs__track { + transition-timing-function: cubic-bezier(.22, .61, .36, 1) !important; + } + + .tour-family-tabs .van-tab__text { + display: block; + max-width: 112px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .tour-family-form { + padding-top: 6px; + } + + .tour-family-empty { + padding: 28px 16px; + color: #94a3b8; + font-size: 13px; + text-align: center; + } + .tour-bottom-bar { position: fixed; left: 0; @@ -315,41 +460,401 @@ layout("/layouts/platform_h5.html"){ .tour-empty { padding-top: 40px; } + + + + .tour-my-page { + background-color: #f3f7fd; + } + + .tour-search-toolbar { + padding: 14px 12px 10px; + background-color: #f3f7fd; + } + + .tour-search-row { + gap: 8px; + } + + .tour-search-row .van-search { + margin: 0; + padding: 0; + overflow: hidden; + border-radius: 12px; + background-color: #fff; + box-shadow: 0 5px 16px rgba(43, 73, 112, .1); + } + + .tour-search-row .van-search__content { + height: 42px; + padding-left: 12px; + border-radius: 12px; + background-color: #fff; + } + + .tour-search-button { + width: 38px; + height: 34px; + margin-right: 4px; + border-radius: 9px; + font-size: 18px; + } + + .tour-year-entry { + width: 86px; + height: 42px; + min-height: 42px; + border-radius: 10px; + background-color: #fff; + box-shadow: 0 5px 16px rgba(43, 73, 112, .08); + flex-direction: row; + gap: 5px; + font-size: 13px; + } + + .tour-year-entry .van-icon { + font-size: 17px; + } + + .tour-list-scroll { + padding: 0 12px 20px; + } + + .tour-card { + margin: 0 0 10px; + padding: 14px; + border-radius: 12px; + box-shadow: 0 7px 20px rgba(55, 85, 126, .08); + } + + .tour-card-heading { + display: flex; + min-width: 0; + align-items: flex-start; + justify-content: space-between; + gap: 10px; + } + + .tour-card-title { + min-width: 0; + margin: 0; + overflow: hidden; + flex: 1; + color: #202938; + font-size: 16px; + line-height: 23px; + font-weight: 600; + text-overflow: ellipsis; + white-space: nowrap; + } + + .tour-card-status { + flex: none; + } + + .tour-card-tags { + margin-top: 8px; + } + + .tour-tag { + min-height: 22px; + height: auto; + padding: 2px 8px; + border: 0; + border-radius: 11px; + color: #1989fa; + background-color: #eaf4ff; + font-size: 11px; + line-height: 18px; + } + + .tour-info { + margin-top: 10px; + padding-top: 8px; + border-top: 1px solid #edf1f6; + } + + .tour-info-row { + min-height: 25px; + font-size: 13px; + line-height: 20px; + } + + .tour-actions { + margin: 11px -14px -14px; + padding: 10px 14px; + border-top: 1px solid #edf1f6; + background-color: #f8fbff; + } + + .tour-actions .van-button { + min-width: 72px; + height: 32px; + border-radius: 6px; + } + + .tour-popup-body { + padding: 12px 12px 82px; + background-color: #f3f7fd; + } + + .tour-section { + margin: 0 0 10px; + border-radius: 12px; + box-shadow: 0 7px 20px rgba(55, 85, 126, .08); + } + + .tour-section-title { + min-height: 46px; + padding: 0 14px 0 20px; + display: flex; + align-items: center; + color: #202938; + } + + .tour-bottom-bar { + box-shadow: 0 -6px 18px rgba(38, 66, 103, .08); + } + + /* 列表页结构与提案校工会预审核保持一致,业务字段及操作条件继续沿用疗休养逻辑。 */ + .tour-my-page .van-nav-bar { + background-color: #fff; + } + + .tour-my-page .van-nav-bar__title { + color: #172033; + font-size: 16px; + font-weight: 600; + } + + .tour-search-toolbar { + padding: 22px 12px 1px; + background-color: #f3f7fd; + } + + .tour-search-row { + display: block; + } + + .tour-search-row .van-search { + width: 100%; + margin: 0 0 8px; + padding: 0; + overflow: hidden; + border-radius: 12px; + background-color: #fff; + box-shadow: 0 5px 16px rgba(43, 73, 112, .1); + } + + .tour-search-row .van-search__content { + width: 100%; + height: 42px; + padding-left: 12px; + align-items: center; + border-radius: 12px; + background-color: #fff; + } + + .tour-search-row .van-field__control { + color: #263548; + font-size: 14px; + } + + .tour-year-entry { + width: 100%; + height: 44px; + min-height: 44px; + margin-bottom: 10px; + padding: 0 16px; + border-radius: 10px; + background-color: #fff; + box-shadow: 0 5px 16px rgba(43, 73, 112, .08); + flex-direction: row; + justify-content: space-between; + color: #66758a; + font-size: 14px; + box-sizing: border-box; + } + + .tour-year-entry .van-icon { + color: #a7b0bf; + font-size: 12px; + } + + .tour-year-entry--active, + .tour-year-entry--active .van-icon { + color: #1989fa; + } + + .tour-list-scroll { + padding: 2px 12px 24px; + } + + .tour-card { + margin: 0 0 10px; + padding: 0; + overflow: hidden; + border: 1px solid #e9eff7; + border-radius: 10px; + background-color: #fff; + box-shadow: 0 3px 11px rgba(51, 87, 126, .08); + } + + .tour-card-heading { + margin: 0; + padding: 13px 14px 8px; + align-items: flex-start; + } + + .tour-card-heading > div:first-child { + min-width: 0; + flex: 1; + } + + .tour-card-title { + color: #253247; + font-size: 15px; + line-height: 22px; + font-weight: 600; + } + + .tour-card-code { + margin-top: 2px; + color: #9ba6b6; + font-size: 12px; + line-height: 18px; + } + + .tour-card-tags { + margin: 0; + padding: 0 14px 7px; + } + + .tour-info { + margin: 0 14px; + padding: 8px 0; + border-top: 1px solid #eef2f7; + } + + .tour-info-row { + min-height: 28px; + padding: 3px 0; + color: #4f5d70; + font-size: 14px; + line-height: 22px; + box-sizing: border-box; + } + + .tour-info-label { + flex-basis: 88px; + color: #596779; + } + + .tour-actions { + display: flex; + margin: 0; + padding: 10px 14px; + border-top: 1px solid #eef2f7; + justify-content: flex-end; + gap: 0; + background-color: #fff; + } + + .tour-action-btn { + display: inline-flex; + min-width: 64px; + height: 30px; + padding: 0 10px; + border: 0; + align-items: center; + justify-content: center; + color: #1989fa; + font-size: 13px; + line-height: 20px; + background: transparent; + box-sizing: border-box; + } + + .tour-action-btn + .tour-action-btn { + border-left: 1px solid #edf1f6; + } + + .tour-action-btn .van-icon { + margin-right: 5px; + font-size: 15px; + } + + .tour-action-btn.is-danger { + color: #ee4d5a; + } + + .tour-action-btn:disabled { + color: #b8c0cc; + cursor: not-allowed; + } + + .tour-h5-empty { + min-height: 280px; + padding: 46px 18px 36px; + } + + .tour-h5-empty img { + width: 60%; + max-width: 190px; + } + + @media (max-width: 350px) { + .tour-search-toolbar, + .tour-list-scroll { + padding-right: 10px; + padding-left: 10px; + } + + .tour-action-btn { + min-width: 58px; + padding-right: 7px; + padding-left: 7px; + } + } -
+
-
- + +
+
+
+
-
{{ row.lineName || '未命名线路' }}
+
+
+
{{ row.lineName || '未命名线路' }}
+
报名时间:{{ row.signupTime || '--' }}
+
+ {{ row.curTaskName || statusText(row) }} +
{{ row.year || '' }}年度 {{ row.lineType }} @@ -375,19 +880,24 @@ layout("/layouts/platform_h5.html"){
- 查看 - 修改 - 撤回 - 取消报名 - 报销申请 - 亲属线路申请 + + + + + +
- +
+ 暂无报名记录插画 +
暂无报名记录
+
当前筛选条件下暂时没有疗休养报名
+
+
- +
选择年度
@@ -407,8 +917,8 @@ layout("/layouts/platform_h5.html"){
- - + +
教职工信息
@@ -462,8 +972,8 @@ layout("/layouts/platform_h5.html"){
- - + +
教职工信息
@@ -506,29 +1016,75 @@ layout("/layouts/platform_h5.html"){
-
家属信息
-
-
- 家属{{ index + 1 }} - 删除 +
+
+ 亲属信息 +
+ 删除亲属 + 添加亲属 +
- - - - - - - - - -
- + +
暂无亲属,请按需添加
@@ -537,14 +1093,14 @@ layout("/layouts/platform_h5.html"){
- - + + - - + + - - + +
@@ -556,6 +1112,8 @@ layout("/layouts/platform_h5.html"){ return { list: [], loading: false, + refreshing: false, + initialLoading: true, finished: false, pageForm: { pageNumber: 1, @@ -584,6 +1142,7 @@ layout("/layouts/platform_h5.html"){ fillBedInfo: true, signupForm: {}, familyData: [], + familyActive: 0, directRelativeForm: {}, bedTypeOptions: [], familyRelationshipOptions: [], @@ -593,10 +1152,14 @@ layout("/layouts/platform_h5.html"){ bedPickerFamilyIndex: -1, relationshipPickerVisible: false, relationshipFamilyIndex: -1, - directRelativePickerVisible: false + directRelativePickerVisible: false, + popupHistoryToken: "" } }, computed: { + currentFamily() { + return this.familyData[this.familyActive] || {} + }, yearOptions() { const currentYear = new Date().getFullYear() const years = [{ text: "全部年度", value: "" }] @@ -616,20 +1179,89 @@ layout("/layouts/platform_h5.html"){ } }, methods: { + // 页签优先展示亲属姓名;姓名尚未填写时使用亲属序号,便于区分每份亲属表单。 + familyTabTitle(family, familyIndex) { + const familyName = family && family.familyName ? String(family.familyName).trim() : "" + return familyName || "亲属" + (familyIndex + 1) + }, + // 等待页签渲染完成后再滚动定位,确保新增亲属始终展示在可视区域内。 + focusFamilyTab(familyIndex) { + const lastIndex = Math.max(this.familyData.length - 1, 0) + const nextIndex = Math.min(Math.max(Number(familyIndex) || 0, 0), lastIndex) + this.$set(this, "familyActive", nextIndex) + this.$nextTick(() => { + const familyTabs = this.$refs.familyTabs + if (familyTabs && typeof familyTabs.resize === "function") { + familyTabs.resize() + } + this.scrollFamilyTabIntoView(nextIndex) + }) + }, + // 将当前亲属页签平滑定位到导航可视区域中间,兼容箭头切换和直接点击页签。 + scrollFamilyTabIntoView(familyIndex) { + const familyTabs = this.$refs.familyTabs + const tabRoot = familyTabs && familyTabs.$el + if (!tabRoot) return + const tabNav = tabRoot.querySelector(".van-tabs__nav") + const tabItems = tabRoot.querySelectorAll(".van-tab") + const currentTab = tabItems[familyIndex] + if (!tabNav || !currentTab) return + const maxScrollLeft = Math.max(tabNav.scrollWidth - tabNav.clientWidth, 0) + const targetScrollLeft = currentTab.offsetLeft - (tabNav.clientWidth - currentTab.offsetWidth) / 2 + tabNav.scrollTo({ + left: Math.min(Math.max(targetScrollLeft, 0), maxScrollLeft), + behavior: "smooth" + }) + }, + // 直接点击页签时,等待 Vant 更新激活状态后再执行横向定位。 + handleFamilyTabChange(familyIndex) { + this.$nextTick(() => { + this.scrollFamilyTabIntoView(Number(familyIndex) || 0) + }) + }, + // 左右箭头按相邻顺序切换亲属,并复用页签组件的平滑定位能力。 + moveFamilyTab(step) { + const nextIndex = Number(this.familyActive) + Number(step) + if (nextIndex < 0 || nextIndex >= this.familyData.length) return + this.focusFamilyTab(nextIndex) + }, toBoolean(value) { return value === true || value === 1 || value === "1" || value === "true" || value === "TRUE" }, openYearPopup() { - this.yearPickerVisible = true + this.$set(this, "yearPickerVisible", true) + this.openHistoryPopup("year-picker") }, selectYear(item) { const year = item && item.value ? item.value : "" this.selectedYear = year this.pageForm.startYear = year this.pageForm.endYear = year - this.yearPickerVisible = false + this.closeHistoryPopup("year-picker") this.doSearch() }, + openHistoryPopup(popupKey) { + window.h5PopupHistory.open(this.popupHistoryToken, popupKey) + }, + closeHistoryPopup(popupKey) { + if (!window.h5PopupHistory.close(this.popupHistoryToken, popupKey)) { + this.syncPopupVisible(popupKey, false) + } + }, + syncPopupVisible(popupKey, visible) { + const popupFieldMap = { + "year-picker": "yearPickerVisible", + "detail": "detailVisible", + "signup": "signupVisible", + "bed-picker": "bedPickerVisible", + "relationship-picker": "relationshipPickerVisible", + "direct-relative-picker": "directRelativePickerVisible" + } + const field = popupFieldMap[popupKey] + if (field) { + this.$set(this, field, visible) + } + }, resetSearch() { this.selectedYear = "" this.pageForm.startYear = "" @@ -639,6 +1271,7 @@ layout("/layouts/platform_h5.html"){ }, doSearch() { this.list = [] + this.$set(this, "initialLoading", true) this.finished = false this.pageForm.pageNumber = 1 this.pageForm.totalCount = 0 @@ -651,7 +1284,6 @@ layout("/layouts/platform_h5.html"){ } this.loading = true this.$axios.post("/platform/tour/mysignup/pageData", this.pageForm).then((res) => { - this.loading = false if (res.code !== 0) { vant.Toast(res.msg || "加载失败") this.finished = true @@ -667,10 +1299,27 @@ layout("/layouts/platform_h5.html"){ this.pageForm.pageNumber += 1 } }).catch(() => { - this.loading = false this.finished = true + }).finally(() => { + this.loading = false + this.$set(this, "refreshing", false) + this.$set(this, "initialLoading", false) }) }, + /** + * 下拉刷新当前筛选结果:保留线路名称和年度条件,只重置分页数据。 + */ + onRefresh() { + if (this.loading) { + this.$set(this, "refreshing", false) + return + } + this.$set(this.pageForm, "pageNumber", 1) + this.$set(this.pageForm, "totalCount", 0) + this.$set(this, "list", []) + this.$set(this, "finished", false) + this.loadData() + }, loadOptions() { this.$axios.post("/platform/tour/mysignup/bedTypeOptions").then(res => { if (res.code === 0) this.bedTypeOptions = res.data || [] @@ -723,6 +1372,15 @@ layout("/layouts/platform_h5.html"){ if (Number(row.instanceState) === 20) return "已结束" return "审批中" }, + statusClass(row) { + if (!row || !row.instanceId || Number(row.instanceState) === 20) { + return "is-success" + } + if (Number(row.instanceState) === 45) { + return "is-muted" + } + return "is-warning" + }, openView(row) { this.detailRow = row || {} this.detail = {} @@ -740,7 +1398,8 @@ layout("/layouts/platform_h5.html"){ this.detailDirectRelative = data.directRelative || {} this.detailDirectFamilyUnitLine = this.toBoolean(data.directFamilyUnitLine) this.detailFillBedInfo = data.fillBedInfo === undefined || data.fillBedInfo === null || this.toBoolean(data.fillBedInfo) - this.detailVisible = true + this.$set(this, "detailVisible", true) + this.openHistoryPopup("detail") this.loadDetailDoneTasks() } else { vant.Toast(res.msg || "查询失败") @@ -828,10 +1487,12 @@ layout("/layouts/platform_h5.html"){ travelEndTime: matter.travelEndTime || "" }) this.familyData = (data.families || []).map(item => Object.assign(this.emptyFamily(), item)) + this.familyActive = 0 if (this.familyData.length > 0) { this.signupForm.hasFamily = true } - this.signupVisible = true + this.$set(this, "signupVisible", true) + this.openHistoryPopup("signup") }) }, isDirectFamilyLine(row) { @@ -845,6 +1506,7 @@ layout("/layouts/platform_h5.html"){ familyName: "", gender: "", idCard: "", + mobile: "", age: null, bedType: "", bedInfo: "", @@ -867,11 +1529,17 @@ layout("/layouts/platform_h5.html"){ } }, addFamily() { + if (!this.allowFamily || this.isDirectFamilyLine(this.signupForm)) return this.familyData.push(this.emptyFamily()) + this.focusFamilyTab(this.familyData.length - 1) this.signupForm.hasFamily = true }, - removeFamily(index) { - this.familyData.splice(index, 1) + removeFamily() { + if (this.familyData.length === 0) return + const removedIndex = this.familyActive + this.familyData.splice(removedIndex, 1) + // 删除当前页签后优先停留在同一位置;删除末项时回到新的最后一项。 + this.focusFamilyTab(this.familyData.length === 0 ? 0 : Math.min(removedIndex, this.familyData.length - 1)) this.signupForm.hasFamily = this.familyData.length > 0 }, openBedPicker(target, index) { @@ -880,8 +1548,9 @@ layout("/layouts/platform_h5.html"){ return } this.bedPickerTarget = target - this.bedPickerFamilyIndex = index === undefined ? -1 : index - this.bedPickerVisible = true + this.bedPickerFamilyIndex = target === "family" && index === undefined ? this.familyActive : (index === undefined ? -1 : index) + this.$set(this, "bedPickerVisible", true) + this.openHistoryPopup("bed-picker") }, confirmBedType(value) { if (this.bedPickerTarget === "family" && this.familyData[this.bedPickerFamilyIndex]) { @@ -889,34 +1558,36 @@ layout("/layouts/platform_h5.html"){ } else { this.signupForm.bedType = value } - this.bedPickerVisible = false + this.closeHistoryPopup("bed-picker") }, openRelationshipPicker(index) { if (this.relationshipColumns.length === 0) { vant.Toast("暂无关系选项") return } - this.relationshipFamilyIndex = index - this.relationshipPickerVisible = true + this.relationshipFamilyIndex = index === undefined ? this.familyActive : index + this.$set(this, "relationshipPickerVisible", true) + this.openHistoryPopup("relationship-picker") }, confirmRelationship(value) { if (this.familyData[this.relationshipFamilyIndex]) { this.familyData[this.relationshipFamilyIndex].relationship = value } - this.relationshipPickerVisible = false + this.closeHistoryPopup("relationship-picker") }, openDirectRelativePicker() { if (this.directRelativeColumns.length === 0) { vant.Toast("暂无亲属关系选项") return } - this.directRelativePickerVisible = true + this.$set(this, "directRelativePickerVisible", true) + this.openHistoryPopup("direct-relative-picker") }, confirmDirectRelative(value) { const item = value && value.item ? value.item : {} this.directRelativeForm.relationshipCode = item.code || "" this.directRelativeForm.relationshipName = item.name || value.text || "" - this.directRelativePickerVisible = false + this.closeHistoryPopup("direct-relative-picker") }, normalizeFamilyIdCard(row) { if (!row || !row.idCard) return @@ -927,19 +1598,36 @@ layout("/layouts/platform_h5.html"){ const idCard = String(value).trim().toUpperCase() return /^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dX]$/.test(idCard) }, + isBlankValue(value) { + return value === undefined || value === null || !String(value).trim() + }, + // 年满16周岁的亲属才强制填写身份证号码和手机号。 + familyContactRequired(family) { + return family && !this.isBlankValue(family.age) && Number(family.age) >= 16 + }, validateFamilies() { if (!this.allowFamily || !this.signupForm.hasFamily) return true if (this.familyData.length === 0) { vant.Toast("请添加亲属信息") return false } - const invalid = this.familyData.some(item => !item.familyName || !item.gender || !item.idCard || !item.relationship) - if (invalid) { - vant.Toast("请完善亲属姓名、性别、身份证号和关系") + const invalidBase = this.familyData.some(item => this.isBlankValue(item.familyName) + || this.isBlankValue(item.age) + || this.isBlankValue(item.gender) + || this.isBlankValue(item.relationship)) + if (invalidBase) { + vant.Toast("请完善亲属姓名、年龄、性别和与本人关系") return false } - if (this.familyData.some(item => !this.isValidIdCard(item.idCard))) { - vant.Toast("请输入正确的亲属身份证号") + const invalidContact = this.familyData.some(item => this.familyContactRequired(item) + && (this.isBlankValue(item.idCard) || this.isBlankValue(item.mobile))) + if (invalidContact) { + vant.Toast("年满16周岁的亲属必须填写身份证号码和手机号") + return false + } + const invalidIdCard = this.familyData.some(item => !this.isBlankValue(item.idCard) && !this.isValidIdCard(item.idCard)) + if (invalidIdCard) { + vant.Toast("请输入正确的亲属身份证号码") return false } return true @@ -965,21 +1653,21 @@ layout("/layouts/platform_h5.html"){ }) this.signupLoading = true this.$axios.post("/platform/tour/mysignup/doSignup", form).then((res) => { - this.signupLoading = false if (res.code === 0) { vant.Toast.success(res.msg || "修改成功") - this.signupVisible = false + this.closeHistoryPopup("signup") this.doSearch() } else { vant.Dialog.alert({ title: "提示", message: res.msg || "修改失败", confirmButtonColor: "#1867b0" }) } }).catch(() => { + }).finally(() => { this.signupLoading = false }) }, cancelSignup() { this.cancelByRow(this.signupForm, () => { - this.signupVisible = false + this.closeHistoryPopup("signup") }) }, cancelByRow(row, done) { @@ -997,7 +1685,6 @@ layout("/layouts/platform_h5.html"){ ledgerId: row.id, matterId: row.matterId }).then((res) => { - this.cancelLoading = false if (res.code === 0) { vant.Toast.success(res.msg || "取消报名成功") if (typeof done === "function") done() @@ -1006,6 +1693,7 @@ layout("/layouts/platform_h5.html"){ vant.Dialog.alert({ title: "提示", message: res.msg || "取消报名失败", confirmButtonColor: "#1867b0" }) } }).catch(() => { + }).finally(() => { this.cancelLoading = false }) }).catch(() => {}) @@ -1035,6 +1723,7 @@ layout("/layouts/platform_h5.html"){ destroySignup() { this.signupForm = {} this.familyData = [] + this.familyActive = 0 this.directRelativeForm = {} this.allowFamily = false this.fillBedInfo = true @@ -1043,7 +1732,14 @@ layout("/layouts/platform_h5.html"){ } }, created() { + this.$set(this, "popupHistoryToken", window.h5PopupHistory.register((popupKey) => { + this.syncPopupVisible(popupKey, false) + })) this.loadOptions() + this.loadData() + }, + beforeDestroy() { + window.h5PopupHistory.unregister(this.popupHistoryToken) } }) diff --git a/src/main/resources/views/platform/zhghh5/dayofficework/tour/schoolUnionApproval/index.html b/src/main/resources/views/platform/zhghh5/dayofficework/tour/schoolUnionApproval/index.html index 0242e899..069b4b0a 100644 --- a/src/main/resources/views/platform/zhghh5/dayofficework/tour/schoolUnionApproval/index.html +++ b/src/main/resources/views/platform/zhghh5/dayofficework/tour/schoolUnionApproval/index.html @@ -2,34 +2,36 @@ layout("/layouts/platform_h5.html"){ #--> - -
+
@@ -116,27 +443,39 @@ layout("/layouts/platform_h5.html"){ class="tour-approval-search" v-model="pageForm.keyword" placeholder="请输入工号/姓名/线路搜索" - show-action clearable input-align="left" @search="doSearch" @clear="doSearch"> - - - - - + + + +
- +
+
+
+
+ 暂无审核记录插画 +
暂无审核记录
+
当前筛选条件下暂时没有疗休养报名
+
+ + @@ -172,6 +511,7 @@ layout("/layouts/platform_h5.html"){
{{ formData.taskName || '审核' }}
const TOUR_INFO = { template: /*language=HTML*/ ` - -
+ +
+ +
教职工信息
@@ -261,9 +603,10 @@ layout("/layouts/platform_h5.html"){
- + +
- +
`, dicts: ["PROCESS_TASK_SUBMIT_TYPE"], data() { @@ -276,13 +619,15 @@ layout("/layouts/platform_h5.html"){ allowFamily: false, fillBedInfo: true, directFamilyUnitLine: false, - doneTasks: [] + doneTasks: [], + popupHistoryToken: "" } }, methods: { onOpen(row) { this.row = row || {} - this.visible = true + this.$set(this, "visible", true) + window.h5PopupHistory.open(this.popupHistoryToken, "detail") this.detail = {} this.familyData = [] this.directRelative = {} @@ -294,7 +639,9 @@ layout("/layouts/platform_h5.html"){ this.getDoneTasks() }, onClose() { - this.visible = false + if (!window.h5PopupHistory.close(this.popupHistoryToken, "detail")) { + this.$set(this, "visible", false) + } }, info() { this.$axios.post("/platform/tour/schoolUnionApproval/detail", { id: this.row.id }).then((res) => { @@ -337,6 +684,15 @@ layout("/layouts/platform_h5.html"){ } return this.hasFamily() ? "是" : "否" } + }, + created() { + this.$set(this, "popupHistoryToken", window.h5PopupHistory.register(() => { + this.$set(this, "visible", false) + this.$emit("closed") + })) + }, + beforeDestroy() { + window.h5PopupHistory.unregister(this.popupHistoryToken) } } @@ -370,7 +726,9 @@ layout("/layouts/platform_h5.html"){ { text: "全部线路类型", value: "" } ], formData: {}, - showApprovalForm: false + showApprovalForm: false, + pageSkeletonLoading: true, + filterOpened: false } }, methods: { @@ -378,12 +736,24 @@ layout("/layouts/platform_h5.html"){ onReady() { this.doSearch() }, + onTableLoading(state) { + if (state && state.initial) { + this.$set(this, "pageSkeletonLoading", !!state.loading) + } + }, + onFilterOpen() { + this.$set(this, "filterOpened", true) + }, + onFilterClose() { + this.$set(this, "filterOpened", false) + }, doSearch() { - this.$nextTick(async () => { - await Promise.all([this.loadUnionOptions(), this.loadLineTypeOptions()]) + this.$nextTick(() => { + Promise.all([this.loadUnionOptions(), this.loadLineTypeOptions()]).then(() => { this.pageForm.pageNumber = 1 this.pageForm.totalCount = 0 this.$refs.tableListRef.doSearch() + }) }) }, loadUnionOptions() { @@ -435,16 +805,12 @@ layout("/layouts/platform_h5.html"){ } this.$refs.infoRef.onOpen(row) }, - async handleTaskAction(val) { - try { - await this.$refs.formRef.validate() - } catch (e) { - return - } - this.$dialog.confirm({ + handleTaskAction(val) { + this.$refs.formRef.validate().then(() => { + this.$dialog.confirm({ title: "提示", message: "您确定要提交吗?" - }).then(() => { + }).then(() => { const loading = this.$toast.loading({ message: "加载中...", forbidClick: true, @@ -467,6 +833,7 @@ layout("/layouts/platform_h5.html"){ }).finally(() => { loading.close() }) + }).catch(() => {}) }).catch(() => {}) } } diff --git a/src/main/resources/views/platform/zhghh5/dayofficework/tour/signup/apply.html b/src/main/resources/views/platform/zhghh5/dayofficework/tour/signup/apply.html index de051fb3..bdcdb042 100644 --- a/src/main/resources/views/platform/zhghh5/dayofficework/tour/signup/apply.html +++ b/src/main/resources/views/platform/zhghh5/dayofficework/tour/signup/apply.html @@ -40,28 +40,132 @@ layout("/layouts/platform_tour_signup_h5.html"){ } .tour-card-title-row { + width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 10px; + box-sizing: border-box; } .tour-card-actions { + margin-left: auto; display: flex; gap: 8px; flex-shrink: 0; } - .tour-family-tab { - margin: 10px 12px 0; - height: 30px; - border-radius: 5px; - background: #1684d2; - color: #ffffff; - font-size: 14px; - font-weight: 700; - line-height: 30px; + .tour-family-tabs { + padding-top: 8px; + } + + .tour-family-tabs-shell { + position: relative; + } + + .tour-family-tab-arrow { + position: absolute; + top: 14px; + z-index: 2; + width: 28px; + height: 28px; + padding: 0; + border: 1px solid #d7e7fb; + border-radius: 50%; + color: #1989fa; + background-color: rgba(255, 255, 255, .94); + font-size: 15px; + line-height: 26px; text-align: center; + box-shadow: 0 2px 8px rgba(43, 73, 112, .1); + box-sizing: border-box; + } + + .tour-family-tab-arrow.is-left { + left: 7px; + } + + .tour-family-tab-arrow.is-right { + right: 7px; + } + + .tour-family-tab-arrow:disabled { + border-color: #edf1f6; + color: #c5ceda; + background-color: #f8fafc; + box-shadow: none; + } + + .tour-family-tabs.is-single { + padding-top: 0; + } + + /* 只有一位亲属时直接展示表单,不显示没有切换意义的页签标题栏。 */ + .tour-family-tabs.is-single .van-tabs__wrap { + display: none; + } + + .tour-family-tabs .van-tabs__wrap { + height: 40px; + padding: 0 12px; + } + + .tour-family-tabs .van-tabs__nav { + background-color: #f6f9fd; + border-radius: 8px; + } + + /* 页签标题栏使用原生惯性滚动,复杂亲属表单不再参与手势拖动。 */ + .tour-family-tabs .van-tabs__wrap--scrollable .van-tabs__nav { + overflow-x: auto; + overflow-y: hidden; + width: 100%; + justify-content: flex-start; + scroll-behavior: smooth; + overscroll-behavior-x: contain; + touch-action: pan-x; + -webkit-overflow-scrolling: touch; + box-sizing: border-box; + } + + .tour-family-tabs .van-tabs__wrap--scrollable .van-tab { + -webkit-box-flex: 0 !important; + -webkit-flex: 0 0 auto !important; + flex: 0 0 auto !important; + min-width: 88px; + padding: 0 14px; + color: #718198; + font-size: 13px; + transition: color .2s ease, background-color .2s ease; + } + + .tour-family-tabs .van-tab--active { + color: #1989fa; + font-weight: 600; + } + + .tour-family-tabs .van-tabs__line { + width: 26px; + height: 3px; + border-radius: 2px; + background-color: #1989fa; + transition-timing-function: cubic-bezier(.22, .61, .36, 1); + } + + .tour-family-tabs .van-tabs__track { + transition-timing-function: cubic-bezier(.22, .61, .36, 1) !important; + } + + .tour-family-tabs .van-tab__text { + display: block; + max-width: 112px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .tour-family-form { + padding-top: 6px; } .tour-field-tip { @@ -96,21 +200,77 @@ layout("/layouts/platform_tour_signup_h5.html"){ font-size: 13px; text-align: center; } + + + + .tour-apply-page { + padding: 12px 12px 82px; + background-color: #f3f7fd; + } + + .tour-apply-card { + margin-bottom: 10px; + border-radius: 12px; + box-shadow: 0 7px 20px rgba(55, 85, 126, .08); + } + + .tour-apply-title { + min-height: 46px; + padding: 0 14px 0 20px; + display: flex; + align-items: center; + border-bottom-color: #edf1f6; + color: #202938; + font-size: 16px; + line-height: 22px; + } + + .tour-apply-title::before { + top: 15px; + bottom: 15px; + left: 10px; + width: 3px; + height: auto; + border-radius: 2px; + background-color: #1989fa; + } + + .tour-card-actions .van-button { + height: 29px; + border-radius: 6px; + } + + .tour-submit-bar { + padding: 10px 12px calc(10px + env(safe-area-inset-bottom)); + border-top-color: #edf1f6; + box-shadow: 0 -6px 18px rgba(38, 66, 103, .08); + } + + .tour-submit-bar .van-button { + height: 42px; + border-radius: 8px; + font-size: 15px; + font-weight: 600; + } -
+
- 加载中... +
+
+
+
+