Kaynağa Gözat

Merge branch 'master' of http://47.99.164.66:3000/hzdyjs-xg/all-project

zlwu 1 yıl önce
ebeveyn
işleme
df38590dbf

+ 48 - 1
backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/controller/InternshipInfoController.java

@@ -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();
+    }
 }

+ 8 - 0
backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/mapper/InternshipInfoMapper.java

@@ -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);
+
     /**
      * 查询实习状态统计数据
      *

+ 70 - 5
backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/service/impl/InternshipInfoServiceImpl.java

@@ -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);
-
-                log.debug("设置数据权限:班主任ID={}", currentUserId);
+                // 检查该用户是否是班主任
+                Long classTeacherCount = internshipInfoMapper.countClassesByTeacherId(currentUserId);
+                log.info("用户ID {}作为班主任管理的班级数量: {}", currentUserId, classTeacherCount);
+
+                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("异常情况下清除权限限制,允许查看所有数据");
         }
     }
 

+ 20 - 8
backend/ruoyi-modules/ruoyi-zsjy/src/main/resources/mapper/InternshipInfoMapper.xml

@@ -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
web/src/api/zsjy/internship.ts

@@ -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
web/src/api/zsjy/types.ts

@@ -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;
 }
 
 /**

+ 71 - 18
web/src/views/zsjy/internship/msgmanage/index.vue

@@ -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;