This commit is contained in:
chenyanchang
2026-06-25 15:09:25 +08:00
38 changed files with 2392 additions and 15 deletions

View File

@@ -0,0 +1,140 @@
package com.ruoyi.cms.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
/**
* 面试菜单权限自动迁移
* 应用启动后自动检查并添加面试列表菜单及按钮权限到 sys_menu 和 sys_role_menu 表
*/
@Slf4j
@Component
public class InterviewMenuMigration {
@Autowired
private DataSource dataSource;
@EventListener(ApplicationReadyEvent.class)
public void migrate() {
log.info("开始检查面试菜单权限...");
try (Connection conn = dataSource.getConnection()) {
// Step 1: 查找岗位管理目录的 menu_id
Long parentId = null;
try (Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(
"SELECT menu_id FROM sys_menu WHERE path = 'management' AND menu_type = 'M' LIMIT 1")) {
if (rs.next()) {
parentId = rs.getLong("menu_id");
}
}
if (parentId == null) {
log.warn("未找到 management 目录菜单,跳过面试菜单迁移");
return;
}
log.info("找到 management 目录菜单parent_id={}", parentId);
// Step 2: 插入面试列表菜单(幂等)
Long menuId = insertMenuIfNotExists(conn, 2100L, "面试列表", parentId, 10,
"interview-list", "Management/InterviewList", "InterviewList",
"C", "cms:interview:list", "message");
if (menuId == null) {
log.warn("面试列表菜单插入失败(可能已存在但 parent_id 不同)");
return;
}
// Step 3: 插入按钮权限
insertMenuIfNotExists(conn, 2101L, "面试查询", menuId, 1,
"", "", "", "F", "cms:interview:query", "#");
insertMenuIfNotExists(conn, 2102L, "面试新增", menuId, 2,
"", "", "", "F", "cms:interview:add", "#");
insertMenuIfNotExists(conn, 2103L, "面试修改", menuId, 3,
"", "", "", "F", "cms:interview:edit", "#");
insertMenuIfNotExists(conn, 2104L, "面试删除", menuId, 4,
"", "", "", "F", "cms:interview:remove", "#");
// Step 4: 将新菜单赋给所有非管理员角色
try (Statement stmt = conn.createStatement()) {
stmt.execute(
"INSERT INTO sys_role_menu (role_id, menu_id) " +
"SELECT r.role_id, " + menuId + " FROM sys_role r " +
"WHERE r.role_key != 'admin' " +
"AND NOT EXISTS (SELECT 1 FROM sys_role_menu rm WHERE rm.role_id = r.role_id AND rm.menu_id = " + menuId + ")");
} catch (Exception e) {
log.debug("角色菜单关联已存在或插入失败: {}", e.getMessage());
}
// 按钮也赋给角色
for (long btnId : new long[]{2101L, 2102L, 2103L, 2104L}) {
try (Statement stmt = conn.createStatement()) {
stmt.execute(
"INSERT INTO sys_role_menu (role_id, menu_id) " +
"SELECT r.role_id, " + btnId + " FROM sys_role r " +
"WHERE r.role_key != 'admin' " +
"AND NOT EXISTS (SELECT 1 FROM sys_role_menu rm WHERE rm.role_id = r.role_id AND rm.menu_id = " + btnId + ")");
} catch (Exception e) {
log.debug("按钮角色关联已存在: {}", e.getMessage());
}
}
log.info("面试菜单权限迁移完成");
} catch (Exception e) {
log.error("面试菜单迁移失败: {}", e.getMessage(), e);
}
}
/**
* 幂等插入菜单记录
*/
private Long insertMenuIfNotExists(Connection conn, Long menuId, String menuName,
Long parentId, int orderNum, String path,
String component, String routeName,
String menuType, String perms, String icon) {
try {
// 检查是否已存在
try (PreparedStatement ps = conn.prepareStatement(
"SELECT 1 FROM sys_menu WHERE menu_id = ?")) {
ps.setLong(1, menuId);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
log.debug("菜单已存在: {} (id={})", menuName, menuId);
return menuId;
}
}
}
// 插入新菜单
try (PreparedStatement ps = conn.prepareStatement(
"INSERT INTO sys_menu (menu_id, 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) " +
"VALUES (?, ?, ?, ?, ?, ?, '', ?, 1, 0, ?, '0', '0', ?, ?, 'admin', CURRENT_TIMESTAMP)")) {
ps.setLong(1, menuId);
ps.setString(2, menuName);
ps.setLong(3, parentId);
ps.setInt(4, orderNum);
ps.setString(5, path);
ps.setString(6, component);
ps.setString(7, routeName);
ps.setString(8, menuType);
ps.setString(9, perms);
ps.setString(10, icon);
ps.executeUpdate();
log.info("菜单创建成功: {} (id={}, perms={})", menuName, menuId, perms);
return menuId;
}
} catch (Exception e) {
log.warn("菜单创建失败: {} (id={}), error={}", menuName, menuId, e.getMessage());
return null;
}
}
}

