ソースを参照

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

zlwu 1 年間 前
親
コミット
4d7bb19fd9

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

@@ -7,6 +7,8 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.web.core.BaseController;
 import org.dromara.zsjy.domain.vo.InternshipInfoVO;
 import org.dromara.zsjy.domain.bo.InternshipInfoQueryBO;
+import org.dromara.zsjy.domain.bo.InternshipInfoAddBO;
+import org.dromara.zsjy.domain.bo.InternshipInfoEditBO;
 import org.dromara.zsjy.service.IInternshipInfoService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
@@ -14,6 +16,8 @@ import io.swagger.v3.oas.annotations.tags.Tag;
 import jakarta.validation.constraints.NotEmpty;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 import jakarta.servlet.http.HttpServletResponse;
@@ -103,9 +107,21 @@ public class InternshipInfoController extends BaseController {
     @Operation(summary = "新增实习信息", description = "为学生新增实习信息")
     @SaCheckPermission("zsjy:internship:add")
     @PostMapping
-    public R<Void> add(@RequestBody @Validated Object addBO) {
-        // TODO: 实现新增实习信息功能
-        return R.ok();
+    public R<Void> add(@RequestBody @Validated(AddGroup.class) InternshipInfoAddBO addBO) {
+        log.info("新增实习信息请求,参数:{}", addBO);
+        try {
+            Boolean result = internshipInfoService.insertInternshipInfo(addBO);
+            if (result) {
+                log.info("新增实习信息成功,学生ID:{}", addBO.getStudentId());
+                return R.ok();
+            } else {
+                log.error("新增实习信息失败,学生ID:{}", addBO.getStudentId());
+                return R.fail("新增实习信息失败");
+            }
+        } catch (Exception e) {
+            log.error("新增实习信息异常,学生ID:{},错误信息:{}", addBO.getStudentId(), e.getMessage(), e);
+            return R.fail("新增实习信息失败:" + e.getMessage());
+        }
     }
 
     /**
@@ -114,9 +130,21 @@ public class InternshipInfoController extends BaseController {
     @Operation(summary = "修改实习信息", description = "修改学生实习信息")
     @SaCheckPermission("zsjy:internship:edit")
     @PutMapping
-    public R<Void> edit(@RequestBody @Validated Object editBO) {
-        // TODO: 实现修改实习信息功能
-        return R.ok();
+    public R<Void> edit(@RequestBody @Validated(EditGroup.class) InternshipInfoEditBO editBO) {
+        log.info("修改实习信息请求,参数:{}", editBO);
+        try {
+            Boolean result = internshipInfoService.updateInternshipInfo(editBO);
+            if (result) {
+                log.info("修改实习信息成功,实习信息ID:{}", editBO.getInternshipId());
+                return R.ok();
+            } else {
+                log.error("修改实习信息失败,实习信息ID:{}", editBO.getInternshipId());
+                return R.fail("修改实习信息失败");
+            }
+        } catch (Exception e) {
+            log.error("修改实习信息异常,实习信息ID:{},错误信息:{}", editBO.getInternshipId(), e.getMessage(), e);
+            return R.fail("修改实习信息失败:" + e.getMessage());
+        }
     }
 
     /**
@@ -127,7 +155,19 @@ public class InternshipInfoController extends BaseController {
     @DeleteMapping("/{internshipIds}")
     public R<Void> remove(@Parameter(description = "实习信息ID串")
                          @PathVariable Long[] internshipIds) {
-        // TODO: 实现删除实习信息功能
-        return R.ok();
+        log.info("删除实习信息请求,IDs:{}", (Object) internshipIds);
+        try {
+            Boolean result = internshipInfoService.deleteInternshipInfo(internshipIds);
+            if (result) {
+                log.info("删除实习信息成功,IDs:{}", (Object) internshipIds);
+                return R.ok();
+            } else {
+                log.error("删除实习信息失败,IDs:{}", (Object) internshipIds);
+                return R.fail("删除实习信息失败");
+            }
+        } catch (Exception e) {
+            log.error("删除实习信息异常,IDs:{},错误信息:{}", internshipIds, e.getMessage(), e);
+            return R.fail("删除实习信息失败:" + e.getMessage());
+        }
     }
 }

+ 26 - 0
backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/service/IInternshipInfoService.java

@@ -4,6 +4,8 @@ import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.zsjy.domain.vo.InternshipInfoVO;
 import org.dromara.zsjy.domain.bo.InternshipInfoQueryBO;
+import org.dromara.zsjy.domain.bo.InternshipInfoAddBO;
+import org.dromara.zsjy.domain.bo.InternshipInfoEditBO;
 import jakarta.servlet.http.HttpServletResponse;
 
 import java.util.List;
@@ -72,4 +74,28 @@ public interface IInternshipInfoService {
      * @param queryBO 查询条件(会被设置权限参数)
      */
     void setDataPermission(InternshipInfoQueryBO queryBO);
+
+    /**
+     * 新增实习信息
+     *
+     * @param addBO 新增参数
+     * @return 是否成功
+     */
+    Boolean insertInternshipInfo(InternshipInfoAddBO addBO);
+
+    /**
+     * 修改实习信息
+     *
+     * @param editBO 修改参数
+     * @return 是否成功
+     */
+    Boolean updateInternshipInfo(InternshipInfoEditBO editBO);
+
+    /**
+     * 删除实习信息
+     *
+     * @param internshipIds 实习信息ID数组
+     * @return 是否成功
+     */
+    Boolean deleteInternshipInfo(Long[] internshipIds);
 }

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

@@ -15,10 +15,15 @@ import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.zsjy.domain.bo.InternshipInfoQueryBO;
+import org.dromara.zsjy.domain.bo.InternshipInfoAddBO;
+import org.dromara.zsjy.domain.bo.InternshipInfoEditBO;
 import org.dromara.zsjy.domain.vo.InternshipInfoVO;
+import org.dromara.zsjy.domain.ZsjyInternshipInfo;
 import org.dromara.zsjy.mapper.InternshipInfoMapper;
+import org.dromara.zsjy.mapper.ZsjyInternshipInfoMapper;
 import org.dromara.zsjy.service.IInternshipInfoService;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 import jakarta.servlet.http.HttpServletResponse;
 
 import java.util.*;
@@ -35,6 +40,7 @@ import java.util.*;
 public class InternshipInfoServiceImpl implements IInternshipInfoService {
 
     private final InternshipInfoMapper internshipInfoMapper;
+    private final ZsjyInternshipInfoMapper zsjyInternshipInfoMapper;
 
     /**
      * 查询学生实习信息分页列表(班主任专用)
@@ -250,4 +256,104 @@ public class InternshipInfoServiceImpl implements IInternshipInfoService {
             default -> "未知状态";
         };
     }
+
+    /**
+     * 新增实习信息
+     *
+     * @param addBO 新增参数
+     * @return 是否成功
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean insertInternshipInfo(InternshipInfoAddBO addBO) {
+        log.info("新增实习信息,参数:{}", addBO);
+
+        // 检查该学生是否已经有实习信息
+        LambdaQueryWrapper<ZsjyInternshipInfo> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(ZsjyInternshipInfo::getStudentId, addBO.getStudentId());
+        ZsjyInternshipInfo existingInfo = zsjyInternshipInfoMapper.selectOne(queryWrapper);
+
+        if (ObjectUtil.isNotNull(existingInfo)) {
+            log.warn("学生ID:{} 已存在实习信息,不能重复添加", addBO.getStudentId());
+            throw new RuntimeException("该学生已存在实习信息,不能重复添加");
+        }
+
+        // 构建实习信息实体
+        ZsjyInternshipInfo internshipInfo = new ZsjyInternshipInfo();
+        BeanUtil.copyProperties(addBO, internshipInfo);
+
+        // 映射字段名称差异
+        internshipInfo.setPositionName(addBO.getInternshipPosition());
+        internshipInfo.setStartDate(addBO.getInternshipStartDate());
+        internshipInfo.setEndDate(addBO.getInternshipEndDate());
+        internshipInfo.setCompanyContact(addBO.getContactPersonName());
+        internshipInfo.setCompanyPhone(addBO.getContactPersonPhone());
+        internshipInfo.setStatus(addBO.getAgreementStatus());
+
+        // 插入数据
+        int result = zsjyInternshipInfoMapper.insert(internshipInfo);
+        log.info("新增实习信息结果:{}", result > 0 ? "成功" : "失败");
+
+        return result > 0;
+    }
+
+    /**
+     * 修改实习信息
+     *
+     * @param editBO 修改参数
+     * @return 是否成功
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean updateInternshipInfo(InternshipInfoEditBO editBO) {
+        log.info("修改实习信息,参数:{}", editBO);
+
+        // 检查实习信息是否存在
+        ZsjyInternshipInfo existingInfo = zsjyInternshipInfoMapper.selectById(editBO.getInternshipId());
+        if (ObjectUtil.isNull(existingInfo)) {
+            log.warn("实习信息ID:{} 不存在", editBO.getInternshipId());
+            throw new RuntimeException("实习信息不存在");
+        }
+
+        // 构建更新实体
+        ZsjyInternshipInfo internshipInfo = new ZsjyInternshipInfo();
+        BeanUtil.copyProperties(editBO, internshipInfo);
+
+        // 映射字段名称差异
+        internshipInfo.setPositionName(editBO.getInternshipPosition());
+        internshipInfo.setStartDate(editBO.getInternshipStartDate());
+        internshipInfo.setEndDate(editBO.getInternshipEndDate());
+        internshipInfo.setCompanyContact(editBO.getContactPersonName());
+        internshipInfo.setCompanyPhone(editBO.getContactPersonPhone());
+        internshipInfo.setStatus(editBO.getAgreementStatus());
+
+        // 更新数据
+        int result = zsjyInternshipInfoMapper.updateById(internshipInfo);
+        log.info("修改实习信息结果:{}", result > 0 ? "成功" : "失败");
+
+        return result > 0;
+    }
+
+    /**
+     * 删除实习信息
+     *
+     * @param internshipIds 实习信息ID数组
+     * @return 是否成功
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean deleteInternshipInfo(Long[] internshipIds) {
+        log.info("删除实习信息,IDs:{}", Arrays.toString(internshipIds));
+
+        if (ObjectUtil.isEmpty(internshipIds)) {
+            log.warn("删除实习信息参数为空");
+            throw new RuntimeException("删除参数不能为空");
+        }
+
+        // 批量删除(逻辑删除)
+        int result = zsjyInternshipInfoMapper.deleteBatchIds(Arrays.asList(internshipIds));
+        log.info("删除实习信息结果:删除了 {} 条记录", result);
+
+        return result > 0;
+    }
 }

+ 10 - 3
web/src/api/zsjy/internship.ts

@@ -1,6 +1,13 @@
 import request from '@/utils/request';
 import { AxiosPromise } from 'axios';
-import { InternshipInfoVO, InternshipInfoQuery, ClassInfoVO, InternshipStatisticsVO } from '@/api/zsjy/types';
+import {
+  InternshipInfoVO,
+  InternshipInfoQuery,
+  InternshipInfoAddBO,
+  InternshipInfoEditBO,
+  ClassInfoVO,
+  InternshipStatisticsVO
+} from '@/api/zsjy/types';
 import { TableDataInfo, R } from '@/api/types';
 
 /**
@@ -65,7 +72,7 @@ export const getInternshipStatistics = (query?: InternshipInfoQuery): AxiosPromi
  * 新增实习信息
  * @param data 实习信息数据
  */
-export const addInternshipInfo = (data: any): AxiosPromise<R<void>> => {
+export const addInternshipInfo = (data: InternshipInfoAddBO): AxiosPromise<R<void>> => {
   return request({
     url: '/zsjy/internship',
     method: 'post',
@@ -77,7 +84,7 @@ export const addInternshipInfo = (data: any): AxiosPromise<R<void>> => {
  * 修改实习信息
  * @param data 实习信息数据
  */
-export const updateInternshipInfo = (data: any): AxiosPromise<R<void>> => {
+export const updateInternshipInfo = (data: InternshipInfoEditBO): AxiosPromise<R<void>> => {
   return request({
     url: '/zsjy/internship',
     method: 'put',

+ 205 - 0
web/src/api/zsjy/types.ts

@@ -862,6 +862,211 @@ export interface InternshipInfoVO {
   updateBy?: number;
 }
 
+/**
+ * 实习信息新增 BO
+ */
+export interface InternshipInfoAddBO {
+  /**
+   * 学生ID
+   */
+  studentId: string | number;
+
+  /**
+   * 实习状态(1进行中 2已完成 3中断)
+   */
+  internshipStatus: string;
+
+  /**
+   * 实习单位名称
+   */
+  companyName: string;
+
+  /**
+   * 实习单位地址
+   */
+  companyAddress: string;
+
+  /**
+   * 行业类型
+   */
+  companyIndustry?: string;
+
+  /**
+   * 单位规模
+   */
+  companyScale?: string;
+
+  /**
+   * 单位联系人
+   */
+  companyContact: string;
+
+  /**
+   * 联系人电话
+   */
+  companyPhone: string;
+
+  /**
+   * 岗位名称
+   */
+  positionName: string;
+
+  /**
+   * 岗位职责
+   */
+  positionDuties?: string;
+
+  /**
+   * 实习津贴
+   */
+  internshipAllowance?: number;
+
+  /**
+   * 工作时长
+   */
+  workHours?: string;
+
+  /**
+   * 住宿地址
+   */
+  accommodationAddress?: string;
+
+  /**
+   * 住宿类型
+   */
+  accommodationType?: string;
+
+  /**
+   * 住宿费用
+   */
+  accommodationCost?: number;
+
+  /**
+   * 实习开始日期
+   */
+  startDate: string;
+
+  /**
+   * 实习结束日期
+   */
+  endDate: string;
+
+  /**
+   * 实际结束日期
+   */
+  actualEndDate?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+}
+
+/**
+ * 实习信息编辑 BO
+ */
+export interface InternshipInfoEditBO {
+  /**
+   * 实习信息ID
+   */
+  internshipId: string | number;
+
+  /**
+   * 学生ID
+   */
+  studentId: string | number;
+
+  /**
+   * 实习状态(1进行中 2已完成 3中断)
+   */
+  internshipStatus: string;
+
+  /**
+   * 实习单位名称
+   */
+  companyName: string;
+
+  /**
+   * 实习单位地址
+   */
+  companyAddress: string;
+
+  /**
+   * 行业类型
+   */
+  companyIndustry?: string;
+
+  /**
+   * 单位规模
+   */
+  companyScale?: string;
+
+  /**
+   * 单位联系人
+   */
+  companyContact: string;
+
+  /**
+   * 联系人电话
+   */
+  companyPhone: string;
+
+  /**
+   * 岗位名称
+   */
+  positionName: string;
+
+  /**
+   * 岗位职责
+   */
+  positionDuties?: string;
+
+  /**
+   * 实习津贴
+   */
+  internshipAllowance?: number;
+
+  /**
+   * 工作时长
+   */
+  workHours?: string;
+
+  /**
+   * 住宿地址
+   */
+  accommodationAddress?: string;
+
+  /**
+   * 住宿类型
+   */
+  accommodationType?: string;
+
+  /**
+   * 住宿费用
+   */
+  accommodationCost?: number;
+
+  /**
+   * 实习开始日期
+   */
+  startDate: string;
+
+  /**
+   * 实习结束日期
+   */
+  endDate: string;
+
+  /**
+   * 实际结束日期
+   */
+  actualEndDate?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+}
+
 /**
  * 实习信息查询 BO
  */

+ 63 - 6
web/src/views/zsjy/internship/msgmanage/index.vue

@@ -137,7 +137,8 @@
         <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" />
+            <span v-if="scope.row.internshipStatus === 'null' || !scope.row.internshipStatus" class="status-tag not-started">未实习</span>
+            <dict-tag v-else :options="internship_status" :value="scope.row.internshipStatus" />
           </template>
         </el-table-column>
         <el-table-column label="实习公司" align="center" prop="companyName" min-width="150" show-overflow-tooltip />
@@ -190,6 +191,8 @@
       </div>
     </el-card>
 
+
+
     <!-- 学生实习详情对话框 -->
     <el-dialog title="学生实习详情" v-model="dialog.visible" width="800px" append-to-body>
       <div v-if="studentDetail" class="student-detail">
@@ -206,7 +209,8 @@
 
         <el-descriptions title="实习信息" :column="2" border class="mt-4">
           <el-descriptions-item label="实习状态">
-            <dict-tag :options="internship_status" :value="studentDetail.internshipStatus" />
+            <span v-if="studentDetail.internshipStatus === 'null' || !studentDetail.internshipStatus" class="status-tag not-started">未实习</span>
+            <dict-tag v-else :options="internship_status" :value="studentDetail.internshipStatus" />
           </el-descriptions-item>
           <el-descriptions-item label="实习公司">{{ studentDetail.internshipCompany || '-' }}</el-descriptions-item>
           <el-descriptions-item label="实习岗位">{{ studentDetail.internshipPosition || '-' }}</el-descriptions-item>
@@ -227,6 +231,20 @@
         </div>
       </template>
     </el-dialog>
+
+    <!-- 新增弹窗 -->
+    <AddDialog
+      v-model="showAddDialog"
+      :student-info="selectedStudentInfo"
+      @success="handleDialogSuccess"
+    />
+
+    <!-- 编辑弹窗 -->
+    <EditDialog
+      v-model="showEditDialog"
+      :student-id="selectedStudentId"
+      @success="handleDialogSuccess"
+    />
   </div>
 </template>
 
@@ -236,6 +254,9 @@ import { InternshipInfoVO, InternshipInfoQuery, ClassInfoVO, InternshipStatistic
 import { ComponentInternalInstance, getCurrentInstance, reactive, ref, toRefs } from 'vue';
 import { parseTime } from '@/utils/ruoyi';
 import { download } from '@/utils/request';
+import { ElMessage } from 'element-plus';
+import AddDialog from './components/AddDialog.vue';
+import EditDialog from './components/EditDialog.vue';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { internship_status, sys_user_sex } = toRefs<any>(proxy?.useDict('internship_status', 'sys_user_sex'));
@@ -254,6 +275,20 @@ const total = ref(0);
 const dateRange = ref<[string, string]>([]);
 const studentDetail = ref<InternshipInfoVO>();
 
+// 弹窗相关状态
+const showAddDialog = ref(false);
+const showEditDialog = ref(false);
+const selectedStudentInfo = ref<{
+  studentId: string;
+  studentName: string;
+  studentNo: string;
+}>({
+  studentId: '',
+  studentName: '',
+  studentNo: ''
+});
+const selectedStudentId = ref('');
+
 const data = reactive({
   queryParams: {
     pageNum: 1,
@@ -388,14 +423,23 @@ const handleExport = () => {
 
 /** 新增实习信息按钮操作 */
 const handleAdd = (row: InternshipInfoVO) => {
-  // TODO: 实现新增实习信息功能
-  proxy?.$modal.msgInfo('新增实习信息功能开发中...');
+  selectedStudentInfo.value = {
+    studentId: row.studentId,
+    studentName: row.studentName,
+    studentNo: row.studentNo
+  };
+  showAddDialog.value = true;
 };
 
 /** 编辑实习信息按钮操作 */
 const handleEdit = (row: InternshipInfoVO) => {
-  // TODO: 实现编辑实习信息功能
-  proxy?.$modal.msgInfo('编辑实习信息功能开发中...');
+  selectedStudentId.value = row.studentId;
+  showEditDialog.value = true;
+};
+
+/** 弹窗操作成功后刷新列表 */
+const handleDialogSuccess = () => {
+  getList();
 };
 
 /** 取消按钮 */
@@ -498,5 +542,18 @@ const cancel = () => {
       margin-top: 20px;
     }
   }
+
+  .status-tag {
+    display: inline-block;
+    padding: 2px 8px;
+    border-radius: 4px;
+    font-size: 12px;
+    font-weight: 500;
+
+    &.not-started {
+      background-color: #f56c6c;
+      color: white;
+    }
+  }
 }
 </style>