diff --git a/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeAccessibilityController.java b/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeAccessibilityController.java new file mode 100644 index 0000000..b987017 --- /dev/null +++ b/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeAccessibilityController.java @@ -0,0 +1,105 @@ +package com.vetti.web.controller.hotake; + +import com.vetti.common.annotation.Log; +import com.vetti.common.core.controller.BaseController; +import com.vetti.common.core.domain.R; +import com.vetti.common.core.page.TableWebDataInfo; +import com.vetti.common.enums.BusinessType; +import com.vetti.hotake.domain.HotakeAccessibility; +import com.vetti.hotake.service.IHotakeAccessibilityService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 用户无障碍设置Controller + * + * @author vetti + * @date 2026-02-01 + */ +@Api(tags = "用户无障碍设置") +@RestController +@RequestMapping("/hotake/accessibility") +public class HotakeAccessibilityController extends BaseController { + @Autowired + private IHotakeAccessibilityService hotakeAccessibilityService; + + /** + * 查询用户无障碍设置列表 + */ + @ApiOperation("查询用户无障碍设置列表(分页)") + @GetMapping("/getPagelist") + public TableWebDataInfo list(HotakeAccessibility hotakeAccessibility) { + startPage(); + hotakeAccessibility.setCreateBy(getUsername()); + List list = hotakeAccessibilityService.selectHotakeAccessibilityList(hotakeAccessibility); + return getWebDataTable(list); + } + + /** + * 查询用户无障碍设置列表 + */ + @ApiOperation("查询用户无障碍设置列表(无分页)") + @GetMapping("/getList") + public R> getList(HotakeAccessibility hotakeAccessibility) { + hotakeAccessibility.setCreateBy(getUsername()); + List list = hotakeAccessibilityService.selectHotakeAccessibilityList(hotakeAccessibility); + return R.ok(list, ""); + } + + /** + * 获取用户无障碍设置详细信息 + */ + @ApiOperation("获取用户无障碍设置详细信息") + @GetMapping(value = "/{id}") + public R getInfo(@ApiParam("设置ID") @PathVariable("id") Integer id) { + return R.ok(hotakeAccessibilityService.selectHotakeAccessibilityById(id), ""); + } + + /** + * 新增用户无障碍设置 + */ + @ApiOperation("新增用户无障碍设置") + @Log(title = "用户无障碍设置", businessType = BusinessType.INSERT) + @PostMapping + public R add(@RequestBody HotakeAccessibility hotakeAccessibility) { + return R.ok(hotakeAccessibilityService.insertHotakeAccessibility(hotakeAccessibility)); + } + + /** + * 修改用户无障碍设置 + */ + @ApiOperation("修改用户无障碍设置") + @Log(title = "用户无障碍设置", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@RequestBody HotakeAccessibility hotakeAccessibility) { + return R.ok(hotakeAccessibilityService.updateHotakeAccessibility(hotakeAccessibility)); + } + + /** + * 删除用户无障碍设置 + */ + @ApiOperation("删除用户无障碍设置") + @Log(title = "用户无障碍设置", businessType = BusinessType.DELETE) + @DeleteMapping("/{id}") + public R remove(@PathVariable Integer id) { + return R.ok(hotakeAccessibilityService.deleteHotakeAccessibilityById(id)); + } + + /** + * 获取当前登录用户的无障碍设置 + * 如果不存在则自动创建默认设置 + */ + @ApiOperation("获取当前登录用户的无障碍设置") + @GetMapping("/getCurrentUser") + public R getCurrentUserAccessibility() { + String username = getUsername(); + HotakeAccessibility accessibility = hotakeAccessibilityService.getCurrentUserAccessibility(username); + return R.ok(accessibility, ""); + } + +} diff --git a/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeNotificationPreferencesController.java b/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeNotificationPreferencesController.java new file mode 100644 index 0000000..fa5077b --- /dev/null +++ b/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeNotificationPreferencesController.java @@ -0,0 +1,105 @@ +package com.vetti.web.controller.hotake; + +import com.vetti.common.annotation.Log; +import com.vetti.common.core.controller.BaseController; +import com.vetti.common.core.domain.R; +import com.vetti.common.core.page.TableWebDataInfo; +import com.vetti.common.enums.BusinessType; +import com.vetti.hotake.domain.HotakeNotificationPreferences; +import com.vetti.hotake.service.IHotakeNotificationPreferencesService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 用户通知偏好设置Controller + * + * @author vetti + * @date 2026-02-01 + */ +@Api(tags = "用户通知偏好设置") +@RestController +@RequestMapping("/hotake/notificationPreferences") +public class HotakeNotificationPreferencesController extends BaseController { + @Autowired + private IHotakeNotificationPreferencesService hotakeNotificationPreferencesService; + + /** + * 查询用户通知偏好设置列表 + */ + @ApiOperation("查询用户通知偏好设置列表(分页)") + @GetMapping("/getPagelist") + public TableWebDataInfo list(HotakeNotificationPreferences hotakeNotificationPreferences) { + startPage(); + hotakeNotificationPreferences.setCreateBy(getUsername()); + List list = hotakeNotificationPreferencesService.selectHotakeNotificationPreferencesList(hotakeNotificationPreferences); + return getWebDataTable(list); + } + + /** + * 查询用户通知偏好设置列表 + */ + @ApiOperation("查询用户通知偏好设置列表(无分页)") + @GetMapping("/getList") + public R> getList(HotakeNotificationPreferences hotakeNotificationPreferences) { + hotakeNotificationPreferences.setCreateBy(getUsername()); + List list = hotakeNotificationPreferencesService.selectHotakeNotificationPreferencesList(hotakeNotificationPreferences); + return R.ok(list, ""); + } + + /** + * 获取用户通知偏好设置详细信息 + */ + @ApiOperation("获取用户通知偏好设置详细信息") + @GetMapping(value = "/{id}") + public R getInfo(@ApiParam("设置ID") @PathVariable("id") Long id) { + return R.ok(hotakeNotificationPreferencesService.selectHotakeNotificationPreferencesById(id), ""); + } + + /** + * 新增用户通知偏好设置 + */ + @ApiOperation("新增用户通知偏好设置") + @Log(title = "用户通知偏好设置", businessType = BusinessType.INSERT) + @PostMapping + public R add(@RequestBody HotakeNotificationPreferences hotakeNotificationPreferences) { + return R.ok(hotakeNotificationPreferencesService.insertHotakeNotificationPreferences(hotakeNotificationPreferences)); + } + + /** + * 修改用户通知偏好设置 + */ + @ApiOperation("修改用户通知偏好设置") + @Log(title = "用户通知偏好设置", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@RequestBody HotakeNotificationPreferences hotakeNotificationPreferences) { + return R.ok(hotakeNotificationPreferencesService.updateHotakeNotificationPreferences(hotakeNotificationPreferences)); + } + + /** + * 删除用户通知偏好设置 + */ + @ApiOperation("删除用户通知偏好设置") + @Log(title = "用户通知偏好设置", businessType = BusinessType.DELETE) + @DeleteMapping("/{id}") + public R remove(@PathVariable Long id) { + return R.ok(hotakeNotificationPreferencesService.deleteHotakeNotificationPreferencesById(id)); + } + + /** + * 获取当前登录用户的通知偏好设置 + * 如果不存在则自动创建默认设置 + */ + @ApiOperation("获取当前登录用户的通知偏好设置") + @GetMapping("/getCurrentUser") + public R getCurrentUserPreferences() { + String username = getUsername(); + HotakeNotificationPreferences preferences = hotakeNotificationPreferencesService.getCurrentUserPreferences(username); + return R.ok(preferences, ""); + } + +} diff --git a/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeReferenceCheckController.java b/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeReferenceCheckController.java new file mode 100644 index 0000000..21ce4e5 --- /dev/null +++ b/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeReferenceCheckController.java @@ -0,0 +1,103 @@ +package com.vetti.web.controller.hotake; + +import com.vetti.common.annotation.Log; +import com.vetti.common.core.controller.BaseController; +import com.vetti.common.core.domain.R; +import com.vetti.common.core.page.TableWebDataInfo; +import com.vetti.common.enums.BusinessType; +import com.vetti.hotake.domain.HotakeReferenceCheck; +import com.vetti.hotake.domain.dto.VcDto.VcExperienceDto; +import com.vetti.hotake.service.IHotakeReferenceCheckService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 参考检查Controller + * + * @author vetti + * @date 2026-01-29 + */ +@Api(tags = "背景调查") +@RestController +@RequestMapping("/hotake/referenceCheck") +public class HotakeReferenceCheckController extends BaseController { + @Autowired + private IHotakeReferenceCheckService hotakeReferenceCheckService; + + /** + * 查询参考检查列表 + */ + @ApiOperation("查询参考检查列表(分页)") + @GetMapping("/getPagelist") + public TableWebDataInfo list(HotakeReferenceCheck hotakeReferenceCheck) { + startPage(); + hotakeReferenceCheck.setCreateBy(getUsername()); + List list = hotakeReferenceCheckService.selectHotakeReferenceCheckList(hotakeReferenceCheck); + return getWebDataTable(list); + } + + /** + * 查询参考检查列表 + */ + @ApiOperation("查询参考检查列表(无分页)") + @GetMapping("/getList") + public R> getList(HotakeReferenceCheck hotakeReferenceCheck) { + hotakeReferenceCheck.setCreateBy(getUsername()); + List list = hotakeReferenceCheckService.selectHotakeReferenceCheckList(hotakeReferenceCheck); + return R.ok(list, ""); + } + + /** + * 获取参考检查详细信息 + */ + @ApiOperation("获取参考检查详细信息") + @GetMapping(value = "/{id}") + public R getInfo(@ApiParam("参考检查ID") @PathVariable("id") Integer id) { + return R.ok(hotakeReferenceCheckService.selectHotakeReferenceCheckById(id), ""); + } + + /** + * 新增参考检查 + */ + @ApiOperation("新增参考检查") + @Log(title = "参考检查", businessType = BusinessType.INSERT) + @PostMapping + public R add(@RequestBody HotakeReferenceCheck hotakeReferenceCheck) { + return R.ok(hotakeReferenceCheckService.insertHotakeReferenceCheck(hotakeReferenceCheck)); + } + + /** + * 修改参考检查 + */ + @ApiOperation("修改参考检查") + @Log(title = "参考检查", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@RequestBody HotakeReferenceCheck hotakeReferenceCheck) { + return R.ok(hotakeReferenceCheckService.updateHotakeReferenceCheck(hotakeReferenceCheck)); + } + + /** + * 删除参考检查 + */ + @ApiOperation("删除参考检查") + @Log(title = "参考检查", businessType = BusinessType.DELETE) + @DeleteMapping("/{id}") + public R remove(@PathVariable Integer id) { + return R.ok(hotakeReferenceCheckService.deleteHotakeReferenceCheckById(id)); + } + + /** + * 获取当前登录人的工作经验列表 + */ + @ApiOperation("获取当前登录人的工作经验列表") + @GetMapping("/getExperienceList") + public R> getExperienceList() { + return R.ok(hotakeReferenceCheckService.getCurrentUserExperienceList(), ""); + } + +} diff --git a/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeSettingsJobController.java b/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeSettingsJobController.java new file mode 100644 index 0000000..38a9512 --- /dev/null +++ b/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeSettingsJobController.java @@ -0,0 +1,104 @@ +package com.vetti.web.controller.hotake; + +import com.vetti.common.annotation.Log; +import com.vetti.common.core.controller.BaseController; +import com.vetti.common.core.domain.R; +import com.vetti.common.core.page.TableWebDataInfo; +import com.vetti.common.enums.BusinessType; +import com.vetti.hotake.domain.HotakeSettingsJob; +import com.vetti.hotake.domain.dto.HotakeSettingsJobDictDto; +import com.vetti.hotake.service.IHotakeSettingsJobService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 用户首选工作设置Controller + * + * @author wangxiangshun + * @date 2025-11-02 + */ +@Api(tags = "用户首选工作设置") +@RestController +@RequestMapping("/hotake/settingsJob") +public class HotakeSettingsJobController extends BaseController { + @Autowired + private IHotakeSettingsJobService hotakeSettingsJobService; + + /** + * 查询用户首选工作设置列表 + */ + @ApiOperation("查询用户首选工作设置列表(分页)") + @GetMapping("/getPagelist") + public TableWebDataInfo list(HotakeSettingsJob hotakeSettingsJob) { + startPage(); + hotakeSettingsJob.setCreateBy(getUsername()); + List list = hotakeSettingsJobService.selectHotakeSettingsJobList(hotakeSettingsJob); + return getWebDataTable(list); + } + + /** + * 查询用户首选工作设置列表 + */ + @ApiOperation("查询用户首选工作设置列表(无分页)") + @GetMapping("/getList") + public R> getList(HotakeSettingsJob hotakeSettingsJob) { + hotakeSettingsJob.setCreateBy(getUsername()); + List list = hotakeSettingsJobService.selectHotakeSettingsJobList(hotakeSettingsJob); + return R.ok(list, ""); + } + + /** + * 获取用户首选工作设置字典对照内容 + */ + @ApiOperation("获取用户首选工作设置字典对照内容") + @GetMapping("/getDictData") + public R getDictData() { + HotakeSettingsJobDictDto dictData = hotakeSettingsJobService.getDictData(); + return R.ok(dictData, ""); + } + + /** + * 获取用户首选工作设置详细信息 + */ + @ApiOperation("获取用户首选工作设置详细信息") + @GetMapping(value = "/{id}") + public R getInfo(@ApiParam("设置ID") @PathVariable("id") Long id) { + return R.ok(hotakeSettingsJobService.selectHotakeSettingsJobById(id), ""); + } + + /** + * 新增用户首选工作设置 + */ + @ApiOperation("新增用户首选工作设置") + @Log(title = "用户首选工作设置", businessType = BusinessType.INSERT) + @PostMapping + public R add(@RequestBody HotakeSettingsJob hotakeSettingsJob) { + return R.ok(hotakeSettingsJobService.insertHotakeSettingsJob(hotakeSettingsJob)); + } + + /** + * 修改用户首选工作设置 + */ + @ApiOperation("修改用户首选工作设置") + @Log(title = "用户首选工作设置", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@RequestBody HotakeSettingsJob hotakeSettingsJob) { + return R.ok(hotakeSettingsJobService.updateHotakeSettingsJob(hotakeSettingsJob)); + } + + /** + * 删除用户首选工作设置 + */ + @ApiOperation("删除用户首选工作设置") + @Log(title = "用户首选工作设置", businessType = BusinessType.DELETE) + @DeleteMapping("/{id}") + public R remove(@PathVariable Long id) { + return R.ok(hotakeSettingsJobService.deleteHotakeSettingsJobById(id)); + } + +} diff --git a/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeSocialLoginController.java b/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeSocialLoginController.java new file mode 100644 index 0000000..9918c19 --- /dev/null +++ b/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeSocialLoginController.java @@ -0,0 +1,88 @@ +package com.vetti.web.controller.hotake; + +import com.vetti.common.annotation.Anonymous; +import com.vetti.common.core.domain.AjaxResult; +import com.vetti.common.core.domain.R; +import com.vetti.common.utils.SecurityUtils; +import com.vetti.hotake.domain.HotakeSocialUser; +import com.vetti.hotake.domain.dto.HotakeSocialLoginRequestDto; +import com.vetti.hotake.domain.dto.HotakeSocialLoginResultDto; +import com.vetti.hotake.service.IHotakeSocialUserService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 社交登录控制器 + * + * @author vetti + */ +@Api(tags = "社交登录模块") +@RestController +@RequestMapping("/oauth2") +public class HotakeSocialLoginController { + + @Autowired + private IHotakeSocialUserService socialUserService; + + /** + * 获取OAuth授权URL + */ + @Anonymous + @ApiOperation("获取OAuth授权URL") + @GetMapping("/authorize/{provider}") + public R getAuthorizationUrl( + @ApiParam(value = "平台类型:google/microsoft/linkedin", required = true) + @PathVariable String provider, + @ApiParam(value = "state参数,用于防止CSRF攻击") + @RequestParam(required = false) String state) { + String authUrl = socialUserService.getAuthorizationUrl(provider, state); + return R.ok(authUrl, ""); + } + + /** + * 社交登录回调(用code换取token并登录) + */ + @Anonymous + @ApiOperation("社交登录") + @PostMapping("/login") + public R socialLogin(@Validated @RequestBody HotakeSocialLoginRequestDto requestDto) { + HotakeSocialLoginResultDto resultDto = socialUserService.socialLogin(requestDto); + return R.ok(resultDto, ""); + } + + /** + * 获取当前用户绑定的社交账号列表 + */ + @ApiOperation("获取当前用户绑定的社交账号列表") + @GetMapping("/bindList") + public R> getBindList() { + Long userId = SecurityUtils.getUserId(); + List list = socialUserService.listByUserId(userId); + // 脱敏处理,不返回token等敏感信息 + list.forEach(item -> { + item.setAccessToken(null); + item.setRefreshToken(null); + item.setRawUserInfo(null); + }); + return R.ok(list, ""); + } + + /** + * 解绑社交账号 + */ + @ApiOperation("解绑社交账号") + @DeleteMapping("/unbind/{provider}") + public AjaxResult unbind( + @ApiParam(value = "平台类型:google/microsoft/linkedin", required = true) + @PathVariable String provider) { + Long userId = SecurityUtils.getUserId(); + socialUserService.unbind(userId, provider); + return AjaxResult.success("解绑成功"); + } +} diff --git a/vetti-admin/src/main/java/com/vetti/web/controller/system/SysLoginController.java b/vetti-admin/src/main/java/com/vetti/web/controller/system/SysLoginController.java index fb90fd5..62bd5f6 100644 --- a/vetti-admin/src/main/java/com/vetti/web/controller/system/SysLoginController.java +++ b/vetti-admin/src/main/java/com/vetti/web/controller/system/SysLoginController.java @@ -2,9 +2,12 @@ package com.vetti.web.controller.system; import java.util.*; +import cn.hutool.core.collection.CollectionUtil; import com.vetti.common.core.domain.R; import com.vetti.common.core.domain.dto.LoginDto; import com.vetti.common.utils.MessageUtils; +import com.vetti.hotake.domain.HotakeCvInfo; +import com.vetti.hotake.service.IHotakeCvInfoService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; @@ -52,6 +55,9 @@ public class SysLoginController @Autowired private ISysConfigService configService; + @Autowired + private IHotakeCvInfoService cvInfoService; + /** * 登录方法 * @@ -64,6 +70,19 @@ public class SysLoginController { LoginDto loginDto = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(), loginBody.getUuid()); + + // 如果是候选者,查询是否有简历 + if (loginDto.getUser() != null && "candidate".equals(loginDto.getUser().getSysUserType())) { + HotakeCvInfo query = new HotakeCvInfo(); + query.setUserId(loginDto.getUserId()); + query.setCvFileType("cv"); // 只查询简历类型的文件 + List cvList = cvInfoService.selectHotakeCvInfoList(query); + + // 设置简历状态标识 + loginDto.setHasCv(!CollectionUtil.isEmpty(cvList)); + loginDto.setCvCount(cvList != null ? cvList.size() : 0); + } + return R.ok(loginDto,""); } @@ -150,4 +169,22 @@ public class SysLoginController loginService.resetPassword(loginBody.getUsername(),loginBody.getPassword(),loginBody.getRepeatPassword(),loginBody.getCode(),loginBody.getUuid()); return AjaxResult.success(MessageUtils.messageCustomize("systemCommonTip10001")); } + + /** + * 退出登录 + * + * @return 结果 + */ + @ApiOperation("退出登录") + @PostMapping("/logout") + public AjaxResult logout() + { + LoginUser loginUser = SecurityUtils.getLoginUser(); + if (loginUser != null) + { + // 删除用户缓存记录 + tokenService.delLoginUser(loginUser.getToken()); + } + return AjaxResult.success("退出成功"); + } } diff --git a/vetti-admin/src/main/java/com/vetti/web/service/impl/HotakeSocialUserServiceImpl.java b/vetti-admin/src/main/java/com/vetti/web/service/impl/HotakeSocialUserServiceImpl.java new file mode 100644 index 0000000..850aa18 --- /dev/null +++ b/vetti-admin/src/main/java/com/vetti/web/service/impl/HotakeSocialUserServiceImpl.java @@ -0,0 +1,449 @@ +package com.vetti.web.service.impl; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.core.collection.CollectionUtil; +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.vetti.common.config.HotakeOAuth2Properties; +import com.vetti.common.core.domain.entity.SysUser; +import com.vetti.common.core.domain.model.LoginUser; +import com.vetti.common.enums.UserFlagEnum; +import com.vetti.common.exception.ServiceException; +import com.vetti.common.utils.DateUtils; +import com.vetti.common.utils.ip.AddressUtils; +import com.vetti.common.utils.ip.IpUtils; +import com.vetti.framework.web.service.SysPermissionService; +import com.vetti.framework.web.service.TokenService; +import com.vetti.hotake.domain.HotakeCvInfo; +import com.vetti.hotake.domain.HotakeSocialLoginLog; +import com.vetti.hotake.domain.HotakeSocialUser; +import com.vetti.hotake.domain.dto.HotakeSocialLoginRequestDto; +import com.vetti.hotake.domain.dto.HotakeSocialLoginResultDto; +import com.vetti.hotake.domain.dto.HotakeSocialUserInfoDto; +import com.vetti.hotake.mapper.HotakeCvInfoMapper; +import com.vetti.hotake.mapper.HotakeSocialLoginLogMapper; +import com.vetti.hotake.mapper.HotakeSocialUserMapper; +import com.vetti.hotake.service.IHotakeSocialUserService; +import com.vetti.system.service.ISysUserService; +import eu.bitwalker.useragentutils.UserAgent; +import okhttp3.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * 社交用户服务实现 + * + * @author vetti + */ +@Service +public class HotakeSocialUserServiceImpl implements IHotakeSocialUserService { + + private static final Logger log = LoggerFactory.getLogger(HotakeSocialUserServiceImpl.class); + + @Autowired + private HotakeOAuth2Properties oAuth2Properties; + + @Autowired + private HotakeSocialUserMapper socialUserMapper; + + @Autowired + private HotakeSocialLoginLogMapper socialLoginLogMapper; + + @Autowired + private ISysUserService sysUserService; + + @Autowired + private TokenService tokenService; + + @Autowired + private SysPermissionService permissionService; + + @Autowired + private HotakeCvInfoMapper cvInfoMapper; + + private final OkHttpClient httpClient = new OkHttpClient.Builder() + .connectTimeout(10, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) + .build(); + + @Override + @Transactional(rollbackFor = Exception.class) + public HotakeSocialLoginResultDto socialLogin(HotakeSocialLoginRequestDto requestDto) { + String provider = requestDto.getProvider().toLowerCase(); + String code = requestDto.getCode(); + + // 1. 获取第三方用户信息 + HotakeSocialUserInfoDto socialUserInfo = getSocialUserInfo(provider, code); + if (socialUserInfo == null || StrUtil.isBlank(socialUserInfo.getProviderUserId())) { + recordLoginLog(null, provider, null, "login", "1", "获取第三方用户信息失败"); + throw new ServiceException("获取第三方用户信息失败"); + } + + // 2. 查询是否已绑定 + HotakeSocialUser existSocialUser = socialUserMapper.selectByProviderAndProviderUserId( + provider, socialUserInfo.getProviderUserId()); + + SysUser sysUser; + String loginType; + boolean isNewUser = false; + + if (existSocialUser != null && existSocialUser.getUserId() != null) { + // 已绑定,直接登录 + loginType = "login"; + sysUser = sysUserService.selectUserById(existSocialUser.getUserId()); + if (sysUser == null) { + recordLoginLog(null, provider, socialUserInfo.getProviderUserId(), loginType, "1", "绑定的用户不存在"); + throw new ServiceException("绑定的用户不存在"); + } + // 更新token信息 + updateSocialUserToken(existSocialUser, socialUserInfo); + } else { + // 未绑定,自动注册 + loginType = "register"; + isNewUser = true; + sysUser = autoRegister(socialUserInfo, requestDto.getSysUserType()); + // 如果是已存在用户绑定,则不是新用户 + if (sysUser.getCreateTime() != null && + System.currentTimeMillis() - sysUser.getCreateTime().getTime() > 5000) { + isNewUser = false; + } + // 创建社交绑定 + createSocialUserBinding(sysUser.getUserId(), socialUserInfo); + } + + // 3. 生成登录Token + HotakeSocialLoginResultDto resultDto = createLoginToken(sysUser, provider, isNewUser); + + // 4. 记录登录日志 + recordLoginLog(sysUser.getUserId(), provider, socialUserInfo.getProviderUserId(), loginType, "0", "登录成功"); + + // 5. 更新登录信息 + recordLoginInfo(sysUser.getUserId()); + + return resultDto; + } + + @Override + public String getAuthorizationUrl(String provider, String state) { + HotakeOAuth2Properties.OAuthClientConfig config = oAuth2Properties.getByProvider(provider); + if (config == null) { + throw new ServiceException("不支持的登录平台: " + provider); + } + + try { + StringBuilder url = new StringBuilder(config.getAuthUri()); + url.append("?client_id=").append(URLEncoder.encode(config.getClientId(), StandardCharsets.UTF_8.name())); + url.append("&redirect_uri=").append(URLEncoder.encode(config.getRedirectUri(), StandardCharsets.UTF_8.name())); + url.append("&response_type=code"); + url.append("&scope=").append(URLEncoder.encode(config.getScope(), StandardCharsets.UTF_8.name())); + if (StrUtil.isNotBlank(state)) { + url.append("&state=").append(URLEncoder.encode(state, StandardCharsets.UTF_8.name())); + } + return url.toString(); + } catch (Exception e) { + throw new ServiceException("生成授权URL失败"); + } + } + + @Override + public List listByUserId(Long userId) { + return socialUserMapper.selectByUserId(userId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void unbind(Long userId, String provider) { + HotakeSocialUser socialUser = socialUserMapper.selectByUserIdAndProvider(userId, provider); + if (socialUser == null) { + throw new ServiceException("未绑定该平台账号"); + } + socialUserMapper.deleteById(socialUser.getId()); + } + + /** + * 获取第三方用户信息 + */ + private HotakeSocialUserInfoDto getSocialUserInfo(String provider, String code) { + HotakeOAuth2Properties.OAuthClientConfig config = oAuth2Properties.getByProvider(provider); + if (config == null) { + throw new ServiceException("不支持的登录平台: " + provider); + } + + // 1. 用code换取access_token + JSONObject tokenResponse = getAccessToken(config, code); + if (tokenResponse == null) { + return null; + } + + String accessToken = tokenResponse.getString("access_token"); + String refreshToken = tokenResponse.getString("refresh_token"); + Long expiresIn = tokenResponse.getLong("expires_in"); + + // 2. 用access_token获取用户信息 + JSONObject userInfo = getUserInfo(config, accessToken); + if (userInfo == null) { + return null; + } + + // 3. 解析用户信息(不同平台字段不同) + return parseSocialUserInfo(provider, userInfo, accessToken, refreshToken, expiresIn); + } + + /** + * 获取access_token + */ + private JSONObject getAccessToken(HotakeOAuth2Properties.OAuthClientConfig config, String code) { + try { + FormBody.Builder formBuilder = new FormBody.Builder() + .add("client_id", config.getClientId()) + .add("client_secret", config.getClientSecret()) + .add("code", code) + .add("redirect_uri", config.getRedirectUri()) + .add("grant_type", "authorization_code"); + + Request request = new Request.Builder() + .url(config.getTokenUri()) + .post(formBuilder.build()) + .addHeader("Accept", "application/json") + .build(); + + try (Response response = httpClient.newCall(request).execute()) { + if (response.isSuccessful() && response.body() != null) { + String body = response.body().string(); + log.debug("Token response: {}", body); + return JSON.parseObject(body); + } + } + } catch (IOException e) { + log.error("获取access_token失败", e); + } + return null; + } + + /** + * 获取用户信息 + */ + private JSONObject getUserInfo(HotakeOAuth2Properties.OAuthClientConfig config, String accessToken) { + try { + Request request = new Request.Builder() + .url(config.getUserInfoUri()) + .get() + .addHeader("Authorization", "Bearer " + accessToken) + .addHeader("Accept", "application/json") + .build(); + + try (Response response = httpClient.newCall(request).execute()) { + if (response.isSuccessful() && response.body() != null) { + String body = response.body().string(); + log.debug("UserInfo response: {}", body); + return JSON.parseObject(body); + } + } + } catch (IOException e) { + log.error("获取用户信息失败", e); + } + return null; + } + + /** + * 解析不同平台的用户信息为统一格式 + */ + private HotakeSocialUserInfoDto parseSocialUserInfo(String provider, JSONObject userInfo, + String accessToken, String refreshToken, Long expiresIn) { + HotakeSocialUserInfoDto dto = new HotakeSocialUserInfoDto(); + dto.setProvider(provider); + dto.setAccessToken(accessToken); + dto.setRefreshToken(refreshToken); + dto.setExpiresIn(expiresIn); + dto.setRawUserInfo(userInfo.toJSONString()); + + switch (provider.toLowerCase()) { + case "google": + dto.setProviderUserId(userInfo.getString("sub")); + dto.setEmail(userInfo.getString("email")); + dto.setName(userInfo.getString("name")); + dto.setAvatar(userInfo.getString("picture")); + break; + case "microsoft": + dto.setProviderUserId(userInfo.getString("id")); + // Microsoft返回的邮箱字段是mail或userPrincipalName + String email = userInfo.getString("mail"); + if (StrUtil.isBlank(email)) { + email = userInfo.getString("userPrincipalName"); + } + dto.setEmail(email); + dto.setName(userInfo.getString("displayName")); + // Microsoft头像需要单独请求,这里暂不处理 + break; + case "linkedin": + dto.setProviderUserId(userInfo.getString("sub")); + dto.setEmail(userInfo.getString("email")); + dto.setName(userInfo.getString("name")); + dto.setAvatar(userInfo.getString("picture")); + break; + default: + throw new ServiceException("不支持的登录平台: " + provider); + } + + return dto; + } + + /** + * 自动注册用户 + */ + private SysUser autoRegister(HotakeSocialUserInfoDto socialUserInfo, String sysUserType) { + // 检查邮箱是否已存在 + if (StrUtil.isNotBlank(socialUserInfo.getEmail())) { + SysUser existUser = sysUserService.selectUserByUserName(socialUserInfo.getEmail()); + if (existUser != null) { + // 邮箱已存在,直接绑定 + return existUser; + } + } + + // 创建新用户 + SysUser sysUser = new SysUser(); + sysUser.setUserName(socialUserInfo.getEmail()); + sysUser.setEmail(socialUserInfo.getEmail()); + sysUser.setNickName(socialUserInfo.getName()); + sysUser.setAvatar(socialUserInfo.getAvatar()); + sysUser.setSysUserType(StrUtil.isNotBlank(sysUserType) ? sysUserType : "candidate"); + sysUser.setUserFlag(UserFlagEnum.FLAG_1.getCode()); + sysUser.setUserOperStatus("1"); + sysUser.setPwdUpdateDate(DateUtils.getNowDate()); + // 社交登录用户不设置密码,或设置随机密码 + sysUser.setPassword(""); + + boolean success = sysUserService.registerUser(sysUser); + if (!success) { + throw new ServiceException("自动注册用户失败"); + } + + return sysUser; + } + + /** + * 创建社交账号绑定 + */ + private void createSocialUserBinding(Long userId, HotakeSocialUserInfoDto socialUserInfo) { + HotakeSocialUser socialUser = new HotakeSocialUser(); + socialUser.setUserId(userId); + socialUser.setProvider(socialUserInfo.getProvider()); + socialUser.setProviderUserId(socialUserInfo.getProviderUserId()); + socialUser.setEmail(socialUserInfo.getEmail()); + socialUser.setName(socialUserInfo.getName()); + socialUser.setAvatar(socialUserInfo.getAvatar()); + socialUser.setAccessToken(socialUserInfo.getAccessToken()); + socialUser.setRefreshToken(socialUserInfo.getRefreshToken()); + if (socialUserInfo.getExpiresIn() != null) { + socialUser.setTokenExpireTime(new Date(System.currentTimeMillis() + socialUserInfo.getExpiresIn() * 1000)); + } + socialUser.setRawUserInfo(socialUserInfo.getRawUserInfo()); + + socialUserMapper.insert(socialUser); + } + + /** + * 更新社交账号token信息 + */ + private void updateSocialUserToken(HotakeSocialUser socialUser, HotakeSocialUserInfoDto socialUserInfo) { + socialUser.setAccessToken(socialUserInfo.getAccessToken()); + socialUser.setRefreshToken(socialUserInfo.getRefreshToken()); + if (socialUserInfo.getExpiresIn() != null) { + socialUser.setTokenExpireTime(new Date(System.currentTimeMillis() + socialUserInfo.getExpiresIn() * 1000)); + } + socialUser.setRawUserInfo(socialUserInfo.getRawUserInfo()); + socialUserMapper.update(socialUser); + } + + /** + * 创建登录Token + */ + private HotakeSocialLoginResultDto createLoginToken(SysUser sysUser, String provider, boolean isNewUser) { + // 获取权限 + Set permissions = permissionService.getMenuPermission(sysUser); + + // 创建LoginUser + LoginUser loginUser = new LoginUser(sysUser.getUserId(), sysUser.getDeptId(), sysUser, permissions); + + // 生成token + String token = tokenService.createToken(loginUser); + + // 构建返回对象 + HotakeSocialLoginResultDto resultDto = new HotakeSocialLoginResultDto(); + resultDto.setToken(token); + resultDto.setUserId(sysUser.getUserId()); + resultDto.setSysUserType(sysUser.getSysUserType()); + resultDto.setIsNewUser(isNewUser); + resultDto.setProvider(provider); + resultDto.setUser(sysUser); + + // 如果是候选者,查询是否有简历 + if ("candidate".equals(sysUser.getSysUserType())) { + HotakeCvInfo query = new HotakeCvInfo(); + query.setUserId(sysUser.getUserId()); + query.setCvFileType("cv"); // 只查询简历类型的文件 + List cvList = cvInfoMapper.selectHotakeCvInfoList(query); + + // 设置简历状态标识 + resultDto.setHasCv(!CollectionUtil.isEmpty(cvList)); + resultDto.setCvCount(cvList != null ? cvList.size() : 0); + } + + return resultDto; + } + + /** + * 记录登录信息 + */ + private void recordLoginInfo(Long userId) { + SysUser sysUser = new SysUser(); + sysUser.setUserId(userId); + sysUser.setLoginIp(IpUtils.getIpAddr()); + sysUser.setLoginDate(DateUtils.getNowDate()); + sysUserService.updateUserProfile(sysUser); + } + + /** + * 记录社交登录日志 + */ + private void recordLoginLog(Long userId, String provider, String providerUserId, + String loginType, String status, String msg) { + try { + HotakeSocialLoginLog loginLog = new HotakeSocialLoginLog(); + loginLog.setUserId(userId); + loginLog.setProvider(provider); + loginLog.setProviderUserId(providerUserId); + loginLog.setLoginType(loginType); + loginLog.setLoginIp(IpUtils.getIpAddr()); + loginLog.setLoginLocation(AddressUtils.getRealAddressByIP(IpUtils.getIpAddr())); + + try { + UserAgent userAgent = UserAgent.parseUserAgentString( + com.vetti.common.utils.ServletUtils.getRequest().getHeader("User-Agent")); + loginLog.setBrowser(userAgent.getBrowser().getName()); + loginLog.setOs(userAgent.getOperatingSystem().getName()); + } catch (Exception ignored) { + } + + loginLog.setStatus(status); + loginLog.setMsg(msg); + loginLog.setLoginTime(new Date()); + + socialLoginLogMapper.insert(loginLog); + } catch (Exception e) { + log.error("记录社交登录日志失败", e); + } + } +} diff --git a/vetti-admin/src/main/resources/application-dev.yml b/vetti-admin/src/main/resources/application-dev.yml index 7fc1b85..7e64ea5 100644 --- a/vetti-admin/src/main/resources/application-dev.yml +++ b/vetti-admin/src/main/resources/application-dev.yml @@ -171,3 +171,44 @@ chatGpt: http: client: connect-timeout-seconds: 10 + +# OAuth2.0 社交登录配置 +oauth2: + # ================================ + # Google (Gmail) 登录配置 + # 申请地址: https://console.cloud.google.com/apis/credentials + # ================================ + google: + client-id: your-google-client-id # Google Cloud Console获取 + client-secret: your-google-client-secret # Google Cloud Console获取 + redirect-uri: https://your-domain.com/api/oauth2/callback/google + scope: openid email profile # Google标准scope(空格分隔) + auth-uri: https://accounts.google.com/o/oauth2/v2/auth # Google授权地址 + token-uri: https://oauth2.googleapis.com/token # Google令牌地址 + user-info-uri: https://www.googleapis.com/oauth2/v3/userinfo # Google用户信息接口 + + # ================================ + # Microsoft (Outlook) 登录配置 + # 申请地址: https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps + # ================================ + microsoft: + client-id: your-microsoft-client-id # Azure Portal获取 + client-secret: your-microsoft-client-secret # Azure Portal获取 + redirect-uri: https://your-domain.com/api/oauth2/callback/microsoft + scope: openid,email,profile,User.Read # 需要额外的User.Read权限才能读取用户信息 + auth-uri: https://login.microsoftonline.com/common/oauth2/v2.0/authorize # 微软授权地址 + token-uri: https://login.microsoftonline.com/common/oauth2/v2.0/token # 微软令牌地址 + user-info-uri: https://graph.microsoft.com/v1.0/me # 使用Microsoft Graph API + + # ================================ + # LinkedIn 登录配置 + # 申请地址: https://www.linkedin.com/developers/apps + # ================================ + linkedin: + client-id: 86uq3opzshd3bq # LinkedIn Developer Portal获取 + client-secret: 86uq3opzshd3bq # LinkedIn Developer Portal获取 + redirect-uri: http://localhost:8080/oauth2/callback/linkedin + scope: openid profile email # LinkedIn使用OpenID Connect,scope顺序和命名略有不同 + auth-uri: https://www.linkedin.com/oauth/v2/authorization # LinkedIn授权地址 + token-uri: https://www.linkedin.com/oauth/v2/accessToken # LinkedIn令牌地址 + user-info-uri: https://api.linkedin.com/v2/userinfo # LinkedIn用户信息接口 \ No newline at end of file diff --git a/vetti-admin/src/main/resources/application-druid.yml b/vetti-admin/src/main/resources/application-druid.yml index cd48dc4..ba7c81c 100644 --- a/vetti-admin/src/main/resources/application-druid.yml +++ b/vetti-admin/src/main/resources/application-druid.yml @@ -197,3 +197,44 @@ chatGpt: http: client: connect-timeout-seconds: 600 + +# OAuth2.0 社交登录配置 +oauth2: + # ================================ + # Google (Gmail) 登录配置 + # 申请地址: https://console.cloud.google.com/apis/credentials + # ================================ + google: + client-id: 398978985110-ve0usu381mmdio12ff01iqvv1g087qvi.apps.googleusercontent.com # Google Cloud Console获取 + client-secret: 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 # Google Cloud Console获取 + redirect-uri: https://vetti.hotake.cn/oauth2/callback/google + scope: openid email profile # Google标准scope(空格分隔) + auth-uri: https://accounts.google.com/o/oauth2/v2/auth # Google授权地址 + token-uri: https://oauth2.googleapis.com/token # Google令牌地址 + user-info-uri: https://www.googleapis.com/oauth2/v3/userinfo # Google用户信息接口 + + # ================================ + # Microsoft (Outlook) 登录配置 + # 申请地址: https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps + # ================================ + microsoft: + client-id: 608cbc4f-3ee2-4f51-a72c-b2e3133fc5b2 # Azure Portal获取 + client-secret: gvw8Q~dwG8Sv7HN3R3W3R7TQtcZyvrh88ZiJubPa # Azure Portal获取 + redirect-uri: https://vetti.hotake.cn/api/oauth2/callback/microsoft + scope: openid,email,profile,User.Read # 需要额外的User.Read权限才能读取用户信息 + auth-uri: https://login.microsoftonline.com/common/oauth2/v2.0/authorize # 微软授权地址 + token-uri: https://login.microsoftonline.com/common/oauth2/v2.0/token # 微软令牌地址 + user-info-uri: https://graph.microsoft.com/v1.0/me # 使用Microsoft Graph API + + # ================================ + # LinkedIn 登录配置 + # 申请地址: https://www.linkedin.com/developers/apps + # ================================ + linkedin: + client-id: 86uq3opzshd3bq # LinkedIn Developer Portal获取 + client-secret: WPL_AP1.mipgyxfgfBoN12Th.1TXeFg== # LinkedIn Developer Portal获取 + redirect-uri: https://vetti.hotake.cn/api/oauth2/callback/linkedin + scope: openid profile email # LinkedIn使用OpenID Connect,scope顺序和命名略有不同 + auth-uri: https://www.linkedin.com/oauth/v2/authorization # LinkedIn授权地址 + token-uri: https://www.linkedin.com/oauth/v2/accessToken # LinkedIn令牌地址 + user-info-uri: https://api.linkedin.com/v2/userinfo # LinkedIn用户信息接口 diff --git a/vetti-admin/src/main/resources/i18n/messages_en_US.properties b/vetti-admin/src/main/resources/i18n/messages_en_US.properties index 7035452..f49a7cc 100644 --- a/vetti-admin/src/main/resources/i18n/messages_en_US.properties +++ b/vetti-admin/src/main/resources/i18n/messages_en_US.properties @@ -63,3 +63,6 @@ HotakeRolesInfoServiceImpl10001 = The job information is abnormal. Please try ag # manager.页面,字段 = User Manager VerificationEmailTiTle = Your verification code VerificationEmailContent = Your verification code is: {0}, valid for {1} minutes. + + +HotakeRolesApplyInfoServiceImpl10001 = You have already applied for this position \ No newline at end of file diff --git a/vetti-admin/src/main/resources/i18n/messages_zh_CN.properties b/vetti-admin/src/main/resources/i18n/messages_zh_CN.properties index 69451eb..90b799f 100644 --- a/vetti-admin/src/main/resources/i18n/messages_zh_CN.properties +++ b/vetti-admin/src/main/resources/i18n/messages_zh_CN.properties @@ -62,3 +62,4 @@ HotakeRolesInfoServiceImpl10001 = 岗位信息异常,请稍后再试 VerificationEmailTiTle = 你的验证码 VerificationEmailContent = 你的验证码是: {0},有效期为 {1} 分钟。 +HotakeRolesApplyInfoServiceImpl10001 = 您已申请该职位 \ No newline at end of file diff --git a/vetti-admin/target/classes/application-druid.yml b/vetti-admin/target/classes/application-druid.yml index cd48dc4..ba7c81c 100644 --- a/vetti-admin/target/classes/application-druid.yml +++ b/vetti-admin/target/classes/application-druid.yml @@ -197,3 +197,44 @@ chatGpt: http: client: connect-timeout-seconds: 600 + +# OAuth2.0 社交登录配置 +oauth2: + # ================================ + # Google (Gmail) 登录配置 + # 申请地址: https://console.cloud.google.com/apis/credentials + # ================================ + google: + client-id: 398978985110-ve0usu381mmdio12ff01iqvv1g087qvi.apps.googleusercontent.com # Google Cloud Console获取 + client-secret: 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 # Google Cloud Console获取 + redirect-uri: https://vetti.hotake.cn/oauth2/callback/google + scope: openid email profile # Google标准scope(空格分隔) + auth-uri: https://accounts.google.com/o/oauth2/v2/auth # Google授权地址 + token-uri: https://oauth2.googleapis.com/token # Google令牌地址 + user-info-uri: https://www.googleapis.com/oauth2/v3/userinfo # Google用户信息接口 + + # ================================ + # Microsoft (Outlook) 登录配置 + # 申请地址: https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps + # ================================ + microsoft: + client-id: 608cbc4f-3ee2-4f51-a72c-b2e3133fc5b2 # Azure Portal获取 + client-secret: gvw8Q~dwG8Sv7HN3R3W3R7TQtcZyvrh88ZiJubPa # Azure Portal获取 + redirect-uri: https://vetti.hotake.cn/api/oauth2/callback/microsoft + scope: openid,email,profile,User.Read # 需要额外的User.Read权限才能读取用户信息 + auth-uri: https://login.microsoftonline.com/common/oauth2/v2.0/authorize # 微软授权地址 + token-uri: https://login.microsoftonline.com/common/oauth2/v2.0/token # 微软令牌地址 + user-info-uri: https://graph.microsoft.com/v1.0/me # 使用Microsoft Graph API + + # ================================ + # LinkedIn 登录配置 + # 申请地址: https://www.linkedin.com/developers/apps + # ================================ + linkedin: + client-id: 86uq3opzshd3bq # LinkedIn Developer Portal获取 + client-secret: WPL_AP1.mipgyxfgfBoN12Th.1TXeFg== # LinkedIn Developer Portal获取 + redirect-uri: https://vetti.hotake.cn/api/oauth2/callback/linkedin + scope: openid profile email # LinkedIn使用OpenID Connect,scope顺序和命名略有不同 + auth-uri: https://www.linkedin.com/oauth/v2/authorization # LinkedIn授权地址 + token-uri: https://www.linkedin.com/oauth/v2/accessToken # LinkedIn令牌地址 + user-info-uri: https://api.linkedin.com/v2/userinfo # LinkedIn用户信息接口 diff --git a/vetti-admin/target/classes/i18n/messages_en_US.properties b/vetti-admin/target/classes/i18n/messages_en_US.properties index 7035452..f49a7cc 100644 --- a/vetti-admin/target/classes/i18n/messages_en_US.properties +++ b/vetti-admin/target/classes/i18n/messages_en_US.properties @@ -63,3 +63,6 @@ HotakeRolesInfoServiceImpl10001 = The job information is abnormal. Please try ag # manager.页面,字段 = User Manager VerificationEmailTiTle = Your verification code VerificationEmailContent = Your verification code is: {0}, valid for {1} minutes. + + +HotakeRolesApplyInfoServiceImpl10001 = You have already applied for this position \ No newline at end of file diff --git a/vetti-admin/target/classes/i18n/messages_zh_CN.properties b/vetti-admin/target/classes/i18n/messages_zh_CN.properties index 69451eb..90b799f 100644 --- a/vetti-admin/target/classes/i18n/messages_zh_CN.properties +++ b/vetti-admin/target/classes/i18n/messages_zh_CN.properties @@ -62,3 +62,4 @@ HotakeRolesInfoServiceImpl10001 = 岗位信息异常,请稍后再试 VerificationEmailTiTle = 你的验证码 VerificationEmailContent = 你的验证码是: {0},有效期为 {1} 分钟。 +HotakeRolesApplyInfoServiceImpl10001 = 您已申请该职位 \ No newline at end of file diff --git a/vetti-common/src/main/java/com/vetti/common/config/HotakeOAuth2Properties.java b/vetti-common/src/main/java/com/vetti/common/config/HotakeOAuth2Properties.java new file mode 100644 index 0000000..4aa4799 --- /dev/null +++ b/vetti-common/src/main/java/com/vetti/common/config/HotakeOAuth2Properties.java @@ -0,0 +1,139 @@ +package com.vetti.common.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * OAuth2.0 社交登录配置属性类 + * + * @author vetti + */ +@Component +@ConfigurationProperties(prefix = "oauth2") +public class HotakeOAuth2Properties { + + /** Google配置 */ + private OAuthClientConfig google; + + /** Microsoft配置 */ + private OAuthClientConfig microsoft; + + /** LinkedIn配置 */ + private OAuthClientConfig linkedin; + + public OAuthClientConfig getGoogle() { + return google; + } + + public void setGoogle(OAuthClientConfig google) { + this.google = google; + } + + public OAuthClientConfig getMicrosoft() { + return microsoft; + } + + public void setMicrosoft(OAuthClientConfig microsoft) { + this.microsoft = microsoft; + } + + public OAuthClientConfig getLinkedin() { + return linkedin; + } + + public void setLinkedin(OAuthClientConfig linkedin) { + this.linkedin = linkedin; + } + + /** + * 根据provider获取对应配置 + */ + public OAuthClientConfig getByProvider(String provider) { + switch (provider.toLowerCase()) { + case "google": + return google; + case "microsoft": + return microsoft; + case "linkedin": + return linkedin; + default: + return null; + } + } + + /** + * OAuth客户端配置 + */ + public static class OAuthClientConfig { + /** 客户端ID */ + private String clientId; + /** 客户端密钥 */ + private String clientSecret; + /** 回调地址 */ + private String redirectUri; + /** 授权范围 */ + private String scope; + /** 授权端点 */ + private String authUri; + /** 令牌端点 */ + private String tokenUri; + /** 用户信息端点 */ + private String userInfoUri; + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getClientSecret() { + return clientSecret; + } + + public void setClientSecret(String clientSecret) { + this.clientSecret = clientSecret; + } + + public String getRedirectUri() { + return redirectUri; + } + + public void setRedirectUri(String redirectUri) { + this.redirectUri = redirectUri; + } + + public String getScope() { + return scope; + } + + public void setScope(String scope) { + this.scope = scope; + } + + public String getAuthUri() { + return authUri; + } + + public void setAuthUri(String authUri) { + this.authUri = authUri; + } + + public String getTokenUri() { + return tokenUri; + } + + public void setTokenUri(String tokenUri) { + this.tokenUri = tokenUri; + } + + public String getUserInfoUri() { + return userInfoUri; + } + + public void setUserInfoUri(String userInfoUri) { + this.userInfoUri = userInfoUri; + } + } +} diff --git a/vetti-common/src/main/java/com/vetti/common/core/domain/dto/LoginDto.java b/vetti-common/src/main/java/com/vetti/common/core/domain/dto/LoginDto.java index 1a8cc4f..4f0cca1 100644 --- a/vetti-common/src/main/java/com/vetti/common/core/domain/dto/LoginDto.java +++ b/vetti-common/src/main/java/com/vetti/common/core/domain/dto/LoginDto.java @@ -25,4 +25,10 @@ public class LoginDto { @ApiModelProperty("用户信息对象") private SysUser user; + @ApiModelProperty("是否已创建简历(仅候选者有此字段)") + private Boolean hasCv; + + @ApiModelProperty("简历数量(仅候选者有此字段)") + private Integer cvCount; + } diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeAccessibility.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeAccessibility.java new file mode 100644 index 0000000..2eb0475 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeAccessibility.java @@ -0,0 +1,70 @@ +package com.vetti.hotake.domain; + +import com.vetti.common.annotation.Excel; +import com.vetti.common.core.domain.BaseEntity; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 用户无障碍设置对象 hotake_accessibility + * + * @author vetti + * @date 2026-02-01 + */ +@Data +@Accessors(chain = true) +public class HotakeAccessibility extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 主键ID */ + @ApiModelProperty("主键ID") + private Integer id; + + /** 颜色模式: light(明亮), dark(暗黑), system(系统) */ + @ApiModelProperty("颜色模式: light(明亮), dark(暗黑), system(系统)") + @Excel(name = "颜色模式") + private String colorMode; + + /** 高对比度模式: 0-关闭, 1-开启 */ + @ApiModelProperty("高对比度模式: 0-关闭, 1-开启") + @Excel(name = "高对比度模式") + private Integer highContrastMode; + + /** 减少动画: 0-关闭, 1-开启 */ + @ApiModelProperty("减少动画: 0-关闭, 1-开启") + @Excel(name = "减少动画") + private Integer reduceMotion; + + /** 字体大小: small(小), medium(中), large(大), extra_large(特大) */ + @ApiModelProperty("字体大小: small(小), medium(中), large(大), extra_large(特大)") + @Excel(name = "字体大小") + private String fontSize; + + /** 屏幕阅读器支持: 0-关闭, 1-开启 */ + @ApiModelProperty("屏幕阅读器支持: 0-关闭, 1-开启") + @Excel(name = "屏幕阅读器支持") + private Integer screenReaderSupport; + + /** 音频描述: 0-关闭, 1-开启 */ + @ApiModelProperty("音频描述: 0-关闭, 1-开启") + @Excel(name = "音频描述") + private Integer audioDescriptions; + + /** 增强键盘导航: 0-关闭, 1-开启 */ + @ApiModelProperty("增强键盘导航: 0-关闭, 1-开启") + @Excel(name = "增强键盘导航") + private Integer enhancedKeyboardNavigation; + + /** 焦点指示器: 0-关闭, 1-开启 */ + @ApiModelProperty("焦点指示器: 0-关闭, 1-开启") + @Excel(name = "焦点指示器") + private Integer focusIndicators; + + /** 语言设置: en(英语), zh(中文)等 */ + @ApiModelProperty("语言设置: en(英语), zh(中文)等") + @Excel(name = "语言设置") + private String language; + +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeNotificationPreferences.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeNotificationPreferences.java new file mode 100644 index 0000000..7616b31 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeNotificationPreferences.java @@ -0,0 +1,65 @@ +package com.vetti.hotake.domain; + +import com.vetti.common.annotation.Excel; +import com.vetti.common.core.domain.BaseEntity; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 用户通知偏好设置对象 hotake_notification_preferences + * + * @author vetti + * @date 2026-02-01 + */ +@Data +@Accessors(chain = true) +public class HotakeNotificationPreferences extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 主键ID */ + @ApiModelProperty("主键ID") + private Long id; + + /** 职位提醒:新职位机会通知 (0-关闭, 1-开启) */ + @ApiModelProperty("职位提醒:新职位机会通知 (0-关闭, 1-开启)") + @Excel(name = "职位提醒") + private Integer emailJobAlerts; + + /** 申请更新:职位申请状态更新 (0-关闭, 1-开启) */ + @ApiModelProperty("申请更新:职位申请状态更新 (0-关闭, 1-开启)") + @Excel(name = "申请更新") + private Integer emailApplicationUpdates; + + /** AI匹配建议:基于个人资料的强匹配职位推荐 (0-关闭, 1-开启) */ + @ApiModelProperty("AI匹配建议:基于个人资料的强匹配职位推荐 (0-关闭, 1-开启)") + @Excel(name = "AI匹配建议") + private Integer emailAiMatchSuggestions; + + /** 新闻简报:每周职业技巧和行业新闻 (0-关闭, 1-开启) */ + @ApiModelProperty("新闻简报:每周职业技巧和行业新闻 (0-关闭, 1-开启)") + @Excel(name = "新闻简报") + private Integer emailNewsletter; + + /** 新消息:收到新消息时通知 (0-关闭, 1-开启) */ + @ApiModelProperty("新消息:收到新消息时通知 (0-关闭, 1-开启)") + @Excel(name = "新消息") + private Integer pushNewMessages; + + /** 面试提醒:即将到来的面试提醒 (0-关闭, 1-开启) */ + @ApiModelProperty("面试提醒:即将到来的面试提醒 (0-关闭, 1-开启)") + @Excel(name = "面试提醒") + private Integer pushInterviewReminders; + + /** 营销邮件:促销内容和特别优惠 (0-关闭, 1-开启) */ + @ApiModelProperty("营销邮件:促销内容和特别优惠 (0-关闭, 1-开启)") + @Excel(name = "营销邮件") + private Integer mailMarketingEmails; + + /** 合作伙伴优惠:来自可信合作伙伴的机会 (0-关闭, 1-开启) */ + @ApiModelProperty("合作伙伴优惠:来自可信合作伙伴的机会 (0-关闭, 1-开启)") + @Excel(name = "合作伙伴优惠") + private Integer mailPartnerOffers; + +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeReferenceCheck.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeReferenceCheck.java new file mode 100644 index 0000000..249548d --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeReferenceCheck.java @@ -0,0 +1,55 @@ +package com.vetti.hotake.domain; + +import com.vetti.common.annotation.Excel; +import com.vetti.common.core.domain.BaseEntity; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 参考检查对象 hotake_reference_check + * + * @author vetti + * @date 2026-01-29 + */ +@Data +@Accessors(chain = true) +public class HotakeReferenceCheck extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 主键ID */ + @ApiModelProperty("主键ID") + private Integer id; + + /** 公司名称 */ + @ApiModelProperty("公司名称") + @Excel(name = "公司名称") + private String company; + + /** 推荐人全名 */ + @ApiModelProperty("推荐人全名") + @Excel(name = "推荐人全名") + private String fullName; + + /** 推荐人职位 */ + @ApiModelProperty("推荐人职位") + @Excel(name = "推荐人职位") + private String position; + + /** 与候选人的关系 */ + @ApiModelProperty("与候选人的关系") + @Excel(name = "与候选人的关系") + private String relationship; + + /** 推荐人邮箱 */ + @ApiModelProperty("推荐人邮箱") + @Excel(name = "推荐人邮箱") + private String email; + + /** 是否为该工作经历保存此推荐人 */ + @ApiModelProperty("是否为该工作经历保存此推荐人") + @Excel(name = "是否为该工作经历保存此推荐人") + private Boolean saveJobExperience; + +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeSettingsJob.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeSettingsJob.java new file mode 100644 index 0000000..78005ec --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeSettingsJob.java @@ -0,0 +1,55 @@ +package com.vetti.hotake.domain; + +import com.vetti.common.annotation.Excel; +import com.vetti.common.core.domain.BaseEntity; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; + +/** + * 用户首选工作设置对象 hotake_settings_job + * + * @author wangxiangshun + * @date 2025-11-02 + */ +@Data +@Accessors(chain = true) +public class HotakeSettingsJob extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 主键ID */ + @ApiModelProperty("主键ID") + private Long id; + + /** 过滤器名称 */ + @ApiModelProperty("过滤器名称") + @Excel(name = "过滤器名称") + private String name; + + /** 地点 */ + @ApiModelProperty("地点") + @Excel(name = "地点") + private String location; + + /** 纬度 */ + @ApiModelProperty("纬度") + private BigDecimal latitude; + + /** 经度 */ + @ApiModelProperty("经度") + private BigDecimal longitude; + + /** 薪资范围(如"80K") */ + @ApiModelProperty("薪资范围") + @Excel(name = "薪资范围") + private String salary; + + /** 标签数组({"dict_type":["dict_value","dict_value"]}) */ + @ApiModelProperty("标签数组") + private String tagsJson; + + +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeSocialLoginLog.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeSocialLoginLog.java new file mode 100644 index 0000000..0c639a0 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeSocialLoginLog.java @@ -0,0 +1,53 @@ +package com.vetti.hotake.domain; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * 社交登录日志对象 hotake_social_login_log + * + * @author vetti + */ +@Data +public class HotakeSocialLoginLog implements Serializable { + private static final long serialVersionUID = 1L; + + @ApiModelProperty("主键ID") + private Long id; + + @ApiModelProperty("系统用户ID") + private Long userId; + + @ApiModelProperty("第三方平台类型") + private String provider; + + @ApiModelProperty("第三方平台用户ID") + private String providerUserId; + + @ApiModelProperty("登录类型:login/register/bind") + private String loginType; + + @ApiModelProperty("登录IP") + private String loginIp; + + @ApiModelProperty("登录地点") + private String loginLocation; + + @ApiModelProperty("浏览器类型") + private String browser; + + @ApiModelProperty("操作系统") + private String os; + + @ApiModelProperty("登录状态(0成功 1失败)") + private String status; + + @ApiModelProperty("提示消息") + private String msg; + + @ApiModelProperty("登录时间") + private Date loginTime; +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeSocialUser.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeSocialUser.java new file mode 100644 index 0000000..abaea60 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeSocialUser.java @@ -0,0 +1,52 @@ +package com.vetti.hotake.domain; + +import com.vetti.common.core.domain.BaseEntity; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Date; + +/** + * 用户社交账号绑定对象 hotake_social_user + * + * @author vetti + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class HotakeSocialUser extends BaseEntity { + private static final long serialVersionUID = 1L; + + @ApiModelProperty("主键ID") + private Long id; + + @ApiModelProperty("系统用户ID") + private Long userId; + + @ApiModelProperty("第三方平台类型:google/microsoft/linkedin") + private String provider; + + @ApiModelProperty("第三方平台用户唯一标识") + private String providerUserId; + + @ApiModelProperty("第三方平台邮箱") + private String email; + + @ApiModelProperty("第三方平台用户名") + private String name; + + @ApiModelProperty("第三方平台头像URL") + private String avatar; + + @ApiModelProperty("访问令牌") + private String accessToken; + + @ApiModelProperty("刷新令牌") + private String refreshToken; + + @ApiModelProperty("令牌过期时间") + private Date tokenExpireTime; + + @ApiModelProperty("第三方平台原始用户信息JSON") + private String rawUserInfo; +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeRolesInfoDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeRolesInfoDto.java index 844e5c1..1c4a18a 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeRolesInfoDto.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeRolesInfoDto.java @@ -48,4 +48,7 @@ public class HotakeRolesInfoDto extends HotakeRolesInfo { @ApiModelProperty("招聘人详细信息") private SysUser recruiterUser; + @ApiModelProperty("当前用户是否已申请该岗位") + private Boolean hasApplied; + } diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeSettingsJobDictDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeSettingsJobDictDto.java new file mode 100644 index 0000000..d0ea442 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeSettingsJobDictDto.java @@ -0,0 +1,98 @@ +package com.vetti.hotake.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * 用户首选工作设置字典对照DTO + * + * @author wangxiangshun + * @date 2025-11-02 + */ +@Data +public class HotakeSettingsJobDictDto +{ + @ApiModelProperty("语言类型") + private List hotakeLanguagesType; + + @ApiModelProperty("技能工具类型") + private List hotakeSkillsToolType; + + @ApiModelProperty("岗位级别") + private List roleLevel; + + @ApiModelProperty("岗位地点类型") + private List roleLocationType; + + @ApiModelProperty("岗位选择工作类型") + private List roleSelectJobType; + + @ApiModelProperty("岗位类型") + private List roleType; + + @ApiModelProperty("所需技能") + private List roleRequiredSkills; + + @ApiModelProperty("拥有的好技能") + private List roleNiceToHaveSkills; + + @ApiModelProperty("教育要求类型") + private List roleEducationRequirementsType; + + @ApiModelProperty("岗位所需证书") + private List roleCertificationLicenses; + + @ApiModelProperty("岗位福利") + private List roleBenefits; + + @ApiModelProperty("发布渠道") + private List rolePublishingChannels; + + @ApiModelProperty("初步筛选问题类型") + private List roleInitialScreeningQuestionsType; + + @ApiModelProperty("预期薪酬范围") + private List expectedPayRange; + + @ApiModelProperty("愿意经常出差") + private List willingnessToTravel; + + @Data + public static class DictItem + { + @ApiModelProperty("字典编码") + private Long dictCode; + + @ApiModelProperty("字典标签") + private String dictLabel; + + @ApiModelProperty("字典键值") + private String dictValue; + + @ApiModelProperty("字典类型") + private String dictType; + + @ApiModelProperty("样式属性") + private String cssClass; + + @ApiModelProperty("表格字典样式") + private String listClass; + + @ApiModelProperty("是否默认") + private String isDefault; + + @ApiModelProperty("状态") + private String status; + + @ApiModelProperty("数据类型") + private String dataType; + + @ApiModelProperty("附件地址") + private String fileUrl; + + @ApiModelProperty("头像地址") + private String avatarUrl; + } +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeSocialLoginRequestDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeSocialLoginRequestDto.java new file mode 100644 index 0000000..59b6b09 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeSocialLoginRequestDto.java @@ -0,0 +1,30 @@ +package com.vetti.hotake.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/** + * 社交登录请求DTO + * + * @author vetti + */ +@Data +public class HotakeSocialLoginRequestDto { + + @NotBlank(message = "平台类型不能为空") + @ApiModelProperty(value = "第三方平台类型:google/microsoft/linkedin", required = true) + private String provider; + + @NotBlank(message = "授权码不能为空") + @ApiModelProperty(value = "OAuth授权码", required = true) + private String code; + + @NotBlank(message = "用户类型不能为空") + @ApiModelProperty(value = "用户类型(interviewer:面试官,candidate:候选者)", required = true) + private String sysUserType; + + @ApiModelProperty("state参数(用于防止CSRF攻击)") + private String state; +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeSocialLoginResultDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeSocialLoginResultDto.java new file mode 100644 index 0000000..a2c0a5d --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeSocialLoginResultDto.java @@ -0,0 +1,38 @@ +package com.vetti.hotake.domain.dto; + +import com.vetti.common.core.domain.entity.SysUser; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 社交登录返回结果DTO + * + * @author vetti + */ +@Data +public class HotakeSocialLoginResultDto { + + @ApiModelProperty("令牌") + private String token; + + @ApiModelProperty("用户ID") + private Long userId; + + @ApiModelProperty("用户类型(interviewer:面试官,candidate:候选者)") + private String sysUserType; + + @ApiModelProperty("是否新注册用户(true:新注册,false:已存在用户登录)") + private Boolean isNewUser; + + @ApiModelProperty("第三方平台类型") + private String provider; + + @ApiModelProperty("用户信息对象") + private SysUser user; + + @ApiModelProperty("是否已创建简历(仅候选者有此字段)") + private Boolean hasCv; + + @ApiModelProperty("简历数量(仅候选者有此字段)") + private Integer cvCount; +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeSocialUserInfoDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeSocialUserInfoDto.java new file mode 100644 index 0000000..4c77043 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeSocialUserInfoDto.java @@ -0,0 +1,40 @@ +package com.vetti.hotake.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 第三方平台用户信息DTO(统一格式) + * + * @author vetti + */ +@Data +public class HotakeSocialUserInfoDto { + + @ApiModelProperty("第三方平台类型") + private String provider; + + @ApiModelProperty("第三方平台用户唯一标识") + private String providerUserId; + + @ApiModelProperty("邮箱") + private String email; + + @ApiModelProperty("用户名/昵称") + private String name; + + @ApiModelProperty("头像URL") + private String avatar; + + @ApiModelProperty("访问令牌") + private String accessToken; + + @ApiModelProperty("刷新令牌") + private String refreshToken; + + @ApiModelProperty("令牌有效期(秒)") + private Long expiresIn; + + @ApiModelProperty("原始用户信息JSON") + private String rawUserInfo; +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/VcExperienceDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/VcExperienceDto.java index c1b84d7..791b914 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/VcExperienceDto.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/VcExperienceDto.java @@ -22,6 +22,9 @@ public class VcExperienceDto { @ApiModelProperty("公司") private String company; + @ApiModelProperty("职位") + private String jobPosition; + @ApiModelProperty("地点") private String location; diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeAccessibilityMapper.java b/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeAccessibilityMapper.java new file mode 100644 index 0000000..37548bb --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeAccessibilityMapper.java @@ -0,0 +1,61 @@ +package com.vetti.hotake.mapper; + +import java.util.List; +import com.vetti.hotake.domain.HotakeAccessibility; + +/** + * 用户无障碍设置Mapper接口 + * + * @author vetti + * @date 2026-02-01 + */ +public interface HotakeAccessibilityMapper +{ + /** + * 查询用户无障碍设置 + * + * @param id 用户无障碍设置主键 + * @return 用户无障碍设置 + */ + public HotakeAccessibility selectHotakeAccessibilityById(Integer id); + + /** + * 查询用户无障碍设置列表 + * + * @param hotakeAccessibility 用户无障碍设置 + * @return 用户无障碍设置集合 + */ + public List selectHotakeAccessibilityList(HotakeAccessibility hotakeAccessibility); + + /** + * 新增用户无障碍设置 + * + * @param hotakeAccessibility 用户无障碍设置 + * @return 结果 + */ + public int insertHotakeAccessibility(HotakeAccessibility hotakeAccessibility); + + /** + * 修改用户无障碍设置 + * + * @param hotakeAccessibility 用户无障碍设置 + * @return 结果 + */ + public int updateHotakeAccessibility(HotakeAccessibility hotakeAccessibility); + + /** + * 删除用户无障碍设置 + * + * @param id 用户无障碍设置主键 + * @return 结果 + */ + public int deleteHotakeAccessibilityById(Integer id); + + /** + * 批量删除用户无障碍设置 + * + * @param ids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteHotakeAccessibilityByIds(Integer[] ids); +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeNotificationPreferencesMapper.java b/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeNotificationPreferencesMapper.java new file mode 100644 index 0000000..b15629f --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeNotificationPreferencesMapper.java @@ -0,0 +1,61 @@ +package com.vetti.hotake.mapper; + +import java.util.List; +import com.vetti.hotake.domain.HotakeNotificationPreferences; + +/** + * 用户通知偏好设置Mapper接口 + * + * @author vetti + * @date 2026-02-01 + */ +public interface HotakeNotificationPreferencesMapper +{ + /** + * 查询用户通知偏好设置 + * + * @param id 用户通知偏好设置主键 + * @return 用户通知偏好设置 + */ + public HotakeNotificationPreferences selectHotakeNotificationPreferencesById(Long id); + + /** + * 查询用户通知偏好设置列表 + * + * @param hotakeNotificationPreferences 用户通知偏好设置 + * @return 用户通知偏好设置集合 + */ + public List selectHotakeNotificationPreferencesList(HotakeNotificationPreferences hotakeNotificationPreferences); + + /** + * 新增用户通知偏好设置 + * + * @param hotakeNotificationPreferences 用户通知偏好设置 + * @return 结果 + */ + public int insertHotakeNotificationPreferences(HotakeNotificationPreferences hotakeNotificationPreferences); + + /** + * 修改用户通知偏好设置 + * + * @param hotakeNotificationPreferences 用户通知偏好设置 + * @return 结果 + */ + public int updateHotakeNotificationPreferences(HotakeNotificationPreferences hotakeNotificationPreferences); + + /** + * 删除用户通知偏好设置 + * + * @param id 用户通知偏好设置主键 + * @return 结果 + */ + public int deleteHotakeNotificationPreferencesById(Long id); + + /** + * 批量删除用户通知偏好设置 + * + * @param ids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteHotakeNotificationPreferencesByIds(Long[] ids); +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeReferenceCheckMapper.java b/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeReferenceCheckMapper.java new file mode 100644 index 0000000..d565bea --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeReferenceCheckMapper.java @@ -0,0 +1,61 @@ +package com.vetti.hotake.mapper; + +import java.util.List; +import com.vetti.hotake.domain.HotakeReferenceCheck; + +/** + * 参考检查Mapper接口 + * + * @author sxc + * @date 2026-01-29 + */ +public interface HotakeReferenceCheckMapper +{ + /** + * 查询参考检查 + * + * @param id 参考检查主键 + * @return 参考检查 + */ + public HotakeReferenceCheck selectHotakeReferenceCheckById(Integer id); + + /** + * 查询参考检查列表 + * + * @param hotakeReferenceCheck 参考检查 + * @return 参考检查集合 + */ + public List selectHotakeReferenceCheckList(HotakeReferenceCheck hotakeReferenceCheck); + + /** + * 新增参考检查 + * + * @param hotakeReferenceCheck 参考检查 + * @return 结果 + */ + public int insertHotakeReferenceCheck(HotakeReferenceCheck hotakeReferenceCheck); + + /** + * 修改参考检查 + * + * @param hotakeReferenceCheck 参考检查 + * @return 结果 + */ + public int updateHotakeReferenceCheck(HotakeReferenceCheck hotakeReferenceCheck); + + /** + * 删除参考检查 + * + * @param id 参考检查主键 + * @return 结果 + */ + public int deleteHotakeReferenceCheckById(Integer id); + + /** + * 批量删除参考检查 + * + * @param ids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteHotakeReferenceCheckByIds(Integer[] ids); +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeRolesApplyInfoMapper.java b/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeRolesApplyInfoMapper.java index acb7d25..c66fba3 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeRolesApplyInfoMapper.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeRolesApplyInfoMapper.java @@ -2,6 +2,7 @@ package com.vetti.hotake.mapper; import java.util.List; import com.vetti.hotake.domain.HotakeRolesApplyInfo; +import org.apache.ibatis.annotations.Param; /** * 候选人岗位申请信息Mapper接口 @@ -90,4 +91,13 @@ public interface HotakeRolesApplyInfoMapper */ public int batchInsertHotakeRolesApplyInfo(List hotakeRolesApplyInfoList); + /** + * 根据候选人ID和岗位ID查询申请信息 + * + * @param candidateId 候选人ID + * @param roleId 岗位ID + * @return 候选人岗位申请信息 + */ + public HotakeRolesApplyInfo selectByCandidateIdAndRoleId(@Param("candidateId") Long candidateId, @Param("roleId") Long roleId); + } diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeSettingsJobMapper.java b/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeSettingsJobMapper.java new file mode 100644 index 0000000..70d9dcb --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeSettingsJobMapper.java @@ -0,0 +1,61 @@ +package com.vetti.hotake.mapper; + +import java.util.List; +import com.vetti.hotake.domain.HotakeSettingsJob; + +/** + * 用户首选工作设置Mapper接口 + * + * @author sxc + * @date 2025-11-02 + */ +public interface HotakeSettingsJobMapper +{ + /** + * 查询用户首选工作设置 + * + * @param id 用户首选工作设置主键 + * @return 用户首选工作设置 + */ + public HotakeSettingsJob selectHotakeSettingsJobById(Long id); + + /** + * 查询用户首选工作设置列表 + * + * @param hotakeSettingsJob 用户首选工作设置 + * @return 用户首选工作设置集合 + */ + public List selectHotakeSettingsJobList(HotakeSettingsJob hotakeSettingsJob); + + /** + * 新增用户首选工作设置 + * + * @param hotakeSettingsJob 用户首选工作设置 + * @return 结果 + */ + public int insertHotakeSettingsJob(HotakeSettingsJob hotakeSettingsJob); + + /** + * 修改用户首选工作设置 + * + * @param hotakeSettingsJob 用户首选工作设置 + * @return 结果 + */ + public int updateHotakeSettingsJob(HotakeSettingsJob hotakeSettingsJob); + + /** + * 删除用户首选工作设置 + * + * @param id 用户首选工作设置主键 + * @return 结果 + */ + public int deleteHotakeSettingsJobById(Long id); + + /** + * 批量删除用户首选工作设置 + * + * @param ids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteHotakeSettingsJobByIds(Long[] ids); +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeSocialLoginLogMapper.java b/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeSocialLoginLogMapper.java new file mode 100644 index 0000000..755fe3b --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeSocialLoginLogMapper.java @@ -0,0 +1,16 @@ +package com.vetti.hotake.mapper; + +import com.vetti.hotake.domain.HotakeSocialLoginLog; + +/** + * 社交登录日志Mapper接口 + * + * @author vetti + */ +public interface HotakeSocialLoginLogMapper { + + /** + * 新增社交登录日志 + */ + int insert(HotakeSocialLoginLog log); +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeSocialUserMapper.java b/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeSocialUserMapper.java new file mode 100644 index 0000000..f676bd6 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeSocialUserMapper.java @@ -0,0 +1,45 @@ +package com.vetti.hotake.mapper; + +import com.vetti.hotake.domain.HotakeSocialUser; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用户社交账号绑定Mapper接口 + * + * @author vetti + */ +public interface HotakeSocialUserMapper { + + /** + * 根据provider和providerUserId查询社交用户 + */ + HotakeSocialUser selectByProviderAndProviderUserId(@Param("provider") String provider, + @Param("providerUserId") String providerUserId); + + /** + * 根据用户ID和provider查询社交绑定 + */ + HotakeSocialUser selectByUserIdAndProvider(@Param("userId") Long userId, @Param("provider") String provider); + + /** + * 根据用户ID查询所有社交绑定 + */ + List selectByUserId(@Param("userId") Long userId); + + /** + * 新增社交用户绑定 + */ + int insert(HotakeSocialUser socialUser); + + /** + * 更新社交用户绑定 + */ + int update(HotakeSocialUser socialUser); + + /** + * 删除社交用户绑定(逻辑删除) + */ + int deleteById(@Param("id") Long id); +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeAccessibilityService.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeAccessibilityService.java new file mode 100644 index 0000000..30bc972 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeAccessibilityService.java @@ -0,0 +1,70 @@ +package com.vetti.hotake.service; + +import java.util.List; +import com.vetti.hotake.domain.HotakeAccessibility; + +/** + * 用户无障碍设置Service接口 + * + * @author vetti + * @date 2026-02-01 + */ +public interface IHotakeAccessibilityService +{ + /** + * 查询用户无障碍设置 + * + * @param id 用户无障碍设置主键 + * @return 用户无障碍设置 + */ + public HotakeAccessibility selectHotakeAccessibilityById(Integer id); + + /** + * 查询用户无障碍设置列表 + * + * @param hotakeAccessibility 用户无障碍设置 + * @return 用户无障碍设置集合 + */ + public List selectHotakeAccessibilityList(HotakeAccessibility hotakeAccessibility); + + /** + * 新增用户无障碍设置 + * + * @param hotakeAccessibility 用户无障碍设置 + * @return 结果 + */ + public HotakeAccessibility insertHotakeAccessibility(HotakeAccessibility hotakeAccessibility); + + /** + * 修改用户无障碍设置 + * + * @param hotakeAccessibility 用户无障碍设置 + * @return 结果 + */ + public HotakeAccessibility updateHotakeAccessibility(HotakeAccessibility hotakeAccessibility); + + /** + * 批量删除用户无障碍设置 + * + * @param ids 需要删除的用户无障碍设置主键集合 + * @return 结果 + */ + public int deleteHotakeAccessibilityByIds(Integer[] ids); + + /** + * 删除用户无障碍设置信息 + * + * @param id 用户无障碍设置主键 + * @return 结果 + */ + public int deleteHotakeAccessibilityById(Integer id); + + /** + * 获取当前登录用户的无障碍设置 + * 如果不存在则自动创建默认设置 + * + * @param username 用户名 + * @return 用户无障碍设置 + */ + public HotakeAccessibility getCurrentUserAccessibility(String username); +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeNotificationPreferencesService.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeNotificationPreferencesService.java new file mode 100644 index 0000000..b48dccc --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeNotificationPreferencesService.java @@ -0,0 +1,70 @@ +package com.vetti.hotake.service; + +import java.util.List; +import com.vetti.hotake.domain.HotakeNotificationPreferences; + +/** + * 用户通知偏好设置Service接口 + * + * @author vetti + * @date 2026-02-01 + */ +public interface IHotakeNotificationPreferencesService +{ + /** + * 查询用户通知偏好设置 + * + * @param id 用户通知偏好设置主键 + * @return 用户通知偏好设置 + */ + public HotakeNotificationPreferences selectHotakeNotificationPreferencesById(Long id); + + /** + * 查询用户通知偏好设置列表 + * + * @param hotakeNotificationPreferences 用户通知偏好设置 + * @return 用户通知偏好设置集合 + */ + public List selectHotakeNotificationPreferencesList(HotakeNotificationPreferences hotakeNotificationPreferences); + + /** + * 新增用户通知偏好设置 + * + * @param hotakeNotificationPreferences 用户通知偏好设置 + * @return 结果 + */ + public HotakeNotificationPreferences insertHotakeNotificationPreferences(HotakeNotificationPreferences hotakeNotificationPreferences); + + /** + * 修改用户通知偏好设置 + * + * @param hotakeNotificationPreferences 用户通知偏好设置 + * @return 结果 + */ + public HotakeNotificationPreferences updateHotakeNotificationPreferences(HotakeNotificationPreferences hotakeNotificationPreferences); + + /** + * 批量删除用户通知偏好设置 + * + * @param ids 需要删除的用户通知偏好设置主键集合 + * @return 结果 + */ + public int deleteHotakeNotificationPreferencesByIds(Long[] ids); + + /** + * 删除用户通知偏好设置信息 + * + * @param id 用户通知偏好设置主键 + * @return 结果 + */ + public int deleteHotakeNotificationPreferencesById(Long id); + + /** + * 获取当前登录用户的通知偏好设置 + * 如果不存在则自动创建默认设置 + * + * @param username 用户名 + * @return 用户通知偏好设置 + */ + public HotakeNotificationPreferences getCurrentUserPreferences(String username); +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeReferenceCheckService.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeReferenceCheckService.java new file mode 100644 index 0000000..8844ec7 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeReferenceCheckService.java @@ -0,0 +1,68 @@ +package com.vetti.hotake.service; + +import java.util.List; +import com.vetti.hotake.domain.HotakeReferenceCheck; + +/** + * 参考检查Service接口 + * + * @author vetti + * @date 2026-01-29 + */ +public interface IHotakeReferenceCheckService +{ + /** + * 查询参考检查 + * + * @param id 参考检查主键 + * @return 参考检查 + */ + public HotakeReferenceCheck selectHotakeReferenceCheckById(Integer id); + + /** + * 查询参考检查列表 + * + * @param hotakeReferenceCheck 参考检查 + * @return 参考检查集合 + */ + public List selectHotakeReferenceCheckList(HotakeReferenceCheck hotakeReferenceCheck); + + /** + * 新增参考检查 + * + * @param hotakeReferenceCheck 参考检查 + * @return 结果 + */ + public HotakeReferenceCheck insertHotakeReferenceCheck(HotakeReferenceCheck hotakeReferenceCheck); + + /** + * 修改参考检查 + * + * @param hotakeReferenceCheck 参考检查 + * @return 结果 + */ + public HotakeReferenceCheck updateHotakeReferenceCheck(HotakeReferenceCheck hotakeReferenceCheck); + + /** + * 批量删除参考检查 + * + * @param ids 需要删除的参考检查主键集合 + * @return 结果 + */ + public int deleteHotakeReferenceCheckByIds(Integer[] ids); + + /** + * 删除参考检查信息 + * + * @param id 参考检查主键 + * @return 结果 + */ + public int deleteHotakeReferenceCheckById(Integer id); + + /** + * 获取当前登录人的工作经验列表 + * + * @return 工作经验列表 + */ + public List getCurrentUserExperienceList(); +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeSettingsJobService.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeSettingsJobService.java new file mode 100644 index 0000000..dbdc5f2 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeSettingsJobService.java @@ -0,0 +1,69 @@ +package com.vetti.hotake.service; + +import java.util.List; +import com.vetti.hotake.domain.HotakeSettingsJob; +import com.vetti.hotake.domain.dto.HotakeSettingsJobDictDto; + +/** + * 用户首选工作设置Service接口 + * + * @author wangxiangshun + * @date 2025-11-02 + */ +public interface IHotakeSettingsJobService +{ + /** + * 查询用户首选工作设置 + * + * @param id 用户首选工作设置主键 + * @return 用户首选工作设置 + */ + public HotakeSettingsJob selectHotakeSettingsJobById(Long id); + + /** + * 查询用户首选工作设置列表 + * + * @param hotakeSettingsJob 用户首选工作设置 + * @return 用户首选工作设置集合 + */ + public List selectHotakeSettingsJobList(HotakeSettingsJob hotakeSettingsJob); + + /** + * 新增用户首选工作设置 + * + * @param hotakeSettingsJob 用户首选工作设置 + * @return 结果 + */ + public HotakeSettingsJob insertHotakeSettingsJob(HotakeSettingsJob hotakeSettingsJob); + + /** + * 修改用户首选工作设置 + * + * @param hotakeSettingsJob 用户首选工作设置 + * @return 结果 + */ + public HotakeSettingsJob updateHotakeSettingsJob(HotakeSettingsJob hotakeSettingsJob); + + /** + * 批量删除用户首选工作设置 + * + * @param ids 需要删除的用户首选工作设置主键集合 + * @return 结果 + */ + public int deleteHotakeSettingsJobByIds(Long[] ids); + + /** + * 删除用户首选工作设置信息 + * + * @param id 用户首选工作设置主键 + * @return 结果 + */ + public int deleteHotakeSettingsJobById(Long id); + + /** + * 获取用户首选工作设置字典对照内容 + * + * @return 字典对照内容 + */ + public HotakeSettingsJobDictDto getDictData(); +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeSocialUserService.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeSocialUserService.java new file mode 100644 index 0000000..709b562 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeSocialUserService.java @@ -0,0 +1,49 @@ +package com.vetti.hotake.service; + +import com.vetti.common.core.domain.entity.SysUser; +import com.vetti.hotake.domain.HotakeSocialUser; +import com.vetti.hotake.domain.dto.HotakeSocialLoginRequestDto; +import com.vetti.hotake.domain.dto.HotakeSocialLoginResultDto; + +import java.util.List; + +/** + * 社交用户服务接口 + * + * @author vetti + */ +public interface IHotakeSocialUserService { + + /** + * 社交登录(登录或自动注册) + * + * @param requestDto 社交登录请求 + * @return 登录结果 + */ + HotakeSocialLoginResultDto socialLogin(HotakeSocialLoginRequestDto requestDto); + + /** + * 获取OAuth授权URL + * + * @param provider 平台类型 + * @param state state参数 + * @return 授权URL + */ + String getAuthorizationUrl(String provider, String state); + + /** + * 根据用户ID查询绑定的社交账号 + * + * @param userId 用户ID + * @return 社交账号列表 + */ + List listByUserId(Long userId); + + /** + * 解绑社交账号 + * + * @param userId 用户ID + * @param provider 平台类型 + */ + void unbind(Long userId, String provider); +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeAccessibilityServiceImpl.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeAccessibilityServiceImpl.java new file mode 100644 index 0000000..21be945 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeAccessibilityServiceImpl.java @@ -0,0 +1,138 @@ +package com.vetti.hotake.service.impl; + +import com.vetti.common.core.service.BaseServiceImpl; +import com.vetti.common.enums.FillTypeEnum; +import com.vetti.hotake.domain.HotakeAccessibility; +import com.vetti.hotake.mapper.HotakeAccessibilityMapper; +import com.vetti.hotake.service.IHotakeAccessibilityService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 用户无障碍设置Service业务层处理 + * + * @author vetti + * @date 2026-02-01 + */ +@Service +public class HotakeAccessibilityServiceImpl extends BaseServiceImpl implements IHotakeAccessibilityService { + + @Autowired + private HotakeAccessibilityMapper hotakeAccessibilityMapper; + + /** + * 查询用户无障碍设置 + * + * @param id 用户无障碍设置主键 + * @return 用户无障碍设置 + */ + @Transactional(readOnly = true) + @Override + public HotakeAccessibility selectHotakeAccessibilityById(Integer id) { + return hotakeAccessibilityMapper.selectHotakeAccessibilityById(id); + } + + /** + * 查询用户无障碍设置列表 + * + * @param hotakeAccessibility 用户无障碍设置 + * @return 用户无障碍设置 + */ + @Transactional(readOnly = true) + @Override + public List selectHotakeAccessibilityList(HotakeAccessibility hotakeAccessibility) { + return hotakeAccessibilityMapper.selectHotakeAccessibilityList(hotakeAccessibility); + } + + /** + * 新增用户无障碍设置 + * + * @param hotakeAccessibility 用户无障碍设置 + * @return 结果 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public HotakeAccessibility insertHotakeAccessibility(HotakeAccessibility hotakeAccessibility) { + fill(FillTypeEnum.INSERT.getCode(), hotakeAccessibility); + hotakeAccessibilityMapper.insertHotakeAccessibility(hotakeAccessibility); + return hotakeAccessibility; + } + + /** + * 修改用户无障碍设置 + * + * @param hotakeAccessibility 用户无障碍设置 + * @return 结果 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public HotakeAccessibility updateHotakeAccessibility(HotakeAccessibility hotakeAccessibility) { + fill(FillTypeEnum.UPDATE.getCode(), hotakeAccessibility); + hotakeAccessibilityMapper.updateHotakeAccessibility(hotakeAccessibility); + return hotakeAccessibility; + } + + /** + * 批量删除用户无障碍设置 + * + * @param ids 需要删除的用户无障碍设置主键 + * @return 结果 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public int deleteHotakeAccessibilityByIds(Integer[] ids) { + return hotakeAccessibilityMapper.deleteHotakeAccessibilityByIds(ids); + } + + /** + * 删除用户无障碍设置信息 + * + * @param id 用户无障碍设置主键 + * @return 结果 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public int deleteHotakeAccessibilityById(Integer id) { + return hotakeAccessibilityMapper.deleteHotakeAccessibilityById(id); + } + + /** + * 获取当前登录用户的无障碍设置 + * 如果不存在则自动创建默认设置 + * + * @param username 用户名 + * @return 用户无障碍设置 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public HotakeAccessibility getCurrentUserAccessibility(String username) { + // 查询当前用户的设置 + HotakeAccessibility query = new HotakeAccessibility(); + query.setCreateBy(username); + List list = hotakeAccessibilityMapper.selectHotakeAccessibilityList(query); + + // 如果存在,返回第一条 + if (list != null && !list.isEmpty()) { + return list.get(0); + } + + // 如果不存在,创建默认设置 + HotakeAccessibility defaultAccessibility = new HotakeAccessibility(); + // 设置默认值(根据数据库表定义) + defaultAccessibility.setColorMode("light"); // 默认明亮模式 + defaultAccessibility.setHighContrastMode(0); // 默认关闭 + defaultAccessibility.setReduceMotion(0); // 默认关闭 + defaultAccessibility.setFontSize("medium"); // 默认中等字体 + defaultAccessibility.setScreenReaderSupport(1); // 默认开启 + defaultAccessibility.setAudioDescriptions(1); // 默认开启 + defaultAccessibility.setEnhancedKeyboardNavigation(0); // 默认关闭 + defaultAccessibility.setFocusIndicators(0); // 默认关闭 + defaultAccessibility.setLanguage("en"); // 默认英语 + + // 保存并返回 + return insertHotakeAccessibility(defaultAccessibility); + } +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeNotificationPreferencesServiceImpl.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeNotificationPreferencesServiceImpl.java new file mode 100644 index 0000000..e5fce4e --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeNotificationPreferencesServiceImpl.java @@ -0,0 +1,137 @@ +package com.vetti.hotake.service.impl; + +import com.vetti.common.core.service.BaseServiceImpl; +import com.vetti.common.enums.FillTypeEnum; +import com.vetti.hotake.domain.HotakeNotificationPreferences; +import com.vetti.hotake.mapper.HotakeNotificationPreferencesMapper; +import com.vetti.hotake.service.IHotakeNotificationPreferencesService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 用户通知偏好设置Service业务层处理 + * + * @author vetti + * @date 2026-02-01 + */ +@Service +public class HotakeNotificationPreferencesServiceImpl extends BaseServiceImpl implements IHotakeNotificationPreferencesService { + + @Autowired + private HotakeNotificationPreferencesMapper hotakeNotificationPreferencesMapper; + + /** + * 查询用户通知偏好设置 + * + * @param id 用户通知偏好设置主键 + * @return 用户通知偏好设置 + */ + @Transactional(readOnly = true) + @Override + public HotakeNotificationPreferences selectHotakeNotificationPreferencesById(Long id) { + return hotakeNotificationPreferencesMapper.selectHotakeNotificationPreferencesById(id); + } + + /** + * 查询用户通知偏好设置列表 + * + * @param hotakeNotificationPreferences 用户通知偏好设置 + * @return 用户通知偏好设置 + */ + @Transactional(readOnly = true) + @Override + public List selectHotakeNotificationPreferencesList(HotakeNotificationPreferences hotakeNotificationPreferences) { + return hotakeNotificationPreferencesMapper.selectHotakeNotificationPreferencesList(hotakeNotificationPreferences); + } + + /** + * 新增用户通知偏好设置 + * + * @param hotakeNotificationPreferences 用户通知偏好设置 + * @return 结果 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public HotakeNotificationPreferences insertHotakeNotificationPreferences(HotakeNotificationPreferences hotakeNotificationPreferences) { + fill(FillTypeEnum.INSERT.getCode(), hotakeNotificationPreferences); + hotakeNotificationPreferencesMapper.insertHotakeNotificationPreferences(hotakeNotificationPreferences); + return hotakeNotificationPreferences; + } + + /** + * 修改用户通知偏好设置 + * + * @param hotakeNotificationPreferences 用户通知偏好设置 + * @return 结果 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public HotakeNotificationPreferences updateHotakeNotificationPreferences(HotakeNotificationPreferences hotakeNotificationPreferences) { + fill(FillTypeEnum.UPDATE.getCode(), hotakeNotificationPreferences); + hotakeNotificationPreferencesMapper.updateHotakeNotificationPreferences(hotakeNotificationPreferences); + return hotakeNotificationPreferences; + } + + /** + * 批量删除用户通知偏好设置 + * + * @param ids 需要删除的用户通知偏好设置主键 + * @return 结果 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public int deleteHotakeNotificationPreferencesByIds(Long[] ids) { + return hotakeNotificationPreferencesMapper.deleteHotakeNotificationPreferencesByIds(ids); + } + + /** + * 删除用户通知偏好设置信息 + * + * @param id 用户通知偏好设置主键 + * @return 结果 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public int deleteHotakeNotificationPreferencesById(Long id) { + return hotakeNotificationPreferencesMapper.deleteHotakeNotificationPreferencesById(id); + } + + /** + * 获取当前登录用户的通知偏好设置 + * 如果不存在则自动创建默认设置 + * + * @param username 用户名 + * @return 用户通知偏好设置 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public HotakeNotificationPreferences getCurrentUserPreferences(String username) { + // 查询当前用户的设置 + HotakeNotificationPreferences query = new HotakeNotificationPreferences(); + query.setCreateBy(username); + List list = hotakeNotificationPreferencesMapper.selectHotakeNotificationPreferencesList(query); + + // 如果存在,返回第一条 + if (list != null && !list.isEmpty()) { + return list.get(0); + } + + // 如果不存在,创建默认设置 + HotakeNotificationPreferences defaultPreferences = new HotakeNotificationPreferences(); + // 设置默认值(根据数据库表定义) + defaultPreferences.setEmailJobAlerts(1); // 默认开启 + defaultPreferences.setEmailApplicationUpdates(1); // 默认开启 + defaultPreferences.setEmailAiMatchSuggestions(0); // 默认关闭 + defaultPreferences.setEmailNewsletter(0); // 默认关闭 + defaultPreferences.setPushNewMessages(1); // 默认开启 + defaultPreferences.setPushInterviewReminders(1); // 默认开启 + defaultPreferences.setMailMarketingEmails(0); // 默认关闭 + defaultPreferences.setMailPartnerOffers(0); // 默认关闭 + + // 保存并返回 + return insertHotakeNotificationPreferences(defaultPreferences); + } +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeReferenceCheckServiceImpl.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeReferenceCheckServiceImpl.java new file mode 100644 index 0000000..1acd129 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeReferenceCheckServiceImpl.java @@ -0,0 +1,142 @@ +package com.vetti.hotake.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.vetti.common.core.service.BaseServiceImpl; +import com.vetti.common.enums.FillTypeEnum; +import com.vetti.common.utils.SecurityUtils; +import com.vetti.hotake.domain.HotakeCvInfo; +import com.vetti.hotake.domain.HotakeReferenceCheck; +import com.vetti.hotake.domain.dto.HotakeCvInfoDto; +import com.vetti.hotake.domain.dto.VcDto.VcExperienceDto; +import com.vetti.hotake.mapper.HotakeCvInfoMapper; +import com.vetti.hotake.mapper.HotakeReferenceCheckMapper; +import com.vetti.hotake.service.IHotakeReferenceCheckService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; + +/** + * 参考检查Service业务层处理 + * + * @author vetti + * @date 2026-01-29 + */ +@Service +public class HotakeReferenceCheckServiceImpl extends BaseServiceImpl implements IHotakeReferenceCheckService { + + @Autowired + private HotakeReferenceCheckMapper hotakeReferenceCheckMapper; + + @Autowired + private HotakeCvInfoMapper hotakeCvInfoMapper; + + /** + * 查询参考检查 + * + * @param id 参考检查主键 + * @return 参考检查 + */ + @Transactional(readOnly = true) + @Override + public HotakeReferenceCheck selectHotakeReferenceCheckById(Integer id) { + return hotakeReferenceCheckMapper.selectHotakeReferenceCheckById(id); + } + + /** + * 查询参考检查列表 + * + * @param hotakeReferenceCheck 参考检查 + * @return 参考检查 + */ + @Transactional(readOnly = true) + @Override + public List selectHotakeReferenceCheckList(HotakeReferenceCheck hotakeReferenceCheck) { + return hotakeReferenceCheckMapper.selectHotakeReferenceCheckList(hotakeReferenceCheck); + } + + /** + * 新增参考检查 + * + * @param hotakeReferenceCheck 参考检查 + * @return 结果 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public HotakeReferenceCheck insertHotakeReferenceCheck(HotakeReferenceCheck hotakeReferenceCheck) { + fill(FillTypeEnum.INSERT.getCode(), hotakeReferenceCheck); + hotakeReferenceCheckMapper.insertHotakeReferenceCheck(hotakeReferenceCheck); + return hotakeReferenceCheck; + } + + /** + * 修改参考检查 + * + * @param hotakeReferenceCheck 参考检查 + * @return 结果 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public HotakeReferenceCheck updateHotakeReferenceCheck(HotakeReferenceCheck hotakeReferenceCheck) { + fill(FillTypeEnum.UPDATE.getCode(), hotakeReferenceCheck); + hotakeReferenceCheckMapper.updateHotakeReferenceCheck(hotakeReferenceCheck); + return hotakeReferenceCheck; + } + + /** + * 批量删除参考检查 + * + * @param ids 需要删除的参考检查主键 + * @return 结果 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public int deleteHotakeReferenceCheckByIds(Integer[] ids) { + return hotakeReferenceCheckMapper.deleteHotakeReferenceCheckByIds(ids); + } + + /** + * 删除参考检查信息 + * + * @param id 参考检查主键 + * @return 结果 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public int deleteHotakeReferenceCheckById(Integer id) { + return hotakeReferenceCheckMapper.deleteHotakeReferenceCheckById(id); + } + + /** + * 获取当前登录人的工作经验列表 + * + * @return 工作经验列表 + */ + @Transactional(readOnly = true) + @Override + public List getCurrentUserExperienceList() { + List experienceList = new ArrayList<>(); + + // 查询当前用户的简历信息 + HotakeCvInfo queryCv = new HotakeCvInfo(); + queryCv.setUserId(SecurityUtils.getUserId()); + queryCv.setCvFileType("cv"); + List cvInfoList = hotakeCvInfoMapper.selectHotakeCvInfoList(queryCv); + + if (CollectionUtil.isNotEmpty(cvInfoList)) { + HotakeCvInfo cvInfo = cvInfoList.get(0); + if (StrUtil.isNotEmpty(cvInfo.getCvTemplateJson())) { + HotakeCvInfoDto cvInfoDto = JSONUtil.toBean(cvInfo.getCvTemplateJson(), HotakeCvInfoDto.class); + if (cvInfoDto != null && CollectionUtil.isNotEmpty(cvInfoDto.getExperience())) { + experienceList = cvInfoDto.getExperience(); + } + } + } + + return experienceList; + } +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeRolesApplyInfoServiceImpl.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeRolesApplyInfoServiceImpl.java index d31cf96..d3ebf49 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeRolesApplyInfoServiceImpl.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeRolesApplyInfoServiceImpl.java @@ -9,6 +9,7 @@ import com.vetti.common.core.service.BaseServiceImpl; import com.vetti.common.enums.FillTypeEnum; import com.vetti.common.enums.StageEnum; import com.vetti.common.exception.ServiceException; +import com.vetti.common.utils.MessageUtils; import com.vetti.common.utils.SecurityUtils; import com.vetti.hotake.domain.*; import com.vetti.hotake.domain.dto.*; @@ -169,7 +170,17 @@ public class HotakeRolesApplyInfoServiceImpl extends BaseServiceImpl implements public HotakeRolesApplyInfo insertHotakeRolesApplyInfo(HotakeRolesApplyInfo hotakeRolesApplyInfo) { fill(FillTypeEnum.INSERT.getCode(), hotakeRolesApplyInfo); - hotakeRolesApplyInfo.setCandidateId(SecurityUtils.getUserId()); + Long candidateId = SecurityUtils.getUserId(); + hotakeRolesApplyInfo.setCandidateId(candidateId); + + // 校验候选人和岗位的唯一性 + if (hotakeRolesApplyInfo.getRoleId() != null) { + HotakeRolesApplyInfo existInfo = hotakeRolesApplyInfoMapper.selectByCandidateIdAndRoleId(candidateId, hotakeRolesApplyInfo.getRoleId()); + if (existInfo != null) { + throw new ServiceException(MessageUtils.messageCustomize("HotakeRolesApplyInfoServiceImpl10001")); + } + } + String fileSuffix = FileUtil.getSuffix(hotakeRolesApplyInfo.getCvFile()); if (StrUtil.isNotEmpty(fileSuffix)) { fileSuffix = fileSuffix.toLowerCase(); @@ -190,7 +201,17 @@ public class HotakeRolesApplyInfoServiceImpl extends BaseServiceImpl implements public HotakeRolesApplyInfo updateHotakeRolesApplyInfo(HotakeRolesApplyInfo hotakeRolesApplyInfo) { fill(FillTypeEnum.UPDATE.getCode(), hotakeRolesApplyInfo); - hotakeRolesApplyInfo.setCandidateId(SecurityUtils.getUserId()); + Long candidateId = SecurityUtils.getUserId(); + hotakeRolesApplyInfo.setCandidateId(candidateId); + + // 校验候选人和岗位的唯一性(排除自身) + if (hotakeRolesApplyInfo.getRoleId() != null && hotakeRolesApplyInfo.getId() != null) { + HotakeRolesApplyInfo existInfo = hotakeRolesApplyInfoMapper.selectByCandidateIdAndRoleId(candidateId, hotakeRolesApplyInfo.getRoleId()); + if (existInfo != null && !existInfo.getId().equals(hotakeRolesApplyInfo.getId())) { + throw new ServiceException(MessageUtils.messageCustomize("HotakeRolesApplyInfoServiceImpl10001")); + } + } + String fileSuffix = FileUtil.getSuffix(hotakeRolesApplyInfo.getCvFile()); if (StrUtil.isNotEmpty(fileSuffix)) { fileSuffix = fileSuffix.toLowerCase(); diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeRolesInfoServiceImpl.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeRolesInfoServiceImpl.java index 75fdd94..32714a4 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeRolesInfoServiceImpl.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeRolesInfoServiceImpl.java @@ -134,6 +134,11 @@ public class HotakeRolesInfoServiceImpl extends BaseServiceImpl implements IHota SysUser user = sysUserMapper.selectUserById(hotakeRolesInfo.getRecruiterId()); dto.setRecruiterUser(user); + + // 判断当前用户是否已申请该岗位 + Long currentUserId = SecurityUtils.getUserId(); + HotakeRolesApplyInfo existApply = hotakeRolesApplyInfoMapper.selectByCandidateIdAndRoleId(currentUserId, id); + dto.setHasApplied(existApply != null); } return dto; diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeSettingsJobServiceImpl.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeSettingsJobServiceImpl.java new file mode 100644 index 0000000..60060a0 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeSettingsJobServiceImpl.java @@ -0,0 +1,160 @@ +package com.vetti.hotake.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import com.vetti.common.core.domain.entity.SysDictData; +import com.vetti.common.core.service.BaseServiceImpl; +import com.vetti.common.enums.FillTypeEnum; +import com.vetti.hotake.domain.HotakeSettingsJob; +import com.vetti.hotake.domain.dto.HotakeSettingsJobDictDto; +import com.vetti.hotake.mapper.HotakeSettingsJobMapper; +import com.vetti.hotake.service.IHotakeSettingsJobService; +import com.vetti.system.service.ISysDictTypeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; + +/** + * 用户首选工作设置Service业务层处理 + * + * @author wangxiangshun + * @date 2025-11-02 + */ +@Service +public class HotakeSettingsJobServiceImpl extends BaseServiceImpl implements IHotakeSettingsJobService { + + @Autowired + private HotakeSettingsJobMapper hotakeSettingsJobMapper; + + @Autowired + private ISysDictTypeService dictTypeService; + + /** + * 查询用户首选工作设置 + * + * @param id 用户首选工作设置主键 + * @return 用户首选工作设置 + */ + @Transactional(readOnly = true) + @Override + public HotakeSettingsJob selectHotakeSettingsJobById(Long id) { + return hotakeSettingsJobMapper.selectHotakeSettingsJobById(id); + } + + /** + * 查询用户首选工作设置列表 + * + * @param hotakeSettingsJob 用户首选工作设置 + * @return 用户首选工作设置 + */ + @Transactional(readOnly = true) + @Override + public List selectHotakeSettingsJobList(HotakeSettingsJob hotakeSettingsJob) { + return hotakeSettingsJobMapper.selectHotakeSettingsJobList(hotakeSettingsJob); + } + + /** + * 新增用户首选工作设置 + * + * @param hotakeSettingsJob 用户首选工作设置 + * @return 结果 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public HotakeSettingsJob insertHotakeSettingsJob(HotakeSettingsJob hotakeSettingsJob) { + fill(FillTypeEnum.INSERT.getCode(), hotakeSettingsJob); + hotakeSettingsJobMapper.insertHotakeSettingsJob(hotakeSettingsJob); + return hotakeSettingsJob; + } + + /** + * 修改用户首选工作设置 + * + * @param hotakeSettingsJob 用户首选工作设置 + * @return 结果 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public HotakeSettingsJob updateHotakeSettingsJob(HotakeSettingsJob hotakeSettingsJob) { + fill(FillTypeEnum.UPDATE.getCode(), hotakeSettingsJob); + hotakeSettingsJobMapper.updateHotakeSettingsJob(hotakeSettingsJob); + return hotakeSettingsJob; + } + + /** + * 批量删除用户首选工作设置 + * + * @param ids 需要删除的用户首选工作设置主键 + * @return 结果 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public int deleteHotakeSettingsJobByIds(Long[] ids) { + return hotakeSettingsJobMapper.deleteHotakeSettingsJobByIds(ids); + } + + /** + * 删除用户首选工作设置信息 + * + * @param id 用户首选工作设置主键 + * @return 结果 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public int deleteHotakeSettingsJobById(Long id) { + return hotakeSettingsJobMapper.deleteHotakeSettingsJobById(id); + } + + /** + * 获取用户首选工作设置字典对照内容 + * + * @return 字典对照内容 + */ + @Transactional(readOnly = true) + @Override + public HotakeSettingsJobDictDto getDictData() { + HotakeSettingsJobDictDto dto = new HotakeSettingsJobDictDto(); + + dto.setHotakeLanguagesType(convertToDictItems(dictTypeService.selectDictDataByType("hotake_languages_type"))); + dto.setHotakeSkillsToolType(convertToDictItems(dictTypeService.selectDictDataByType("hotake_skills_tool_type"))); + dto.setRoleLevel(convertToDictItems(dictTypeService.selectDictDataByType("role_level"))); + dto.setRoleLocationType(convertToDictItems(dictTypeService.selectDictDataByType("role_location_type"))); + dto.setRoleSelectJobType(convertToDictItems(dictTypeService.selectDictDataByType("role_select_job_type"))); + dto.setRoleType(convertToDictItems(dictTypeService.selectDictDataByType("role_type"))); + dto.setRoleRequiredSkills(convertToDictItems(dictTypeService.selectDictDataByType("role_required_skills"))); + dto.setRoleNiceToHaveSkills(convertToDictItems(dictTypeService.selectDictDataByType("role_nice_to_have_skills"))); + dto.setRoleEducationRequirementsType(convertToDictItems(dictTypeService.selectDictDataByType("role_education_requirements_type"))); + dto.setRoleCertificationLicenses(convertToDictItems(dictTypeService.selectDictDataByType("role_certification_licenses"))); + dto.setRoleBenefits(convertToDictItems(dictTypeService.selectDictDataByType("role_benefits"))); + dto.setRolePublishingChannels(convertToDictItems(dictTypeService.selectDictDataByType("role_publishing_channels"))); + dto.setRoleInitialScreeningQuestionsType(convertToDictItems(dictTypeService.selectDictDataByType("role_initial_screening_questions_type"))); + dto.setExpectedPayRange(convertToDictItems(dictTypeService.selectDictDataByType("expected_pay_range"))); + dto.setWillingnessToTravel(convertToDictItems(dictTypeService.selectDictDataByType("willingness_to_travel"))); + + return dto; + } + + private List convertToDictItems(List dictDataList) { + List items = new ArrayList<>(); + if (CollectionUtil.isNotEmpty(dictDataList)) { + for (SysDictData dictData : dictDataList) { + HotakeSettingsJobDictDto.DictItem item = new HotakeSettingsJobDictDto.DictItem(); + item.setDictCode(dictData.getDictCode()); + item.setDictLabel(dictData.getDictLabel()); + item.setDictValue(dictData.getDictValue()); + item.setDictType(dictData.getDictType()); + item.setCssClass(dictData.getCssClass()); + item.setListClass(dictData.getListClass()); + item.setIsDefault(dictData.getIsDefault()); + item.setStatus(dictData.getStatus()); + item.setDataType(dictData.getDataType()); + item.setFileUrl(dictData.getFileUrl()); + item.setAvatarUrl(dictData.getAvatarUrl()); + items.add(item); + } + } + return items; + } +} diff --git a/vetti-hotakes/src/main/resources/mapper/hotake/HotakeAccessibilityMapper.xml b/vetti-hotakes/src/main/resources/mapper/hotake/HotakeAccessibilityMapper.xml new file mode 100644 index 0000000..4334fb8 --- /dev/null +++ b/vetti-hotakes/src/main/resources/mapper/hotake/HotakeAccessibilityMapper.xml @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + select id, color_mode, high_contrast_mode, reduce_motion, font_size, + screen_reader_support, audio_descriptions, enhanced_keyboard_navigation, + focus_indicators, language, + del_flag, create_by, create_time, update_by, update_time, remark + from hotake_accessibility + + + + + + + + insert into hotake_accessibility + + color_mode, + high_contrast_mode, + reduce_motion, + font_size, + screen_reader_support, + audio_descriptions, + enhanced_keyboard_navigation, + focus_indicators, + language, + del_flag, + create_by, + create_time, + update_by, + update_time, + remark, + + + #{colorMode}, + #{highContrastMode}, + #{reduceMotion}, + #{fontSize}, + #{screenReaderSupport}, + #{audioDescriptions}, + #{enhancedKeyboardNavigation}, + #{focusIndicators}, + #{language}, + #{delFlag}, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + #{remark}, + + + + + update hotake_accessibility + + color_mode = #{colorMode}, + high_contrast_mode = #{highContrastMode}, + reduce_motion = #{reduceMotion}, + font_size = #{fontSize}, + screen_reader_support = #{screenReaderSupport}, + audio_descriptions = #{audioDescriptions}, + enhanced_keyboard_navigation = #{enhancedKeyboardNavigation}, + focus_indicators = #{focusIndicators}, + language = #{language}, + del_flag = #{delFlag}, + create_by = #{createBy}, + create_time = #{createTime}, + update_by = #{updateBy}, + update_time = #{updateTime}, + remark = #{remark}, + + where id = #{id} + + + + delete from hotake_accessibility where id = #{id} + + + + delete from hotake_accessibility where id in + + #{id} + + + diff --git a/vetti-hotakes/src/main/resources/mapper/hotake/HotakeNotificationPreferencesMapper.xml b/vetti-hotakes/src/main/resources/mapper/hotake/HotakeNotificationPreferencesMapper.xml new file mode 100644 index 0000000..3894a01 --- /dev/null +++ b/vetti-hotakes/src/main/resources/mapper/hotake/HotakeNotificationPreferencesMapper.xml @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + select id, email_job_alerts, email_application_updates, email_ai_match_suggestions, + email_newsletter, push_new_messages, push_interview_reminders, + mail_marketing_emails, mail_partner_offers, + del_flag, create_by, create_time, update_by, update_time, remark + from hotake_notification_preferences + + + + + + + + insert into hotake_notification_preferences + + email_job_alerts, + email_application_updates, + email_ai_match_suggestions, + email_newsletter, + push_new_messages, + push_interview_reminders, + mail_marketing_emails, + mail_partner_offers, + del_flag, + create_by, + create_time, + update_by, + update_time, + remark, + + + #{emailJobAlerts}, + #{emailApplicationUpdates}, + #{emailAiMatchSuggestions}, + #{emailNewsletter}, + #{pushNewMessages}, + #{pushInterviewReminders}, + #{mailMarketingEmails}, + #{mailPartnerOffers}, + #{delFlag}, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + #{remark}, + + + + + update hotake_notification_preferences + + email_job_alerts = #{emailJobAlerts}, + email_application_updates = #{emailApplicationUpdates}, + email_ai_match_suggestions = #{emailAiMatchSuggestions}, + email_newsletter = #{emailNewsletter}, + push_new_messages = #{pushNewMessages}, + push_interview_reminders = #{pushInterviewReminders}, + mail_marketing_emails = #{mailMarketingEmails}, + mail_partner_offers = #{mailPartnerOffers}, + del_flag = #{delFlag}, + create_by = #{createBy}, + create_time = #{createTime}, + update_by = #{updateBy}, + update_time = #{updateTime}, + remark = #{remark}, + + where id = #{id} + + + + delete from hotake_notification_preferences where id = #{id} + + + + delete from hotake_notification_preferences where id in + + #{id} + + + diff --git a/vetti-hotakes/src/main/resources/mapper/hotake/HotakeReferenceCheckMapper.xml b/vetti-hotakes/src/main/resources/mapper/hotake/HotakeReferenceCheckMapper.xml new file mode 100644 index 0000000..50726d8 --- /dev/null +++ b/vetti-hotakes/src/main/resources/mapper/hotake/HotakeReferenceCheckMapper.xml @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + select id, company, full_name, position, relationship, email, save_job_experience, + del_flag, create_by, create_time, update_by, update_time, remark + from hotake_reference_check + + + + + + + + insert into hotake_reference_check + + company, + full_name, + position, + relationship, + email, + save_job_experience, + del_flag, + create_by, + create_time, + update_by, + update_time, + remark, + + + #{company}, + #{fullName}, + #{position}, + #{relationship}, + #{email}, + #{saveJobExperience}, + #{delFlag}, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + #{remark}, + + + + + update hotake_reference_check + + company = #{company}, + full_name = #{fullName}, + position = #{position}, + relationship = #{relationship}, + email = #{email}, + save_job_experience = #{saveJobExperience}, + del_flag = #{delFlag}, + create_by = #{createBy}, + create_time = #{createTime}, + update_by = #{updateBy}, + update_time = #{updateTime}, + remark = #{remark}, + + where id = #{id} + + + + delete from hotake_reference_check where id = #{id} + + + + delete from hotake_reference_check where id in + + #{id} + + + diff --git a/vetti-hotakes/src/main/resources/mapper/hotake/HotakeRolesApplyInfoMapper.xml b/vetti-hotakes/src/main/resources/mapper/hotake/HotakeRolesApplyInfoMapper.xml index 00fcc9c..3a74761 100644 --- a/vetti-hotakes/src/main/resources/mapper/hotake/HotakeRolesApplyInfoMapper.xml +++ b/vetti-hotakes/src/main/resources/mapper/hotake/HotakeRolesApplyInfoMapper.xml @@ -341,4 +341,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ( #{item.id}, #{item.candidateId},#{item.recruiterId}, #{item.roleId}, #{item.fullName}, #{item.email}, #{item.phoneNumber}, #{item.cvFile}, #{item.coverLetter}, #{item.candidateStatus}, #{item.stage}, #{item.lastContact}, #{item.cvTemplateJson}, #{item.cvScore}, #{item.cvMd5}, #{item.experience}, #{item.aiMatchScore}, #{item.aiMatchScorePercentage}, #{item.delFlag}, #{item.createBy}, #{item.createTime}, #{item.updateBy}, #{item.updateTime}, #{item.remark}) + + \ No newline at end of file diff --git a/vetti-hotakes/src/main/resources/mapper/hotake/HotakeSettingsJobMapper.xml b/vetti-hotakes/src/main/resources/mapper/hotake/HotakeSettingsJobMapper.xml new file mode 100644 index 0000000..b4f1499 --- /dev/null +++ b/vetti-hotakes/src/main/resources/mapper/hotake/HotakeSettingsJobMapper.xml @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + select id, name, location, latitude, longitude, salary, tags_json, + del_flag, create_by, create_time, update_by, update_time, remark from hotake_settings_job + + + + + + + + insert into hotake_settings_job + + name, + location, + latitude, + longitude, + salary, + tags_json, + del_flag, + create_by, + create_time, + update_by, + update_time, + remark, + + + #{name}, + #{location}, + #{latitude}, + #{longitude}, + #{salary}, + #{tagsJson}, + #{delFlag}, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + #{remark}, + + + + + update hotake_settings_job + + name = #{name}, + location = #{location}, + latitude = #{latitude}, + longitude = #{longitude}, + salary = #{salary}, + tags_json = #{tagsJson}, + del_flag = #{delFlag}, + create_by = #{createBy}, + create_time = #{createTime}, + update_by = #{updateBy}, + update_time = #{updateTime}, + remark = #{remark}, + + where id = #{id} + + + + delete from hotake_settings_job where id = #{id} + + + + delete from hotake_settings_job where id in + + #{id} + + + diff --git a/vetti-hotakes/src/main/resources/mapper/hotake/HotakeSocialLoginLogMapper.xml b/vetti-hotakes/src/main/resources/mapper/hotake/HotakeSocialLoginLogMapper.xml new file mode 100644 index 0000000..39ffa6a --- /dev/null +++ b/vetti-hotakes/src/main/resources/mapper/hotake/HotakeSocialLoginLogMapper.xml @@ -0,0 +1,15 @@ + + + + + + insert into hotake_social_login_log ( + user_id, provider, provider_user_id, login_type, login_ip, login_location, + browser, os, status, msg, login_time + ) values ( + #{userId}, #{provider}, #{providerUserId}, #{loginType}, #{loginIp}, #{loginLocation}, + #{browser}, #{os}, #{status}, #{msg}, #{loginTime} + ) + + + diff --git a/vetti-hotakes/src/main/resources/mapper/hotake/HotakeSocialUserMapper.xml b/vetti-hotakes/src/main/resources/mapper/hotake/HotakeSocialUserMapper.xml new file mode 100644 index 0000000..4a85765 --- /dev/null +++ b/vetti-hotakes/src/main/resources/mapper/hotake/HotakeSocialUserMapper.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + id, user_id, provider, provider_user_id, email, name, avatar, access_token, refresh_token, + token_expire_time, raw_user_info, del_flag, create_by, create_time, update_by, update_time, remark + + + + + + + + + + insert into hotake_social_user ( + user_id, provider, provider_user_id, email, name, avatar, access_token, refresh_token, + token_expire_time, raw_user_info, del_flag, create_by, create_time, remark + ) values ( + #{userId}, #{provider}, #{providerUserId}, #{email}, #{name}, #{avatar}, #{accessToken}, #{refreshToken}, + #{tokenExpireTime}, #{rawUserInfo}, '0', #{createBy}, now(), #{remark} + ) + + + + update hotake_social_user + + user_id = #{userId}, + email = #{email}, + name = #{name}, + avatar = #{avatar}, + access_token = #{accessToken}, + refresh_token = #{refreshToken}, + token_expire_time = #{tokenExpireTime}, + raw_user_info = #{rawUserInfo}, + update_by = #{updateBy}, + update_time = now() + + where id = #{id} + + + + update hotake_social_user set del_flag = '2', update_time = now() where id = #{id} + + +