From b35ed5989e1b20571ffcf9ccb8f0b7f8167e625f Mon Sep 17 00:00:00 2001 From: lapuda <577732344@qq.com> Date: Sat, 27 Jun 2026 22:44:56 +0800 Subject: [PATCH] feat: Add Cross-Domain Job Fair and Alliance City Management - Implemented AppOutdoorFairController for outdoor job fair public H5 interfaces. - Created CrossCityAllianceController for managing cross-domain alliance cities. - Added CrossCityAlliance domain model and corresponding service and mapper. - Developed CrossDomainJobVO for aggregating job data across job fairs. - Created SQL scripts for initializing the cross-city alliance table and modifying the public job fair schema. - Added migration script for backing up and restoring the HighGo database schema. --- docs/app-outdoor-fair-h5-api.md | 65 +++ .../src/main/resources/application-local.yml | 8 +- .../static/h5/outdoor-fair/company.html | 299 +++++++++++++ .../static/h5/outdoor-fair/detail.html | 208 +++++++++ .../app/AppOutdoorFairController.java | 398 +++++++++++++++++ .../cms/CmsPublicJobFairController.java | 12 + .../cms/CrossCityAllianceController.java | 99 +++++ .../controller/cms/OutdoorFairController.java | 405 +++++++++++++++++- .../cms/OutdoorFairDeviceController.java | 19 +- .../ruoyi/cms/domain/CrossCityAlliance.java | 21 + .../com/ruoyi/cms/domain/FairCompany.java | 14 + .../main/java/com/ruoyi/cms/domain/Job.java | 13 + .../com/ruoyi/cms/domain/OutdoorFair.java | 29 ++ .../com/ruoyi/cms/domain/OutdoorFairJob.java | 20 + .../ruoyi/cms/domain/rc/CrossDomainJobVO.java | 65 +++ .../ruoyi/cms/domain/rc/PublicJobFair.java | 6 + .../cms/mapper/CrossCityAllianceMapper.java | 11 + .../cms/mapper/rc/PublicJobFairMapper.java | 5 + .../service/ICrossCityAllianceService.java | 17 + .../service/IOutdoorFairDeviceService.java | 11 +- .../impl/CrossCityAllianceServiceImpl.java | 29 ++ .../impl/OutdoorFairDeviceServiceImpl.java | 49 ++- .../cms/service/rc/IPublicJobFairService.java | 5 + .../rc/impl/PublicJobFairServiceImpl.java | 5 + .../mapper/app/OutdoorFairJobMapper.xml | 5 +- .../mapper/rc/PublicJobFairMapper.xml | 27 +- scripts/migrate-highgo-shz.sh | 100 +++++ sql/cms_cross_city_alliance.sql | 67 +++ sql/public_job_fair_cross_domain_cities.sql | 7 + 29 files changed, 1969 insertions(+), 50 deletions(-) create mode 100644 docs/app-outdoor-fair-h5-api.md create mode 100644 ruoyi-admin/src/main/resources/static/h5/outdoor-fair/company.html create mode 100644 ruoyi-admin/src/main/resources/static/h5/outdoor-fair/detail.html create mode 100644 ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/app/AppOutdoorFairController.java create mode 100644 ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/CrossCityAllianceController.java create mode 100644 ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/CrossCityAlliance.java create mode 100644 ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/rc/CrossDomainJobVO.java create mode 100644 ruoyi-bussiness/src/main/java/com/ruoyi/cms/mapper/CrossCityAllianceMapper.java create mode 100644 ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/ICrossCityAllianceService.java create mode 100644 ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/CrossCityAllianceServiceImpl.java create mode 100755 scripts/migrate-highgo-shz.sh create mode 100644 sql/cms_cross_city_alliance.sql create mode 100644 sql/public_job_fair_cross_domain_cities.sql diff --git a/docs/app-outdoor-fair-h5-api.md b/docs/app-outdoor-fair-h5-api.md new file mode 100644 index 0000000..cb00790 --- /dev/null +++ b/docs/app-outdoor-fair-h5-api.md @@ -0,0 +1,65 @@ +# 户外招聘会企业 H5 公共接口 + +基础路径:`/app/outdoor-fair` + +## 1. 扫码进入企业 H5 + +**请求方式:** `GET` + +**请求路径:** `/company-page` + +**请求参数:** + +| 参数 | 类型 | 必填 | 说明 | +| --- | --- | --- | --- | +| deviceCode | String | 是 | 后台设备码绑定企业后生成的扫码参数 | + +**响应字段:** + +| 字段 | 说明 | +| --- | --- | +| fair | 户外招聘会信息 | +| company | 企业信息 | +| booth | 企业展位信息,未分配展位时为空 | +| jobs | 当前企业在本场招聘会下的岗位列表 | +| fairH5Url | 本场招聘会 H5 链接 | +| companyH5Url | 当前企业 H5 链接 | +| qrCodeContent | 二维码内容,前端用该值生成二维码 | +| deviceId | 绑定设备码 ID | +| deviceCode | 绑定设备码 | + +## 2. 通过招聘会和企业获取 H5 数据 + +**请求方式:** `GET` + +**请求路径:** `/{fairId}/companies/{companyId}/page` + +用于未绑定设备码或后台预览企业 H5 页面。 + +## 3. 获取招聘会公共详情 + +**请求方式:** `GET` + +**请求路径:** `/{fairId}` + +返回 `fair` 和 `fairH5Url`。 + +## 4. 后台参会企业二维码入口 + +后台接口 `GET /cms/outdoor-fair/{fairId}/companies` 的每行企业现在额外返回: + +| 字段 | 说明 | +| --- | --- | +| deviceId | 已绑定设备码 ID,未绑定为空 | +| deviceCode | 已绑定设备码,未绑定为空 | +| h5Url | 企业 H5 链接,格式为 `/h5/outdoor-fair/company.html?fairId={fairId}&companyId={companyId}` | +| qrCodeContent | 二维码内容,前端点击“查看二维码”时用该值生成二维码 | + +也可以调用 `GET /cms/outdoor-fair/{fairId}/companies/{companyId}/qrcode` 单独获取某个参会企业的二维码内容。 + +## 5. 已提供的静态 H5 + +| 页面 | 说明 | +| --- | --- | +| `/h5/outdoor-fair/company.html?fairId={fairId}&companyId={companyId}` | 扫码后的参会企业公共页 | +| `/h5/outdoor-fair/detail.html?fairId={fairId}` | 招聘会公共详情页 | diff --git a/ruoyi-admin/src/main/resources/application-local.yml b/ruoyi-admin/src/main/resources/application-local.yml index a3c83d2..83d2353 100644 --- a/ruoyi-admin/src/main/resources/application-local.yml +++ b/ruoyi-admin/src/main/resources/application-local.yml @@ -20,12 +20,16 @@ spring: driverClassName: com.highgo.jdbc.Driver druid: # 主库数据源 + # master: + # url: jdbc:highgo://124.243.245.42:5866/shz?useUnicode=true&characterEncoding=utf8¤tSchema=shz&stringtype=unspecified + # #username: syssso + # username: sysdba + # password: ZKR2024@comzkr master: url: jdbc:highgo://39.98.44.136:6023/highgo?useUnicode=true&characterEncoding=utf8¤tSchema=shz&stringtype=unspecified #username: syssso username: sysdba password: Hello@2026 - # 从库数据源 slave: # 从数据源开关/默认关闭 @@ -86,7 +90,7 @@ spring: # 密码 password: ZKR2024@@.com # 连接超时时间 - timeout: 10s + timeout: 100s lettuce: pool: # 连接池中的最小空闲连接 diff --git a/ruoyi-admin/src/main/resources/static/h5/outdoor-fair/company.html b/ruoyi-admin/src/main/resources/static/h5/outdoor-fair/company.html new file mode 100644 index 0000000..f95904a --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/h5/outdoor-fair/company.html @@ -0,0 +1,299 @@ + + + + + + 参会企业 + + + +
+
正在加载...
+
+ + + diff --git a/ruoyi-admin/src/main/resources/static/h5/outdoor-fair/detail.html b/ruoyi-admin/src/main/resources/static/h5/outdoor-fair/detail.html new file mode 100644 index 0000000..17b4af7 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/h5/outdoor-fair/detail.html @@ -0,0 +1,208 @@ + + + + + + 户外招聘会 + + + +
+
正在加载...
+
+ + + diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/app/AppOutdoorFairController.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/app/AppOutdoorFairController.java new file mode 100644 index 0000000..0290a7f --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/app/AppOutdoorFairController.java @@ -0,0 +1,398 @@ +package com.ruoyi.cms.controller.app; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.ruoyi.cms.domain.FairCompany; +import com.ruoyi.cms.domain.Job; +import com.ruoyi.cms.domain.OutdoorFair; +import com.ruoyi.cms.domain.OutdoorFairAttendee; +import com.ruoyi.cms.domain.OutdoorFairBoothBooking; +import com.ruoyi.cms.domain.OutdoorFairDevice; +import com.ruoyi.cms.mapper.CompanyMapper; +import com.ruoyi.cms.mapper.FairCompanyMapper; +import com.ruoyi.cms.mapper.OutdoorFairBoothBookingMapper; +import com.ruoyi.cms.mapper.OutdoorFairDeviceMapper; +import com.ruoyi.cms.mapper.OutdoorFairJobMapper; +import com.ruoyi.cms.domain.rc.PublicJobFair; +import com.ruoyi.cms.domain.rc.PublicJobFairQuery; +import com.ruoyi.cms.domain.rc.PublicJobFairResponse; +import com.ruoyi.cms.service.IOutdoorFairAttendeeService; +import com.ruoyi.cms.service.IOutdoorFairService; +import com.ruoyi.common.annotation.BussinessLog; +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.exception.ServiceException; +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.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 移动端:户外招聘会公共 H5 接口。 + */ +@RestController +@RequestMapping("/app/outdoor-fair") +@Api(tags = "移动端:户外招聘会公共H5") +public class AppOutdoorFairController extends BaseController +{ + private static final String DAY_PATTERN = "yyyy-MM-dd"; + + @Autowired + private IOutdoorFairService outdoorFairService; + + @Autowired + private CompanyMapper companyMapper; + + @Autowired + private FairCompanyMapper fairCompanyMapper; + + @Autowired + private OutdoorFairDeviceMapper outdoorFairDeviceMapper; + + @Autowired + private OutdoorFairBoothBookingMapper outdoorFairBoothBookingMapper; + + @Autowired + private OutdoorFairJobMapper outdoorFairJobMapper; + + @Autowired + private IOutdoorFairAttendeeService outdoorFairAttendeeService; + + @BussinessLog(title = "户外招聘会列表") + @ApiOperation("分页查询户外招聘会列表") + @GetMapping("/page") + public PublicJobFairResponse page(PublicJobFairQuery query) + { + if (query == null) { + query = new PublicJobFairQuery(); + } + int pageNum = query.getPageNum() == null || query.getPageNum() < 1 ? 1 : query.getPageNum(); + int pageSize = query.getPageSize() == null || query.getPageSize() < 1 ? 10 : query.getPageSize(); + Page page = outdoorFairService.page(new Page<>(pageNum, pageSize), buildOutdoorFairWrapper(query)); + + PublicJobFairResponse response = new PublicJobFairResponse(); + response.setCode(200); + response.setMsg("查询成功"); + response.setData(buildPageData(page, pageNum, pageSize)); + return response; + } + + @BussinessLog(title = "查看当季度户外招聘会信息") + @ApiOperation("查看当季度户外招聘会信息") + @GetMapping("/currentQuarter") + public AjaxResult currentQuarterFairs() + { + Calendar calendar = Calendar.getInstance(); + int currentMonth = calendar.get(Calendar.MONTH); + int quarterStartMonth = currentMonth / 3 * 3; + calendar.set(Calendar.MONTH, quarterStartMonth); + calendar.set(Calendar.DAY_OF_MONTH, 1); + setStartOfDay(calendar); + Date startTime = calendar.getTime(); + + calendar.add(Calendar.MONTH, 3); + Date endTime = calendar.getTime(); + + return success(listOutdoorFairsByRange(startTime, endTime)); + } + + @BussinessLog(title = "查看当月户外招聘会信息") + @ApiOperation("查看当月户外招聘会信息") + @GetMapping("/currentMonth") + public AjaxResult currentMonthFairs() + { + Calendar calendar = Calendar.getInstance(); + calendar.set(Calendar.DAY_OF_MONTH, 1); + setStartOfDay(calendar); + Date startTime = calendar.getTime(); + + calendar.add(Calendar.MONTH, 1); + Date endTime = calendar.getTime(); + + return success(listOutdoorFairsByRange(startTime, endTime)); + } + + @BussinessLog(title = "查询有户外招聘会的日期列表") + @ApiOperation("查询有户外招聘会的日期列表") + @GetMapping("/dates") + public AjaxResult dates() + { + List dates = outdoorFairService.list(new LambdaQueryWrapper() + .isNotNull(OutdoorFair::getHoldTime) + .orderByAsc(OutdoorFair::getHoldTime)) + .stream() + .map(OutdoorFair::getHoldTime) + .map(AppOutdoorFairController::formatDay) + .distinct() + .collect(Collectors.toList()); + return success(dates); + } + + @BussinessLog(title = "户外招聘会企业H5详情") + @ApiOperation("通过设备码获取户外招聘会企业H5详情") + @GetMapping("/company-page") + public AjaxResult companyPageByDeviceCode(@RequestParam String deviceCode, HttpServletRequest request) + { + if (StringUtils.isBlank(deviceCode)) { + return AjaxResult.error("设备码不能为空"); + } + OutdoorFairDevice device = outdoorFairDeviceMapper.selectOne(new LambdaQueryWrapper() + .eq(OutdoorFairDevice::getDeviceCode, deviceCode) + .last("LIMIT 1")); + if (device == null || device.getCompanyId() == null) { + return AjaxResult.error("设备码未绑定参会企业"); + } + return success(buildCompanyPage(device.getFairId(), device.getCompanyId(), device, request)); + } + + @BussinessLog(title = "户外招聘会企业H5详情") + @ApiOperation("通过招聘会ID和企业ID获取户外招聘会企业H5详情") + @GetMapping("/{fairId}/companies/{companyId}/page") + public AjaxResult companyPage(@PathVariable Long fairId, @PathVariable Long companyId, + HttpServletRequest request) + { + OutdoorFairDevice device = outdoorFairDeviceMapper.selectOne(new LambdaQueryWrapper() + .eq(OutdoorFairDevice::getFairId, fairId) + .eq(OutdoorFairDevice::getCompanyId, companyId) + .last("LIMIT 1")); + return success(buildCompanyPage(fairId, companyId, device, request)); + } + + @BussinessLog(title = "户外招聘会详情") + @ApiOperation("获取户外招聘会公共详情") + @GetMapping("/{fairId}") + public AjaxResult detail(@PathVariable Long fairId, HttpServletRequest request) + { + OutdoorFair fair = outdoorFairService.getById(fairId); + if (fair == null) { + return AjaxResult.error("招聘会不存在"); + } + Map data = new HashMap<>(); + data.put("fair", fair); + data.put("fairH5Url", buildFairH5Url(request, fairId)); + return success(data); + } + + /** + * 匿名签到(姓名+手机号)。H5 企业页调用,无需登录。 + */ + @BussinessLog(title = "户外招聘会企业H5签到") + @ApiOperation("匿名签到(姓名+手机号)") + @PostMapping("/check-in") + public AjaxResult checkIn(@RequestBody OutdoorFairAttendee attendee) + { + if (attendee.getFairId() == null) { + return AjaxResult.error("缺少招聘会参数"); + } + if (StringUtils.isBlank(attendee.getName())) { + return AjaxResult.error("姓名不能为空"); + } + if (StringUtils.isBlank(attendee.getPhone())) { + return AjaxResult.error("手机号不能为空"); + } + // 同一招聘会下同手机号已签到则不重复记录 + Long exists = outdoorFairAttendeeService.count(new LambdaQueryWrapper() + .eq(OutdoorFairAttendee::getFairId, attendee.getFairId()) + .eq(OutdoorFairAttendee::getPhone, attendee.getPhone())); + if (exists != null && exists > 0) { + return AjaxResult.error("该手机号已签到"); + } + attendee.setCheckInTime(new Date()); + return toAjax(outdoorFairAttendeeService.save(attendee)); + } + + private Map buildCompanyPage(Long fairId, Long companyId, OutdoorFairDevice device, + HttpServletRequest request) + { + OutdoorFair fair = outdoorFairService.getById(fairId); + if (fair == null) { + throw new ServiceException("招聘会不存在"); + } + Company company = companyMapper.selectById(companyId); + if (company == null) { + throw new ServiceException("企业不存在"); + } + Long relationCount = fairCompanyMapper.selectCount(new LambdaQueryWrapper() + .eq(FairCompany::getJobFairId, fairId) + .eq(FairCompany::getCompanyId, companyId)); + if (relationCount == null || relationCount == 0) { + throw new ServiceException("该企业未参加当前招聘会"); + } + OutdoorFairBoothBooking booking = outdoorFairBoothBookingMapper.selectOne( + new LambdaQueryWrapper() + .eq(OutdoorFairBoothBooking::getFairId, fairId) + .eq(OutdoorFairBoothBooking::getCompanyId, companyId) + .eq(OutdoorFairBoothBooking::getStatus, "reserved") + .last("LIMIT 1")); + List jobs = outdoorFairJobMapper.selectFairJobPage( + fairId, companyId, null, null, null, null, 0, 200); + + String companyH5Url = buildCompanyH5Url(request, fairId, companyId); + Map data = new HashMap<>(); + data.put("fair", fair); + data.put("company", company); + data.put("booth", booking); + data.put("jobs", jobs); + data.put("fairH5Url", buildFairH5Url(request, fairId)); + data.put("companyH5Url", companyH5Url); + data.put("qrCodeContent", companyH5Url); + data.put("deviceId", device == null ? null : device.getId()); + data.put("deviceCode", device == null ? null : device.getDeviceCode()); + return data; + } + + private String buildCompanyH5Url(HttpServletRequest request, Long fairId, Long companyId) + { + String baseUrl = buildBaseUrl(request); + return baseUrl + "/h5/outdoor-fair/company.html?fairId=" + fairId + "&companyId=" + companyId; + } + + private String buildFairH5Url(HttpServletRequest request, Long fairId) + { + return buildBaseUrl(request) + "/h5/outdoor-fair/detail.html?fairId=" + fairId; + } + + private LambdaQueryWrapper buildOutdoorFairWrapper(PublicJobFairQuery query) + { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + if (query != null && StringUtils.isNotBlank(query.getJobFairTitle())) { + wrapper.like(OutdoorFair::getTitle, query.getJobFairTitle()); + } + if (query != null && StringUtils.isNotBlank(query.getZphjbsj())) { + Date[] dayRange = parseDayRange(query.getZphjbsj()); + if (dayRange != null) { + wrapper.lt(OutdoorFair::getHoldTime, dayRange[1]) + .and(w -> w.isNull(OutdoorFair::getEndTime) + .or() + .ge(OutdoorFair::getEndTime, dayRange[0])); + } + } + wrapper.orderByDesc(OutdoorFair::getHoldTime) + .orderByDesc(OutdoorFair::getCreateTime); + return wrapper; + } + + private PublicJobFairResponse.PageData buildPageData(Page page, int pageNum, int pageSize) + { + PublicJobFairResponse.PageData data = new PublicJobFairResponse.PageData(); + List list = page.getRecords().stream() + .map(this::buildPublicJobFair) + .collect(Collectors.toList()); + int pages = (int) page.getPages(); + data.setTotal(page.getTotal()); + data.setList(list); + data.setPageNum(pageNum); + data.setPageSize(pageSize); + data.setSize(list.size()); + data.setStartRow(list.isEmpty() ? 0 : (pageNum - 1) * pageSize + 1); + data.setEndRow(list.isEmpty() ? 0 : (pageNum - 1) * pageSize + list.size()); + data.setPages(pages); + data.setPrePage(pageNum > 1 ? pageNum - 1 : 0); + data.setNextPage(pageNum < pages ? pageNum + 1 : 0); + data.setIsFirstPage(pageNum <= 1); + data.setIsLastPage(pageNum >= pages); + data.setHasPreviousPage(pageNum > 1); + data.setHasNextPage(pageNum < pages); + data.setNavigatePages(8); + data.setNavigatepageNums(buildNavigatePageNums(pages)); + data.setNavigateFirstPage(pages > 0 ? 1 : 0); + data.setNavigateLastPage(pages); + return data; + } + + private List buildNavigatePageNums(int pages) + { + List pageNums = new ArrayList<>(); + for (int i = 1; i <= pages; i++) { + pageNums.add(i); + } + return pageNums; + } + + private List listOutdoorFairsByRange(Date startTime, Date endTime) + { + return outdoorFairService.list(new LambdaQueryWrapper() + .ge(OutdoorFair::getHoldTime, startTime) + .lt(OutdoorFair::getHoldTime, endTime) + .orderByAsc(OutdoorFair::getHoldTime)) + .stream() + .map(this::buildPublicJobFair) + .collect(Collectors.toList()); + } + + private PublicJobFair buildPublicJobFair(OutdoorFair fair) + { + PublicJobFair jobFair = new PublicJobFair(); + jobFair.setJobFairId(String.valueOf(fair.getId())); + jobFair.setJobFairTitle(fair.getTitle()); + jobFair.setJobFairAddress(StringUtils.isNotBlank(fair.getAddress()) ? fair.getAddress() : fair.getVenueName()); + jobFair.setJobFairType("outdoor"); + jobFair.setJobFairStartTime(fair.getHoldTime()); + jobFair.setJobFairEndTime(fair.getEndTime()); + jobFair.setJobFairHostUnit(fair.getHostUnit()); + jobFair.setJobFairOrganizeUnit(fair.getHostUnit()); + jobFair.setJobFairIntroduction(StringUtils.isNotBlank(fair.getVenueName()) ? fair.getVenueName() : fair.getAddress()); + jobFair.setJobFairImage(fair.getPhotoUrl()); + jobFair.setJobFairSignUpStartTime(fair.getApplyStartTime()); + jobFair.setJobFairSignUpEndTime(fair.getApplyEndTime()); + jobFair.setJobFairVenueId(fair.getVenueId() == null ? null : String.valueOf(fair.getVenueId())); + jobFair.setBoothNum(fair.getBoothCount() == null ? null : String.valueOf(fair.getBoothCount())); + return jobFair; + } + + private Date[] parseDayRange(String day) + { + try { + Date startTime = new SimpleDateFormat(DAY_PATTERN).parse(day); + Calendar calendar = Calendar.getInstance(); + calendar.setTime(startTime); + calendar.add(Calendar.DAY_OF_MONTH, 1); + return new Date[]{startTime, calendar.getTime()}; + } catch (ParseException e) { + return null; + } + } + + private static String formatDay(Date date) + { + return new SimpleDateFormat(DAY_PATTERN).format(date); + } + + private void setStartOfDay(Calendar calendar) + { + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + } + + private String buildBaseUrl(HttpServletRequest request) + { + String baseUrl = request.getScheme() + "://" + request.getServerName(); + int port = request.getServerPort(); + if (port != 80 && port != 443) { + baseUrl += ":" + port; + } + return baseUrl + (request.getContextPath() == null ? "" : request.getContextPath()); + } + +} diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/CmsPublicJobFairController.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/CmsPublicJobFairController.java index f18647e..e61b6ef 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/CmsPublicJobFairController.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/CmsPublicJobFairController.java @@ -39,6 +39,18 @@ public class CmsPublicJobFairController extends BaseController { return getDataTable(list); } + /** + * 查询跨域招聘会下的岗位(可按联盟城市过滤,cityNames 为逗号分隔的城市名称) + */ + @ApiOperation("跨域招聘会岗位列表") + @PreAuthorize("@ss.hasPermi('cms:crossCityFair:list')") + @GetMapping("/cross-domain-jobs") + public TableDataInfo crossDomainJobs(@RequestParam(required = false) String cityNames) { + startPage(); + List list = publicJobFairService.selectCrossDomainJobs(cityNames); + return getDataTable(list); + } + /** * 获取招聘会详情 */ diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/CrossCityAllianceController.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/CrossCityAllianceController.java new file mode 100644 index 0000000..613fff9 --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/CrossCityAllianceController.java @@ -0,0 +1,99 @@ +package com.ruoyi.cms.controller.cms; + +import java.util.Arrays; +import java.util.List; + +import com.ruoyi.cms.domain.CrossCityAlliance; +import com.ruoyi.cms.service.ICrossCityAllianceService; +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 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.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-27 + */ +@RestController +@RequestMapping("/cms/cross-city-alliance") +@Api(tags = "后台:跨域联合招聘会-联盟城市") +public class CrossCityAllianceController extends BaseController +{ + @Autowired + private ICrossCityAllianceService crossCityAllianceService; + + /** + * 查询联盟城市列表(支持按城市名称模糊查询) + */ + @ApiOperation("查询联盟城市列表") + @PreAuthorize("@ss.hasPermi('cms:crossCityFair:list')") + @GetMapping("/list") + public TableDataInfo list(CrossCityAlliance query) + { + startPage(); + List list = crossCityAllianceService.selectAllianceList(query); + return getDataTable(list); + } + + /** + * 获取联盟城市详细信息 + */ + @ApiOperation("获取联盟城市详细信息") + @PreAuthorize("@ss.hasPermi('cms:crossCityFair:query')") + @GetMapping("/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) + { + return success(crossCityAllianceService.getById(id)); + } + + /** + * 新增联盟城市 + */ + @ApiOperation("新增联盟城市") + @PreAuthorize("@ss.hasPermi('cms:crossCityFair:add')") + @Log(title = "跨域联合招聘会-联盟城市", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody CrossCityAlliance alliance) + { + return toAjax(crossCityAllianceService.save(alliance)); + } + + /** + * 修改联盟城市 + */ + @ApiOperation("修改联盟城市") + @PreAuthorize("@ss.hasPermi('cms:crossCityFair:edit')") + @Log(title = "跨域联合招聘会-联盟城市", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody CrossCityAlliance alliance) + { + return toAjax(crossCityAllianceService.updateById(alliance)); + } + + /** + * 删除联盟城市 + */ + @ApiOperation("删除联盟城市") + @PreAuthorize("@ss.hasPermi('cms:crossCityFair:remove')") + @Log(title = "跨域联合招聘会-联盟城市", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) + { + return toAjax(crossCityAllianceService.removeByIds(Arrays.asList(ids))); + } +} diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/OutdoorFairController.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/OutdoorFairController.java index 3f85249..201a78a 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/OutdoorFairController.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/OutdoorFairController.java @@ -23,24 +23,31 @@ import com.ruoyi.cms.domain.Job; import com.ruoyi.cms.domain.OutdoorFair; import com.ruoyi.cms.domain.OutdoorFairBooth; import com.ruoyi.cms.domain.OutdoorFairBoothBooking; +import com.ruoyi.cms.domain.OutdoorFairDevice; import com.ruoyi.cms.domain.OutdoorFairDictDataRequest; import com.ruoyi.cms.domain.OutdoorFairJob; import com.ruoyi.cms.domain.VenueInfo; import com.ruoyi.cms.mapper.FairCompanyMapper; import com.ruoyi.cms.mapper.OutdoorFairBoothMapper; import com.ruoyi.cms.mapper.OutdoorFairBoothBookingMapper; +import com.ruoyi.cms.mapper.OutdoorFairDeviceMapper; import com.ruoyi.cms.mapper.OutdoorFairJobMapper; import com.ruoyi.cms.mapper.CompanyMapper; +import com.ruoyi.cms.service.ICompanyService; import com.ruoyi.cms.service.IJobService; import com.ruoyi.cms.service.IOutdoorFairService; import com.ruoyi.cms.service.IVenueInfoService; +import com.ruoyi.cms.util.RoleUtils; 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.domain.entity.SysUser; +import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.StringUtils; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -58,6 +65,8 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import javax.servlet.http.HttpServletRequest; + /** * 户外招聘会Controller * @@ -90,19 +99,27 @@ public class OutdoorFairController extends BaseController @Autowired private OutdoorFairJobMapper outdoorFairJobMapper; + @Autowired + private OutdoorFairDeviceMapper outdoorFairDeviceMapper; + @Autowired private IJobService jobService; + @Autowired + private ICompanyService companyService; + /** * 查询户外招聘会列表 */ @ApiOperation("查询户外招聘会列表") @PreAuthorize("@ss.hasPermi('cms:outdoorFair:list')") @GetMapping("/list") - public TableDataInfo list(OutdoorFair outdoorFair) + public TableDataInfo list(OutdoorFair outdoorFair, HttpServletRequest request) { + Company company = RoleUtils.isCompanyAdmin() ? getCurrentCompanyOrNull() : null; startPage(); List list = outdoorFairService.selectOutdoorFairList(outdoorFair); + fillCompanyApplyState(list, request, company); return getDataTable(list); } @@ -114,6 +131,9 @@ public class OutdoorFairController extends BaseController @GetMapping(value = "/{id}") public AjaxResult getInfo(@PathVariable("id") Long id) { + if (RoleUtils.isCompanyAdmin()) { + return AjaxResult.error("企业用户无权查看招聘会详情"); + } return success(outdoorFairService.getById(id)); } @@ -346,6 +366,9 @@ public class OutdoorFairController extends BaseController @PostMapping public AjaxResult add(@RequestBody OutdoorFair outdoorFair) { + if (RoleUtils.isCompanyAdmin()) { + return AjaxResult.error("企业用户无权新增户外招聘会"); + } fillVenueFields(outdoorFair); boolean saved = outdoorFairService.save(outdoorFair); if (saved) { @@ -364,6 +387,9 @@ public class OutdoorFairController extends BaseController @PutMapping public AjaxResult edit(@RequestBody OutdoorFair outdoorFair) { + if (RoleUtils.isCompanyAdmin()) { + return AjaxResult.error("企业用户无权编辑户外招聘会"); + } OutdoorFair oldFair = outdoorFair.getId() == null ? null : outdoorFairService.getById(outdoorFair.getId()); fillVenueFields(outdoorFair); boolean updated = outdoorFairService.updateById(outdoorFair); @@ -383,6 +409,9 @@ public class OutdoorFairController extends BaseController @DeleteMapping("/{ids}") public AjaxResult remove(@PathVariable Long[] ids) { + if (RoleUtils.isCompanyAdmin()) { + return AjaxResult.error("企业用户无权删除户外招聘会"); + } return toAjax(outdoorFairService.removeByIds(Arrays.asList(ids))); } @@ -395,23 +424,60 @@ public class OutdoorFairController extends BaseController @PostMapping("/dict-data") public AjaxResult addDictData(@Validated @RequestBody OutdoorFairDictDataRequest request) { + if (RoleUtils.isCompanyAdmin()) { + return AjaxResult.error("企业用户无权维护户外招聘会字典"); + } return toAjax(outdoorFairService.insertOutdoorFairDictData(request.getDictType(), request.getDictLabel(), getUsername())); } + @ApiOperation("企业报名户外招聘会") + @PreAuthorize("@ss.hasPermi('cms:outdoorFair:list')") + @PostMapping("/{fairId}/company/signup") + @Transactional(rollbackFor = Exception.class) + public AjaxResult signupCompany(@PathVariable Long fairId, HttpServletRequest request) + { + Company company = getCurrentCompanyOrThrow(); + ensureFairExists(fairId); + FairCompany relation = ensureFairCompany(fairId, company.getCompanyId(), "0"); + Map data = buildCompanyQrCodeData(request, fairId, company.getCompanyId()); + data.put("companyName", company.getName()); + data.put("signedUp", true); + data.put("reviewStatus", relation.getReviewStatus()); + data.put("reviewRemark", relation.getReviewRemark()); + return success(data); + } + + @ApiOperation("获取当前企业户外招聘会二维码内容") + @PreAuthorize("@ss.hasPermi('cms:outdoorFair:list')") + @GetMapping("/{fairId}/company/qrcode") + public AjaxResult getCurrentCompanyQrCode(@PathVariable Long fairId, HttpServletRequest request) + { + Company company = getCurrentCompanyOrThrow(); + ensureFairCompanyExists(fairId, company.getCompanyId()); + ensureFairCompanyApprovedIfCompany(fairId, company.getCompanyId()); + return success(buildCompanyQrCodeData(request, fairId, company.getCompanyId())); + } + @ApiOperation("查询户外招聘会参会企业") @PreAuthorize("@ss.hasPermi('cms:outdoorFair:query')") @GetMapping("/{fairId}/companies") public AjaxResult listCompanies(@PathVariable Long fairId, String companyName, - Integer current, Integer pageSize) + Integer current, Integer pageSize, + HttpServletRequest request) { - List relations = fairCompanyMapper.selectList(new LambdaQueryWrapper() + LambdaQueryWrapper relationWrapper = new LambdaQueryWrapper() .eq(FairCompany::getJobFairId, fairId) - .orderByDesc(FairCompany::getId)); + .orderByDesc(FairCompany::getId); + if (RoleUtils.isCompanyAdmin()) { + Company company = getCurrentCompanyOrNull(); + if (company == null) { + return emptyAjaxPage(); + } + relationWrapper.eq(FairCompany::getCompanyId, company.getCompanyId()); + } + List relations = fairCompanyMapper.selectList(relationWrapper); if (relations.isEmpty()) { - AjaxResult result = AjaxResult.success(); - result.put("rows", new ArrayList<>()); - result.put("total", 0); - return result; + return emptyAjaxPage(); } List companyIds = relations.stream().map(FairCompany::getCompanyId).collect(Collectors.toList()); @@ -428,6 +494,11 @@ public class OutdoorFairController extends BaseController item -> Long.valueOf(String.valueOf(item.get("companyId"))), item -> Long.valueOf(String.valueOf(item.get("jobCount"))), (a, b) -> a)); + Map deviceMap = outdoorFairDeviceMapper.selectList(new LambdaQueryWrapper() + .eq(OutdoorFairDevice::getFairId, fairId) + .isNotNull(OutdoorFairDevice::getCompanyId)) + .stream() + .collect(Collectors.toMap(OutdoorFairDevice::getCompanyId, item -> item, (a, b) -> a)); List> rows = new ArrayList<>(); for (FairCompany relation : relations) { @@ -451,6 +522,16 @@ public class OutdoorFairController extends BaseController row.put("boothId", booking == null ? null : booking.getBoothId()); row.put("boothNumber", booking == null ? null : booking.getBoothNumber()); row.put("jobCount", jobCountMap.getOrDefault(company.getCompanyId(), 0L)); + row.put("reviewStatus", relation.getReviewStatus()); + row.put("reviewBy", relation.getReviewBy()); + row.put("reviewTime", relation.getReviewTime()); + row.put("reviewRemark", relation.getReviewRemark()); + OutdoorFairDevice device = deviceMap.get(company.getCompanyId()); + String h5Url = buildOutdoorFairCompanyH5Url(request, fairId, company.getCompanyId()); + row.put("deviceId", device == null ? null : device.getId()); + row.put("deviceCode", device == null ? null : device.getDeviceCode()); + row.put("h5Url", h5Url); + row.put("qrCodeContent", h5Url); rows.add(row); } @@ -465,13 +546,30 @@ public class OutdoorFairController extends BaseController return result; } - @ApiOperation("分页查询户外招聘会参会岗位") + @ApiOperation("获取户外招聘会参会企业二维码内容") @PreAuthorize("@ss.hasPermi('cms:outdoorFair:query')") + @GetMapping("/{fairId}/companies/{companyId}/qrcode") + public AjaxResult getCompanyQrCode(@PathVariable Long fairId, @PathVariable Long companyId, + HttpServletRequest request) + { + ensureCurrentCompanyIfNeeded(companyId); + ensureFairCompanyExists(fairId, companyId); + ensureFairCompanyApprovedIfCompany(fairId, companyId); + return success(buildCompanyQrCodeData(request, fairId, companyId)); + } + + @ApiOperation("分页查询户外招聘会参会岗位") + @PreAuthorize("@ss.hasAnyPermi('cms:outdoorFair:list,cms:outdoorFair:query')") @GetMapping("/{fairId}/jobs") public AjaxResult listJobs(@PathVariable Long fairId, Long companyId, String companyName, String jobTitle, String education, String experience, Integer current, Integer pageSize) { + if (RoleUtils.isCompanyAdmin()) { + Company company = getCurrentCompanyOrThrow(); + companyId = company.getCompanyId(); + companyName = null; + } int page = current == null || current < 1 ? 1 : current; int size = pageSize == null || pageSize < 1 ? 10 : Math.min(pageSize, 100); int offset = (page - 1) * size; @@ -491,14 +589,29 @@ public class OutdoorFairController extends BaseController public AjaxResult getCompanyJob(@PathVariable Long fairId, @PathVariable Long jobId) { ensureFairJobExists(fairId, jobId); + ensureFairJobBelongsToCurrentCompanyIfNeeded(fairId, jobId); return success(jobService.selectJobByJobId(jobId)); } + @ApiOperation("当前企业新增户外招聘会岗位") + @PreAuthorize("@ss.hasPermi('cms:outdoorFair:list')") + @Transactional(rollbackFor = Exception.class) + @PostMapping("/{fairId}/company/jobs") + public AjaxResult addCurrentCompanyJob(@PathVariable Long fairId, @RequestBody Job job) + { + Company company = getCurrentCompanyOrThrow(); + ensureFairCompanyApprovedIfCompany(fairId, company.getCompanyId()); + return addCompanyJobInternal(fairId, company.getCompanyId(), job); + } + @ApiOperation("新增户外招聘会参会企业") @PreAuthorize("@ss.hasPermi('cms:outdoorFair:edit')") @PostMapping("/{fairId}/companies") public AjaxResult addCompany(@PathVariable Long fairId, @RequestBody Map request) { + if (RoleUtils.isCompanyAdmin()) { + return AjaxResult.error("企业用户请使用报名入口"); + } Long companyId = Long.valueOf(String.valueOf(request.get("companyId"))); Company company = companyMapper.selectById(companyId); if (company == null || company.getStatus() == null || company.getStatus() != 1) { @@ -508,12 +621,36 @@ public class OutdoorFairController extends BaseController return success(); } + @ApiOperation("审核户外招聘会参会企业") + @PreAuthorize("@ss.hasPermi('cms:outdoorFair:edit')") + @PutMapping("/{fairId}/companies/{id}/review") + public AjaxResult reviewCompany(@PathVariable Long fairId, @PathVariable Long id, + @RequestBody Map request) + { + String reviewStatus = String.valueOf(request.get("reviewStatus")); + validateReviewStatus(reviewStatus); + FairCompany relation = fairCompanyMapper.selectById(id); + if (relation == null || !fairId.equals(relation.getJobFairId())) { + return AjaxResult.error("参会企业不存在"); + } + String reviewRemark = request.get("reviewRemark") == null ? null : String.valueOf(request.get("reviewRemark")); + validateRejectRemark(reviewStatus, reviewRemark); + relation.setReviewStatus(reviewStatus); + relation.setReviewBy(getUsername()); + relation.setReviewTime(new Date()); + relation.setReviewRemark(reviewRemark); + return toAjax(fairCompanyMapper.updateById(relation)); + } + @ApiOperation("移除户外招聘会参会企业") @PreAuthorize("@ss.hasPermi('cms:outdoorFair:edit')") @DeleteMapping("/{fairId}/companies/{id}") @Transactional(rollbackFor = Exception.class) public AjaxResult removeCompany(@PathVariable Long fairId, @PathVariable Long id) { + if (RoleUtils.isCompanyAdmin()) { + return AjaxResult.error("企业用户无权移除参会企业"); + } FairCompany relation = fairCompanyMapper.selectById(id); if (relation == null || !fairId.equals(relation.getJobFairId())) { return AjaxResult.error("参会企业不存在"); @@ -530,9 +667,19 @@ public class OutdoorFairController extends BaseController @PostMapping("/{fairId}/companies/{companyId}/jobs") public AjaxResult addCompanyJob(@PathVariable Long fairId, @PathVariable Long companyId, @RequestBody Job job) + { + ensureCurrentCompanyIfNeeded(companyId); + ensureFairCompanyApprovedIfCompany(fairId, companyId); + return addCompanyJobInternal(fairId, companyId, job); + } + + private AjaxResult addCompanyJobInternal(Long fairId, Long companyId, Job job) { ensureFairCompanyExists(fairId, companyId); Company company = companyMapper.selectById(companyId); + if (company == null) { + return AjaxResult.error("企业不存在"); + } job.setCompanyId(companyId); job.setCompanyName(company.getName()); if (job.getIsPublish() == null) { @@ -546,6 +693,7 @@ public class OutdoorFairController extends BaseController relation.setFairId(fairId); relation.setCompanyId(companyId); relation.setJobId(job.getJobId()); + relation.setReviewStatus(RoleUtils.isCompanyAdmin() ? "0" : "1"); relation.setCreateBy(getUsername()); outdoorFairJobMapper.insert(relation); return success(job); @@ -558,6 +706,7 @@ public class OutdoorFairController extends BaseController @RequestBody Job job) { ensureFairJobExists(fairId, jobId); + ensureFairJobBelongsToCurrentCompanyIfNeeded(fairId, jobId); job.setJobId(jobId); // 当前弹窗不修改发布状态,避免重复触发岗位发布流程。 job.setIsPublish(null); @@ -571,12 +720,37 @@ public class OutdoorFairController extends BaseController public AjaxResult removeCompanyJob(@PathVariable Long fairId, @PathVariable Long jobId) { ensureFairJobExists(fairId, jobId); + ensureFairJobBelongsToCurrentCompanyIfNeeded(fairId, jobId); outdoorFairJobMapper.delete(new LambdaQueryWrapper() .eq(OutdoorFairJob::getFairId, fairId) .eq(OutdoorFairJob::getJobId, jobId)); return toAjax(jobService.deleteJobByJobIds(new Long[]{jobId})); } + @ApiOperation("审核户外招聘会岗位") + @PreAuthorize("@ss.hasPermi('cms:outdoorFair:edit')") + @PutMapping("/{fairId}/jobs/{jobId}/review") + public AjaxResult reviewCompanyJob(@PathVariable Long fairId, @PathVariable Long jobId, + @RequestBody Map request) + { + String reviewStatus = String.valueOf(request.get("reviewStatus")); + validateReviewStatus(reviewStatus); + OutdoorFairJob relation = outdoorFairJobMapper.selectOne(new LambdaQueryWrapper() + .eq(OutdoorFairJob::getFairId, fairId) + .eq(OutdoorFairJob::getJobId, jobId) + .last("LIMIT 1")); + if (relation == null) { + return AjaxResult.error("当前招聘会不存在该岗位"); + } + String reviewRemark = request.get("reviewRemark") == null ? null : String.valueOf(request.get("reviewRemark")); + validateRejectRemark(reviewStatus, reviewRemark); + relation.setReviewStatus(reviewStatus); + relation.setReviewBy(getUsername()); + relation.setReviewTime(new Date()); + relation.setReviewRemark(reviewRemark); + return toAjax(outdoorFairJobMapper.updateById(relation)); + } + private void ensureFairCompanyExists(Long fairId, Long companyId) { Long count = fairCompanyMapper.selectCount(new LambdaQueryWrapper() @@ -587,6 +761,30 @@ public class OutdoorFairController extends BaseController } } + private void ensureFairCompanyApprovedIfCompany(Long fairId, Long companyId) + { + if (!RoleUtils.isCompanyAdmin()) { + return; + } + FairCompany relation = fairCompanyMapper.selectOne(new LambdaQueryWrapper() + .eq(FairCompany::getJobFairId, fairId) + .eq(FairCompany::getCompanyId, companyId) + .last("LIMIT 1")); + if (relation == null) { + throw new ServiceException("该企业未参加当前招聘会"); + } + if (!"1".equals(relation.getReviewStatus())) { + throw new ServiceException("报名审核通过后才能操作"); + } + } + + private void ensureFairExists(Long fairId) + { + if (fairId == null || outdoorFairService.getById(fairId) == null) { + throw new ServiceException("户外招聘会不存在"); + } + } + private void ensureFairJobExists(Long fairId, Long jobId) { Long count = outdoorFairJobMapper.selectCount(new LambdaQueryWrapper() @@ -597,18 +795,171 @@ public class OutdoorFairController extends BaseController } } + private void ensureFairJobBelongsToCurrentCompanyIfNeeded(Long fairId, Long jobId) + { + if (!RoleUtils.isCompanyAdmin()) { + return; + } + Company company = getCurrentCompanyOrThrow(); + Long count = outdoorFairJobMapper.selectCount(new LambdaQueryWrapper() + .eq(OutdoorFairJob::getFairId, fairId) + .eq(OutdoorFairJob::getJobId, jobId) + .eq(OutdoorFairJob::getCompanyId, company.getCompanyId())); + if (count == null || count == 0) { + throw new ServiceException("只能维护本企业报名岗位"); + } + } + + private void ensureCurrentCompanyIfNeeded(Long companyId) + { + if (!RoleUtils.isCompanyAdmin()) { + return; + } + Company company = getCurrentCompanyOrThrow(); + if (!company.getCompanyId().equals(companyId)) { + throw new ServiceException("只能维护本企业报名信息"); + } + } + + private Company getCurrentCompanyOrThrow() + { + Company company = getCurrentCompanyOrNull(); + if (company == null) { + throw new ServiceException("未查询到当前登录企业信息"); + } + return company; + } + + private Company getCurrentCompanyOrNull() + { + if (!RoleUtils.isCompanyAdmin()) { + return null; + } + LoginUser loginUser = SecurityUtils.getLoginUser(); + if (loginUser == null || loginUser.getUser() == null) { + return null; + } + + SysUser sysUser = loginUser.getUser(); + Company company = null; + if (StringUtils.isNotBlank(sysUser.getIdCard())) { + company = companyService.queryCodeCompany(sysUser.getIdCard()); + if (company != null) { + return company; + } + } + + Long userId = loginUser.getUserId() == null ? sysUser.getUserId() : loginUser.getUserId(); + if (userId != null) { + company = companyMapper.selectOne(new LambdaQueryWrapper() + .eq(Company::getUserId, userId) + .eq(Company::getDelFlag, "0") + .orderByDesc(Company::getUpdateTime) + .last("LIMIT 1")); + if (company != null) { + return company; + } + } + + List companyNames = new ArrayList<>(); + if (StringUtils.isNotBlank(sysUser.getNickName())) { + companyNames.add(sysUser.getNickName()); + } + if (StringUtils.isNotBlank(sysUser.getUserName()) && !companyNames.contains(sysUser.getUserName())) { + companyNames.add(sysUser.getUserName()); + } + if (!companyNames.isEmpty()) { + List companies = companyMapper.selectList(new LambdaQueryWrapper() + .in(Company::getName, companyNames) + .eq(Company::getStatus, 1) + .eq(Company::getDelFlag, "0") + .orderByDesc(Company::getUpdateTime)); + if (companies.size() == 1) { + return companies.get(0); + } + } + return null; + } + + private void fillCompanyApplyState(List list, HttpServletRequest request, Company company) + { + if (!RoleUtils.isCompanyAdmin() || list == null || list.isEmpty()) { + return; + } + if (company == null) { + for (OutdoorFair fair : list) { + fair.setSignedUp(false); + } + return; + } + List fairIds = list.stream().map(OutdoorFair::getId).collect(Collectors.toList()); + Map relationMap = fairCompanyMapper.selectList(new LambdaQueryWrapper() + .in(FairCompany::getJobFairId, fairIds) + .eq(FairCompany::getCompanyId, company.getCompanyId())) + .stream() + .collect(Collectors.toMap(FairCompany::getJobFairId, item -> item, (a, b) -> a)); + for (OutdoorFair fair : list) { + FairCompany relation = relationMap.get(fair.getId()); + boolean signedUp = relation != null; + fair.setCompanyId(company.getCompanyId()); + fair.setCompanyName(company.getName()); + fair.setSignedUp(signedUp); + fair.setReviewStatus(relation == null ? null : relation.getReviewStatus()); + fair.setReviewRemark(relation == null ? null : relation.getReviewRemark()); + if (signedUp) { + String h5Url = buildOutdoorFairCompanyH5Url(request, fair.getId(), company.getCompanyId()); + fair.setH5Url(h5Url); + fair.setQrCodeContent(h5Url); + } + } + } + + private AjaxResult emptyAjaxPage() + { + AjaxResult result = AjaxResult.success(); + result.put("rows", new ArrayList<>()); + result.put("total", 0); + return result; + } + private void ensureFairCompany(Long fairId, Long companyId) { - Long count = fairCompanyMapper.selectCount(new LambdaQueryWrapper() + ensureFairCompany(fairId, companyId, "1"); + } + + private FairCompany ensureFairCompany(Long fairId, Long companyId, String reviewStatus) + { + FairCompany existing = fairCompanyMapper.selectOne(new LambdaQueryWrapper() .eq(FairCompany::getJobFairId, fairId) - .eq(FairCompany::getCompanyId, companyId)); - if (count != null && count > 0) { - return; + .eq(FairCompany::getCompanyId, companyId) + .last("LIMIT 1")); + if (existing != null) { + if (StringUtils.isBlank(existing.getReviewStatus())) { + existing.setReviewStatus(reviewStatus); + fairCompanyMapper.updateById(existing); + } + return existing; } FairCompany fairCompany = new FairCompany(); fairCompany.setJobFairId(fairId); fairCompany.setCompanyId(companyId); + fairCompany.setReviewStatus(reviewStatus); fairCompanyMapper.insert(fairCompany); + return fairCompany; + } + + private void validateReviewStatus(String reviewStatus) + { + if (!"0".equals(reviewStatus) && !"1".equals(reviewStatus) && !"2".equals(reviewStatus)) { + throw new ServiceException("审核状态不正确"); + } + } + + private void validateRejectRemark(String reviewStatus, String reviewRemark) + { + if ("2".equals(reviewStatus) && StringUtils.isBlank(reviewRemark)) { + throw new ServiceException("驳回时请填写原因"); + } } private void resetBoothSnapshot(OutdoorFair outdoorFair, boolean forceRecreate) @@ -640,4 +991,32 @@ public class OutdoorFairController extends BaseController outdoorFair.setBoothCount(0); } } + + private String buildOutdoorFairCompanyH5Url(HttpServletRequest request, Long fairId, Long companyId) + { + String baseUrl = request.getScheme() + "://" + request.getServerName(); + int port = request.getServerPort(); + if (port != 80 && port != 443) { + baseUrl += ":" + port; + } + String contextPath = request.getContextPath() == null ? "" : request.getContextPath(); + return baseUrl + contextPath + "/h5/outdoor-fair/company.html?fairId=" + fairId + "&companyId=" + companyId; + } + + private Map buildCompanyQrCodeData(HttpServletRequest request, Long fairId, Long companyId) + { + OutdoorFairDevice device = outdoorFairDeviceMapper.selectOne(new LambdaQueryWrapper() + .eq(OutdoorFairDevice::getFairId, fairId) + .eq(OutdoorFairDevice::getCompanyId, companyId) + .last("LIMIT 1")); + String h5Url = buildOutdoorFairCompanyH5Url(request, fairId, companyId); + Map data = new HashMap<>(); + data.put("fairId", fairId); + data.put("companyId", companyId); + data.put("deviceId", device == null ? null : device.getId()); + data.put("deviceCode", device == null ? null : device.getDeviceCode()); + data.put("h5Url", h5Url); + data.put("qrCodeContent", h5Url); + return data; + } } diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/OutdoorFairDeviceController.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/OutdoorFairDeviceController.java index a84c5c5..060903f 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/OutdoorFairDeviceController.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/OutdoorFairDeviceController.java @@ -63,20 +63,21 @@ public class OutdoorFairDeviceController extends BaseController } /** - * 批量生成设备码(UUID) - * 请求体:{ fairId, quantity } + * 新增设备码(由用户手动填写设备码,可选同时绑定参会企业) + * 请求体:{ fairId, deviceCode, companyId? } */ - @ApiOperation("批量生成设备码") + @ApiOperation("新增设备码") @PreAuthorize("@ss.hasPermi('cms:outdoorFair:add')") @Log(title = "户外招聘会设备码", businessType = BusinessType.INSERT) - @PostMapping("/batch") - public AjaxResult batch(@RequestBody Map request) + @PostMapping("/add") + public AjaxResult add(@RequestBody Map request) { Long fairId = request.get("fairId") == null ? null : Long.valueOf(String.valueOf(request.get("fairId"))); - Integer quantity = request.get("quantity") == null ? null : Integer.valueOf(String.valueOf(request.get("quantity"))); - List devices = outdoorFairDeviceService.batchGenerate(fairId, quantity); - AjaxResult result = AjaxResult.success("生成成功"); - result.put("data", devices); + String deviceCode = request.get("deviceCode") == null ? null : String.valueOf(request.get("deviceCode")).trim(); + Long companyId = request.get("companyId") == null ? null : Long.valueOf(String.valueOf(request.get("companyId"))); + OutdoorFairDevice device = outdoorFairDeviceService.addDevice(fairId, deviceCode, companyId); + AjaxResult result = AjaxResult.success("新增成功"); + result.put("data", device); return result; } diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/CrossCityAlliance.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/CrossCityAlliance.java new file mode 100644 index 0000000..22a209c --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/CrossCityAlliance.java @@ -0,0 +1,21 @@ +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 lombok.Data; + +/** + * 跨域联合招聘会-联盟城市。 + */ +@Data +@TableName("shz.cms_cross_city_alliance") +public class CrossCityAlliance extends BaseEntity +{ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + /** 城市名称 */ + private String name; +} diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/FairCompany.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/FairCompany.java index e67a97c..9e58f28 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/FairCompany.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/FairCompany.java @@ -9,6 +9,8 @@ import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.ruoyi.common.core.domain.BaseEntity; + +import java.util.Date; /** * 公司招聘会关联对象 fair_company * @author lishundong @@ -34,4 +36,16 @@ public class FairCompany extends BaseEntity @ApiModelProperty("招聘会id") private Long jobFairId; + @ApiModelProperty("审核状态 0待审核 1通过 2驳回") + private String reviewStatus; + + @ApiModelProperty("审核人") + private String reviewBy; + + @ApiModelProperty("审核时间") + private Date reviewTime; + + @ApiModelProperty("审核备注") + private String reviewRemark; + } diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/Job.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/Job.java index 8acf763..0952ec2 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/Job.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/Job.java @@ -202,6 +202,19 @@ public class Job extends BaseEntity @ApiModelProperty("审核状态") private String reviewStatus; + + @TableField(exist = false) + @ApiModelProperty("户外招聘会岗位审核状态") + private String fairReviewStatus; + + @TableField(exist = false) + @ApiModelProperty("户外招聘会岗位审核备注") + private String fairReviewRemark; + + @TableField(exist = false) + @ApiModelProperty("户外招聘会岗位审核时间") + private String fairReviewTime; + //简历是否被查看 @TableField(exist = false) private String isView; diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/OutdoorFair.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/OutdoorFair.java index e3dd59a..ea6f6d4 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/OutdoorFair.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/OutdoorFair.java @@ -3,6 +3,7 @@ package com.ruoyi.cms.domain; import java.util.Date; import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonFormat; @@ -88,4 +89,32 @@ public class OutdoorFair extends BaseEntity @Excel(name = "招聘会照片") @ApiModelProperty("招聘会照片") private String photoUrl; + + @TableField(exist = false) + @ApiModelProperty("当前企业ID") + private Long companyId; + + @TableField(exist = false) + @ApiModelProperty("当前企业名称") + private String companyName; + + @TableField(exist = false) + @ApiModelProperty("当前企业是否已报名") + private Boolean signedUp; + + @TableField(exist = false) + @ApiModelProperty("当前企业公共H5页面链接") + private String h5Url; + + @TableField(exist = false) + @ApiModelProperty("当前企业二维码内容") + private String qrCodeContent; + + @TableField(exist = false) + @ApiModelProperty("当前企业报名审核状态") + private String reviewStatus; + + @TableField(exist = false) + @ApiModelProperty("当前企业报名审核备注") + private String reviewRemark; } diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/OutdoorFairJob.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/OutdoorFairJob.java index 040a3af..14360ff 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/OutdoorFairJob.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/OutdoorFairJob.java @@ -1,11 +1,15 @@ package com.ruoyi.cms.domain; import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; import com.ruoyi.common.core.domain.BaseEntity; import lombok.Data; +import java.util.Date; + /** * 户外招聘会岗位关联。 */ @@ -21,4 +25,20 @@ public class OutdoorFairJob extends BaseEntity private Long companyId; private Long jobId; + + /** 审核状态 0待审核 1通过 2驳回。 */ + private String reviewStatus; + + private String reviewBy; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date reviewTime; + + private String reviewRemark; + + @TableField(exist = false) + private String companyName; + + @TableField(exist = false) + private String jobTitle; } diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/rc/CrossDomainJobVO.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/rc/CrossDomainJobVO.java new file mode 100644 index 0000000..5672a79 --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/rc/CrossDomainJobVO.java @@ -0,0 +1,65 @@ +package com.ruoyi.cms.domain.rc; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * 跨域招聘会岗位视图(聚合 public_job_fair -> public_job_fair_job -> job -> company) + */ +@Data +@ApiModel("跨域招聘会岗位") +public class CrossDomainJobVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("岗位ID") + private Long jobId; + + @ApiModelProperty("岗位名称") + private String jobTitle; + + @ApiModelProperty("最低薪资") + private Integer minSalary; + + @ApiModelProperty("最高薪资") + private Integer maxSalary; + + @ApiModelProperty("学历要求") + private String education; + + @ApiModelProperty("经验要求") + private String experience; + + @ApiModelProperty("招聘人数") + private Integer vacancies; + + @JsonFormat(pattern = "yyyy-MM-dd") + @ApiModelProperty("发布日期") + private Date postingDate; + + @ApiModelProperty("企业ID") + private Long companyId; + + @ApiModelProperty("企业名称") + private String companyName; + + @ApiModelProperty("行业") + private String industry; + + @ApiModelProperty("企业规模") + private String scale; + + @ApiModelProperty("招聘会ID") + private String jobFairId; + + @ApiModelProperty("招聘会标题") + private String jobFairTitle; + + @ApiModelProperty("跨域联盟城市(逗号分隔)") + private String crossDomainCities; +} diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/rc/PublicJobFair.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/rc/PublicJobFair.java index f62d5b8..6d0982e 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/rc/PublicJobFair.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/rc/PublicJobFair.java @@ -151,6 +151,12 @@ public class PublicJobFair implements Serializable { @ApiModelProperty("招聘会类别") private String jobFairCategory; + @ApiModelProperty("是否跨域(Y-是 N-否)") + private String isCrossDomain; + + @ApiModelProperty("跨域联盟城市(逗号分隔的城市名称)") + private String crossDomainCities; + @ApiModelProperty("纬度") private java.math.BigDecimal latitude; diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/mapper/CrossCityAllianceMapper.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/mapper/CrossCityAllianceMapper.java new file mode 100644 index 0000000..275dc3e --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/mapper/CrossCityAllianceMapper.java @@ -0,0 +1,11 @@ +package com.ruoyi.cms.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ruoyi.cms.domain.CrossCityAlliance; + +/** + * 跨域联合招聘会-联盟城市 Mapper。 + */ +public interface CrossCityAllianceMapper extends BaseMapper +{ +} diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/mapper/rc/PublicJobFairMapper.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/mapper/rc/PublicJobFairMapper.java index 3cb5122..da44a11 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/mapper/rc/PublicJobFairMapper.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/mapper/rc/PublicJobFairMapper.java @@ -32,6 +32,11 @@ public interface PublicJobFairMapper extends BaseMapper { */ List selectJobListByJobFairIdAndCompanyId(@Param("jobFairId") String jobFairId, @Param("companyId") Long companyId); + /** + * 查询跨域招聘会下的岗位(可按联盟城市过滤,cityNames 为逗号分隔的城市名称) + */ + List selectCrossDomainJobs(@Param("cityNames") String cityNames); + /** * 检查用户是否已报名 */ diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/ICrossCityAllianceService.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/ICrossCityAllianceService.java new file mode 100644 index 0000000..f70f354 --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/ICrossCityAllianceService.java @@ -0,0 +1,17 @@ +package com.ruoyi.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.ruoyi.cms.domain.CrossCityAlliance; + +import java.util.List; + +/** + * 跨域联合招聘会-联盟城市 Service。 + */ +public interface ICrossCityAllianceService extends IService +{ + /** + * 查询联盟城市列表(支持按城市名称模糊查询)。 + */ + List selectAllianceList(CrossCityAlliance query); +} diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/IOutdoorFairDeviceService.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/IOutdoorFairDeviceService.java index f63bb39..3d13f4d 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/IOutdoorFairDeviceService.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/IOutdoorFairDeviceService.java @@ -16,13 +16,14 @@ public interface IOutdoorFairDeviceService extends IService List selectDeviceList(OutdoorFairDevice query); /** - * 批量生成设备码(UUID)。 + * 新增设备码(由用户手动填写设备码,可选同时绑定参会企业)。 * - * @param fairId 招聘会ID - * @param quantity 生成数量 - * @return 已生成的设备码列表 + * @param fairId 招聘会ID + * @param deviceCode 设备码(全局唯一) + * @param companyId 参会企业ID,为空表示暂不绑定 + * @return 新增的设备码 */ - List batchGenerate(Long fairId, Integer quantity); + OutdoorFairDevice addDevice(Long fairId, String deviceCode, Long companyId); /** * 绑定/解绑参会企业(companyId 为空表示解绑)。 diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/CrossCityAllianceServiceImpl.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/CrossCityAllianceServiceImpl.java new file mode 100644 index 0000000..9a5fb45 --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/CrossCityAllianceServiceImpl.java @@ -0,0 +1,29 @@ +package com.ruoyi.cms.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.ruoyi.cms.domain.CrossCityAlliance; +import com.ruoyi.cms.mapper.CrossCityAllianceMapper; +import com.ruoyi.cms.service.ICrossCityAllianceService; +import com.ruoyi.common.utils.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 跨域联合招聘会-联盟城市 Service 实现。 + */ +@Service +public class CrossCityAllianceServiceImpl + extends ServiceImpl + implements ICrossCityAllianceService +{ + @Override + public List selectAllianceList(CrossCityAlliance query) + { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.like(StringUtils.isNotBlank(query.getName()), CrossCityAlliance::getName, query.getName()); + wrapper.orderByAsc(CrossCityAlliance::getId); + return list(wrapper); + } +} diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/OutdoorFairDeviceServiceImpl.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/OutdoorFairDeviceServiceImpl.java index 149ba4c..040d89f 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/OutdoorFairDeviceServiceImpl.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/OutdoorFairDeviceServiceImpl.java @@ -15,10 +15,8 @@ import com.ruoyi.common.utils.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.ArrayList; import java.util.Date; import java.util.List; -import java.util.UUID; /** * 户外招聘会设备码 Service 实现。 @@ -47,28 +45,45 @@ public class OutdoorFairDeviceServiceImpl } @Override - public List batchGenerate(Long fairId, Integer quantity) + public OutdoorFairDevice addDevice(Long fairId, String deviceCode, Long companyId) { if (fairId == null) { throw new ServiceException("招聘会ID不能为空"); } - int count = quantity == null ? 0 : quantity; - if (count <= 0) { - throw new ServiceException("生成数量必须大于0"); + if (StringUtils.isBlank(deviceCode)) { + throw new ServiceException("设备码不能为空"); } - if (count > 1000) { - throw new ServiceException("单次生成数量不能超过1000"); + // 设备码全局唯一(H5 端按设备码查询) + Long exists = baseMapper.selectCount(new LambdaQueryWrapper() + .eq(OutdoorFairDevice::getDeviceCode, deviceCode)); + if (exists != null && exists > 0) { + throw new ServiceException("设备码已存在"); } - List devices = new ArrayList<>(count); - for (int i = 0; i < count; i++) { - OutdoorFairDevice device = new OutdoorFairDevice(); - device.setFairId(fairId); - // 去掉中划线,得到 32 位十六进制设备码 - device.setDeviceCode(UUID.randomUUID().toString().replace("-", "")); - devices.add(device); + OutdoorFairDevice device = new OutdoorFairDevice(); + device.setFairId(fairId); + device.setDeviceCode(deviceCode); + if (companyId != null) { + // 仅允许绑定已参加当前招聘会的企业 + Long count = fairCompanyMapper.selectCount(new LambdaQueryWrapper() + .eq(FairCompany::getJobFairId, fairId) + .eq(FairCompany::getCompanyId, companyId)); + if (count == null || count == 0) { + throw new ServiceException("该企业未参加当前招聘会"); + } + // 同一招聘会下,一个企业只能绑定一个设备码 + Long bound = baseMapper.selectCount(new LambdaQueryWrapper() + .eq(OutdoorFairDevice::getFairId, fairId) + .eq(OutdoorFairDevice::getCompanyId, companyId)); + if (bound != null && bound > 0) { + throw new ServiceException("该企业已绑定其他设备码"); + } + Company company = companyMapper.selectById(companyId); + device.setCompanyId(companyId); + device.setCompanyName(company == null ? null : company.getName()); + device.setBindTime(new Date()); } - saveBatch(devices); - return devices; + save(device); + return device; } @Override diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/rc/IPublicJobFairService.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/rc/IPublicJobFairService.java index a22ba43..541ad8f 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/rc/IPublicJobFairService.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/rc/IPublicJobFairService.java @@ -100,4 +100,9 @@ public interface IPublicJobFairService { * 查询招聘会报名列表 */ List selectSignUpList(String jobFairId); + + /** + * 查询跨域招聘会下的岗位(可按联盟城市过滤,cityNames 为逗号分隔的城市名称) + */ + List selectCrossDomainJobs(String cityNames); } diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/rc/impl/PublicJobFairServiceImpl.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/rc/impl/PublicJobFairServiceImpl.java index 5408ee1..877bc37 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/rc/impl/PublicJobFairServiceImpl.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/rc/impl/PublicJobFairServiceImpl.java @@ -219,4 +219,9 @@ public class PublicJobFairServiceImpl implements IPublicJobFairService { public List selectSignUpList(String jobFairId) { return publicJobFairMapper.selectSignUpListByJobFairId(jobFairId); } + + @Override + public List selectCrossDomainJobs(String cityNames) { + return publicJobFairMapper.selectCrossDomainJobs(cityNames); + } } diff --git a/ruoyi-bussiness/src/main/resources/mapper/app/OutdoorFairJobMapper.xml b/ruoyi-bussiness/src/main/resources/mapper/app/OutdoorFairJobMapper.xml index 8a3f1ce..81f7706 100644 --- a/ruoyi-bussiness/src/main/resources/mapper/app/OutdoorFairJobMapper.xml +++ b/ruoyi-bussiness/src/main/resources/mapper/app/OutdoorFairJobMapper.xml @@ -34,7 +34,10 @@ + +