commit
This commit is contained in:
+264
@@ -0,0 +1,264 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.flow.constant.FlowConst;
|
||||
import com.budwk.app.flow.engine.FlowEngine;
|
||||
import com.budwk.app.flow.entity.ProcessInstance;
|
||||
import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.enums.ProcessSubmitTypeEnum;
|
||||
import com.budwk.app.sys.models.SysHoliday;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugApply;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugFunctionType;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugInfo;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.service.SiteCugApplyService;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.service.SiteCugInfoService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import java.time.Year;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@IocBean
|
||||
@Ok("json:full")
|
||||
@Api(tags = "场地预约-场馆")
|
||||
@At("/platform/siteCug/apply")
|
||||
public class SiteCugApplyController {
|
||||
|
||||
private static final String YEARLY_BATCH_PREFIX = "YEARLY_BATCH:";
|
||||
|
||||
@Inject
|
||||
private Dao dao;
|
||||
@Inject
|
||||
private SiteCugInfoService infoService;
|
||||
@Inject
|
||||
private SiteCugApplyService applyService;
|
||||
@Inject
|
||||
private FlowEngine flowEngine;
|
||||
|
||||
@At("/")
|
||||
@SaCheckPermission("siteCug.apply")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/siteCug/apply/index.html")
|
||||
public void index() {}
|
||||
|
||||
@At("/h5")
|
||||
@SaCheckPermission(value = {"siteCug.apply", "h5.siteCug.apply"}, mode = SaMode.OR)
|
||||
@Ok("beetl:/platform/zhghh5/dayofficework/siteCug/apply/index.html")
|
||||
public void h5Index() {}
|
||||
|
||||
@At("/form/h5")
|
||||
@SaCheckPermission(value = {"siteCug.apply", "h5.siteCug.apply"}, mode = SaMode.OR)
|
||||
@Ok("beetl:/platform/zhghh5/dayofficework/siteCug/apply/form/index.html")
|
||||
public void h5Form() {}
|
||||
|
||||
@At
|
||||
@ApiOperation("分页查询场地")
|
||||
@SaCheckPermission(value = {"siteCug.apply", "h5.siteCug.apply"}, mode = SaMode.OR)
|
||||
public Result pageData(PageForm pageForm, @Param("type") String type) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and(SiteCugInfo::getState, "=", true);
|
||||
cnd.andEX(SiteCugInfo::getTypeId, "=", type);
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
seg.or(SiteCugInfo::getName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
seg.or(SiteCugInfo::getAddress, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
cnd.and(seg);
|
||||
}
|
||||
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||
cnd.asc("sortNum * 1");
|
||||
} else {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
}
|
||||
Pagination pagination = infoService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), cnd);
|
||||
List<NutMap> listMap = pagination.getList(NutMap.class);
|
||||
|
||||
List<SiteCugFunctionType> typeList = dao.query(SiteCugFunctionType.class, Cnd.NEW());
|
||||
Map<String, String> typeMap = typeList.stream().collect(Collectors.toMap(SiteCugFunctionType::getId, SiteCugFunctionType::getName));
|
||||
for (NutMap map : listMap) {
|
||||
map.put("typeName", typeMap.get(map.getString("typeId")));
|
||||
}
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("提交预约")
|
||||
@SaCheckPermission(value = {"siteCug.apply", "h5.siteCug.apply"}, mode = SaMode.OR)
|
||||
@SLog(tag = "场馆功能管理-场地预约", msg = "提交场地预约")
|
||||
public Result submit(@Param("data") SiteCugApply apply) {
|
||||
Map<Boolean, String> validate = applyService.validateApply(apply);
|
||||
if (validate.containsKey(false)) {
|
||||
return Result.error(validate.get(false));
|
||||
}
|
||||
submitSingleApply(apply);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At("/submitYearly")
|
||||
@ApiOperation("按本年后续同星期同时间段批量提交预约")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission(value = {"siteCug.apply", "h5.siteCug.apply"}, mode = SaMode.OR)
|
||||
@SLog(tag = "场馆功能管理-场地预约", msg = "批量提交本年场地预约")
|
||||
public Result submitYearly(@Param("data") SiteCugApply apply) {
|
||||
List<SiteCugApply> applyList = buildYearlyApplyList(apply);
|
||||
if (applyList.isEmpty()) {
|
||||
return Result.error("未生成可预约的日期");
|
||||
}
|
||||
for (SiteCugApply item : applyList) {
|
||||
Map<Boolean, String> validate = applyService.validateApply(item);
|
||||
if (validate.containsKey(false)) {
|
||||
return Result.error(String.format("%s 预约失败:%s", item.getReserveStartTime(), validate.get(false)));
|
||||
}
|
||||
}
|
||||
String yearlyBatchNo = YEARLY_BATCH_PREFIX + UUID.randomUUID();
|
||||
for (SiteCugApply item : applyList) {
|
||||
item.setBackOption(yearlyBatchNo);
|
||||
submitSingleApply(item);
|
||||
}
|
||||
return Result.success(String.format("已成功预约本年剩余%d个时间段", applyList.size()));
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("查询预约限制配置")
|
||||
@SaCheckPermission(value = {"siteCug.apply", "h5.siteCug.apply"}, mode = SaMode.OR)
|
||||
public Result timeLimitConfig(@Param("siteId") String siteId) {
|
||||
if (StrUtil.isBlank(siteId)) {
|
||||
return Result.success(NutMap.NEW().addv("filterHolidays", false).addv("holidayList", new ArrayList<>()).addv("notApplyTimeList", new ArrayList<>()));
|
||||
}
|
||||
SiteCugInfo info = infoService.fetch(siteId);
|
||||
if (info == null) {
|
||||
return Result.success(NutMap.NEW().addv("filterHolidays", false).addv("holidayList", new ArrayList<>()).addv("notApplyTimeList", new ArrayList<>()));
|
||||
}
|
||||
List<String> holidayList = new ArrayList<>();
|
||||
if (Boolean.TRUE.equals(info.getFilterHolidays())) {
|
||||
int currentYear = Year.now().getValue();
|
||||
List<String> yearPrefixList = List.of(currentYear + "-", (currentYear + 1) + "-");
|
||||
List<SysHoliday> holidays = dao.query(SysHoliday.class, Cnd.NEW());
|
||||
holidayList = holidays.stream()
|
||||
.map(SysHoliday::getDay)
|
||||
.filter(day -> day != null && yearPrefixList.stream().anyMatch(day::startsWith))
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
return Result.success(NutMap.NEW()
|
||||
.addv("filterHolidays", Boolean.TRUE.equals(info.getFilterHolidays()))
|
||||
.addv("holidayList", holidayList)
|
||||
.addv("notApplyTimeList", info.getNotApplyTimeList() == null ? new ArrayList<>() : info.getNotApplyTimeList()));
|
||||
}
|
||||
|
||||
private List<SiteCugApply> buildYearlyApplyList(SiteCugApply apply) {
|
||||
if (apply == null || StrUtil.hasBlank(apply.getReserveStartTime(), apply.getReserveEndTime())) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
DateTime start = DateUtil.parseDateTime(apply.getReserveStartTime());
|
||||
DateTime end = DateUtil.parseDateTime(apply.getReserveEndTime());
|
||||
if (!end.isAfter(start)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
SiteCugInfo siteInfo = infoService.fetch(apply.getSiteId());
|
||||
if (siteInfo == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
List<String> holidayList = new ArrayList<>();
|
||||
if (Boolean.TRUE.equals(siteInfo.getFilterHolidays())) {
|
||||
int currentYear = start.year();
|
||||
List<String> yearPrefixList = List.of(currentYear + "-", (currentYear + 1) + "-");
|
||||
List<SysHoliday> holidays = dao.query(SysHoliday.class, Cnd.NEW());
|
||||
holidayList = holidays.stream()
|
||||
.map(SysHoliday::getDay)
|
||||
.filter(day -> day != null && yearPrefixList.stream().anyMatch(day::startsWith))
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
int targetWeek = start.dayOfWeek() - 1;
|
||||
int startHour = start.hour(true);
|
||||
int startMinute = start.minute();
|
||||
int startSecond = start.second();
|
||||
int endHour = end.hour(true);
|
||||
int endMinute = end.minute();
|
||||
int endSecond = end.second();
|
||||
Date current = DateUtil.beginOfDay(start);
|
||||
Date endOfYear = DateUtil.endOfYear(start);
|
||||
List<SiteCugApply> result = new ArrayList<>();
|
||||
while (current.compareTo(endOfYear) <= 0) {
|
||||
DateTime currentDate = DateUtil.date(current);
|
||||
String currentDay = DateUtil.formatDate(currentDate);
|
||||
if (currentDate.dayOfWeek() - 1 == targetWeek && !holidayList.contains(currentDay)) {
|
||||
SiteCugApply item = copyApply(apply);
|
||||
item.setId(null);
|
||||
item.setReserveStartTime(DateUtil.formatDateTime(buildDateTime(currentDate, startHour, startMinute, startSecond)));
|
||||
item.setReserveEndTime(DateUtil.formatDateTime(buildDateTime(currentDate, endHour, endMinute, endSecond)));
|
||||
result.add(item);
|
||||
}
|
||||
current = DateUtil.offsetDay(current, 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private DateTime buildDateTime(DateTime date, int hour, int minute, int second) {
|
||||
return DateUtil.parseDateTime(String.format("%s %02d:%02d:%02d", DateUtil.formatDate(date), hour, minute, second));
|
||||
}
|
||||
|
||||
private SiteCugApply copyApply(SiteCugApply apply) {
|
||||
return new SiteCugApply()
|
||||
.setSiteId(apply.getSiteId())
|
||||
.setApplyUserId(apply.getApplyUserId())
|
||||
.setApplyUserName(apply.getApplyUserName())
|
||||
.setApplySex(apply.getApplySex())
|
||||
.setApplyLoginName(apply.getApplyLoginName())
|
||||
.setApplyUnitId(apply.getApplyUnitId())
|
||||
.setApplyUnitName(apply.getApplyUnitName())
|
||||
.setReserveType(apply.getReserveType())
|
||||
.setApplyUnionId(apply.getApplyUnionId())
|
||||
.setApplyUnionName(apply.getApplyUnionName())
|
||||
.setClubId(apply.getClubId())
|
||||
.setClubName(apply.getClubName())
|
||||
.setApplyMobile(apply.getApplyMobile())
|
||||
.setReserveStartTime(apply.getReserveStartTime())
|
||||
.setReserveEndTime(apply.getReserveEndTime())
|
||||
.setJoinCount(apply.getJoinCount())
|
||||
.setApplyCause(apply.getApplyCause())
|
||||
.setBackOption(apply.getBackOption());
|
||||
}
|
||||
|
||||
private void submitSingleApply(SiteCugApply apply) {
|
||||
dao.insertOrUpdate(apply);
|
||||
|
||||
Dict args = Dict.create();
|
||||
args.set(FlowConst.SUBMIT_TYPE, ProcessSubmitTypeEnum.APPLY.getCode());
|
||||
args.set(FlowConst.FORM_DATA, apply);
|
||||
ProcessInstance instance = flowEngine.startProcessInstanceByKey("CDYY", apply.getId(), SecurityUtil.getUserId(), args);
|
||||
|
||||
List<ProcessTask> doingTaskList = flowEngine.processTaskService().getDoingTaskList(instance.getId(), null);
|
||||
for (ProcessTask task : doingTaskList) {
|
||||
flowEngine.executeProcessTask(task.getId(), SecurityUtil.getUserId(), args);
|
||||
}
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugFunctionType;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.service.SiteCugFunctionTypeService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@IocBean
|
||||
@Ok("json:full")
|
||||
@Api(tags = "功能类型")
|
||||
@At("/platform/siteCug/function/type")
|
||||
public class SiteCugFunctionTypeController {
|
||||
|
||||
@Inject
|
||||
private SiteCugFunctionTypeService typeService;
|
||||
|
||||
@At("")
|
||||
@SaCheckPermission("siteCug.function.type")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/siteCug/type/index.html")
|
||||
public void index() {}
|
||||
|
||||
@At
|
||||
@ApiOperation("分页查询")
|
||||
@SaCheckPermission("siteCug.function.type")
|
||||
public Result pageData(PageForm pageForm) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
seg.or(SiteCugFunctionType::getName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
seg.or(SiteCugFunctionType::getCode, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
cnd.and(seg);
|
||||
}
|
||||
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||
cnd.asc("code");
|
||||
} else {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
}
|
||||
Pagination pagination = typeService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), cnd);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("新增/修改功能类型")
|
||||
@SaCheckPermission("siteCug.function.type")
|
||||
@SLog(tag = "场馆功能管理-功能类型", msg = "新增/修改功能类型")
|
||||
public Object submit(SiteCugFunctionType type) {
|
||||
typeService.insertOrUpdate(type);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("删除功能类型")
|
||||
@SaCheckPermission("siteCug.function.type")
|
||||
@SLog(tag = "场馆功能管理-功能类型", msg = "删除功能类型")
|
||||
public Object delete(String id) {
|
||||
typeService.delete(id);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("查询功能类型")
|
||||
@SaCheckLogin
|
||||
public Result queryFunctionType() {
|
||||
List<SiteCugFunctionType> list = typeService.query(Cnd.where(SiteCugFunctionType::getEnable, "=", true).asc(SiteCugFunctionType::getCode));
|
||||
return Result.success(list);
|
||||
}
|
||||
}
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugFunctionType;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugInfo;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.service.SiteCugInfoService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Lang;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@IocBean
|
||||
@Ok("json:full")
|
||||
@Api(tags = "场地管理-场馆")
|
||||
@At("/platform/siteCug/manage")
|
||||
public class SiteCugManageController {
|
||||
|
||||
@Inject
|
||||
private Dao dao;
|
||||
@Inject
|
||||
private SiteCugInfoService infoService;
|
||||
|
||||
@At("")
|
||||
@SaCheckPermission("siteCug.manage")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/siteCug/manage/index.html")
|
||||
public void index() {}
|
||||
|
||||
@At
|
||||
@ApiOperation("分页查询")
|
||||
@SaCheckPermission("siteCug.manage")
|
||||
public Result pageData(PageForm pageForm, @Param("type") String type) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX(SiteCugInfo::getTypeId, "=", type);
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
seg.or(SiteCugInfo::getName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
seg.or(SiteCugInfo::getAddress, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
cnd.and(seg);
|
||||
}
|
||||
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||
cnd.asc("sortNum * 1");
|
||||
} else {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
}
|
||||
Pagination pagination = infoService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), cnd);
|
||||
List<NutMap> listMap = pagination.getList(NutMap.class);
|
||||
|
||||
List<SiteCugFunctionType> typeList = dao.query(SiteCugFunctionType.class, Cnd.NEW());
|
||||
Map<String, String> typeMap = typeList.stream().collect(Collectors.toMap(SiteCugFunctionType::getId, SiteCugFunctionType::getName));
|
||||
|
||||
for (NutMap map : listMap) {
|
||||
map.put("typeName", typeMap.get(map.getString("typeId")));
|
||||
}
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("新增/修改场地")
|
||||
@SaCheckPermission("siteCug.manage")
|
||||
@SLog(tag = "场馆功能管理-场地管理", msg = "新增/修改场地")
|
||||
public Object submit(@Param("data") SiteCugInfo info) {
|
||||
List<NutMap> notApplyTimeList = info.getNotApplyTimeList();
|
||||
if (notApplyTimeList != null) {
|
||||
boolean invalid = notApplyTimeList.stream().anyMatch(item ->
|
||||
item == null
|
||||
|| StrUtil.isBlank(item.getString("date"))
|
||||
|| StrUtil.isBlank(item.getString("startTime"))
|
||||
|| StrUtil.isBlank(item.getString("endTime"))
|
||||
|| item.getString("startTime").compareTo(item.getString("endTime")) >= 0);
|
||||
if (invalid) {
|
||||
return Result.error("禁用时间设置有误");
|
||||
}
|
||||
}
|
||||
if (info.getFilterHolidays() == null) {
|
||||
info.setFilterHolidays(false);
|
||||
}
|
||||
infoService.insertOrUpdate(info);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("删除场地")
|
||||
@SaCheckPermission("siteCug.manage")
|
||||
@SLog(tag = "场馆功能管理-场地管理", msg = "删除场地")
|
||||
public Object delete(String id) {
|
||||
infoService.delete(id);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("查询场地")
|
||||
@SaCheckLogin
|
||||
public Result querySites() {
|
||||
List<SiteCugInfo> list = infoService.query(Cnd.where(SiteCugInfo::getState, "=", true).desc(SiteCugInfo::getSortNum));
|
||||
return Result.success(list);
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("查询单个场地")
|
||||
@SaCheckLogin
|
||||
public Result info(String id) {
|
||||
SiteCugInfo info = infoService.fetch(id);
|
||||
if (info == null) {
|
||||
return Result.success(null);
|
||||
}
|
||||
NutMap map = Lang.obj2nutmap(info);
|
||||
SiteCugFunctionType type = dao.fetch(SiteCugFunctionType.class, info.getTypeId());
|
||||
map.put("typeName", type == null ? "" : type.getName());
|
||||
return Result.success(map);
|
||||
}
|
||||
}
|
||||
+184
@@ -0,0 +1,184 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.flow.engine.FlowEngine;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugApply;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.service.SiteCugApplyService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@IocBean
|
||||
@Ok("json:full")
|
||||
@Api(tags = "场地预约-我的预约")
|
||||
@At("/platform/siteCug/mine")
|
||||
public class SiteCugMineController {
|
||||
|
||||
private static final String YEARLY_BATCH_PREFIX = "YEARLY_BATCH:";
|
||||
|
||||
@Inject
|
||||
private FlowEngine flowEngine;
|
||||
@Inject
|
||||
private SiteCugApplyService applyService;
|
||||
|
||||
@At("/")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/siteCug/mine/index.html")
|
||||
@SaCheckPermission("siteCug.mine")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At("/h5")
|
||||
@Ok("beetl:/platform/zhghh5/dayofficework/siteCug/mine/index.html")
|
||||
@SaCheckPermission(value = {"siteCug.mine", "h5.siteCug.mine"}, mode = SaMode.OR)
|
||||
public void h5Index() {
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("分页查询我的预约")
|
||||
@SaCheckPermission(value = {"siteCug.mine", "h5.siteCug.mine"}, mode = SaMode.OR)
|
||||
public Result pageData(PageForm pageForm,
|
||||
@Param("siteType") String siteType,
|
||||
@Param("siteId") String siteId) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
info.*,
|
||||
si.name as siteName,
|
||||
ins.id AS instanceId,
|
||||
ins.businessNo,
|
||||
ins.state instanceState,
|
||||
ins.variable instanceVariable,
|
||||
ins.processDefineId instanceProcessDefineId,
|
||||
t.id taskId,
|
||||
t.taskName AS taskKey,
|
||||
t.displayName taskName,
|
||||
t.taskType,
|
||||
t.performType taskPerformType,
|
||||
t.taskState,
|
||||
t.finishTime,
|
||||
t.taskParentId,
|
||||
t.variable taskVariable,
|
||||
CASE
|
||||
WHEN ins.state in (10, 20) AND (t.displayName LIKE '%校工会允许%' OR t.taskName = 'c8c03407-cf26-4e0b-82f1-b2afc9c79996')
|
||||
THEN 1
|
||||
ELSE 0
|
||||
END canCancel,
|
||||
IF((SELECT taskName FROM wf_process_task tt WHERE tt.id = t.taskParentId) = 'startTask', 1, 0) canRevoke,
|
||||
(select MAX(id) from wf_process_task where processInstanceId = ins.id and taskName = 'startTask') AS startTaskId,
|
||||
CASE WHEN info.backOption LIKE 'YEARLY_BATCH:%' THEN 1 ELSE 0 END AS yearlyBatch,
|
||||
CASE WHEN info.backOption LIKE 'YEARLY_BATCH:%' THEN (
|
||||
SELECT COUNT(1) FROM site_cug_apply batch_info WHERE batch_info.backOption = info.backOption AND batch_info.createdBy = info.createdBy
|
||||
) ELSE 1 END AS batchDeleteCount
|
||||
FROM
|
||||
site_cug_apply info
|
||||
LEFT JOIN site_cug_info si ON info.siteId = si.id
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||
LEFT JOIN wf_process_task t ON t.processInstanceId = ins.id AND t.taskState = 10
|
||||
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
seg.or(SiteCugApply::getApplyUserName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
seg.or(SiteCugApply::getApplyLoginName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
seg.or("si.name", "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
cnd.and(seg);
|
||||
}
|
||||
cnd.andEX("si.typeId", "=", siteType);
|
||||
cnd.andEX("info.siteId", "=", siteId);
|
||||
cnd.and("info.createdBy", "=", SecurityUtil.getUserId());
|
||||
|
||||
if (StrUtil.isNotBlank(pageForm.getPageOrderName()) && StrUtil.isNotBlank(pageForm.getPageOrderBy())) {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
} else {
|
||||
cnd.desc("info.createdAt");
|
||||
}
|
||||
cnd.groupBy("info.id");
|
||||
sql.setCondition(cnd);
|
||||
Pagination<NutMap> pagination = applyService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("取消我的预约")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission(value = {"siteCug.mine", "h5.siteCug.mine"}, mode = SaMode.OR)
|
||||
@SLog(tag = "场馆功能管理-我的预约", msg = "取消场地预约")
|
||||
public Result delete(@Param("id") String id) {
|
||||
SiteCugApply apply = applyService.fetch(id);
|
||||
if (apply == null) {
|
||||
return Result.error("预约记录不存在");
|
||||
}
|
||||
if (!StrUtil.equals(apply.getCreatedBy(), SecurityUtil.getUserId())) {
|
||||
return Result.error("无权取消该预约");
|
||||
}
|
||||
|
||||
List<String> deleteIds = new ArrayList<>();
|
||||
if (StrUtil.isNotBlank(apply.getBackOption()) && apply.getBackOption().startsWith(YEARLY_BATCH_PREFIX)) {
|
||||
List<SiteCugApply> batchList = applyService.query(Cnd.where("backOption", "=", apply.getBackOption()).and("createdBy", "=", SecurityUtil.getUserId()));
|
||||
deleteIds.addAll(batchList.stream().map(SiteCugApply::getId).toList());
|
||||
} else {
|
||||
deleteIds.add(id);
|
||||
}
|
||||
if (deleteIds.isEmpty()) {
|
||||
return Result.error("未找到可取消的预约记录");
|
||||
}
|
||||
|
||||
for (String deleteId : deleteIds) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
CASE
|
||||
WHEN ins.state in (10, 20) AND (t.displayName LIKE '%校工会允许%' OR t.taskName = 'c8c03407-cf26-4e0b-82f1-b2afc9c79996')
|
||||
THEN 1
|
||||
ELSE 0
|
||||
END canCancel
|
||||
FROM
|
||||
site_cug_apply info
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||
LEFT JOIN wf_process_task t ON t.processInstanceId = ins.id AND t.taskState = 10
|
||||
WHERE info.id = @id
|
||||
""");
|
||||
sql.params().set("id", deleteId);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
applyService.dao().execute(sql);
|
||||
List<NutMap> list = sql.getList(NutMap.class);
|
||||
boolean canCancel = list != null && !list.isEmpty() && list.get(0).getInt("canCancel", 0) == 1;
|
||||
if (!canCancel) {
|
||||
return Result.error("当前批次中存在不可取消的预约,无法整批删除");
|
||||
}
|
||||
}
|
||||
|
||||
for (String deleteId : deleteIds) {
|
||||
applyService.delete(deleteId);
|
||||
flowEngine.processInstanceService().deleteProcessInstanceByBusinessKey(deleteId);
|
||||
}
|
||||
if (deleteIds.size() > 1) {
|
||||
return Result.success("已取消该批次下全部预约记录");
|
||||
}
|
||||
return Result.success("取消成功");
|
||||
}
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.flow.engine.FlowEngine;
|
||||
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugApply;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.param.SiteCugRecordPageForm;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.service.SiteCugApplyService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
|
||||
@IocBean
|
||||
@Ok("json:full")
|
||||
@Api(tags = "场馆预约查询")
|
||||
@At("/platform/siteCug/record")
|
||||
public class SiteCugRecordController {
|
||||
|
||||
@Inject
|
||||
private FlowEngine flowEngine;
|
||||
@Inject
|
||||
private SiteCugApplyService applyService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/siteCug/record/index.html")
|
||||
@SaCheckPermission("siteCug.record")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("分页查询")
|
||||
@SaCheckPermission("siteCug.record")
|
||||
public Result pageData(SiteCugRecordPageForm pageForm) {
|
||||
// 查询页只负责调用 service 公共查询方法,controller 不再维护重复 SQL/Cnd 逻辑
|
||||
Sql sql = applyService.buildRecordSql();
|
||||
Cnd cnd = applyService.buildRecordCnd(pageForm);
|
||||
sql.setCondition(cnd);
|
||||
Pagination<NutMap> pageVO = applyService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
return Result.success(pageVO);
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("删除预约记录")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("siteCug.record")
|
||||
public Result delete(@Param("id") String id) {
|
||||
SiteCugApply apply = applyService.fetch(id);
|
||||
if (apply == null) {
|
||||
return Result.error("记录不存在");
|
||||
}
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
ins.state AS instanceState
|
||||
FROM
|
||||
site_cug_apply info
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||
WHERE info.id = @id
|
||||
""");
|
||||
sql.params().set("id", id);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
applyService.dao().execute(sql);
|
||||
List<NutMap> list = sql.getList(NutMap.class);
|
||||
Integer state = list != null && !list.isEmpty() ? list.get(0).getInt("instanceState") : null;
|
||||
// 预约查询页只展示审核结束数据,这里也只允许删除已完成/已拒绝的流程记录
|
||||
if (state == null || !List.of(ProcessInstanceStateEnum.FINISHED.getCode(), ProcessInstanceStateEnum.REJECT.getCode()).contains(state)) {
|
||||
return Result.error("仅可删除审核结束的预约记录");
|
||||
}
|
||||
|
||||
applyService.delete(id);
|
||||
flowEngine.processInstanceService().deleteProcessInstanceByBusinessKey(id);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@Ok("void")
|
||||
@ApiOperation("导出预约记录")
|
||||
@SaCheckPermission("siteCug.record")
|
||||
public void doExport(SiteCugRecordPageForm pageForm, HttpServletResponse response) {
|
||||
// 导出逻辑统一下沉到 service,导出结果和当前筛选条件保持一致
|
||||
applyService.exportRecord(pageForm, response);
|
||||
}
|
||||
}
|
||||
+215
@@ -0,0 +1,215 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.flow.constant.FlowConst;
|
||||
import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||
import com.budwk.app.flow.service.FlowCommonService;
|
||||
import com.budwk.app.flow.service.ProcessTaskService;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugApply;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.service.SiteCugApplyService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.json.Json;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@IocBean
|
||||
@At("/platform/siteCug/schoolUnionAudit")
|
||||
@Api("场馆校工会审核")
|
||||
@Ok("json:full")
|
||||
public class SiteCugSchoolUnionAuditController {
|
||||
|
||||
private static final String YEARLY_BATCH_PREFIX = "YEARLY_BATCH:";
|
||||
|
||||
@Inject
|
||||
private SiteCugApplyService applyService;
|
||||
@Inject
|
||||
private ProcessTaskService processTaskService;
|
||||
@Inject
|
||||
private FlowCommonService flowCommonService;
|
||||
|
||||
@At("/")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/siteCug/schoolUnionAudit/index.html")
|
||||
@SaCheckPermission("siteCug.schoolUnionAudit")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At("/h5")
|
||||
@Ok("beetl:/platform/zhghh5/dayofficework/siteCug/schoolUnionAudit/index.html")
|
||||
@SaCheckPermission("h5.siteCug.schoolUnionAudit")
|
||||
public void h5Index() {
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("分页查询")
|
||||
@SaCheckPermission(value = {"siteCug.schoolUnionAudit", "h5.siteCug.schoolUnionAudit"}, mode = SaMode.OR)
|
||||
public Result pageData(PageForm pageForm,
|
||||
@Param("siteType") String siteType,
|
||||
@Param("siteId") String siteId,
|
||||
@Param("approval") Boolean approval) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
info.*,
|
||||
si.name as siteName,
|
||||
ins.id AS instanceId,
|
||||
ins.businessNo,
|
||||
ins.state instanceState,
|
||||
ins.variable instanceVariable,
|
||||
ins.processDefineId instanceProcessDefineId,
|
||||
t.id taskId,
|
||||
t.taskName AS taskKey,
|
||||
t.displayName taskName,
|
||||
t.taskType,
|
||||
t.performType taskPerformType,
|
||||
t.taskState,
|
||||
t.finishTime,
|
||||
t.taskParentId,
|
||||
t.variable taskVariable,
|
||||
IFNULL(GROUP_CONCAT(DISTINCT nt.displayName),'结束') curTaskName,
|
||||
CASE WHEN EXISTS (
|
||||
SELECT 1 FROM wf_process_task rt
|
||||
WHERE rt.processInstanceId = ins.id AND rt.taskParentId = t.id
|
||||
) THEN 1 ELSE 0 END AS canRevoke,
|
||||
CASE WHEN info.backOption LIKE 'YEARLY_BATCH:%' THEN 1 ELSE 0 END AS yearlyBatch,
|
||||
CASE WHEN info.backOption LIKE 'YEARLY_BATCH:%' THEN (
|
||||
SELECT COUNT(1) FROM site_cug_apply batch_info WHERE batch_info.backOption = info.backOption AND batch_info.createdBy = info.createdBy
|
||||
) ELSE 1 END AS batchAuditCount
|
||||
FROM
|
||||
wf_process_task t
|
||||
LEFT JOIN wf_process_instance ins ON ins.id = t.processInstanceId
|
||||
LEFT JOIN site_cug_apply info ON info.id = ins.businessNo
|
||||
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id
|
||||
LEFT JOIN site_cug_info si ON info.siteId = si.id
|
||||
LEFT JOIN wf_process_task nt ON nt.processInstanceId = ins.id AND nt.taskState = 10
|
||||
LEFT JOIN wf_process_task rt ON rt.processInstanceId = ins.id AND rt.taskParentId = t.id
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
seg.or(SiteCugApply::getApplyUserName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
seg.or(SiteCugApply::getApplyLoginName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
seg.or("si.name", "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
cnd.and(seg);
|
||||
}
|
||||
cnd.andEX("si.typeId", "=", siteType);
|
||||
cnd.andEX("info.siteId", "=", siteId);
|
||||
cnd.and("t.taskName", "=", "c8c03407-cf26-4e0b-82f1-b2afc9c79996");
|
||||
if (!StpUtil.hasRole(RoleConstant.SYSADMIN.name())) {
|
||||
cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
|
||||
}
|
||||
if (Boolean.TRUE.equals(approval)) {
|
||||
cnd.and("t.taskState", "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.INTERRUPT.getCode()));
|
||||
} else {
|
||||
cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
|
||||
}
|
||||
|
||||
if (StrUtil.isNotBlank(pageForm.getPageOrderName()) && StrUtil.isNotBlank(pageForm.getPageOrderBy())) {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
} else {
|
||||
cnd.desc("info.createdAt");
|
||||
}
|
||||
cnd.groupBy("t.id");
|
||||
sql.setCondition(cnd);
|
||||
Pagination<NutMap> pageVO = applyService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
return Result.success(pageVO);
|
||||
}
|
||||
|
||||
@At("/executeTask")
|
||||
@ApiOperation("执行审核任务")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission(value = {"siteCug.schoolUnionAudit", "h5.siteCug.schoolUnionAudit"}, mode = SaMode.OR)
|
||||
public Result executeTask(@Param("data") String data) {
|
||||
Dict args = Json.fromJson(Dict.class, data);
|
||||
Long processTaskId = args.getLong(FlowConst.PROCESS_TASK_ID_KEY);
|
||||
ProcessTask currentTask = processTaskService.getById(processTaskId);
|
||||
if (currentTask == null) {
|
||||
return Result.error("审核任务不存在");
|
||||
}
|
||||
|
||||
SiteCugApply apply = applyService.fetch(args.getStr("applyId"));
|
||||
if (apply == null) {
|
||||
return Result.error("预约记录不存在");
|
||||
}
|
||||
|
||||
List<ProcessTask> taskList = new ArrayList<>();
|
||||
if (StrUtil.isNotBlank(apply.getBackOption()) && apply.getBackOption().startsWith(YEARLY_BATCH_PREFIX)) {
|
||||
List<SiteCugApply> batchList = applyService.query(Cnd.where("backOption", "=", apply.getBackOption()).and("createdBy", "=", apply.getCreatedBy()));
|
||||
List<String> bizIds = batchList.stream().map(SiteCugApply::getId).toList();
|
||||
taskList = processTaskService.getDoingTaskByBizIdTaskName(bizIds, currentTask.getTaskName());
|
||||
}
|
||||
if (taskList.isEmpty()) {
|
||||
taskList.add(currentTask);
|
||||
}
|
||||
|
||||
for (ProcessTask task : taskList) {
|
||||
Dict cloneArgs = args.clone();
|
||||
cloneArgs.put(FlowConst.PROCESS_TASK_ID_KEY, task.getId());
|
||||
flowCommonService.executeTask(cloneArgs);
|
||||
}
|
||||
if (taskList.size() > 1) {
|
||||
return Result.success("已完成该全年预约批次的审核");
|
||||
}
|
||||
return Result.success("提交成功");
|
||||
}
|
||||
|
||||
|
||||
@At("/revokeTask")
|
||||
@ApiOperation("撤回审核任务")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission(value = {"siteCug.schoolUnionAudit", "h5.siteCug.schoolUnionAudit"}, mode = SaMode.OR)
|
||||
public Result revokeTask(@Param("taskId") Long taskId, @Param("applyId") String applyId) {
|
||||
ProcessTask currentTask = processTaskService.getById(taskId);
|
||||
if (currentTask == null) {
|
||||
return Result.error("撤回任务不存在");
|
||||
}
|
||||
|
||||
SiteCugApply apply = applyService.fetch(applyId);
|
||||
if (apply == null) {
|
||||
return Result.error("预约记录不存在");
|
||||
}
|
||||
|
||||
List<ProcessTask> taskList = new ArrayList<>();
|
||||
if (StrUtil.isNotBlank(apply.getBackOption()) && apply.getBackOption().startsWith(YEARLY_BATCH_PREFIX)) {
|
||||
List<SiteCugApply> batchList = applyService.query(Cnd.where("backOption", "=", apply.getBackOption()).and("createdBy", "=", apply.getCreatedBy()));
|
||||
List<String> bizIds = batchList.stream().map(SiteCugApply::getId).toList();
|
||||
taskList = processTaskService.getDoneTaskByBizIdTaskName(bizIds, currentTask.getTaskName());
|
||||
}
|
||||
if (taskList.isEmpty()) {
|
||||
taskList.add(currentTask);
|
||||
}
|
||||
|
||||
for (ProcessTask task : taskList) {
|
||||
flowCommonService.revokeTask(task.getId());
|
||||
}
|
||||
if (taskList.size() > 1) {
|
||||
return Result.success("已撤回该全年预约批次的审核任务");
|
||||
}
|
||||
return Result.success("撤回成功");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.model;
|
||||
|
||||
import com.budwk.app.base.model.BaseModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.nutz.dao.entity.annotation.*;
|
||||
import org.nutz.dao.interceptor.annotation.PrevInsert;
|
||||
|
||||
@Data
|
||||
@Comment("场地预约-场馆")
|
||||
@Accessors(chain = true)
|
||||
@Table("site_cug_apply")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SiteCugApply extends BaseModel {
|
||||
|
||||
@Name
|
||||
@Comment("ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@PrevInsert(uu32 = true)
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("场地id")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String siteId;
|
||||
|
||||
@Column
|
||||
@Comment("预约人")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String applyUserId;
|
||||
|
||||
@Column
|
||||
@Comment("预约人姓名")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
private String applyUserName;
|
||||
|
||||
@Column
|
||||
@Comment("性别")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 10)
|
||||
private String applySex;
|
||||
|
||||
@Column
|
||||
@Comment("预约人工号")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
private String applyLoginName;
|
||||
|
||||
@Column
|
||||
@Comment("预约人单位id")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String applyUnitId;
|
||||
|
||||
@Column
|
||||
@Comment("预约人单位")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String applyUnitName;
|
||||
|
||||
@Column
|
||||
@Comment("预约类型")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
private String reserveType;
|
||||
|
||||
@Column
|
||||
@Comment("分工会id")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String applyUnionId;
|
||||
|
||||
@Column
|
||||
@Comment("分工会名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String applyUnionName;
|
||||
|
||||
@Column
|
||||
@Comment("协会id")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String clubId;
|
||||
|
||||
@Column
|
||||
@Comment("协会名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String clubName;
|
||||
|
||||
@Column
|
||||
@Comment("预约人联系方式")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
private String applyMobile;
|
||||
|
||||
@Column
|
||||
@Comment("预约开始时间")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
private String reserveStartTime;
|
||||
|
||||
@Column
|
||||
@Comment("预约结束时间")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
private String reserveEndTime;
|
||||
|
||||
@Column
|
||||
@Comment("预约人数")
|
||||
@ColDefine(type = ColType.INT)
|
||||
private Integer joinCount;
|
||||
|
||||
@Column
|
||||
@Comment("预约事由")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 1000)
|
||||
private String applyCause;
|
||||
|
||||
@Column
|
||||
@Comment("反馈意见")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 200)
|
||||
private String backOption;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.model;
|
||||
|
||||
import com.budwk.app.base.model.BaseModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.nutz.dao.entity.annotation.*;
|
||||
import org.nutz.dao.interceptor.annotation.PrevInsert;
|
||||
|
||||
@Data
|
||||
@Comment("功能类型")
|
||||
@Accessors(chain = true)
|
||||
@Table("site_cug_function_type")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SiteCugFunctionType extends BaseModel {
|
||||
|
||||
@Name
|
||||
@Comment("ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@PrevInsert(uu32 = true)
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
@Comment("类型编码")
|
||||
private String code;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
@Comment("类型名称")
|
||||
private String name;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Comment("是否启用")
|
||||
@Default("1")
|
||||
private Boolean enable;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.INT)
|
||||
@Comment("排序编号")
|
||||
private Integer sortNum;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.model;
|
||||
|
||||
import com.budwk.app.base.model.BaseModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.nutz.dao.entity.annotation.*;
|
||||
import org.nutz.dao.interceptor.annotation.PrevInsert;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Comment("场地信息-场馆")
|
||||
@Accessors(chain = true)
|
||||
@Table("site_cug_info")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SiteCugInfo extends BaseModel {
|
||||
|
||||
@Name
|
||||
@Comment("ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@PrevInsert(uu32 = true)
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("创建人ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String createUserId;
|
||||
|
||||
@Column
|
||||
@Comment("创建人")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
private String createUserName;
|
||||
|
||||
@Column
|
||||
@Comment("排序编号")
|
||||
@ColDefine(type = ColType.INT)
|
||||
private Integer sortNum;
|
||||
|
||||
@Column
|
||||
@Comment("场地名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String name;
|
||||
|
||||
@Column
|
||||
@Comment("场地地址")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 255)
|
||||
private String address;
|
||||
|
||||
@Column
|
||||
@Comment("联系人")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String contactName;
|
||||
|
||||
@Column
|
||||
@Comment("联系电话")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
private String contactPhone;
|
||||
|
||||
@Column
|
||||
@Comment("可容纳人数")
|
||||
@ColDefine(type = ColType.INT)
|
||||
private Integer maxNum;
|
||||
|
||||
@Column
|
||||
@Comment("场地类型")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String typeId;
|
||||
|
||||
@Column
|
||||
@Comment("性别限制(0不限,1男,2女)")
|
||||
@ColDefine(type = ColType.INT)
|
||||
private Integer sexLimit;
|
||||
|
||||
@Column
|
||||
@Comment("场地的禁用时间")
|
||||
@ColDefine(type = ColType.MYSQL_JSON)
|
||||
private List<NutMap> notApplyTimeList;
|
||||
|
||||
@Column
|
||||
@Comment("开启状态")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Default("1")
|
||||
private Boolean state;
|
||||
|
||||
@Column
|
||||
@Comment("排除节假日")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Default("0")
|
||||
private Boolean filterHolidays;
|
||||
|
||||
@Column
|
||||
@Comment("场地介绍")
|
||||
@ColDefine(type = ColType.TEXT)
|
||||
private String introduce;
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.param;
|
||||
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@ApiModel("场馆预约查询参数")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class SiteCugRecordPageForm extends PageForm {
|
||||
|
||||
@ApiModelProperty("场地类型ID")
|
||||
private String siteType;
|
||||
|
||||
@ApiModelProperty("场地ID")
|
||||
private String siteId;
|
||||
|
||||
@ApiModelProperty("预约类型")
|
||||
private String reserveType;
|
||||
|
||||
@ApiModelProperty("预约单位关键字")
|
||||
private String reserveTargetKeyword;
|
||||
|
||||
@ApiModelProperty("预约时间开始")
|
||||
private String reserveTimeStart;
|
||||
|
||||
@ApiModelProperty("预约时间结束")
|
||||
private String reserveTimeEnd;
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugApply;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.param.SiteCugRecordPageForm;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.Map;
|
||||
|
||||
public interface SiteCugApplyService extends BaseService<SiteCugApply> {
|
||||
|
||||
Map<Boolean, String> validateApply(SiteCugApply apply);
|
||||
|
||||
// 场馆预约查询页和导出共用同一套查询字段定义,统一由 service 生成 SQL
|
||||
Sql buildRecordSql();
|
||||
|
||||
// 场馆预约查询页和导出的筛选条件统一由 service 组装,避免 controller 重复维护
|
||||
Cnd buildRecordCnd(SiteCugRecordPageForm pageForm);
|
||||
|
||||
// 场馆预约查询页的导出逻辑统一放在 service,controller 只负责接收请求
|
||||
void exportRecord(SiteCugRecordPageForm pageForm, HttpServletResponse response);
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugFunctionType;
|
||||
|
||||
public interface SiteCugFunctionTypeService extends BaseService<SiteCugFunctionType> {
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugInfo;
|
||||
|
||||
public interface SiteCugInfoService extends BaseService<SiteCugInfo> {
|
||||
}
|
||||
+321
@@ -0,0 +1,321 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.service.impl;
|
||||
|
||||
import cn.afterturn.easypoi.excel.ExcelExportUtil;
|
||||
import cn.afterturn.easypoi.excel.entity.ExportParams;
|
||||
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
|
||||
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.flow.entity.ProcessInstance;
|
||||
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
|
||||
import com.budwk.app.sys.models.SysHoliday;
|
||||
import com.budwk.app.sys.models.Sys_union;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.club.model.SysClub;
|
||||
import com.budwk.app.zhgh.club.service.SysClubService;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugApply;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugInfo;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.param.SiteCugRecordPageForm;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.service.SiteCugApplyService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class SiteCugApplyServiceImpl extends BaseServiceImpl<SiteCugApply> implements SiteCugApplyService {
|
||||
|
||||
@Inject
|
||||
private SysClubService sysClubService;
|
||||
|
||||
public SiteCugApplyServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Boolean, String> validateApply(SiteCugApply apply) {
|
||||
// 预约类型校验和自动回填:
|
||||
// 1. 分工会预约时,强制读取当前登录人的分工会信息
|
||||
// 2. 协会预约时,只允许选择当前登录人实际管理的协会
|
||||
Map<Boolean, String> reserveTypeValidate = fillReserveTypeData(apply);
|
||||
if (reserveTypeValidate.containsKey(false)) {
|
||||
return reserveTypeValidate;
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(apply.getReserveStartTime()) || StrUtil.isBlank(apply.getReserveEndTime())) {
|
||||
return Map.of(false, "预约时间不能为空");
|
||||
}
|
||||
if (!DateUtil.parseDateTime(apply.getReserveEndTime()).isAfter(DateUtil.parseDateTime(apply.getReserveStartTime()))) {
|
||||
return Map.of(false, "结束时间必须晚于开始时间");
|
||||
}
|
||||
if (!DateUtil.parseDateTime(apply.getReserveStartTime()).isAfter(DateUtil.date())) {
|
||||
return Map.of(false, "预约开始时间必须晚于当前时间");
|
||||
}
|
||||
|
||||
SiteCugInfo siteInfo = dao().fetch(SiteCugInfo.class, apply.getSiteId());
|
||||
if (siteInfo == null) {
|
||||
return Map.of(false, "场地不存在");
|
||||
}
|
||||
if (!Boolean.TRUE.equals(siteInfo.getState())) {
|
||||
return Map.of(false, "该场地未开启预约");
|
||||
}
|
||||
if (apply.getJoinCount() == null || apply.getJoinCount() <= 0) {
|
||||
return Map.of(false, "预约人数必须大于0");
|
||||
}
|
||||
if (apply.getJoinCount() > siteInfo.getMaxNum()) {
|
||||
return Map.of(false, "预约人数最多为%s人".formatted(siteInfo.getMaxNum()));
|
||||
}
|
||||
// 周六、周日整天不可预约,避免只做前端限制被绕过
|
||||
if (containsWeekend(apply.getReserveStartTime(), apply.getReserveEndTime())) {
|
||||
return Map.of(false, "预约时间不能落在周六或周日");
|
||||
}
|
||||
// 开启排除节假日后,节假日整天不可预约
|
||||
if (Boolean.TRUE.equals(siteInfo.getFilterHolidays()) && containsHoliday(apply.getReserveStartTime(), apply.getReserveEndTime())) {
|
||||
return Map.of(false, "预约时间不能落在节假日");
|
||||
}
|
||||
// 只要预约时间范围和禁用时间段有交叉,就不允许预约
|
||||
if (intersectsDisabledTime(siteInfo, apply.getReserveStartTime(), apply.getReserveEndTime())) {
|
||||
return Map.of(false, "预约时间落在禁用时间内");
|
||||
}
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
select
|
||||
sa.*
|
||||
from
|
||||
site_cug_apply sa
|
||||
left join wf_process_instance ins on ins.businessNo = sa.id
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and(SiteCugApply::getSiteId, "=", apply.getSiteId());
|
||||
cnd.andEX("sa.id", "!=", apply.getId());
|
||||
List<Integer> stateList = List.of(ProcessInstanceStateEnum.DOING.getCode(), ProcessInstanceStateEnum.FINISHED.getCode(), ProcessInstanceStateEnum.PENDING.getCode());
|
||||
cnd.and(ProcessInstance::getState, "in", stateList);
|
||||
sql.setCondition(cnd);
|
||||
List<SiteCugApply> applyList = listEntity(sql);
|
||||
|
||||
// 只要已有预约和当前申请时间段有交叉,并且流程状态是待审核/办理中/已通过,就直接判定冲突
|
||||
for (SiteCugApply item : applyList) {
|
||||
boolean overlap = DateUtil.parseDateTime(item.getReserveStartTime()).isBefore(DateUtil.parseDateTime(apply.getReserveEndTime()))
|
||||
&& DateUtil.parseDateTime(item.getReserveEndTime()).isAfter(DateUtil.parseDateTime(apply.getReserveStartTime()));
|
||||
if (overlap) {
|
||||
if (StrUtil.isBlank(apply.getId()) && StrUtil.equals(item.getApplyUserId(), SecurityUtil.getUserId())) {
|
||||
return Map.of(false, "该时间段您已存在预约");
|
||||
}
|
||||
return Map.of(false, String.format("预约时间冲突,%s 至 %s 已被预约,请重新选择", item.getReserveStartTime(), item.getReserveEndTime()));
|
||||
}
|
||||
}
|
||||
return Map.of(true, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sql buildRecordSql() {
|
||||
// 场馆预约查询页和导出页共用同一套返回字段,统一在 service 中维护,避免 controller 重复拼 SQL
|
||||
return Sqls.create("""
|
||||
SELECT
|
||||
info.*,
|
||||
si.name AS siteName,
|
||||
ins.id AS instanceId,
|
||||
ins.processDefineId instanceProcessDefineId,
|
||||
CASE WHEN info.reserveType = 'club' THEN '协会预约' ELSE '分工会预约' END AS reserveTypeName,
|
||||
CASE WHEN info.reserveType = 'club' THEN info.clubName ELSE info.applyUnionName END AS reserveTargetName,
|
||||
DATE_FORMAT(info.createdAt, '%Y-%m-%d %H:%i:%s') AS applyTime
|
||||
FROM
|
||||
site_cug_apply info
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||
LEFT JOIN site_cug_info si ON info.siteId = si.id
|
||||
$condition
|
||||
""");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cnd buildRecordCnd(SiteCugRecordPageForm pageForm) {
|
||||
// 场馆预约查询页和导出共用同一套筛选条件,保证列表看见什么,导出就拿到什么
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
seg.or(SiteCugApply::getApplyUserName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
seg.or(SiteCugApply::getApplyLoginName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
seg.or("si.name", "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
cnd.and(seg);
|
||||
}
|
||||
if (StrUtil.isNotBlank(pageForm.getReserveTargetKeyword())) {
|
||||
// 预约单位支持同时匹配分工会名称和协会名称,方便直接查某个预约主体的全部记录
|
||||
SqlExpressionGroup reserveTargetSeg = new SqlExpressionGroup();
|
||||
reserveTargetSeg.or("info.applyUnionName", "like", "%" + pageForm.getReserveTargetKeyword() + "%");
|
||||
reserveTargetSeg.or("info.clubName", "like", "%" + pageForm.getReserveTargetKeyword() + "%");
|
||||
cnd.and(reserveTargetSeg);
|
||||
}
|
||||
if (StrUtil.isNotBlank(pageForm.getReserveType())) {
|
||||
cnd.andEX("info.reserveType", "=", pageForm.getReserveType());
|
||||
}
|
||||
if (StrUtil.isNotBlank(pageForm.getReserveTimeStart())) {
|
||||
// 按预约时间查询时,开始边界取“预约结束时间大于等于筛选开始”,这样跨段预约也能查出来
|
||||
cnd.andEX("info.reserveEndTime", ">=", pageForm.getReserveTimeStart());
|
||||
}
|
||||
if (StrUtil.isNotBlank(pageForm.getReserveTimeEnd())) {
|
||||
// 按预约时间查询时,结束边界取“预约开始时间小于等于筛选结束”,保证时间段有交叉就能命中
|
||||
cnd.andEX("info.reserveStartTime", "<=", pageForm.getReserveTimeEnd());
|
||||
}
|
||||
cnd.andEX("si.typeId", "=", pageForm.getSiteType());
|
||||
cnd.andEX("info.siteId", "=", pageForm.getSiteId());
|
||||
// 预约查询页固定只看审核结束记录;导出复用同一条件,实现所见即所得
|
||||
cnd.and("ins.state", "in", List.of(ProcessInstanceStateEnum.FINISHED.getCode(), ProcessInstanceStateEnum.REJECT.getCode()));
|
||||
if (StrUtil.isNotBlank(pageForm.getPageOrderName()) && StrUtil.isNotBlank(pageForm.getPageOrderBy())) {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
} else {
|
||||
cnd.desc("info.createdAt");
|
||||
}
|
||||
cnd.groupBy("info.id");
|
||||
return cnd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exportRecord(SiteCugRecordPageForm pageForm, HttpServletResponse response) {
|
||||
// 导出直接复用列表同一套查询条件和字段定义,保证导出结果与当前列表查询结果一致
|
||||
Sql sql = buildRecordSql();
|
||||
Cnd cnd = buildRecordCnd(pageForm);
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
dao().execute(sql);
|
||||
List<NutMap> list = sql.getList(NutMap.class);
|
||||
ExportParams exportParams = new ExportParams("预约查询", "预约查询");
|
||||
exportParams.setType(ExcelType.XSSF);
|
||||
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, buildRecordExportEntities(), list);
|
||||
CommonDownloadUtil.download("场馆预约查询.xlsx", workbook, response);
|
||||
}
|
||||
|
||||
// 场馆预约查询导出字段统一在 service 中定义,并与当前列表展示字段保持一致
|
||||
private List<ExcelExportEntity> buildRecordExportEntities() {
|
||||
List<ExcelExportEntity> exportEntities = new ArrayList<>();
|
||||
exportEntities.add(new ExcelExportEntity("场地名称", "siteName", 20));
|
||||
exportEntities.add(new ExcelExportEntity("预约人", "applyUserName", 20));
|
||||
exportEntities.add(new ExcelExportEntity("预约类型", "reserveTypeName", 20));
|
||||
exportEntities.add(new ExcelExportEntity("预约单位", "reserveTargetName", 20));
|
||||
exportEntities.add(new ExcelExportEntity("所属单位", "applyUnitName", 20));
|
||||
exportEntities.add(new ExcelExportEntity("预约开始时间", "reserveStartTime", 24));
|
||||
exportEntities.add(new ExcelExportEntity("预约结束时间", "reserveEndTime", 24));
|
||||
exportEntities.add(new ExcelExportEntity("联系方式", "applyMobile", 20));
|
||||
return exportEntities;
|
||||
}
|
||||
|
||||
// 预约时间范围内只要包含周六或周日,就视为不可预约
|
||||
private boolean containsWeekend(String reserveStartTime, String reserveEndTime) {
|
||||
Date start = DateUtil.beginOfDay(DateUtil.parseDateTime(reserveStartTime));
|
||||
Date end = DateUtil.beginOfDay(DateUtil.parseDateTime(reserveEndTime));
|
||||
Date current = start;
|
||||
while (current.compareTo(end) <= 0) {
|
||||
DateTime currentDay = DateUtil.date(current);
|
||||
int week = currentDay.dayOfWeek() - 1;
|
||||
if (week == 0 || week == 6) {
|
||||
return true;
|
||||
}
|
||||
current = DateUtil.offsetDay(current, 1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 预约时间范围内只要包含节假日,就视为不可预约
|
||||
private boolean containsHoliday(String reserveStartTime, String reserveEndTime) {
|
||||
Date start = DateUtil.beginOfDay(DateUtil.parseDateTime(reserveStartTime));
|
||||
Date end = DateUtil.beginOfDay(DateUtil.parseDateTime(reserveEndTime));
|
||||
List<String> dayList = new ArrayList<>();
|
||||
Date current = start;
|
||||
while (current.compareTo(end) <= 0) {
|
||||
dayList.add(DateUtil.formatDate(current));
|
||||
current = DateUtil.offsetDay(current, 1);
|
||||
}
|
||||
if (dayList.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
List<SysHoliday> holidays = dao().query(SysHoliday.class, Cnd.NEW());
|
||||
Set<String> holidaySet = holidays.stream().map(SysHoliday::getDay).filter(StrUtil::isNotBlank).collect(Collectors.toSet());
|
||||
return dayList.stream().anyMatch(holidaySet::contains);
|
||||
}
|
||||
|
||||
// 预约时间范围只要与后台配置的禁用时间段有交叉,就直接拦截
|
||||
private boolean intersectsDisabledTime(SiteCugInfo siteInfo, String reserveStartTime, String reserveEndTime) {
|
||||
List<NutMap> timeRanges = siteInfo.getNotApplyTimeList();
|
||||
if (timeRanges == null || timeRanges.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
DateTime reserveStart = DateUtil.parseDateTime(reserveStartTime);
|
||||
DateTime reserveEnd = DateUtil.parseDateTime(reserveEndTime);
|
||||
for (NutMap range : timeRanges) {
|
||||
if (range == null || StrUtil.hasBlank(range.getString("date"), range.getString("startTime"), range.getString("endTime"))) {
|
||||
continue;
|
||||
}
|
||||
DateTime disabledStart = DateUtil.parseDateTime(range.getString("date") + " " + range.getString("startTime") + ":00");
|
||||
DateTime disabledEnd = DateUtil.parseDateTime(range.getString("date") + " " + range.getString("endTime") + ":00");
|
||||
boolean overlap = reserveStart.isBefore(disabledEnd) && reserveEnd.isAfter(disabledStart);
|
||||
if (overlap) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 按预约类型补齐最终落库数据,避免前端传错或被绕过
|
||||
private Map<Boolean, String> fillReserveTypeData(SiteCugApply apply) {
|
||||
if (StrUtil.isBlank(apply.getReserveType())) {
|
||||
return Map.of(false, "请选择预约类型");
|
||||
}
|
||||
if (StrUtil.equals(apply.getReserveType(), "union")) {
|
||||
String unionId = SecurityUtil.getUnionId();
|
||||
if (StrUtil.isBlank(unionId)) {
|
||||
return Map.of(false, "当前用户未关联分工会,不能发起分工会预约");
|
||||
}
|
||||
Sys_union union = dao().fetch(Sys_union.class, unionId);
|
||||
if (union == null) {
|
||||
return Map.of(false, "当前用户分工会信息不存在,请联系管理员核查");
|
||||
}
|
||||
apply.setApplyUnionId(union.getId());
|
||||
apply.setApplyUnionName(union.getName());
|
||||
apply.setClubId("");
|
||||
apply.setClubName("");
|
||||
return Map.of(true, "");
|
||||
}
|
||||
if (StrUtil.equals(apply.getReserveType(), "club")) {
|
||||
if (StrUtil.isBlank(apply.getClubId())) {
|
||||
return Map.of(false, "请选择协会");
|
||||
}
|
||||
// 协会预约直接复用项目现成能力;getMyManageClub() 对 SYSADMIN 已放开,因此超级管理员也能代任意协会预约
|
||||
List<SysClub> myManageClub = sysClubService.getMyManageClub();
|
||||
SysClub club = myManageClub.stream()
|
||||
.filter(item -> StrUtil.equals(item.getId(), apply.getClubId()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (club == null) {
|
||||
return Map.of(false, "所选协会不是您当前管理的协会");
|
||||
}
|
||||
apply.setClubName(club.getClubName());
|
||||
apply.setApplyUnionId("");
|
||||
apply.setApplyUnionName("");
|
||||
return Map.of(true, "");
|
||||
}
|
||||
return Map.of(false, "预约类型不合法");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.service.impl;
|
||||
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugFunctionType;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.service.SiteCugFunctionTypeService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
@Slf4j
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class SiteCugFunctionTypeServiceImpl extends BaseServiceImpl<SiteCugFunctionType> implements SiteCugFunctionTypeService {
|
||||
|
||||
public SiteCugFunctionTypeServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.budwk.app.zhgh.dayofficework.siteCug.service.impl;
|
||||
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugInfo;
|
||||
import com.budwk.app.zhgh.dayofficework.siteCug.service.SiteCugInfoService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
@Slf4j
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class SiteCugInfoServiceImpl extends BaseServiceImpl<SiteCugInfo> implements SiteCugInfoService {
|
||||
|
||||
public SiteCugInfoServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,531 @@
|
||||
const apply = {
|
||||
template: /*language=HTML*/ `
|
||||
<div>
|
||||
<el-row :gutter="20" class="mb10">
|
||||
<el-col :span="24" style="text-align: center">
|
||||
<div style="font-size: large;color: #303133">
|
||||
您正在预约【<span style="color: #409EFF">{{ row.name }}</span>】活动场地
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-form :model="formData" ref="formRef" :rules="formRules" label-position="left" label-width="110px">
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="预约人" prop="applyUserName">
|
||||
<el-input readonly v-model="formData.applyUserName"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="工号" prop="applyLoginName">
|
||||
<el-input readonly v-model="formData.applyLoginName"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="所属单位" prop="applyUnitName">
|
||||
<el-input readonly v-model="formData.applyUnitName"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="预约类型" prop="reserveType">
|
||||
<el-radio-group v-model="formData.reserveType" @change="reserveTypeChange">
|
||||
<el-radio-button label="union">分工会预约</el-radio-button>
|
||||
<el-radio-button label="club">协会预约</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="分工会" prop="applyUnionName" v-if="formData.reserveType === 'union'">
|
||||
<el-input readonly v-model="formData.applyUnionName"
|
||||
placeholder="自动读取当前登录人的分工会"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item
|
||||
label="协会"
|
||||
prop="clubId"
|
||||
v-if="formData.reserveType === 'club'"
|
||||
:rules="[{ required: true, message: '请选择您管理的协会', trigger: ['change', 'blur'] }]">
|
||||
<el-select v-model="formData.clubId" placeholder="请选择您管理的协会" filterable clearable
|
||||
style="width: 100%" @change="clubChange">
|
||||
<el-option
|
||||
v-for="item in clubOptions"
|
||||
:key="item.id"
|
||||
:label="item.clubName"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="联系电话" prop="applyMobile">
|
||||
<el-input maxlength="11" placeholder="请输入联系电话" v-model="formData.applyMobile"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="预约开始时间" prop="reserveStartTime">
|
||||
<el-date-picker
|
||||
:key="'start-' + pickerRefreshKey"
|
||||
v-model="formData.reserveStartTime"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="请选择预约开始时间"
|
||||
:picker-options="startPickerOptions"
|
||||
style="width: 100%"
|
||||
@change="timeFieldChange('reserveStartTime')">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="预约结束时间" prop="reserveEndTime">
|
||||
<el-date-picker
|
||||
:key="'end-' + pickerRefreshKey"
|
||||
v-model="formData.reserveEndTime"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="请选择预约结束时间"
|
||||
:picker-options="endPickerOptions"
|
||||
style="width: 100%"
|
||||
@change="timeFieldChange('reserveEndTime')">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="批量预约">
|
||||
<div style="display:flex;align-items:flex-start;column-gap:12px;flex-wrap:wrap;line-height:1.7;">
|
||||
<el-checkbox v-model="yearlyReserve">预约本年后续每周同一时段</el-checkbox>
|
||||
<span style="color:#909399;">
|
||||
例如先选某个周一 09:00-11:00,勾选后会自动预约本年剩余所有周一的这个时段。
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="yearlyReserve && yearlyReserveSummary" style="margin-top:8px;color:#E6A23C;">
|
||||
{{ yearlyReserveSummary }}
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="预约事由" prop="applyCause">
|
||||
<el-input maxlength="1000" placeholder="请输入预约事由" v-model="formData.applyCause"
|
||||
type="textarea" :autosize="{ minRows: 4, maxRows: 6}"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
<el-row class="mt10" justify="end" type="flex">
|
||||
<el-button @click="$emit('refresh')">取消</el-button>
|
||||
<el-button type="primary" @click="onSubmit">提交预约</el-button>
|
||||
</el-row>
|
||||
</div>
|
||||
`,
|
||||
store,
|
||||
data() {
|
||||
return {
|
||||
row: {},
|
||||
clubOptions: [],
|
||||
yearlyReserve: false,
|
||||
timeLimitConfig: {
|
||||
filterHolidays: false,
|
||||
holidayList: [],
|
||||
notApplyTimeList: [],
|
||||
},
|
||||
pickerRefreshKey: 0,
|
||||
formData: {
|
||||
reserveType: 'union',
|
||||
applyUnionId: '',
|
||||
applyUnionName: '',
|
||||
clubId: '',
|
||||
clubName: '',
|
||||
reserveStartTime: '',
|
||||
reserveEndTime: '',
|
||||
joinCount: 1,
|
||||
applyCause: '',
|
||||
},
|
||||
formRules: {
|
||||
applyUserName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
applySex: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
applyLoginName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
applyUnitName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
reserveType: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
applyMobile: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
reserveStartTime: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
reserveEndTime: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
joinCount: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
applyCause: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
clubId: [{ validator: (rule, value, callback) => {
|
||||
if (this.formData.reserveType === 'club' && !value) {
|
||||
callback(new Error('请选择您管理的协会'))
|
||||
return
|
||||
}
|
||||
callback()
|
||||
}, trigger: ['blur', 'change']}],
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
startPickerOptions() {
|
||||
return {
|
||||
disabledDate: (time) => this.isDisabledDate(time),
|
||||
selectableRange: this.buildSelectableRange(this.formData.reserveStartTime),
|
||||
}
|
||||
},
|
||||
endPickerOptions() {
|
||||
return {
|
||||
disabledDate: (time) => this.isDisabledDate(time),
|
||||
selectableRange: this.buildSelectableRange(this.formData.reserveEndTime),
|
||||
}
|
||||
},
|
||||
yearlyReserveDates() {
|
||||
if (!this.yearlyReserve || !this.formData.reserveStartTime || !this.formData.reserveEndTime) {
|
||||
return []
|
||||
}
|
||||
const start = this.$moment(this.formData.reserveStartTime)
|
||||
const end = this.$moment(this.formData.reserveEndTime)
|
||||
if (!start.isValid() || !end.isValid() || !end.isAfter(start)) {
|
||||
return []
|
||||
}
|
||||
const result = []
|
||||
const current = start.clone().startOf('day')
|
||||
const endOfYear = start.clone().endOf('year').startOf('day')
|
||||
const targetWeekDay = start.day()
|
||||
const startClock = start.format('HH:mm:ss')
|
||||
const endClock = end.format('HH:mm:ss')
|
||||
while (current.isSameOrBefore(endOfYear, 'day')) {
|
||||
if (current.day() === targetWeekDay) {
|
||||
const day = current.format('YYYY-MM-DD')
|
||||
const startTime = day + ' ' + startClock
|
||||
const endTime = day + ' ' + endClock
|
||||
if (this.validateTimeLimit(false, startTime, endTime)) {
|
||||
result.push(day)
|
||||
}
|
||||
}
|
||||
current.add(1, 'day')
|
||||
}
|
||||
return result
|
||||
},
|
||||
yearlyReserveSummary() {
|
||||
if (!this.yearlyReserve) {
|
||||
return ''
|
||||
}
|
||||
if (!this.formData.reserveStartTime || !this.formData.reserveEndTime) {
|
||||
return '请先选择开始和结束时间后,再批量预约本年同星期时段'
|
||||
}
|
||||
if (!this.yearlyReserveDates.length) {
|
||||
return '当前时间段无法生成本年批量预约日期'
|
||||
}
|
||||
return '将从 ' + this.yearlyReserveDates[0] + ' 开始,自动预约到 ' + this.yearlyReserveDates[this.yearlyReserveDates.length - 1] + ',共 ' + this.yearlyReserveDates.length + ' 个时段'
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async onOpen(row) {
|
||||
this.row = row
|
||||
this.clubOptions = []
|
||||
this.yearlyReserve = false
|
||||
this.formData = {
|
||||
siteId: row.id,
|
||||
applyUserId: this.$store.state.user.id,
|
||||
applyUserName: this.$store.state.user.username,
|
||||
applySex: this.$store.state.user.sex,
|
||||
applyLoginName: this.$store.state.user.loginname,
|
||||
applyUnitId: this.$store.state.user?.unit?.id,
|
||||
applyUnitName: this.$store.state.user?.unit?.name,
|
||||
reserveType: 'union',
|
||||
applyUnionId: this.$store.state.user?.union?.id,
|
||||
applyUnionName: this.$store.state.user?.union?.name,
|
||||
clubId: '',
|
||||
clubName: '',
|
||||
applyMobile: this.$store.state.user.mobile,
|
||||
reserveStartTime: '',
|
||||
reserveEndTime: '',
|
||||
joinCount: 1,
|
||||
applyCause: '',
|
||||
}
|
||||
await this.queryTimeLimitConfig()
|
||||
},
|
||||
async queryTimeLimitConfig() {
|
||||
const fallback = {
|
||||
filterHolidays: !!this.row.filterHolidays,
|
||||
holidayList: [],
|
||||
notApplyTimeList: Array.isArray(this.row.notApplyTimeList) ? this.row.notApplyTimeList : [],
|
||||
}
|
||||
try {
|
||||
const res = await this.$axios.post('/platform/siteCug/apply/timeLimitConfig', {
|
||||
siteId: this.row.id,
|
||||
})
|
||||
if (res.code === 0 && res.data) {
|
||||
this.timeLimitConfig = {
|
||||
filterHolidays: !!res.data.filterHolidays,
|
||||
holidayList: Array.isArray(res.data.holidayList) ? res.data.holidayList : [],
|
||||
notApplyTimeList: Array.isArray(res.data.notApplyTimeList) ? res.data.notApplyTimeList : [],
|
||||
}
|
||||
} else {
|
||||
this.timeLimitConfig = fallback
|
||||
}
|
||||
} catch (e) {
|
||||
this.timeLimitConfig = fallback
|
||||
}
|
||||
this.pickerRefreshKey += 1
|
||||
},
|
||||
async reserveTypeChange(value) {
|
||||
if (value === 'union') {
|
||||
this.formData.applyUnionId = this.$store.state.user?.union?.id || ''
|
||||
this.formData.applyUnionName = this.$store.state.user?.union?.name || ''
|
||||
this.formData.clubId = ''
|
||||
this.formData.clubName = ''
|
||||
}
|
||||
if (value === 'club') {
|
||||
this.formData.applyUnionId = ''
|
||||
this.formData.applyUnionName = ''
|
||||
this.formData.clubId = ''
|
||||
this.formData.clubName = ''
|
||||
await this.loadManagedClubs()
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.$refs.formRef?.clearValidate(['applyUnionName', 'clubId'])
|
||||
})
|
||||
},
|
||||
async loadManagedClubs() {
|
||||
try {
|
||||
const res = await this.$axios.post('/platform/club/examine/apply/getClubsByRole')
|
||||
this.clubOptions = Array.isArray(res.data) ? res.data : []
|
||||
if (!this.clubOptions.length) {
|
||||
this.$message.warning('您当前没有可预约的协会管理权限')
|
||||
}
|
||||
} catch (e) {
|
||||
this.clubOptions = []
|
||||
this.$message.warning('协会列表加载失败,请稍后重试')
|
||||
}
|
||||
},
|
||||
clubChange(clubId) {
|
||||
const club = this.clubOptions.find(item => item.id === clubId)
|
||||
this.formData.clubName = club ? club.clubName : ''
|
||||
},
|
||||
async normalizeReserveTypeData() {
|
||||
if (this.formData.reserveType === 'union') {
|
||||
this.formData.applyUnionId = this.$store.state.user?.union?.id || ''
|
||||
this.formData.applyUnionName = this.$store.state.user?.union?.name || ''
|
||||
this.formData.clubId = ''
|
||||
this.formData.clubName = ''
|
||||
return true
|
||||
}
|
||||
if (this.formData.reserveType === 'club') {
|
||||
if (!this.clubOptions.length) {
|
||||
await this.loadManagedClubs()
|
||||
}
|
||||
const club = this.clubOptions.find(item => item.id === this.formData.clubId)
|
||||
this.formData.clubName = club ? club.clubName : ''
|
||||
this.formData.applyUnionId = ''
|
||||
this.formData.applyUnionName = ''
|
||||
return true
|
||||
}
|
||||
return false
|
||||
},
|
||||
isDisabledDate(time) {
|
||||
const day = this.$moment(time).format('YYYY-MM-DD')
|
||||
const today = this.$moment().startOf('day')
|
||||
const currentDay = this.$moment(day)
|
||||
if (currentDay.isBefore(today)) {
|
||||
return true
|
||||
}
|
||||
if (currentDay.day() === 0 || currentDay.day() === 6) {
|
||||
return true
|
||||
}
|
||||
return this.timeLimitConfig.filterHolidays && this.timeLimitConfig.holidayList.includes(day)
|
||||
},
|
||||
normalizeTime(timeStr) {
|
||||
if (!timeStr) {
|
||||
return '00:00:00'
|
||||
}
|
||||
return timeStr.length === 5 ? timeStr + ':00' : timeStr
|
||||
},
|
||||
getDisabledRangesByDay(dayStr) {
|
||||
const list = Array.isArray(this.timeLimitConfig.notApplyTimeList) ? this.timeLimitConfig.notApplyTimeList : []
|
||||
return list
|
||||
.filter(item => item && item.date && this.$moment(item.date).format('YYYY-MM-DD') === dayStr)
|
||||
.sort((a, b) => this.normalizeTime(a.startTime).localeCompare(this.normalizeTime(b.startTime)))
|
||||
},
|
||||
buildSelectableRange(dateTimeValue) {
|
||||
if (!dateTimeValue) {
|
||||
return ['00:00:00 - 23:59:59']
|
||||
}
|
||||
const dayStr = this.$moment(dateTimeValue).format('YYYY-MM-DD')
|
||||
const disabledRanges = this.getDisabledRangesByDay(dayStr)
|
||||
if (!disabledRanges.length) {
|
||||
return ['00:00:00 - 23:59:59']
|
||||
}
|
||||
const result = []
|
||||
let cursor = '00:00:00'
|
||||
disabledRanges.forEach(item => {
|
||||
const start = this.normalizeTime(item.startTime)
|
||||
const end = this.normalizeTime(item.endTime)
|
||||
if (cursor < start) {
|
||||
result.push(cursor + ' - ' + start)
|
||||
}
|
||||
if (cursor < end) {
|
||||
cursor = end
|
||||
}
|
||||
})
|
||||
if (cursor < '23:59:59') {
|
||||
result.push(cursor + ' - 23:59:59')
|
||||
}
|
||||
return result.length ? result : ['00:00:00 - 00:00:00']
|
||||
},
|
||||
isDateTimeBlocked(dateTimeStr) {
|
||||
if (!dateTimeStr) {
|
||||
return false
|
||||
}
|
||||
const target = this.$moment(dateTimeStr)
|
||||
const dayStr = target.format('YYYY-MM-DD')
|
||||
if (this.timeLimitConfig.filterHolidays && this.timeLimitConfig.holidayList.includes(dayStr)) {
|
||||
return true
|
||||
}
|
||||
const disabledRanges = this.getDisabledRangesByDay(dayStr)
|
||||
return disabledRanges.some(item => {
|
||||
const start = this.$moment(dayStr + ' ' + this.normalizeTime(item.startTime))
|
||||
const end = this.$moment(dayStr + ' ' + this.normalizeTime(item.endTime))
|
||||
return target.isSameOrAfter(start) && target.isBefore(end)
|
||||
})
|
||||
},
|
||||
hasHolidayInRange(start, end) {
|
||||
const current = start.clone().startOf('day')
|
||||
const endDay = end.clone().startOf('day')
|
||||
while (current.isSameOrBefore(endDay)) {
|
||||
if (current.day() === 0 || current.day() === 6) {
|
||||
return true
|
||||
}
|
||||
if (this.timeLimitConfig.filterHolidays && this.timeLimitConfig.holidayList.includes(current.format('YYYY-MM-DD'))) {
|
||||
return true
|
||||
}
|
||||
current.add(1, 'day')
|
||||
}
|
||||
return false
|
||||
},
|
||||
overlapsDisabledRange(start, end) {
|
||||
const list = Array.isArray(this.timeLimitConfig.notApplyTimeList) ? this.timeLimitConfig.notApplyTimeList : []
|
||||
return list.some(item => {
|
||||
if (!item || !item.date || !item.startTime || !item.endTime) {
|
||||
return false
|
||||
}
|
||||
const rangeStart = this.$moment(this.$moment(item.date).format('YYYY-MM-DD') + ' ' + this.normalizeTime(item.startTime))
|
||||
const rangeEnd = this.$moment(this.$moment(item.date).format('YYYY-MM-DD') + ' ' + this.normalizeTime(item.endTime))
|
||||
return start.isBefore(rangeEnd) && end.isAfter(rangeStart)
|
||||
})
|
||||
},
|
||||
validateTimeLimit(showMessage = true, startTime = this.formData.reserveStartTime, endTime = this.formData.reserveEndTime) {
|
||||
if (!startTime || !endTime) {
|
||||
return true
|
||||
}
|
||||
const start = this.$moment(startTime)
|
||||
const end = this.$moment(endTime)
|
||||
if (this.isDateTimeBlocked(startTime) || this.isDateTimeBlocked(endTime)) {
|
||||
if (showMessage) {
|
||||
this.$message.warning('预约时间不能选择周末、节假日或禁用时间')
|
||||
}
|
||||
return false
|
||||
}
|
||||
if (this.hasHolidayInRange(start, end)) {
|
||||
if (showMessage) {
|
||||
this.$message.warning('预约时间范围内包含周末或节假日,请重新选择')
|
||||
}
|
||||
return false
|
||||
}
|
||||
if (this.overlapsDisabledRange(start, end)) {
|
||||
if (showMessage) {
|
||||
this.$message.warning('预约时间范围与禁用时间冲突,请重新选择')
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
timeFieldChange(field) {
|
||||
const value = this.formData[field]
|
||||
if (!value) {
|
||||
return
|
||||
}
|
||||
if (this.isDateTimeBlocked(value)) {
|
||||
this.$message.warning('该时间点不可预约,请重新选择')
|
||||
this.$set(this.formData, field, '')
|
||||
return
|
||||
}
|
||||
if (this.formData.reserveStartTime && this.formData.reserveEndTime && !this.validateTimeLimit()) {
|
||||
this.$set(this.formData, field, '')
|
||||
}
|
||||
},
|
||||
validateYearlyReserve() {
|
||||
if (!this.yearlyReserve) {
|
||||
return true
|
||||
}
|
||||
if (!this.yearlyReserveDates.length) {
|
||||
this.$message.warning('?????????????????????')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
buildSubmitApi() {
|
||||
return this.yearlyReserve ? '/platform/siteCug/apply/submitYearly' : '/platform/siteCug/apply/submit'
|
||||
},
|
||||
buildSubmitConfirmMessage() {
|
||||
if (!this.yearlyReserve) {
|
||||
return '您确定要提交吗?'
|
||||
}
|
||||
return '将一次性预约本年后续 ' + this.yearlyReserveDates.length + ' 个同星期时段,确认提交吗?'
|
||||
},
|
||||
onSubmit() {
|
||||
this.$refs.formRef.validate(async (valid) => {
|
||||
if (!valid) return
|
||||
if (!this.formData.reserveType) {
|
||||
this.$message.warning('请选择预约类型')
|
||||
return
|
||||
}
|
||||
await this.normalizeReserveTypeData()
|
||||
if (this.formData.reserveType === 'union' && !this.formData.applyUnionId) {
|
||||
this.$message.warning('当前用户未关联分工会,不能发起分工会预约')
|
||||
return
|
||||
}
|
||||
if (this.formData.reserveType === 'club' && !this.formData.clubId) {
|
||||
this.$message.warning('请选择您管理的协会')
|
||||
return
|
||||
}
|
||||
if (!this.formData.reserveStartTime || !this.formData.reserveEndTime) {
|
||||
this.$message.warning('请选择预约开始和结束时间')
|
||||
return
|
||||
}
|
||||
const start = this.$moment(this.formData.reserveStartTime)
|
||||
const end = this.$moment(this.formData.reserveEndTime)
|
||||
if (!start.isAfter(this.$moment())) {
|
||||
this.$message.warning('预约开始时间必须晚于当前时间')
|
||||
return
|
||||
}
|
||||
if (!end.isAfter(start)) {
|
||||
this.$message.warning('预约结束时间必须晚于开始时间')
|
||||
return
|
||||
}
|
||||
if (!this.validateTimeLimit()) {
|
||||
return
|
||||
}
|
||||
if (!this.validateYearlyReserve()) {
|
||||
return
|
||||
}
|
||||
|
||||
this.$confirm(this.buildSubmitConfirmMessage(), '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$axios.post(this.buildSubmitApi(), {
|
||||
data: JSON.stringify(this.formData),
|
||||
}).then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg || '提交成功')
|
||||
this.$emit('refresh')
|
||||
} else {
|
||||
this.$message.warning(resp.msg || '提交失败')
|
||||
}
|
||||
}).catch((err) => {
|
||||
this.$message.warning((err && err.msg) || '提交失败')
|
||||
})
|
||||
}).catch(() => {})
|
||||
})
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,125 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<guava ref="guava">
|
||||
<template>
|
||||
<el-card shadow="never">
|
||||
<search @search="doSearch">
|
||||
<search-item label="名称/地址">
|
||||
<el-input placeholder="请输入名称或地址" clearable v-model="pageForm.searchKeyword"
|
||||
@keyup.enter.native="doSearch">
|
||||
</el-input>
|
||||
</search-item>
|
||||
<search-item label="场地类型">
|
||||
<el-select v-model="pageForm.type" clearable filterable placeholder="请选择场地类型" @change="doSearch">
|
||||
<el-option
|
||||
v-for="item in typeOptions"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
:key="item.id"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
</search>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="mt20">
|
||||
<table-tool label="场地列表"></table-tool>
|
||||
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize">
|
||||
<el-table-column label="序号" type="index" :index="indexMethod" width="60"></el-table-column>
|
||||
<el-table-column
|
||||
:label="column.label"
|
||||
:prop="column.prop"
|
||||
:key="column.prop"
|
||||
:width="column.width"
|
||||
:sortable="column.sortable"
|
||||
align="center"
|
||||
header-align="center"
|
||||
show-overflow-tooltip
|
||||
v-for="column in tableColumns"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="180">
|
||||
<template v-slot="{ row }">
|
||||
<el-button @click="onViewSite(row)" size="mini" type="primary">查看场地</el-button>
|
||||
<el-button @click="onApply(row)" size="mini" type="primary">预约</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<template #edit>
|
||||
<site-apply ref="applyRef" @refresh="refresh"></site-apply>
|
||||
</template>
|
||||
<template #view>
|
||||
<info ref="infoRef"></info>
|
||||
</template>
|
||||
</guava>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include('../manage/info.js'){}#-->
|
||||
<!--#include('apply.js'){}#-->
|
||||
const vue = new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
components: {
|
||||
"info": siteInfo,
|
||||
"site-apply": apply,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
typeOptions: [],
|
||||
tableColumns: [
|
||||
{prop: 'name', label: '场地名称'},
|
||||
{prop: 'address', label: '场地地址'},
|
||||
{prop: 'contactName', label: '联系人'},
|
||||
{prop: 'contactPhone', label: '联系电话'},
|
||||
{prop: 'maxNum', label: '容纳人数'},
|
||||
{prop: 'typeName', label: '场地类型'},
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
refresh() {
|
||||
this.doSearch()
|
||||
this.$refs.guava.index()
|
||||
},
|
||||
onApply(row) {
|
||||
this.$refs.guava.edit(() => {
|
||||
this.$refs.applyRef.onOpen(row)
|
||||
})
|
||||
},
|
||||
onViewSite(row) {
|
||||
this.$refs.guava.view(() => {
|
||||
this.$refs.infoRef.onOpen(row)
|
||||
})
|
||||
},
|
||||
querySiteType() {
|
||||
this.$axios.post('/platform/siteCug/function/type/queryFunctionType').then((res) => {
|
||||
this.typeOptions = res.data
|
||||
})
|
||||
},
|
||||
pageData() {
|
||||
this.$axios.post(loc() + '/pageData', this.pageForm).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.tableData = res.data.list
|
||||
this.pageForm.totalCount = res.data.totalCount
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
this.querySiteType()
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,80 @@
|
||||
const siteCugApplyInfo = {
|
||||
template: /*language=HTML*/ `
|
||||
<div>
|
||||
<div class="process-title">
|
||||
申请信息
|
||||
<el-link type="primary" @click="openChart">点击查看流程图</el-link>
|
||||
</div>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="预约场地">{{ viewData.siteName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="预约人">{{ viewData.applyUserName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="预约人工号">{{ viewData.applyLoginName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="所属单位">{{ viewData.applyUnitName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="预约类型">{{ reserveTypeLabel }}</el-descriptions-item>
|
||||
<el-descriptions-item label="预约主体">{{ reserveTargetName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="开始时间">{{ viewData.reserveStartTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="结束时间">{{ viewData.reserveEndTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="联系电话">{{ viewData.applyMobile }}</el-descriptions-item>
|
||||
<el-descriptions-item label="预约人数">{{ viewData.joinCount }}</el-descriptions-item>
|
||||
<el-descriptions-item label="预约事由" :span="2">{{ viewData.applyCause }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<template v-for="task in doneTasks">
|
||||
<div class="mt10">
|
||||
<div class="process-title">{{ task.displayName }}</div>
|
||||
<el-descriptions border class="flow-task-form" :column="3" :key="task.id" v-if="task.ext.isFirstTaskNode">
|
||||
<el-descriptions-item label="申请用户">{{ task.ext.initiatorName }}({{task.ext.initiatorAccount}})</el-descriptions-item>
|
||||
<el-descriptions-item label="申请时间">{{ task.finishTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="办理结果">
|
||||
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE" :value="task.ext.submitType"></dict-tag>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<el-descriptions border class="flow-task-form" :column="3" :key="task.id" v-else>
|
||||
<el-descriptions-item label="办理用户">{{ task.taskFormData.userName }}({{task.taskFormData.loginName}})</el-descriptions-item>
|
||||
<el-descriptions-item label="办理时间">{{ task.finishTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="办理结果">
|
||||
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE" :value="task.ext.submitType"></dict-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="办理意见">{{ task.taskFormData.opinion }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</template>
|
||||
<slot></slot>
|
||||
<snaker-chart ref="snakerChartRef"></snaker-chart>
|
||||
</div>
|
||||
`,
|
||||
store,
|
||||
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
|
||||
data() {
|
||||
return {
|
||||
viewData: {},
|
||||
doneTasks: [],
|
||||
row: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
reserveTypeLabel() {
|
||||
return this.viewData.reserveType === 'club' ? '协会预约' : '分工会预约'
|
||||
},
|
||||
reserveTargetName() {
|
||||
return this.viewData.reserveType === 'club' ? (this.viewData.clubName || '-') : (this.viewData.applyUnionName || '-')
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onOpen(row) {
|
||||
this.row = row
|
||||
this.viewData = row
|
||||
this.getDoneTasks()
|
||||
},
|
||||
getDoneTasks() {
|
||||
this.$axios.post('/flow/common/doneTasks', {bizId: this.row.id}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.doneTasks = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
openChart() {
|
||||
this.$refs.snakerChartRef.onOpenFull(this.row.instanceProcessDefineId, this.row.instanceId)
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,341 @@
|
||||
const basicForm = {
|
||||
template: /*language=HTML*/ `
|
||||
<div>
|
||||
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="110px" label-position="left">
|
||||
<el-row :gutter="20" type="flex">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="创建人" prop="createUserName">
|
||||
<el-input disabled type="text" v-model="formData.createUserName" maxlength="20" placeholder="请输入创建人"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="sortNum" label="排序编号">
|
||||
<el-input v-model="formData.sortNum" placeholder="请输入排序编号" type="number"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" type="flex">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="场地名称" prop="name">
|
||||
<el-input type="text" v-model="formData.name" maxlength="50" placeholder="请输入场地名称"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="场地地址" prop="address">
|
||||
<el-input type="text" v-model="formData.address" maxlength="100" placeholder="请输入场地地址"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" type="flex">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="联系人" prop="contactName">
|
||||
<el-input type="text" v-model="formData.contactName" maxlength="20" placeholder="请输入联系人"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="联系电话" prop="contactPhone">
|
||||
<el-input type="text" v-model="formData.contactPhone" maxlength="20" placeholder="请输入联系电话"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" type="flex">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="容纳人数" prop="maxNum">
|
||||
<el-input v-model="formData.maxNum" placeholder="请输入容纳人数" type="number"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="场地类型" prop="typeId">
|
||||
<el-select v-model="formData.typeId" clearable filterable placeholder="请选择场地类型" style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in typeList"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
:key="item.id"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" type="flex">
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="sexLimit" label="性别限制">
|
||||
<el-radio-group v-model="formData.sexLimit" size="medium">
|
||||
<el-radio-button :label="0">不限制</el-radio-button>
|
||||
<el-radio-button :label="1">男</el-radio-button>
|
||||
<el-radio-button :label="2">女</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="state" label="开启状态">
|
||||
<el-radio-group v-model="formData.state" size="medium">
|
||||
<el-radio-button :label="true">开启</el-radio-button>
|
||||
<el-radio-button :label="false">禁用</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" type="flex">
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="filterHolidays" label="排除节假日">
|
||||
<el-radio-group v-model="formData.filterHolidays" size="medium">
|
||||
<el-radio-button :label="true">是</el-radio-button>
|
||||
<el-radio-button :label="false">否</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="禁用时间">
|
||||
<el-button type="primary" @click="openSetUpTime" size="small">点击设置禁用时间</el-button>
|
||||
<span style="color: #c64120">您已设置{{ formData.notApplyTimeList ? formData.notApplyTimeList.length : 0 }}个禁用时间</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-form-item label="场地介绍" prop="introduce">
|
||||
<text-editor v-model="formData.introduce"></text-editor>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-row class="mt10" justify="end" type="flex">
|
||||
<el-button @click="$emit('refresh')">取消</el-button>
|
||||
<el-button @click="onSubmit" type="primary">提交</el-button>
|
||||
</el-row>
|
||||
|
||||
<el-dialog append-to-body :close-on-click-modal="false" :visible.sync="setUpTimeDialog" title="设置时间">
|
||||
<div class="left-span-label">选择日期</div>
|
||||
<el-date-picker
|
||||
@change="setUpDateChange"
|
||||
placeholder="请选择一个或多个日期"
|
||||
style="width: 100%"
|
||||
type="dates"
|
||||
v-model="formData.setUpDate"
|
||||
value-format="yyyy-MM-dd">
|
||||
</el-date-picker>
|
||||
<div class="left-span-label mt20">设置禁用时间</div>
|
||||
<el-row>
|
||||
<el-time-select
|
||||
:picker-options="{
|
||||
start: '00:00',
|
||||
step: '00:05',
|
||||
end: '23:55'
|
||||
}"
|
||||
placeholder="开始时间"
|
||||
v-model="timeOneKeySet.startTime">
|
||||
</el-time-select>
|
||||
<el-time-select
|
||||
:picker-options="{
|
||||
start: '00:00',
|
||||
step: '00:05',
|
||||
end: '23:55'
|
||||
}"
|
||||
placeholder="结束时间"
|
||||
v-model="timeOneKeySet.endTime">
|
||||
</el-time-select>
|
||||
<el-button @click="oneKeySetStartEndTime" type="primary">一键设置开始/结束时间</el-button>
|
||||
</el-row>
|
||||
<el-table :data="formData.notApplyTimeList" class="mt10" max-height="520px" size="mini" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55"></el-table-column>
|
||||
<el-table-column label="日期" width="200">
|
||||
<template v-slot="{row}">
|
||||
<i class="el-icon-time"></i>
|
||||
{{$moment(row.date).format('YYYY-MM-DD')}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="开始时间">
|
||||
<template v-slot="{row}">
|
||||
<el-time-select
|
||||
size="mini"
|
||||
:picker-options="{
|
||||
start: '00:00',
|
||||
step: '00:05',
|
||||
end: '23:55'
|
||||
}"
|
||||
v-model="row.startTime">
|
||||
</el-time-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="结束时间">
|
||||
<template v-slot="{row}">
|
||||
<el-time-select
|
||||
size="mini"
|
||||
:picker-options="{
|
||||
start: '00:00',
|
||||
step: '00:05',
|
||||
end: '23:55'
|
||||
}"
|
||||
v-model="row.endTime">
|
||||
</el-time-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="200">
|
||||
<template v-slot="{row, $index}">
|
||||
<el-button
|
||||
size="mini"
|
||||
@click="formData.notApplyTimeList.splice($index,0,{date:row.date,startTime:'',endTime:''})"
|
||||
type="primary">
|
||||
新增同天时段
|
||||
</el-button>
|
||||
<el-button size="mini" @click="removeSetUpTableRow(row,$index)" type="danger">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-row class="mt20" justify="end" type="flex">
|
||||
<el-button @click="setUpTimeDialog = false">取消</el-button>
|
||||
<el-button @click="doConfirmSetUpCourse" type="primary">确定</el-button>
|
||||
</el-row>
|
||||
</el-dialog>
|
||||
</div>
|
||||
`,
|
||||
props: {
|
||||
typeList: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: [],
|
||||
}
|
||||
},
|
||||
store,
|
||||
data() {
|
||||
return {
|
||||
formData: {
|
||||
state: true,
|
||||
sexLimit: 0,
|
||||
filterHolidays: false,
|
||||
notApplyTimeList: [],
|
||||
createUserName: this.$store.state.user.username,
|
||||
createUserId: this.$store.state.user.id,
|
||||
},
|
||||
formRules: {
|
||||
createUserName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
sortNum: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
name: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
address: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
contactName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
contactPhone: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
maxNum: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
typeId: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
sexLimit: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
filterHolidays: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
state: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
},
|
||||
setUpTimeDialog: false,
|
||||
timeOneKeySet: {
|
||||
startTime: "",
|
||||
endTime: ""
|
||||
},
|
||||
multipleSelection: [],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
doConfirmSetUpCourse() {
|
||||
const timeList = this.formData.notApplyTimeList
|
||||
if (timeList && timeList.length > 0) {
|
||||
const valid = timeList.every(v => v.date && v.startTime && v.endTime && (v.startTime < v.endTime))
|
||||
if (!valid) {
|
||||
this.$message.warning("时间不完整或者有误")
|
||||
return
|
||||
}
|
||||
}
|
||||
this.setUpTimeDialog = false
|
||||
},
|
||||
removeSetUpTableRow(row, index) {
|
||||
this.formData.notApplyTimeList.splice(index, 1)
|
||||
const dateArray = this.formData.notApplyTimeList.map(v => this.$moment(v.date).format("YYYY-MM-DD"))
|
||||
const setUpDate = this.formData.setUpDate || []
|
||||
this.formData.setUpDate = setUpDate.filter(v => {
|
||||
return dateArray.includes(this.$moment(v).format("YYYY-MM-DD"))
|
||||
})
|
||||
},
|
||||
handleSelectionChange(val) {
|
||||
this.multipleSelection = val
|
||||
},
|
||||
oneKeySetStartEndTime() {
|
||||
if (this.multipleSelection.length === 0) {
|
||||
this.$message.warning('请在下面表格多选框中选择需要一键设置的时间')
|
||||
return
|
||||
}
|
||||
const { startTime, endTime } = this.timeOneKeySet
|
||||
this.formData.notApplyTimeList.forEach(v => {
|
||||
const selected = this.multipleSelection.find(o => o.date === v.date && o.startTime === v.startTime && o.endTime === v.endTime)
|
||||
if (selected) {
|
||||
this.$set(v, "startTime", startTime)
|
||||
this.$set(v, "endTime", endTime)
|
||||
}
|
||||
})
|
||||
this.$forceUpdate()
|
||||
},
|
||||
setUpDateChange(val) {
|
||||
if (!val) {
|
||||
this.formData.notApplyTimeList = []
|
||||
return
|
||||
}
|
||||
if (this.formData.notApplyTimeList === undefined) {
|
||||
this.$set(this.formData, "notApplyTimeList", [])
|
||||
}
|
||||
const dateSet = new Set(this.formData.notApplyTimeList.map(v => this.$moment(v.date).format("YYYY-MM-DD")))
|
||||
val.forEach(v => {
|
||||
if (!dateSet.has(v)) {
|
||||
this.formData.notApplyTimeList.push({
|
||||
date: v, startTime: "", endTime: ""
|
||||
})
|
||||
}
|
||||
})
|
||||
this.formData.notApplyTimeList = this.formData.notApplyTimeList.filter(v => {
|
||||
return val.includes(this.$moment(v.date).format("YYYY-MM-DD"))
|
||||
})
|
||||
this.formData.notApplyTimeList.sort((a, b) => {
|
||||
return Date.parse(a.date) - Date.parse(b.date)
|
||||
})
|
||||
},
|
||||
openSetUpTime() {
|
||||
if (this.formData.notApplyTimeList) {
|
||||
this.$set(this.formData, 'setUpDate', this.formData.notApplyTimeList.map(o => o.date))
|
||||
}
|
||||
this.setUpTimeDialog = true
|
||||
},
|
||||
onOpen(row) {
|
||||
if (row && row.id) {
|
||||
this.formData = clone(row)
|
||||
if (!Array.isArray(this.formData.notApplyTimeList)) {
|
||||
this.$set(this.formData, 'notApplyTimeList', [])
|
||||
}
|
||||
} else {
|
||||
this.formData = {
|
||||
state: true,
|
||||
sexLimit: 0,
|
||||
filterHolidays: false,
|
||||
notApplyTimeList: [],
|
||||
createUserName: this.$store.state.user.username,
|
||||
createUserId: this.$store.state.user.id,
|
||||
}
|
||||
}
|
||||
},
|
||||
onSubmit() {
|
||||
this.$refs.formRef.validate((valid) => {
|
||||
if (valid) {
|
||||
this.$confirm("您确定要提交吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(async () => {
|
||||
const resp = await this.$axios.post("/platform/siteCug/manage/submit", {data: JSON.stringify(this.formData)})
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.$emit('refresh')
|
||||
} else {
|
||||
this.$message.warning(resp.msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
style: /*language=CSS*/ `
|
||||
|
||||
`
|
||||
};
|
||||
@@ -0,0 +1,180 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<guava ref="guava">
|
||||
<template>
|
||||
<el-card shadow="never">
|
||||
<search @search="doSearch">
|
||||
<search-item label="名称/地址">
|
||||
<el-input placeholder="请输入名称或地址" clearable v-model="pageForm.searchKeyword"
|
||||
@keyup.enter.native="doSearch">
|
||||
</el-input>
|
||||
</search-item>
|
||||
<search-item label="场地类型">
|
||||
<el-select v-model="pageForm.type" clearable filterable placeholder="请选择场地类型" @change="doSearch">
|
||||
<el-option
|
||||
v-for="item in typeOptions"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
:key="item.id"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
</search>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="mt20">
|
||||
<table-tool label="场地列表">
|
||||
<el-button type="primary" size="small" @click="onAdd">
|
||||
<i class="ti-plus"></i>
|
||||
新增场地
|
||||
</el-button>
|
||||
</table-tool>
|
||||
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize">
|
||||
<el-table-column label="序号" type="index" :index="indexMethod" width="60"></el-table-column>
|
||||
<el-table-column
|
||||
:label="column.label"
|
||||
:prop="column.prop"
|
||||
:key="column.prop"
|
||||
:width="column.width"
|
||||
:sortable="column.sortable"
|
||||
align="center"
|
||||
header-align="center"
|
||||
show-overflow-tooltip
|
||||
v-for="column in tableColumns"
|
||||
>
|
||||
<template v-slot="{ row }" v-if="column.prop === 'state'">
|
||||
<el-switch
|
||||
@change="switchChange(row)"
|
||||
v-model="row.state"
|
||||
active-color="#13ce66"
|
||||
inactive-color="#ff4949">
|
||||
</el-switch>
|
||||
</template>
|
||||
<template v-slot="{ row }" v-else-if="column.prop === 'sexLimit'">
|
||||
<span v-if="row.sexLimit === 0">不限制</span>
|
||||
<span v-else-if="row.sexLimit === 1">男</span>
|
||||
<span v-else-if="row.sexLimit === 2">女</span>
|
||||
<span v-else>--</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="230">
|
||||
<template v-slot="{ row }">
|
||||
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
|
||||
<el-button @click="onEdit(row)" size="mini" type="primary">编辑</el-button>
|
||||
<el-button @click="onDelete(row)" size="mini" type="danger">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<template #edit>
|
||||
<basic-form :type-list="typeOptions" ref="basicFormRef" @refresh="refresh"></basic-form>
|
||||
</template>
|
||||
<template #view>
|
||||
<info ref="infoRef"></info>
|
||||
</template>
|
||||
</guava>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include('basicForm.js'){}#-->
|
||||
<!--#include('info.js'){}#-->
|
||||
const vue = new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
components: {
|
||||
"basic-form": basicForm,
|
||||
"info": siteInfo,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
typeOptions: [],
|
||||
tableColumns: [
|
||||
{prop: 'createUserName', label: '创建人'},
|
||||
{prop: 'sortNum', label: '排序编号'},
|
||||
{prop: 'name', label: '场地名称'},
|
||||
{prop: 'address', label: '场地地址'},
|
||||
{prop: 'contactName', label: '联系人'},
|
||||
{prop: 'contactPhone', label: '联系电话'},
|
||||
{prop: 'maxNum', label: '容纳人数'},
|
||||
{prop: 'typeName', label: '场地类型'},
|
||||
{prop: 'sexLimit', label: '性别限制'},
|
||||
{prop: 'state', label: '开启状态'},
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
refresh() {
|
||||
this.doSearch()
|
||||
this.$refs.guava.index()
|
||||
},
|
||||
onAdd() {
|
||||
this.$refs.guava.edit(() => {
|
||||
this.$refs.basicFormRef.onOpen()
|
||||
})
|
||||
},
|
||||
onEdit(row) {
|
||||
this.$refs.guava.edit(() => {
|
||||
this.$refs.basicFormRef.onOpen(row)
|
||||
})
|
||||
},
|
||||
onView(row) {
|
||||
this.$refs.guava.view(() => {
|
||||
this.$refs.infoRef.onOpen(row)
|
||||
})
|
||||
},
|
||||
onDelete(row) {
|
||||
this.$confirm("您确定要删除吗, 是否继续?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
})
|
||||
.then(() => {
|
||||
this.$axios.post("/platform/siteCug/manage/delete", { id: row.id }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success(res.msg)
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
},
|
||||
switchChange(row) {
|
||||
this.$axios.post("/platform/siteCug/manage/submit", row).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success(res.msg)
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
},
|
||||
querySiteType() {
|
||||
this.$axios.post("/platform/siteCug/function/type/queryFunctionType").then((res) => {
|
||||
this.typeOptions = res.data
|
||||
})
|
||||
},
|
||||
pageData() {
|
||||
this.$axios.post(loc() + "/pageData", this.pageForm).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.tableData = res.data.list
|
||||
this.pageForm.totalCount = res.data.totalCount
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
this.querySiteType()
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,59 @@
|
||||
const siteInfo = {
|
||||
template: /*language=HTML*/ `
|
||||
<div>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="创建人">{{ viewData.createUserName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="排序编号">{{ viewData.sortNum }}</el-descriptions-item>
|
||||
<el-descriptions-item label="场地名称">{{ viewData.name }}</el-descriptions-item>
|
||||
<el-descriptions-item label="场地地址">{{ viewData.address }}</el-descriptions-item>
|
||||
<el-descriptions-item label="联系人">{{ viewData.contactName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="联系电话">{{ viewData.contactPhone }}</el-descriptions-item>
|
||||
<el-descriptions-item label="容纳人数">{{ viewData.maxNum }}</el-descriptions-item>
|
||||
<el-descriptions-item label="场地类型">{{ viewData.typeName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="排除节假日">
|
||||
<span v-if="viewData.filterHolidays">是</span>
|
||||
<span v-else>否</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="禁用时间" :span="2">
|
||||
<el-table v-if="viewData.notApplyTimeList && viewData.notApplyTimeList.length > 0"
|
||||
:data="viewData.notApplyTimeList" max-height="300" size="mini">
|
||||
<el-table-column prop="date" label="日期"></el-table-column>
|
||||
<el-table-column prop="startTime" label="开始时间"></el-table-column>
|
||||
<el-table-column prop="endTime" label="结束时间"></el-table-column>
|
||||
</el-table>
|
||||
<span v-else>暂无禁用时间</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="性别限制">
|
||||
<span v-if="viewData.sexLimit === 0">不限制</span>
|
||||
<span v-if="viewData.sexLimit === 1">男</span>
|
||||
<span v-if="viewData.sexLimit === 2">女</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="开启状态">
|
||||
<span v-if="viewData.state">开启</span>
|
||||
<span v-else>禁用</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="场地介绍" :span="2">
|
||||
<div v-if="viewData.introduce" v-html="viewData.introduce"></div>
|
||||
<div v-else>暂无场地介绍</div>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
viewData: {},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onOpen(row) {
|
||||
this.viewData = row
|
||||
},
|
||||
},
|
||||
style: /*language=CSS*/ `
|
||||
.el-descriptions-item__label {
|
||||
width: 200px;
|
||||
min-width: 200px;
|
||||
max-width: 200px;
|
||||
}
|
||||
`
|
||||
};
|
||||
@@ -0,0 +1,140 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
<div id="app" v-cloak>
|
||||
<guava ref="guava">
|
||||
<template>
|
||||
<el-card shadow="never">
|
||||
<search @search="doSearch">
|
||||
<search-item label="姓名/工号/场地">
|
||||
<el-input placeholder="请输入姓名/工号/场地" clearable v-model="pageForm.searchKeyword"
|
||||
@keyup.enter.native="doSearch">
|
||||
</el-input>
|
||||
</search-item>
|
||||
<search-item label="活动场地">
|
||||
<el-select v-model="pageForm.siteId" @change="doSearch" style="width: 100%" placeholder="请选择活动场地" filterable clearable>
|
||||
<el-option v-for="item in siteOptions" :value="item.id" :key="item.id" :label="item.name"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="场地类型">
|
||||
<el-select v-model="pageForm.siteType" @change="doSearch" style="width: 100%" placeholder="请选择场地类型" filterable clearable>
|
||||
<el-option v-for="item in typeOptions" :value="item.id" :key="item.id" :label="item.name"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
</search>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never">
|
||||
<table-tool label="申请列表"></table-tool>
|
||||
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
|
||||
<el-table-column type="index" width="50" label="序号" :index="indexMethod"></el-table-column>
|
||||
<el-table-column
|
||||
:label="column.label"
|
||||
:prop="column.prop"
|
||||
:key="column.prop"
|
||||
:width="column.width"
|
||||
:sortable="column.sortable"
|
||||
align="center"
|
||||
header-align="center"
|
||||
show-overflow-tooltip
|
||||
v-for="column in tableColumns"
|
||||
>
|
||||
<template v-slot="{ row }" v-if="column.prop === 'instanceState'">
|
||||
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message" size="small"></enum-tag>
|
||||
</template>
|
||||
<template v-slot="{ row }" v-else-if="column.prop === 'reserveType'">
|
||||
<span>{{ row.reserveType === 'club' ? '协会预约' : '分工会预约' }}</span>
|
||||
</template>
|
||||
<template v-slot="{ row }" v-else-if="column.prop === 'reserveTargetName'">
|
||||
<span>{{ row.reserveType === 'club' ? (row.clubName || '-') : (row.applyUnionName || '-') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="180">
|
||||
<template v-slot="{row}">
|
||||
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
|
||||
<el-button v-if="row.canCancel" @click="onDelete(row)" size="mini" type="danger">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<template #edit>
|
||||
<info ref="infoRef"></info>
|
||||
</template>
|
||||
</guava>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include('../common/applyInfo.js'){}#-->
|
||||
new Vue({
|
||||
el: '#app',
|
||||
store,
|
||||
mixins: [initTableMixins],
|
||||
components: {
|
||||
'info': siteCugApplyInfo,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
typeOptions: [],
|
||||
siteOptions: [],
|
||||
tableColumns: [
|
||||
{prop: 'siteName', label: '场地名称'},
|
||||
{prop: 'applyUserName', label: '预约人'},
|
||||
{prop: 'reserveType', label: '预约类型'},
|
||||
{prop: 'reserveTargetName', label: '预约单位'},
|
||||
{prop: 'applyUnitName', label: '所属单位'},
|
||||
{prop: 'reserveStartTime', label: '开始时间'},
|
||||
{prop: 'reserveEndTime', label: '结束时间'},
|
||||
{prop: 'applyMobile', label: '联系方式'},
|
||||
{prop: 'taskName', label: '当前节点'},
|
||||
{prop: 'instanceState', label: '流程状态'},
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onView(row) {
|
||||
this.$refs.guava.edit(() => {
|
||||
this.$refs.infoRef.onOpen(row)
|
||||
})
|
||||
},
|
||||
onDelete(row) {
|
||||
const message = row.yearlyBatch
|
||||
? ('该记录属于“预约本年”批量预约,确认后将一并删除同批次的 ' + (row.batchDeleteCount || 0) + ' 条预约记录,是否继续?')
|
||||
: '您确定要删除吗?'
|
||||
this.$confirm(message, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$axios.post('/platform/siteCug/mine/delete', { id: row.id }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success(res.msg)
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
querySiteType() {
|
||||
this.$axios.post('/platform/siteCug/function/type/queryFunctionType').then((res) => {
|
||||
this.typeOptions = res.data
|
||||
})
|
||||
},
|
||||
querySites() {
|
||||
this.$axios.post('/platform/siteCug/manage/querySites').then((res) => {
|
||||
this.siteOptions = res.data
|
||||
})
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
this.querySiteType()
|
||||
this.querySites()
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,187 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
<div id="app" v-cloak>
|
||||
<guava ref="guava">
|
||||
<template>
|
||||
<el-card shadow="never">
|
||||
<search @search="doSearch">
|
||||
<search-item label="姓名/工号/场地">
|
||||
<el-input placeholder="请输入姓名/工号/场地" clearable v-model="pageForm.searchKeyword"
|
||||
@keyup.enter.native="doSearch">
|
||||
</el-input>
|
||||
</search-item>
|
||||
<search-item label="活动场地">
|
||||
<el-select v-model="pageForm.siteId" @change="doSearch" style="width: 100%"
|
||||
placeholder="请选择活动场地" filterable clearable>
|
||||
<el-option v-for="item in siteOptions"
|
||||
:value="item.id"
|
||||
:key="item.id"
|
||||
:label="item.name"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="场地类型">
|
||||
<el-select v-model="pageForm.siteType" @change="doSearch" style="width: 100%"
|
||||
placeholder="请选择场地类型" filterable clearable>
|
||||
<el-option v-for="item in typeOptions"
|
||||
:value="item.id"
|
||||
:key="item.id"
|
||||
:label="item.name"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="预约类型">
|
||||
<el-select v-model="pageForm.reserveType" @change="doSearch" style="width: 100%"
|
||||
placeholder="请选择预约类型" clearable>
|
||||
<el-option label="分工会预约" value="union"></el-option>
|
||||
<el-option label="协会预约" value="club"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="预约单位">
|
||||
<el-input placeholder="请输入分工会或协会名称" clearable v-model="pageForm.reserveTargetKeyword"
|
||||
@keyup.enter.native="doSearch">
|
||||
</el-input>
|
||||
</search-item>
|
||||
<search-item label="预约开始时间">
|
||||
<el-date-picker v-model="pageForm.reserveTimeStart"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="请选择预约开始时间"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
@change="doSearch">
|
||||
</el-date-picker>
|
||||
</search-item>
|
||||
<search-item label="预约结束时间">
|
||||
<el-date-picker v-model="pageForm.reserveTimeEnd"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="请选择预约结束时间"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
@change="doSearch">
|
||||
</el-date-picker>
|
||||
</search-item>
|
||||
</search>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never">
|
||||
<table-tool label="申请列表">
|
||||
<el-button type="primary" size="small" @click="doExport">导出表格</el-button>
|
||||
</table-tool>
|
||||
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
|
||||
<el-table-column type="index" width="50px" label="序号" :index="indexMethod"></el-table-column>
|
||||
<el-table-column
|
||||
:label="column.label"
|
||||
:prop="column.prop"
|
||||
:key="column.prop"
|
||||
:width="column.width"
|
||||
:sortable="column.sortable"
|
||||
align="center"
|
||||
header-align="center"
|
||||
show-overflow-tooltip
|
||||
v-for="column in tableColumns">
|
||||
<template v-slot="{ row }" v-if="column.prop === 'reserveType'">
|
||||
<span>{{ row.reserveType === 'club' ? '协会预约' : '分工会预约' }}</span>
|
||||
</template>
|
||||
<template v-slot="{ row }" v-else-if="column.prop === 'reserveTargetName'">
|
||||
<span>{{ row.reserveType === 'club' ? (row.clubName || '-') : (row.applyUnionName || '-') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="180">
|
||||
<template v-slot="{row}">
|
||||
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
|
||||
<el-button @click="onDelete(row.id)" size="mini" type="danger">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<template #edit>
|
||||
<info ref="infoRef"></info>
|
||||
</template>
|
||||
</guava>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include('../common/applyInfo.js'){}#-->
|
||||
new Vue({
|
||||
el: '#app',
|
||||
store,
|
||||
mixins: [initTableMixins],
|
||||
components: {
|
||||
'info': siteCugApplyInfo,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageForm: {
|
||||
audit: false,
|
||||
siteType: '',
|
||||
siteId: '',
|
||||
reserveType: '',
|
||||
reserveTargetKeyword: '',
|
||||
reserveTimeStart: '',
|
||||
reserveTimeEnd: '',
|
||||
},
|
||||
typeOptions: [],
|
||||
siteOptions: [],
|
||||
tableColumns: [
|
||||
{prop: 'siteName', label: '场地名称'},
|
||||
{prop: 'applyUserName', label: '预约人'},
|
||||
{prop: 'reserveType', label: '预约类型'},
|
||||
{prop: 'reserveTargetName', label: '预约单位'},
|
||||
{prop: 'applyUnitName', label: '所属单位'},
|
||||
{prop: 'reserveStartTime', label: '开始时间'},
|
||||
{prop: 'reserveEndTime', label: '结束时间'},
|
||||
{prop: 'applyMobile', label: '联系方式'},
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onView(row) {
|
||||
this.$refs.guava.edit(() => {
|
||||
this.$refs.infoRef.onOpen(row)
|
||||
})
|
||||
},
|
||||
onDelete(id) {
|
||||
this.$confirm('您确定要删除吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$axios.post('/platform/siteCug/record/delete', { id }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success(res.msg)
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
// 导出内容和列表当前筛选条件保持一致,实现所见即所得
|
||||
doExport() {
|
||||
this.$downLoad('/platform/siteCug/record/doExport', this.pageForm)
|
||||
},
|
||||
querySiteType() {
|
||||
this.$axios.post('/platform/siteCug/function/type/queryFunctionType').then((res) => {
|
||||
this.typeOptions = res.data
|
||||
})
|
||||
},
|
||||
querySites() {
|
||||
this.$axios.post('/platform/siteCug/manage/querySites').then((res) => {
|
||||
this.siteOptions = res.data
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// 查询字段在 data 中一次性声明完整,避免 Vue 2 对后加属性渲染不稳定
|
||||
this.querySiteType()
|
||||
this.querySites()
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+237
@@ -0,0 +1,237 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<div id="app">
|
||||
<guava ref="guava">
|
||||
|
||||
<el-card shadow="never">
|
||||
<search @search="doSearch">
|
||||
<search-item label="姓名/工号/场地">
|
||||
<el-input placeholder="请输入姓名/工号/场地" clearable v-model="pageForm.searchKeyword"
|
||||
@keyup.enter.native="doSearch">
|
||||
</el-input>
|
||||
</search-item>
|
||||
<search-item label="活动场地">
|
||||
<el-select v-model="pageForm.siteId" @change="doSearch" style="width: 100%"
|
||||
placeholder="请选择活动场地" filterable clearable>
|
||||
<el-option v-for="item in siteOptions"
|
||||
:value="item.id"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="场地类型">
|
||||
<el-select v-model="pageForm.siteType" @change="doSearch" style="width: 100%"
|
||||
placeholder="请选择场地类型" filterable clearable>
|
||||
<el-option v-for="item in typeOptions"
|
||||
:value="item.id"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
</search>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never">
|
||||
<table-tool label="申请列表">
|
||||
<el-radio-group v-model="pageForm.approval" size="small" @change="doSearch">
|
||||
<el-radio-button :label="true">已审核</el-radio-button>
|
||||
<el-radio-button :label="false">未审核</el-radio-button>
|
||||
</el-radio-group>
|
||||
</table-tool>
|
||||
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
|
||||
<el-table-column type="index" width="50px" label="序号" :index="indexMethod"></el-table-column>
|
||||
<el-table-column
|
||||
:label="column.label"
|
||||
:prop="column.prop"
|
||||
:key="column.prop"
|
||||
:width="column.width"
|
||||
:sortable="column.sortable"
|
||||
align="center"
|
||||
header-align="center"
|
||||
show-overflow-tooltip
|
||||
v-for="column in tableColumns"
|
||||
>
|
||||
<template v-slot="{ row }" v-if="column.prop === 'instanceState'">
|
||||
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message" size="small"></enum-tag>
|
||||
</template>
|
||||
<template v-slot="{ row }" v-else-if="column.prop === 'reserveType'">
|
||||
<span>{{ row.reserveType === 'club' ? '协会预约' : '分工会预约' }}</span>
|
||||
</template>
|
||||
<template v-slot="{ row }" v-else-if="column.prop === 'reserveTargetName'">
|
||||
<span>{{ row.reserveType === 'club' ? (row.clubName || '-') : (row.applyUnionName || '-') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="300px">
|
||||
<template v-slot="{row}">
|
||||
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
|
||||
<el-button v-if="row.taskState === 10" @click="onAudit(row)" size="mini" type="primary">审核</el-button>
|
||||
<el-button v-if="canRevoke(row)" :loading="revokeLoading" :disabled="revokeLoading" @click="onRevoke(row)" size="mini" type="danger">撤回</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
</el-card>
|
||||
|
||||
<template #edit>
|
||||
<info ref="infoRef">
|
||||
<div v-if="showApprovalForm">
|
||||
<div class="process-title">
|
||||
{{formData.taskName}}
|
||||
</div>
|
||||
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=":"
|
||||
class="flow-task-form">
|
||||
<el-form-item label="审批意见" prop="tf_opinion"
|
||||
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
||||
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-row type="flex" justify="end">
|
||||
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
|
||||
<el-button @click="handleTaskAction(6)" :loading="auditLoading" :disabled="auditLoading" size="small" type="info">退回到发起人</el-button>
|
||||
<el-button @click="handleTaskAction(2)" :loading="auditLoading" :disabled="auditLoading" size="small" type="danger">拒绝申请</el-button>
|
||||
<el-button @click="handleTaskAction(1)" :loading="auditLoading" :disabled="auditLoading" size="small" type="primary">同意申请</el-button>
|
||||
</el-row>
|
||||
</div>
|
||||
</info>
|
||||
</template>
|
||||
|
||||
</guava>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include('../common/applyInfo.js'){}#-->
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
mixins: [initTableMixins],
|
||||
components: {
|
||||
"info": siteCugApplyInfo,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageForm: {
|
||||
approval: false
|
||||
},
|
||||
tableColumns: [
|
||||
{prop: 'siteName', label: '场地名称'},
|
||||
{prop: 'applyUserName', label: '预约人'},
|
||||
{prop: 'reserveType', label: '预约类型'},
|
||||
{prop: 'reserveTargetName', label: '预约单位'},
|
||||
{prop: 'applyUnitName', label: '所属单位'},
|
||||
{prop: 'reserveStartTime', label: '开始时间'},
|
||||
{prop: 'reserveEndTime', label: '结束时间'},
|
||||
{prop: 'applyMobile', label: '联系方式'},
|
||||
{prop: 'curTaskName', label: '当前节点'},
|
||||
{prop: 'instanceState', label: '流程状态'},
|
||||
],
|
||||
typeOptions: [],
|
||||
siteOptions: [],
|
||||
formData: {},
|
||||
formRules: {},
|
||||
showApprovalForm: false,
|
||||
auditLoading: false,
|
||||
revokeLoading: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
canRevoke(row) {
|
||||
return Number(row.instanceState) === 20
|
||||
},
|
||||
onView(row) {
|
||||
this.$refs.guava.edit(() => {
|
||||
this.showApprovalForm = false
|
||||
this.$refs.infoRef.onOpen(row)
|
||||
})
|
||||
},
|
||||
onAudit(row) {
|
||||
this.$refs.guava.edit(() => {
|
||||
this.showApprovalForm = true
|
||||
this.formData = {
|
||||
processTaskId: row.taskId,
|
||||
applyId: row.id,
|
||||
taskName: row.curTaskName,
|
||||
tf_opinion: '',
|
||||
yearlyBatch: row.yearlyBatch,
|
||||
batchAuditCount: row.batchAuditCount,
|
||||
}
|
||||
this.$refs.infoRef.onOpen(row)
|
||||
})
|
||||
},
|
||||
handleTaskAction(val) {
|
||||
if (this.auditLoading) {
|
||||
return
|
||||
}
|
||||
const message = this.formData.yearlyBatch
|
||||
? ('该记录属于“预约本年”批量预约,提交后将一并审核同批次的 ' + (this.formData.batchAuditCount || 0) + ' 条预约记录,是否继续?')
|
||||
: '您确定要提交吗?'
|
||||
this.$confirm(message, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.auditLoading = true
|
||||
this.$axios.post('/platform/siteCug/schoolUnionAudit/executeTask', {
|
||||
data: JSON.stringify({
|
||||
...this.formData,
|
||||
submitType: val
|
||||
})
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$refs.guava.index()
|
||||
this.$message.success(res.msg)
|
||||
this.doSearch()
|
||||
}
|
||||
}).finally(() => {
|
||||
this.auditLoading = false
|
||||
})
|
||||
}).catch(() => {})
|
||||
},
|
||||
onRevoke(row) {
|
||||
if (!this.canRevoke(row) || this.revokeLoading) {
|
||||
return
|
||||
}
|
||||
const message = row.yearlyBatch
|
||||
? ('该记录属于“预约本年”批量预约,撤回后将一并撤回同批次的 ' + (row.batchAuditCount || 0) + ' 条审核任务,是否继续?')
|
||||
: '您确定要撤回吗?'
|
||||
this.$confirm(message, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'info'
|
||||
}).then(() => {
|
||||
this.revokeLoading = true
|
||||
this.$axios.post('/platform/siteCug/schoolUnionAudit/revokeTask', { taskId: row.taskId, applyId: row.id }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success(res.msg)
|
||||
this.doSearch()
|
||||
}
|
||||
}).finally(() => {
|
||||
this.revokeLoading = false
|
||||
})
|
||||
}).catch(() => {})
|
||||
},
|
||||
querySiteType() {
|
||||
this.$axios.post('/platform/siteCug/function/type/queryFunctionType').then((res) => {
|
||||
this.typeOptions = res.data
|
||||
})
|
||||
},
|
||||
querySites() {
|
||||
this.$axios.post('/platform/siteCug/manage/querySites').then((res) => {
|
||||
this.siteOptions = res.data
|
||||
})
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
this.querySiteType()
|
||||
this.querySites()
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,68 @@
|
||||
const basicForm = {
|
||||
template: /*language=HTML*/ `
|
||||
<div>
|
||||
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="110px" label-position="left">
|
||||
<el-form-item label="类型编码" prop="code">
|
||||
<el-input type="text" v-model="formData.code" maxlength="50"
|
||||
placeholder="请输入类型编码"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型名称" prop="name">
|
||||
<el-input type="text" v-model="formData.name" maxlength="50"
|
||||
placeholder="请输入类型名称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否启用" prop="enable">
|
||||
<el-switch
|
||||
v-model="formData.enable"
|
||||
active-color="#13ce66"
|
||||
inactive-color="#ff4949">
|
||||
</el-switch>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-row class="mt10" justify="end" type="flex">
|
||||
<el-button @click="$emit('refresh')">取消</el-button>
|
||||
<el-button @click="onSubmit" type="primary">提交</el-button>
|
||||
</el-row>
|
||||
</div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
formData: {
|
||||
enable: true
|
||||
},
|
||||
formRules: {
|
||||
name: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
code: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
enable: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onOpen(row) {
|
||||
if (row && row.id) {
|
||||
this.formData = clone(row)
|
||||
}
|
||||
},
|
||||
onSubmit() {
|
||||
this.$refs.formRef.validate((valid) => {
|
||||
if (valid) {
|
||||
this.$confirm("您确定要提交吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(async () => {
|
||||
const resp = await this.$axios.post("/platform/siteCug/function/type/submit", this.formData)
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.$emit('refresh')
|
||||
} else {
|
||||
this.$message.warning(resp.msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
style: /*language=CSS*/ `
|
||||
|
||||
`
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<guava ref="guava">
|
||||
<template>
|
||||
<el-card shadow="never">
|
||||
<search @search="doSearch">
|
||||
<search-item label="名称/编码">
|
||||
<el-input placeholder="请输入名称或编码" clearable v-model="pageForm.searchKeyword"
|
||||
@keyup.enter.native="doSearch">
|
||||
</el-input>
|
||||
</search-item>
|
||||
</search>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="mt20">
|
||||
<table-tool label="功能类型列表">
|
||||
<el-button type="primary" size="small" @click="onAdd">
|
||||
<i class="ti-plus"></i>
|
||||
新增类型
|
||||
</el-button>
|
||||
</table-tool>
|
||||
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize">
|
||||
<el-table-column label="序号" type="index" :index="indexMethod" width="60"></el-table-column>
|
||||
<el-table-column
|
||||
:label="column.label"
|
||||
:prop="column.prop"
|
||||
:key="column.prop"
|
||||
:width="column.width"
|
||||
:sortable="column.sortable"
|
||||
align="center"
|
||||
header-align="center"
|
||||
show-overflow-tooltip
|
||||
v-for="column in tableColumns"
|
||||
>
|
||||
<template v-slot="{ row }" v-if="column.prop === 'enable'">
|
||||
<el-switch
|
||||
@change="switchChange(row)"
|
||||
v-model="row.enable"
|
||||
active-color="#13ce66"
|
||||
inactive-color="#ff4949">
|
||||
</el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="230">
|
||||
<template v-slot="{ row }">
|
||||
<el-button @click="onEdit(row)" size="mini" type="primary">编辑</el-button>
|
||||
<el-button @click="onDelete(row)" size="mini" type="danger">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<template #edit>
|
||||
<basic-form ref="basicFormRef" @refresh="refresh"></basic-form>
|
||||
</template>
|
||||
</guava>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include('basicForm.js'){}#-->
|
||||
const vue = new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
components: {
|
||||
"basic-form": basicForm,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableColumns: [
|
||||
{prop: 'code', label: '类型编码'},
|
||||
{prop: 'name', label: '类型名称'},
|
||||
{prop: 'enable', label: '是否启用'},
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
refresh() {
|
||||
this.doSearch()
|
||||
this.$refs.guava.index()
|
||||
},
|
||||
onAdd() {
|
||||
this.$refs.guava.edit(() => {
|
||||
this.$refs.basicFormRef.onOpen()
|
||||
})
|
||||
},
|
||||
onEdit(row) {
|
||||
this.$refs.guava.edit(() => {
|
||||
this.$refs.basicFormRef.onOpen(row)
|
||||
})
|
||||
},
|
||||
onDelete(row) {
|
||||
this.$confirm("您确定要删除吗, 是否继续?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
})
|
||||
.then(() => {
|
||||
this.$axios.post("/platform/siteCug/function/type/delete", { id: row.id }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success(res.msg)
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
},
|
||||
switchChange(row) {
|
||||
this.$axios.post("/platform/siteCug/function/type/submit", row).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success(res.msg)
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
},
|
||||
pageData() {
|
||||
this.$axios.post(loc() + "/pageData", this.pageForm).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.tableData = res.data.list
|
||||
this.pageForm.totalCount = res.data.totalCount
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,887 @@
|
||||
new Vue({
|
||||
el: '#app',
|
||||
store,
|
||||
data() {
|
||||
return {
|
||||
siteId: GetQueryString('siteId'),
|
||||
row: {},
|
||||
siteLoaded: false,
|
||||
clubOptions: [],
|
||||
timeLimitConfig: {
|
||||
filterHolidays: false,
|
||||
holidayList: [],
|
||||
notApplyTimeList: [],
|
||||
},
|
||||
formData: {
|
||||
reserveType: 'union',
|
||||
applyUnionId: '',
|
||||
applyUnionName: '',
|
||||
clubId: '',
|
||||
clubName: '',
|
||||
applyMobile: '',
|
||||
reserveStartTime: '',
|
||||
reserveEndTime: '',
|
||||
joinCount: 1,
|
||||
applyCause: '',
|
||||
},
|
||||
showReserveTypePicker: false,
|
||||
showClubPicker: false,
|
||||
showTimePicker: false,
|
||||
timePickerField: '',
|
||||
timePickerColumns: [],
|
||||
timePickerParts: {
|
||||
date: '',
|
||||
hour: null,
|
||||
minute: null,
|
||||
},
|
||||
timePickerSyncing: false,
|
||||
pickerFilterCache: {},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
reserveTypeColumns() {
|
||||
return ['分工会预约', '协会预约']
|
||||
},
|
||||
reserveTypeText() {
|
||||
if (this.formData.reserveType === 'club') {
|
||||
return '协会预约'
|
||||
}
|
||||
if (this.formData.reserveType === 'union') {
|
||||
return '分工会预约'
|
||||
}
|
||||
return ''
|
||||
},
|
||||
clubColumns() {
|
||||
return this.clubOptions.map(item => item.clubName)
|
||||
},
|
||||
timePickerTitle() {
|
||||
return this.timePickerField === 'reserveEndTime' ? '选择预约结束时间' : '选择预约开始时间'
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
historyBack,
|
||||
clearTimePickerCache() {
|
||||
this.pickerFilterCache = {}
|
||||
},
|
||||
buildDefaultFormData() {
|
||||
const user = this.$store.state.user || {}
|
||||
return {
|
||||
siteId: this.row.id || '',
|
||||
applyUserId: user.id || '',
|
||||
applyUserName: user.username || '',
|
||||
applySex: user.sex || '',
|
||||
applyLoginName: user.loginname || '',
|
||||
applyUnitId: user.unit ? user.unit.id : '',
|
||||
applyUnitName: user.unit ? user.unit.name : '',
|
||||
reserveType: 'union',
|
||||
applyUnionId: user.union ? user.union.id : '',
|
||||
applyUnionName: user.union ? user.union.name : '',
|
||||
clubId: '',
|
||||
clubName: '',
|
||||
applyMobile: user.mobile || '',
|
||||
reserveStartTime: '',
|
||||
reserveEndTime: '',
|
||||
joinCount: 1,
|
||||
applyCause: '',
|
||||
}
|
||||
},
|
||||
getNormalizedMoment(value) {
|
||||
return this.$moment(value).seconds(0).milliseconds(0)
|
||||
},
|
||||
getFieldMinMoment(field) {
|
||||
const now = this.$moment().add(1, 'minute').seconds(0).milliseconds(0)
|
||||
if (field === 'reserveEndTime' && this.formData.reserveStartTime) {
|
||||
const start = this.getNormalizedMoment(this.formData.reserveStartTime).add(1, 'minute')
|
||||
return start.isAfter(now) ? start : now
|
||||
}
|
||||
return now
|
||||
},
|
||||
getFieldLatestMoment(field) {
|
||||
if (field === 'reserveStartTime' && this.formData.reserveEndTime) {
|
||||
return this.getNormalizedMoment(this.formData.reserveEndTime).subtract(1, 'minute')
|
||||
}
|
||||
return null
|
||||
},
|
||||
getFieldMaxMoment(field) {
|
||||
const defaultMax = this.$moment().add(365, 'day').endOf('day').seconds(0).milliseconds(0)
|
||||
const latest = this.getFieldLatestMoment(field)
|
||||
if (latest && latest.isBefore(defaultMax)) {
|
||||
return latest.clone().seconds(0).milliseconds(0)
|
||||
}
|
||||
return defaultMax
|
||||
},
|
||||
getContinuousEndBounds() {
|
||||
if (!this.formData.reserveStartTime) {
|
||||
return null
|
||||
}
|
||||
const minMoment = this.getFieldMinMoment('reserveEndTime')
|
||||
let maxMoment = this.getFieldMaxMoment('reserveEndTime')
|
||||
if (maxMoment.isBefore(minMoment)) {
|
||||
return null
|
||||
}
|
||||
let boundary = null
|
||||
const blockedDayCursor = minMoment.clone().startOf('day').add(1, 'day')
|
||||
while (blockedDayCursor.isSameOrBefore(maxMoment, 'day')) {
|
||||
if (this.isBlockedDay(blockedDayCursor)) {
|
||||
boundary = blockedDayCursor.clone().startOf('day')
|
||||
break
|
||||
}
|
||||
blockedDayCursor.add(1, 'day')
|
||||
}
|
||||
const list = Array.isArray(this.timeLimitConfig.notApplyTimeList) ? this.timeLimitConfig.notApplyTimeList : []
|
||||
list.forEach(item => {
|
||||
if (!item || !item.date || !item.startTime || !item.endTime) {
|
||||
return
|
||||
}
|
||||
const dayStr = this.$moment(item.date).format('YYYY-MM-DD')
|
||||
const rangeStart = this.$moment(dayStr + ' ' + this.normalizeTime(item.startTime))
|
||||
const rangeEnd = this.$moment(dayStr + ' ' + this.normalizeTime(item.endTime))
|
||||
if (rangeEnd.isSameOrBefore(minMoment)) {
|
||||
return
|
||||
}
|
||||
if (rangeStart.isSameOrBefore(minMoment) && rangeEnd.isAfter(minMoment)) {
|
||||
boundary = minMoment.clone()
|
||||
return
|
||||
}
|
||||
if (rangeStart.isAfter(minMoment) && rangeStart.isSameOrBefore(maxMoment)) {
|
||||
if (!boundary || rangeStart.isBefore(boundary)) {
|
||||
boundary = rangeStart.clone()
|
||||
}
|
||||
}
|
||||
})
|
||||
if (boundary && boundary.isSameOrBefore(maxMoment)) {
|
||||
maxMoment = boundary.clone().subtract(1, 'minute')
|
||||
}
|
||||
if (maxMoment.isBefore(minMoment)) {
|
||||
return null
|
||||
}
|
||||
return {
|
||||
minMoment: minMoment,
|
||||
maxMoment: maxMoment,
|
||||
}
|
||||
},
|
||||
getEffectiveFieldMaxMoment(field) {
|
||||
if (field === 'reserveEndTime' && this.formData.reserveStartTime) {
|
||||
const bounds = this.getContinuousEndBounds()
|
||||
return bounds ? bounds.maxMoment.clone() : this.getFieldMinMoment(field).clone().subtract(1, 'minute')
|
||||
}
|
||||
return this.getFieldMaxMoment(field)
|
||||
},
|
||||
buildPickerMoment(parts) {
|
||||
if (parts && parts.date) {
|
||||
return this.$moment(parts.date, 'YYYY-MM-DD')
|
||||
.hour(parts.hour || 0)
|
||||
.minute(parts.minute || 0)
|
||||
.second(0)
|
||||
.millisecond(0)
|
||||
}
|
||||
return this.$moment({
|
||||
year: parts.year,
|
||||
month: parts.month - 1,
|
||||
date: parts.day,
|
||||
hour: parts.hour,
|
||||
minute: parts.minute,
|
||||
second: 0,
|
||||
millisecond: 0,
|
||||
})
|
||||
},
|
||||
extractTimePickerPartsFromMoment(momentValue) {
|
||||
const pickerMoment = this.getNormalizedMoment(momentValue)
|
||||
return {
|
||||
date: pickerMoment.format('YYYY-MM-DD'),
|
||||
hour: pickerMoment.hour(),
|
||||
minute: pickerMoment.minute(),
|
||||
}
|
||||
},
|
||||
getPickerPartValue(item, fallback) {
|
||||
if (item && typeof item === 'object' && item !== null && typeof item.value !== 'undefined') {
|
||||
return item.value
|
||||
}
|
||||
if (item === '' || item === null || typeof item === 'undefined') {
|
||||
return fallback
|
||||
}
|
||||
return item
|
||||
},
|
||||
extractTimePickerParts(values) {
|
||||
const fallback = this.timePickerParts || {}
|
||||
return {
|
||||
date: this.getPickerPartValue(values && values[0], fallback.date),
|
||||
hour: Number(this.getPickerPartValue(values && values[1], fallback.hour)),
|
||||
minute: Number(this.getPickerPartValue(values && values[2], fallback.minute)),
|
||||
}
|
||||
},
|
||||
isValidCalendarMoment(momentValue, month, day) {
|
||||
return momentValue.isValid() && momentValue.month() + 1 === month && momentValue.date() === day
|
||||
},
|
||||
isBlockedDay(momentValue) {
|
||||
if (!momentValue || !momentValue.isValid()) {
|
||||
return true
|
||||
}
|
||||
if (momentValue.day() === 0 || momentValue.day() === 6) {
|
||||
return true
|
||||
}
|
||||
return this.timeLimitConfig.filterHolidays && this.timeLimitConfig.holidayList.includes(momentValue.format('YYYY-MM-DD'))
|
||||
},
|
||||
isRangeSelectable(start, end) {
|
||||
if (!start || !end || !start.isValid() || !end.isValid()) {
|
||||
return false
|
||||
}
|
||||
if (!end.isAfter(start)) {
|
||||
return false
|
||||
}
|
||||
if (this.hasHolidayInRange(start, end)) {
|
||||
return false
|
||||
}
|
||||
if (this.overlapsDisabledRange(start, end)) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
isExactTimeSelectable(momentValue, field) {
|
||||
if (!momentValue || !momentValue.isValid()) {
|
||||
return false
|
||||
}
|
||||
const candidate = momentValue.clone().seconds(0).milliseconds(0)
|
||||
const minMoment = this.getFieldMinMoment(field)
|
||||
if (candidate.isBefore(minMoment)) {
|
||||
return false
|
||||
}
|
||||
const latestMoment = this.getFieldLatestMoment(field)
|
||||
if (latestMoment && candidate.isAfter(latestMoment)) {
|
||||
return false
|
||||
}
|
||||
if (field === 'reserveEndTime' && this.formData.reserveStartTime) {
|
||||
const bounds = this.getContinuousEndBounds()
|
||||
if (!bounds) {
|
||||
return false
|
||||
}
|
||||
return candidate.isSameOrAfter(bounds.minMoment) && candidate.isSameOrBefore(bounds.maxMoment)
|
||||
}
|
||||
if (this.isDateTimeBlocked(candidate.format('YYYY-MM-DD HH:mm:ss'))) {
|
||||
return false
|
||||
}
|
||||
if (field === 'reserveStartTime' && this.formData.reserveEndTime) {
|
||||
const end = this.getNormalizedMoment(this.formData.reserveEndTime)
|
||||
if (!candidate.isBefore(end)) {
|
||||
return false
|
||||
}
|
||||
return this.isRangeSelectable(candidate, end)
|
||||
}
|
||||
return true
|
||||
},
|
||||
dayHasAvailableTime(year, month, day, field) {
|
||||
const cacheKey = ['day', field, year, month, day, this.formData.reserveStartTime || '', this.formData.reserveEndTime || ''].join('|')
|
||||
if (cacheKey in this.pickerFilterCache) {
|
||||
return this.pickerFilterCache[cacheKey]
|
||||
}
|
||||
const dayMoment = this.buildPickerMoment({ year: year, month: month, day: day, hour: 0, minute: 0 })
|
||||
if (!this.isValidCalendarMoment(dayMoment, month, day) || this.isBlockedDay(dayMoment)) {
|
||||
this.pickerFilterCache[cacheKey] = false
|
||||
return false
|
||||
}
|
||||
const minMoment = this.getFieldMinMoment(field)
|
||||
const maxMoment = this.getEffectiveFieldMaxMoment(field)
|
||||
const dayStart = dayMoment.clone().startOf('day')
|
||||
const dayEnd = dayMoment.clone().endOf('day')
|
||||
if (dayEnd.isBefore(minMoment) || dayStart.isAfter(maxMoment)) {
|
||||
this.pickerFilterCache[cacheKey] = false
|
||||
return false
|
||||
}
|
||||
if (field === 'reserveEndTime' && this.formData.reserveStartTime) {
|
||||
this.pickerFilterCache[cacheKey] = true
|
||||
return true
|
||||
}
|
||||
for (let hour = 0; hour < 24; hour++) {
|
||||
if (this.hourHasAvailableTime(year, month, day, hour, field)) {
|
||||
this.pickerFilterCache[cacheKey] = true
|
||||
return true
|
||||
}
|
||||
}
|
||||
this.pickerFilterCache[cacheKey] = false
|
||||
return false
|
||||
},
|
||||
hourHasAvailableTime(year, month, day, hour, field) {
|
||||
const cacheKey = ['hour', field, year, month, day, hour, this.formData.reserveStartTime || '', this.formData.reserveEndTime || ''].join('|')
|
||||
if (cacheKey in this.pickerFilterCache) {
|
||||
return this.pickerFilterCache[cacheKey]
|
||||
}
|
||||
const hourMoment = this.buildPickerMoment({ year: year, month: month, day: day, hour: hour, minute: 0 })
|
||||
if (!this.isValidCalendarMoment(hourMoment, month, day)) {
|
||||
this.pickerFilterCache[cacheKey] = false
|
||||
return false
|
||||
}
|
||||
const minMoment = this.getFieldMinMoment(field)
|
||||
const maxMoment = this.getEffectiveFieldMaxMoment(field)
|
||||
const hourStart = hourMoment.clone().startOf('hour')
|
||||
const hourEnd = hourMoment.clone().endOf('hour')
|
||||
if (hourEnd.isBefore(minMoment) || hourStart.isAfter(maxMoment)) {
|
||||
this.pickerFilterCache[cacheKey] = false
|
||||
return false
|
||||
}
|
||||
if (field === 'reserveEndTime' && this.formData.reserveStartTime) {
|
||||
this.pickerFilterCache[cacheKey] = true
|
||||
return true
|
||||
}
|
||||
for (let minute = 0; minute < 60; minute++) {
|
||||
const candidate = this.buildPickerMoment({ year: year, month: month, day: day, hour: hour, minute: minute })
|
||||
if (this.isExactTimeSelectable(candidate, field)) {
|
||||
this.pickerFilterCache[cacheKey] = true
|
||||
return true
|
||||
}
|
||||
}
|
||||
this.pickerFilterCache[cacheKey] = false
|
||||
return false
|
||||
},
|
||||
findFirstSelectableDateTime(field, baseMoment) {
|
||||
let startMoment = this.getNormalizedMoment(baseMoment)
|
||||
const minMoment = this.getFieldMinMoment(field)
|
||||
const maxMoment = this.getEffectiveFieldMaxMoment(field)
|
||||
if (maxMoment.isBefore(minMoment)) {
|
||||
return null
|
||||
}
|
||||
if (startMoment.isBefore(minMoment)) {
|
||||
startMoment = minMoment.clone()
|
||||
}
|
||||
for (let dayOffset = 0; dayOffset <= 366; dayOffset++) {
|
||||
const dayMoment = startMoment.clone().startOf('day').add(dayOffset, 'day')
|
||||
if (dayMoment.isAfter(maxMoment, 'day')) {
|
||||
break
|
||||
}
|
||||
if (this.isBlockedDay(dayMoment)) {
|
||||
continue
|
||||
}
|
||||
const startHour = dayMoment.isSame(startMoment, 'day') ? startMoment.hour() : 0
|
||||
for (let hour = startHour; hour < 24; hour++) {
|
||||
const startMinute = dayMoment.isSame(startMoment, 'day') && hour === startMoment.hour() ? startMoment.minute() : 0
|
||||
for (let minute = startMinute; minute < 60; minute++) {
|
||||
const candidate = dayMoment.clone().hour(hour).minute(minute).second(0).millisecond(0)
|
||||
if (candidate.isAfter(maxMoment)) {
|
||||
return null
|
||||
}
|
||||
if (this.isExactTimeSelectable(candidate, field)) {
|
||||
return candidate
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
},
|
||||
formatPickerNumber(value) {
|
||||
return value < 10 ? '0' + value : '' + value
|
||||
},
|
||||
getWeekdayText(momentValue) {
|
||||
const weekdayList = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
|
||||
return weekdayList[momentValue.day()]
|
||||
},
|
||||
createPickerOption(text, value, disabled) {
|
||||
return {
|
||||
text: text,
|
||||
value: value,
|
||||
disabled: !!disabled,
|
||||
}
|
||||
},
|
||||
findNearestEnabledIndex(options, preferredValue) {
|
||||
if (!Array.isArray(options) || !options.length) {
|
||||
return -1
|
||||
}
|
||||
const enabledIndexes = []
|
||||
options.forEach((item, index) => {
|
||||
if (!item.disabled) {
|
||||
enabledIndexes.push(index)
|
||||
}
|
||||
})
|
||||
if (!enabledIndexes.length) {
|
||||
return -1
|
||||
}
|
||||
if (preferredValue === '' || preferredValue === null || typeof preferredValue === 'undefined' || Number.isNaN(preferredValue)) {
|
||||
return enabledIndexes[0]
|
||||
}
|
||||
let targetIndex = enabledIndexes[0]
|
||||
let targetDistance = Math.abs(Number(options[targetIndex].value) - Number(preferredValue))
|
||||
enabledIndexes.forEach(index => {
|
||||
const distance = Math.abs(Number(options[index].value) - Number(preferredValue))
|
||||
if (distance < targetDistance) {
|
||||
targetIndex = index
|
||||
targetDistance = distance
|
||||
}
|
||||
})
|
||||
return targetIndex
|
||||
},
|
||||
buildDateOptions(field) {
|
||||
const minMoment = this.getFieldMinMoment(field).clone().startOf('day')
|
||||
const maxMoment = this.getEffectiveFieldMaxMoment(field).clone().startOf('day')
|
||||
const options = []
|
||||
const cursor = minMoment.clone()
|
||||
while (cursor.isSameOrBefore(maxMoment, 'day')) {
|
||||
const text = cursor.format('MM-DD') + ' ' + this.getWeekdayText(cursor)
|
||||
options.push(this.createPickerOption(text, cursor.format('YYYY-MM-DD'), !this.dayHasAvailableTime(cursor.year(), cursor.month() + 1, cursor.date(), field)))
|
||||
cursor.add(1, 'day')
|
||||
}
|
||||
return options
|
||||
},
|
||||
buildHourOptionsByDate(field, dateValue) {
|
||||
const dateMoment = this.$moment(dateValue, 'YYYY-MM-DD')
|
||||
const year = dateMoment.year()
|
||||
const month = dateMoment.month() + 1
|
||||
const day = dateMoment.date()
|
||||
const options = []
|
||||
for (let hour = 0; hour < 24; hour++) {
|
||||
options.push(this.createPickerOption(this.formatPickerNumber(hour) + '时', hour, !this.hourHasAvailableTime(year, month, day, hour, field)))
|
||||
}
|
||||
return options
|
||||
},
|
||||
buildMinuteOptionsByDateHour(field, dateValue, hour) {
|
||||
const dateMoment = this.$moment(dateValue, 'YYYY-MM-DD')
|
||||
const options = []
|
||||
for (let minute = 0; minute < 60; minute++) {
|
||||
const candidate = this.buildPickerMoment({
|
||||
year: dateMoment.year(),
|
||||
month: dateMoment.month() + 1,
|
||||
day: dateMoment.date(),
|
||||
hour: hour,
|
||||
minute: minute,
|
||||
})
|
||||
options.push(this.createPickerOption(this.formatPickerNumber(minute) + '分', minute, !this.isExactTimeSelectable(candidate, field)))
|
||||
}
|
||||
return options
|
||||
},
|
||||
buildTimePickerColumns(field, preferredParts) {
|
||||
const dateOptions = this.buildDateOptions(field)
|
||||
const enabledDateIndex = dateOptions.findIndex(item => !item.disabled)
|
||||
if (enabledDateIndex < 0) {
|
||||
return null
|
||||
}
|
||||
let dateIndex = enabledDateIndex
|
||||
if (preferredParts && preferredParts.date) {
|
||||
const exactIndex = dateOptions.findIndex(item => item.value === preferredParts.date && !item.disabled)
|
||||
if (exactIndex >= 0) {
|
||||
dateIndex = exactIndex
|
||||
}
|
||||
}
|
||||
const selectedDate = dateOptions[dateIndex].value
|
||||
|
||||
const hourOptions = this.buildHourOptionsByDate(field, selectedDate)
|
||||
const hourIndex = this.findNearestEnabledIndex(hourOptions, preferredParts ? preferredParts.hour : null)
|
||||
if (hourIndex < 0) {
|
||||
return null
|
||||
}
|
||||
const selectedHour = hourOptions[hourIndex].value
|
||||
|
||||
const minuteOptions = this.buildMinuteOptionsByDateHour(field, selectedDate, selectedHour)
|
||||
const minuteIndex = this.findNearestEnabledIndex(minuteOptions, preferredParts ? preferredParts.minute : null)
|
||||
if (minuteIndex < 0) {
|
||||
return null
|
||||
}
|
||||
const selectedMinute = minuteOptions[minuteIndex].value
|
||||
|
||||
return {
|
||||
parts: {
|
||||
date: selectedDate,
|
||||
hour: selectedHour,
|
||||
minute: selectedMinute,
|
||||
},
|
||||
indexes: [dateIndex, hourIndex, minuteIndex],
|
||||
columns: [
|
||||
{ values: dateOptions, defaultIndex: dateIndex },
|
||||
{ values: hourOptions, defaultIndex: hourIndex },
|
||||
{ values: minuteOptions, defaultIndex: minuteIndex },
|
||||
],
|
||||
}
|
||||
},
|
||||
sameTimePickerParts(left, right) {
|
||||
if (!left || !right) {
|
||||
return false
|
||||
}
|
||||
return left.date === right.date
|
||||
&& left.hour === right.hour
|
||||
&& left.minute === right.minute
|
||||
},
|
||||
syncTimePickerColumns(picker, built) {
|
||||
if (!picker || !built) {
|
||||
this.timePickerSyncing = false
|
||||
return
|
||||
}
|
||||
this.timePickerSyncing = true
|
||||
built.columns.forEach((column, index) => {
|
||||
picker.setColumnValues(index, column.values)
|
||||
})
|
||||
picker.setIndexes(built.indexes)
|
||||
this.timePickerParts = built.parts
|
||||
setTimeout(() => {
|
||||
this.timePickerSyncing = false
|
||||
}, 0)
|
||||
},
|
||||
applyTimePickerState(built, picker, syncColumns = true) {
|
||||
if (!built) {
|
||||
return false
|
||||
}
|
||||
const currentPicker = picker || this.$refs.timePickerRef
|
||||
if (syncColumns) {
|
||||
this.timePickerColumns = built.columns
|
||||
this.$nextTick(() => {
|
||||
this.syncTimePickerColumns(currentPicker || this.$refs.timePickerRef, built)
|
||||
})
|
||||
return true
|
||||
}
|
||||
this.syncTimePickerColumns(currentPicker, built)
|
||||
return true
|
||||
},
|
||||
async init() {
|
||||
if (!this.siteId) {
|
||||
this.$toast('未获取到场馆信息')
|
||||
this.historyBack()
|
||||
return
|
||||
}
|
||||
const siteRes = await this.$axios.post('/platform/siteCug/manage/info', { id: this.siteId })
|
||||
if (siteRes.code !== 0 || !siteRes.data) {
|
||||
this.$toast(siteRes.msg || '场馆信息加载失败')
|
||||
this.historyBack()
|
||||
return
|
||||
}
|
||||
this.row = siteRes.data
|
||||
this.formData = this.buildDefaultFormData()
|
||||
await this.queryTimeLimitConfig()
|
||||
this.siteLoaded = true
|
||||
},
|
||||
async queryTimeLimitConfig() {
|
||||
const fallback = {
|
||||
filterHolidays: !!this.row.filterHolidays,
|
||||
holidayList: [],
|
||||
notApplyTimeList: Array.isArray(this.row.notApplyTimeList) ? this.row.notApplyTimeList : [],
|
||||
}
|
||||
try {
|
||||
const res = await this.$axios.post('/platform/siteCug/apply/timeLimitConfig', {
|
||||
siteId: this.row.id,
|
||||
})
|
||||
if (res.code === 0 && res.data) {
|
||||
this.timeLimitConfig = {
|
||||
filterHolidays: !!res.data.filterHolidays,
|
||||
holidayList: Array.isArray(res.data.holidayList) ? res.data.holidayList : [],
|
||||
notApplyTimeList: Array.isArray(res.data.notApplyTimeList) ? res.data.notApplyTimeList : [],
|
||||
}
|
||||
this.clearTimePickerCache()
|
||||
return
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
this.timeLimitConfig = fallback
|
||||
this.clearTimePickerCache()
|
||||
},
|
||||
async reserveTypeChange(value) {
|
||||
const user = this.$store.state.user || {}
|
||||
if (value === 'union') {
|
||||
this.formData.applyUnionId = user.union ? user.union.id : ''
|
||||
this.formData.applyUnionName = user.union ? user.union.name : ''
|
||||
this.formData.clubId = ''
|
||||
this.formData.clubName = ''
|
||||
return
|
||||
}
|
||||
if (value === 'club') {
|
||||
this.formData.applyUnionId = ''
|
||||
this.formData.applyUnionName = ''
|
||||
this.formData.clubId = ''
|
||||
this.formData.clubName = ''
|
||||
await this.loadManagedClubs()
|
||||
}
|
||||
},
|
||||
async loadManagedClubs() {
|
||||
try {
|
||||
const res = await this.$axios.post('/platform/club/examine/apply/getClubsByRole')
|
||||
this.clubOptions = Array.isArray(res.data) ? res.data : []
|
||||
if (!this.clubOptions.length) {
|
||||
this.$toast('您当前没有可预约的协会管理权限')
|
||||
}
|
||||
} catch (e) {
|
||||
this.clubOptions = []
|
||||
this.$toast('协会列表加载失败,请稍后重试')
|
||||
}
|
||||
},
|
||||
onReserveTypeConfirm(value) {
|
||||
this.showReserveTypePicker = false
|
||||
const reserveType = value === '协会预约' ? 'club' : 'union'
|
||||
this.$set(this.formData, 'reserveType', reserveType)
|
||||
this.reserveTypeChange(reserveType)
|
||||
},
|
||||
async openClubPicker() {
|
||||
if (this.formData.reserveType !== 'club') {
|
||||
this.$toast('请先选择协会预约')
|
||||
return
|
||||
}
|
||||
if (!this.clubOptions.length) {
|
||||
await this.loadManagedClubs()
|
||||
}
|
||||
if (!this.clubOptions.length) {
|
||||
return
|
||||
}
|
||||
this.showClubPicker = true
|
||||
},
|
||||
onClubConfirm(value, index) {
|
||||
this.showClubPicker = false
|
||||
const club = this.clubOptions[index]
|
||||
this.formData.clubId = club ? club.id : ''
|
||||
this.formData.clubName = club ? club.clubName : value
|
||||
},
|
||||
openTimePicker(field) {
|
||||
this.timePickerField = field
|
||||
this.timePickerSyncing = false
|
||||
this.clearTimePickerCache()
|
||||
let defaultTime = this.formData[field] ? this.getNormalizedMoment(this.formData[field]) : null
|
||||
if (!defaultTime || !defaultTime.isValid()) {
|
||||
defaultTime = field === 'reserveEndTime' && this.formData.reserveStartTime
|
||||
? this.getNormalizedMoment(this.formData.reserveStartTime).add(1, 'hour')
|
||||
: this.$moment().add(1, 'hour').startOf('hour')
|
||||
}
|
||||
const availableTime = this.findFirstSelectableDateTime(field, defaultTime)
|
||||
if (!availableTime) {
|
||||
this.$toast('当前没有可预约的时间')
|
||||
return
|
||||
}
|
||||
const built = this.buildTimePickerColumns(field, this.extractTimePickerPartsFromMoment(availableTime))
|
||||
if (!built) {
|
||||
this.$toast('当前没有可预约的时间')
|
||||
return
|
||||
}
|
||||
this.showTimePicker = true
|
||||
this.applyTimePickerState(built, null, true)
|
||||
},
|
||||
onTimePickerChange(picker, values) {
|
||||
if (!this.timePickerField || this.timePickerSyncing) {
|
||||
return
|
||||
}
|
||||
const parts = this.extractTimePickerParts(values)
|
||||
const built = this.buildTimePickerColumns(this.timePickerField, parts)
|
||||
if (!built) {
|
||||
return
|
||||
}
|
||||
if (this.sameTimePickerParts(parts, built.parts)) {
|
||||
this.timePickerParts = built.parts
|
||||
return
|
||||
}
|
||||
this.applyTimePickerState(built, picker, false)
|
||||
},
|
||||
onTimeConfirm(values) {
|
||||
const parts = this.extractTimePickerParts(values)
|
||||
const candidate = this.buildPickerMoment(parts)
|
||||
if (!this.isExactTimeSelectable(candidate, this.timePickerField)) {
|
||||
this.$toast('该时间不可预约,请重新选择')
|
||||
const built = this.buildTimePickerColumns(this.timePickerField, parts)
|
||||
this.applyTimePickerState(built, this.$refs.timePickerRef)
|
||||
return
|
||||
}
|
||||
const formatted = candidate.format('YYYY-MM-DD HH:mm:ss')
|
||||
this.timePickerSyncing = false
|
||||
this.showTimePicker = false
|
||||
this.$set(this.formData, this.timePickerField, formatted)
|
||||
this.clearTimePickerCache()
|
||||
this.timeFieldChange(this.timePickerField)
|
||||
},
|
||||
async normalizeReserveTypeData() {
|
||||
const user = this.$store.state.user || {}
|
||||
if (this.formData.reserveType === 'union') {
|
||||
this.formData.applyUnionId = user.union ? user.union.id : ''
|
||||
this.formData.applyUnionName = user.union ? user.union.name : ''
|
||||
this.formData.clubId = ''
|
||||
this.formData.clubName = ''
|
||||
return true
|
||||
}
|
||||
if (this.formData.reserveType === 'club') {
|
||||
if (!this.clubOptions.length) {
|
||||
await this.loadManagedClubs()
|
||||
}
|
||||
const club = this.clubOptions.find(item => item.id === this.formData.clubId)
|
||||
this.formData.clubName = club ? club.clubName : ''
|
||||
this.formData.applyUnionId = ''
|
||||
this.formData.applyUnionName = ''
|
||||
return true
|
||||
}
|
||||
return false
|
||||
},
|
||||
normalizeTime(timeStr) {
|
||||
if (!timeStr) {
|
||||
return '00:00:00'
|
||||
}
|
||||
return timeStr.length === 5 ? timeStr + ':00' : timeStr
|
||||
},
|
||||
getDisabledRangesByDay(dayStr) {
|
||||
const list = Array.isArray(this.timeLimitConfig.notApplyTimeList) ? this.timeLimitConfig.notApplyTimeList : []
|
||||
return list
|
||||
.filter(item => item && item.date && this.$moment(item.date).format('YYYY-MM-DD') === dayStr)
|
||||
.sort((a, b) => this.normalizeTime(a.startTime).localeCompare(this.normalizeTime(b.startTime)))
|
||||
},
|
||||
isDateTimeBlocked(dateTimeStr) {
|
||||
if (!dateTimeStr) {
|
||||
return false
|
||||
}
|
||||
const target = this.$moment(dateTimeStr)
|
||||
const dayStr = target.format('YYYY-MM-DD')
|
||||
if (target.day() === 0 || target.day() === 6) {
|
||||
return true
|
||||
}
|
||||
if (this.timeLimitConfig.filterHolidays && this.timeLimitConfig.holidayList.includes(dayStr)) {
|
||||
return true
|
||||
}
|
||||
const disabledRanges = this.getDisabledRangesByDay(dayStr)
|
||||
return disabledRanges.some(item => {
|
||||
const start = this.$moment(dayStr + ' ' + this.normalizeTime(item.startTime))
|
||||
const end = this.$moment(dayStr + ' ' + this.normalizeTime(item.endTime))
|
||||
return target.isSameOrAfter(start) && target.isBefore(end)
|
||||
})
|
||||
},
|
||||
hasHolidayInRange(start, end) {
|
||||
const current = start.clone().startOf('day')
|
||||
const endDay = end.clone().startOf('day')
|
||||
while (current.isSameOrBefore(endDay)) {
|
||||
if (current.day() === 0 || current.day() === 6) {
|
||||
return true
|
||||
}
|
||||
if (this.timeLimitConfig.filterHolidays && this.timeLimitConfig.holidayList.includes(current.format('YYYY-MM-DD'))) {
|
||||
return true
|
||||
}
|
||||
current.add(1, 'day')
|
||||
}
|
||||
return false
|
||||
},
|
||||
overlapsDisabledRange(start, end) {
|
||||
const list = Array.isArray(this.timeLimitConfig.notApplyTimeList) ? this.timeLimitConfig.notApplyTimeList : []
|
||||
return list.some(item => {
|
||||
if (!item || !item.date || !item.startTime || !item.endTime) {
|
||||
return false
|
||||
}
|
||||
const rangeStart = this.$moment(this.$moment(item.date).format('YYYY-MM-DD') + ' ' + this.normalizeTime(item.startTime))
|
||||
const rangeEnd = this.$moment(this.$moment(item.date).format('YYYY-MM-DD') + ' ' + this.normalizeTime(item.endTime))
|
||||
return start.isBefore(rangeEnd) && end.isAfter(rangeStart)
|
||||
})
|
||||
},
|
||||
showSubmitError(message) {
|
||||
return this.$dialog.alert({
|
||||
title: '提示',
|
||||
message: message || '提交失败',
|
||||
}).catch(() => {})
|
||||
},
|
||||
validateTimeLimit(showMessage = true, useDialog = false) {
|
||||
const reserveStartTime = this.formData.reserveStartTime
|
||||
const reserveEndTime = this.formData.reserveEndTime
|
||||
if (!reserveStartTime || !reserveEndTime) {
|
||||
return true
|
||||
}
|
||||
const start = this.$moment(reserveStartTime)
|
||||
const end = this.$moment(reserveEndTime)
|
||||
const showError = (message) => {
|
||||
if (!showMessage) {
|
||||
return
|
||||
}
|
||||
if (useDialog) {
|
||||
this.showSubmitError(message)
|
||||
return
|
||||
}
|
||||
this.$toast(message)
|
||||
}
|
||||
if (this.isDateTimeBlocked(reserveStartTime) || this.isDateTimeBlocked(reserveEndTime)) {
|
||||
showError('预约时间不能选择周末、节假日或禁用时间')
|
||||
return false
|
||||
}
|
||||
if (this.hasHolidayInRange(start, end)) {
|
||||
showError('预约时间范围内包含周末或节假日,请重新选择')
|
||||
return false
|
||||
}
|
||||
if (this.overlapsDisabledRange(start, end)) {
|
||||
showError('预约时间范围与禁用时间冲突,请重新选择')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
timeFieldChange(field) {
|
||||
const value = this.formData[field]
|
||||
this.clearTimePickerCache()
|
||||
if (!value) {
|
||||
return
|
||||
}
|
||||
if (this.isDateTimeBlocked(value)) {
|
||||
this.$toast('该时间点不可预约,请重新选择')
|
||||
this.$set(this.formData, field, '')
|
||||
return
|
||||
}
|
||||
if (field === 'reserveStartTime' && this.formData.reserveEndTime) {
|
||||
const start = this.$moment(value)
|
||||
const end = this.$moment(this.formData.reserveEndTime)
|
||||
if (!end.isAfter(start)) {
|
||||
this.$set(this.formData, 'reserveEndTime', '')
|
||||
this.$toast('结束时间需晚于开始时间,请重新选择')
|
||||
return
|
||||
}
|
||||
}
|
||||
if (field === 'reserveEndTime' && this.formData.reserveStartTime) {
|
||||
const start = this.$moment(this.formData.reserveStartTime)
|
||||
const end = this.$moment(value)
|
||||
if (!end.isAfter(start)) {
|
||||
this.$toast('预约结束时间必须晚于开始时间')
|
||||
this.$set(this.formData, field, '')
|
||||
return
|
||||
}
|
||||
}
|
||||
if (this.formData.reserveStartTime && this.formData.reserveEndTime && !this.validateTimeLimit()) {
|
||||
this.$set(this.formData, field, '')
|
||||
}
|
||||
},
|
||||
onSubmit() {
|
||||
this.$refs.formRef.validate().then(async () => {
|
||||
if (!this.formData.reserveType) {
|
||||
await this.showSubmitError('请选择预约类型')
|
||||
return
|
||||
}
|
||||
await this.normalizeReserveTypeData()
|
||||
if (this.formData.reserveType === 'union' && !this.formData.applyUnionId) {
|
||||
await this.showSubmitError('当前用户未关联分工会,不能发起分工会预约')
|
||||
return
|
||||
}
|
||||
if (this.formData.reserveType === 'club' && !this.formData.clubId) {
|
||||
await this.showSubmitError('请选择您管理的协会')
|
||||
return
|
||||
}
|
||||
if (!this.formData.reserveStartTime || !this.formData.reserveEndTime) {
|
||||
await this.showSubmitError('请选择预约开始和结束时间')
|
||||
return
|
||||
}
|
||||
const start = this.$moment(this.formData.reserveStartTime)
|
||||
const end = this.$moment(this.formData.reserveEndTime)
|
||||
if (!start.isAfter(this.$moment())) {
|
||||
await this.showSubmitError('预约开始时间必须晚于当前时间')
|
||||
return
|
||||
}
|
||||
if (!end.isAfter(start)) {
|
||||
await this.showSubmitError('预约结束时间必须晚于开始时间')
|
||||
return
|
||||
}
|
||||
if (!this.validateTimeLimit(true, true)) {
|
||||
return
|
||||
}
|
||||
this.$dialog.confirm({
|
||||
title: '提示',
|
||||
message: '您确定要提交吗?',
|
||||
}).then(() => {
|
||||
const loading = this.$toast.loading({
|
||||
message: '提交中...',
|
||||
forbidClick: true,
|
||||
overlay: true,
|
||||
duration: 0,
|
||||
})
|
||||
this.$axios.post('/platform/siteCug/apply/submit', {
|
||||
data: JSON.stringify(this.formData),
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$toast.success(res.msg || '提交成功')
|
||||
this.$pjaxReplace('/platform/siteCug/apply/h5')
|
||||
}
|
||||
}).catch((err) => {
|
||||
this.showSubmitError((err && err.msg) || '提交失败')
|
||||
}).finally(() => {
|
||||
loading.close()
|
||||
})
|
||||
}).catch(() => {})
|
||||
}).catch(() => {})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,167 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<style scoped>
|
||||
.page-container {
|
||||
padding-bottom: 84px;
|
||||
background: #f7f8fa;
|
||||
min-height: calc(100vh - 46px);
|
||||
}
|
||||
|
||||
.footer-actions {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
padding: 10px 12px calc(env(safe-area-inset-bottom) + 10px);
|
||||
background: #ffffff;
|
||||
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.footer-actions .van-button {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.disabled-time-item {
|
||||
line-height: 20px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
/deep/ .direction-column-cell .van-cell__value {
|
||||
white-space: normal;
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar title="场馆申请" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
|
||||
|
||||
<div class="page-container" v-if="siteLoaded">
|
||||
<van-cell-group title="场馆信息">
|
||||
<van-cell title="场馆名称" :value="row.name || '-' "></van-cell>
|
||||
<van-cell title="场地地址" class="direction-column-cell">
|
||||
<template #default>
|
||||
{{ row.address || '-' }}
|
||||
</template>
|
||||
</van-cell>
|
||||
<van-cell title="联系人" :value="row.contactName || '-' "></van-cell>
|
||||
<van-cell title="联系电话" :value="row.contactPhone || '-' "></van-cell>
|
||||
<van-cell title="场地类型" :value="row.typeName || '-' "></van-cell>
|
||||
</van-cell-group>
|
||||
|
||||
<van-cell-group title="预约须知">
|
||||
<van-cell title="可预约日期" value="仅限工作日"></van-cell>
|
||||
<van-cell title="节假日限制"
|
||||
:value="timeLimitConfig.filterHolidays ? '节假日不可预约' : '不排除节假日'"></van-cell>
|
||||
<van-cell title="禁用时段" class="direction-column-cell">
|
||||
<template #default>
|
||||
<div v-if="timeLimitConfig.notApplyTimeList.length">
|
||||
<div
|
||||
class="disabled-time-item"
|
||||
v-for="(item, index) in timeLimitConfig.notApplyTimeList"
|
||||
:key="item.date + item.startTime + item.endTime + index">
|
||||
{{ item.date }} {{ item.startTime }} - {{ item.endTime }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>暂无禁用时段</div>
|
||||
</template>
|
||||
</van-cell>
|
||||
</van-cell-group>
|
||||
|
||||
<van-form ref="formRef" class="form-container" :show-error-message="false">
|
||||
<van-cell-group title="申请信息">
|
||||
<van-field v-model="formData.applyUserName" label="预约人" name="applyUserName" readonly
|
||||
:rules="[{ required: true, message: '请确认预约人' }]"></van-field>
|
||||
<van-field v-model="formData.applyLoginName" label="工号" name="applyLoginName" readonly
|
||||
:rules="[{ required: true, message: '请确认工号' }]"></van-field>
|
||||
<van-field v-model="formData.applyUnitName" label="所属单位" name="applyUnitName" readonly
|
||||
:rules="[{ required: true, message: '请确认所属单位' }]"></van-field>
|
||||
<van-field
|
||||
:value="reserveTypeText"
|
||||
label="预约类型"
|
||||
name="reserveType"
|
||||
readonly
|
||||
clickable
|
||||
is-link
|
||||
required
|
||||
placeholder="请选择预约类型"
|
||||
@click="showReserveTypePicker = true"
|
||||
:rules="[{ required: true, message: '请选择预约类型' }]">
|
||||
</van-field>
|
||||
<van-field
|
||||
v-if="formData.reserveType === 'union'"
|
||||
v-model="formData.applyUnionName"
|
||||
label="分工会"
|
||||
name="applyUnionName"
|
||||
readonly
|
||||
placeholder="自动读取当前登录人的分工会">
|
||||
</van-field>
|
||||
<van-field
|
||||
v-if="formData.reserveType === 'club'"
|
||||
v-model="formData.clubName"
|
||||
label="协会"
|
||||
name="clubName"
|
||||
readonly
|
||||
clickable
|
||||
is-link
|
||||
required
|
||||
placeholder="请选择您管理的协会"
|
||||
@click="openClubPicker"
|
||||
:rules="[{ required: true, message: '请选择您管理的协会' }]">
|
||||
</van-field>
|
||||
<van-field v-model="formData.applyMobile" label="联系电话" name="applyMobile" type="tel" maxlength="11"
|
||||
required placeholder="请输入联系电话"
|
||||
:rules="[{ required: true, message: '请输入联系电话' }]"></van-field>
|
||||
<van-field v-model="formData.reserveStartTime" label="开始时间" name="reserveStartTime" readonly
|
||||
clickable is-link required placeholder="请选择预约开始时间"
|
||||
@click="openTimePicker('reserveStartTime')"
|
||||
:rules="[{ required: true, message: '请选择预约开始时间' }]"></van-field>
|
||||
<van-field v-model="formData.reserveEndTime" label="结束时间" name="reserveEndTime" readonly clickable
|
||||
is-link required placeholder="请选择预约结束时间" @click="openTimePicker('reserveEndTime')"
|
||||
:rules="[{ required: true, message: '请选择预约结束时间' }]"></van-field>
|
||||
<van-field v-model="formData.applyCause" label="预约事由" name="applyCause" required rows="4" autosize
|
||||
type="textarea" maxlength="1000" show-word-limit placeholder="请输入预约事由"
|
||||
:rules="[{ required: true, message: '请输入预约事由' }]"></van-field>
|
||||
</van-cell-group>
|
||||
</van-form>
|
||||
</div>
|
||||
|
||||
<div class="footer-actions" v-if="siteLoaded">
|
||||
<van-button plain round type="info" @click="historyBack">取消</van-button>
|
||||
<van-button round type="primary" color="#246fb4" @click="onSubmit">提交预约</van-button>
|
||||
</div>
|
||||
|
||||
<van-popup v-model="showReserveTypePicker" position="bottom" round>
|
||||
<van-picker show-toolbar :columns="reserveTypeColumns" @confirm="onReserveTypeConfirm"
|
||||
@cancel="showReserveTypePicker = false"></van-picker>
|
||||
</van-popup>
|
||||
|
||||
<van-popup v-model="showClubPicker" position="bottom" round>
|
||||
<van-picker show-toolbar :columns="clubColumns" @confirm="onClubConfirm"
|
||||
@cancel="showClubPicker = false"></van-picker>
|
||||
</van-popup>
|
||||
|
||||
<van-popup v-model="showTimePicker" position="bottom" round>
|
||||
<van-picker
|
||||
ref="timePickerRef"
|
||||
show-toolbar
|
||||
value-key="text"
|
||||
:title="timePickerTitle"
|
||||
:columns="timePickerColumns"
|
||||
@change="onTimePickerChange"
|
||||
@confirm="onTimeConfirm"
|
||||
@cancel="timePickerSyncing = false; showTimePicker = false">
|
||||
</van-picker>
|
||||
</van-popup>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include('apply.js'){}#-->
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,106 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
|
||||
<div id="app">
|
||||
<van-nav-bar title="场馆预约" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
|
||||
|
||||
<van-sticky offset-top="46px">
|
||||
<van-search
|
||||
v-model="pageForm.searchKeyword"
|
||||
:show-action="false"
|
||||
:reverse-color="false"
|
||||
input-align="left"
|
||||
placeholder="请输入名称或地址搜索"
|
||||
@search="doSearch"
|
||||
></van-search>
|
||||
<van-dropdown-menu :close-on-click-outside="false" :close-on-click-overlay="false">
|
||||
<van-dropdown-item v-model="pageForm.type" :options="typeOptions" :multiple="false" @change="doSearch"></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
</van-sticky>
|
||||
|
||||
<table-list api="/platform/siteCug/apply/pageData" :page_form.sync="pageForm" ref="tableListRef" title="name" @ready="onReady">
|
||||
<template v-slot="{ row }">
|
||||
<table-column label="场地地址">{{ row.address }}</table-column>
|
||||
<table-column label="联系人">{{ row.contactName }}</table-column>
|
||||
<table-column label="联系方式">{{ row.contactPhone }}</table-column>
|
||||
<table-column label="场地类型">{{ row.typeName }}</table-column>
|
||||
</template>
|
||||
<template #actions="{ row }">
|
||||
<div class="action-btn" @click="onView(row)">
|
||||
<i class="fa fa-eye"></i>
|
||||
<span>查看</span>
|
||||
</div>
|
||||
<div class="action-btn" @click="onApply(row)">
|
||||
<i class="fa fa-edit"></i>
|
||||
<span>预约</span>
|
||||
</div>
|
||||
</template>
|
||||
</table-list>
|
||||
|
||||
<info ref="infoRef"></info>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include('../common/siteInfo.js'){}#-->
|
||||
new Vue({
|
||||
el: '#app',
|
||||
store,
|
||||
components: {
|
||||
info: siteInfo,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
searchKeyword: '',
|
||||
type: null,
|
||||
},
|
||||
typeOptions: [],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
historyBack,
|
||||
onView(row) {
|
||||
this.$refs.infoRef.onOpen(row)
|
||||
},
|
||||
onApply(row) {
|
||||
this.$pjaxReplace('/platform/siteCug/apply/form/h5?siteId=' + row.id)
|
||||
},
|
||||
async onReady() {
|
||||
const typeList = await this.querySiteType()
|
||||
this.typeOptions = [
|
||||
{
|
||||
text: '全部类型',
|
||||
value: null,
|
||||
}
|
||||
].concat(typeList.map((item) => ({ text: item.name, value: item.id })))
|
||||
if (this.typeOptions.length > 0) {
|
||||
this.pageForm.type = this.typeOptions[0].value
|
||||
this.doSearch()
|
||||
}
|
||||
},
|
||||
async querySiteType() {
|
||||
const res = await this.$axios.post('/platform/siteCug/function/type/queryFunctionType')
|
||||
return Array.isArray(res.data) ? res.data : []
|
||||
},
|
||||
doSearch() {
|
||||
this.$nextTick(() => {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageForm.totalCount = 0
|
||||
this.$refs.tableListRef.doSearch()
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,80 @@
|
||||
const siteCugApplyInfoH5 = {
|
||||
template:
|
||||
/*language=HTML*/
|
||||
`
|
||||
<van-action-sheet v-model="visible" :title="sheetTitle">
|
||||
<div class="detail-container">
|
||||
<van-cell-group title="基本信息">
|
||||
<van-cell title="预约场地">{{ viewData.siteName }}</van-cell>
|
||||
<van-cell title="预约人">{{ viewData.applyUserName }}</van-cell>
|
||||
<van-cell title="预约人工号">{{ viewData.applyLoginName }}</van-cell>
|
||||
<van-cell title="所属单位">{{ viewData.applyUnitName }}</van-cell>
|
||||
<van-cell title="预约类型">{{ reserveTypeLabel }}</van-cell>
|
||||
<van-cell title="预约主体">{{ reserveTargetName }}</van-cell>
|
||||
<van-cell title="开始时间">{{ viewData.reserveStartTime }}</van-cell>
|
||||
<van-cell title="结束时间">{{ viewData.reserveEndTime }}</van-cell>
|
||||
<van-cell title="联系电话">{{ viewData.applyMobile }}</van-cell>
|
||||
<van-cell title="预约事由" class="direction-column-cell">{{ viewData.applyCause }}</van-cell>
|
||||
</van-cell-group>
|
||||
<template v-for="task in doneTasks">
|
||||
<van-cell-group :title="task.displayName" v-if="task.ext.isFirstTaskNode" :key="task.id + '-first'">
|
||||
<van-cell title="申请用户">{{ task.ext.initiatorName }}({{task.ext.initiatorAccount}})</van-cell>
|
||||
<van-cell title="申请时间">{{ task.finishTime }}</van-cell>
|
||||
<van-cell title="办理结果">
|
||||
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE" :value="task.ext.submitType"></dict-tag>
|
||||
</van-cell>
|
||||
</van-cell-group>
|
||||
<van-cell-group :title="task.displayName" v-else :key="task.id + '-done'">
|
||||
<van-cell title="办理用户">{{ task.taskFormData.userName }}({{task.taskFormData.loginName}})</van-cell>
|
||||
<van-cell title="办理时间">{{ task.finishTime }}</van-cell>
|
||||
<van-cell title="办理结果">
|
||||
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE" :value="task.ext.submitType"></dict-tag>
|
||||
</van-cell>
|
||||
<van-cell title="办理意见" class="direction-column-cell">
|
||||
<div v-html="task.taskFormData.opinion || task.taskFormData.tf_opinion || '-' "></div>
|
||||
</van-cell>
|
||||
</van-cell-group>
|
||||
</template>
|
||||
</div>
|
||||
<slot></slot>
|
||||
</van-action-sheet>
|
||||
`,
|
||||
dicts: ['PROCESS_TASK_SUBMIT_TYPE'],
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
viewData: {},
|
||||
doneTasks: [],
|
||||
row: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
reserveTypeLabel() {
|
||||
return this.viewData.reserveType === 'club' ? '协会预约' : '分工会预约'
|
||||
},
|
||||
reserveTargetName() {
|
||||
return this.viewData.reserveType === 'club' ? (this.viewData.clubName || '-') : (this.viewData.applyUnionName || '-')
|
||||
},
|
||||
sheetTitle() {
|
||||
return this.visible && this.$slots.default ? '审核预约' : '预约详情'
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onOpen(row) {
|
||||
this.row = row
|
||||
this.visible = true
|
||||
this.viewData = row
|
||||
this.getDoneTasks()
|
||||
},
|
||||
onClose() {
|
||||
this.visible = false
|
||||
},
|
||||
getDoneTasks() {
|
||||
this.$axios.post('/flow/common/doneTasks', { bizId: this.row.id }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.doneTasks = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,105 @@
|
||||
const siteInfo = {
|
||||
template: /*language=HTML*/ `
|
||||
<div>
|
||||
<van-action-sheet v-model="visible" title="场馆信息">
|
||||
<div class="detail-container">
|
||||
<van-cell-group title="基本信息">
|
||||
<van-cell title="创建人" :value="viewData.createUserName || '-' "></van-cell>
|
||||
<van-cell title="场馆名称" :value="viewData.name || '-' "></van-cell>
|
||||
<van-cell title="场地地址" class="direction-column-cell">
|
||||
<template #default>
|
||||
{{ viewData.address || '-' }}
|
||||
</template>
|
||||
</van-cell>
|
||||
<van-cell title="联系人" :value="viewData.contactName || '-' "></van-cell>
|
||||
<van-cell title="联系电话" :value="viewData.contactPhone || '-' "></van-cell>
|
||||
<van-cell title="排序编号" :value="viewData.sortNum || '-' "></van-cell>
|
||||
<van-cell title="容纳人数" :value="viewData.maxNum || '-' "></van-cell>
|
||||
<van-cell title="场地类型" :value="viewData.typeName || '-' "></van-cell>
|
||||
<van-cell title="性别限制">
|
||||
<template #default>
|
||||
<span v-if="viewData.sexLimit === 1">男</span>
|
||||
<span v-else-if="viewData.sexLimit === 2">女</span>
|
||||
<span v-else>不限制</span>
|
||||
</template>
|
||||
</van-cell>
|
||||
<van-cell title="开启状态">
|
||||
<template #default>
|
||||
<span v-if="viewData.state">开启</span>
|
||||
<span v-else>禁用</span>
|
||||
</template>
|
||||
</van-cell>
|
||||
<van-cell title="排除节假日">
|
||||
<template #default>
|
||||
<span v-if="viewData.filterHolidays">是</span>
|
||||
<span v-else>否</span>
|
||||
</template>
|
||||
</van-cell>
|
||||
<van-cell title="场地介绍" class="direction-column-cell">
|
||||
<template #default>
|
||||
<div v-if="viewData.introduce" v-html="viewData.introduce"></div>
|
||||
<div v-else>暂无场地介绍</div>
|
||||
</template>
|
||||
</van-cell>
|
||||
</van-cell-group>
|
||||
<van-cell-group title="禁用时间" v-if="viewData.notApplyTimeList && viewData.notApplyTimeList.length > 0">
|
||||
<table class="table-class">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>日期</th>
|
||||
<th>开始时间</th>
|
||||
<th>结束时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(item, index) in viewData.notApplyTimeList" :key="item.date + item.startTime + item.endTime + index">
|
||||
<td>{{ item.date }}</td>
|
||||
<td>{{ item.startTime }}</td>
|
||||
<td>{{ item.endTime }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</van-cell-group>
|
||||
</div>
|
||||
</van-action-sheet>
|
||||
</div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
viewData: {},
|
||||
visible: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onOpen(row) {
|
||||
this.viewData = row
|
||||
this.visible = true
|
||||
},
|
||||
},
|
||||
style: /*language=CSS*/ `
|
||||
/deep/ .direction-column-cell .van-cell__value {
|
||||
white-space: normal;
|
||||
text-align: left;
|
||||
}
|
||||
/deep/ .table-class {
|
||||
width: 100%;
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
line-height: 1.5rem;
|
||||
font-size: 13px;
|
||||
table-layout: fixed;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
/deep/ .table-class th {
|
||||
background-color: #f2f2f2;
|
||||
border: 1px solid #dddddd;
|
||||
}
|
||||
/deep/ .table-class tr {
|
||||
text-align: center;
|
||||
border-bottom: 1px solid #dddddd;
|
||||
}
|
||||
/deep/ .table-class td {
|
||||
border: 1px solid #dddddd;
|
||||
}
|
||||
`
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar title="我的预约" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
|
||||
|
||||
<van-sticky offset-top="46px">
|
||||
<van-dropdown-menu :close-on-click-outside="false" :close-on-click-overlay="false">
|
||||
<van-dropdown-item v-model="pageForm.siteType" :options="typeOptions" :multiple="false" @change="doSearch"></van-dropdown-item>
|
||||
<van-dropdown-item v-model="pageForm.siteId" :options="siteOptions" :multiple="false" @change="doSearch"></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
</van-sticky>
|
||||
|
||||
<table-list api="/platform/siteCug/mine/pageData" :page_form.sync="pageForm" ref="tableListRef" title="siteName" @ready="onReady">
|
||||
<template v-slot="{index,row}">
|
||||
<table-column label="场地名称">{{row.siteName}}</table-column>
|
||||
<table-column label="预约类型">{{row.reserveType === 'club' ? '协会预约' : '分工会预约'}}</table-column>
|
||||
<table-column label="预约主体">{{row.reserveType === 'club' ? (row.clubName || '-') : (row.applyUnionName || '-')}}</table-column>
|
||||
<table-column label="所属单位">{{row.applyUnitName}}</table-column>
|
||||
<table-column label="开始时间">{{row.reserveStartTime}}</table-column>
|
||||
<table-column label="结束时间">{{row.reserveEndTime}}</table-column>
|
||||
<table-column label="当前节点">{{row.taskName || '-'}}</table-column>
|
||||
</template>
|
||||
<template #actions="{index,row}">
|
||||
<div class="action-btn" @click="onView(row)">
|
||||
<i class="fa fa-eye"></i>
|
||||
<span>查看</span>
|
||||
</div>
|
||||
<div class="action-btn delete" @click="onDelete(row)" v-if="row.canCancel">
|
||||
<i class="fa fa-trash"></i>
|
||||
<span>取消预约</span>
|
||||
</div>
|
||||
</template>
|
||||
</table-list>
|
||||
|
||||
<info ref="infoRef"></info>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include('../common/applyInfo.js'){}#-->
|
||||
new Vue({
|
||||
el: '#app',
|
||||
store,
|
||||
components: {
|
||||
info: siteCugApplyInfoH5,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
siteType: null,
|
||||
siteId: null,
|
||||
},
|
||||
typeOptions: [
|
||||
{
|
||||
text: '全部类型',
|
||||
value: null,
|
||||
}
|
||||
],
|
||||
siteOptions: [
|
||||
{
|
||||
text: '全部场地',
|
||||
value: null,
|
||||
}
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
historyBack,
|
||||
async onReady() {
|
||||
await this.querySiteType()
|
||||
await this.querySites()
|
||||
this.doSearch()
|
||||
},
|
||||
onView(row) {
|
||||
this.$refs.infoRef.onOpen(row)
|
||||
},
|
||||
onDelete(row) {
|
||||
this.$dialog.confirm({
|
||||
title: '提示',
|
||||
message: row.yearlyBatch
|
||||
? ('该记录属于“预约本年”批量预约,确认后将一并删除同批次的 ' + (row.batchDeleteCount || 0) + ' 条预约记录,是否继续?')
|
||||
: '您确定要取消该预约吗?',
|
||||
}).then(() => {
|
||||
this.$axios.post('/platform/siteCug/mine/delete', { id: row.id }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$toast.success(res.msg || '取消成功')
|
||||
this.doSearch()
|
||||
} else {
|
||||
this.$dialog.alert({
|
||||
title: '提示',
|
||||
message: res.msg || '取消失败',
|
||||
}).catch(() => {})
|
||||
}
|
||||
}).catch((err) => {
|
||||
this.$dialog.alert({
|
||||
title: '提示',
|
||||
message: (err && err.msg) || '取消失败',
|
||||
}).catch(() => {})
|
||||
})
|
||||
}).catch(() => {})
|
||||
},
|
||||
querySiteType() {
|
||||
return this.$axios.post('/platform/siteCug/function/type/queryFunctionType').then((res) => {
|
||||
const list = Array.isArray(res.data) ? res.data : []
|
||||
this.typeOptions = [
|
||||
{
|
||||
text: '全部类型',
|
||||
value: null,
|
||||
}
|
||||
].concat(list.map((item) => ({
|
||||
text: item.name,
|
||||
value: item.id,
|
||||
})))
|
||||
})
|
||||
},
|
||||
querySites() {
|
||||
return this.$axios.post('/platform/siteCug/manage/querySites').then((res) => {
|
||||
const list = Array.isArray(res.data) ? res.data : []
|
||||
this.siteOptions = [
|
||||
{
|
||||
text: '全部场地',
|
||||
value: null,
|
||||
}
|
||||
].concat(list.map((item) => ({
|
||||
text: item.name,
|
||||
value: item.id,
|
||||
})))
|
||||
})
|
||||
},
|
||||
doSearch() {
|
||||
this.$nextTick(() => {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageForm.totalCount = 0
|
||||
this.$refs.tableListRef.doSearch()
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+272
@@ -0,0 +1,272 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<style scoped>
|
||||
.action-btn.disabled {
|
||||
opacity: 0.45;
|
||||
pointer-events: none;
|
||||
}
|
||||
.action-btn.loading {
|
||||
opacity: 0.9;
|
||||
}
|
||||
.action-btn .van-loading {
|
||||
margin-right: 4px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar title="校工会审核" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
|
||||
|
||||
<van-sticky offset-top="46px">
|
||||
<van-search
|
||||
v-model="pageForm.searchKeyword"
|
||||
:show-action="false"
|
||||
:reverse-color="false"
|
||||
input-align="left"
|
||||
placeholder="请输入姓名/工号/场地搜索"
|
||||
@search="doSearch"
|
||||
></van-search>
|
||||
<van-dropdown-menu :close-on-click-outside="false" :close-on-click-overlay="false">
|
||||
<van-dropdown-item v-model="pageForm.siteType" :options="typeOptions" :multiple="false" @change="doSearch"></van-dropdown-item>
|
||||
<van-dropdown-item v-model="pageForm.siteId" :options="siteOptions" :multiple="false" @change="doSearch"></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
<van-tabs v-model="pageForm.approvalText" @change="onApprovalTabChange">
|
||||
<van-tab title="已审核" name="1"></van-tab>
|
||||
<van-tab title="未审核" name="0"></van-tab>
|
||||
</van-tabs>
|
||||
</van-sticky>
|
||||
|
||||
<table-list api="/platform/siteCug/schoolUnionAudit/pageData" :page_form.sync="pageForm" ref="tableListRef" title="applyUserName" @ready="onReady">
|
||||
<template v-slot="{index,row}">
|
||||
<table-column label="场地名称">{{row.siteName}}</table-column>
|
||||
<table-column label="预约类型">{{row.reserveType === 'club' ? '协会预约' : '分工会预约'}}</table-column>
|
||||
<table-column label="预约主体">{{row.reserveType === 'club' ? (row.clubName || '-') : (row.applyUnionName || '-')}}</table-column>
|
||||
<table-column label="所属单位">{{row.applyUnitName}}</table-column>
|
||||
<table-column label="开始时间">{{row.reserveStartTime}}</table-column>
|
||||
<table-column label="结束时间">{{row.reserveEndTime}}</table-column>
|
||||
<table-column label="当前节点">{{row.curTaskName || '-'}}</table-column>
|
||||
</template>
|
||||
<template #actions="{index,row}">
|
||||
<div class="action-btn" @click="onView(row)">
|
||||
<i class="fa fa-eye"></i>
|
||||
<span>查看</span>
|
||||
</div>
|
||||
<div class="action-btn" v-if="row.taskState === 10" @click="onAudit(row)">
|
||||
<i class="fa fa-edit"></i>
|
||||
<span>审核</span>
|
||||
</div>
|
||||
<div class="action-btn delete" v-if="canRevoke(row)" :class="{ loading: revokeLoading }" @click="onRevoke(row)">
|
||||
<van-loading v-if="revokeLoading" size="14px" color="#fff"></van-loading>
|
||||
<i v-else class="fa fa-reply"></i>
|
||||
<span>撤回</span>
|
||||
</div>
|
||||
</template>
|
||||
</table-list>
|
||||
|
||||
<info ref="infoRef">
|
||||
<div v-if="showApprovalForm">
|
||||
<div class="process-title">{{formData.taskName}}</div>
|
||||
<van-form ref="formRef">
|
||||
<van-field
|
||||
v-model="formData.tf_opinion"
|
||||
name="tf_opinion"
|
||||
label="审批意见"
|
||||
placeholder="请输入审批意见"
|
||||
:rules="[{ required: true, message: '请填写审批意见' }]"
|
||||
required
|
||||
maxlength="100"
|
||||
show-word-limit
|
||||
></van-field>
|
||||
</van-form>
|
||||
<div style="display:flex;justify-content:space-between;column-gap:10px;padding:10px;">
|
||||
<van-button type="info" block :loading="auditLoading" :disabled="auditLoading" @click="handleTaskAction(6)">退回</van-button>
|
||||
<van-button type="danger" block :loading="auditLoading" :disabled="auditLoading" @click="handleTaskAction(2)">不同意</van-button>
|
||||
<van-button type="primary" block :loading="auditLoading" :disabled="auditLoading" @click="handleTaskAction(1)">同意</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</info>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include('../common/applyInfo.js'){}#-->
|
||||
new Vue({
|
||||
el: '#app',
|
||||
store,
|
||||
components: {
|
||||
info: siteCugApplyInfoH5,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
searchKeyword: '',
|
||||
approvalText: '0',
|
||||
approval: false,
|
||||
siteType: null,
|
||||
siteId: null,
|
||||
},
|
||||
typeOptions: [
|
||||
{
|
||||
text: '全部类型',
|
||||
value: null,
|
||||
}
|
||||
],
|
||||
siteOptions: [
|
||||
{
|
||||
text: '全部场地',
|
||||
value: null,
|
||||
}
|
||||
],
|
||||
formData: {},
|
||||
showApprovalForm: false,
|
||||
auditLoading: false,
|
||||
revokeLoading: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
historyBack,
|
||||
async onReady() {
|
||||
await this.querySiteType()
|
||||
await this.querySites()
|
||||
this.doSearch()
|
||||
},
|
||||
onApprovalTabChange(val) {
|
||||
this.pageForm.approval = val === '1'
|
||||
this.doSearch()
|
||||
},
|
||||
canRevoke(row) {
|
||||
return Number(row.instanceState) === 20
|
||||
},
|
||||
onView(row) {
|
||||
this.showApprovalForm = false
|
||||
this.$refs.infoRef.onOpen(row)
|
||||
},
|
||||
onAudit(row) {
|
||||
this.showApprovalForm = true
|
||||
this.formData = {
|
||||
processTaskId: row.taskId,
|
||||
applyId: row.id,
|
||||
taskName: row.curTaskName,
|
||||
tf_opinion: '',
|
||||
yearlyBatch: row.yearlyBatch,
|
||||
batchAuditCount: row.batchAuditCount,
|
||||
}
|
||||
this.$refs.infoRef.onOpen(row)
|
||||
},
|
||||
async handleTaskAction(submitType) {
|
||||
if (this.auditLoading) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
await this.$refs.formRef.validate()
|
||||
this.$dialog.confirm({
|
||||
title: '提示',
|
||||
message: this.formData.yearlyBatch
|
||||
? ('该记录属于“预约本年”批量预约,提交后将一并审核同批次的 ' + (this.formData.batchAuditCount || 0) + ' 条预约记录,是否继续?')
|
||||
: '您确定要提交吗?',
|
||||
}).then(() => {
|
||||
this.auditLoading = true
|
||||
this.$axios.post('/platform/siteCug/schoolUnionAudit/executeTask', {
|
||||
data: JSON.stringify({
|
||||
...this.formData,
|
||||
submitType: submitType,
|
||||
})
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$refs.infoRef.onClose()
|
||||
this.$toast.success(res.msg || '提交成功')
|
||||
this.doSearch()
|
||||
} else {
|
||||
this.$dialog.alert({
|
||||
title: '提示',
|
||||
message: res.msg || '提交失败',
|
||||
}).catch(() => {})
|
||||
}
|
||||
}).catch((err) => {
|
||||
this.$dialog.alert({
|
||||
title: '提示',
|
||||
message: (err && err.msg) || '提交失败',
|
||||
}).catch(() => {})
|
||||
}).finally(() => {
|
||||
this.auditLoading = false
|
||||
})
|
||||
}).catch(() => {})
|
||||
} catch (e) {
|
||||
}
|
||||
},
|
||||
onRevoke(row) {
|
||||
if (!this.canRevoke(row) || this.revokeLoading) {
|
||||
return
|
||||
}
|
||||
this.$dialog.confirm({
|
||||
title: '提示',
|
||||
message: row.yearlyBatch
|
||||
? ('该记录属于“预约本年”批量预约,撤回后将一并撤回同批次的 ' + (row.batchAuditCount || 0) + ' 条审核任务,是否继续?')
|
||||
: '您确定要撤回吗?',
|
||||
}).then(() => {
|
||||
this.revokeLoading = true
|
||||
this.$axios.post('/platform/siteCug/schoolUnionAudit/revokeTask', { taskId: row.taskId, applyId: row.id }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$toast.success(res.msg || '撤回成功')
|
||||
this.doSearch()
|
||||
} else {
|
||||
this.$dialog.alert({
|
||||
title: '提示',
|
||||
message: res.msg || '撤回失败',
|
||||
}).catch(() => {})
|
||||
}
|
||||
}).catch((err) => {
|
||||
this.$dialog.alert({
|
||||
title: '提示',
|
||||
message: (err && err.msg) || '撤回失败',
|
||||
}).catch(() => {})
|
||||
}).finally(() => {
|
||||
this.revokeLoading = false
|
||||
})
|
||||
}).catch(() => {})
|
||||
},
|
||||
querySiteType() {
|
||||
return this.$axios.post('/platform/siteCug/function/type/queryFunctionType').then((res) => {
|
||||
const list = Array.isArray(res.data) ? res.data : []
|
||||
this.typeOptions = [
|
||||
{
|
||||
text: '全部类型',
|
||||
value: null,
|
||||
}
|
||||
].concat(list.map((item) => ({
|
||||
text: item.name,
|
||||
value: item.id,
|
||||
})))
|
||||
})
|
||||
},
|
||||
querySites() {
|
||||
return this.$axios.post('/platform/siteCug/manage/querySites').then((res) => {
|
||||
const list = Array.isArray(res.data) ? res.data : []
|
||||
this.siteOptions = [
|
||||
{
|
||||
text: '全部场地',
|
||||
value: null,
|
||||
}
|
||||
].concat(list.map((item) => ({
|
||||
text: item.name,
|
||||
value: item.id,
|
||||
})))
|
||||
})
|
||||
},
|
||||
doSearch() {
|
||||
this.$nextTick(() => {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageForm.totalCount = 0
|
||||
this.$refs.tableListRef.doSearch()
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
Reference in New Issue
Block a user