场地预约问题
This commit is contained in:
@@ -5,6 +5,9 @@ import io.v.nutz.activity.models.ActivitySiteInfo;
|
|||||||
import io.v.nutz.activity.services.SiteInfoService;
|
import io.v.nutz.activity.services.SiteInfoService;
|
||||||
import io.v.nutz.annontation.ViReturn;
|
import io.v.nutz.annontation.ViReturn;
|
||||||
import io.v.nutz.base.utils.PageUtil;
|
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.RequiresAuthentication;
|
||||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
import org.nutz.dao.Cnd;
|
import org.nutz.dao.Cnd;
|
||||||
@@ -62,18 +65,28 @@ public class SiteManageController {
|
|||||||
return siteInfoService.listPage(pageNumber, pageSize, cnd);
|
return siteInfoService.listPage(pageNumber, pageSize, cnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param activitySiteInfo data为场地表单,reserve_deadline传yyyy-MM-dd或空值(不限制)
|
||||||
|
* @return 保存成功沿用ViReturn默认成功结构,校验失败返回Result错误信息
|
||||||
|
*/
|
||||||
@At
|
@At
|
||||||
@ViReturn
|
@ViReturn
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
public Object doAdd(@Param("data") ActivitySiteInfo activitySiteInfo) {
|
public Object doAdd(@Param("data") ActivitySiteInfo activitySiteInfo) {
|
||||||
siteInfoService.insert(activitySiteInfo);
|
String error = siteInfoService.saveSite(activitySiteInfo, false);
|
||||||
return null;
|
return error == null ? null : Result.error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param activitySiteInfo data为带id的场地表单,reserve_deadline空值表示清除截止日期
|
||||||
|
* @return 保存成功沿用ViReturn默认成功结构,校验失败返回Result错误信息
|
||||||
|
*/
|
||||||
@At
|
@At
|
||||||
@ViReturn
|
@ViReturn
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
public Object doEdit(@Param("data") ActivitySiteInfo activitySiteInfo) {
|
public Object doEdit(@Param("data") ActivitySiteInfo activitySiteInfo) {
|
||||||
siteInfoService.updateIgnoreNull(activitySiteInfo);
|
String error = siteInfoService.saveSite(activitySiteInfo, true);
|
||||||
return null;
|
return error == null ? null : Result.error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@At
|
@At
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ import io.v.nutz.activity.models.ActivitySiteInfo;
|
|||||||
import io.v.nutz.activity.models.ActivitySiteReserve;
|
import io.v.nutz.activity.models.ActivitySiteReserve;
|
||||||
import io.v.nutz.activity.services.ActivityCommonService;
|
import io.v.nutz.activity.services.ActivityCommonService;
|
||||||
import io.v.nutz.activity.services.SiteInfoService;
|
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.activity.services.SiteReserveService;
|
||||||
import io.v.nutz.annontation.ViReturn;
|
import io.v.nutz.annontation.ViReturn;
|
||||||
import io.v.nutz.base.utils.PageUtil;
|
import io.v.nutz.base.utils.PageUtil;
|
||||||
@@ -53,6 +56,19 @@ public class SiteReserveController {
|
|||||||
@Inject
|
@Inject
|
||||||
private SiteInfoService siteInfoService;
|
private SiteInfoService siteInfoService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private SysHolidayService sysHolidayService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 无请求参数。返回日历对象:days为yyyy-MM-dd节假日列表,years为已同步年份列表。
|
||||||
|
* PC和手机使用同一本地数据源,预约请求不访问外部接口。
|
||||||
|
*/
|
||||||
|
@At
|
||||||
|
@ViReturn
|
||||||
|
public Object holidayCalendar() {
|
||||||
|
return sysHolidayService.getCalendar();
|
||||||
|
}
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private SiteReserveService siteReserveService;
|
private SiteReserveService siteReserveService;
|
||||||
|
|
||||||
@@ -152,8 +168,14 @@ public class SiteReserveController {
|
|||||||
return fetch.getReserve_state() > stateCode;
|
return fetch.getReserve_state() > stateCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param activitySiteReserve data提交预约表单,包含site_id及起止时间等原有字段
|
||||||
|
* @param days days提交yyyy-MM-dd日期数组,必须整批通过日期限制后才保存
|
||||||
|
* @return 校验失败返回Result错误对象;成功保持原接口由ViReturn包装的结果结构
|
||||||
|
*/
|
||||||
@At
|
@At
|
||||||
@ViReturn
|
@ViReturn
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
public Object doAdd(@Param("data") ActivitySiteReserve activitySiteReserve, @Param("days") String[] days) {
|
public Object doAdd(@Param("data") ActivitySiteReserve activitySiteReserve, @Param("days") String[] days) {
|
||||||
|
|
||||||
String r = R.UU32();
|
String r = R.UU32();
|
||||||
@@ -167,10 +189,12 @@ public class SiteReserveController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ActivitySiteInfo siteInfo = siteInfoService.fetch(activitySiteReserve.getSite_id());
|
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) {
|
for (String d : days) {
|
||||||
if (siteInfoService.isInCloseDates(siteInfo, d)) {
|
|
||||||
return Result.error(siteInfoService.getCloseDateMessage(siteInfo));
|
|
||||||
}
|
|
||||||
activitySiteReserve.setReserve_day(d);
|
activitySiteReserve.setReserve_day(d);
|
||||||
//查询这个人是否已经预约这个时间段
|
//查询这个人是否已经预约这个时间段
|
||||||
int count = siteReserveService.count("activity_site_reserve", Cnd.NEW().and("reserve_person_id", "=", ShiroUtil.getPrincipalProperty("id"))
|
int count = siteReserveService.count("activity_site_reserve", Cnd.NEW().and("reserve_person_id", "=", ShiroUtil.getPrincipalProperty("id"))
|
||||||
|
|||||||
@@ -57,6 +57,11 @@ public class ActivitySiteInfo {
|
|||||||
@ColDefine(type = ColType.MYSQL_JSON)
|
@ColDefine(type = ColType.MYSQL_JSON)
|
||||||
private List close_dates;
|
private List close_dates;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("最后可预约日期,yyyy-MM-dd,含当天;空值表示不限制")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 10)
|
||||||
|
private String reserve_deadline;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@Comment("创建人")
|
@Comment("创建人")
|
||||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||||
|
|||||||
@@ -6,6 +6,22 @@ import io.v.nutz.activity.models.ActivitySiteInfo;
|
|||||||
|
|
||||||
public interface SiteInfoService extends BaseService<ActivitySiteInfo> {
|
public interface SiteInfoService extends BaseService<ActivitySiteInfo> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验并保存场地,清空截止日期时显式保存空字符串,避免忽略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<String> days);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断指定预约日期是否落在场地关闭时段内。
|
* 判断指定预约日期是否落在场地关闭时段内。
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -4,9 +4,14 @@ package io.v.nutz.activity.services.impl;
|
|||||||
import cn.wizzer.framework.base.service.BaseServiceImpl;
|
import cn.wizzer.framework.base.service.BaseServiceImpl;
|
||||||
import io.v.nutz.activity.models.ActivitySiteInfo;
|
import io.v.nutz.activity.models.ActivitySiteInfo;
|
||||||
import io.v.nutz.activity.services.SiteInfoService;
|
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.dao.Dao;
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
import org.nutz.lang.Strings;
|
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.LocalDate;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
@@ -20,6 +25,85 @@ import java.util.List;
|
|||||||
@IocBean(args = {"refer:dao"})
|
@IocBean(args = {"refer:dao"})
|
||||||
public class SiteInfoServiceImpl extends BaseServiceImpl<ActivitySiteInfo> implements SiteInfoService {
|
public class SiteInfoServiceImpl extends BaseServiceImpl<ActivitySiteInfo> 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<String> 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) {
|
public SiteInfoServiceImpl(Dao dao) {
|
||||||
super(dao);
|
super(dao);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ import io.v.nutz.activity.models.ActivitySiteInfo;
|
|||||||
import io.v.nutz.activity.models.ActivitySiteReserve;
|
import io.v.nutz.activity.models.ActivitySiteReserve;
|
||||||
import io.v.nutz.activity.services.ActivityCommonService;
|
import io.v.nutz.activity.services.ActivityCommonService;
|
||||||
import io.v.nutz.activity.services.SiteInfoService;
|
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.activity.services.SiteReserveService;
|
||||||
import io.v.nutz.annontation.ViReturn;
|
import io.v.nutz.annontation.ViReturn;
|
||||||
import io.v.nutz.base.utils.SendMsg;
|
import io.v.nutz.base.utils.SendMsg;
|
||||||
@@ -50,6 +53,19 @@ public class SiteInfoMobileController {
|
|||||||
@Inject
|
@Inject
|
||||||
private SiteInfoService siteInfoService;
|
private SiteInfoService siteInfoService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private SysHolidayService sysHolidayService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 无请求参数。返回日历对象:days为yyyy-MM-dd节假日列表,years为已同步年份列表。
|
||||||
|
* PC和手机使用同一本地数据源,预约请求不访问外部接口。
|
||||||
|
*/
|
||||||
|
@At
|
||||||
|
@ViReturn
|
||||||
|
public Object holidayCalendar() {
|
||||||
|
return sysHolidayService.getCalendar();
|
||||||
|
}
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private SiteReserveService siteReserveService;
|
private SiteReserveService siteReserveService;
|
||||||
|
|
||||||
@@ -238,9 +254,16 @@ public class SiteInfoMobileController {
|
|||||||
return hours;
|
return hours;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param siteId 预约场地ID,限制开关以数据库场地配置为准
|
||||||
|
* @param times JSON数组,每项包含day(yyyy-MM-dd)、start_time、end_time
|
||||||
|
* @param message 预约事由
|
||||||
|
* @return 校验失败返回Result错误对象;成功保持原接口由ViReturn包装的结果结构
|
||||||
|
*/
|
||||||
@At("/reserveDo")
|
@At("/reserveDo")
|
||||||
@Ok("json:full")
|
@Ok("json:full")
|
||||||
@ViReturn
|
@ViReturn
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
public Object reserveDo(String siteId, String times, String message) {
|
public Object reserveDo(String siteId, String times, String message) {
|
||||||
String moduleName = activityCommonService.findModuleNameByActivityId(siteId);
|
String moduleName = activityCommonService.findModuleNameByActivityId(siteId);
|
||||||
Integer stateCode = activityCommonService.findStartStateCodeByModuleName(moduleName);
|
Integer stateCode = activityCommonService.findStartStateCodeByModuleName(moduleName);
|
||||||
@@ -254,13 +277,17 @@ public class SiteInfoMobileController {
|
|||||||
|
|
||||||
ActivitySiteInfo siteInfo = siteInfoService.fetch(siteId);
|
ActivitySiteInfo siteInfo = siteInfoService.fetch(siteId);
|
||||||
List<NutMap> nutMaps = Json.fromJsonAsList(NutMap.class, times);
|
List<NutMap> nutMaps = Json.fromJsonAsList(NutMap.class, times);
|
||||||
|
// 校验整批日期后再构造和保存预约,客户端传来的日期不能绕过工作日限制。
|
||||||
|
List<String> 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 str = "";
|
||||||
String r = R.UU32();
|
String r = R.UU32();
|
||||||
for (NutMap item : nutMaps) {
|
for (NutMap item : nutMaps) {
|
||||||
String reserveDay = item.getString("day");
|
String reserveDay = item.getString("day");
|
||||||
if (siteInfoService.isInCloseDates(siteInfo, reserveDay)) {
|
|
||||||
return Result.error(siteInfoService.getCloseDateMessage(siteInfo));
|
|
||||||
}
|
|
||||||
ActivitySiteReserve as = new ActivitySiteReserve();
|
ActivitySiteReserve as = new ActivitySiteReserve();
|
||||||
as.setSqid(r);
|
as.setSqid(r);
|
||||||
as.setSite_id(siteId);
|
as.setSite_id(siteId);
|
||||||
|
|||||||
@@ -268,17 +268,15 @@ layout("/mobile/platform.html"){
|
|||||||
times: [],
|
times: [],
|
||||||
weekList: [],
|
weekList: [],
|
||||||
calendarVisible: false,
|
calendarVisible: false,
|
||||||
selectDate: null,
|
selectDate: moment(),
|
||||||
//已经预约的记录
|
//已经预约的记录
|
||||||
alreadyReserveRecord: [],
|
alreadyReserveRecord: [],
|
||||||
holidays: [
|
holidays: [],
|
||||||
'2025-01-01',
|
holidayYears: [],
|
||||||
'2025-01-28','2025-01-29','2025-01-30','2025-01-31','2025-02-01','2025-02-02','2025-02-03','2025-02-04',
|
holidayReady: false,
|
||||||
'2025-04-04', '2025-04-05', '2025-04-06',
|
holidayLoading: false,
|
||||||
'2025-05-01', '2025-05-02', '2025-05-03', '2025-05-04', '2025-05-05',
|
reserveDataLoading: false,
|
||||||
'2025-05-31', '2025-06-01', '2025-06-02',
|
reservationLoading: false,
|
||||||
'2025-10-01', '2025-10-02', '2025-10-03', '2025-10-04', '2025-10-05', '2025-10-06', '2025-10-07', '2025-10-08'
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -306,17 +304,64 @@ layout("/mobile/platform.html"){
|
|||||||
calendarFormatter() {
|
calendarFormatter() {
|
||||||
return (day) => {
|
return (day) => {
|
||||||
// 休息日不能选择
|
// 休息日不能选择
|
||||||
if(this.site.workday === true) {
|
if (this.getReserveDateMessage(moment(day.date).format('YYYY-MM-DD'), this.site)) {
|
||||||
let week = day.date.getDay()
|
day.type = 'disabled'
|
||||||
if (week === 0 || week === 6) {
|
|
||||||
day.type = 'disabled'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return day
|
return day
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
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) {
|
close(f) {
|
||||||
if (this.times.length === 1) {
|
if (this.times.length === 1) {
|
||||||
vant.Toast('必须保留一个时间段')
|
vant.Toast('必须保留一个时间段')
|
||||||
@@ -333,23 +378,18 @@ layout("/mobile/platform.html"){
|
|||||||
//这里要排除掉休息日
|
//这里要排除掉休息日
|
||||||
setWeekList(startDate) {
|
setWeekList(startDate) {
|
||||||
const wk = []
|
const wk = []
|
||||||
wk.push(moment(startDate))
|
// 包含起始日期逐天校验;设定上限,跨入尚未同步年度时不会无限查找。
|
||||||
let count = 1
|
for (let count = 0; count < 366 && wk.length < 7; count++) {
|
||||||
while (wk.length < 7) {
|
const day = moment(startDate).add(count, 'd')
|
||||||
const addDate = 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) {
|
}
|
||||||
if(
|
if (this.site.workday === true && (!this.holidayReady || !this.holidayYears.includes(day.year()))) {
|
||||||
addDate.day() !== 0 &&
|
break
|
||||||
addDate.day() !== 6 &&
|
}
|
||||||
!this.holidays.includes(moment(addDate).format('YYYY-MM-DD'))
|
if (!this.getReserveDateMessage(day.format('YYYY-MM-DD'), this.site)) {
|
||||||
) {
|
wk.push(day)
|
||||||
wk.push(addDate)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
wk.push(addDate)
|
|
||||||
}
|
}
|
||||||
count++
|
|
||||||
}
|
}
|
||||||
this.weekList = wk
|
this.weekList = wk
|
||||||
},
|
},
|
||||||
@@ -398,7 +438,8 @@ layout("/mobile/platform.html"){
|
|||||||
return day >= start && day <= end
|
return day >= start && day <= end
|
||||||
},
|
},
|
||||||
showCloseDateMessage() {
|
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() {
|
reserve() {
|
||||||
if (this.times.length === 0) {
|
if (this.times.length === 0) {
|
||||||
@@ -407,6 +448,11 @@ layout("/mobile/platform.html"){
|
|||||||
}
|
}
|
||||||
for (let i = 0; i < this.times.length; i++) {
|
for (let i = 0; i < this.times.length; i++) {
|
||||||
let time = this.times[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)) {
|
if (this.isInCloseDates(time.day, this.site)) {
|
||||||
vant.Toast(this.getCloseReserveMessage(this.site))
|
vant.Toast(this.getCloseReserveMessage(this.site))
|
||||||
this.times.splice(i, 1)
|
this.times.splice(i, 1)
|
||||||
@@ -452,6 +498,11 @@ layout("/mobile/platform.html"){
|
|||||||
this.reserveLoading = false
|
this.reserveLoading = false
|
||||||
},
|
},
|
||||||
chooseTime(item) {
|
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)) {
|
if (this.isInCloseDates(this.selectDate.format('YYYY-MM-DD'), this.site)) {
|
||||||
vant.Toast(this.getCloseReserveMessage(this.site))
|
vant.Toast(this.getCloseReserveMessage(this.site))
|
||||||
return
|
return
|
||||||
@@ -477,7 +528,8 @@ layout("/mobile/platform.html"){
|
|||||||
return 3
|
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
|
return 4
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -492,66 +544,86 @@ layout("/mobile/platform.html"){
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async onLoad() {
|
onLoad() {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
const resp = await $.post('/mobile/activity/site/info/getDetail', {id: this.site_id})
|
return $.post('/mobile/activity/site/info/getDetail', {id: this.site_id})
|
||||||
if (resp.code === 0) {
|
.then((resp) => {
|
||||||
this.site = resp.data
|
if (resp.code !== 0 || !resp.data) {
|
||||||
if (this.site.close_dates && typeof this.site.close_dates === 'string') {
|
return $.Deferred().reject('场地信息加载失败').promise()
|
||||||
this.$set(this.site, 'close_dates', JSON.parse(this.site.close_dates))
|
}
|
||||||
} else if (!this.site.close_dates) {
|
this.site = resp.data
|
||||||
this.$set(this.site, 'close_dates', [])
|
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.loading = false
|
this.$set(this.site, 'close_dates', [])
|
||||||
},
|
}
|
||||||
async getReserve() {
|
return this.site.workday === true ? this.loadHolidayCalendar() : null
|
||||||
const resp = await $.post('/mobile/activity/site/info/getReserve', {
|
})
|
||||||
siteId: this.site_id,
|
.always(() => {
|
||||||
day: moment(this.selectDate).format('YYYY-MM-DD'),
|
this.loading = false
|
||||||
})
|
|
||||||
if (resp.code === 0) {
|
|
||||||
resp.data.forEach(item => {
|
|
||||||
item.isClick = true
|
|
||||||
})
|
})
|
||||||
this.timeData = resp.data
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
async getMyReservation() {
|
getReserve() {
|
||||||
const resp = await $.post('/mobile/activity/site/info/getMyReservation', {
|
// siteId为场地ID、day为选中日期;返回场次及占用状态数组。
|
||||||
site_id: this.site_id
|
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() {
|
getLatestWorkDay() {
|
||||||
//1.首先判断今天是不是工作日
|
const today = moment()
|
||||||
const weekNum = moment().day()
|
for (let offset = 0; offset < 366; offset++) {
|
||||||
let selectDate = null
|
const date = moment(today).add(offset, 'd')
|
||||||
if(this.site.workday === true) {
|
if (this.site.reserve_deadline && date.format('YYYY-MM-DD') > this.site.reserve_deadline) {
|
||||||
if (weekNum === 0) {
|
break
|
||||||
//周日
|
}
|
||||||
selectDate = moment().add(1, 'd')
|
if (this.site.workday === true && (!this.holidayReady || !this.holidayYears.includes(date.year()))) {
|
||||||
} else if (weekNum === 6) {
|
break
|
||||||
//周六
|
}
|
||||||
selectDate = moment().add(2, 'd')
|
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.site_id = getQueryString('id')
|
||||||
this.selectDate = this.getLatestWorkDay()
|
this.onLoad().then(() => {
|
||||||
await this.onLoad()
|
this.selectDate = this.getLatestWorkDay()
|
||||||
this.setWeekList(this.selectDate)
|
this.setWeekList(this.selectDate)
|
||||||
await this.getReserve()
|
const message = this.getReserveDateMessage(this.selectDate.format('YYYY-MM-DD'), this.site)
|
||||||
await this.getMyReservation()
|
if (message) {
|
||||||
|
vant.Toast(message)
|
||||||
|
}
|
||||||
|
return this.getReserve()
|
||||||
|
}).then(() => this.getMyReservation(), () => {
|
||||||
|
vant.Toast('场地或节假日数据加载失败,请刷新重试')
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -187,6 +187,19 @@ layout("/layouts/platform.html"){
|
|||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
|
<el-form-item label="预约截止日期" prop="reserve_deadline">
|
||||||
|
<!-- 截止日期含当天,清空表示不限制最晚预约日期。 -->
|
||||||
|
<el-date-picker
|
||||||
|
:value="formData.reserve_deadline"
|
||||||
|
@input="value => this.$set(formData, 'reserve_deadline', value || '')"
|
||||||
|
type="date"
|
||||||
|
value-format="yyyy-MM-dd"
|
||||||
|
placeholder="不设置则不限制"
|
||||||
|
clearable>
|
||||||
|
</el-date-picker>
|
||||||
|
<span style="color: #909399; margin-left: 12px">截止当天仍可预约,之后不可预约</span>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="关闭时段" label-width="110px">
|
<el-form-item label="关闭时段" label-width="110px">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-model="formData.close_dates"
|
v-model="formData.close_dates"
|
||||||
@@ -238,7 +251,7 @@ layout("/layouts/platform.html"){
|
|||||||
|
|
||||||
</el-form>
|
</el-form>
|
||||||
<div style="float: right;margin: 20px 0">
|
<div style="float: right;margin: 20px 0">
|
||||||
<el-button type="primary" :disabled="subDis" @click="operation">确 定</el-button>
|
<el-button type="primary" :disabled="formLoading" @click="operation">确 定</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -258,10 +271,11 @@ layout("/layouts/platform.html"){
|
|||||||
activityTypeList: [],
|
activityTypeList: [],
|
||||||
tabKey: '',
|
tabKey: '',
|
||||||
tableLoading: false,
|
tableLoading: false,
|
||||||
subDis: false,
|
formLoading: false,
|
||||||
tableData: [],
|
tableData: [],
|
||||||
formData: {
|
formData: {
|
||||||
open_hours: [{}],
|
open_hours: [{}],
|
||||||
|
reserve_deadline: '',
|
||||||
close_dates: []
|
close_dates: []
|
||||||
},
|
},
|
||||||
pageForm: {
|
pageForm: {
|
||||||
@@ -307,50 +321,71 @@ layout("/layouts/platform.html"){
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
async operation() {
|
operation() {
|
||||||
let method = this.formData.id ? "/doEdit" : "/doAdd"
|
const method = this.formData.id ? '/doEdit' : '/doAdd'
|
||||||
this.$refs["addForm"].validate(async (valid) => {
|
this.$refs['addForm'].validate((valid) => {
|
||||||
if (valid) {
|
if (!valid) {
|
||||||
this.subDis = true
|
return
|
||||||
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
|
|
||||||
}
|
}
|
||||||
});
|
// 清空日期时仍提交空字符串,确保后端删除旧的截止配置。
|
||||||
|
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) {
|
findOneSite(id) {
|
||||||
const {data} = await $.get("/platform/activity/site/mange/findOneSite", {id: id})
|
// id为场地ID;data为场地实体,旧场地没有截止日期时按不限处理。
|
||||||
if (!data.close_dates) {
|
this.formLoading = true
|
||||||
this.$set(data, 'close_dates', [])
|
return $.post('/platform/activity/site/mange/findOneSite', {id: id})
|
||||||
}
|
.then((res) => {
|
||||||
return data
|
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) {
|
openView(row) {
|
||||||
this.$refs.guava.view()
|
this.$refs.guava.view()
|
||||||
},
|
},
|
||||||
async openEdit(id) {
|
openEdit(id) {
|
||||||
this.formData = await this.findOneSite(id)
|
this.findOneSite(id).then((data) => {
|
||||||
this.$refs.guava.edit()
|
this.formData = data
|
||||||
|
this.$refs.guava.edit()
|
||||||
|
}, () => {
|
||||||
|
this.$message.error('场地信息加载失败,请稍后重试')
|
||||||
|
})
|
||||||
},
|
},
|
||||||
openAdd() {
|
openAdd() {
|
||||||
this.formData = {
|
this.formData = {
|
||||||
state: true,
|
state: true,
|
||||||
multiple: true,
|
multiple: true,
|
||||||
open_hours: [{}],
|
open_hours: [{}],
|
||||||
|
reserve_deadline: '',
|
||||||
close_dates: [],
|
close_dates: [],
|
||||||
create_username: '${@shiro.getPrincipalProperty("username")}',
|
create_username: '${@shiro.getPrincipalProperty("username")}',
|
||||||
create_time: moment().format('YYYY-MM-DD'),
|
create_time: moment().format('YYYY-MM-DD'),
|
||||||
|
|||||||
@@ -29,6 +29,11 @@ layout("/layouts/platform.html"){
|
|||||||
color: #1989FA;
|
color: #1989FA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.reserve-date-disabled {
|
||||||
|
opacity: 0.45;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
.div-Calendar {
|
.div-Calendar {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -325,7 +330,9 @@ layout("/layouts/platform.html"){
|
|||||||
</el-row>
|
</el-row>
|
||||||
<el-calendar v-model="reserve_time">
|
<el-calendar v-model="reserve_time">
|
||||||
<template slot="dateCell" slot-scope="{date, data}">
|
<template slot="dateCell" slot-scope="{date, data}">
|
||||||
<div class="div-Calendar" @click="pushDay(data)">
|
<div class="div-Calendar" @click="pushDay(data)"
|
||||||
|
:class="{'reserve-date-disabled': !!getReserveDateMessage(data.day, infoViewData)}"
|
||||||
|
:aria-disabled="!!getReserveDateMessage(data.day, infoViewData)">
|
||||||
<p :style="dayArray.includes(data.day) ? 'color: #246fb4' : ''">
|
<p :style="dayArray.includes(data.day) ? 'color: #246fb4' : ''">
|
||||||
{{ data.day.split('-').slice(1).join('-') }} {{ dayArray.includes(data.day) ? '√' : ''}}
|
{{ data.day.split('-').slice(1).join('-') }} {{ dayArray.includes(data.day) ? '√' : ''}}
|
||||||
</p>
|
</p>
|
||||||
@@ -465,7 +472,7 @@ layout("/layouts/platform.html"){
|
|||||||
|
|
||||||
<span slot="footer" class="dialog-footer">
|
<span slot="footer" class="dialog-footer">
|
||||||
<el-button @click="closeAdd">取 消</el-button>
|
<el-button @click="closeAdd">取 消</el-button>
|
||||||
<el-button type="primary" :disabled="subDis" @click="doAdd">确 定</el-button>
|
<el-button type="primary" :disabled="formLoading" @click="doAdd">确 定</el-button>
|
||||||
</span>
|
</span>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
@@ -535,7 +542,7 @@ layout("/layouts/platform.html"){
|
|||||||
reserveViewData: {},
|
reserveViewData: {},
|
||||||
tableLoading: false,
|
tableLoading: false,
|
||||||
addDialogVisible: false,
|
addDialogVisible: false,
|
||||||
subDis: false,
|
formLoading: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
tableData: [],
|
tableData: [],
|
||||||
formData: {
|
formData: {
|
||||||
@@ -568,8 +575,11 @@ layout("/layouts/platform.html"){
|
|||||||
/*reserve_cause: [{required: true, message: '请选择预约事由', trigger: ['blur', 'change']}],*/
|
/*reserve_cause: [{required: true, message: '请选择预约事由', trigger: ['blur', 'change']}],*/
|
||||||
},
|
},
|
||||||
dayArray: [],
|
dayArray: [],
|
||||||
holidays: ['2022-06-03','2022-06-04','2022-06-05','2022-09-10','2022-09-11','2022-09-12',
|
holidays: [],
|
||||||
'2022-10-01','2022-10-02','2022-10-03','2022-10-04','2022-10-05','2022-10-06','2022-10-07',],
|
holidayYears: [],
|
||||||
|
holidayReady: false,
|
||||||
|
holidayLoading: false,
|
||||||
|
reserveDataLoading: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
@@ -577,6 +587,56 @@ layout("/layouts/platform.html"){
|
|||||||
'reserve-info': httpVueLoader('/components/activity/site/ReserveInfo.vue'),
|
'reserve-info': httpVueLoader('/components/activity/site/ReserveInfo.vue'),
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
// 后端返回days日期数组及years已同步年份,加载失败时禁止按空日历放行。
|
||||||
|
loadHolidayCalendar() {
|
||||||
|
this.holidayReady = false
|
||||||
|
this.holidayLoading = true
|
||||||
|
return $.post('/platform/activity/site/reserve/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 + '为节假日,该场地仅限工作日预约' : ''
|
||||||
|
},
|
||||||
|
|
||||||
diaOpen() {
|
diaOpen() {
|
||||||
if(this.infoViewData.multiple === true ||
|
if(this.infoViewData.multiple === true ||
|
||||||
(this.infoViewData.open_hours.length === 1 && this.infoViewData.open_hours[0].disabled !== true)) {
|
(this.infoViewData.open_hours.length === 1 && this.infoViewData.open_hours[0].disabled !== true)) {
|
||||||
@@ -776,7 +836,6 @@ layout("/layouts/platform.html"){
|
|||||||
return day >= start && day <= end
|
return day >= start && day <= end
|
||||||
},
|
},
|
||||||
pushDay (data) {
|
pushDay (data) {
|
||||||
const d = new Date(data.day).getDay()
|
|
||||||
if (this.isInCloseDates(data.day, this.textData)) {
|
if (this.isInCloseDates(data.day, this.textData)) {
|
||||||
this.$message.warning(this.getCloseReserveMessage(this.textData))
|
this.$message.warning(this.getCloseReserveMessage(this.textData))
|
||||||
return
|
return
|
||||||
@@ -791,8 +850,9 @@ layout("/layouts/platform.html"){
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(this.textData.workday === true && (d === 0 || d === 6 || this.holidays.includes(data.day))) {
|
const workdayMessage = this.getReserveDateMessage(data.day, this.textData)
|
||||||
this.$message.warning('抱歉,该场地只能预约工作日')
|
if (workdayMessage) {
|
||||||
|
this.$message.warning(workdayMessage)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (data.day < moment(new Date()).format('YYYY-MM-DD')) {
|
if (data.day < moment(new Date()).format('YYYY-MM-DD')) {
|
||||||
@@ -895,11 +955,16 @@ layout("/layouts/platform.html"){
|
|||||||
transNum(hm) {
|
transNum(hm) {
|
||||||
return (moment("1970-01-01 " + hm).valueOf() + HOUR8) / HOUR1
|
return (moment("1970-01-01 " + hm).valueOf() + HOUR8) / HOUR1
|
||||||
},
|
},
|
||||||
async doAdd() {
|
doAdd() {
|
||||||
if (!this.formData.time) {
|
if (!this.formData.time) {
|
||||||
this.$notify.warning({title: '警告', message: '未选择预约时间!'});
|
this.$notify.warning({title: '警告', message: '未选择预约时间!'});
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
const invalidDay = this.dayArray.find(day => this.getReserveDateMessage(day, this.infoViewData))
|
||||||
|
if (invalidDay) {
|
||||||
|
this.$notify.warning({title: '警告', message: this.getReserveDateMessage(invalidDay, this.infoViewData)});
|
||||||
|
return
|
||||||
|
}
|
||||||
const closeDay = this.dayArray.find(day => this.isInCloseDates(day, this.infoViewData))
|
const closeDay = this.dayArray.find(day => this.isInCloseDates(day, this.infoViewData))
|
||||||
if (closeDay) {
|
if (closeDay) {
|
||||||
this.$notify.warning({title: '警告', message: this.getCloseReserveMessage(this.infoViewData)});
|
this.$notify.warning({title: '警告', message: this.getCloseReserveMessage(this.infoViewData)});
|
||||||
@@ -918,9 +983,9 @@ layout("/layouts/platform.html"){
|
|||||||
this.$notify.warning({title: '警告', message: '您预约的时间段已过!'});
|
this.$notify.warning({title: '警告', message: '您预约的时间段已过!'});
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.$refs["addForm"].validate(async (valid) => {
|
this.$refs["addForm"].validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
this.subDis = true
|
this.formLoading = true
|
||||||
const loading = this.$loading({
|
const loading = this.$loading({
|
||||||
lock: true,
|
lock: true,
|
||||||
text: '正在提交...',
|
text: '正在提交...',
|
||||||
@@ -928,20 +993,24 @@ layout("/layouts/platform.html"){
|
|||||||
background: 'rgba(0, 0, 0, 0.7)'
|
background: 'rgba(0, 0, 0, 0.7)'
|
||||||
});
|
});
|
||||||
|
|
||||||
const {code, msg} = await $.post(location.href + "/doAdd", {
|
$.post(location.href + "/doAdd", {
|
||||||
data: JSON.stringify(this.formData),
|
data: JSON.stringify(this.formData),
|
||||||
days: JSON.stringify(this.dayArray)
|
days: JSON.stringify(this.dayArray)
|
||||||
|
}).then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.addDialogVisible = false
|
||||||
|
this.$message.success(res.msg)
|
||||||
|
this.pageData()
|
||||||
|
this.$refs.guava.index()
|
||||||
|
} else {
|
||||||
|
this.$notify.warning({title: '警告', message: res.msg})
|
||||||
|
}
|
||||||
|
}, () => {
|
||||||
|
this.$message.warning('预约提交失败,请稍后重试')
|
||||||
|
}).always(() => {
|
||||||
|
loading.close()
|
||||||
|
this.formLoading = false
|
||||||
})
|
})
|
||||||
if (code === 0) {
|
|
||||||
this.addDialogVisible = false
|
|
||||||
this.$message.success(msg);
|
|
||||||
this.pageData()
|
|
||||||
this.$refs.guava.index()
|
|
||||||
} else {
|
|
||||||
this.$notify.warning({title: '警告', message: msg});
|
|
||||||
}
|
|
||||||
loading.close()
|
|
||||||
this.subDis = false
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -953,16 +1022,23 @@ layout("/layouts/platform.html"){
|
|||||||
this.$refs.reserve.backOptionShow = (role || backOptionShow)
|
this.$refs.reserve.backOptionShow = (role || backOptionShow)
|
||||||
this.$refs.reserve.openView(row.id)
|
this.$refs.reserve.openView(row.id)
|
||||||
},
|
},
|
||||||
async openReserve(data) {
|
openReserve(data) {
|
||||||
this.drawer = false
|
this.drawer = false
|
||||||
data.open_hours = site.reverseRankingDate(data.open_hours)
|
this.$set(data, 'open_hours', site.reverseRankingDate(data.open_hours))
|
||||||
this.reserveViewData = await this.findReserveInfo(data.id)
|
// 进入预约日历前先读取服务端假期,再显示可选日期。
|
||||||
this.reserveViewData.forEach(item => {
|
const calendarRequest = data.workday === true ? this.loadHolidayCalendar() : $.Deferred().resolve().promise()
|
||||||
item.index = 0
|
calendarRequest.then(() => this.findReserveInfo(data.id))
|
||||||
})
|
.then((records) => {
|
||||||
this.formData.site_id = data.id
|
this.reserveViewData = records
|
||||||
this.infoViewData = data
|
this.reserveViewData.forEach(item => {
|
||||||
this.$refs.guava.edit()
|
this.$set(item, 'index', 0)
|
||||||
|
})
|
||||||
|
this.$set(this.formData, 'site_id', data.id)
|
||||||
|
this.infoViewData = data
|
||||||
|
this.$refs.guava.edit()
|
||||||
|
}, () => {
|
||||||
|
this.$message.warning('预约数据加载失败,请稍后重试')
|
||||||
|
})
|
||||||
},
|
},
|
||||||
async doSearch() {
|
async doSearch() {
|
||||||
this.pageForm.pageNumber = 1
|
this.pageForm.pageNumber = 1
|
||||||
@@ -997,9 +1073,15 @@ layout("/layouts/platform.html"){
|
|||||||
}
|
}
|
||||||
}, "json");
|
}, "json");
|
||||||
},
|
},
|
||||||
async findReserveInfo(siteId) {
|
findReserveInfo(siteId) {
|
||||||
const {data} = await $.get("/platform/activity/site/reserve/findReserveInfo", {siteId})
|
// siteId为场地ID,返回该场地预约记录数组,供预约日历显示。
|
||||||
return data;
|
this.reserveDataLoading = true
|
||||||
|
return $.post('/platform/activity/site/reserve/findReserveInfo', {siteId: siteId})
|
||||||
|
.then((res) => {
|
||||||
|
return res.code === 0 && Array.isArray(res.data) ? res.data : $.Deferred().reject().promise()
|
||||||
|
}).always(() => {
|
||||||
|
this.reserveDataLoading = false
|
||||||
|
})
|
||||||
},
|
},
|
||||||
async findReserveInfoByClickDay(siteId, day) {
|
async findReserveInfoByClickDay(siteId, day) {
|
||||||
const {data} = await $.get("/platform/activity/site/reserve/findReserveInfo", {siteId: siteId, day: day})
|
const {data} = await $.get("/platform/activity/site/reserve/findReserveInfo", {siteId: siteId, day: day})
|
||||||
|
|||||||
Reference in New Issue
Block a user