Compare commits

...

3 Commits

18 changed files with 1056 additions and 0 deletions

View File

@@ -5,12 +5,15 @@ import java.util.List;
import com.ruoyi.cms.domain.OutdoorFair;
import com.ruoyi.cms.domain.OutdoorFairDictDataRequest;
import com.ruoyi.cms.domain.VenueInfo;
import com.ruoyi.cms.service.IOutdoorFairService;
import com.ruoyi.cms.service.IVenueInfoService;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.exception.ServiceException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
@@ -39,6 +42,9 @@ public class OutdoorFairController extends BaseController
@Autowired
private IOutdoorFairService outdoorFairService;
@Autowired
private IVenueInfoService venueInfoService;
/**
* 查询户外招聘会列表
*/
@@ -72,6 +78,7 @@ public class OutdoorFairController extends BaseController
@PostMapping
public AjaxResult add(@RequestBody OutdoorFair outdoorFair)
{
fillVenueFields(outdoorFair);
return toAjax(outdoorFairService.save(outdoorFair));
}
@@ -84,6 +91,7 @@ public class OutdoorFairController extends BaseController
@PutMapping
public AjaxResult edit(@RequestBody OutdoorFair outdoorFair)
{
fillVenueFields(outdoorFair);
return toAjax(outdoorFairService.updateById(outdoorFair));
}
@@ -110,4 +118,17 @@ public class OutdoorFairController extends BaseController
{
return toAjax(outdoorFairService.insertOutdoorFairDictData(request.getDictType(), request.getDictLabel(), getUsername()));
}
private void fillVenueFields(OutdoorFair outdoorFair)
{
if (outdoorFair.getVenueId() == null) {
return;
}
VenueInfo venueInfo = venueInfoService.getById(outdoorFair.getVenueId());
if (venueInfo == null) {
throw new ServiceException("绑定场地不存在");
}
outdoorFair.setVenueName(venueInfo.getVenueName());
outdoorFair.setBoothCount(venueInfo.getFloorCount() == null ? 0 : venueInfo.getFloorCount());
}
}

View File

@@ -0,0 +1,325 @@
package com.ruoyi.cms.controller.cms;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.cms.domain.VenueInfo;
import com.ruoyi.cms.domain.OutdoorFair;
import com.ruoyi.cms.domain.OutdoorFairBoothBooking;
import com.ruoyi.cms.domain.VenueBooth;
import com.ruoyi.cms.domain.VenueInfoDictDataRequest;
import com.ruoyi.cms.domain.VenueBoothSwapRequest;
import com.ruoyi.cms.mapper.CompanyMapper;
import com.ruoyi.cms.mapper.OutdoorFairBoothBookingMapper;
import com.ruoyi.cms.mapper.OutdoorFairMapper;
import com.ruoyi.cms.mapper.VenueBoothMapper;
import com.ruoyi.cms.service.IVenueInfoService;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.Company;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 场地信息Controller
*
* @author ruoyi
* @date 2026-06-25
*/
@RestController
@RequestMapping("/cms/venue-info")
@Api(tags = "后台:场地信息维护")
public class VenueInfoController extends BaseController
{
@Autowired
private IVenueInfoService venueInfoService;
@Autowired
private VenueBoothMapper venueBoothMapper;
@Autowired
private OutdoorFairMapper outdoorFairMapper;
@Autowired
private OutdoorFairBoothBookingMapper outdoorFairBoothBookingMapper;
@Autowired
private CompanyMapper companyMapper;
/**
* 查询场地信息列表
*/
@ApiOperation("查询场地信息列表")
@PreAuthorize("@ss.hasPermi('cms:venueInfo:list')")
@GetMapping("/list")
public TableDataInfo list(VenueInfo venueInfo)
{
startPage();
List<VenueInfo> list = venueInfoService.selectVenueInfoList(venueInfo);
return getDataTable(list);
}
/**
* 获取场地信息详细信息
*/
@ApiOperation("获取场地信息详细信息")
@PreAuthorize("@ss.hasPermi('cms:venueInfo:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
{
return success(venueInfoService.getById(id));
}
/**
* 新增场地信息
*/
@ApiOperation("新增场地信息")
@PreAuthorize("@ss.hasPermi('cms:venueInfo:add')")
@Log(title = "场地信息", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody VenueInfo venueInfo)
{
fillHandleFields(venueInfo);
return toAjax(venueInfoService.save(venueInfo));
}
/**
* 修改场地信息
*/
@ApiOperation("修改场地信息")
@PreAuthorize("@ss.hasPermi('cms:venueInfo:edit')")
@Log(title = "场地信息", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody VenueInfo venueInfo)
{
fillHandleFields(venueInfo);
return toAjax(venueInfoService.updateById(venueInfo));
}
/**
* 删除场地信息
*/
@ApiOperation("删除场地信息")
@PreAuthorize("@ss.hasPermi('cms:venueInfo:remove')")
@Log(title = "场地信息", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids)
{
return toAjax(venueInfoService.removeByIds(Arrays.asList(ids)));
}
/**
* 新增场地信息维护页面使用的字典项
*/
@ApiOperation("新增场地信息字典项")
@PreAuthorize("@ss.hasAnyPermi('cms:venueInfo:add,cms:venueInfo:edit')")
@Log(title = "场地信息字典项", businessType = BusinessType.INSERT)
@PostMapping("/dict-data")
public AjaxResult addDictData(@Validated @RequestBody VenueInfoDictDataRequest request)
{
return toAjax(venueInfoService.insertVenueInfoDictData(request.getDictType(), request.getDictLabel(), getUsername()));
}
@ApiOperation("查询场地展位图")
@PreAuthorize("@ss.hasAnyPermi('cms:venueInfo:query,cms:outdoorFair:query')")
@GetMapping("/{venueId}/booths")
public AjaxResult listBooths(@PathVariable Long venueId)
{
List<VenueBooth> list = venueBoothMapper.selectList(new LambdaQueryWrapper<VenueBooth>()
.eq(VenueBooth::getVenueId, venueId)
.orderByAsc(VenueBooth::getPositionY)
.orderByAsc(VenueBooth::getPositionX)
.orderByAsc(VenueBooth::getBoothNumber));
return success(list);
}
@ApiOperation("保存场地展位图")
@PreAuthorize("@ss.hasPermi('cms:venueInfo:edit')")
@Transactional(rollbackFor = Exception.class)
@PostMapping("/{venueId}/booths")
public AjaxResult saveBooths(@PathVariable Long venueId, @RequestBody List<VenueBooth> booths)
{
venueBoothMapper.physicalDeleteDeletedByVenueId(venueId);
List<VenueBooth> existingBooths = venueBoothMapper.selectList(new LambdaQueryWrapper<VenueBooth>()
.eq(VenueBooth::getVenueId, venueId));
Map<Long, VenueBooth> existingById = existingBooths.stream()
.filter(item -> item.getId() != null)
.collect(Collectors.toMap(VenueBooth::getId, item -> item, (a, b) -> a));
Map<String, VenueBooth> existingByNumber = existingBooths.stream()
.filter(item -> StringUtils.isNotBlank(item.getBoothNumber()))
.collect(Collectors.toMap(VenueBooth::getBoothNumber, item -> item, (a, b) -> a));
Set<String> boothNumbers = new HashSet<>();
Set<Long> savedIds = new HashSet<>();
if (booths != null) {
for (VenueBooth booth : booths) {
if (StringUtils.isBlank(booth.getBoothNumber())) {
return AjaxResult.error("展位号不能为空");
}
if (!boothNumbers.add(booth.getBoothNumber())) {
return AjaxResult.error("展位号不能重复:" + booth.getBoothNumber());
}
}
for (VenueBooth booth : booths) {
VenueBooth existing = booth.getId() == null ? null : existingById.get(booth.getId());
if (existing == null) {
existing = existingByNumber.get(booth.getBoothNumber());
}
booth.setVenueId(venueId);
if (existing == null) {
booth.setId(null);
venueBoothMapper.insert(booth);
} else {
booth.setId(existing.getId());
venueBoothMapper.updateById(booth);
}
if (booth.getId() != null) {
savedIds.add(booth.getId());
}
}
VenueInfo venueInfo = venueInfoService.getById(venueId);
if (venueInfo != null) {
venueInfo.setFloorCount(booths.size());
venueInfoService.updateById(venueInfo);
}
}
List<Long> removedIds = existingBooths.stream()
.map(VenueBooth::getId)
.filter(id -> id != null && !savedIds.contains(id))
.collect(Collectors.toList());
if (!removedIds.isEmpty()) {
venueBoothMapper.physicalDeleteByVenueIdAndIds(venueId, removedIds);
}
return success();
}
@ApiOperation("查询户外招聘会展位图")
@PreAuthorize("@ss.hasPermi('cms:outdoorFair:query')")
@GetMapping("/fair/{fairId}/booth-map")
public AjaxResult fairBoothMap(@PathVariable Long fairId)
{
OutdoorFair fair = outdoorFairMapper.selectById(fairId);
if (fair == null || fair.getVenueId() == null) {
return success(new ArrayList<>());
}
List<VenueBooth> booths = venueBoothMapper.selectList(new LambdaQueryWrapper<VenueBooth>()
.eq(VenueBooth::getVenueId, fair.getVenueId())
.orderByAsc(VenueBooth::getPositionY)
.orderByAsc(VenueBooth::getPositionX)
.orderByAsc(VenueBooth::getBoothNumber));
List<OutdoorFairBoothBooking> bookings = outdoorFairBoothBookingMapper.selectList(new LambdaQueryWrapper<OutdoorFairBoothBooking>()
.eq(OutdoorFairBoothBooking::getFairId, fairId));
Map<Long, OutdoorFairBoothBooking> bookingMap = bookings.stream().collect(Collectors.toMap(OutdoorFairBoothBooking::getBoothId, item -> item, (a, b) -> a));
List<Map<String, Object>> result = new ArrayList<>();
for (VenueBooth booth : booths) {
OutdoorFairBoothBooking booking = bookingMap.get(booth.getId());
Map<String, Object> row = new java.util.HashMap<>();
row.put("id", booth.getId());
row.put("boothId", booth.getId());
row.put("boothNumber", booth.getBoothNumber());
row.put("positionX", booth.getPositionX());
row.put("positionY", booth.getPositionY());
row.put("bookingId", booking == null ? null : booking.getId());
row.put("companyId", booking == null ? null : booking.getCompanyId());
row.put("companyName", booking == null ? null : booking.getCompanyName());
row.put("status", booking == null ? "available" : booking.getStatus());
result.add(row);
}
return success(result);
}
@ApiOperation("预定户外招聘会展位")
@PreAuthorize("@ss.hasPermi('cms:outdoorFair:edit')")
@PostMapping("/fair/{fairId}/booth-booking")
public AjaxResult bookBooth(@PathVariable Long fairId, @RequestBody OutdoorFairBoothBooking booking)
{
if (booking.getCompanyId() == null) {
return AjaxResult.error("请选择预定单位");
}
Company company = companyMapper.selectById(booking.getCompanyId());
if (company == null || company.getStatus() == null || company.getStatus() != 1) {
return AjaxResult.error("只能预定审核通过的企业");
}
VenueBooth booth = venueBoothMapper.selectById(booking.getBoothId());
booking.setFairId(fairId);
booking.setBoothNumber(booth == null ? booking.getBoothNumber() : booth.getBoothNumber());
booking.setCompanyName(company.getName());
booking.setStatus(StringUtils.isBlank(booking.getStatus()) ? "reserved" : booking.getStatus());
OutdoorFairBoothBooking existing = outdoorFairBoothBookingMapper.selectOne(new LambdaQueryWrapper<OutdoorFairBoothBooking>()
.eq(OutdoorFairBoothBooking::getFairId, fairId)
.eq(OutdoorFairBoothBooking::getBoothId, booking.getBoothId())
.last("limit 1"));
if (existing == null) {
return toAjax(outdoorFairBoothBookingMapper.insert(booking));
}
booking.setId(existing.getId());
return toAjax(outdoorFairBoothBookingMapper.updateById(booking));
}
@ApiOperation("取消户外招聘会展位预定")
@PreAuthorize("@ss.hasPermi('cms:outdoorFair:edit')")
@DeleteMapping("/fair/{fairId}/booth-booking/{boothId}")
public AjaxResult cancelBooth(@PathVariable Long fairId, @PathVariable Long boothId)
{
return toAjax(outdoorFairBoothBookingMapper.delete(new LambdaQueryWrapper<OutdoorFairBoothBooking>()
.eq(OutdoorFairBoothBooking::getFairId, fairId)
.eq(OutdoorFairBoothBooking::getBoothId, boothId)));
}
@ApiOperation("调换户外招聘会展位")
@PreAuthorize("@ss.hasPermi('cms:outdoorFair:edit')")
@PostMapping("/fair/{fairId}/booth-swap")
public AjaxResult swapBooth(@PathVariable Long fairId, @RequestBody VenueBoothSwapRequest request)
{
OutdoorFairBoothBooking first = outdoorFairBoothBookingMapper.selectOne(new LambdaQueryWrapper<OutdoorFairBoothBooking>()
.eq(OutdoorFairBoothBooking::getFairId, fairId)
.eq(OutdoorFairBoothBooking::getBoothId, request.getFirstBoothId()).last("limit 1"));
OutdoorFairBoothBooking second = outdoorFairBoothBookingMapper.selectOne(new LambdaQueryWrapper<OutdoorFairBoothBooking>()
.eq(OutdoorFairBoothBooking::getFairId, fairId)
.eq(OutdoorFairBoothBooking::getBoothId, request.getSecondBoothId()).last("limit 1"));
if (first == null || second == null) {
return AjaxResult.error("请选择两个已预定展位");
}
Long companyId = first.getCompanyId();
String companyName = first.getCompanyName();
first.setCompanyId(second.getCompanyId());
first.setCompanyName(second.getCompanyName());
second.setCompanyId(companyId);
second.setCompanyName(companyName);
outdoorFairBoothBookingMapper.updateById(first);
outdoorFairBoothBookingMapper.updateById(second);
return success();
}
private void fillHandleFields(VenueInfo venueInfo)
{
if (venueInfo.getHandleDate() == null) {
venueInfo.setHandleDate(new Date());
}
if (StringUtils.isBlank(venueInfo.getHandler())) {
venueInfo.setHandler(getUsername());
}
}
}

View File

@@ -45,6 +45,14 @@ public class OutdoorFair extends BaseEntity
@ApiModelProperty("举办区域")
private String region;
@Excel(name = "绑定场地ID")
@ApiModelProperty("绑定场地ID")
private Long venueId;
@Excel(name = "绑定场地")
@ApiModelProperty("绑定场地")
private String venueName;
@Excel(name = "举办地址")
@ApiModelProperty("举办地址")
private String address;

View File

@@ -0,0 +1,38 @@
package com.ruoyi.cms.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.core.domain.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel("户外招聘会展位预定")
@TableName("cms_outdoor_fair_booth_booking")
public class OutdoorFairBoothBooking extends BaseEntity
{
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@ApiModelProperty("招聘会ID")
private Long fairId;
@ApiModelProperty("场地展位ID")
private Long boothId;
@ApiModelProperty("展位号")
private String boothNumber;
@ApiModelProperty("企业ID")
private Long companyId;
@ApiModelProperty("企业名称")
private String companyName;
@ApiModelProperty("预定状态")
private String status;
}

View File

@@ -0,0 +1,32 @@
package com.ruoyi.cms.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.core.domain.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel("场地展位")
@TableName("cms_venue_booth")
public class VenueBooth extends BaseEntity
{
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@ApiModelProperty("场地ID")
private Long venueId;
@ApiModelProperty("展位号")
private String boothNumber;
@ApiModelProperty("X坐标")
private Integer positionX;
@ApiModelProperty("Y坐标")
private Integer positionY;
}

View File

@@ -0,0 +1,10 @@
package com.ruoyi.cms.domain;
import lombok.Data;
@Data
public class VenueBoothSwapRequest
{
private Long firstBoothId;
private Long secondBoothId;
}

View File

@@ -0,0 +1,77 @@
package com.ruoyi.cms.domain;
import java.math.BigDecimal;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 场地信息对象 cms_venue_info
*
* @author ruoyi
* @date 2026-06-25
*/
@Data
@ApiModel("场地信息")
@TableName("cms_venue_info")
public class VenueInfo extends BaseEntity
{
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
@ApiModelProperty("主键ID")
private Long id;
@Excel(name = "场地类型")
@ApiModelProperty("场地类型")
private String venueType;
@Excel(name = "场地名称")
@ApiModelProperty("场地名称")
private String venueName;
@Excel(name = "场地面积")
@ApiModelProperty("场地面积")
private BigDecimal venueArea;
@Excel(name = "展位数量")
@ApiModelProperty("展位数量")
private Integer floorCount;
@Excel(name = "场地地址")
@ApiModelProperty("场地地址")
private String venueAddress;
@Excel(name = "联系电话")
@ApiModelProperty("联系电话")
private String contactPhone;
@Excel(name = "乘坐线路ID")
@ApiModelProperty("乘坐线路ID多个用英文逗号分隔")
private String routeLineIds;
@Excel(name = "乘坐线路")
@ApiModelProperty("乘坐线路名称,多个用英文逗号分隔")
private String routeLineNames;
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "经办日期", width = 30, dateFormat = "yyyy-MM-dd")
@ApiModelProperty("经办日期")
private Date handleDate;
@Excel(name = "经办机构")
@ApiModelProperty("经办机构")
private String handleOrg;
@Excel(name = "经办人")
@ApiModelProperty("经办人")
private String handler;
}

