wuzhen 1 anno fa
parent
commit
871899c9e9

+ 0 - 1
backend/ruoyi-modules/ruoyi-jcbt/src/main/java/org/dromara/jcbt/controller/JcbtWorkStudyApplicationController.java

@@ -324,7 +324,6 @@ public class JcbtWorkStudyApplicationController extends BaseController {
      * 获取当前用户学生信息
      */
     @Operation(summary = "获取当前用户学生信息")
-    @SaCheckPermission("jcbt:workStudyApplication:query")
     @GetMapping("/currentStudentInfo")
     public R<XgStudentMsgVo> getCurrentStudentInfo() {
         try {

+ 10 - 0
mobile/src/api/workStudy.js

@@ -131,3 +131,13 @@ export const updateApplication = (data) => {
         data: data
     });
 };
+
+/**
+ * 获取学生已申请岗位状态列表
+ */
+export const getStudentApplicationStatusList = () => {
+    return request({
+        url: '/jcbt/workStudyApplication/student/applicationStatus',
+        method: 'GET'
+    });
+};

+ 27 - 106
mobile/src/pages/workStudy/apply.vue

@@ -113,19 +113,7 @@
                         />
                     </u-form-item>
                     
-                    <u-form-item 
-                        label="年级" 
-                        prop="grade"
-                    >
-                        <view @click="showGradePicker = true">
-                            <u-input 
-                                v-model="gradeText" 
-                                placeholder="请选择年级"
-                                readonly
-                                suffix-icon="arrow-down"
-                            />
-                        </view>
-                    </u-form-item>
+
                 </view>
 
                 <!-- 申请信息 -->
@@ -137,14 +125,15 @@
                         prop="familyFinancialStatus"
                         :required="true"
                     >
-                        <view @click="showFinancialPicker = true">
-                            <u-input 
-                                v-model="financialText" 
-                                placeholder="请选择家庭经济情况"
-                                readonly
-                                suffix-icon="arrow-down"
+                        <u-radio-group v-model="formData.familyFinancialStatus">
+                            <u-radio 
+                                v-for="option in familyStatusOptions" 
+                                :key="option.value"
+                                :name="option.value"
+                                :label="option.label"
+                                style="margin-right: 20rpx; margin-bottom: 15rpx; font-size: 28rpx;"
                             />
-                        </view>
+                        </u-radio-group>
                     </u-form-item>
                     
                     <u-form-item 
@@ -241,23 +230,9 @@
             </u-button>
         </view>
 
-        <!-- 年级选择器 -->
-        <u-picker
-            :show="showGradePicker"
-            :columns="gradeOptions"
-            keyName="label"
-            @confirm="onGradeConfirm"
-            @cancel="showGradePicker = false"
-        />
-
-        <!-- 家庭经济情况选择器 -->
-        <u-picker
-            :show="showFinancialPicker"
-            :columns="financialOptions"
-            keyName="label"
-            @confirm="onFinancialConfirm"
-            @cancel="showFinancialPicker = false"
-        />
+
+
+
 
         <!-- 加载状态 -->
         <u-loading-page :loading="loading" loading-text="加载中..." />
@@ -293,7 +268,7 @@ export default {
                 collegeName: '',
                 majorName: '',
                 className: '',
-                grade: '',
+
                 familyFinancialStatus: '',
                 plannedWorkHours: '',
                 applicationReason: '',
@@ -302,17 +277,13 @@ export default {
                 remark: ''
             },
             
-            // 选择器显示状态
-            showGradePicker: false,
-            showFinancialPicker: false,
-            
-            // 选择器文本
-            gradeText: '',
-            financialText: '',
-            
-            // 选择器选项
-            gradeOptions: [[]],
-            financialOptions: [[]],
+            // 家庭经济情况选项(与web端保持一致)
+            familyStatusOptions: [
+                { value: '特困', label: '特困' },
+                { value: '贫困', label: '贫困' },
+                { value: '一般', label: '一般' },
+                { value: '良好', label: '良好' }
+            ],
             
             // 加载状态
             loading: false,
@@ -348,8 +319,7 @@ export default {
                 // 并行加载数据
                 const promises = [
                     this.loadPositionData(),
-                    this.loadStudentInfo(),
-                    this.loadApplicationOptions()
+                    this.loadStudentInfo()
                 ];
                 
                 await Promise.all(promises);
@@ -396,20 +366,6 @@ export default {
             }
         },
         
-        // 加载申请选项
-        async loadApplicationOptions() {
-            const response = await getApplicationOptions();
-            if (response.code === 200) {
-                const options = response.data;
-                
-                // 设置年级选项
-                this.gradeOptions = [options.gradeOptions || []];
-                
-                // 设置家庭经济情况选项
-                this.financialOptions = [options.familyFinancialStatusOptions || []];
-            }
-        },
-        
         // 加载申请详情(编辑模式)
         async loadApplicationDetail() {
             const response = await getApplicationDetail(this.applicationId);
@@ -423,16 +379,16 @@ export default {
                     }
                 });
                 
-                // 设置选择器文本
-                this.updatePickerTexts();
+
             }
         },
         
         // 填充学生基本信息
         fillStudentInfo() {
             if (this.studentInfo) {
-                this.formData.studentName = this.studentInfo.studentName || '';
-                this.formData.studentNumber = this.studentInfo.studentNumber || '';
+                // 修改字段映射以匹配后端返回的字段名
+                this.formData.studentName = this.studentInfo.name || '';           // 修正:name
+                this.formData.studentNumber = this.studentInfo.studentNo || '';   // 修正:studentNo
                 this.formData.collegeName = this.studentInfo.collegeName || '';
                 this.formData.majorName = this.studentInfo.majorName || '';
                 this.formData.className = this.studentInfo.className || '';
@@ -440,47 +396,12 @@ export default {
                 // 如果是创建模式,填充其他基本信息
                 if (this.mode === 'create') {
                     this.formData.idCard = this.studentInfo.idCard || '';
-                    this.formData.contactPhone = this.studentInfo.contactPhone || '';
-                    this.formData.grade = this.studentInfo.grade || '';
+                    this.formData.contactPhone = this.studentInfo.phone || '';     // 修正:phone
+
                 }
-                
-                this.updatePickerTexts();
-            }
-        },
-        
-        // 更新选择器文本显示
-        updatePickerTexts() {
-            // 更新年级文本
-            if (this.formData.grade && this.gradeOptions[0].length > 0) {
-                const gradeOption = this.gradeOptions[0].find(item => item.value === this.formData.grade);
-                this.gradeText = gradeOption ? gradeOption.label : '';
-            }
-            
-            // 更新家庭经济情况文本
-            if (this.formData.familyFinancialStatus && this.financialOptions[0].length > 0) {
-                const financialOption = this.financialOptions[0].find(item => item.value === this.formData.familyFinancialStatus);
-                this.financialText = financialOption ? financialOption.label : '';
             }
         },
         
-        // 年级选择确认
-        onGradeConfirm(e) {
-            const index = e.indexs[0];
-            const selected = this.gradeOptions[0][index];
-            this.formData.grade = selected.value;
-            this.gradeText = selected.label;
-            this.showGradePicker = false;
-        },
-        
-        // 家庭经济情况选择确认
-        onFinancialConfirm(e) {
-            const index = e.indexs[0];
-            const selected = this.financialOptions[0][index];
-            this.formData.familyFinancialStatus = selected.value;
-            this.financialText = selected.label;
-            this.showFinancialPicker = false;
-        },
-        
         // 表单验证
         validateForm() {
             const requiredFields = [

+ 206 - 56
mobile/src/pages/workStudy/index.vue

@@ -142,6 +142,11 @@
                             <u-icon name="calendar" size="28" color="#666" />
                             <text class="info-text">有效期:{{ item.startDate }} 至 {{ item.endDate }}</text>
                         </view>
+                        <!-- 申请状态信息 -->
+                        <view class="info-row" v-if="getPositionApplicationStatus(item)">
+                            <u-icon name="checkmark-circle" size="28" color="#1890ff" />
+                            <text class="info-text" style="color: #1890ff;">我的申请:{{ getPositionApplicationStatus(item) }}</text>
+                        </view>
                     </view>
 
                     <!-- 操作按钮 -->
@@ -286,7 +291,8 @@ import {
     getAvailablePositions, 
     getMyApplications, 
     cancelApplication,
-    getCurrentStudentInfo 
+    getCurrentStudentInfo,
+    getStudentApplicationStatusList 
 } from '@/api/workStudy.js';
 
 export default {
@@ -354,7 +360,10 @@ export default {
             refreshing: false,
             
             // 用户信息
-            studentInfo: null
+            studentInfo: null,
+            
+            // 学生申请状态列表(用于判断申请状态)
+            studentApplications: []
         };
     },
     
@@ -396,6 +405,8 @@ export default {
             try {
                 // 获取学生信息
                 await this.loadStudentInfo();
+                // 获取学生申请状态列表
+                await this.loadStudentApplications();
                 // 加载岗位列表
                 await this.loadPositionList(true);
             } catch (error) {
@@ -419,6 +430,18 @@ export default {
             }
         },
         
+        // 加载学生申请状态列表
+        async loadStudentApplications() {
+            try {
+                const response = await getStudentApplicationStatusList();
+                if (response.code === 200) {
+                    this.studentApplications = response.data || [];
+                }
+            } catch (error) {
+                console.error('获取申请状态失败:', error);
+            }
+        },
+        
         // 加载岗位列表
         async loadPositionList(reset = false) {
             if (this.loading) return;
@@ -532,16 +555,21 @@ export default {
         },
         
         // 刷新数据
-        refreshData() {
+        async refreshData() {
             this.refreshing = true;
-            if (this.currentTab === 0) {
-                this.loadPositionList(true).finally(() => {
-                    this.refreshing = false;
-                });
-            } else {
-                this.loadMyApplications(true).finally(() => {
-                    this.refreshing = false;
-                });
+            try {
+                // 同时刷新学生申请状态
+                await this.loadStudentApplications();
+                
+                if (this.currentTab === 0) {
+                    await this.loadPositionList(true);
+                } else {
+                    await this.loadMyApplications(true);
+                }
+            } catch (error) {
+                console.error('刷新数据失败:', error);
+            } finally {
+                this.refreshing = false;
             }
         },
         
@@ -564,23 +592,45 @@ export default {
             });
         },
         
-        // 申请岗位
-        handleApply(event, item) {
-            // 如果只传了一个参数,说明是从卡片点击调用的,第一个参数就是item
-            if (!item && typeof event === 'object' && event.id) {
-                item = event;
+        // 申请岗位(参考web端实现)
+        handleApply(event, position) {
+            // 如果只传了一个参数,说明是从卡片点击调用的,第一个参数就是position
+            if (!position && typeof event === 'object' && event.id) {
+                position = event;
             }
             
-            if (!this.canApply(item)) {
+            const application = this.studentApplications.find(app => app.positionId === position.id);
+            
+            // 如果已有申请且状态为已提交或审核中,跳转到申请管理页面
+            if (application && ['submitted', 'college_reviewing', 'final_reviewing'].includes(application.status)) {
+                uni.switchTab({
+                    url: '/pages/workStudy/index'
+                });
+                // 切换到"我的申请"标签页
+                this.currentTab = 1;
+                this.onTabChange(1);
+                return;
+            }
+            
+            // 如果已录用,不允许操作
+            if (application && application.status === 'approved') {
                 uni.showToast({
-                    title: this.getApplyButtonText(item),
+                    title: '您已被该岗位录用',
+                    icon: 'none'
+                });
+                return;
+            }
+            
+            if (!this.canApply(position)) {
+                uni.showToast({
+                    title: '该岗位当前不可申请',
                     icon: 'none'
                 });
                 return;
             }
             
             uni.navigateTo({
-                url: `/pages/workStudy/apply?positionId=${item.id}`
+                url: `/pages/workStudy/apply?positionId=${position.id}`
             });
         },
         
@@ -661,53 +711,140 @@ export default {
             return typeMap[status] || 'default';
         },
         
-        // 判断是否可以申请
-        canApply(item) {
-            return item.status === 'RECRUITING' && 
-                   (item.currentCount || 0) < (item.requiredCount || 0);
+        // 判断是否可以申请(完全参考web端实现)
+        canApply(position) {
+            const application = this.studentApplications.find(app => app.positionId === position.id);
+            
+            // 如果已录用,禁用按钮
+            if (application && application.status === 'approved') {
+                return false;
+            }
+            
+            // 检查岗位状态
+            if (!['PUBLISHED', 'RECRUITING'].includes(position.status || '')) {
+                return false;
+            }
+            
+            // 检查是否还有空缺
+            const current = position.currentCount || 0;
+            const required = position.requiredCount || 0;
+            if (current >= required) {
+                return false;
+            }
+            
+            // 检查有效期
+            if (position.endDate) {
+                const endDate = new Date(position.endDate);
+                if (endDate < new Date()) {
+                    return false;
+                }
+            }
+            
+            return true;
         },
         
-        // 获取申请按钮文字
-        getApplyButtonText(item) {
-            if (item.status !== 'RECRUITING') {
-                return '暂不可申请';
+        // 获取申请按钮文字(参考web端实现8种状态)
+        getApplyButtonText(position) {
+            const application = this.studentApplications.find(app => app.positionId === position.id);
+            
+            // 如果已录用
+            if (application && application.status === 'approved') {
+                return '申请已通过';
+            }
+            
+            // 如果有申请且状态为审核中
+            if (application && ['submitted', 'college_reviewing', 'final_reviewing'].includes(application.status)) {
+                return '申请审核中';
+            }
+            
+            // 如果被拒绝
+            if (application && application.status === 'rejected') {
+                return '重新申请';
+            }
+            
+            // 检查岗位状态
+            if (!['PUBLISHED', 'RECRUITING'].includes(position.status || '')) {
+                if (position.status === 'EXPIRED') {
+                    return '岗位已过期';
+                } else if (position.status === 'SUSPENDED') {
+                    return '岗位已暂停';
+                } else if (position.status === 'CANCELLED') {
+                    return '岗位已取消';
+                } else {
+                    return '暂不可申请';
+                }
+            }
+            
+            // 检查是否还有空缺
+            const current = position.currentCount || 0;
+            const required = position.requiredCount || 0;
+            if (current >= required) {
+                return '岗位已满员';
             }
-            if ((item.currentCount || 0) >= (item.requiredCount || 0)) {
-                return '已满员';
+            
+            // 检查有效期
+            if (position.endDate) {
+                const endDate = new Date(position.endDate);
+                if (endDate < new Date()) {
+                    return '岗位已过期';
+                }
             }
-            return '申请岗位';
+            
+            // 默认可申请
+            return '申请此岗位';
         },
         
-        // 获取申请状态文字
+        // 获取申请状态文字(与web端保持一致)
         getApplicationStatusText(item) {
-            const statusMap = {
-                'DRAFT': '草稿',
-                'SUBMITTED': '已提交',
-                'COLLEGE_REVIEWING': '学院审核中',
-                'COLLEGE_APPROVED': '学院审核通过',
-                'COLLEGE_REJECTED': '学院审核未通过',
-                'FINAL_REVIEWING': '学生处审核中',
-                'FINAL_APPROVED': '审核通过',
-                'FINAL_REJECTED': '审核未通过',
-                'CANCELLED': '已撤销'
-            };
-            return statusMap[item.status] || '未知状态';
+            if (!item) return '未申请';
+            
+            // 支持两种格式:web端的小写格式和移动端的大写格式
+            const status = item.status ? item.status.toLowerCase() : '';
+            
+            switch (status) {
+                case 'submitted':
+                case 'SUBMITTED':
+                    return '已提交';
+                case 'college_reviewing':
+                case 'COLLEGE_REVIEWING':
+                    return '学院审核中';
+                case 'final_reviewing':
+                case 'FINAL_REVIEWING':
+                    return '学生处审核中';
+                case 'approved':
+                case 'FINAL_APPROVED':
+                    return '审核通过';
+                case 'rejected':
+                case 'FINAL_REJECTED':
+                    return '审核不通过';
+                case 'cancelled':
+                case 'CANCELLED':
+                    return '已撤销';
+                case 'draft':
+                case 'DRAFT':
+                    return '草稿';
+                default:
+                    return '未知状态';
+            }
         },
         
-        // 获取申请状态类型
+        // 获取申请状态类型(与web端保持一致)
         getApplicationStatusType(item) {
+            if (!item) return 'default';
+            
+            // 支持两种格式:web端的小写格式和移动端的大写格式
+            const status = item.status ? item.status.toLowerCase() : '';
+            
             const typeMap = {
-                'DRAFT': 'info',
-                'SUBMITTED': 'warning',
-                'COLLEGE_REVIEWING': 'warning',
-                'COLLEGE_APPROVED': 'success',
-                'COLLEGE_REJECTED': 'error',
-                'FINAL_REVIEWING': 'warning',
-                'FINAL_APPROVED': 'success',
-                'FINAL_REJECTED': 'error',
-                'CANCELLED': 'info'
+                'draft': 'info',
+                'submitted': 'warning',
+                'college_reviewing': 'warning',
+                'final_reviewing': 'warning',
+                'approved': 'success',
+                'rejected': 'error',
+                'cancelled': 'info'
             };
-            return typeMap[item.status] || 'default';
+            return typeMap[status] || 'default';
         },
         
         // 获取审核状态文字
@@ -720,9 +857,22 @@ export default {
             return statusMap[status] || '未知';
         },
         
-        // 判断是否可以撤销申请
+        // 判断是否可以撤销申请(与web端保持一致)
         canCancelApplication(item) {
-            return ['DRAFT', 'SUBMITTED', 'COLLEGE_REVIEWING'].includes(item.status);
+            if (!item) return false;
+            
+            // 支持两种格式:web端的小写格式和移动端的大写格式
+            const status = item.status ? item.status.toLowerCase() : '';
+            return ['draft', 'submitted', 'college_reviewing'].includes(status) ||
+                   ['DRAFT', 'SUBMITTED', 'COLLEGE_REVIEWING'].includes(item.status);
+        },
+        
+        // 获取岗位的申请状态(用于在岗位卡片中显示)
+        getPositionApplicationStatus(position) {
+            const application = this.studentApplications.find(app => app.positionId === position.id);
+            if (!application) return null;
+            
+            return this.getApplicationStatusText(application);
         }
     }
 };

+ 0 - 2
web/src/views/jcbt/workstudy/Application/form.vue

@@ -232,8 +232,6 @@ const initFormData = async () => {
     formData.positionId = props.position.id as number;
     formData.positionName = props.position.positionName || '';
     formData.positionType = '勤工俭学'; // 默认类型
-    // 使用学院名称作为工作地点
-    formData.workLocation = props.position.collegeName || '待确定';
   }
 
   try {

+ 25 - 33
web/src/views/jcbt/workstudy/Application/index.vue

@@ -156,8 +156,7 @@
 
     <!-- 岗位详情对话框 -->
     <el-dialog v-model="detailDialogVisible" title="岗位详情" width="80%" :close-on-click-modal="false" class="position-detail-dialog">
-      <!-- <PositionDetail v-if="detailDialogVisible && selectedPositionId" :position-id="selectedPositionId" @apply="handleApplyFromDetail" /> -->
-      <div style="padding: 20px; text-align: center;">岗位详情页面开发中...</div>
+      <PositionDetail v-if="detailDialogVisible && selectedPositionId" :position-id="selectedPositionId" @apply="handleApplyFromDetail" />
       <template #footer>
         <el-button @click="detailDialogVisible = false">关闭</el-button>
       </template>
@@ -165,17 +164,12 @@
 
     <!-- 申请表单对话框 -->
     <el-dialog v-model="applyDialogVisible" title="申请岗位" width="70%" :close-on-click-modal="false" class="apply-dialog">
-      <!-- <ApplicationForm
+      <ApplicationForm
         v-if="applyDialogVisible && selectedPosition"
         :position="selectedPosition"
         @success="handleApplySuccess"
         @cancel="applyDialogVisible = false"
-      /> -->
-      <div style="padding: 20px; text-align: center;">申请表单页面开发中...</div>
-      <template #footer>
-        <el-button @click="applyDialogVisible = false">取消</el-button>
-        <el-button type="primary" @click="handleApplySuccess">确认申请</el-button>
-      </template>
+      />
     </el-dialog>
   </div>
 </template>
@@ -187,8 +181,8 @@ import { useRouter } from 'vue-router';
 import { listVisiblePositions } from '@/api/jcbt/workStudyPosition';
 import type { WorkStudyPositionVO } from '@/api/jcbt/workStudyPosition';
 import { getStudentApplicationStatusList } from '@/api/jcbt/workStudyApplication';
-// import PositionDetail from './detail.vue';
-// import ApplicationForm from './form.vue';
+import PositionDetail from './detail.vue';
+import ApplicationForm from './form.vue';
 
 const router = useRouter();
 
@@ -557,13 +551,11 @@ onMounted(() => {
   margin-bottom: 20px;
 }
 
-:deep(.el-table__header) {
-  th {
-    background: linear-gradient(135deg, #fafbff 0%, #f8fafc 100%);
-    color: #303133;
-    font-weight: 600;
-    border-color: rgba(93, 135, 255, 0.1);
-  }
+:deep(.el-table__header th) {
+  background: linear-gradient(135deg, #fafbff 0%, #f8fafc 100%);
+  color: #303133;
+  font-weight: 600;
+  border-color: rgba(93, 135, 255, 0.1);
 }
 
 :deep(.el-table__row:hover) {
@@ -579,10 +571,10 @@ onMounted(() => {
 .number-display {
   font-weight: 600;
   color: rgb(93, 135, 255);
+}
 
-  &.text-success {
-    color: rgb(19, 222, 185);
-  }
+.number-display.text-success {
+  color: rgb(19, 222, 185);
 }
 
 .salary-info {
@@ -591,10 +583,10 @@ onMounted(() => {
   gap: 4px;
   color: rgb(255, 174, 31);
   font-weight: 500;
+}
 
-  .el-icon {
-    color: rgb(255, 174, 31);
-  }
+.salary-info .el-icon {
+  color: rgb(255, 174, 31);
 }
 
 .date-range {
@@ -602,17 +594,17 @@ onMounted(() => {
   flex-direction: column;
   gap: 2px;
   font-size: 12px;
+}
 
-  .date-item {
-    color: #606266;
-    font-family: monospace;
-  }
+.date-range .date-item {
+  color: #606266;
+  font-family: monospace;
+}
 
-  .date-separator {
-    color: #909399;
-    text-align: center;
-    font-size: 10px;
-  }
+.date-range .date-separator {
+  color: #909399;
+  text-align: center;
+  font-size: 10px;
 }
 
 .action-buttons {