“rs招聘和培训修改”

This commit is contained in:
weizhong committed 2025-09-22 22:39:59 +08:00
1 parent 465c284d4a
commit e6201af3db
11 files changed
+1966 -354

No files matched your search

@@ -9,6 +9,7 @@ import org.dromara.common.mybatis.core.domain.BaseEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.baomidou.mybatisplus.annotation.IdType;
import java.math.BigDecimal;
import java.util.Date;
/**
@@ -60,6 +61,52 @@ public class RsTrainingApplication extends BaseEntity {
*/
private String position;
/**
* 现职称
*/
private String currentTitle;
/**
* 现岗位
*/
private String currentPosition;
/**
* 参加工作时间
*/
@JsonFormat(pattern = "yyyy-MM-dd")
private Date workStartTime;
/**
* 联系电话
*/
private String phone;
/**
* 主办单位
*/
private String organizerUnit;
/**
* 培训类型
*/
private String trainingType;
/**
* 培训费用
*/
private BigDecimal trainingFee;
/**
* 同行人员(JSON格式)
*/
private String companions;
/**
* 培训目的
*/
private String trainingPurpose;
/**
* 申请理由
*/
@@ -118,6 +165,11 @@ public class RsTrainingApplication extends BaseEntity {
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date rejectTime;
/**
* 附件ID列表(逗号分隔)
*/
private String attachmentIds;
/**
* 排除状态(查询时排除指定状态,不存储到数据库)
@@ -70,10 +70,69 @@ public class RsTrainingApproval extends BaseEntity {
*/
private String tenantId;
/** 非数据库字段 **/
/** 非数据库字段 - 审批记录列表显示 **/
@TableField(exist = false)
private String applicationUserName;
@TableField(exist = false)
private String courseTitle;
/** 非数据库字段 - 审批记录详情显示 **/
@TableField(exist = false)
private String userName;
@TableField(exist = false)
private String department;
@TableField(exist = false)
private String currentTitle;
@TableField(exist = false)
private String currentPosition;
@TableField(exist = false)
@JsonFormat(pattern = "yyyy-MM-dd")
private Date workStartTime;
@TableField(exist = false)
private String phone;
@TableField(exist = false)
private String organizerUnit;
@TableField(exist = false)
private String courseName;
@TableField(exist = false)
private String location;
@TableField(exist = false)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime;
@TableField(exist = false)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date endTime;
@TableField(exist = false)
private String trainingType;
@TableField(exist = false)
private Double trainingFee;
@TableField(exist = false)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date applyTime;
@TableField(exist = false)
private String companions;
@TableField(exist = false)
private String trainingPurpose;
@TableField(exist = false)
private String reason;
@TableField(exist = false)
private String attachmentIds;
}
@@ -20,4 +20,12 @@ public interface RsTrainingApprovalMapper extends BaseMapperPlus<RsTrainingAppro
*/
List<RsTrainingApproval> selectRsTrainingApprovalWithDetailsList(RsTrainingApproval approval);
/**
* 查询带详细信息的审批记录数量(关联申请人和课程信息)
*
* @param approval 查询条件
* @return 记录数量
*/
long selectRsTrainingApprovalWithDetailsCount(RsTrainingApproval approval);
}
@@ -197,8 +197,8 @@ public class RsTrainingApprovalServiceImpl implements IRsTrainingApprovalService
approval.setTenantId(LoginHelper.getTenantId());
}
// 查询总数
long total = trainingApprovalMapper.selectCount(buildQueryWrapper(approval));
// 查询总数 - 使用与列表查询相同的条件
long total = trainingApprovalMapper.selectRsTrainingApprovalWithDetailsCount(approval);
// 使用自定义分页查询获取列表数据
List<RsTrainingApproval> list = trainingApprovalMapper.selectRsTrainingApprovalWithDetailsList(approval);
@@ -11,6 +11,16 @@
<result property="userName" column="user_name"/>
<result property="department" column="department"/>
<result property="position" column="position"/>
<result property="currentTitle" column="current_title"/>
<result property="currentPosition" column="current_position"/>
<result property="workStartTime" column="work_start_time"/>
<result property="phone" column="phone"/>
<result property="organizerUnit" column="organizer_unit"/>
<result property="trainingType" column="training_type"/>
<result property="trainingFee" column="training_fee"/>
<result property="companions" column="companions"/>
<result property="trainingPurpose" column="training_purpose"/>
<result property="attachmentIds" column="attachment_ids"/>
<result property="reason" column="reason"/>
<result property="status" column="status"/>
<result property="applyTime" column="apply_time"/>
@@ -31,8 +41,10 @@
<sql id="selectRsTrainingApplicationVo">
SELECT
a.application_id, a.course_id, a.course_name as custom_course_name, a.user_id, a.user_name, a.department, a.position, a.reason,
a.status, a.apply_time, a.current_approver, a.location, a.duration, a.start_time, a.end_time,
a.application_id, a.course_id, a.course_name as custom_course_name, a.user_id, a.user_name, a.department, a.position,
a.current_title, a.current_position, a.work_start_time, a.phone, a.organizer_unit,
a.training_type, a.training_fee, a.companions, a.training_purpose, a.attachment_ids,
a.reason, a.status, a.apply_time, a.current_approver, a.location, a.duration, a.start_time, a.end_time,
a.tenant_id, a.create_dept, a.reject_time, a.create_by, a.create_time, a.update_by, a.update_time,
CASE
WHEN a.course_id = 0 THEN a.course_name
@@ -37,9 +37,28 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
<result property="remark" column="remark"/>
<!-- 关联字段 -->
<!-- 关联字段 - 审批记录显示需要的申请信息 -->
<result property="applicationUserName" column="application_user_name"/>
<result property="courseTitle" column="course_title"/>
<!-- 新增详情显示需要的字段 -->
<result property="userName" column="user_name"/>
<result property="department" column="department"/>
<result property="currentTitle" column="current_title"/>
<result property="currentPosition" column="current_position"/>
<result property="workStartTime" column="work_start_time"/>
<result property="phone" column="phone"/>
<result property="organizerUnit" column="organizer_unit"/>
<result property="courseName" column="course_name"/>
<result property="location" column="location"/>
<result property="startTime" column="start_time"/>
<result property="endTime" column="end_time"/>
<result property="trainingType" column="training_type"/>
<result property="trainingFee" column="training_fee"/>
<result property="applyTime" column="apply_time"/>
<result property="companions" column="companions"/>
<result property="trainingPurpose" column="training_purpose"/>
<result property="reason" column="reason"/>
<result property="attachmentIds" column="attachment_ids"/>
</resultMap>
<sql id="selectRsTrainingApprovalVo">
@@ -81,8 +100,28 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
a.approval_id, a.application_id, a.approver_id, a.approver_name,
a.approval_level, a.status, a.approval_time, a.opinion,
a.tenant_id, a.create_by, a.create_time, a.update_by, a.update_time, a.remark,
-- 审批记录列表显示字段
app.user_name as application_user_name,
COALESCE(app.course_name, c.title) as course_title
COALESCE(app.course_name, c.title) as course_title,
-- 详情弹窗显示字段(使用别名避免重复)
app.user_name as user_name,
app.department,
app.current_title,
app.current_position,
app.work_start_time,
app.phone,
app.organizer_unit,
app.course_name as course_name,
app.location,
app.start_time,
app.end_time,
app.training_type,
app.training_fee,
app.apply_time,
app.companions,
app.training_purpose,
app.reason,
app.attachment_ids
FROM rs_training_approval a
LEFT JOIN rs_training_application app ON a.application_id = app.application_id AND app.deleted = '0'
LEFT JOIN rs_training_course c ON app.course_id = c.course_id AND c.deleted = '0'
@@ -121,4 +160,44 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
ORDER BY a.approval_time DESC
</select>
<!-- 查询带详细信息的审批记录数量(关联申请人和课程信息) -->
<select id="selectRsTrainingApprovalWithDetailsCount" parameterType="RsTrainingApproval" resultType="long">
SELECT COUNT(1)
FROM rs_training_approval a
LEFT JOIN rs_training_application app ON a.application_id = app.application_id AND app.deleted = '0'
LEFT JOIN rs_training_course c ON app.course_id = c.course_id AND c.deleted = '0'
<where>
a.deleted = '0'
<if test="applicationId != null">
AND a.application_id = #{applicationId}
</if>
<if test="approverId != null">
AND a.approver_id = #{approverId}
</if>
<if test="approverName != null and approverName != ''">
AND a.approver_name like concat('%', #{approverName}, '%')
</if>
<if test="approvalLevel != null">
AND a.approval_level = #{approvalLevel}
</if>
<if test="status != null and status != ''">
AND a.status IN
<foreach collection="status.split(',')" item="statusItem" open="(" separator="," close=")">
#{statusItem}
</foreach>
</if>
<if test="tenantId != null and tenantId != ''">
AND a.tenant_id = #{tenantId}
</if>
<!-- 支持按申请人姓名搜索 -->
<if test="applicationUserName != null and applicationUserName != ''">
AND app.user_name like concat('%', #{applicationUserName}, '%')
</if>
<!-- 支持按课程名称搜索 -->
<if test="courseTitle != null and courseTitle != ''">
AND (app.course_name like concat('%', #{courseTitle}, '%') OR c.title like concat('%', #{courseTitle}, '%'))
</if>
</where>
</select>
</mapper>
+28 -4
View File
@@ -70,16 +70,29 @@ export interface ApplicationVO {
userName: string;
department: string;
position?: string;
currentTitle?: string; // 现职称
currentPosition?: string; // 现岗位
workStartTime?: string; // 参加工作时间
phone?: string; // 联系电话
organizerUnit?: string; // 主办单位
trainingType?: string; // 培训类型
trainingFee?: number; // 培训费用
companions?: string; // 同行人员(JSON字符串)
trainingPurpose?: string; // 培训目的
reason?: string;
status: string;
applyTime: string;
currentApprover?: string;
certificatePath?: string;
certificateNumber?: string;
location?: string;
duration?: number;
startTime?: string;
endTime?: string;
rejectTime?: string; // 拒绝时间
attachmentIds?: string; // 附件ID列表
createTime: string;
updateTime: string;
createBy: string;
updateBy: string;
createBy: number; // 修正类型:string -> number
updateBy: number; // 修正类型:string -> number
remark: string;
}
@@ -92,12 +105,23 @@ export interface ApplicationForm {
userName?: string;
department?: string;
position?: string;
currentTitle?: string; // 现职称
currentPosition?: string; // 现岗位
workStartTime?: string; // 参加工作时间
phone?: string; // 联系电话
organizerUnit?: string; // 主办单位
trainingType?: string; // 培训类型
trainingTypeOther?: string; // 其他培训类型描述
trainingFee?: number; // 培训费用
companions?: (string | number)[]; // 同行人员数组
trainingPurpose?: string; // 培训目的
reason?: string;
status?: string;
location?: string;
duration?: number;
startTime?: string;
endTime?: string;
attachmentIds?: string[]; // 附件ID数组
remark?: string;
}
@@ -157,14 +157,10 @@
</el-col>
<el-col :span="8">
<el-form-item>
<el-button
:type="studentRecordsData ? 'success' : 'info'"
:plain="!studentRecordsData"
@click="handleViewStudentViolations"
>
<i :class="studentRecordsData ? 'el-icon-check' : 'el-icon-view'" style="margin-right: 4px;"></i>
{{ studentRecordsData ? '查看已加载的违规处分信息' : '学生违规处分信息查看' }}
</el-button>
<el-button :type="studentRecordsData ? 'success' : 'info'" :plain="!studentRecordsData" @click="handleViewStudentViolations">
<i :class="studentRecordsData ? 'el-icon-check' : 'el-icon-view'" style="margin-right: 4px"></i>
{{ studentRecordsData ? '查看已加载的违规处分信息' : '学生违规处分信息查看' }}
</el-button>
</el-form-item>
</el-col>
</el-row>
@@ -382,27 +378,22 @@
<!-- 违纪记录Tab -->
<el-tab-pane label="违纪记录" name="discipline">
<!-- 扣分汇总信息 -->
<el-row :gutter="20" style="margin-bottom: 16px;">
<el-row :gutter="20" style="margin-bottom: 16px">
<el-col :span="16">
<el-alert
:title="`违纪记录扣分汇总: ${calculateTotalDeduction()} 分 (生效记录: ${getEffectiveDisciplineRecords().length} 条)`"
type="warning"
<el-alert
:title="`违纪记录扣分汇总: ${calculateTotalDeduction()} 分 (生效记录: ${getEffectiveDisciplineRecords().length} 条)`"
type="warning"
:closable="false"
show-icon
/>
</el-col>
<el-col :span="8" style="text-align: right;">
<el-button
type="primary"
icon="Refresh"
@click="applyDeductionToClassScore"
:disabled="calculateTotalDeduction() === 0"
>
<el-col :span="8" style="text-align: right">
<el-button type="primary" icon="Refresh" @click="applyDeductionToClassScore" :disabled="calculateTotalDeduction() === 0">
重新同步到班级扣分
</el-button>
</el-col>
</el-row>
<el-table :data="studentRecordsData?.disciplineRecords || []" border style="width: 100%" max-height="400" empty-text="暂无违纪记录">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="studentNo" label="学号" min-width="120" align="center" />
@@ -417,10 +408,7 @@
<el-table-column prop="disciplineContent" label="处分内容" min-width="200" :show-overflow-tooltip="true" />
<el-table-column prop="scoreDeduction" label="扣分" min-width="80" align="center">
<template #default="scope">
<el-tag
:type="scope.row.status === '1' ? 'danger' : 'info'"
size="small"
>
<el-tag :type="scope.row.status === '1' ? 'danger' : 'info'" size="small">
{{ scope.row.scoreDeduction || 0 }}
</el-tag>
</template>
@@ -721,7 +709,7 @@ const loadAssessmentDetail = async () => {
overallComment: monthlyScoreForm.overallComment
});
console.log('==================');
// 自动加载学生违规处分信息数据
await autoLoadStudentRecords();
} catch (error) {
@@ -746,7 +734,7 @@ const autoLoadStudentRecords = async () => {
try {
const res = await getClassStudentRecords(props.classId, props.planId);
studentRecordsData.value = res.data;
// 自动同步违纪记录扣分到班级扣分字段(不显示提示消息)
autoSyncDeductionToClassScore(false);
console.log('✅ 学生违规处分数据自动加载完成');
@@ -778,7 +766,7 @@ const handleViewStudentViolations = async () => {
studentRecordsData.value = res.data;
studentRecordsVisible.value = true;
}
// 手动查看时也重新同步一次扣分(显示提示消息)
autoSyncDeductionToClassScore(true);
} catch (error) {
@@ -795,7 +783,7 @@ const getEffectiveDisciplineRecords = () => {
return [];
}
// 只统计状态为'1'(生效)的违纪记录
return studentRecordsData.value.disciplineRecords.filter(record => record.status === '1');
return studentRecordsData.value.disciplineRecords.filter((record) => record.status === '1');
};
/** 计算违纪记录总扣分 */
@@ -810,50 +798,57 @@ const calculateTotalDeduction = () => {
/** 自动同步违纪记录扣分到班级扣分字段 */
const autoSyncDeductionToClassScore = (showMessage = true) => {
const totalDeduction = calculateTotalDeduction();
// 自动将汇总的扣分设置到班级扣分字段
managementEffectivenessForm.classDeduction = totalDeduction;
// 自动计算50%计
calculateDeductionHalf();
if (totalDeduction > 0 && showMessage) {
proxy?.$modal.msgSuccess(`已自动同步违纪记录扣分汇总 ${totalDeduction} 分到班级扣分字段`);
}
};
// 监听学生违纪记录数据变化,自动同步扣分
watch(() => studentRecordsData.value?.disciplineRecords, (newRecords) => {
if (newRecords && studentRecordsVisible.value) {
// 延迟执行,确保数据完全加载,但不显示提示消息
nextTick(() => {
autoSyncDeductionToClassScore(false);
});
}
}, { deep: true });
watch(
() => studentRecordsData.value?.disciplineRecords,
(newRecords) => {
if (newRecords && studentRecordsVisible.value) {
// 延迟执行,确保数据完全加载,但不显示提示消息
nextTick(() => {
autoSyncDeductionToClassScore(false);
});
}
},
{ deep: true }
);
/** 将违纪记录扣分汇总应用到班级扣分字段 */
const applyDeductionToClassScore = () => {
const totalDeduction = calculateTotalDeduction();
if (totalDeduction === 0) {
proxy?.$modal.msgWarning('当前没有生效的违纪记录扣分可以应用');
return;
}
// 确认应用操作
proxy?.$modal.confirm(`确定要将违纪记录扣分汇总 ${totalDeduction} 分重新应用到班级扣分字段吗?`).then(() => {
// 将汇总的扣分设置到班级扣分字段
managementEffectivenessForm.classDeduction = totalDeduction;
// 自动计算50%计
calculateDeductionHalf();
proxy?.$modal.msgSuccess(`已重新应用违纪记录扣分汇总 ${totalDeduction} 分到班级扣分字段`);
// 关闭学生记录弹窗
studentRecordsVisible.value = false;
}).catch(() => {
// 用户取消操作
});
proxy?.$modal
.confirm(`确定要将违纪记录扣分汇总 ${totalDeduction} 分重新应用到班级扣分字段吗?`)
.then(() => {
// 将汇总的扣分设置到班级扣分字段
managementEffectivenessForm.classDeduction = totalDeduction;
// 自动计算50%计
calculateDeductionHalf();
proxy?.$modal.msgSuccess(`已重新应用违纪记录扣分汇总 ${totalDeduction} 分到班级扣分字段`);
// 关闭学生记录弹窗
studentRecordsVisible.value = false;
})
.catch(() => {
// 用户取消操作
});
};
/** 保存考核数据 */
+63 -3
View File
@@ -385,6 +385,18 @@
</el-descriptions-item>
<el-descriptions-item label="申请人数">{{ viewForm.applicantCount }}</el-descriptions-item>
<el-descriptions-item label="浏览次数">{{ viewForm.viewCount }}</el-descriptions-item>
<el-descriptions-item label="应聘链接">
<el-link
:href="`/recruitment-apply?jobId=${viewForm.jobId}`"
target="_blank"
type="primary"
:underline="false"
style="font-size: 14px;"
>
点击前往应聘页面
<el-icon style="margin-left: 4px;"><Link /></el-icon>
</el-link>
</el-descriptions-item>
<el-descriptions-item label="发布时间">
{{ parseTime(viewForm.publishTime) || (viewForm.isActive === '0' ? parseTime(viewForm.createTime) || '长期有效' : '未发布') }}
</el-descriptions-item>
@@ -508,7 +520,21 @@
</el-descriptions-item>
<el-descriptions-item label="申请时间">{{ parseTime(applicationDetail.applyTime) }}</el-descriptions-item>
<el-descriptions-item label="联系电话">{{ applicationDetail.contactPhone }}</el-descriptions-item>
<el-descriptions-item label="联系邮箱">{{ applicationDetail.contactEmail }}</el-descriptions-item>
<el-descriptions-item label="联系邮箱">
<div style="display: flex; align-items: center; gap: 8px;">
<span>{{ applicationDetail.contactEmail }}</span>
<el-button
v-if="applicationDetail.contactEmail"
size="small"
type="primary"
:icon="Message"
@click="sendEmail(applicationDetail.contactEmail, applicationDetail.applicantName)"
style="margin-left: 8px;"
>
发送邮件
</el-button>
</div>
</el-descriptions-item>
<el-descriptions-item label="学历">{{ applicationDetail.education || '暂无信息' }}</el-descriptions-item>
<el-descriptions-item label="教育背景">{{ applicationDetail.educationBackground || '暂无信息' }}</el-descriptions-item>
<el-descriptions-item label="工作经验" :span="2">{{ applicationDetail.experience || '暂无信息' }}</el-descriptions-item>
@@ -544,7 +570,21 @@
<el-descriptions-item label="性别">{{ currentApplication?.gender || '未提供' }}</el-descriptions-item>
<el-descriptions-item label="年龄">{{ currentApplication?.age || '未提供' }}</el-descriptions-item>
<el-descriptions-item label="联系电话">{{ currentApplication?.contactPhone }}</el-descriptions-item>
<el-descriptions-item label="邮箱地址">{{ currentApplication?.contactEmail }}</el-descriptions-item>
<el-descriptions-item label="邮箱地址">
<div style="display: flex; align-items: center; gap: 8px;">
<span>{{ currentApplication?.contactEmail }}</span>
<el-button
v-if="currentApplication?.contactEmail"
size="small"
type="primary"
:icon="Message"
@click="sendEmail(currentApplication?.contactEmail, currentApplication?.applicantName)"
style="margin-left: 8px;"
>
发送邮件
</el-button>
</div>
</el-descriptions-item>
<el-descriptions-item label="申请状态">
<el-tag
:type="
@@ -681,7 +721,7 @@ import { parseTime } from '@/utils/ruoyi';
import type { JobVO, JobForm, ApplicationVO } from '@/api/rs/job';
import { listDept } from '@/api/system/dept';
import type { DeptVO } from '@/api/system/dept/types';
import { Document } from '@element-plus/icons-vue';
import { Document, Link, Message } from '@element-plus/icons-vue';
import { getToken } from '@/utils/auth';
import jsPDF from 'jspdf';
import html2canvas from 'html2canvas';
@@ -1484,6 +1524,26 @@ function getStatusType(value: string): 'primary' | 'success' | 'info' | 'warning
return (option?.type as 'primary' | 'success' | 'info' | 'warning' | 'danger') || 'info';
}
/** 发送邮件 */
function sendEmail(email: string, applicantName: string) {
if (!email) {
ElMessage.warning('邮箱地址为空');
return;
}
const subject = encodeURIComponent(`关于您的求职申请 - ${applicantName}`);
const body = encodeURIComponent(`亲爱的 ${applicantName}:\n\n感谢您对我们的关注和求职申请。\n\n我们将仔细审核您的申请材料,如有需要会及时与您联系。\n\n祝您工作顺利!\n\n此致\n敬礼\n\nHR部门`);
const mailtoUrl = `mailto:${email}?subject=${subject}&body=${body}`;
try {
window.open(mailtoUrl);
ElMessage.success('已打开邮件客户端');
} catch (error) {
ElMessage.error('打开邮件客户端失败,请检查系统设置');
}
}
/** 选项卡切换 */
function handleTabClick() {
if (activeTab.value === 'application') {
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff