diff --git a/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeMeetingCalendarInfoController.java b/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeMeetingCalendarInfoController.java index fc7e24b..dd01c41 100644 --- a/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeMeetingCalendarInfoController.java +++ b/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeMeetingCalendarInfoController.java @@ -122,4 +122,16 @@ public class HotakeMeetingCalendarInfoController extends BaseController List list = hotakeMeetingCalendarInfoService.selectHotakeMeetingCalendarDataDtoList(); return R.ok(list,""); } + + + /** + * 获取当前候选人即将开始的会议信息 + */ + @ApiOperation("获取当前候选人即将开始的会议信息") + @GetMapping(value = "/getCandidateStartCalendarInfo") + public R getCandidateStartCalendarInfo() + { + return R.ok(hotakeMeetingCalendarInfoService.selectCandidateStartCalendarInfo()); + } + } diff --git a/vetti-admin/src/main/resources/application-druid.yml b/vetti-admin/src/main/resources/application-druid.yml index 1463f6f..feb4f08 100644 --- a/vetti-admin/src/main/resources/application-druid.yml +++ b/vetti-admin/src/main/resources/application-druid.yml @@ -138,6 +138,7 @@ twilio: reply-to-em7941: noreply@em7941.routez.app template-ids: routez-verification-code: d-18475c5d41e349e2bc3a35f2b4992182 + interview-template-code: d-c377f1e7f5e04cb794e2753af9d2e0c8 accountSID: 1111 authToken: 22222 sendPhoneNumber: 33333 diff --git a/vetti-common/src/main/java/com/vetti/common/config/TwilioConfig.java b/vetti-common/src/main/java/com/vetti/common/config/TwilioConfig.java index 548ffb8..fb0cfda 100644 --- a/vetti-common/src/main/java/com/vetti/common/config/TwilioConfig.java +++ b/vetti-common/src/main/java/com/vetti/common/config/TwilioConfig.java @@ -24,7 +24,7 @@ public class TwilioConfig { @Data public static class TemplateIds { private String routezVerificationCode; - + private String interviewTemplateCode; } } diff --git a/vetti-common/src/main/java/com/vetti/common/constant/AiCommonPromptConstants.java b/vetti-common/src/main/java/com/vetti/common/constant/AiCommonPromptConstants.java index ea68655..cec3943 100644 --- a/vetti-common/src/main/java/com/vetti/common/constant/AiCommonPromptConstants.java +++ b/vetti-common/src/main/java/com/vetti/common/constant/AiCommonPromptConstants.java @@ -61,26 +61,46 @@ public class AiCommonPromptConstants { "- Core Keywords: Safety first, quality control, project management, teamwork\n" + "- Key Requirements: Safety awareness, field experience, technical qualifications, stress resistance\n" + "- Development Path: Technical specialization, project management, safety management, quality control\n" + + "- Typical Skills:\n" + + " * Technical Skills: Project Management, AutoCAD, MS Project, Building Codes, Construction Management, Site Supervision, Quality Control, Safety Management\n" + + " * Soft Skills: Team Leadership, Communication, Problem-solving, Time Management, Conflict Resolution\n" + + " * Certifications: White Card, First Aid Certificate, WHS Certificates, Trade Licenses, PMP (for management roles)\n" + "\n" + "### Logistics Industry\n" + "- Core Keywords: Efficiency optimization, cost control, supply chain management, customer service\n" + "- Key Requirements: Time management, communication coordination, problem solving, strong responsibility\n" + "- Development Path: Operations optimization, management advancement, professional certification, cross-departmental development\n" + + "- Typical Skills:\n" + + " * Technical Skills: Warehouse Management, WMS Systems, Transportation Scheduling, Inventory Control, Supply Chain Management, Route Planning, Logistics Software\n" + + " * Soft Skills: Time Management, Customer Service, Communication, Problem-solving, Attention to Detail\n" + + " * Certifications: Forklift License, Dangerous Goods Handling, Supply Chain Certifications\n" + "\n" + "### Manufacturing Industry\n" + "- Core Keywords: Production efficiency, quality standards, safe operations, continuous improvement\n" + "- Key Requirements: Technical skills, safety awareness, teamwork, learning ability\n" + "- Development Path: Skill enhancement, team leader, supervisor, professional technical route\n" + + "- Typical Skills:\n" + + " * Technical Skills: Production Management, Quality Inspection, Equipment Operation, Lean Manufacturing, 6S Management, Process Control, Machine Operation\n" + + " * Soft Skills: Teamwork, Attention to Detail, Problem-solving, Continuous Improvement Mindset\n" + + " * Certifications: Machine Operation Licenses, Quality Control Certifications, Safety Certifications\n" + "\n" + "### Hospitality Industry\n" + "- Core Keywords: Customer service, teamwork, flexibility, professional image\n" + "- Key Requirements: Service mindset, communication skills, stress resistance, language abilities\n" + "- Development Path: Service specialization, management training, department supervisor, hotel management\n" + + "- Typical Skills:\n" + + " * Technical Skills: Customer Service, Front Desk Management, Booking Systems, Food & Beverage Service, Housekeeping Management, POS Systems\n" + + " * Soft Skills: Multilingual Communication, Guest Relations, Problem-solving, Flexibility, Professional Appearance\n" + + " * Certifications: RSA (Responsible Service of Alcohol), Food Safety, First Aid\n" + "\n" + "### Mining Industry\n" + "- Core Keywords: Safe operations, environmental protection, technical standards, teamwork\n" + "- Key Requirements: Safety awareness, physical requirements, technical qualifications, emergency response\n" + "- Development Path: Technical certification, safety management, equipment expertise, field management\n" + + "- Typical Skills:\n" + + " * Technical Skills: Safety Operations, Equipment Maintenance, Geological Exploration, Environmental Monitoring, Emergency Response, Mining Regulations, Heavy Machinery Operation\n" + + " * Soft Skills: Teamwork, Physical Fitness, Stress Management, Attention to Detail, Environmental Awareness\n" + + " * Certifications: Mining Licenses, Heavy Vehicle Licenses, Safety Certifications, First Aid, Emergency Response Training\n" + "\n" + "Language Style:\n" + "- Practical and down-to-earth, close to frontline work\n" + @@ -89,6 +109,12 @@ public class AiCommonPromptConstants { "- Emphasize teamwork and responsibility\n" + "- Avoid overly technical expressions, use clear and understandable language\n" + "\n" + + "**IMPORTANT - Skills Requirements:**\n" + + "- Skills MUST match the target industry (Construction, Logistics, Manufacturing, Hospitality, Mining)\n" + + "- DO NOT include IT/software development skills (e.g., Python, Java, JavaScript, C#, Angular, React, Node.js) unless the position is specifically for IT roles\n" + + "- Focus on industry-specific technical skills, soft skills, and relevant certifications\n" + + "- Use the \"Typical Skills\" examples provided for each industry as guidance\n" + + "\n" + "Output Format Requirements:\n" + "Must return standard JSON format with the following structure:\n" + "\n" + @@ -1746,8 +1772,8 @@ public class AiCommonPromptConstants { "| aboutRole | Text Input | Detailed description about the role, including background, importance, and development prospects |\n" + "| responsibilities | Text Input | Detailed job responsibilities description, including main work content and specific tasks |\n" + "| roleBenefitsList | Structure+Value Rules | 1. Structure: Array, each element contains only keyValue field;
2. Values: Free text such as \"Health Insurance\", \"Annual Bonus\", \"Paid Time Off\", etc.;
3. Quantity: 3-8 items |\n" + - "| requiredSkillsList | Structure+Value Rules | 1. Structure: Array, each element contains only keyValue field;
2. Values: Must be \"Angular 4+ & RxJS\"/\"Financial Services Industry Experience\"/\"Health & Travel Account Modification\"/\"Information Technology\";
3. Quantity: 1-5 items |\n" + - "| niceToHaveSkillsList | Structure+Value Rules | 1. Structure: Array, each element contains only keyValue field;
2. Values: Must be \"Financial Services Industry Experience\"/\"Health & Travel Account Modification\"/\"Information Technology\";
3. Quantity: 0-3 items |\n" + + "| requiredSkillsList | Structure+Value Rules | 1. Structure: Array, each element contains only keyValue field;
2. Values: Must match the target industry and position. Generate industry-appropriate skills:
- Construction: Project Management, Safety Management, Quality Control, AutoCAD, Construction Management, Site Supervision, Building Codes
- Logistics: Warehouse Management, Transportation Scheduling, Inventory Control, WMS Systems, Supply Chain Management, Route Planning
- Manufacturing: Production Management, Quality Inspection, Equipment Operation, Lean Manufacturing, 6S Management, Process Control
- Hospitality: Customer Service, Front Desk Management, Food & Beverage Service, Multilingual Communication, Booking Systems, Guest Relations
- Mining: Safety Operations, Equipment Maintenance, Geological Exploration, Environmental Monitoring, Emergency Response, Mining Regulations
3. Quantity: 1-5 items |\n" + + "| niceToHaveSkillsList | Structure+Value Rules | 1. Structure: Array, each element contains only keyValue field;
2. Values: Must match the target industry and position. Generate industry-appropriate optional skills based on the examples above;
3. Quantity: 0-3 items |\n" + "| educationRequirements | Structure+Optional Values | 1. Structure: Object containing academicMajor, degree;
2. academicMajor: Only allow \"Computer Science\";
3. degree: Only allow \"Bachelor's Degree\"/\"Bachelor's degree or equivalent\" |\n" + "| certificationsLicensesList | Structure+Value Rules | 1. Structure: Array, each element contains type, val;
2. type: Only allow \"standard\"/\"customize\";
3. val (standard): Only allow \"AWS Certified Solutions Architect\"/\"CISSP Certified Information Systems Security Professional\"/\"PMP Certified\";
4. Quantity: 0-3 items |\n" + "\n" + @@ -1762,6 +1788,12 @@ public class AiCommonPromptConstants { "8. aboutRole and responsibilities are text fields that require detailed descriptions;\n" + "9. roleBenefitsList is in array format, containing 3-8 role benefits.\n" + "\n" + + "**CRITICAL - Skills Generation Rules:**\n" + + "- Skills in requiredSkillsList and niceToHaveSkillsList MUST match the target industry\n" + + "- For Construction/Logistics/Manufacturing/Hospitality/Mining industries, DO NOT generate IT/software development skills (Python, Java, JavaScript, C#, Angular, React, Node.js, etc.)\n" + + "- Generate industry-appropriate skills based on the examples provided in the constraint rules table\n" + + "- Skills should reflect the actual requirements of the position and industry\n" + + "\n" + "## API Response Format Requirements\n" + "- Top-level fields: code (fixed 0), data (HotakeRolesInfoDtoRes), message (empty string), timestamp (current time, format YYYY-MM-DDTHH:MM:SS);\n" + "- Strictly exclude: createTime, updateTime, uuid, sysUserType, speechSpeed, acceptEquivalentWorkFlag;\n" + diff --git a/vetti-common/src/main/java/com/vetti/common/service/verification/VerificationService.java b/vetti-common/src/main/java/com/vetti/common/service/verification/VerificationService.java index f72ef03..104c100 100644 --- a/vetti-common/src/main/java/com/vetti/common/service/verification/VerificationService.java +++ b/vetti-common/src/main/java/com/vetti/common/service/verification/VerificationService.java @@ -39,6 +39,16 @@ public interface VerificationService { */ boolean sendTemplateCode(String email,String code, String templateId, BaseTemplateEmail templateEmail); + /** + * 发送面试邀请邮件 (内容走的官网配置模板) + * + * @param email 收件人邮箱 + * @param templateId 官网模板ID + * @param templateEmail 模板参数实体 + * @return + */ + boolean sendInterviewTemplate(String email,String templateId, BaseTemplateEmail templateEmail); + /** * 验证验证码是否有效 * diff --git a/vetti-common/src/main/java/com/vetti/common/service/verification/impl/VerificationServiceImpl.java b/vetti-common/src/main/java/com/vetti/common/service/verification/impl/VerificationServiceImpl.java index 11af9d0..4d3e735 100644 --- a/vetti-common/src/main/java/com/vetti/common/service/verification/impl/VerificationServiceImpl.java +++ b/vetti-common/src/main/java/com/vetti/common/service/verification/impl/VerificationServiceImpl.java @@ -114,6 +114,27 @@ public class VerificationServiceImpl implements VerificationService { } } + /** + * 发送面试邀请邮件 (内容走的官网配置模板) + * + * @param email 收件人邮箱 + * @param templateId 官网模板ID + * @param templateEmail 模板参数实体 + * @return + */ + @Override + public boolean sendInterviewTemplate(String email,String templateId, BaseTemplateEmail templateEmail) { + try { + emailUtil.sendEmail(email, templateId, templateEmail); + return true; + } catch (Exception e) { + // 记录日志 + e.printStackTrace(); + return false; + } + } + + /** * 验证验证码是否有效 * diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/vo/HotakeInterviewInvitationVo.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/vo/HotakeInterviewInvitationVo.java new file mode 100644 index 0000000..47db770 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/vo/HotakeInterviewInvitationVo.java @@ -0,0 +1,32 @@ +package com.vetti.hotake.domain.vo; + +import com.vetti.common.entity.verification.BaseTemplateEmail; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 面试邀请 请求实体 + * + * @author wangxiangshun + * @date 2025-12-14 + */ +@Data +@Accessors(chain = true) +public class HotakeInterviewInvitationVo extends BaseTemplateEmail { + + @ApiModelProperty("候选人名称") + private String candidate_name; + + @ApiModelProperty("岗位") + private String position_name; + + @ApiModelProperty("公司名称") + private String company_name; + + @ApiModelProperty("面试时间") + private String interview_date; + + @ApiModelProperty("当前年") + private String current_year; +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeMeetingCalendarInfoService.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeMeetingCalendarInfoService.java index 516e255..361828f 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeMeetingCalendarInfoService.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeMeetingCalendarInfoService.java @@ -97,4 +97,11 @@ public interface IHotakeMeetingCalendarInfoService public List selectHotakeMeetingCalendarDataDtoList(); + /** + * 获取当前候选人即将开始的会议信息 + * + * @return 会议日历记录主 + */ + public HotakeMeetingCalendarInfo selectCandidateStartCalendarInfo(); + } diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeMeetingCalendarInfoServiceImpl.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeMeetingCalendarInfoServiceImpl.java index 1b0b799..fe266b3 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeMeetingCalendarInfoServiceImpl.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeMeetingCalendarInfoServiceImpl.java @@ -1,5 +1,6 @@ package com.vetti.hotake.service.impl; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -7,16 +8,24 @@ import java.util.Map; import java.util.stream.Collectors; import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.date.format.DatePrinter; +import cn.hutool.core.util.StrUtil; +import com.vetti.common.config.TwilioConfig; import com.vetti.common.core.domain.entity.SysUser; import com.vetti.common.core.service.BaseServiceImpl; import com.vetti.common.enums.FillTypeEnum; import com.vetti.common.enums.MeetingCalendarStatus; import com.vetti.common.enums.StageEnum; +import com.vetti.common.exception.ServiceException; +import com.vetti.common.service.verification.VerificationService; +import com.vetti.common.service.verification.impl.VerificationServiceImpl; import com.vetti.common.utils.SecurityUtils; import com.vetti.hotake.domain.HotakeMeetingCalendarDetail; import com.vetti.hotake.domain.HotakeRolesApplyInfo; import com.vetti.hotake.domain.HotakeRolesInfo; import com.vetti.hotake.domain.dto.HotakeMeetingCalendarDataDto; +import com.vetti.hotake.domain.vo.HotakeInterviewInvitationVo; import com.vetti.hotake.domain.vo.HotakeMeetingCalendarInfoVo; import com.vetti.hotake.domain.vo.HotakeMeetingCalendarVo; import com.vetti.hotake.mapper.HotakeMeetingCalendarDetailMapper; @@ -32,6 +41,8 @@ import com.vetti.hotake.mapper.HotakeMeetingCalendarInfoMapper; import com.vetti.hotake.domain.HotakeMeetingCalendarInfo; import com.vetti.hotake.service.IHotakeMeetingCalendarInfoService; +import javax.annotation.Resource; + /** * 会议日历记录主Service业务层处理 * @@ -60,10 +71,16 @@ public class HotakeMeetingCalendarInfoServiceImpl extends BaseServiceImpl implem @Autowired private HotakeRolesApplyInfoMapper hotakeRolesApplyInfoMapper; + @Autowired + private VerificationService verificationService; + @Autowired private ISysUserService userService; + @Resource + private TwilioConfig twilioConfig; + /** * 查询会议日历记录主 * @@ -343,6 +360,27 @@ public class HotakeMeetingCalendarInfoServiceImpl extends BaseServiceImpl implem applyInfo.setStage(StageEnum.INTERVIEW.getCode()); hotakeRolesApplyInfoMapper.updateHotakeRolesApplyInfo(applyInfo); + //发送信息-邮件信息 + try{ + if(StrUtil.isNotEmpty(calendarInfoVo.getMessageVia())){ + SysUser user = userService.selectUserById(calendarInfoVo.getCandidateId()); + + HotakeRolesApplyInfo applyInfo1 = hotakeRolesApplyInfoMapper.selectHotakeRolesApplyInfoById(calendarVo.getRoleApplyId()); + + HotakeRolesInfo rolesInfo = hotakeRolesInfoMapper.selectHotakeRolesInfoById(applyInfo1.getRoleId()); + if (calendarInfoVo.getMessageVia().contains("Email")){ + HotakeInterviewInvitationVo vo = new HotakeInterviewInvitationVo(); + vo.setCandidate_name(user.getNickName()); + vo.setCompany_name(rolesInfo.getCompanyName()); + vo.setPosition_name(rolesInfo.getRoleName()); + vo.setInterview_date(calendarInfoVo.getMeetingDate() + " "+calendarInfoVo.getTimes()); + vo.setCurrent_year(String.valueOf(DateUtil.year(DateUtil.date()))); + verificationService.sendInterviewTemplate(user.getEmail(),twilioConfig.getTemplateIds().getInterviewTemplateCode(),vo); + } + } + }catch (Exception e){ + e.printStackTrace(); + } } } } @@ -383,4 +421,43 @@ public class HotakeMeetingCalendarInfoServiceImpl extends BaseServiceImpl implem return new ArrayList<>(); } } + + /** + * 获取当前候选人即将开始的会议信息 + * @return + */ + @Override + public HotakeMeetingCalendarInfo selectCandidateStartCalendarInfo() { + //获取候选人所有的日程信息 + HotakeMeetingCalendarDetail queryDetai = new HotakeMeetingCalendarDetail(); + queryDetai.setCandidateId(SecurityUtils.getUserId()); + List calendarDetailList = calendarDetailService.selectHotakeMeetingCalendarDetailList(queryDetai); + if(CollectionUtil.isEmpty(calendarDetailList)) { + throw new ServiceException("Currently, you have no upcoming scheduled meetings"); + } + List meetingIds = calendarDetailList.stream().map(HotakeMeetingCalendarDetail::getMeetingId).collect(Collectors.toList()); + //查询对应的会议列表数据 + HotakeMeetingCalendarInfo queryCalendarInfo = new HotakeMeetingCalendarInfo(); + queryCalendarInfo.setMeetingIds(meetingIds); + List calendarInfoList = selectHotakeMeetingCalendarInfoList(queryCalendarInfo); + //获取符合当前时间的会议日程信息 + String day = DateUtil.format(DateUtil.date(), "MM/dd/yyyy"); + Boolean flag = true; + HotakeMeetingCalendarInfo calendarInfoResultData = null; + for(HotakeMeetingCalendarInfo calendarInfo : calendarInfoList) { + if (day.equals(calendarInfo.getMeetingDate())) { + String times = DateUtil.format(DateUtil.date(), "hh"); + String timesType = DateUtil.isAM(DateUtil.date()) ? "AM" : "PM"; + if(calendarInfo.getTimes().startsWith(times+" "+timesType)){ + flag = false; + calendarInfoResultData = calendarInfo; + break; + } + } + } + if(flag){ + throw new ServiceException("Currently, you have no upcoming scheduled meetings"); + } + return calendarInfoResultData; + } }