View File

@@ -0,0 +1,26 @@
package com.ruoyi.cms.domain;
import javax.validation.constraints.NotBlank;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 场地信息字典新增请求
*
* @author ruoyi
* @date 2026-06-25
*/
@Data
@ApiModel("场地信息字典新增请求")
public class VenueInfoDictDataRequest
{
@NotBlank(message = "字典类型不能为空")
@ApiModelProperty(value = "字典类型", required = true)
private String dictType;
@NotBlank(message = "字典标签不能为空")
@ApiModelProperty(value = "字典标签", required = true)
private String dictLabel;
}

View File

@@ -0,0 +1,8 @@
package com.ruoyi.cms.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.cms.domain.OutdoorFairBoothBooking;
public interface OutdoorFairBoothBookingMapper extends BaseMapper<OutdoorFairBoothBooking>
{
}

View File

@@ -0,0 +1,24 @@
package com.ruoyi.cms.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.cms.domain.VenueBooth;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface VenueBoothMapper extends BaseMapper<VenueBooth>
{
@Delete("DELETE FROM cms_venue_booth WHERE venue_id = #{venueId} AND del_flag <> '0'")
int physicalDeleteDeletedByVenueId(@Param("venueId") Long venueId);
@Delete({
"<script>",
"DELETE FROM cms_venue_booth WHERE venue_id = #{venueId} AND id IN",
"<foreach collection='ids' item='id' open='(' separator=',' close=')'>",
"#{id}",
"</foreach>",
"</script>"
})
int physicalDeleteByVenueIdAndIds(@Param("venueId") Long venueId, @Param("ids") List<Long> ids);
}

