From 92ff657e7103a91f03b33a7ae2e489c3c607f9f9 Mon Sep 17 00:00:00 2001 From: lapuda <577732344@qq.com> Date: Thu, 25 Jun 2026 11:30:31 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=88=B7=E5=A4=96?= =?UTF-8?q?=E6=8B=9B=E8=81=98=E4=BC=9A=E7=9B=B8=E5=85=B3=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=EF=BC=8C=E5=8C=85=E6=8B=AC=E6=8E=A7=E5=88=B6=E5=99=A8=E3=80=81?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E3=80=81=E6=95=B0=E6=8D=AE=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E5=8F=8A=E6=95=B0=E6=8D=AE=E5=BA=93=E8=A1=A8=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 10 +- .../controller/cms/OutdoorFairController.java | 113 ++++++++++ .../com/ruoyi/cms/domain/OutdoorFair.java | 83 +++++++ .../domain/OutdoorFairDictDataRequest.java | 26 +++ .../ruoyi/cms/mapper/OutdoorFairMapper.java | 53 +++++ .../cms/service/IOutdoorFairService.java | 33 +++ .../cms/service/impl/ESJobSearchImpl.java | 2 +- .../impl/InterviewInvitationServiceImpl.java | 2 +- .../service/impl/OutdoorFairServiceImpl.java | 78 +++++++ sql/cms_outdoor_fair.sql | 53 +++++ sql/cms_outdoor_fair_seed_shihezi.sql | 202 ++++++++++++++++++ sql/sys_dict_outdoor_fair_region.sql | 70 ++++++ sql/sys_dict_outdoor_fair_type.sql | 64 ++++++ 13 files changed, 786 insertions(+), 3 deletions(-) create mode 100644 ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/OutdoorFairController.java create mode 100644 ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/OutdoorFair.java create mode 100644 ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/OutdoorFairDictDataRequest.java create mode 100644 ruoyi-bussiness/src/main/java/com/ruoyi/cms/mapper/OutdoorFairMapper.java create mode 100644 ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/IOutdoorFairService.java create mode 100644 ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/OutdoorFairServiceImpl.java create mode 100644 sql/cms_outdoor_fair.sql create mode 100644 sql/cms_outdoor_fair_seed_shihezi.sql create mode 100644 sql/sys_dict_outdoor_fair_region.sql create mode 100644 sql/sys_dict_outdoor_fair_type.sql diff --git a/.gitignore b/.gitignore index 0f3ddc9..a86bdd0 100644 --- a/.gitignore +++ b/.gitignore @@ -45,4 +45,12 @@ nbdist/ !*/build/*.java !*/build/*.html !*/build/*.xml -.DS_Store \ No newline at end of file +.DS_Store + +# Local credentials for project-scoped Codex skills +.codex/skills/*/.password + +# Local application runtime files +.local/ +.codex/ +local.sh \ No newline at end of file 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 new file mode 100644 index 0000000..be8d68d --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/OutdoorFairController.java @@ -0,0 +1,113 @@ +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.service.IOutdoorFairService; +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.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; + + /** + * 查询户外招聘会列表 + */ + @ApiOperation("查询户外招聘会列表") + @PreAuthorize("@ss.hasPermi('cms:outdoorFair:list')") + @GetMapping("/list") + public TableDataInfo list(OutdoorFair outdoorFair) + { + startPage(); + List 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) + { + return toAjax(outdoorFairService.save(outdoorFair)); + } + + /** + * 修改户外招聘会 + */ + @ApiOperation("修改户外招聘会") + @PreAuthorize("@ss.hasPermi('cms:outdoorFair:edit')") + @Log(title = "户外招聘会", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody OutdoorFair 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())); + } +} 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 new file mode 100644 index 0000000..204cf32 --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/OutdoorFair.java @@ -0,0 +1,83 @@ +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 = "举办地址") + @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; +} diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/OutdoorFairDictDataRequest.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/OutdoorFairDictDataRequest.java new file mode 100644 index 0000000..99e8225 --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/OutdoorFairDictDataRequest.java @@ -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; +} diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/mapper/OutdoorFairMapper.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/mapper/OutdoorFairMapper.java new file mode 100644 index 0000000..3154722 --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/mapper/OutdoorFairMapper.java @@ -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 +{ + /** + * 查询字典项是否存在 + * + * @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); +} diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/IOutdoorFairService.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/IOutdoorFairService.java new file mode 100644 index 0000000..210546f --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/IOutdoorFairService.java @@ -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 +{ + /** + * 查询户外招聘会列表 + * + * @param outdoorFair 户外招聘会 + * @return 户外招聘会集合 + */ + List selectOutdoorFairList(OutdoorFair outdoorFair); + + /** + * 新增户外招聘会相关字典项 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @param createBy 创建人 + * @return 影响行数 + */ + int insertOutdoorFairDictData(String dictType, String dictLabel, String createBy); +} diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/ESJobSearchImpl.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/ESJobSearchImpl.java index 97461f2..2f2535c 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/ESJobSearchImpl.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/ESJobSearchImpl.java @@ -72,7 +72,7 @@ public class ESJobSearchImpl implements IESJobSearchService /** * 项目启动时,初始化索引及数据 */ - @PostConstruct +// @PostConstruct public void init() { boolean isLockAcquired = false; diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/InterviewInvitationServiceImpl.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/InterviewInvitationServiceImpl.java index 8d334f6..f8461c7 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/InterviewInvitationServiceImpl.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/InterviewInvitationServiceImpl.java @@ -43,7 +43,7 @@ public class InterviewInvitationServiceImpl implements InterviewInvitationServic @Autowired private DataSource dataSource; - @PostConstruct + // @PostConstruct public void initTable() { try (Connection conn = dataSource.getConnection(); Statement stmt = conn.createStatement()) { diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/OutdoorFairServiceImpl.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/OutdoorFairServiceImpl.java new file mode 100644 index 0000000..f3ad728 --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/OutdoorFairServiceImpl.java @@ -0,0 +1,78 @@ +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 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 selectOutdoorFairList(OutdoorFair outdoorFair) + { + LambdaQueryWrapper 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.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; + } +} diff --git a/sql/cms_outdoor_fair.sql b/sql/cms_outdoor_fair.sql new file mode 100644 index 0000000..52aea23 --- /dev/null +++ b/sql/cms_outdoor_fair.sql @@ -0,0 +1,53 @@ +-- 户外招聘会表 +-- 瀚高数据库 / PostgreSQL 兼容 + +CREATE SEQUENCE IF NOT EXISTS "cms_outdoor_fair_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +CREATE TABLE IF NOT EXISTS "cms_outdoor_fair" ( + "id" BIGINT NOT NULL DEFAULT nextval('"cms_outdoor_fair_id_seq"') PRIMARY KEY, + "title" VARCHAR(200) NOT NULL, + "host_unit" VARCHAR(200) NOT NULL, + "fair_type" VARCHAR(50) NOT NULL, + "region" VARCHAR(100) NOT NULL, + "address" VARCHAR(500) NOT NULL, + "booth_count" INTEGER NOT NULL DEFAULT 0, + "hold_time" TIMESTAMP(0) NOT NULL, + "end_time" TIMESTAMP(0) NOT NULL, + "apply_start_time" TIMESTAMP(0) NOT NULL, + "apply_end_time" TIMESTAMP(0) NOT NULL, + "online_apply" BOOLEAN NOT NULL DEFAULT FALSE, + "photo_url" VARCHAR(500), + "create_by" VARCHAR(64) DEFAULT '', + "create_time" TIMESTAMP(0), + "update_by" VARCHAR(64) DEFAULT '', + "update_time" TIMESTAMP(0), + "remark" VARCHAR(500), + "del_flag" CHAR(1) DEFAULT '0' +); + +COMMENT ON TABLE "cms_outdoor_fair" IS '户外招聘会表'; +COMMENT ON COLUMN "cms_outdoor_fair"."id" IS '主键ID'; +COMMENT ON COLUMN "cms_outdoor_fair"."title" IS '招聘会标题'; +COMMENT ON COLUMN "cms_outdoor_fair"."host_unit" IS '举办单位'; +COMMENT ON COLUMN "cms_outdoor_fair"."fair_type" IS '招聘会类型'; +COMMENT ON COLUMN "cms_outdoor_fair"."region" IS '举办区域'; +COMMENT ON COLUMN "cms_outdoor_fair"."address" IS '举办地址'; +COMMENT ON COLUMN "cms_outdoor_fair"."booth_count" IS '展位数量'; +COMMENT ON COLUMN "cms_outdoor_fair"."hold_time" IS '举办时间'; +COMMENT ON COLUMN "cms_outdoor_fair"."end_time" IS '截止时间'; +COMMENT ON COLUMN "cms_outdoor_fair"."apply_start_time" IS '开放申请时间'; +COMMENT ON COLUMN "cms_outdoor_fair"."apply_end_time" IS '截止申请时间'; +COMMENT ON COLUMN "cms_outdoor_fair"."online_apply" IS '是否开启线上申请'; +COMMENT ON COLUMN "cms_outdoor_fair"."photo_url" IS '招聘会照片'; +COMMENT ON COLUMN "cms_outdoor_fair"."del_flag" IS '删除标志(0代表存在 2代表删除)'; + +CREATE INDEX IF NOT EXISTS "idx_cms_outdoor_fair_title" ON "cms_outdoor_fair" ("title"); +CREATE INDEX IF NOT EXISTS "idx_cms_outdoor_fair_host_unit" ON "cms_outdoor_fair" ("host_unit"); +CREATE INDEX IF NOT EXISTS "idx_cms_outdoor_fair_type" ON "cms_outdoor_fair" ("fair_type"); +CREATE INDEX IF NOT EXISTS "idx_cms_outdoor_fair_hold_time" ON "cms_outdoor_fair" ("hold_time"); +CREATE INDEX IF NOT EXISTS "idx_cms_outdoor_fair_del_flag" ON "cms_outdoor_fair" ("del_flag"); diff --git a/sql/cms_outdoor_fair_seed_shihezi.sql b/sql/cms_outdoor_fair_seed_shihezi.sql new file mode 100644 index 0000000..de21a73 --- /dev/null +++ b/sql/cms_outdoor_fair_seed_shihezi.sql @@ -0,0 +1,202 @@ +-- 户外招聘会石河子 mock 数据 +-- 可重复执行:按 title 去重,已存在同名招聘会时不会重复插入。 + +INSERT INTO "cms_outdoor_fair" ( + "title", "host_unit", "fair_type", "region", "address", "booth_count", + "hold_time", "end_time", "apply_start_time", "apply_end_time", + "online_apply", "photo_url", "create_by", "create_time", "update_by", "update_time", "del_flag" +) +SELECT + '2026年石河子市春季户外综合招聘会', + '第八师石河子市人力资源和社会保障局', + '综合类', + '第八师(石河子市)', + '石河子市北三路石河子大学中区图书馆前广场', + 80, + TIMESTAMP '2026-03-15 09:00:00', + TIMESTAMP '2026-03-15 17:00:00', + TIMESTAMP '2026-03-01 00:00:00', + TIMESTAMP '2026-03-10 23:59:59', + TRUE, + 'https://picsum.photos/seed/shihezi-outdoor-1/400/300', + 'system', + NOW(), + 'system', + NOW(), + '0' +WHERE NOT EXISTS (SELECT 1 FROM "cms_outdoor_fair" WHERE "title" = '2026年石河子市春季户外综合招聘会'); + +INSERT INTO "cms_outdoor_fair" ( + "title", "host_unit", "fair_type", "region", "address", "booth_count", + "hold_time", "end_time", "apply_start_time", "apply_end_time", + "online_apply", "photo_url", "create_by", "create_time", "update_by", "update_time", "del_flag" +) +SELECT + '2026年石河子大学毕业生户外专场招聘会', + '石河子大学就业指导中心', + '校园招聘', + '第八师(石河子市)', + '石河子大学中区主楼前广场', + 60, + TIMESTAMP '2026-04-18 09:30:00', + TIMESTAMP '2026-04-18 16:30:00', + TIMESTAMP '2026-04-01 00:00:00', + TIMESTAMP '2026-04-12 23:59:59', + TRUE, + 'https://picsum.photos/seed/shihezi-outdoor-2/400/300', + 'system', + NOW(), + 'system', + NOW(), + '0' +WHERE NOT EXISTS (SELECT 1 FROM "cms_outdoor_fair" WHERE "title" = '2026年石河子大学毕业生户外专场招聘会'); + +INSERT INTO "cms_outdoor_fair" ( + "title", "host_unit", "fair_type", "region", "address", "booth_count", + "hold_time", "end_time", "apply_start_time", "apply_end_time", + "online_apply", "photo_url", "create_by", "create_time", "update_by", "update_time", "del_flag" +) +SELECT + '2026年石河子经开区制造业户外招聘会', + '石河子经济技术开发区管委会', + '行业专场', + '第八师(石河子市)', + '石河子经济技术开发区企业服务中心广场', + 100, + TIMESTAMP '2026-05-16 09:00:00', + TIMESTAMP '2026-05-16 17:30:00', + TIMESTAMP '2026-04-25 00:00:00', + TIMESTAMP '2026-05-10 23:59:59', + TRUE, + 'https://picsum.photos/seed/shihezi-outdoor-3/400/300', + 'system', + NOW(), + 'system', + NOW(), + '0' +WHERE NOT EXISTS (SELECT 1 FROM "cms_outdoor_fair" WHERE "title" = '2026年石河子经开区制造业户外招聘会'); + +INSERT INTO "cms_outdoor_fair" ( + "title", "host_unit", "fair_type", "region", "address", "booth_count", + "hold_time", "end_time", "apply_start_time", "apply_end_time", + "online_apply", "photo_url", "create_by", "create_time", "update_by", "update_time", "del_flag" +) +SELECT + '2026年石河子市高新区数字经济户外招聘会', + '石河子高新技术产业开发区管理委员会', + '高新技术专场', + '第八师(石河子市)', + '石河子高新区科技企业孵化器广场', + 55, + TIMESTAMP '2026-06-20 09:00:00', + TIMESTAMP '2026-06-20 16:30:00', + TIMESTAMP '2026-06-01 00:00:00', + TIMESTAMP '2026-06-14 23:59:59', + TRUE, + 'https://picsum.photos/seed/shihezi-outdoor-4/400/300', + 'system', + NOW(), + 'system', + NOW(), + '0' +WHERE NOT EXISTS (SELECT 1 FROM "cms_outdoor_fair" WHERE "title" = '2026年石河子市高新区数字经济户外招聘会'); + +INSERT INTO "cms_outdoor_fair" ( + "title", "host_unit", "fair_type", "region", "address", "booth_count", + "hold_time", "end_time", "apply_start_time", "apply_end_time", + "online_apply", "photo_url", "create_by", "create_time", "update_by", "update_time", "del_flag" +) +SELECT + '2026年石河子军垦文化广场服务业招聘会', + '石河子市就业服务中心', + '服务业专场', + '第八师(石河子市)', + '石河子市军垦文化广场', + 45, + TIMESTAMP '2026-07-11 10:00:00', + TIMESTAMP '2026-07-11 17:00:00', + TIMESTAMP '2026-06-20 00:00:00', + TIMESTAMP '2026-07-05 23:59:59', + FALSE, + 'https://picsum.photos/seed/shihezi-outdoor-5/400/300', + 'system', + NOW(), + 'system', + NOW(), + '0' +WHERE NOT EXISTS (SELECT 1 FROM "cms_outdoor_fair" WHERE "title" = '2026年石河子军垦文化广场服务业招聘会'); + +INSERT INTO "cms_outdoor_fair" ( + "title", "host_unit", "fair_type", "region", "address", "booth_count", + "hold_time", "end_time", "apply_start_time", "apply_end_time", + "online_apply", "photo_url", "create_by", "create_time", "update_by", "update_time", "del_flag" +) +SELECT + '2026年第八师团场农业技术人才户外招聘会', + '第八师农业农村局', + '行业专场', + '第八师(石河子市)', + '石河子市人民广场东侧', + 50, + TIMESTAMP '2026-08-08 09:00:00', + TIMESTAMP '2026-08-08 17:00:00', + TIMESTAMP '2026-07-20 00:00:00', + TIMESTAMP '2026-08-02 23:59:59', + FALSE, + 'https://picsum.photos/seed/shihezi-outdoor-6/400/300', + 'system', + NOW(), + 'system', + NOW(), + '0' +WHERE NOT EXISTS (SELECT 1 FROM "cms_outdoor_fair" WHERE "title" = '2026年第八师团场农业技术人才户外招聘会'); + +INSERT INTO "cms_outdoor_fair" ( + "title", "host_unit", "fair_type", "region", "address", "booth_count", + "hold_time", "end_time", "apply_start_time", "apply_end_time", + "online_apply", "photo_url", "create_by", "create_time", "update_by", "update_time", "del_flag" +) +SELECT + '2026年石河子市金秋就业援助户外招聘会', + '石河子市公共就业和人才服务中心', + '就业援助专场', + '第八师(石河子市)', + '石河子市幸福路步行街广场', + 70, + TIMESTAMP '2026-09-19 09:30:00', + TIMESTAMP '2026-09-19 17:30:00', + TIMESTAMP '2026-09-01 00:00:00', + TIMESTAMP '2026-09-13 23:59:59', + TRUE, + 'https://picsum.photos/seed/shihezi-outdoor-7/400/300', + 'system', + NOW(), + 'system', + NOW(), + '0' +WHERE NOT EXISTS (SELECT 1 FROM "cms_outdoor_fair" WHERE "title" = '2026年石河子市金秋就业援助户外招聘会'); + +INSERT INTO "cms_outdoor_fair" ( + "title", "host_unit", "fair_type", "region", "address", "booth_count", + "hold_time", "end_time", "apply_start_time", "apply_end_time", + "online_apply", "photo_url", "create_by", "create_time", "update_by", "update_time", "del_flag" +) +SELECT + '2026年石河子市文旅商贸户外招聘会', + '石河子市文化体育广电和旅游局', + '文旅专场', + '第八师(石河子市)', + '石河子市北湖公园游客服务中心广场', + 40, + TIMESTAMP '2026-10-24 10:00:00', + TIMESTAMP '2026-10-24 17:00:00', + TIMESTAMP '2026-10-01 00:00:00', + TIMESTAMP '2026-10-18 23:59:59', + FALSE, + 'https://picsum.photos/seed/shihezi-outdoor-8/400/300', + 'system', + NOW(), + 'system', + NOW(), + '0' +WHERE NOT EXISTS (SELECT 1 FROM "cms_outdoor_fair" WHERE "title" = '2026年石河子市文旅商贸户外招聘会'); diff --git a/sql/sys_dict_outdoor_fair_region.sql b/sql/sys_dict_outdoor_fair_region.sql new file mode 100644 index 0000000..23cff86 --- /dev/null +++ b/sql/sys_dict_outdoor_fair_region.sql @@ -0,0 +1,70 @@ +-- 户外招聘会举办区域系统字典 +-- 可重复执行:按 dict_type / dict_value 去重。 + +INSERT INTO "sys_dict_type" ( + "dict_id", "dict_name", "dict_type", "status", "create_by", "create_time", "remark" +) +SELECT + (SELECT COALESCE(MAX("dict_id"), 0) + 1 FROM "sys_dict_type"), + '户外招聘会举办区域', + 'outdoor_fair_region', + '0', + 'system', + NOW(), + '户外招聘会管理使用' +WHERE NOT EXISTS ( + SELECT 1 FROM "sys_dict_type" WHERE "dict_type" = 'outdoor_fair_region' +); + +WITH seed("dict_sort", "dict_label", "dict_value", "list_class", "is_default") AS ( + VALUES + (1, '石河子市', '石河子市', 'primary', 'N'), + (2, '第一师(阿拉尔市)', '第一师(阿拉尔市)', 'default', 'N'), + (3, '第二师(铁门关市)', '第二师(铁门关市)', 'default', 'N'), + (4, '第三师(图木舒克市)', '第三师(图木舒克市)', 'default', 'N'), + (5, '第四师(可克达拉市)', '第四师(可克达拉市)', 'default', 'N'), + (6, '第五师(双河市)', '第五师(双河市)', 'default', 'N'), + (7, '第六师(五家渠市)', '第六师(五家渠市)', 'default', 'N'), + (8, '第七师(胡杨河市)', '第七师(胡杨河市)', 'default', 'N'), + (9, '第八师(石河子市)', '第八师(石河子市)', 'success', 'Y'), + (10, '第九师(白杨市)', '第九师(白杨市)', 'default', 'N'), + (11, '第十师(北屯市)', '第十师(北屯市)', 'default', 'N'), + (12, '第十一师(建工师)', '第十一师(建工师)', 'default', 'N'), + (13, '第十二师', '第十二师', 'default', 'N'), + (14, '第十三师(新星市)', '第十三师(新星市)', 'default', 'N'), + (15, '第十四师(昆玉市)', '第十四师(昆玉市)', 'default', 'N') +), +new_rows AS ( + SELECT + ROW_NUMBER() OVER (ORDER BY seed."dict_sort") AS rn, + seed.* + FROM seed + WHERE NOT EXISTS ( + SELECT 1 + FROM "sys_dict_data" data + WHERE data."dict_type" = 'outdoor_fair_region' + AND data."dict_value" = seed."dict_value" + ) +), +base AS ( + SELECT COALESCE(MAX("dict_code"), 0) AS max_code FROM "sys_dict_data" +) +INSERT INTO "sys_dict_data" ( + "dict_code", "dict_sort", "dict_label", "dict_value", "dict_type", + "css_class", "list_class", "is_default", "status", "create_by", "create_time", "remark" +) +SELECT + base.max_code + new_rows.rn, + new_rows."dict_sort", + new_rows."dict_label", + new_rows."dict_value", + 'outdoor_fair_region', + NULL, + new_rows."list_class", + new_rows."is_default", + '0', + 'system', + NOW(), + '户外招聘会举办区域' +FROM new_rows +CROSS JOIN base; diff --git a/sql/sys_dict_outdoor_fair_type.sql b/sql/sys_dict_outdoor_fair_type.sql new file mode 100644 index 0000000..989e58c --- /dev/null +++ b/sql/sys_dict_outdoor_fair_type.sql @@ -0,0 +1,64 @@ +-- 户外招聘会类型系统字典 +-- 可重复执行:按 dict_type / dict_value 去重。 + +INSERT INTO "sys_dict_type" ( + "dict_id", "dict_name", "dict_type", "status", "create_by", "create_time", "remark" +) +SELECT + (SELECT COALESCE(MAX("dict_id"), 0) + 1 FROM "sys_dict_type"), + '户外招聘会类型', + 'outdoor_fair_type', + '0', + 'system', + NOW(), + '户外招聘会管理使用' +WHERE NOT EXISTS ( + SELECT 1 FROM "sys_dict_type" WHERE "dict_type" = 'outdoor_fair_type' +); + +WITH seed("dict_sort", "dict_label", "dict_value", "list_class", "is_default") AS ( + VALUES + (1, '综合类', '综合类', 'primary', 'Y'), + (2, '校园招聘', '校园招聘', 'success', 'N'), + (3, '行业专场', '行业专场', 'processing', 'N'), + (4, '高新技术专场', '高新技术专场', 'purple', 'N'), + (5, '智能制造专场', '智能制造专场', 'cyan', 'N'), + (6, '服务业专场', '服务业专场', 'blue', 'N'), + (7, '就业援助专场', '就业援助专场', 'warning', 'N'), + (8, '文旅专场', '文旅专场', 'magenta', 'N'), + (9, '其他', '其他', 'default', 'N') +), +new_rows AS ( + SELECT + ROW_NUMBER() OVER (ORDER BY seed."dict_sort") AS rn, + seed.* + FROM seed + WHERE NOT EXISTS ( + SELECT 1 + FROM "sys_dict_data" data + WHERE data."dict_type" = 'outdoor_fair_type' + AND data."dict_value" = seed."dict_value" + ) +), +base AS ( + SELECT COALESCE(MAX("dict_code"), 0) AS max_code FROM "sys_dict_data" +) +INSERT INTO "sys_dict_data" ( + "dict_code", "dict_sort", "dict_label", "dict_value", "dict_type", + "css_class", "list_class", "is_default", "status", "create_by", "create_time", "remark" +) +SELECT + base.max_code + new_rows.rn, + new_rows."dict_sort", + new_rows."dict_label", + new_rows."dict_value", + 'outdoor_fair_type', + NULL, + new_rows."list_class", + new_rows."is_default", + '0', + 'system', + NOW(), + '户外招聘会类型' +FROM new_rows +CROSS JOIN base; From d1319c6a7cf73ec77a6cb437d34c3f70792a9b19 Mon Sep 17 00:00:00 2001 From: lapuda <577732344@qq.com> Date: Thu, 25 Jun 2026 12:47:54 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=9C=BA=E5=9C=B0?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD=EF=BC=8C?= =?UTF-8?q?=E5=8C=85=E6=8B=AC=E5=9C=BA=E5=9C=B0=E4=BF=A1=E6=81=AF=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=E5=99=A8=E3=80=81=E6=9C=8D=E5=8A=A1=E3=80=81=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=A8=A1=E5=9E=8B=E5=8F=8A=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E8=A1=A8=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/cms/OutdoorFairController.java | 21 ++ .../controller/cms/VenueInfoController.java | 127 +++++++++++ .../com/ruoyi/cms/domain/OutdoorFair.java | 8 + .../java/com/ruoyi/cms/domain/VenueInfo.java | 77 +++++++ .../cms/domain/VenueInfoDictDataRequest.java | 26 +++ .../com/ruoyi/cms/mapper/VenueInfoMapper.java | 53 +++++ .../ruoyi/cms/service/IVenueInfoService.java | 33 +++ .../service/impl/OutdoorFairServiceImpl.java | 1 + .../service/impl/VenueInfoServiceImpl.java | 74 ++++++ sql/cms_outdoor_fair.sql | 5 + sql/cms_outdoor_fair_bind_venue.sql | 20 ++ sql/cms_venue_info.sql | 215 ++++++++++++++++++ 12 files changed, 660 insertions(+) create mode 100644 ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/VenueInfoController.java create mode 100644 ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/VenueInfo.java create mode 100644 ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/VenueInfoDictDataRequest.java create mode 100644 ruoyi-bussiness/src/main/java/com/ruoyi/cms/mapper/VenueInfoMapper.java create mode 100644 ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/IVenueInfoService.java create mode 100644 ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/VenueInfoServiceImpl.java create mode 100644 sql/cms_outdoor_fair_bind_venue.sql create mode 100644 sql/cms_venue_info.sql 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 be8d68d..e289dbe 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 @@ -5,12 +5,15 @@ import java.util.List; import com.ruoyi.cms.domain.OutdoorFair; import com.ruoyi.cms.domain.OutdoorFairDictDataRequest; +import com.ruoyi.cms.domain.VenueInfo; import com.ruoyi.cms.service.IOutdoorFairService; +import com.ruoyi.cms.service.IVenueInfoService; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.exception.ServiceException; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; @@ -39,6 +42,9 @@ public class OutdoorFairController extends BaseController @Autowired private IOutdoorFairService outdoorFairService; + @Autowired + private IVenueInfoService venueInfoService; + /** * 查询户外招聘会列表 */ @@ -72,6 +78,7 @@ public class OutdoorFairController extends BaseController @PostMapping public AjaxResult add(@RequestBody OutdoorFair outdoorFair) { + fillVenueFields(outdoorFair); return toAjax(outdoorFairService.save(outdoorFair)); } @@ -84,6 +91,7 @@ public class OutdoorFairController extends BaseController @PutMapping public AjaxResult edit(@RequestBody OutdoorFair outdoorFair) { + fillVenueFields(outdoorFair); return toAjax(outdoorFairService.updateById(outdoorFair)); } @@ -110,4 +118,17 @@ public class OutdoorFairController extends BaseController { return toAjax(outdoorFairService.insertOutdoorFairDictData(request.getDictType(), request.getDictLabel(), getUsername())); } + + private void fillVenueFields(OutdoorFair outdoorFair) + { + if (outdoorFair.getVenueId() == null) { + return; + } + VenueInfo venueInfo = venueInfoService.getById(outdoorFair.getVenueId()); + if (venueInfo == null) { + throw new ServiceException("绑定场地不存在"); + } + outdoorFair.setVenueName(venueInfo.getVenueName()); + outdoorFair.setBoothCount(venueInfo.getFloorCount() == null ? 0 : venueInfo.getFloorCount()); + } } diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/VenueInfoController.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/VenueInfoController.java new file mode 100644 index 0000000..46c431e --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/VenueInfoController.java @@ -0,0 +1,127 @@ +package com.ruoyi.cms.controller.cms; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import com.ruoyi.cms.domain.VenueInfo; +import com.ruoyi.cms.domain.VenueInfoDictDataRequest; +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.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.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; + + /** + * 查询场地信息列表 + */ + @ApiOperation("查询场地信息列表") + @PreAuthorize("@ss.hasPermi('cms:venueInfo:list')") + @GetMapping("/list") + public TableDataInfo list(VenueInfo venueInfo) + { + startPage(); + List 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())); + } + + private void fillHandleFields(VenueInfo venueInfo) + { + if (venueInfo.getHandleDate() == null) { + venueInfo.setHandleDate(new Date()); + } + if (StringUtils.isBlank(venueInfo.getHandler())) { + venueInfo.setHandler(getUsername()); + } + } +} 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 204cf32..e3dd59a 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 @@ -45,6 +45,14 @@ public class OutdoorFair extends BaseEntity @ApiModelProperty("举办区域") private String region; + @Excel(name = "绑定场地ID") + @ApiModelProperty("绑定场地ID") + private Long venueId; + + @Excel(name = "绑定场地") + @ApiModelProperty("绑定场地") + private String venueName; + @Excel(name = "举办地址") @ApiModelProperty("举办地址") private String address; diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/VenueInfo.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/VenueInfo.java new file mode 100644 index 0000000..685bf36 --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/VenueInfo.java @@ -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; +} diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/VenueInfoDictDataRequest.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/VenueInfoDictDataRequest.java new file mode 100644 index 0000000..6a85774 --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/VenueInfoDictDataRequest.java @@ -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; +} diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/mapper/VenueInfoMapper.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/mapper/VenueInfoMapper.java new file mode 100644 index 0000000..3b74eeb --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/mapper/VenueInfoMapper.java @@ -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 +{ + /** + * 查询字典项是否存在 + * + * @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); +} diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/IVenueInfoService.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/IVenueInfoService.java new file mode 100644 index 0000000..fbfc4a0 --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/IVenueInfoService.java @@ -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 +{ + /** + * 查询场地信息列表 + * + * @param venueInfo 场地信息 + * @return 场地信息集合 + */ + List selectVenueInfoList(VenueInfo venueInfo); + + /** + * 新增场地信息相关字典项 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @param createBy 创建人 + * @return 影响行数 + */ + int insertVenueInfoDictData(String dictType, String dictLabel, String createBy); +} diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/OutdoorFairServiceImpl.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/OutdoorFairServiceImpl.java index f3ad728..97362ff 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/OutdoorFairServiceImpl.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/OutdoorFairServiceImpl.java @@ -39,6 +39,7 @@ public class OutdoorFairServiceImpl extends ServiceImpl implements IVenueInfoService +{ + private static final String VENUE_TYPE_DICT = "venue_info_type"; + + /** + * 查询场地信息列表 + * + * @param venueInfo 场地信息 + * @return 场地信息集合 + */ + @Override + public List selectVenueInfoList(VenueInfo venueInfo) + { + LambdaQueryWrapper 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; + } +} diff --git a/sql/cms_outdoor_fair.sql b/sql/cms_outdoor_fair.sql index 52aea23..79b2415 100644 --- a/sql/cms_outdoor_fair.sql +++ b/sql/cms_outdoor_fair.sql @@ -14,6 +14,8 @@ CREATE TABLE IF NOT EXISTS "cms_outdoor_fair" ( "host_unit" VARCHAR(200) NOT NULL, "fair_type" VARCHAR(50) NOT NULL, "region" VARCHAR(100) NOT NULL, + "venue_id" BIGINT, + "venue_name" VARCHAR(200), "address" VARCHAR(500) NOT NULL, "booth_count" INTEGER NOT NULL DEFAULT 0, "hold_time" TIMESTAMP(0) NOT NULL, @@ -36,6 +38,8 @@ COMMENT ON COLUMN "cms_outdoor_fair"."title" IS '招聘会标题'; COMMENT ON COLUMN "cms_outdoor_fair"."host_unit" IS '举办单位'; COMMENT ON COLUMN "cms_outdoor_fair"."fair_type" IS '招聘会类型'; COMMENT ON COLUMN "cms_outdoor_fair"."region" IS '举办区域'; +COMMENT ON COLUMN "cms_outdoor_fair"."venue_id" IS '绑定场地ID'; +COMMENT ON COLUMN "cms_outdoor_fair"."venue_name" IS '绑定场地'; COMMENT ON COLUMN "cms_outdoor_fair"."address" IS '举办地址'; COMMENT ON COLUMN "cms_outdoor_fair"."booth_count" IS '展位数量'; COMMENT ON COLUMN "cms_outdoor_fair"."hold_time" IS '举办时间'; @@ -49,5 +53,6 @@ COMMENT ON COLUMN "cms_outdoor_fair"."del_flag" IS '删除标志(0代表存在 CREATE INDEX IF NOT EXISTS "idx_cms_outdoor_fair_title" ON "cms_outdoor_fair" ("title"); CREATE INDEX IF NOT EXISTS "idx_cms_outdoor_fair_host_unit" ON "cms_outdoor_fair" ("host_unit"); CREATE INDEX IF NOT EXISTS "idx_cms_outdoor_fair_type" ON "cms_outdoor_fair" ("fair_type"); +CREATE INDEX IF NOT EXISTS "idx_cms_outdoor_fair_venue_id" ON "cms_outdoor_fair" ("venue_id"); CREATE INDEX IF NOT EXISTS "idx_cms_outdoor_fair_hold_time" ON "cms_outdoor_fair" ("hold_time"); CREATE INDEX IF NOT EXISTS "idx_cms_outdoor_fair_del_flag" ON "cms_outdoor_fair" ("del_flag"); diff --git a/sql/cms_outdoor_fair_bind_venue.sql b/sql/cms_outdoor_fair_bind_venue.sql new file mode 100644 index 0000000..3ecfea3 --- /dev/null +++ b/sql/cms_outdoor_fair_bind_venue.sql @@ -0,0 +1,20 @@ +-- 户外招聘会绑定场地字段 +-- 瀚高数据库 / PostgreSQL 兼容 +-- 可重复执行。 + +ALTER TABLE "cms_outdoor_fair" + ADD COLUMN IF NOT EXISTS "venue_id" BIGINT; + +ALTER TABLE "cms_outdoor_fair" + ADD COLUMN IF NOT EXISTS "venue_name" VARCHAR(200); + +COMMENT ON COLUMN "cms_outdoor_fair"."venue_id" IS '绑定场地ID'; +COMMENT ON COLUMN "cms_outdoor_fair"."venue_name" IS '绑定场地'; + +CREATE INDEX IF NOT EXISTS "idx_cms_outdoor_fair_venue_id" ON "cms_outdoor_fair" ("venue_id"); + +UPDATE "cms_outdoor_fair" fair +SET "venue_name" = venue."venue_name", + "booth_count" = COALESCE(venue."floor_count", 0) +FROM "cms_venue_info" venue +WHERE fair."venue_id" = venue."id"; diff --git a/sql/cms_venue_info.sql b/sql/cms_venue_info.sql new file mode 100644 index 0000000..b2ed405 --- /dev/null +++ b/sql/cms_venue_info.sql @@ -0,0 +1,215 @@ +-- 场地信息维护表、字典、菜单 +-- 瀚高数据库 / PostgreSQL 兼容 +-- 可重复执行。 + +CREATE SEQUENCE IF NOT EXISTS "cms_venue_info_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +CREATE TABLE IF NOT EXISTS "cms_venue_info" ( + "id" BIGINT NOT NULL DEFAULT nextval('"cms_venue_info_id_seq"') PRIMARY KEY, + "venue_type" VARCHAR(100) NOT NULL, + "venue_name" VARCHAR(200) NOT NULL, + "venue_area" NUMERIC(12, 2), + "floor_count" INTEGER, + "venue_address" VARCHAR(500) NOT NULL, + "contact_phone" VARCHAR(50), + "route_line_ids" VARCHAR(500), + "route_line_names" VARCHAR(1000), + "handle_date" DATE, + "handle_org" VARCHAR(200), + "handler" VARCHAR(100), + "create_by" VARCHAR(64) DEFAULT '', + "create_time" TIMESTAMP(0), + "update_by" VARCHAR(64) DEFAULT '', + "update_time" TIMESTAMP(0), + "remark" VARCHAR(100), + "del_flag" CHAR(1) DEFAULT '0' +); + +COMMENT ON TABLE "cms_venue_info" IS '场地信息维护表'; +COMMENT ON COLUMN "cms_venue_info"."id" IS '主键ID'; +COMMENT ON COLUMN "cms_venue_info"."venue_type" IS '场地类型'; +COMMENT ON COLUMN "cms_venue_info"."venue_name" IS '场地名称'; +COMMENT ON COLUMN "cms_venue_info"."venue_area" IS '场地面积'; +COMMENT ON COLUMN "cms_venue_info"."floor_count" IS '展位数量'; +COMMENT ON COLUMN "cms_venue_info"."venue_address" IS '场地地址'; +COMMENT ON COLUMN "cms_venue_info"."contact_phone" IS '联系电话'; +COMMENT ON COLUMN "cms_venue_info"."route_line_ids" IS '乘坐线路ID,多个用英文逗号分隔'; +COMMENT ON COLUMN "cms_venue_info"."route_line_names" IS '乘坐线路名称,多个用英文逗号分隔'; +COMMENT ON COLUMN "cms_venue_info"."handle_date" IS '经办日期'; +COMMENT ON COLUMN "cms_venue_info"."handle_org" IS '经办机构'; +COMMENT ON COLUMN "cms_venue_info"."handler" IS '经办人'; +COMMENT ON COLUMN "cms_venue_info"."remark" IS '备注'; +COMMENT ON COLUMN "cms_venue_info"."del_flag" IS '删除标志(0代表存在 2代表删除)'; + +CREATE INDEX IF NOT EXISTS "idx_cms_venue_info_type" ON "cms_venue_info" ("venue_type"); +CREATE INDEX IF NOT EXISTS "idx_cms_venue_info_name" ON "cms_venue_info" ("venue_name"); +CREATE INDEX IF NOT EXISTS "idx_cms_venue_info_del_flag" ON "cms_venue_info" ("del_flag"); + +INSERT INTO "sys_dict_type" ( + "dict_id", "dict_name", "dict_type", "status", "create_by", "create_time", "remark" +) +SELECT + (SELECT COALESCE(MAX("dict_id"), 0) + 1 FROM "sys_dict_type"), + '场地类型', + 'venue_info_type', + '0', + 'system', + NOW(), + '场地信息维护使用' +WHERE NOT EXISTS ( + SELECT 1 FROM "sys_dict_type" WHERE "dict_type" = 'venue_info_type' +); + +WITH seed("dict_sort", "dict_label", "dict_value", "list_class", "is_default") AS ( + VALUES + (1, '智能化招聘场馆', '智能化招聘场馆', 'primary', 'Y'), + (2, '户外招聘广场', '户外招聘广场', 'success', 'N'), + (3, '高校招聘场地', '高校招聘场地', 'processing', 'N'), + (4, '园区招聘场地', '园区招聘场地', 'cyan', 'N'), + (5, '临时招聘场地', '临时招聘场地', 'warning', 'N'), + (6, '其他', '其他', 'default', 'N') +), +new_rows AS ( + SELECT + ROW_NUMBER() OVER (ORDER BY seed."dict_sort") AS rn, + seed.* + FROM seed + WHERE NOT EXISTS ( + SELECT 1 + FROM "sys_dict_data" data + WHERE data."dict_type" = 'venue_info_type' + AND data."dict_value" = seed."dict_value" + ) +), +base AS ( + SELECT COALESCE(MAX("dict_code"), 0) AS max_code FROM "sys_dict_data" +) +INSERT INTO "sys_dict_data" ( + "dict_code", "dict_sort", "dict_label", "dict_value", "dict_type", + "css_class", "list_class", "is_default", "status", "create_by", "create_time", "remark" +) +SELECT + base.max_code + new_rows.rn, + new_rows."dict_sort", + new_rows."dict_label", + new_rows."dict_value", + 'venue_info_type', + NULL, + new_rows."list_class", + new_rows."is_default", + '0', + 'system', + NOW(), + '场地类型' +FROM new_rows +CROSS JOIN base; + +WITH parent_menu AS ( + SELECT "menu_id" FROM "sys_menu" WHERE "menu_id" = 2055 +), +inserted_page AS ( + INSERT INTO "sys_menu" ( + "menu_name", "parent_id", "order_num", "path", "component", "query", "route_name", + "is_frame", "is_cache", "menu_type", "visible", "status", "perms", "icon", + "create_by", "create_time", "remark" + ) + SELECT + '场地信息维护', + parent_menu."menu_id", + 2, + 'jobfair/venueinfo', + 'jobfair/venueinfo/index', + NULL, + '', + 1, + 0, + 'C', + '0', + '0', + 'cms:venueInfo:list', + '#', + 'system', + NOW(), + '场地信息维护菜单' + FROM parent_menu + WHERE NOT EXISTS ( + SELECT 1 FROM "sys_menu" WHERE "parent_id" = parent_menu."menu_id" AND "menu_name" = '场地信息维护' + ) + RETURNING "menu_id" +), +page_menu AS ( + SELECT "menu_id" FROM inserted_page + UNION + SELECT "menu_id" FROM "sys_menu" WHERE "parent_id" = 2055 AND "menu_name" = '场地信息维护' +), +button_seed("menu_name", "order_num", "perms") AS ( + VALUES + ('场地信息查询', 1, 'cms:venueInfo:query'), + ('场地信息新增', 2, 'cms:venueInfo:add'), + ('场地信息修改', 3, 'cms:venueInfo:edit'), + ('场地信息删除', 4, 'cms:venueInfo:remove') +) +INSERT INTO "sys_menu" ( + "menu_name", "parent_id", "order_num", "path", "component", "query", "route_name", + "is_frame", "is_cache", "menu_type", "visible", "status", "perms", "icon", + "create_by", "create_time", "remark" +) +SELECT + button_seed."menu_name", + page_menu."menu_id", + button_seed."order_num", + '', + NULL, + NULL, + '', + 1, + 0, + 'F', + '0', + '0', + button_seed."perms", + '#', + 'system', + NOW(), + '场地信息维护按钮' +FROM page_menu +CROSS JOIN button_seed +WHERE NOT EXISTS ( + SELECT 1 FROM "sys_menu" WHERE "perms" = button_seed."perms" +); + +WITH outdoor_roles AS ( + SELECT DISTINCT "role_id" + FROM "sys_role_menu" + WHERE "menu_id" = 2111 +), +venue_menus AS ( + SELECT "menu_id" + FROM "sys_menu" + WHERE ("parent_id" = 2055 AND "menu_name" = '场地信息维护') + OR "perms" IN ( + 'cms:venueInfo:query', + 'cms:venueInfo:add', + 'cms:venueInfo:edit', + 'cms:venueInfo:remove' + ) +), +role_menu_rows AS ( + SELECT outdoor_roles."role_id", venue_menus."menu_id" + FROM outdoor_roles + CROSS JOIN venue_menus +) +INSERT INTO "sys_role_menu" ("role_id", "menu_id") +SELECT role_menu_rows."role_id", role_menu_rows."menu_id" +FROM role_menu_rows +WHERE NOT EXISTS ( + SELECT 1 + FROM "sys_role_menu" existing + WHERE existing."role_id" = role_menu_rows."role_id" + AND existing."menu_id" = role_menu_rows."menu_id" +); From feaa9cf74724ced95f837d2fef984808b5ce5813 Mon Sep 17 00:00:00 2001 From: francis-fh Date: Thu, 25 Jun 2026 13:32:37 +0800 Subject: [PATCH 3/7] =?UTF-8?q?=E9=9D=A2=E8=AF=95=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E5=BC=80=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cms/config/InterviewMenuMigration.java | 140 ++++++++++++++++++ .../app/AppInterviewController.java | 29 +++- .../cms/CmsInterviewController.java | 3 +- .../ruoyi/cms/domain/InterviewInvitation.java | 5 + .../com/ruoyi/cms/domain/vo/CandidateVO.java | 2 + .../cms/domain/vo/InterviewInvitationVO.java | 6 + .../impl/InterviewInvitationServiceImpl.java | 21 ++- .../mapper/app/InterviewInvitationMapper.xml | 10 +- .../resources/mapper/app/JobApplyMapper.xml | 36 ++++- sql/migration_interview_menu.sql | 90 +++++++++++ 10 files changed, 331 insertions(+), 11 deletions(-) create mode 100644 ruoyi-bussiness/src/main/java/com/ruoyi/cms/config/InterviewMenuMigration.java create mode 100644 sql/migration_interview_menu.sql diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/config/InterviewMenuMigration.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/config/InterviewMenuMigration.java new file mode 100644 index 0000000..855235d --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/config/InterviewMenuMigration.java @@ -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; + } + } +} diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/app/AppInterviewController.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/app/AppInterviewController.java index 1fc40dd..5ec8fac 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/app/AppInterviewController.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/app/AppInterviewController.java @@ -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)) { // 接受时返回面试官联系方式,供前端弹窗展示 diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/CmsInterviewController.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/CmsInterviewController.java index 27239ff..5ad5191 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/CmsInterviewController.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/cms/CmsInterviewController.java @@ -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 list = interviewInvitationService.getInterviewInvitationList(interviewInvitation); + List list = interviewInvitationService.getInterviewInvitationVOList(interviewInvitation); return getDataTable(list); } diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/InterviewInvitation.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/InterviewInvitation.java index af095fb..c0f8281 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/InterviewInvitation.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/InterviewInvitation.java @@ -77,6 +77,11 @@ public class InterviewInvitation extends BaseEntity { */ @ApiModelProperty("面试官联系方式") private String contactPhone; + /** + * 面试官姓名 + */ + @ApiModelProperty("面试官姓名") + private String interviewerName; /** * 公司名称(冗余存储,创建时从company表获取) */ diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/CandidateVO.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/CandidateVO.java index 5ba7347..38ec0ec 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/CandidateVO.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/CandidateVO.java @@ -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; } diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/InterviewInvitationVO.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/InterviewInvitationVO.java index aaa8356..2b56d61 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/InterviewInvitationVO.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/InterviewInvitationVO.java @@ -11,4 +11,10 @@ public class InterviewInvitationVO extends InterviewInvitation { @ApiModelProperty("岗位名称(来自关联查询的实时数据)") private String jobTitle; + + @ApiModelProperty("求职者姓名(来自关联查询的实时数据)") + private String applicantName; + + @ApiModelProperty("求职者联系方式(来自关联查询的实时数据)") + private String applicantPhone; } diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/InterviewInvitationServiceImpl.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/InterviewInvitationServiceImpl.java index f8461c7..d4f955e 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/InterviewInvitationServiceImpl.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/InterviewInvitationServiceImpl.java @@ -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()); diff --git a/ruoyi-bussiness/src/main/resources/mapper/app/InterviewInvitationMapper.xml b/ruoyi-bussiness/src/main/resources/mapper/app/InterviewInvitationMapper.xml index 59e7c90..8afcdfa 100644 --- a/ruoyi-bussiness/src/main/resources/mapper/app/InterviewInvitationMapper.xml +++ b/ruoyi-bussiness/src/main/resources/mapper/app/InterviewInvitationMapper.xml @@ -16,6 +16,7 @@ + @@ -30,12 +31,14 @@ + + select id, company_id, job_id, user_id, apply_id, interview_time, interview_method, meeting_link, meeting_password, interview_location, - contact_phone, company_name, job_name, status, del_flag, + contact_phone, interviewer_name, company_name, job_name, status, del_flag, create_by, create_time, update_by, update_time, remark from interview_invitation @@ -56,10 +59,13 @@ +