This commit is contained in:
zlwu committed 2025-08-13 17:21:05 +08:00
commit df38590dbf
7 files changed
+267 -46

No files matched your search

@@ -13,6 +13,7 @@ import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.NotEmpty;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletResponse;
@@ -23,6 +24,7 @@ import jakarta.servlet.http.HttpServletResponse;
* @author system
* @date 2025-01-03
*/
@Slf4j
@Validated
@RequiredArgsConstructor
@RestController
@@ -39,7 +41,18 @@ public class InternshipInfoController extends BaseController {
@SaCheckPermission("zsjy:internship:list")
@GetMapping("/list")
public TableDataInfo<InternshipInfoVO> list(@Validated InternshipInfoQueryBO queryBO, PageQuery pageQuery) {
return internshipInfoService.queryPageList(queryBO, pageQuery);
log.info("=== Controller层调试 ===");
log.info("接口被调用: /zsjy/internship/list");
log.info("查询参数: {}", queryBO);
log.info("分页参数: pageNum={}, pageSize={}", pageQuery.getPageNum(), pageQuery.getPageSize());
TableDataInfo<InternshipInfoVO> result = internshipInfoService.queryPageList(queryBO, pageQuery);
log.info("Controller返回结果: total={}, rows.size={}",
result.getTotal(), result.getRows() != null ? result.getRows().size() : "null");
log.info("=== Controller层调试结束 ===");
return result;
}
/**
@@ -83,4 +96,38 @@ public class InternshipInfoController extends BaseController {
public R<?> getInternshipStatistics(@Validated InternshipInfoQueryBO queryBO) {
return R.ok(internshipInfoService.getInternshipStatistics(queryBO));
}
/**
* 新增实习信息
*/
@Operation(summary = "新增实习信息", description = "为学生新增实习信息")
@SaCheckPermission("zsjy:internship:add")
@PostMapping
public R<Void> add(@RequestBody @Validated Object addBO) {
// TODO: 实现新增实习信息功能
return R.ok();
}
/**
* 修改实习信息
*/
@Operation(summary = "修改实习信息", description = "修改学生实习信息")
@SaCheckPermission("zsjy:internship:edit")
@PutMapping
public R<Void> edit(@RequestBody @Validated Object editBO) {
// TODO: 实现修改实习信息功能
return R.ok();
}
/**
* 删除实习信息
*/
@Operation(summary = "删除实习信息", description = "删除学生实习信息")
@SaCheckPermission("zsjy:internship:remove")
@DeleteMapping("/{internshipIds}")
public R<Void> remove(@Parameter(description = "实习信息ID串")
@PathVariable Long[] internshipIds) {
// TODO: 实现删除实习信息功能
return R.ok();
}
}
@@ -44,6 +44,14 @@ public interface InternshipInfoMapper {
*/
List<Map<String, Object>> selectTeacherClasses(@Param("teacherId") Long teacherId);
/**
* 统计班主任管理的班级数量
*
* @param teacherId 班主任ID
* @return 班级数量
*/
Long countClassesByTeacherId(@Param("teacherId") Long teacherId);
/**
* 查询实习状态统计数据
*
@@ -41,17 +41,58 @@ public class InternshipInfoServiceImpl implements IInternshipInfoService {
*/
@Override
public TableDataInfo<InternshipInfoVO> queryPageList(InternshipInfoQueryBO queryBO, PageQuery pageQuery) {
log.info("=== 后端调试日志 ===");
log.info("1. 查询参数: {}", queryBO);
log.info("2. 分页参数: pageNum={}, pageSize={}", pageQuery.getPageNum(), pageQuery.getPageSize());
// 设置数据权限
setDataPermission(queryBO);
log.info("3. 设置数据权限后的查询参数: {}", queryBO);
log.info("3.1. 权限控制参数: classTeacherId={}, counselorId={}",
queryBO.getClassTeacherId(), queryBO.getCounselorId());
// 创建分页对象
Page<InternshipInfoVO> page = pageQuery.build();
// 查询数据
List<InternshipInfoVO> list = internshipInfoMapper.selectInternshipInfoList(page, queryBO);
log.info("4. 查询到的数据条数: {}", list != null ? list.size() : "null");
// 调试:输出前几条数据的关键字段和映射结果
if (list != null && !list.isEmpty()) {
InternshipInfoVO firstRecord = list.get(0);
log.info("4.1. 第一条数据示例: studentId={}, studentName={}, className={}",
firstRecord.getStudentId(), firstRecord.getStudentName(), firstRecord.getClassName());
// 详细输出映射结果
log.info("=== MyBatis映射结果详细信息 ===");
log.info("学生信息 - ID:{}, 学号:{}, 姓名:{}, 性别:{}, 手机:{}",
firstRecord.getStudentId(), firstRecord.getStudentNo(),
firstRecord.getStudentName(), firstRecord.getGender(), firstRecord.getPhone());
log.info("班级信息 - 班级ID:{}, 班级名称:{}, 年级:{}, 学院:{}, 专业:{}",
firstRecord.getClassId(), firstRecord.getClassName(),
firstRecord.getGrade(), firstRecord.getCollegeName(), firstRecord.getMajorName());
log.info("实习信息 - 实习ID:{}, 状态:{}, 单位:{}, 岗位:{}, 薪资:{}",
firstRecord.getInternshipId(), firstRecord.getInternshipStatus(),
firstRecord.getCompanyName(), firstRecord.getInternshipPosition(),
firstRecord.getInternshipAllowance());
log.info("时间信息 - 开始:{}, 结束:{}, 创建时间:{}",
firstRecord.getInternshipStartDate(), firstRecord.getInternshipEndDate(),
firstRecord.getCreateTime());
log.info("联系信息 - 联系人:{}, 电话:{}, 协议状态:{}",
firstRecord.getContactPersonName(), firstRecord.getContactPersonPhone(),
firstRecord.getAgreementStatus());
log.info("=== 映射结果输出完成 ===");
}
log.info("5. page对象信息: total={}, size={}, current={}", page.getTotal(), page.getSize(), page.getCurrent());
// 处理实习状态显示名称
processInternshipStatusName(list);
log.info("6. 处理状态名称后的数据条数: {}", list != null ? list.size() : "null");
// 设置查询结果到page对象中
page.setRecords(list);
log.info("7. 设置records后的page信息: total={}, records.size={}", page.getTotal(), page.getRecords().size());
return TableDataInfo.build(page);
}
@@ -142,15 +183,39 @@ public class InternshipInfoServiceImpl implements IInternshipInfoService {
try {
// 获取当前登录用户ID
Long currentUserId = LoginHelper.getUserId();
log.info("当前登录用户ID: {}", currentUserId);
if (ObjectUtil.isNotNull(currentUserId)) {
// 设置班主任ID用于数据权限控制
queryBO.setClassTeacherId(currentUserId);
// 检查该用户是否是班主任
Long classTeacherCount = internshipInfoMapper.countClassesByTeacherId(currentUserId);
log.info("用户ID {}作为班主任管理的班级数量: {}", currentUserId, classTeacherCount);
log.debug("设置数据权限:班主任ID={}", currentUserId);
if (classTeacherCount > 0) {
// 是班主任,设置权限限制
queryBO.setClassTeacherId(currentUserId);
log.info("设置数据权限:班主任ID={}", currentUserId);
} else {
// 不是班主任,检查是否是辅导员或管理员
// 这里可以根据业务需求,设置更灵活的权限控制
log.info("当前用户不是班主任,不设置班主任权限限制");
// 可以在这里添加其他角色的权限判断,比如:
// 1. 检查是否是辅导员
// 2. 检查是否是管理员
// 3. 检查是否有相关权限
// 暂时不设置权限限制,允许查看所有数据
queryBO.setClassTeacherId(null);
queryBO.setCounselorId(null);
log.info("清除权限限制,允许查看所有数据");
}
}
} catch (Exception e) {
log.warn("获取数据权限失败:{}", e.getMessage());
log.error("设置数据权限失败:{}", e.getMessage(), e);
// 异常情况下,清除权限限制以避免查询为空
queryBO.setClassTeacherId(null);
queryBO.setCounselorId(null);
log.warn("异常情况下清除权限限制,允许查看所有数据");
}
}
@@ -51,8 +51,11 @@
s.class_teacher_name,
c.class_teacher_id,
c.counselor_id,
i.internship_id as internship_id,
i.internship_status,
i.internship_id,
CASE
WHEN i.internship_status IS NULL OR i.internship_status = '' THEN 'null'
ELSE i.internship_status
END as internship_status,
i.company_name,
i.company_address,
i.position_name as internship_position,
@@ -119,22 +122,22 @@
AND i.company_address LIKE CONCAT('%', #{queryBO.companyAddress}, '%')
</if>
<if test="queryBO.internshipPosition != null and queryBO.internshipPosition != ''">
AND i.internship_position LIKE CONCAT('%', #{queryBO.internshipPosition}, '%')
AND i.position_name LIKE CONCAT('%', #{queryBO.internshipPosition}, '%')
</if>
<if test="queryBO.agreementStatus != null and queryBO.agreementStatus != ''">
AND i.agreement_status = #{queryBO.agreementStatus}
AND i.status = #{queryBO.agreementStatus}
</if>
<if test="queryBO.internshipStartDateBegin != null">
AND i.internship_start_date >= #{queryBO.internshipStartDateBegin}
AND i.start_date >= #{queryBO.internshipStartDateBegin}
</if>
<if test="queryBO.internshipStartDateEnd != null">
AND i.internship_start_date &lt;= #{queryBO.internshipStartDateEnd}
AND i.start_date &lt;= #{queryBO.internshipStartDateEnd}
</if>
<if test="queryBO.internshipEndDateBegin != null">
AND i.internship_end_date >= #{queryBO.internshipEndDateBegin}
AND i.end_date >= #{queryBO.internshipEndDateBegin}
</if>
<if test="queryBO.internshipEndDateEnd != null">
AND i.internship_end_date &lt;= #{queryBO.internshipEndDateEnd}
AND i.end_date &lt;= #{queryBO.internshipEndDateEnd}
</if>
<!-- 数据权限控制:班主任只能查看自己班级的学生 -->
<if test="queryBO.classTeacherId != null">
@@ -194,4 +197,13 @@
<include refid="selectInternshipInfoWhere"/>
</select>
<!-- 统计班主任管理的班级数量 -->
<select id="countClassesByTeacherId" parameterType="Long" resultType="Long">
SELECT COUNT(*)
FROM xg_class_msg
WHERE class_teacher_id = #{teacherId}
AND deleted = 0
AND tenant_id = '000000'
</select>
</mapper>
+40 -4
View File
@@ -1,12 +1,13 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { InternshipInfoVO, InternshipInfoQuery, ClassInfoVO, InternshipStatisticsVO } from '@/api/zsjy/types';
import { TableDataInfo, R } from '@/api/types';
/**
* 查询实习信息列表
* @param query 查询参数
*/
export const listInternshipInfo = (query?: InternshipInfoQuery): AxiosPromise<InternshipInfoVO[]> => {
export const listInternshipInfo = (query?: InternshipInfoQuery): AxiosPromise<TableDataInfo<InternshipInfoVO>> => {
return request({
url: '/zsjy/internship/list',
method: 'get',
@@ -18,7 +19,7 @@ export const listInternshipInfo = (query?: InternshipInfoQuery): AxiosPromise<In
* 查询学生实习详细信息
* @param studentId 学生ID
*/
export const getInternshipInfo = (studentId: string | number): AxiosPromise<InternshipInfoVO> => {
export const getInternshipInfo = (studentId: string | number): AxiosPromise<R<InternshipInfoVO>> => {
return request({
url: `/zsjy/internship/${studentId}`,
method: 'get'
@@ -41,7 +42,7 @@ export const exportInternshipInfo = (query: InternshipInfoQuery) => {
/**
* 获取班级信息列表(用于下拉选择)
*/
export const getClassOptions = (): AxiosPromise<ClassInfoVO[]> => {
export const getClassOptions = (): AxiosPromise<R<ClassInfoVO[]>> => {
return request({
url: '/zsjy/internship/classes',
method: 'get'
@@ -52,10 +53,45 @@ export const getClassOptions = (): AxiosPromise<ClassInfoVO[]> => {
* 获取实习统计数据
* @param query 查询参数
*/
export const getInternshipStatistics = (query?: InternshipInfoQuery): AxiosPromise<InternshipStatisticsVO> => {
export const getInternshipStatistics = (query?: InternshipInfoQuery): AxiosPromise<R<InternshipStatisticsVO>> => {
return request({
url: '/zsjy/internship/statistics',
method: 'get',
params: query
});
};
/**
* 新增实习信息
* @param data 实习信息数据
*/
export const addInternshipInfo = (data: any): AxiosPromise<R<void>> => {
return request({
url: '/zsjy/internship',
method: 'post',
data: data
});
};
/**
* 修改实习信息
* @param data 实习信息数据
*/
export const updateInternshipInfo = (data: any): AxiosPromise<R<void>> => {
return request({
url: '/zsjy/internship',
method: 'put',
data: data
});
};
/**
* 删除实习信息
* @param internshipId 实习信息ID
*/
export const delInternshipInfo = (internshipId: string | number): AxiosPromise<R<void>> => {
return request({
url: `/zsjy/internship/${internshipId}`,
method: 'delete'
});
};
+11 -11
View File
@@ -769,7 +769,7 @@ export interface InternshipInfoVO {
/**
* 手机号
*/
mobile?: string;
phone?: string;
/**
* 学院ID
@@ -804,7 +804,7 @@ export interface InternshipInfoVO {
/**
* 班主任姓名
*/
classMasterName?: string;
classTeacherName?: string;
/**
* 实习状态 (0=未实习, 1=实习中, 2=实习完成)
@@ -819,7 +819,7 @@ export interface InternshipInfoVO {
/**
* 实习公司
*/
internshipCompany?: string;
companyName?: string;
/**
* 实习岗位
@@ -829,17 +829,17 @@ export interface InternshipInfoVO {
/**
* 实习开始时间
*/
internshipStartTime?: string;
internshipStartDate?: string;
/**
* 实习结束时间
*/
internshipEndTime?: string;
internshipEndDate?: string;
/**
* 实习地点
*/
internshipLocation?: string;
companyAddress?: string;
/**
* 创建时间
@@ -909,17 +909,17 @@ export interface InternshipInfoQuery {
/**
* 实习公司
*/
internshipCompany?: string;
companyName?: string;
/**
* 开始时间范围
* 实习开始日期-开始
*/
startTimeBegin?: string;
internshipStartDateBegin?: string;
/**
* 开始时间范围
* 实习开始日期-结束
*/
startTimeEnd?: string;
internshipStartDateEnd?: string;
}
/**
@@ -32,8 +32,8 @@
</el-row>
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="实习公司" prop="internshipCompany">
<el-input v-model="queryParams.internshipCompany" placeholder="请输入实习公司名称" clearable @keyup.enter="handleQuery" />
<el-form-item label="实习公司" prop="companyName">
<el-input v-model="queryParams.companyName" placeholder="请输入实习公司名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
</el-col>
<el-col :span="12">
@@ -128,24 +128,28 @@
<el-table v-loading="loading" border :data="internshipList" @row-dblclick="handleView">
<el-table-column label="学号" align="center" prop="studentNo" width="120" />
<el-table-column label="姓名" align="center" prop="studentName" width="100" />
<el-table-column label="性别" align="center" prop="gender" width="80" />
<el-table-column label="性别" align="center" prop="gender" width="80">
<template #default="scope">
<dict-tag :options="sys_user_sex" :value="scope.row.gender" />
</template>
</el-table-column>
<el-table-column label="班级" align="center" prop="className" width="180" />
<el-table-column label="班主任" align="center" prop="classMasterName" width="100" />
<el-table-column label="班主任" align="center" prop="classTeacherName" width="100" />
<el-table-column label="实习状态" align="center" prop="internshipStatus" width="100">
<template #default="scope">
<dict-tag :options="internship_status" :value="scope.row.internshipStatus" />
</template>
</el-table-column>
<el-table-column label="实习公司" align="center" prop="internshipCompany" min-width="150" show-overflow-tooltip />
<el-table-column label="实习公司" align="center" prop="companyName" min-width="150" show-overflow-tooltip />
<el-table-column label="实习岗位" align="center" prop="internshipPosition" width="120" show-overflow-tooltip />
<el-table-column label="实习开始时间" align="center" prop="internshipStartTime" width="120">
<el-table-column label="实习开始时间" align="center" prop="internshipStartDate" width="120">
<template #default="scope">
<span v-if="scope.row.internshipStartTime">{{ parseTime(scope.row.internshipStartTime, '{y}-{m}-{d}') }}</span>
<span v-if="scope.row.internshipStartDate">{{ parseTime(scope.row.internshipStartDate, '{y}-{m}-{d}') }}</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="实习地点" align="center" prop="internshipLocation" width="120" show-overflow-tooltip />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120">
<el-table-column label="实习地点" align="center" prop="companyAddress" width="120" show-overflow-tooltip />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200">
<template #default="scope">
<el-tooltip content="查看详情" placement="top">
<el-button
@@ -153,11 +157,30 @@
type="primary"
icon="View"
size="default"
style="font-size: 16px; color: blue"
@click="handleView(scope.row)"
v-hasPermi="['zsjy:internship:query']"
></el-button>
</el-tooltip>
<el-tooltip content="新增实习信息" placement="top" v-if="!scope.row.internshipId">
<el-button
link
type="success"
icon="Plus"
size="default"
@click="handleAdd(scope.row)"
v-hasPermi="['zsjy:internship:add']"
></el-button>
</el-tooltip>
<el-tooltip content="编辑实习信息" placement="top" v-if="scope.row.internshipId">
<el-button
link
type="warning"
icon="Edit"
size="default"
@click="handleEdit(scope.row)"
v-hasPermi="['zsjy:internship:edit']"
></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
@@ -215,7 +238,7 @@ import { parseTime } from '@/utils/ruoyi';
import { download } from '@/utils/request';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { internship_status } = toRefs<any>(proxy?.useDict('internship_status'));
const { internship_status, sys_user_sex } = toRefs<any>(proxy?.useDict('internship_status', 'sys_user_sex'));
const internshipList = ref<InternshipInfoVO[]>([]);
const classOptions = ref<ClassInfoVO[]>([]);
@@ -239,9 +262,9 @@ const data = reactive({
studentNo: '',
classId: '',
internshipStatus: '',
internshipCompany: '',
startTimeBegin: '',
startTimeEnd: ''
companyName: '',
internshipStartDateBegin: '',
internshipStartDateEnd: ''
} as InternshipInfoQuery,
dialog: {
visible: false,
@@ -256,19 +279,33 @@ const getList = async () => {
loading.value = true;
// 处理日期范围
if (dateRange.value && dateRange.value.length === 2) {
queryParams.value.startTimeBegin = dateRange.value[0];
queryParams.value.startTimeEnd = dateRange.value[1];
queryParams.value.internshipStartDateBegin = dateRange.value[0];
queryParams.value.internshipStartDateEnd = dateRange.value[1];
} else {
queryParams.value.startTimeBegin = '';
queryParams.value.startTimeEnd = '';
queryParams.value.internshipStartDateBegin = '';
queryParams.value.internshipStartDateEnd = '';
}
console.log('=== 前端调试日志 ===');
console.log('1. 查询参数:', JSON.stringify(queryParams.value, null, 2));
try {
const res = await listInternshipInfo(queryParams.value);
console.log('2. API响应完整数据:', JSON.stringify(res, null, 2));
console.log('3. res.rows类型:', typeof res.rows, '长度:', res.rows ? res.rows.length : 'undefined');
console.log('4. res.total:', res.total);
console.log('5. res.code:', res.code);
console.log('6. res.msg:', res.msg);
internshipList.value = res.rows;
total.value = res.total;
console.log('7. 赋值后 internshipList.value:', internshipList.value);
console.log('8. 赋值后 total.value:', total.value);
loading.value = false;
} catch (error) {
console.error('API调用失败:', error);
loading.value = false;
}
};
@@ -349,6 +386,18 @@ const handleExport = () => {
});
};
/** 新增实习信息按钮操作 */
const handleAdd = (row: InternshipInfoVO) => {
// TODO: 实现新增实习信息功能
proxy?.$modal.msgInfo('新增实习信息功能开发中...');
};
/** 编辑实习信息按钮操作 */
const handleEdit = (row: InternshipInfoVO) => {
// TODO: 实现编辑实习信息功能
proxy?.$modal.msgInfo('编辑实习信息功能开发中...');
};
/** 取消按钮 */
const cancel = () => {
dialog.value.visible = false;
@@ -381,9 +430,13 @@ const cancel = () => {
color: white;
position: relative;
overflow: hidden;
height: 100px; /* 设置固定高度,确保所有卡片高度一致 */
.statistics-content {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center; /* 内容垂直居中 */
.statistics-number {
font-size: 28px;