View File

@@ -0,0 +1,53 @@
package com.ruoyi.cms.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.cms.domain.VenueInfo;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
/**
* 场地信息Mapper接口
*
* @author ruoyi
* @date 2026-06-25
*/
public interface VenueInfoMapper extends BaseMapper<VenueInfo>
{
/**
* 查询字典项是否存在
*
* @param dictType 字典类型
* @param dictValue 字典值
* @return 存在数量
*/
@Select("select count(1) from sys_dict_data where dict_type = #{dictType} and dict_value = #{dictValue}")
int countDictDataByTypeAndValue(@Param("dictType") String dictType, @Param("dictValue") String dictValue);
/**
* 获取字典下一个排序
*
* @param dictType 字典类型
* @return 下一个排序值
*/
@Select("select coalesce(max(dict_sort), 0) + 1 from sys_dict_data where dict_type = #{dictType}")
Long selectNextDictSort(@Param("dictType") String dictType);
/**
* 新增系统字典项
*
* @param dictSort 字典排序
* @param dictLabel 字典标签
* @param dictValue 字典值
* @param dictType 字典类型
* @param createBy 创建人
* @return 影响行数
*/
@Insert("insert into sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, list_class, is_default, status, create_by, create_time, remark) " +
"values ((select coalesce(max(dict_code), 0) + 1 from sys_dict_data), #{dictSort}, #{dictLabel}, #{dictValue}, #{dictType}, 'default', 'N', '0', #{createBy}, sysdate(), '场地信息维护页面新增')")
int insertDictData(@Param("dictSort") Long dictSort,
@Param("dictLabel") String dictLabel,
@Param("dictValue") String dictValue,
@Param("dictType") String dictType,
@Param("createBy") String createBy);
}

View File

@@ -0,0 +1,33 @@
package com.ruoyi.cms.service;
import java.util.List;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.cms.domain.VenueInfo;
/**
* 场地信息Service接口
*
* @author ruoyi
* @date 2026-06-25
*/
public interface IVenueInfoService extends IService<VenueInfo>
{
/**
* 查询场地信息列表
*
* @param venueInfo 场地信息
* @return 场地信息集合
*/
List<VenueInfo> selectVenueInfoList(VenueInfo venueInfo);
/**
* 新增场地信息相关字典项
*
* @param dictType 字典类型
* @param dictLabel 字典标签
* @param createBy 创建人
* @return 影响行数
*/
int insertVenueInfoDictData(String dictType, String dictLabel, String createBy);
}

View File

@@ -39,6 +39,7 @@ public class OutdoorFairServiceImpl extends ServiceImpl<OutdoorFairMapper, Outdo
queryWrapper.like(StringUtils.isNotBlank(outdoorFair.getHostUnit()), OutdoorFair::getHostUnit, outdoorFair.getHostUnit());
queryWrapper.eq(StringUtils.isNotBlank(outdoorFair.getFairType()), OutdoorFair::getFairType, outdoorFair.getFairType());
queryWrapper.eq(StringUtils.isNotBlank(outdoorFair.getRegion()), OutdoorFair::getRegion, outdoorFair.getRegion());
queryWrapper.eq(outdoorFair.getVenueId() != null, OutdoorFair::getVenueId, outdoorFair.getVenueId());
queryWrapper.orderByDesc(OutdoorFair::getHoldTime);
queryWrapper.orderByDesc(OutdoorFair::getCreateTime);
return list(queryWrapper);

View File

@@ -0,0 +1,74 @@
package com.ruoyi.cms.service.impl;
import java.util.List;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.cms.domain.VenueInfo;
import com.ruoyi.cms.mapper.VenueInfoMapper;
import com.ruoyi.cms.service.IVenueInfoService;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.stereotype.Service;
/**
* 场地信息Service业务层处理
*
* @author ruoyi
* @date 2026-06-25
*/
@Service
public class VenueInfoServiceImpl extends ServiceImpl<VenueInfoMapper, VenueInfo> implements IVenueInfoService
{
private static final String VENUE_TYPE_DICT = "venue_info_type";
/**
* 查询场地信息列表
*
* @param venueInfo 场地信息
* @return 场地信息集合
*/
@Override
public List<VenueInfo> selectVenueInfoList(VenueInfo venueInfo)
{
LambdaQueryWrapper<VenueInfo> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(StringUtils.isNotBlank(venueInfo.getVenueType()), VenueInfo::getVenueType, venueInfo.getVenueType());
queryWrapper.like(StringUtils.isNotBlank(venueInfo.getVenueName()), VenueInfo::getVenueName, venueInfo.getVenueName());
queryWrapper.like(StringUtils.isNotBlank(venueInfo.getVenueAddress()), VenueInfo::getVenueAddress, venueInfo.getVenueAddress());
queryWrapper.orderByDesc(VenueInfo::getCreateTime);
return list(queryWrapper);
}
/**
* 新增场地信息相关字典项
*
* @param dictType 字典类型
* @param dictLabel 字典标签
* @param createBy 创建人
* @return 影响行数
*/
@Override
public int insertVenueInfoDictData(String dictType, String dictLabel, String createBy)
{
if (!VENUE_TYPE_DICT.equals(dictType)) {
throw new ServiceException("只允许维护场地类型字典");
}
String trimmedLabel = StringUtils.trim(dictLabel);
if (StringUtils.isBlank(trimmedLabel)) {
throw new ServiceException("字典名称不能为空");
}
if (trimmedLabel.length() > 100) {
throw new ServiceException("字典名称长度不能超过100个字符");
}
if (baseMapper.countDictDataByTypeAndValue(dictType, trimmedLabel) > 0) {
return 1;
}
Long dictSort = baseMapper.selectNextDictSort(dictType);
int rows = baseMapper.insertDictData(dictSort, trimmedLabel, trimmedLabel, dictType, createBy);
if (rows > 0) {
DictUtils.removeDictCache(dictType);
}
return rows;
}
}

View File

