diff --git a/src/main/java/io/v/nutz/activity/controller/site/SiteManageController.java b/src/main/java/io/v/nutz/activity/controller/site/SiteManageController.java index 124a962..67f079c 100644 --- a/src/main/java/io/v/nutz/activity/controller/site/SiteManageController.java +++ b/src/main/java/io/v/nutz/activity/controller/site/SiteManageController.java @@ -5,6 +5,9 @@ import io.v.nutz.activity.models.ActivitySiteInfo; import io.v.nutz.activity.services.SiteInfoService; import io.v.nutz.annontation.ViReturn; import io.v.nutz.base.utils.PageUtil; +import cn.wizzer.framework.base.Result; +import org.nutz.aop.interceptor.ioc.TransAop; +import org.nutz.ioc.aop.Aop; import org.apache.shiro.authz.annotation.RequiresAuthentication; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.nutz.dao.Cnd; @@ -62,18 +65,28 @@ public class SiteManageController { return siteInfoService.listPage(pageNumber, pageSize, cnd); } + /** + * @param activitySiteInfo data为场地表单,reserve_deadline传yyyy-MM-dd或空值(不限制) + * @return 保存成功沿用ViReturn默认成功结构,校验失败返回Result错误信息 + */ @At @ViReturn + @Aop(TransAop.READ_COMMITTED) public Object doAdd(@Param("data") ActivitySiteInfo activitySiteInfo) { - siteInfoService.insert(activitySiteInfo); - return null; + String error = siteInfoService.saveSite(activitySiteInfo, false); + return error == null ? null : Result.error(error); } + /** + * @param activitySiteInfo data为带id的场地表单,reserve_deadline空值表示清除截止日期 + * @return 保存成功沿用ViReturn默认成功结构,校验失败返回Result错误信息 + */ @At @ViReturn + @Aop(TransAop.READ_COMMITTED) public Object doEdit(@Param("data") ActivitySiteInfo activitySiteInfo) { - siteInfoService.updateIgnoreNull(activitySiteInfo); - return null; + String error = siteInfoService.saveSite(activitySiteInfo, true); + return error == null ? null : Result.error(error); } @At diff --git a/src/main/java/io/v/nutz/activity/controller/site/SiteReserveController.java b/src/main/java/io/v/nutz/activity/controller/site/SiteReserveController.java index a93649c..f03aa7c 100644 --- a/src/main/java/io/v/nutz/activity/controller/site/SiteReserveController.java +++ b/src/main/java/io/v/nutz/activity/controller/site/SiteReserveController.java @@ -7,6 +7,9 @@ import io.v.nutz.activity.models.ActivitySiteInfo; import io.v.nutz.activity.models.ActivitySiteReserve; import io.v.nutz.activity.services.ActivityCommonService; import io.v.nutz.activity.services.SiteInfoService; +import io.v.nutz.sys.services.SysHolidayService; +import org.nutz.aop.interceptor.ioc.TransAop; +import org.nutz.ioc.aop.Aop; import io.v.nutz.activity.services.SiteReserveService; import io.v.nutz.annontation.ViReturn; import io.v.nutz.base.utils.PageUtil; @@ -53,6 +56,19 @@ public class SiteReserveController { @Inject private SiteInfoService siteInfoService; + @Inject + private SysHolidayService sysHolidayService; + + /** + * 无请求参数。返回日历对象:days为yyyy-MM-dd节假日列表,years为已同步年份列表。 + * PC和手机使用同一本地数据源,预约请求不访问外部接口。 + */ + @At + @ViReturn + public Object holidayCalendar() { + return sysHolidayService.getCalendar(); + } + @Inject private SiteReserveService siteReserveService; @@ -152,8 +168,14 @@ public class SiteReserveController { return fetch.getReserve_state() > stateCode; } + /** + * @param activitySiteReserve data提交预约表单,包含site_id及起止时间等原有字段 + * @param days days提交yyyy-MM-dd日期数组,必须整批通过日期限制后才保存 + * @return 校验失败返回Result错误对象;成功保持原接口由ViReturn包装的结果结构 + */ @At @ViReturn + @Aop(TransAop.READ_COMMITTED) public Object doAdd(@Param("data") ActivitySiteReserve activitySiteReserve, @Param("days") String[] days) { String r = R.UU32(); @@ -167,10 +189,12 @@ public class SiteReserveController { } ActivitySiteInfo siteInfo = siteInfoService.fetch(activitySiteReserve.getSite_id()); + // 在第一条记录写入前校验全部日期,避免后面的节假日导致前面的日期已被保存。 + String dateError = siteInfoService.validateReserveDays(siteInfo, days == null ? null : Arrays.asList(days)); + if (dateError != null) { + return Result.error(dateError); + } for (String d : days) { - if (siteInfoService.isInCloseDates(siteInfo, d)) { - return Result.error(siteInfoService.getCloseDateMessage(siteInfo)); - } activitySiteReserve.setReserve_day(d); //查询这个人是否已经预约这个时间段 int count = siteReserveService.count("activity_site_reserve", Cnd.NEW().and("reserve_person_id", "=", ShiroUtil.getPrincipalProperty("id")) diff --git a/src/main/java/io/v/nutz/activity/models/ActivitySiteInfo.java b/src/main/java/io/v/nutz/activity/models/ActivitySiteInfo.java index af3ec68..2ebecf3 100644 --- a/src/main/java/io/v/nutz/activity/models/ActivitySiteInfo.java +++ b/src/main/java/io/v/nutz/activity/models/ActivitySiteInfo.java @@ -57,6 +57,11 @@ public class ActivitySiteInfo { @ColDefine(type = ColType.MYSQL_JSON) private List close_dates; + @Column + @Comment("最后可预约日期,yyyy-MM-dd,含当天;空值表示不限制") + @ColDefine(type = ColType.VARCHAR, width = 10) + private String reserve_deadline; + @Column @Comment("创建人") @ColDefine(type = ColType.VARCHAR, width = 30) diff --git a/src/main/java/io/v/nutz/activity/services/SiteInfoService.java b/src/main/java/io/v/nutz/activity/services/SiteInfoService.java index 6ffc84c..315424c 100644 --- a/src/main/java/io/v/nutz/activity/services/SiteInfoService.java +++ b/src/main/java/io/v/nutz/activity/services/SiteInfoService.java @@ -6,6 +6,22 @@ import io.v.nutz.activity.models.ActivitySiteInfo; public interface SiteInfoService extends BaseService { + /** + * 校验并保存场地,清空截止日期时显式保存空字符串,避免忽略null更新保留旧值。 + * @param siteInfo 场地表单,reserve_deadline为yyyy-MM-dd,null或空串表示不限制 + * @param edit true表示编辑已有场地(必须提供id),false表示新增 + * @return null表示保存成功,非空字符串为校验失败原因,校验失败不写入 + */ + String saveSite(ActivitySiteInfo siteInfo, boolean edit); + + /** + * 在写入预约记录前检查整批日期,截止日期和关闭时段始终生效,workday开启时额外排除周末及节假日。 + * @param siteInfo 从数据库读取的场地,不能使用客户端传入的开关 + * @param days 预约日期列表,每项必须为 yyyy-MM-dd + * @return null 表示全部日期允许预约,否则返回第一条拒绝原因 + */ + String validateReserveDays(ActivitySiteInfo siteInfo, java.util.List days); + /** * 判断指定预约日期是否落在场地关闭时段内。 * diff --git a/src/main/java/io/v/nutz/activity/services/impl/SiteInfoServiceImpl.java b/src/main/java/io/v/nutz/activity/services/impl/SiteInfoServiceImpl.java index 31feabf..9910368 100644 --- a/src/main/java/io/v/nutz/activity/services/impl/SiteInfoServiceImpl.java +++ b/src/main/java/io/v/nutz/activity/services/impl/SiteInfoServiceImpl.java @@ -4,9 +4,14 @@ package io.v.nutz.activity.services.impl; import cn.wizzer.framework.base.service.BaseServiceImpl; import io.v.nutz.activity.models.ActivitySiteInfo; import io.v.nutz.activity.services.SiteInfoService; +import io.v.nutz.sys.services.SysHolidayService; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.lang.util.NutMap; import org.nutz.dao.Dao; import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.lang.Strings; +import org.nutz.aop.interceptor.ioc.TransAop; +import org.nutz.ioc.aop.Aop; import java.time.LocalDate; import java.time.format.DateTimeFormatter; @@ -20,6 +25,85 @@ import java.util.List; @IocBean(args = {"refer:dao"}) public class SiteInfoServiceImpl extends BaseServiceImpl implements SiteInfoService { + @Inject + private SysHolidayService sysHolidayService; + + @Override + @Aop(TransAop.READ_COMMITTED) + public String saveSite(ActivitySiteInfo siteInfo, boolean edit) { + if (siteInfo == null || (edit && Strings.isBlank(siteInfo.getId()))) { + return "场地信息不完整,请刷新后重试"; + } + String deadline = Strings.sNull(siteInfo.getReserve_deadline()).trim(); + if (!deadline.isEmpty()) { + try { + if (!LocalDate.parse(deadline).toString().equals(deadline)) { + return "预约截止日期格式必须为yyyy-MM-dd"; + } + } catch (Exception e) { + return "预约截止日期格式必须为yyyy-MM-dd"; + } + } + // 日期框清空返回null;转为空串后updateIgnoreNull才能真正清除原来的截止日期。 + siteInfo.setReserve_deadline(deadline); + if (edit) { + updateIgnoreNull(siteInfo); + } else { + insert(siteInfo); + } + return null; + } + + @Override + public String validateReserveDays(ActivitySiteInfo siteInfo, List days) { + if (siteInfo == null) { + return "场地不存在,请刷新后重试"; + } + if (days == null || days.isEmpty()) { + return "请选择预约日期"; + } + LocalDate deadline = null; + if (!Strings.isBlank(siteInfo.getReserve_deadline())) { + try { + deadline = LocalDate.parse(siteInfo.getReserve_deadline()); + } catch (Exception e) { + return "场地预约截止日期配置异常,请联系管理员"; + } + } + // 整批只加载一次日历;未开启限定工作日时,不依赖节假日同步状态。 + NutMap calendar = Boolean.TRUE.equals(siteInfo.getWorkday()) ? sysHolidayService.getCalendar() : null; + for (String day : days) { + LocalDate date; + try { + date = LocalDate.parse(day); + if (!date.toString().equals(day)) { + return "预约日期格式必须为yyyy-MM-dd"; + } + } catch (Exception e) { + return "预约日期格式必须为yyyy-MM-dd"; + } + // 截止当天仍可预约,只有晚于截止日才拒绝;与限定工作日开关无关。 + if (deadline != null && date.isAfter(deadline)) { + return "该场地最晚可预约至" + deadline + ",请选择截止日期当天或之前的日期"; + } + if (isInCloseDates(siteInfo, day)) { + return getCloseDateMessage(siteInfo); + } + if (calendar != null) { + if (date.getDayOfWeek().getValue() >= 6) { + return day + "为周末,该场地仅限工作日预约"; + } + if (!((List) calendar.get("years")).contains(date.getYear())) { + return date.getYear() + "年节假日尚未同步,暂不能预约,请联系管理员"; + } + if (((List) calendar.get("days")).contains(day)) { + return day + "为节假日,该场地仅限工作日预约"; + } + } + } + return null; + } + public SiteInfoServiceImpl(Dao dao) { super(dao); } diff --git a/src/main/java/io/v/nutz/mobile/activity/site/SiteInfoMobileController.java b/src/main/java/io/v/nutz/mobile/activity/site/SiteInfoMobileController.java index 049d275..5d942bc 100644 --- a/src/main/java/io/v/nutz/mobile/activity/site/SiteInfoMobileController.java +++ b/src/main/java/io/v/nutz/mobile/activity/site/SiteInfoMobileController.java @@ -7,6 +7,9 @@ import io.v.nutz.activity.models.ActivitySiteInfo; import io.v.nutz.activity.models.ActivitySiteReserve; import io.v.nutz.activity.services.ActivityCommonService; import io.v.nutz.activity.services.SiteInfoService; +import io.v.nutz.sys.services.SysHolidayService; +import org.nutz.aop.interceptor.ioc.TransAop; +import org.nutz.ioc.aop.Aop; import io.v.nutz.activity.services.SiteReserveService; import io.v.nutz.annontation.ViReturn; import io.v.nutz.base.utils.SendMsg; @@ -50,6 +53,19 @@ public class SiteInfoMobileController { @Inject private SiteInfoService siteInfoService; + @Inject + private SysHolidayService sysHolidayService; + + /** + * 无请求参数。返回日历对象:days为yyyy-MM-dd节假日列表,years为已同步年份列表。 + * PC和手机使用同一本地数据源,预约请求不访问外部接口。 + */ + @At + @ViReturn + public Object holidayCalendar() { + return sysHolidayService.getCalendar(); + } + @Inject private SiteReserveService siteReserveService; @@ -238,9 +254,16 @@ public class SiteInfoMobileController { return hours; } + /** + * @param siteId 预约场地ID,限制开关以数据库场地配置为准 + * @param times JSON数组,每项包含day(yyyy-MM-dd)、start_time、end_time + * @param message 预约事由 + * @return 校验失败返回Result错误对象;成功保持原接口由ViReturn包装的结果结构 + */ @At("/reserveDo") @Ok("json:full") @ViReturn + @Aop(TransAop.READ_COMMITTED) public Object reserveDo(String siteId, String times, String message) { String moduleName = activityCommonService.findModuleNameByActivityId(siteId); Integer stateCode = activityCommonService.findStartStateCodeByModuleName(moduleName); @@ -254,13 +277,17 @@ public class SiteInfoMobileController { ActivitySiteInfo siteInfo = siteInfoService.fetch(siteId); List nutMaps = Json.fromJsonAsList(NutMap.class, times); + // 校验整批日期后再构造和保存预约,客户端传来的日期不能绕过工作日限制。 + List reserveDays = nutMaps == null ? null : nutMaps.stream() + .map(item -> item == null ? null : item.getString("day")).collect(Collectors.toList()); + String dateError = siteInfoService.validateReserveDays(siteInfo, reserveDays); + if (dateError != null) { + return Result.error(dateError); + } String str = ""; String r = R.UU32(); for (NutMap item : nutMaps) { String reserveDay = item.getString("day"); - if (siteInfoService.isInCloseDates(siteInfo, reserveDay)) { - return Result.error(siteInfoService.getCloseDateMessage(siteInfo)); - } ActivitySiteReserve as = new ActivitySiteReserve(); as.setSqid(r); as.setSite_id(siteId); diff --git a/src/main/resources/views/mobile/activity/site/reserve.html b/src/main/resources/views/mobile/activity/site/reserve.html index b178527..503d7b4 100644 --- a/src/main/resources/views/mobile/activity/site/reserve.html +++ b/src/main/resources/views/mobile/activity/site/reserve.html @@ -268,17 +268,15 @@ layout("/mobile/platform.html"){ times: [], weekList: [], calendarVisible: false, - selectDate: null, + selectDate: moment(), //已经预约的记录 alreadyReserveRecord: [], - holidays: [ - '2025-01-01', - '2025-01-28','2025-01-29','2025-01-30','2025-01-31','2025-02-01','2025-02-02','2025-02-03','2025-02-04', - '2025-04-04', '2025-04-05', '2025-04-06', - '2025-05-01', '2025-05-02', '2025-05-03', '2025-05-04', '2025-05-05', - '2025-05-31', '2025-06-01', '2025-06-02', - '2025-10-01', '2025-10-02', '2025-10-03', '2025-10-04', '2025-10-05', '2025-10-06', '2025-10-07', '2025-10-08' - ], + holidays: [], + holidayYears: [], + holidayReady: false, + holidayLoading: false, + reserveDataLoading: false, + reservationLoading: false, } }, computed: { @@ -306,17 +304,64 @@ layout("/mobile/platform.html"){ calendarFormatter() { return (day) => { // 休息日不能选择 - if(this.site.workday === true) { - let week = day.date.getDay() - if (week === 0 || week === 6) { - day.type = 'disabled' - } + if (this.getReserveDateMessage(moment(day.date).format('YYYY-MM-DD'), this.site)) { + day.type = 'disabled' } return day } } }, methods: { + // 后端返回days日期数组及years已同步年份,加载失败时禁止按空日历放行。 + loadHolidayCalendar() { + this.holidayReady = false + this.holidayLoading = true + return $.post('/mobile/activity/site/info/holidayCalendar', {}) + .then((res) => { + if (res.code !== 0 || !res.data || !Array.isArray(res.data.days) || !Array.isArray(res.data.years)) { + return $.Deferred().reject('节假日日历加载失败,请稍后重试').promise() + } + this.holidays = res.data.days + this.holidayYears = res.data.years + this.holidayReady = true + }) + .always(() => { + this.holidayLoading = false + }) + }, + // 截止日期独立于工作日开关:截止当天允许,超过截止日禁止;原有假期规则继续生效。 + getReserveDateMessage(day, siteData) { + if (!siteData) { + return '' + } + const date = moment(day, 'YYYY-MM-DD', true) + if (!date.isValid()) { + return '预约日期格式不正确' + } + if (siteData.reserve_deadline) { + const deadline = moment(siteData.reserve_deadline, 'YYYY-MM-DD', true) + if (!deadline.isValid()) { + return '场地预约截止日期配置异常,请联系管理员' + } + if (date.isAfter(deadline, 'day')) { + return '该场地最晚可预约至' + siteData.reserve_deadline + ',请选择截止日期当天或之前的日期' + } + } + if (siteData.workday !== true) { + return '' + } + if (date.day() === 0 || date.day() === 6) { + return day + '为周末,该场地仅限工作日预约' + } + if (!this.holidayReady) { + return '节假日日历尚未加载,请稍后重试' + } + if (!this.holidayYears.includes(date.year())) { + return date.year() + '年节假日尚未同步,暂不能预约,请联系管理员' + } + return this.holidays.includes(day) ? day + '为节假日,该场地仅限工作日预约' : '' + }, + close(f) { if (this.times.length === 1) { vant.Toast('必须保留一个时间段') @@ -333,23 +378,18 @@ layout("/mobile/platform.html"){ //这里要排除掉休息日 setWeekList(startDate) { const wk = [] - wk.push(moment(startDate)) - let count = 1 - while (wk.length < 7) { - const addDate = moment(startDate).add(count, 'd') - //这里不是休息日才能加到数组里 - if (this.site.workday === true) { - if( - addDate.day() !== 0 && - addDate.day() !== 6 && - !this.holidays.includes(moment(addDate).format('YYYY-MM-DD')) - ) { - wk.push(addDate) - } - } else { - wk.push(addDate) + // 包含起始日期逐天校验;设定上限,跨入尚未同步年度时不会无限查找。 + for (let count = 0; count < 366 && wk.length < 7; count++) { + const day = moment(startDate).add(count, 'd') + if (this.site.reserve_deadline && day.format('YYYY-MM-DD') > this.site.reserve_deadline) { + break + } + if (this.site.workday === true && (!this.holidayReady || !this.holidayYears.includes(day.year()))) { + break + } + if (!this.getReserveDateMessage(day.format('YYYY-MM-DD'), this.site)) { + wk.push(day) } - count++ } this.weekList = wk }, @@ -398,7 +438,8 @@ layout("/mobile/platform.html"){ return day >= start && day <= end }, showCloseDateMessage() { - vant.Toast(this.getCloseReserveMessage(this.site)) + const message = this.getReserveDateMessage(this.selectDate.format('YYYY-MM-DD'), this.site) + vant.Toast(message || this.getCloseReserveMessage(this.site)) }, reserve() { if (this.times.length === 0) { @@ -407,6 +448,11 @@ layout("/mobile/platform.html"){ } for (let i = 0; i < this.times.length; i++) { let time = this.times[i] + const workdayMessage = this.getReserveDateMessage(time.day, this.site) + if (workdayMessage) { + vant.Toast(workdayMessage) + return + } if (this.isInCloseDates(time.day, this.site)) { vant.Toast(this.getCloseReserveMessage(this.site)) this.times.splice(i, 1) @@ -452,6 +498,11 @@ layout("/mobile/platform.html"){ this.reserveLoading = false }, chooseTime(item) { + const workdayMessage = this.getReserveDateMessage(this.selectDate.format('YYYY-MM-DD'), this.site) + if (workdayMessage) { + vant.Toast(workdayMessage) + return + } if (this.isInCloseDates(this.selectDate.format('YYYY-MM-DD'), this.site)) { vant.Toast(this.getCloseReserveMessage(this.site)) return @@ -477,7 +528,8 @@ layout("/mobile/platform.html"){ return 3 } - if (this.isInCloseDates(this.selectDate.format('YYYY-MM-DD'), this.site)) { + if (this.getReserveDateMessage(this.selectDate.format('YYYY-MM-DD'), this.site) + || this.isInCloseDates(this.selectDate.format('YYYY-MM-DD'), this.site)) { return 4 } @@ -492,66 +544,86 @@ layout("/mobile/platform.html"){ } }, - async onLoad() { + onLoad() { this.loading = true - const resp = await $.post('/mobile/activity/site/info/getDetail', {id: this.site_id}) - if (resp.code === 0) { - this.site = resp.data - if (this.site.close_dates && typeof this.site.close_dates === 'string') { - this.$set(this.site, 'close_dates', JSON.parse(this.site.close_dates)) - } else if (!this.site.close_dates) { - this.$set(this.site, 'close_dates', []) - } - } - this.loading = false - }, - async getReserve() { - const resp = await $.post('/mobile/activity/site/info/getReserve', { - siteId: this.site_id, - day: moment(this.selectDate).format('YYYY-MM-DD'), - }) - if (resp.code === 0) { - resp.data.forEach(item => { - item.isClick = true + return $.post('/mobile/activity/site/info/getDetail', {id: this.site_id}) + .then((resp) => { + if (resp.code !== 0 || !resp.data) { + return $.Deferred().reject('场地信息加载失败').promise() + } + this.site = resp.data + if (typeof this.site.close_dates === 'string') { + this.$set(this.site, 'close_dates', JSON.parse(this.site.close_dates)) + } else if (!this.site.close_dates) { + this.$set(this.site, 'close_dates', []) + } + return this.site.workday === true ? this.loadHolidayCalendar() : null + }) + .always(() => { + this.loading = false }) - this.timeData = resp.data - } }, - async getMyReservation() { - const resp = await $.post('/mobile/activity/site/info/getMyReservation', { - site_id: this.site_id + getReserve() { + // siteId为场地ID、day为选中日期;返回场次及占用状态数组。 + this.reserveDataLoading = true + return $.post('/mobile/activity/site/info/getReserve', { + siteId: this.site_id, + day: this.selectDate.format('YYYY-MM-DD') + }).then((resp) => { + if (resp.code !== 0 || !Array.isArray(resp.data)) { + return $.Deferred().reject().promise() + } + resp.data.forEach(item => this.$set(item, 'isClick', true)) + this.timeData = resp.data + }).always(() => { + this.reserveDataLoading = false }) - if (resp.code === 0) { - this.alreadyReserveRecord = resp.data.map(v => v.reserve_day + " " + v.start_time + "-" + v.end_time) - } }, - //获取最新的一个工作日设为当前时间 + getMyReservation() { + // site_id为当前场地ID;预约日期和起止时间合并为前端已选状态标识。 + this.reservationLoading = true + return $.post('/mobile/activity/site/info/getMyReservation', {site_id: this.site_id}) + .then((resp) => { + if (resp.code !== 0 || !Array.isArray(resp.data)) { + return $.Deferred().reject().promise() + } + this.alreadyReserveRecord = resp.data.map(v => v.reserve_day + ' ' + v.start_time + '-' + v.end_time) + }).always(() => { + this.reservationLoading = false + }) + }, + // 场地与日历加载后再确定默认日期,普通周一至周五也始终返回有效日期。 getLatestWorkDay() { - //1.首先判断今天是不是工作日 - const weekNum = moment().day() - let selectDate = null - if(this.site.workday === true) { - if (weekNum === 0) { - //周日 - selectDate = moment().add(1, 'd') - } else if (weekNum === 6) { - //周六 - selectDate = moment().add(2, 'd') + const today = moment() + for (let offset = 0; offset < 366; offset++) { + const date = moment(today).add(offset, 'd') + if (this.site.reserve_deadline && date.format('YYYY-MM-DD') > this.site.reserve_deadline) { + break + } + if (this.site.workday === true && (!this.holidayReady || !this.holidayYears.includes(date.year()))) { + break + } + if (!this.getReserveDateMessage(date.format('YYYY-MM-DD'), this.site)) { + return date } - } else { - selectDate = moment() } - return selectDate + // 年度未同步时保留显示日期,但选择与后端提交都保持禁止。 + return today } }, - async created() { + created() { this.site_id = getQueryString('id') - this.selectDate = this.getLatestWorkDay() - await this.onLoad() - this.setWeekList(this.selectDate) - await this.getReserve() - await this.getMyReservation() - + this.onLoad().then(() => { + this.selectDate = this.getLatestWorkDay() + this.setWeekList(this.selectDate) + const message = this.getReserveDateMessage(this.selectDate.format('YYYY-MM-DD'), this.site) + if (message) { + vant.Toast(message) + } + return this.getReserve() + }).then(() => this.getMyReservation(), () => { + vant.Toast('场地或节假日数据加载失败,请刷新重试') + }) } }) diff --git a/src/main/resources/views/platform/activity/site/SiteManage.html b/src/main/resources/views/platform/activity/site/SiteManage.html index c213e38..ecfee5f 100644 --- a/src/main/resources/views/platform/activity/site/SiteManage.html +++ b/src/main/resources/views/platform/activity/site/SiteManage.html @@ -187,6 +187,19 @@ layout("/layouts/platform.html"){ + + + + + 截止当天仍可预约,之后不可预约 + +
- 确 定 + 确 定
@@ -258,10 +271,11 @@ layout("/layouts/platform.html"){ activityTypeList: [], tabKey: '', tableLoading: false, - subDis: false, + formLoading: false, tableData: [], formData: { open_hours: [{}], + reserve_deadline: '', close_dates: [] }, pageForm: { @@ -307,50 +321,71 @@ layout("/layouts/platform.html"){ } }); }, - async operation() { - let method = this.formData.id ? "/doEdit" : "/doAdd" - this.$refs["addForm"].validate(async (valid) => { - if (valid) { - this.subDis = true - const loading = this.$loading({ - lock: true, - text: '正在提交...', - spinner: 'el-icon-loading', - background: 'rgba(0, 0, 0, 0.7)' - }); - - const {code, data, msg} = await $.post(location.href + method, {data: JSON.stringify(this.formData)}) - if (code === 0) { - this.pageData() - this.$message.success(msg); - this.$refs.guava.index() - } else { - this.$message.error(msg); - } - loading.close() - this.subDis = false + operation() { + const method = this.formData.id ? '/doEdit' : '/doAdd' + this.$refs['addForm'].validate((valid) => { + if (!valid) { + return } - }); + // 清空日期时仍提交空字符串,确保后端删除旧的截止配置。 + this.$set(this.formData, 'reserve_deadline', this.formData.reserve_deadline || '') + this.formLoading = true + const loading = this.$loading({ + lock: true, + text: '正在提交...', + spinner: 'el-icon-loading', + background: 'rgba(0, 0, 0, 0.7)' + }) + // data包含原有场地字段及reserve_deadline;code为0表示保存成功,msg为结果提示。 + $.post(location.href + method, {data: JSON.stringify(this.formData)}) + .then((res) => { + if (res.code === 0) { + this.pageData() + this.$message.success(res.msg) + this.$refs.guava.index() + } else { + this.$message.error(res.msg) + } + }, () => { + this.$message.error('场地保存失败,请稍后重试') + }).always(() => { + loading.close() + this.formLoading = false + }) + }) }, - async findOneSite(id) { - const {data} = await $.get("/platform/activity/site/mange/findOneSite", {id: id}) - if (!data.close_dates) { - this.$set(data, 'close_dates', []) - } - return data + findOneSite(id) { + // id为场地ID;data为场地实体,旧场地没有截止日期时按不限处理。 + this.formLoading = true + return $.post('/platform/activity/site/mange/findOneSite', {id: id}) + .then((res) => { + if (res.code !== 0 || !res.data) { + return $.Deferred().reject().promise() + } + this.$set(res.data, 'close_dates', res.data.close_dates || []) + this.$set(res.data, 'reserve_deadline', res.data.reserve_deadline || '') + return res.data + }).always(() => { + this.formLoading = false + }) }, openView(row) { this.$refs.guava.view() }, - async openEdit(id) { - this.formData = await this.findOneSite(id) - this.$refs.guava.edit() + openEdit(id) { + this.findOneSite(id).then((data) => { + this.formData = data + this.$refs.guava.edit() + }, () => { + this.$message.error('场地信息加载失败,请稍后重试') + }) }, openAdd() { this.formData = { state: true, multiple: true, open_hours: [{}], + reserve_deadline: '', close_dates: [], create_username: '${@shiro.getPrincipalProperty("username")}', create_time: moment().format('YYYY-MM-DD'), diff --git a/src/main/resources/views/platform/activity/site/SiteReserve.html b/src/main/resources/views/platform/activity/site/SiteReserve.html index e67ca69..386213e 100644 --- a/src/main/resources/views/platform/activity/site/SiteReserve.html +++ b/src/main/resources/views/platform/activity/site/SiteReserve.html @@ -29,6 +29,11 @@ layout("/layouts/platform.html"){ color: #1989FA; } + .reserve-date-disabled { + opacity: 0.45; + cursor: not-allowed; + } + .div-Calendar { box-sizing: border-box; height: 100%; @@ -325,7 +330,9 @@ layout("/layouts/platform.html"){