View File

@@ -12,6 +12,8 @@ import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.util.List;
@@ -67,7 +69,32 @@ public class AppInterviewController extends BaseController {
*/
@ApiOperation("更新面试邀约状态")
@PutMapping("/status/{id}")
public AjaxResult updateStatus(@PathVariable Long id, @RequestParam String status){
public AjaxResult updateStatus(@PathVariable Long id, HttpServletRequest request) {
String status = request.getParameter("status");
// 如果 URL 参数没有,尝试从 JSON body 中读取
if (status == null || status.isEmpty()) {
try {
BufferedReader reader = request.getReader();
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
String body = sb.toString();
if (body != null && !body.isEmpty()) {
// 简单解析 JSON: {"status": "accepted"}
status = body.replaceAll(".*\"status\"\\s*:\\s*\"([^\"]+)\".*", "$1");
if (status.equals(body)) {
status = null;
}
}
} catch (Exception e) {
// ignore body read errors
}
}
if (status == null || status.isEmpty()) {
return AjaxResult.error("状态参数不能为空");
}
int rows = interviewInvitationService.updateInterviewStatus(id, status);
if (rows > 0 && "accepted".equals(status)) {
// 接受时返回面试官联系方式,供前端弹窗展示

View File

@@ -1,6 +1,7 @@
package com.ruoyi.cms.controller.cms;
import com.ruoyi.cms.domain.InterviewInvitation;
import com.ruoyi.cms.domain.vo.InterviewInvitationVO;
import com.ruoyi.cms.service.InterviewInvitationService;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
@@ -38,7 +39,7 @@ public class CmsInterviewController extends BaseController {
@GetMapping("/list")
public TableDataInfo list(InterviewInvitation interviewInvitation){
startPage();
List<InterviewInvitation> list = interviewInvitationService.getInterviewInvitationList(interviewInvitation);
List<InterviewInvitationVO> list = interviewInvitationService.getInterviewInvitationVOList(interviewInvitation);
return getDataTable(list);
}

View File

@@ -0,0 +1,134 @@
package com.ruoyi.cms.controller.cms;
import java.util.Arrays;
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;
import org.springframework.security.access.prepost.PreAuthorize;
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/outdoor-fair")
@Api(tags = "后台:户外招聘会")
public class OutdoorFairController extends BaseController
{
@Autowired
private IOutdoorFairService outdoorFairService;
@Autowired
private IVenueInfoService venueInfoService;
/**
* 查询户外招聘会列表
*/
@ApiOperation("查询户外招聘会列表")
@PreAuthorize("@ss.hasPermi('cms:outdoorFair:list')")
@GetMapping("/list")
public TableDataInfo list(OutdoorFair outdoorFair)
{
startPage();
List<OutdoorFair> list = outdoorFairService.selectOutdoorFairList(outdoorFair);
return getDataTable(list);
}
/**
* 获取户外招聘会详细信息
*/
@ApiOperation("获取户外招聘会详细信息")
@PreAuthorize("@ss.hasPermi('cms:outdoorFair:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
{
return success(outdoorFairService.getById(id));
}
/**
* 新增户外招聘会
*/
@ApiOperation("新增户外招聘会")
@PreAuthorize("@ss.hasPermi('cms:outdoorFair:add')")
@Log(title = "户外招聘会", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody OutdoorFair outdoorFair)
{
fillVenueFields(outdoorFair);
return toAjax(outdoorFairService.save(outdoorFair));
}
/**
* 修改户外招聘会
*/
@ApiOperation("修改户外招聘会")
@PreAuthorize("@ss.hasPermi('cms:outdoorFair:edit')")
@Log(title = "户外招聘会", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody OutdoorFair outdoorFair)
{
fillVenueFields(outdoorFair);
return toAjax(outdoorFairService.updateById(outdoorFair));
}
/**
* 删除户外招聘会
*/
@ApiOperation("删除户外招聘会")
@PreAuthorize("@ss.hasPermi('cms:outdoorFair:remove')")
@Log(title = "户外招聘会", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids)
{
return toAjax(outdoorFairService.removeByIds(Arrays.asList(ids)));
}
/**
* 新增户外招聘会页面使用的字典项
*/
@ApiOperation("新增户外招聘会字典项")
@PreAuthorize("@ss.hasAnyPermi('cms:outdoorFair:add,cms:outdoorFair:edit')")
@Log(title = "户外招聘会字典项", businessType = BusinessType.INSERT)
@PostMapping("/dict-data")
public AjaxResult addDictData(@Validated @RequestBody OutdoorFairDictDataRequest request)
{
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

@@ -77,6 +77,11 @@ public class InterviewInvitation extends BaseEntity {
*/
@ApiModelProperty("面试官联系方式")
private String contactPhone;
/**
* 面试官姓名
*/
@ApiModelProperty("面试官姓名")
private String interviewerName;
/**
* 公司名称冗余存储创建时从company表获取
*/

View File

@@ -0,0 +1,91 @@
package com.ruoyi.cms.domain;
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_outdoor_fair
*
* @author ruoyi
* @date 2026-06-25
*/
@Data
@ApiModel("户外招聘会")
@TableName("cms_outdoor_fair")
public class OutdoorFair extends BaseEntity
{
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
@ApiModelProperty("主键ID")
private Long id;
@Excel(name = "招聘会标题")
@ApiModelProperty("招聘会标题")
private String title;
@Excel(name = "举办单位")
@ApiModelProperty("举办单位")
private String hostUnit;
@Excel(name = "招聘会类型")
@ApiModelProperty("招聘会类型")
private String fairType;
@Excel(name = "举办区域")
@ApiModelProperty("举办区域")
private String region;
@Excel(name = "绑定场地ID")
@ApiModelProperty("绑定场地ID")
private Long venueId;
@Excel(name = "绑定场地")
@ApiModelProperty("绑定场地")
private String venueName;
@Excel(name = "举办地址")
@ApiModelProperty("举办地址")
private String address;
@Excel(name = "展位数量")
@ApiModelProperty("展位数量")
private Integer boothCount;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "举办时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty("举办时间")
private Date holdTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "截止时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty("截止时间")
private Date endTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "开放申请时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty("开放申请时间")
private Date applyStartTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "截止申请时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty("截止申请时间")
private Date applyEndTime;
@Excel(name = "是否开启线上申请")
@ApiModelProperty("是否开启线上申请")
private Boolean onlineApply;
@Excel(name = "招聘会照片")
@ApiModelProperty("招聘会照片")
private String photoUrl;
}

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,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 OutdoorFairDictDataRequest
{
@NotBlank(message = "字典类型不能为空")
@ApiModelProperty(value = "字典类型", required = true)
private String dictType;
@NotBlank(message = "字典标签不能为空")
@ApiModelProperty(value = "字典标签", required = true)
private String dictLabel;
}

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

@@ -18,4 +18,6 @@ public class CandidateVO extends AppUser {
private String companyName;
@Excel(name = "岗位名称", sort = 1)
private String jobName;
private String interviewStatus;
private Long interviewId;
}

View File

@@ -11,4 +11,10 @@ public class InterviewInvitationVO extends InterviewInvitation {
@ApiModelProperty("岗位名称(来自关联查询的实时数据)")
private String jobTitle;
@ApiModelProperty("求职者姓名(来自关联查询的实时数据)")
private String applicantName;
@ApiModelProperty("求职者联系方式(来自关联查询的实时数据)")
private String applicantPhone;
}

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,53 @@
package com.ruoyi.cms.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.cms.domain.OutdoorFair;
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 OutdoorFairMapper extends BaseMapper<OutdoorFair>
{
/**
* 查询字典项是否存在
*
* @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,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.OutdoorFair;
/**
* 户外招聘会Service接口
*
* @author ruoyi
* @date 2026-06-25
*/
public interface IOutdoorFairService extends IService<OutdoorFair>
{
/**
* 查询户外招聘会列表
*
* @param outdoorFair 户外招聘会
* @return 户外招聘会集合
*/
List<OutdoorFair> selectOutdoorFairList(OutdoorFair outdoorFair);
/**
* 新增户外招聘会相关字典项
*
* @param dictType 字典类型
* @param dictLabel 字典标签
* @param createBy 创建人
* @return 影响行数
*/
int insertOutdoorFairDictData(String dictType, String dictLabel, 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

@@ -72,7 +72,7 @@ public class ESJobSearchImpl implements IESJobSearchService
/**
* 项目启动时,初始化索引及数据
*/
@PostConstruct
// @PostConstruct
public void init()
{
boolean isLockAcquired = false;

View File

@@ -17,12 +17,14 @@ import com.ruoyi.common.core.domain.entity.Company;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.Statement;
import lombok.extern.slf4j.Slf4j;
import java.util.Arrays;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import java.util.List;
@@ -43,8 +45,9 @@ public class InterviewInvitationServiceImpl implements InterviewInvitationServic
@Autowired
private DataSource dataSource;
@PostConstruct
@EventListener(ApplicationReadyEvent.class)
public void initTable() {
log.info("开始检查并初始化 interview_invitation 表...");
try (Connection conn = dataSource.getConnection();
Statement stmt = conn.createStatement()) {
// Check if id column has auto-increment (BIGSERIAL or sequence default)
@@ -80,6 +83,7 @@ public class InterviewInvitationServiceImpl implements InterviewInvitationServic
+ "meeting_password varchar(100) NULL,"
+ "interview_location varchar(500) NULL,"
+ "contact_phone varchar(50) NULL,"
+ "interviewer_name varchar(100) NULL,"
+ "company_name varchar(200) NULL,"
+ "job_name varchar(200) NULL,"
+ "status varchar(20) DEFAULT 'pending' NULL,"
@@ -96,9 +100,16 @@ public class InterviewInvitationServiceImpl implements InterviewInvitationServic
log.info("interview_invitation 表创建成功(序列自增)!");
} else {
log.info("interview_invitation 表结构正常,检查新增列...");
// 为已有数据库添加新列(幂等操作)
try { stmt.execute("ALTER TABLE interview_invitation ADD COLUMN IF NOT EXISTS company_name varchar(200) NULL"); } catch (Exception ignored) {}
try { stmt.execute("ALTER TABLE interview_invitation ADD COLUMN IF NOT EXISTS job_name varchar(200) NULL"); } catch (Exception ignored) {}
// 为已有数据库添加新列(幂等操作,使用 DO 块兼容不支持 IF NOT EXISTS 的数据库版本
try {
stmt.execute("DO $$ BEGIN ALTER TABLE interview_invitation ADD COLUMN company_name varchar(200) NULL; EXCEPTION WHEN duplicate_column THEN END; $$;");
} catch (Exception e) { log.warn("添加 company_name 列失败: {}", e.getMessage()); }
try {
stmt.execute("DO $$ BEGIN ALTER TABLE interview_invitation ADD COLUMN job_name varchar(200) NULL; EXCEPTION WHEN duplicate_column THEN END; $$;");
} catch (Exception e) { log.warn("添加 job_name 列失败: {}", e.getMessage()); }
try {
stmt.execute("DO $$ BEGIN ALTER TABLE interview_invitation ADD COLUMN interviewer_name varchar(100) NULL; EXCEPTION WHEN duplicate_column THEN END; $$;");
} catch (Exception e) { log.warn("添加 interviewer_name 列失败: {}", e.getMessage()); }
}
} catch (Exception e) {
log.error("初始化表失败: {}", e.getMessage());

View File

@@ -0,0 +1,79 @@
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.OutdoorFair;
import com.ruoyi.cms.mapper.OutdoorFairMapper;
import com.ruoyi.cms.service.IOutdoorFairService;
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 OutdoorFairServiceImpl extends ServiceImpl<OutdoorFairMapper, OutdoorFair> implements IOutdoorFairService
{
private static final String OUTDOOR_FAIR_TYPE_DICT = "outdoor_fair_type";
private static final String OUTDOOR_FAIR_REGION_DICT = "outdoor_fair_region";
/**
* 查询户外招聘会列表
*
* @param outdoorFair 户外招聘会
* @return 户外招聘会集合
*/
@Override
public List<OutdoorFair> selectOutdoorFairList(OutdoorFair outdoorFair)
{
LambdaQueryWrapper<OutdoorFair> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(StringUtils.isNotBlank(outdoorFair.getTitle()), OutdoorFair::getTitle, outdoorFair.getTitle());
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);
}
/**
* 新增户外招聘会相关字典项
*
* @param dictType 字典类型
* @param dictLabel 字典标签
* @param createBy 创建人
* @return 影响行数
*/
@Override
public int insertOutdoorFairDictData(String dictType, String dictLabel, String createBy)
{
if (!OUTDOOR_FAIR_TYPE_DICT.equals(dictType) && !OUTDOOR_FAIR_REGION_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

@@ -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;
}
}