@@ -14,6 +14,8 @@ CREATE TABLE IF NOT EXISTS "cms_outdoor_fair" (
"host_unit" VARCHAR(200) NOT NULL,
"fair_type" VARCHAR(50) NOT NULL,
"region" VARCHAR(100) NOT NULL,
"venue_id" BIGINT,
"venue_name" VARCHAR(200),
"address" VARCHAR(500) NOT NULL,
"booth_count" INTEGER NOT NULL DEFAULT 0,
"hold_time" TIMESTAMP(0) NOT NULL,
@@ -36,6 +38,8 @@ COMMENT ON COLUMN "cms_outdoor_fair"."title" IS '招聘会标题';
COMMENT ON COLUMN "cms_outdoor_fair"."host_unit" IS '举办单位';
COMMENT ON COLUMN "cms_outdoor_fair"."fair_type" IS '招聘会类型';
COMMENT ON COLUMN "cms_outdoor_fair"."region" IS '举办区域';
COMMENT ON COLUMN "cms_outdoor_fair"."venue_id" IS '绑定场地ID';
COMMENT ON COLUMN "cms_outdoor_fair"."venue_name" IS '绑定场地';
COMMENT ON COLUMN "cms_outdoor_fair"."address" IS '举办地址';
COMMENT ON COLUMN "cms_outdoor_fair"."booth_count" IS '展位数量';
COMMENT ON COLUMN "cms_outdoor_fair"."hold_time" IS '举办时间';
@@ -49,5 +53,6 @@ COMMENT ON COLUMN "cms_outdoor_fair"."del_flag" IS '删除标志0代表存在
CREATE INDEX IF NOT EXISTS "idx_cms_outdoor_fair_title" ON "cms_outdoor_fair" ("title");
CREATE INDEX IF NOT EXISTS "idx_cms_outdoor_fair_host_unit" ON "cms_outdoor_fair" ("host_unit");
CREATE INDEX IF NOT EXISTS "idx_cms_outdoor_fair_type" ON "cms_outdoor_fair" ("fair_type");
CREATE INDEX IF NOT EXISTS "idx_cms_outdoor_fair_venue_id" ON "cms_outdoor_fair" ("venue_id");
CREATE INDEX IF NOT EXISTS "idx_cms_outdoor_fair_hold_time" ON "cms_outdoor_fair" ("hold_time");
CREATE INDEX IF NOT EXISTS "idx_cms_outdoor_fair_del_flag" ON "cms_outdoor_fair" ("del_flag");

View File

@@ -0,0 +1,20 @@
-- 户外招聘会绑定场地字段
-- 瀚高数据库 / PostgreSQL 兼容
-- 可重复执行。
ALTER TABLE "cms_outdoor_fair"
ADD COLUMN IF NOT EXISTS "venue_id" BIGINT;
ALTER TABLE "cms_outdoor_fair"
ADD COLUMN IF NOT EXISTS "venue_name" VARCHAR(200);
COMMENT ON COLUMN "cms_outdoor_fair"."venue_id" IS '绑定场地ID';
COMMENT ON COLUMN "cms_outdoor_fair"."venue_name" IS '绑定场地';
CREATE INDEX IF NOT EXISTS "idx_cms_outdoor_fair_venue_id" ON "cms_outdoor_fair" ("venue_id");
UPDATE "cms_outdoor_fair" fair
SET "venue_name" = venue."venue_name",
"booth_count" = COALESCE(venue."floor_count", 0)
FROM "cms_venue_info" venue
WHERE fair."venue_id" = venue."id";

View File

@@ -0,0 +1,86 @@
-- 场地展位图与户外招聘会展位预定
-- 瀚高数据库 / PostgreSQL 兼容
CREATE SEQUENCE IF NOT EXISTS "cms_venue_booth_id_seq" START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
CREATE TABLE IF NOT EXISTS "cms_venue_booth" (
"id" BIGINT NOT NULL DEFAULT nextval('"cms_venue_booth_id_seq"') PRIMARY KEY,
"venue_id" BIGINT NOT NULL,
"booth_number" VARCHAR(50) NOT NULL,
"position_x" INTEGER NOT NULL DEFAULT 0,
"position_y" INTEGER NOT NULL DEFAULT 0,
"create_by" VARCHAR(64) DEFAULT '',
"create_time" TIMESTAMP(0),
"update_by" VARCHAR(64) DEFAULT '',
"update_time" TIMESTAMP(0),
"remark" VARCHAR(500),
"del_flag" CHAR(1) DEFAULT '0'
);
COMMENT ON TABLE "cms_venue_booth" IS '场地展位图';
COMMENT ON COLUMN "cms_venue_booth"."venue_id" IS '场地ID';
COMMENT ON COLUMN "cms_venue_booth"."booth_number" IS '展位号';
COMMENT ON COLUMN "cms_venue_booth"."position_x" IS 'X坐标';
COMMENT ON COLUMN "cms_venue_booth"."position_y" IS 'Y坐标';
CREATE UNIQUE INDEX IF NOT EXISTS "uk_cms_venue_booth_number" ON "cms_venue_booth" ("venue_id", "booth_number");
CREATE INDEX IF NOT EXISTS "idx_cms_venue_booth_venue" ON "cms_venue_booth" ("venue_id");
CREATE SEQUENCE IF NOT EXISTS "cms_outdoor_fair_booth_booking_id_seq" START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
CREATE TABLE IF NOT EXISTS "cms_outdoor_fair_booth_booking" (
"id" BIGINT NOT NULL DEFAULT nextval('"cms_outdoor_fair_booth_booking_id_seq"') PRIMARY KEY,
"fair_id" BIGINT NOT NULL,
"booth_id" BIGINT NOT NULL,
"booth_number" VARCHAR(50) NOT NULL,
"company_id" BIGINT,
"company_name" VARCHAR(200),
"status" VARCHAR(30) DEFAULT 'reserved',
"create_by" VARCHAR(64) DEFAULT '',
"create_time" TIMESTAMP(0),
"update_by" VARCHAR(64) DEFAULT '',
"update_time" TIMESTAMP(0),
"remark" VARCHAR(500),
"del_flag" CHAR(1) DEFAULT '0'
);
COMMENT ON TABLE "cms_outdoor_fair_booth_booking" IS '户外招聘会展位预定';
CREATE UNIQUE INDEX IF NOT EXISTS "uk_cms_outdoor_fair_booth_booking" ON "cms_outdoor_fair_booth_booking" ("fair_id", "booth_id");
CREATE INDEX IF NOT EXISTS "idx_cms_outdoor_fair_booth_booking_fair" ON "cms_outdoor_fair_booth_booking" ("fair_id");
WITH target_venue AS (
SELECT "id" AS venue_id
FROM "cms_venue_info"
WHERE "venue_name" = '石河子市人民广场户外招聘区'
LIMIT 1
),
seed AS (
SELECT
target_venue.venue_id,
'KJ' || LPAD(gs::text, 2, '0') AS booth_number,
40 + ((gs - 1) % 20) * 54 AS position_x,
40 + ((gs - 1) / 20) * 54 AS position_y
FROM target_venue
CROSS JOIN generate_series(1, 80) gs
)
INSERT INTO "cms_venue_booth" ("venue_id", "booth_number", "position_x", "position_y", "create_by", "create_time", "del_flag")
SELECT seed.venue_id, seed.booth_number, seed.position_x, seed.position_y, 'system', NOW(), '0'
FROM seed
WHERE NOT EXISTS (
SELECT 1
FROM "cms_venue_booth" existing
WHERE existing."venue_id" = seed.venue_id
AND existing."booth_number" = seed.booth_number
);
UPDATE "cms_venue_info" venue
SET "floor_count" = booth_counts.total
FROM (
SELECT "venue_id", COUNT(*) AS total
FROM "cms_venue_booth"
GROUP BY "venue_id"
) booth_counts
WHERE venue."id" = booth_counts."venue_id";
UPDATE "cms_outdoor_fair" fair
SET "booth_count" = venue."floor_count"
FROM "cms_venue_info" venue
WHERE fair."venue_id" = venue."id";

215
sql/cms_venue_info.sql Normal file
View File

@@ -0,0 +1,215 @@
-- 场地信息维护表、字典、菜单
-- 瀚高数据库 / PostgreSQL 兼容
-- 可重复执行。
CREATE SEQUENCE IF NOT EXISTS "cms_venue_info_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
CREATE TABLE IF NOT EXISTS "cms_venue_info" (
"id" BIGINT NOT NULL DEFAULT nextval('"cms_venue_info_id_seq"') PRIMARY KEY,
"venue_type" VARCHAR(100) NOT NULL,
"venue_name" VARCHAR(200) NOT NULL,
"venue_area" NUMERIC(12, 2),
"floor_count" INTEGER,
"venue_address" VARCHAR(500) NOT NULL,
"contact_phone" VARCHAR(50),
"route_line_ids" VARCHAR(500),
"route_line_names" VARCHAR(1000),
"handle_date" DATE,
"handle_org" VARCHAR(200),
"handler" VARCHAR(100),
"create_by" VARCHAR(64) DEFAULT '',
"create_time" TIMESTAMP(0),
"update_by" VARCHAR(64) DEFAULT '',
"update_time" TIMESTAMP(0),
"remark" VARCHAR(100),
"del_flag" CHAR(1) DEFAULT '0'
);
COMMENT ON TABLE "cms_venue_info" IS '场地信息维护表';
COMMENT ON COLUMN "cms_venue_info"."id" IS '主键ID';
COMMENT ON COLUMN "cms_venue_info"."venue_type" IS '场地类型';
COMMENT ON COLUMN "cms_venue_info"."venue_name" IS '场地名称';
COMMENT ON COLUMN "cms_venue_info"."venue_area" IS '场地面积';
COMMENT ON COLUMN "cms_venue_info"."floor_count" IS '展位数量';
COMMENT ON COLUMN "cms_venue_info"."venue_address" IS '场地地址';
COMMENT ON COLUMN "cms_venue_info"."contact_phone" IS '联系电话';
COMMENT ON COLUMN "cms_venue_info"."route_line_ids" IS '乘坐线路ID多个用英文逗号分隔';
COMMENT ON COLUMN "cms_venue_info"."route_line_names" IS '乘坐线路名称,多个用英文逗号分隔';
COMMENT ON COLUMN "cms_venue_info"."handle_date" IS '经办日期';
COMMENT ON COLUMN "cms_venue_info"."handle_org" IS '经办机构';
COMMENT ON COLUMN "cms_venue_info"."handler" IS '经办人';
COMMENT ON COLUMN "cms_venue_info"."remark" IS '备注';
COMMENT ON COLUMN "cms_venue_info"."del_flag" IS '删除标志0代表存在 2代表删除';
CREATE INDEX IF NOT EXISTS "idx_cms_venue_info_type" ON "cms_venue_info" ("venue_type");
CREATE INDEX IF NOT EXISTS "idx_cms_venue_info_name" ON "cms_venue_info" ("venue_name");
CREATE INDEX IF NOT EXISTS "idx_cms_venue_info_del_flag" ON "cms_venue_info" ("del_flag");
INSERT INTO "sys_dict_type" (
"dict_id", "dict_name", "dict_type", "status", "create_by", "create_time", "remark"
)
SELECT
(SELECT COALESCE(MAX("dict_id"), 0) + 1 FROM "sys_dict_type"),
'场地类型',
'venue_info_type',
'0',
'system',
NOW(),
'场地信息维护使用'
WHERE NOT EXISTS (
SELECT 1 FROM "sys_dict_type" WHERE "dict_type" = 'venue_info_type'
);
WITH seed("dict_sort", "dict_label", "dict_value", "list_class", "is_default") AS (
VALUES
(1, '智能化招聘场馆', '智能化招聘场馆', 'primary', 'Y'),
(2, '户外招聘广场', '户外招聘广场', 'success', 'N'),
(3, '高校招聘场地', '高校招聘场地', 'processing', 'N'),
(4, '园区招聘场地', '园区招聘场地', 'cyan', 'N'),
(5, '临时招聘场地', '临时招聘场地', 'warning', 'N'),
(6, '其他', '其他', 'default', 'N')
),
new_rows AS (
SELECT
ROW_NUMBER() OVER (ORDER BY seed."dict_sort") AS rn,
seed.*
FROM seed
WHERE NOT EXISTS (
SELECT 1
FROM "sys_dict_data" data
WHERE data."dict_type" = 'venue_info_type'
AND data."dict_value" = seed."dict_value"
)
),
base AS (
SELECT COALESCE(MAX("dict_code"), 0) AS max_code FROM "sys_dict_data"
)
INSERT INTO "sys_dict_data" (
"dict_code", "dict_sort", "dict_label", "dict_value", "dict_type",
"css_class", "list_class", "is_default", "status", "create_by", "create_time", "remark"
)
SELECT
base.max_code + new_rows.rn,
new_rows."dict_sort",
new_rows."dict_label",
new_rows."dict_value",
'venue_info_type',
NULL,
new_rows."list_class",
new_rows."is_default",
'0',
'system',
NOW(),
'场地类型'
FROM new_rows
CROSS JOIN base;
WITH parent_menu AS (
SELECT "menu_id" FROM "sys_menu" WHERE "menu_id" = 2055
),
inserted_page AS (
INSERT INTO "sys_menu" (
"menu_name", "parent_id", "order_num", "path", "component", "query", "route_name",
"is_frame", "is_cache", "menu_type", "visible", "status", "perms", "icon",
"create_by", "create_time", "remark"
)
SELECT
'场地信息维护',
parent_menu."menu_id",
2,
'jobfair/venueinfo',
'jobfair/venueinfo/index',
NULL,
'',
1,
0,
'C',
'0',
'0',
'cms:venueInfo:list',
'#',
'system',
NOW(),
'场地信息维护菜单'
FROM parent_menu
WHERE NOT EXISTS (
SELECT 1 FROM "sys_menu" WHERE "parent_id" = parent_menu."menu_id" AND "menu_name" = '场地信息维护'
)
RETURNING "menu_id"
),
page_menu AS (
SELECT "menu_id" FROM inserted_page
UNION
SELECT "menu_id" FROM "sys_menu" WHERE "parent_id" = 2055 AND "menu_name" = '场地信息维护'
),
button_seed("menu_name", "order_num", "perms") AS (
VALUES
('场地信息查询', 1, 'cms:venueInfo:query'),
('场地信息新增', 2, 'cms:venueInfo:add'),
('场地信息修改', 3, 'cms:venueInfo:edit'),
('场地信息删除', 4, 'cms:venueInfo:remove')
)
INSERT INTO "sys_menu" (
"menu_name", "parent_id", "order_num", "path", "component", "query", "route_name",
"is_frame", "is_cache", "menu_type", "visible", "status", "perms", "icon",
"create_by", "create_time", "remark"
)
SELECT
button_seed."menu_name",
page_menu."menu_id",
button_seed."order_num",
'',
NULL,
NULL,
'',
1,
0,
'F',
'0',
'0',
button_seed."perms",
'#',
'system',
NOW(),
'场地信息维护按钮'
FROM page_menu
CROSS JOIN button_seed
WHERE NOT EXISTS (
SELECT 1 FROM "sys_menu" WHERE "perms" = button_seed."perms"
);
WITH outdoor_roles AS (
SELECT DISTINCT "role_id"
FROM "sys_role_menu"
WHERE "menu_id" = 2111
),
venue_menus AS (
SELECT "menu_id"
FROM "sys_menu"
WHERE ("parent_id" = 2055 AND "menu_name" = '场地信息维护')
OR "perms" IN (
'cms:venueInfo:query',
'cms:venueInfo:add',
'cms:venueInfo:edit',
'cms:venueInfo:remove'
)
),
role_menu_rows AS (
SELECT outdoor_roles."role_id", venue_menus."menu_id"
FROM outdoor_roles
CROSS JOIN venue_menus
)
INSERT INTO "sys_role_menu" ("role_id", "menu_id")
SELECT role_menu_rows."role_id", role_menu_rows."menu_id"
FROM role_menu_rows
WHERE NOT EXISTS (
SELECT 1
FROM "sys_role_menu" existing
WHERE existing."role_id" = role_menu_rows."role_id"
AND existing."menu_id" = role_menu_rows."menu_id"
);