744 lines
24 KiB
Vue
744 lines
24 KiB
Vue
<template>
|
||
<view class="apply-container">
|
||
<!-- 岗位信息卡片 -->
|
||
<view class="position-card" v-if="positionData">
|
||
<view class="card-title">申请岗位</view>
|
||
<view class="position-info">
|
||
<view class="position-name">{{ positionData.positionName }}</view>
|
||
<view class="position-detail">
|
||
<text>工作时间:{{ positionData.workTime }}</text>
|
||
<text>联系老师:{{ positionData.contactTeacher }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 申请表单 -->
|
||
<view class="form-container">
|
||
<u-form
|
||
:model="formData"
|
||
ref="form"
|
||
label-width="140"
|
||
label-position="left"
|
||
>
|
||
<!-- 基本信息 -->
|
||
<view class="form-section">
|
||
<view class="section-title">基本信息</view>
|
||
|
||
<u-form-item
|
||
label="学生姓名"
|
||
prop="studentName"
|
||
:required="true"
|
||
>
|
||
<u-input
|
||
v-model="formData.studentName"
|
||
placeholder="请输入学生姓名"
|
||
:disabled="true"
|
||
/>
|
||
</u-form-item>
|
||
|
||
<u-form-item
|
||
label="学号"
|
||
prop="studentNumber"
|
||
:required="true"
|
||
>
|
||
<u-input
|
||
v-model="formData.studentNumber"
|
||
placeholder="请输入学号"
|
||
:disabled="true"
|
||
/>
|
||
</u-form-item>
|
||
|
||
<u-form-item
|
||
label="身份证号"
|
||
prop="idCard"
|
||
:required="true"
|
||
>
|
||
<u-input
|
||
v-model="formData.idCard"
|
||
placeholder="请输入身份证号"
|
||
maxlength="18"
|
||
/>
|
||
</u-form-item>
|
||
|
||
<u-form-item
|
||
label="联系电话"
|
||
prop="contactPhone"
|
||
:required="true"
|
||
>
|
||
<u-input
|
||
v-model="formData.contactPhone"
|
||
placeholder="请输入联系电话"
|
||
maxlength="11"
|
||
/>
|
||
</u-form-item>
|
||
</view>
|
||
|
||
<!-- 学籍信息 -->
|
||
<view class="form-section">
|
||
<view class="section-title">学籍信息</view>
|
||
|
||
<u-form-item
|
||
label="学院名称"
|
||
prop="collegeName"
|
||
:required="true"
|
||
>
|
||
<u-input
|
||
v-model="formData.collegeName"
|
||
placeholder="学院名称"
|
||
:disabled="true"
|
||
/>
|
||
</u-form-item>
|
||
|
||
<u-form-item
|
||
label="专业名称"
|
||
prop="majorName"
|
||
:required="true"
|
||
>
|
||
<u-input
|
||
v-model="formData.majorName"
|
||
placeholder="专业名称"
|
||
:disabled="true"
|
||
/>
|
||
</u-form-item>
|
||
|
||
<u-form-item
|
||
label="班级名称"
|
||
prop="className"
|
||
:required="true"
|
||
>
|
||
<u-input
|
||
v-model="formData.className"
|
||
placeholder="班级名称"
|
||
:disabled="true"
|
||
/>
|
||
</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>
|
||
|
||
<!-- 申请信息 -->
|
||
<view class="form-section">
|
||
<view class="section-title">申请信息</view>
|
||
|
||
<u-form-item
|
||
label="家庭经济情况"
|
||
prop="familyFinancialStatus"
|
||
:required="true"
|
||
>
|
||
<view @click="showFinancialPicker = true">
|
||
<u-input
|
||
v-model="financialText"
|
||
placeholder="请选择家庭经济情况"
|
||
readonly
|
||
suffix-icon="arrow-down"
|
||
/>
|
||
</view>
|
||
</u-form-item>
|
||
|
||
<u-form-item
|
||
label="计划工作时长"
|
||
prop="plannedWorkHours"
|
||
>
|
||
<u-input
|
||
v-model="formData.plannedWorkHours"
|
||
placeholder="请输入计划工作时长(小时/周)"
|
||
type="number"
|
||
/>
|
||
</u-form-item>
|
||
|
||
<u-form-item
|
||
label="申请理由"
|
||
prop="applicationReason"
|
||
:required="true"
|
||
>
|
||
<u-textarea
|
||
v-model="formData.applicationReason"
|
||
placeholder="请详细说明申请此岗位的理由"
|
||
:maxlength="500"
|
||
:show-word-limit="true"
|
||
height="200"
|
||
count
|
||
/>
|
||
</u-form-item>
|
||
|
||
<u-form-item
|
||
label="个人能力及经验"
|
||
prop="personalAbility"
|
||
:required="true"
|
||
>
|
||
<u-textarea
|
||
v-model="formData.personalAbility"
|
||
placeholder="请描述与岗位相关的个人能力和经验"
|
||
:maxlength="500"
|
||
:show-word-limit="true"
|
||
height="200"
|
||
count
|
||
/>
|
||
</u-form-item>
|
||
|
||
<u-form-item
|
||
label="时间安排"
|
||
prop="timeArrangement"
|
||
:required="true"
|
||
>
|
||
<u-textarea
|
||
v-model="formData.timeArrangement"
|
||
placeholder="请说明您的时间安排,确保能够胜任此岗位工作"
|
||
:maxlength="300"
|
||
:show-word-limit="true"
|
||
height="150"
|
||
count
|
||
/>
|
||
</u-form-item>
|
||
|
||
<u-form-item
|
||
label="备注"
|
||
prop="remark"
|
||
>
|
||
<u-textarea
|
||
v-model="formData.remark"
|
||
placeholder="其他需要说明的情况(选填)"
|
||
:maxlength="200"
|
||
:show-word-limit="true"
|
||
height="120"
|
||
count
|
||
/>
|
||
</u-form-item>
|
||
</view>
|
||
</u-form>
|
||
</view>
|
||
|
||
<!-- 底部操作按钮 -->
|
||
<view class="bottom-actions">
|
||
<u-button
|
||
type="default"
|
||
size="large"
|
||
@click="saveDraft"
|
||
:loading="saving"
|
||
style="margin-right: 20rpx;"
|
||
>
|
||
保存草稿
|
||
</u-button>
|
||
<u-button
|
||
type="primary"
|
||
size="large"
|
||
@click="submitApplication"
|
||
:loading="submitting"
|
||
>
|
||
提交申请
|
||
</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="加载中..." />
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import {
|
||
getPositionWithApplicationStatus,
|
||
getCurrentStudentInfo,
|
||
getApplicationOptions,
|
||
addApplication,
|
||
updateApplication,
|
||
getApplicationDetail
|
||
} from '@/api/workStudy.js';
|
||
|
||
export default {
|
||
name: 'WorkStudyApply',
|
||
data() {
|
||
return {
|
||
positionId: '',
|
||
applicationId: '',
|
||
mode: 'create', // create 或 edit
|
||
positionData: null,
|
||
studentInfo: null,
|
||
|
||
// 表单数据
|
||
formData: {
|
||
studentName: '',
|
||
studentNumber: '',
|
||
idCard: '',
|
||
contactPhone: '',
|
||
collegeName: '',
|
||
majorName: '',
|
||
className: '',
|
||
grade: '',
|
||
familyFinancialStatus: '',
|
||
plannedWorkHours: '',
|
||
applicationReason: '',
|
||
personalAbility: '',
|
||
timeArrangement: '',
|
||
remark: ''
|
||
},
|
||
|
||
// 选择器显示状态
|
||
showGradePicker: false,
|
||
showFinancialPicker: false,
|
||
|
||
// 选择器文本
|
||
gradeText: '',
|
||
financialText: '',
|
||
|
||
// 选择器选项
|
||
gradeOptions: [[]],
|
||
financialOptions: [[]],
|
||
|
||
// 加载状态
|
||
loading: false,
|
||
saving: false,
|
||
submitting: false
|
||
};
|
||
},
|
||
|
||
onLoad(options) {
|
||
if (options.positionId) {
|
||
this.positionId = options.positionId;
|
||
this.applicationId = options.applicationId || '';
|
||
this.mode = options.mode || 'create';
|
||
|
||
this.initData();
|
||
} else {
|
||
uni.showToast({
|
||
title: '岗位ID不能为空',
|
||
icon: 'none'
|
||
});
|
||
setTimeout(() => {
|
||
uni.navigateBack();
|
||
}, 1500);
|
||
}
|
||
},
|
||
|
||
methods: {
|
||
// 初始化数据
|
||
async initData() {
|
||
this.loading = true;
|
||
|
||
try {
|
||
// 并行加载数据
|
||
const promises = [
|
||
this.loadPositionData(),
|
||
this.loadStudentInfo(),
|
||
this.loadApplicationOptions()
|
||
];
|
||
|
||
await Promise.all(promises);
|
||
|
||
// 如果是编辑模式,加载申请详情
|
||
if (this.mode === 'edit' && this.applicationId) {
|
||
await this.loadApplicationDetail();
|
||
}
|
||
|
||
// 填充学生基本信息
|
||
this.fillStudentInfo();
|
||
|
||
} catch (error) {
|
||
console.error('初始化数据失败:', error);
|
||
uni.showToast({
|
||
title: '加载数据失败',
|
||
icon: 'none'
|
||
});
|
||
setTimeout(() => {
|
||
uni.navigateBack();
|
||
}, 1500);
|
||
} finally {
|
||
this.loading = false;
|
||
}
|
||
},
|
||
|
||
// 加载岗位数据
|
||
async loadPositionData() {
|
||
const response = await getPositionWithApplicationStatus(this.positionId);
|
||
if (response.code === 200) {
|
||
this.positionData = response.data.position;
|
||
} else {
|
||
throw new Error(response.msg || '获取岗位信息失败');
|
||
}
|
||
},
|
||
|
||
// 加载学生信息
|
||
async loadStudentInfo() {
|
||
const response = await getCurrentStudentInfo();
|
||
if (response.code === 200) {
|
||
this.studentInfo = response.data;
|
||
} else {
|
||
throw new Error(response.msg || '获取学生信息失败');
|
||
}
|
||
},
|
||
|
||
// 加载申请选项
|
||
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);
|
||
if (response.code === 200) {
|
||
const data = response.data;
|
||
|
||
// 填充表单数据
|
||
Object.keys(this.formData).forEach(key => {
|
||
if (data[key] !== undefined) {
|
||
this.formData[key] = data[key];
|
||
}
|
||
});
|
||
|
||
// 设置选择器文本
|
||
this.updatePickerTexts();
|
||
}
|
||
},
|
||
|
||
// 填充学生基本信息
|
||
fillStudentInfo() {
|
||
if (this.studentInfo) {
|
||
this.formData.studentName = this.studentInfo.studentName || '';
|
||
this.formData.studentNumber = this.studentInfo.studentNumber || '';
|
||
this.formData.collegeName = this.studentInfo.collegeName || '';
|
||
this.formData.majorName = this.studentInfo.majorName || '';
|
||
this.formData.className = this.studentInfo.className || '';
|
||
|
||
// 如果是创建模式,填充其他基本信息
|
||
if (this.mode === 'create') {
|
||
this.formData.idCard = this.studentInfo.idCard || '';
|
||
this.formData.contactPhone = this.studentInfo.contactPhone || '';
|
||
this.formData.grade = this.studentInfo.grade || '';
|
||
}
|
||
|
||
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 = [
|
||
{ field: 'studentName', name: '学生姓名' },
|
||
{ field: 'studentNumber', name: '学号' },
|
||
{ field: 'idCard', name: '身份证号' },
|
||
{ field: 'contactPhone', name: '联系电话' },
|
||
{ field: 'collegeName', name: '学院名称' },
|
||
{ field: 'majorName', name: '专业名称' },
|
||
{ field: 'className', name: '班级名称' },
|
||
{ field: 'familyFinancialStatus', name: '家庭经济情况' },
|
||
{ field: 'applicationReason', name: '申请理由' },
|
||
{ field: 'personalAbility', name: '个人能力及经验' },
|
||
{ field: 'timeArrangement', name: '时间安排' }
|
||
];
|
||
|
||
for (const item of requiredFields) {
|
||
if (!this.formData[item.field] || this.formData[item.field].trim() === '') {
|
||
uni.showToast({
|
||
title: `请填写${item.name}`,
|
||
icon: 'none'
|
||
});
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 验证身份证号格式
|
||
if (this.formData.idCard && !/^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/.test(this.formData.idCard)) {
|
||
uni.showToast({
|
||
title: '身份证号格式不正确',
|
||
icon: 'none'
|
||
});
|
||
return false;
|
||
}
|
||
|
||
// 验证手机号格式
|
||
if (this.formData.contactPhone && !/^1[3-9]\d{9}$/.test(this.formData.contactPhone)) {
|
||
uni.showToast({
|
||
title: '手机号格式不正确',
|
||
icon: 'none'
|
||
});
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
},
|
||
|
||
// 保存草稿
|
||
async saveDraft(autoNavigate = true) {
|
||
if (!this.validateForm()) return false;
|
||
|
||
this.saving = true;
|
||
|
||
try {
|
||
const requestData = {
|
||
...this.formData,
|
||
positionId: this.positionId,
|
||
positionName: this.positionData.positionName,
|
||
positionType: this.positionData.positionType || ''
|
||
};
|
||
|
||
let response;
|
||
if (this.mode === 'edit' && this.applicationId) {
|
||
requestData.id = this.applicationId;
|
||
response = await updateApplication(requestData);
|
||
} else {
|
||
response = await addApplication(requestData);
|
||
}
|
||
|
||
if (response.code === 200) {
|
||
uni.showToast({
|
||
title: '保存成功',
|
||
icon: 'success'
|
||
});
|
||
|
||
if (autoNavigate) {
|
||
setTimeout(() => {
|
||
uni.navigateBack();
|
||
}, 1000);
|
||
}
|
||
return true;
|
||
} else {
|
||
throw new Error(response.msg || '保存失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('保存草稿失败:', error);
|
||
uni.showToast({
|
||
title: error.message || '保存失败',
|
||
icon: 'none'
|
||
});
|
||
return false;
|
||
} finally {
|
||
this.saving = false;
|
||
}
|
||
},
|
||
|
||
// 提交申请
|
||
async submitApplication() {
|
||
if (!this.validateForm()) return;
|
||
|
||
try {
|
||
const { confirm } = await uni.showModal({
|
||
title: '确认提交',
|
||
content: '确定要提交申请吗?提交后将无法修改。',
|
||
showCancel: true
|
||
});
|
||
|
||
if (!confirm) return; // 用户取消
|
||
|
||
this.submitting = true;
|
||
|
||
// 先保存申请(不自动跳转)
|
||
const saveSuccess = await this.saveDraft(false);
|
||
|
||
if (saveSuccess) {
|
||
// 这里可以添加提交申请的逻辑
|
||
// 如果后端有单独的提交接口,可以调用
|
||
|
||
uni.showToast({
|
||
title: '提交成功',
|
||
icon: 'success'
|
||
});
|
||
|
||
setTimeout(() => {
|
||
uni.navigateBack();
|
||
}, 1000);
|
||
}
|
||
|
||
} catch (error) {
|
||
console.error('提交申请失败:', error);
|
||
uni.showToast({
|
||
title: error.message || '提交失败',
|
||
icon: 'none'
|
||
});
|
||
} finally {
|
||
this.submitting = false;
|
||
}
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
.apply-container {
|
||
min-height: 100vh;
|
||
background-color: #f5f5f5;
|
||
padding-bottom: 120rpx; /* 为底部按钮留空间 */
|
||
}
|
||
|
||
.position-card {
|
||
background-color: #fff;
|
||
margin: 20rpx;
|
||
border-radius: 12rpx;
|
||
padding: 30rpx;
|
||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.card-title {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 20rpx;
|
||
padding-bottom: 16rpx;
|
||
border-bottom: 1rpx solid #f0f0f0;
|
||
}
|
||
|
||
.position-info {
|
||
margin-top: 12rpx;
|
||
}
|
||
|
||
.position-name {
|
||
font-size: 30rpx;
|
||
font-weight: 500;
|
||
color: #1890ff;
|
||
margin-bottom: 12rpx;
|
||
}
|
||
|
||
.position-detail {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8rpx;
|
||
}
|
||
|
||
.position-detail text {
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
}
|
||
|
||
.form-container {
|
||
background-color: #fff;
|
||
margin: 20rpx;
|
||
border-radius: 12rpx;
|
||
padding: 30rpx;
|
||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.form-section {
|
||
margin-bottom: 40rpx;
|
||
}
|
||
|
||
.form-section:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 30rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 30rpx;
|
||
padding-bottom: 12rpx;
|
||
border-bottom: 2rpx solid #1890ff;
|
||
position: relative;
|
||
}
|
||
|
||
.section-title::after {
|
||
content: '';
|
||
position: absolute;
|
||
bottom: -2rpx;
|
||
left: 0;
|
||
width: 60rpx;
|
||
height: 2rpx;
|
||
background-color: #1890ff;
|
||
}
|
||
|
||
.bottom-actions {
|
||
position: fixed;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
background-color: #fff;
|
||
padding: 20rpx 30rpx;
|
||
border-top: 1rpx solid #eee;
|
||
display: flex;
|
||
z-index: 100;
|
||
}
|
||
|
||
.bottom-actions .u-button {
|
||
flex: 1;
|
||
}
|
||
|
||
/* 覆盖uview样式 */
|
||
:deep(.u-form-item) {
|
||
margin-bottom: 30rpx;
|
||
}
|
||
|
||
:deep(.u-form-item__body__left__content__label) {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
font-weight: 500;
|
||
}
|
||
|
||
:deep(.u-input__content__field-wrapper__field) {
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
:deep(.u-textarea__count) {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
</style>
|