Files
zhxg_app/pages/finance/special/apply.vue

1671 lines
43 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="special-apply">
<!-- 页面标题 -->
<!-- <view class="page-header">
<text class="title">特殊困难资助申请</text>
<text class="back" @click="goBack">&lt;</text>
</view> -->
<!-- 选项卡容器 -->
<view class="tabs-container">
<view class="tabs-header">
<view class="tab-item" :class="{ active: activeTab === 0 }" @click="switchTab(0)">
<uni-icons type="contact" size="12" :color="activeTab === 0 ? '#409EFF' : '#666'"></uni-icons>
<text class="tab-text">基本信息</text>
</view>
<view class="tab-item" :class="{ active: activeTab === 1 }" @click="switchTab(1)">
<uni-icons type="home" size="12" :color="activeTab === 1 ? '#409EFF' : '#666'"></uni-icons>
<text class="tab-text">家庭经济情况</text>
</view>
<view class="tab-item" :class="{ active: activeTab === 2 }" @click="switchTab(2)">
<uni-icons type="team" size="12" :color="activeTab === 2 ? '#409EFF' : '#666'"></uni-icons>
<text class="tab-text">家庭成员</text>
</view>
<view class="tab-item" :class="{ active: activeTab === 3 }" @click="switchTab(3)">
<uni-icons type="compose" size="12" :color="activeTab === 3 ? '#409EFF' : '#666'"></uni-icons>
<text class="tab-text">申请理由</text>
</view>
<view class="tab-item" :class="{ active: activeTab === 4 }" @click="switchTab(4)">
<uni-icons type="chat" size="12" :color="activeTab === 4 ? '#409EFF' : '#666'"></uni-icons>
<text class="tab-text">审核意见</text>
</view>
</view>
</view>
<!-- 表单内容区域 -->
<scroll-view scroll-y class="form-scroll" :style="{ height: formScrollHeight }">
<view class="form-wrapper">
<!-- 1. 基本信息标签页 -->
<view v-show="activeTab === 0" class="tab-panel">
<view class="form-card">
<view class="card-title">学生基本信息</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>学号</label>
<input v-model="formData.stuNo" placeholder="请输入学号" class="form-input" :disabled="detailMode"></input>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>姓名</label>
<input v-model="formData.stuName" placeholder="请输入姓名" class="form-input" :disabled="detailMode"></input>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>性别</label>
<picker mode="selector" :range="genderOptions" :range-key="'text'" v-model="formData.gender" @change="handleGenderChange" :disabled="detailMode">
<view class="picker-input">
{{ formData.gender ? formData.gender : '请选择性别' }}
</view>
</picker>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>民族</label>
<input v-model="formData.mz" placeholder="请输入民族" class="form-input" :disabled="detailMode"></input>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>班级</label>
<input v-model="formData.className" placeholder="请输入班级" class="form-input" :disabled="detailMode"></input>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>联系电话</label>
<input v-model="formData.stuPhone" placeholder="请输入联系电话" class="form-input" type="number" :disabled="detailMode"></input>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>身份证号</label>
<input v-model="formData.sfzh" placeholder="请输入身份证号" class="form-input" :disabled="detailMode"></input>
</view>
<view class="form-item">
<label class="form-label">曾获资助/奖励</label>
<textarea v-model="formData.helpHis" placeholder="请输入曾获资助或奖励情况" class="form-textarea" rows="3" :disabled="detailMode"></textarea>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>农行卡号</label>
<input v-model="formData.bankCard" placeholder="请输入农行卡号" class="form-input" :disabled="detailMode"></input>
</view>
</view>
</view>
<!-- 2. 家庭经济情况标签页 -->
<view v-show="activeTab === 1" class="tab-panel">
<view class="form-card">
<view class="card-title">家庭经济情况</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>家庭户口</label>
<view class="checkbox-container">
<view class="checkbox-item" @click="!detailMode && setFamilyHukou('城镇')">
<view class="custom-checkbox" :class="{ 'checkbox-checked': formData.jthk === '城镇' }">{{ formData.jthk === '城镇' ? '✓' : '' }}</view>
<text class="checkbox-text">城镇</text>
</view>
<view class="checkbox-item" @click="!detailMode && setFamilyHukou('农村')">
<view class="custom-checkbox" :class="{ 'checkbox-checked': formData.jthk === '农村' }">{{ formData.jthk === '农村' ? '✓' : '' }}</view>
<text class="checkbox-text">农村</text>
</view>
</view>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>困难程度</label>
<view class="checkbox-container">
<view class="checkbox-item" v-for="(option, index) in hardConditionOptions" :key="index" @click="!detailMode && setHardCondition(option)">
<view class="custom-checkbox" :class="{ 'checkbox-checked': formData.hardCondition === option }">{{ formData.hardCondition === option ? '✓' : '' }}</view>
<text class="checkbox-text">{{ option }}</text>
</view>
</view>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>家庭年总收入</label>
<input v-model="formData.yearMoney" placeholder="请输入家庭年总收入" class="form-input" type="number" :disabled="detailMode"></input>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>人均月收入</label>
<input v-model="formData.monthMoney" placeholder="请输入人均月收入" class="form-input" type="number" :disabled="detailMode"></input>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>收入来源</label>
<input v-model="formData.moneySource" placeholder="请输入收入来源" class="form-input" :disabled="detailMode"></input>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>家庭详细住址</label>
<input v-model="formData.familyAddr" placeholder="请输入家庭详细住址" class="form-input" :disabled="detailMode"></input>
</view>
<view class="form-item">
<label class="form-label">邮政编码</label>
<input v-model="formData.postCode" placeholder="请输入邮政编码" class="form-input" type="number" :disabled="detailMode"></input>
</view>
</view>
</view>
<!-- 3. 家庭成员标签页 -->
<view v-show="activeTab === 2" class="tab-panel">
<view class="form-card">
<view class="card-title">家庭成员情况</view>
<view class="family-list">
<view v-for="(member, index) in familyList" :key="index" class="family-item">
<view class="item-header">
<text class="item-title">家庭成员 {{ index + 1 }}</text>
<uni-icons type="close" size="20" color="#ff4d4f" @click="deleteFamilyMember(index)" class="delete-btn" v-if="!detailMode"></uni-icons>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>姓名</label>
<input v-model="member.familyName" placeholder="请输入姓名" class="form-input" :disabled="detailMode"></input>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>年龄</label>
<input v-model="member.age" placeholder="请输入年龄" class="form-input" type="number" :disabled="detailMode"></input>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>与本人关系</label>
<input v-model="member.familyRelation" placeholder="请输入与本人关系" class="form-input" :disabled="detailMode"></input>
</view>
<view class="form-item">
<label class="form-label">工作单位</label>
<input v-model="member.workPlace" placeholder="请输入工作单位" class="form-input" :disabled="detailMode"></input>
</view>
</view>
</view>
<view class="add-family-btn" @click="addFamilyMember" v-if="!detailMode">
<uni-icons type="plus" size="20" color="#409EFF"></uni-icons>
<text>新增家庭成员</text>
</view>
</view>
</view>
<!-- 4. 申请理由标签页 -->
<view v-show="activeTab === 3" class="tab-panel">
<view class="form-card">
<view class="card-title">申请理由与承诺</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>申请理由100-150</label>
<textarea placeholder="请输入申请理由" v-model="formData.applyReason" class="form-textarea" rows="4" :disabled="detailMode"></textarea>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>申请人签名</label>
<view class="sign-img" v-if="signImg">
<image :src="signImg" mode="aspectFit" style="width: 200px; height: 50px; cursor: pointer;" @click="previewImage(signImg)"></image>
<text @tap="signToggle" class="re-sign-text">重新签名</text>
</view>
<view v-else class="sign" @tap="signToggle" :class="{ 'sign-disabled': detailMode }">
点击签名
</view>
</view>
<view class="form-item">
<label class="form-label">困难佐证材料</label>
<view class="upload-btn" @click="handleUpload" :class="{ 'upload-disabled': detailMode }">
<text class="upload-icon">+</text>
<text>{{ detailMode ? '已上传佐证材料' : '上传文件' }}</text>
</view>
<view class="file-list" v-if="affixFiles.length">
<view class="file-item" v-for="(file, index) in affixFiles" :key="index">
<text class="file-name" @click="previewImage(uni.getStorageSync('baseUrl') + '/' + file.savePath)">{{ file.attachmentName || file.trueName }}</text>
<uni-icons type="trash-filled" size="30" @click="deleteFile(index)" v-if="!detailMode" class="delete-btn"></uni-icons>
</view>
</view>
<view class="upload-tip" v-if="!detailMode">支持上传jpg/png/pdf格式文件单个文件不超过10MB如病例住房证明等</view>
</view>
</view>
</view>
<!-- 5. 审核意见标签页 -->
<view v-show="activeTab === 4" class="tab-panel">
<view class="form-card">
<view class="card-title">审核意见</view>
<!-- 辅导员审核意见 -->
<view class="approval-section">
<view class="section-title">辅导员意见</view>
<view class="approval-content">
<text v-if="formData.fdyCmt" class="approval-text">{{ formData.fdyCmt }}</text>
<text v-else class="no-content">暂无审核意见</text>
</view>
<view class="approval-info">
<text v-if="formData.fdyName">审核人{{ formData.fdyName }}</text>
<text v-if="formData.fdyDate">审核时间{{ formData.fdyDate }}</text>
</view>
</view>
<!-- 学院审核意见 -->
<view class="approval-section">
<view class="section-title">二级学院意见</view>
<view class="approval-content">
<text v-if="formData.deptCmt" class="approval-text">{{ formData.deptCmt }}</text>
<text v-else class="no-content">暂无审核意见</text>
</view>
<view class="approval-info">
<text v-if="formData.xwName">审核人{{ formData.xwName }}</text>
<text v-if="formData.deptDate">审核时间{{ formData.deptDate }}</text>
</view>
</view>
<!-- 学校意见 -->
<view class="approval-section">
<view class="section-title">学校意见</view>
<view class="approval-content">
<text v-if="formData.xgCmt" class="approval-text">{{ formData.xgCmt }}</text>
<text v-else class="no-content">暂无审核意见</text>
</view>
<view class="approval-info">
<text v-if="formData.xgName">审核人{{ formData.xgName }}</text>
<text v-if="formData.xgDate">审核时间{{ formData.xgDate }}</text>
</view>
</view>
</view>
</view>
</view>
</scroll-view>
<!-- 提交按钮 -->
<view class="submit-area">
<button class="submit-btn" @click="submitApply" :disabled="detailMode">提交申请</button>
</view>
<!-- 签名组件 -->
<jp-signature-popup ref="jpSignature" :required="true" popup @change="uploadSign" />
</view>
</template>
<script>
import { addApply, updateApply, getApply, getOwnFamily, getOwnKnrd, getOwnExtraInfo, getOwnInfo, reApply } from '@/api/finance/special';
import uploadFile from "@/plugins/upload.js"
import { getUserProfile } from '@/api/system/user'
import config from '@/config'
export default {
data() {
return {
hardConditionOptions: ['特别困难', '比较困难', '一般困难', '突发困难'],
hardConditionIndex: 0,
activeTab: 0,
formScrollHeight: '600px',
detailMode: false,
applyId: '',
loading: false,
listData: null,
formData: {
stuNo: '',
stuName: '',
gender: '',
mz: '',
className: '',
stuPhone: '',
sfzh: '',
helpHis: '',
bankCard: '',
jthk: '',
hardCondition: '',
yearMoney: '',
monthMoney: '',
moneySource: '',
familyAddr: '',
postCode: '',
applyReason: '',
applySign: '',
hardFile: '',
applyDate: '',
applyStatus: '',
fdyCmt: '',
fdySign: '',
fdyDate: '',
fdyNo: '',
deptCmt: '',
deptSign: '',
deptDate: '',
deptNo: '',
xgCmt: '',
xgSign: '',
xgDate: '',
xgNo: '',
leaderCmt: '',
leaderSign: '',
leaderDate: '',
leaderNo: '',
stuYearId: '',
stuYearName: '',
deptName: '',
fdyName: '',
xwName: '',
xgName: '',
leaderName: '',
deptId: ''
},
familyList: [{
familyName: '',
age: '',
familyRelation: '',
workPlace: ''
}],
genderOptions: [
{ value: '男', text: '男' },
{ value: '女', text: '女' }
],
affixFiles: [],
signImg: '',
baseUrl: config.baseUrl || ''
};
},
onLoad(option) {
// 接收从主页面传递过来的申请ID和类型
if (option && option.id) {
this.applyId = option.id;
if (option.type === 'detail') {
this.detailMode = true;
}
// 从本地存储获取从列表页面传递的数据
const storedItem = uni.getStorageSync('specialApplyItem');
if (storedItem) {
this.listData = storedItem;
// 清除本地存储,避免数据残留
uni.removeStorageSync('specialApplyItem');
}
}
this.calculateFormHeight();
this.initData();
},
onShow() {
this.calculateFormHeight();
},
methods: {
// 计算表单滚动区域高度
calculateFormHeight() {
const systemInfo = uni.getSystemInfoSync();
const navHeight = 44; // 导航栏高度
const tabsHeight = 50; // 选项卡高度
const submitBtnHeight = 60; // 提交按钮高度
const padding = 20; // 页面内边距
this.formScrollHeight = (systemInfo.windowHeight - navHeight - tabsHeight - submitBtnHeight - padding) + 'px';
},
// 初始化数据
async initData() {
this.loading = true;
try {
if (this.applyId) {
// 如果有从列表页面传递的数据,直接使用该数据进行回显
if (this.listData) {
this.formData = this.listData;
// 处理家庭成员数据
if (this.listData.familyMemberList) {
if (typeof this.listData.familyMemberList === 'string') {
try {
this.familyList = JSON.parse(this.listData.familyMemberList);
} catch (e) {
this.familyList = [];
}
} else if (Array.isArray(this.listData.familyMemberList)) {
this.familyList = this.listData.familyMemberList;
}
}
// 处理签名图片
if (this.listData.applySign) {
this.signImg = this.baseUrl + this.listData.applySign;
} else {
this.signImg = '';
}
// 处理困难佐证材料(支持多个文件)
if (this.listData.hardFile) {
// 分割文件路径字符串
const filePaths = this.listData.hardFile.split(',');
// 构造文件信息对象数组
this.affixFiles = filePaths.map(filePath => {
// 从文件路径中提取文件名
const fileName = filePath.split('/').pop();
return {
attachmentName: fileName,
attachmentUrl: filePath,
serverUrl: filePath,
fileId: '',
fileSize: 0,
fileSuffix: fileName.split('.').pop().toLowerCase(),
savePath: filePath
};
});
} else {
this.affixFiles = [];
}
} else {
// 否则,调用接口获取申请详情
await this.getApplyDetail();
}
} else {
// 如果没有applyId获取用户基本信息
await this.getUserInfo();
// 获取用户家庭信息
await this.getFamilyInfo();
// 获取用户贫困认定信息
await this.getKnrdInfo();
}
} catch (error) {
uni.showToast({ title: '获取数据失败', icon: 'none' });
} finally {
this.loading = false;
}
},
// 获取用户基本信息
async getUserInfo() {
try {
const res = await getOwnInfo();
if (res.code === 200) {
const data = res.data;
this.formData.stuName = data.name || '';
this.formData.gender = data.gender || '';
this.formData.stuPhone = data.phone || '';
this.formData.stuNo = data.stuNo || '';
this.formData.className = data.srsClass ? data.srsClass.className : '';
this.formData.sfzh = data.idCard || '';
this.formData.bankCard = data.xhk || '';
}
// 获取用户扩展信息
const extraRes = await getOwnExtraInfo();
if (extraRes.code === 200) {
const extraData = extraRes.data;
this.formData.mz = extraData.mz || '';
this.formData.jthk = extraData.hkxz || '';
this.formData.familyAddr = extraData.xjtdz || '';
this.formData.postCode = extraData.jtyzbm || '';
}
// 获取用户签名
const userProfileRes = await getUserProfile();
if (userProfileRes.code === 200 && userProfileRes.data) {
const signature = userProfileRes.data.signature;
if (signature) {
// 设置表单签名字段
this.formData.applySign = signature;
// 构造完整的图片URL
this.signImg = this.baseUrl + signature;
}
}
} catch (error) {
console.error('获取用户信息失败:', error);
}
},
// 获取用户家庭信息
async getFamilyInfo() {
try {
const res = await getOwnFamily();
if (res.code === 200 && res.data && res.data.length > 0) {
this.familyList = res.data;
this.formData.familyMemberList = JSON.stringify(res.data);
}
} catch (error) {
console.error('获取家庭信息失败:', error);
}
},
// 获取用户贫困认定信息
async getKnrdInfo() {
try {
const res = await getOwnKnrd();
if (res.code === 200) {
const data = res.data;
// 根据贫困认定等级设置困难程度
switch (data.xsqmyj) {
case '1':
this.formData.hardCondition = '特别困难';
break;
case '2':
this.formData.hardCondition = '比较困难';
break;
case '3':
this.formData.hardCondition = '一般困难';
break;
}
}
} catch (error) {
console.error('获取贫困认定信息失败:', error);
uni.showToast({
title: '获取贫困认定信息失败,请先完成贫困认定',
icon: 'none',
duration: 2000
});
// 跳转到贫困认定列表页面
setTimeout(() => {
uni.navigateTo({
url: '/pages/finance/poverty/index'
});
}, 2000);
}
},
// 返回上一页
goBack() {
uni.navigateBack();
},
// 切换选项卡
switchTab(index) {
this.activeTab = index;
},
// 处理性别选择
handleGenderChange(e) {
this.formData.gender = this.genderOptions[e.detail.value].value;
},
// 设置家庭户口
setFamilyHukou(value) {
this.formData.jthk = value;
},
// 设置困难程度
setHardCondition(value) {
this.formData.hardCondition = value;
},
// 添加家庭成员
addFamilyMember() {
this.familyList.push({
familyName: '',
age: '',
familyRelation: '',
workPlace: ''
});
},
// 删除家庭成员
deleteFamilyMember(index) {
if (this.familyList.length > 1) {
this.familyList.splice(index, 1);
} else {
uni.showToast({
title: '至少保留一个家庭成员',
icon: 'none'
});
}
},
// 签名切换
signToggle() {
// 打开签名组件
this.$refs.jpSignature.toPop();
},
// 上传签名
uploadSign(e) {
uploadFile('/common/upload', e).then((res) => {
const data = JSON.parse(res);
this.formData.applySign = data.fileName;
this.signImg = data.url || (this.baseUrl + data.fileName);
})
},
// 处理文件上传
handleUpload() {
// 如果是详情模式,不执行上传操作
if (this.detailMode) {
return;
}
// 定义affixId生成工具函数
const generateUUID = () => {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
};
uni.chooseFile({
count: 10, // 最多选择10个文件
extension: ['.jpg', '.png', '.pdf'], // 限制文件类型
success: async (chooseRes) => {
// 初始化affixId如果为空则生成唯一ID
if (!this.formData.affixId) {
this.formData.affixId = generateUUID();
}
// 遍历选择的文件,逐个上传(支持多文件)
for (const file of chooseRes.tempFiles) {
try {
// 构造上传参数
const formDataObj = {
affixId: this.formData.affixId,
fileName: file.name,
fileSize: file.size
};
// 上传文件
const uploadRes = await uploadFile('/affix/upload', file.path, formDataObj);
const result = typeof uploadRes === 'string' ? JSON.parse(uploadRes) : uploadRes;
// 上传结果校验
if (result && result.code === 200) {
// 构造文件信息对象
const fileInfo = {
attachmentName: file.name,
attachmentUrl: result.savePath,
serverUrl: result.savePath || '',
fileId: result.id || '',
fileSize: file.size,
fileSuffix: file.name.split('.').pop().toLowerCase(),
savePath: result.savePath
};
// 去重逻辑
const isDuplicate = this.affixFiles.some(item =>
item.attachmentName === file.name && item.fileSize === file.size
);
if (!isDuplicate) {
this.affixFiles.push(fileInfo);
}
uni.showToast({
title: `文件 ${file.name} 上传成功`,
icon: 'success',
duration: 1500
});
} else {
// 上传失败处理
uni.showToast({
title: `文件 ${file.name} 上传失败:${result.message || '未知错误'}`,
icon: 'none',
duration: 2000
});
}
} catch (error) {
// 异常捕获
console.error(`文件 ${file.name} 上传异常:`, error);
uni.showToast({
title: `文件 ${file.name} 上传异常,请重试`,
icon: 'none',
duration: 2000
});
}
}
},
// 取消选择文件的处理
fail: (err) => {
console.error('选择文件失败:', err);
uni.showToast({
title: '选择文件失败,请重试',
icon: 'none'
});
}
});
},
// 删除文件
deleteFile(index) {
const deletedFile = this.affixFiles[index];
this.affixFiles.splice(index, 1);
if (this.affixFiles.length === 0) {
this.formData.affixId = null;
}
uni.showToast({
title: '删除成功',
icon: 'success'
});
},
// 预览图片
previewImage(url) {
uni.previewImage({
urls: [url]
});
},
// 获取申请详情
async getApplyDetail() {
this.loading = true;
try {
const res = await getApply(this.applyId);
if (res.code === 200) {
const data = res.data;
this.formData = data;
// 处理家庭成员数据
if (data.familyMemberList) {
if (typeof data.familyMemberList === 'string') {
try {
this.familyList = JSON.parse(data.familyMemberList);
} catch (e) {
this.familyList = [];
}
} else if (Array.isArray(data.familyMemberList)) {
this.familyList = data.familyMemberList;
}
}
// 处理签名图片
if (data.applySign) {
this.signImg = this.baseUrl + data.applySign;
} else {
this.signImg = '';
}
// 处理困难佐证材料(支持多个文件)
if (data.hardFile) {
// 分割文件路径字符串
const filePaths = data.hardFile.split(',');
// 构造文件信息对象数组
this.affixFiles = filePaths.map(filePath => {
// 从文件路径中提取文件名
const fileName = filePath.split('/').pop();
return {
attachmentName: fileName,
attachmentUrl: filePath,
serverUrl: filePath,
fileId: '',
fileSize: 0,
fileSuffix: fileName.split('.').pop().toLowerCase(),
savePath: filePath
};
});
} else {
this.affixFiles = [];
}
}
} catch (error) {
console.error('获取申请详情失败:', error);
uni.showToast({ title: '获取申请详情失败', icon: 'none' });
} finally {
this.loading = false;
}
},
// 提交申请
async submitApply() {
// 表单验证
if (!this.validateForm()) {
return;
}
// 准备提交数据
const submitData = {
...this.formData,
familyMemberList: JSON.stringify(this.familyList),
applyDate: new Date()
};
// 处理困难佐证材料,将 affixFiles 转换为 hardFile支持多个文件用逗号分隔
if (this.affixFiles.length > 0) {
// 将所有文件的路径用逗号分隔拼接成一个字符串
submitData.hardFile = this.affixFiles.map(file => file.savePath).join(',');
} else {
submitData.hardFile = '';
}
this.loading = true;
try {
let res;
if (this.applyId) {
// 根据申请状态判断调用哪个接口
if (this.formData.applyStatus == '10') {
// 重新提交申请
res = await reApply(submitData);
} else {
// 修改申请
res = await updateApply(submitData);
}
} else {
// 新增申请
res = await addApply(submitData);
}
if (res.code === 200) {
uni.showToast({ title: '提交成功', icon: 'success' });
setTimeout(() => {
this.goBack();
}, 1500);
} else {
uni.showToast({ title: res.msg || '提交失败', icon: 'none' });
}
} catch (error) {
console.error('提交申请失败:', error);
uni.showToast({ title: '提交申请失败', icon: 'none' });
} finally {
this.loading = false;
}
},
// 表单验证
validateForm() {
// 基本信息验证
if (!this.formData.stuNo) {
uni.showToast({ title: '请输入学号', icon: 'none' });
return false;
}
if (!this.formData.stuName) {
uni.showToast({ title: '请输入姓名', icon: 'none' });
return false;
}
if (!this.formData.gender) {
uni.showToast({ title: '请选择性别', icon: 'none' });
return false;
}
if (!this.formData.mz) {
uni.showToast({ title: '请输入民族', icon: 'none' });
return false;
}
if (!this.formData.className) {
uni.showToast({ title: '请输入班级', icon: 'none' });
return false;
}
if (!this.formData.stuPhone) {
uni.showToast({ title: '请输入联系电话', icon: 'none' });
return false;
}
// 电话号码格式验证
if (!/^1[3-9]\d{9}$/.test(this.formData.stuPhone)) {
uni.showToast({ title: '请输入正确的手机号码', icon: 'none' });
return false;
}
if (!this.formData.sfzh) {
uni.showToast({ title: '请输入身份证号', icon: 'none' });
return false;
}
// 身份证号格式验证
if (!/^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/.test(this.formData.sfzh)) {
uni.showToast({ title: '请输入正确的身份证号', icon: 'none' });
return false;
}
if (!this.formData.bankCard) {
uni.showToast({ title: '请输入农行卡号', icon: 'none' });
return false;
}
// 银行卡号格式验证
if (!/^\d{16,19}$/.test(this.formData.bankCard)) {
uni.showToast({ title: '请输入正确的银行卡号', icon: 'none' });
return false;
}
// 家庭经济情况验证
if (!this.formData.jthk) {
uni.showToast({ title: '请选择家庭户口', icon: 'none' });
return false;
}
if (!this.formData.hardCondition) {
uni.showToast({ title: '请选择困难程度', icon: 'none' });
return false;
}
if (!this.formData.yearMoney) {
uni.showToast({ title: '请输入家庭年总收入', icon: 'none' });
return false;
}
// 验证家庭年总收入为数字
if (!/^\d+(\.\d+)?$/.test(this.formData.yearMoney)) {
uni.showToast({ title: '请输入正确的家庭年总收入', icon: 'none' });
return false;
}
if (!this.formData.monthMoney) {
uni.showToast({ title: '请输入人均月收入', icon: 'none' });
return false;
}
// 验证人均月收入为数字
if (!/^\d+(\.\d+)?$/.test(this.formData.monthMoney)) {
uni.showToast({ title: '请输入正确的人均月收入', icon: 'none' });
return false;
}
if (!this.formData.moneySource) {
uni.showToast({ title: '请输入收入来源', icon: 'none' });
return false;
}
if (!this.formData.familyAddr) {
uni.showToast({ title: '请输入家庭详细住址', icon: 'none' });
return false;
}
// 家庭成员验证
for (let i = 0; i < this.familyList.length; i++) {
const member = this.familyList[i];
if (!member.familyName) {
uni.showToast({ title: `请输入家庭成员${i + 1}的姓名`, icon: 'none' });
return false;
}
if (!member.age) {
uni.showToast({ title: `请输入家庭成员${i + 1}的年龄`, icon: 'none' });
return false;
}
// 验证年龄为数字
if (!/^\d+$/.test(member.age)) {
uni.showToast({ title: `请输入正确的家庭成员${i + 1}年龄`, icon: 'none' });
return false;
}
if (!member.familyRelation) {
uni.showToast({ title: `请输入家庭成员${i + 1}与本人关系`, icon: 'none' });
return false;
}
}
// 申请理由验证
if (!this.formData.applyReason) {
uni.showToast({ title: '请填写申请理由', icon: 'none' });
return false;
}
if (!this.formData.applySign) {
uni.showToast({ title: '请完成手写签名', icon: 'none' });
return false;
}
if (this.affixFiles.length === 0 && !this.formData.hardFile) {
uni.showToast({ title: '请上传困难佐证材料', icon: 'none' });
return false;
}
return true;
},
// 设置困难程度
setHardCondition(condition) {
this.formData.hardCondition = condition;
}
}
};
</script>
<style lang="less" scoped>
/* 全局样式重置 */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.special-apply {
background-color: #F3F4F6;
min-height: 100vh;
padding-bottom: 30rpx;
}
/* 页面头部 */
.page-header {
background-color: #4A90E2;
color: white;
padding: 30rpx 20rpx;
display: flex;
align-items: center;
position: relative;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
.title {
font-size: 36rpx;
font-weight: bold;
margin: 0 auto;
}
.back {
font-size: 40rpx;
position: absolute;
left: 20rpx;
top: 25rpx;
cursor: pointer;
transition: all 0.3s ease;
&:hover {
transform: translateX(-5rpx);
}
}
}
/* 选项卡样式 */
.tabs-container {
background-color: #fff;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
position: sticky;
top: 0;
z-index: 100;
.tabs-header {
display: flex;
padding-bottom: 10rpx;
.tab-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
flex: 1;
padding: 20rpx 10rpx;
position: relative;
cursor: pointer;
transition: all 0.3s ease;
.tab-text {
font-size: 24rpx;
color: #666;
margin-top: 5rpx;
transition: all 0.3s ease;
text-align: center;
}
&.active {
.tab-text {
color: #409EFF;
font-weight: bold;
}
&::after {
content: '';
position: absolute;
bottom: 0;
left: 20%;
right: 20%;
height: 3rpx;
background-color: #409EFF;
border-radius: 3rpx;
animation: tabSlide 0.3s ease-in-out;
}
}
&:hover {
.tab-text {
color: #409EFF;
}
}
}
}
}
/* 表单滚动区域 */
.form-scroll {
padding: 20rpx;
.form-wrapper {
background-color: #fff;
border-radius: 10rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
animation: fadeIn 0.3s ease-in-out;
}
}
/* 标签页面板 */
.tab-panel {
padding: 20rpx;
}
/* 表单卡片 */
.form-card {
margin-bottom: 20rpx;
.card-title {
font-size: 28rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
padding-bottom: 10rpx;
border-bottom: 1rpx solid #E0E0E0;
}
}
/* 表单项目 */
.form-item {
margin-bottom: 25rpx;
.form-label {
font-size: 26rpx;
color: #333;
margin-bottom: 10rpx;
display: block;
.red-tip {
color: #FF4D4F;
margin-right: 5rpx;
}
}
.form-input {
width: 100%;
height: 70rpx;
padding: 0 20rpx;
border: 1rpx solid #E0E0E0;
border-radius: 8rpx;
font-size: 26rpx;
background-color: #F9F9F9;
transition: all 0.3s ease;
&:focus {
outline: none;
border-color: #409EFF;
box-shadow: 0 0 0 2rpx rgba(64, 158, 255, 0.1);
background-color: #fff;
}
}
.form-textarea {
width: 100%;
min-height: 150rpx;
padding: 15rpx;
border: 1rpx solid #E0E0E0;
border-radius: 8rpx;
font-size: 26rpx;
background-color: #F9F9F9;
resize: none;
transition: all 0.3s ease;
&:focus {
outline: none;
border-color: #409EFF;
box-shadow: 0 0 0 2rpx rgba(64, 158, 255, 0.1);
background-color: #fff;
}
}
.picker-input {
width: 100%;
height: 70rpx;
padding: 0 20rpx;
border: 1rpx solid #E0E0E0;
border-radius: 8rpx;
font-size: 26rpx;
background-color: #F9F9F9;
display: flex;
align-items: center;
color: #666;
transition: all 0.3s ease;
&:hover {
border-color: #409EFF;
background-color: #fff;
}
}
.value {
font-size: 26rpx;
color: #666;
padding: 15rpx 20rpx;
background-color: #F9F9F9;
border-radius: 8rpx;
}
}
/* 复选框容器 */
.checkbox-container {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
.checkbox-item {
display: flex;
align-items: center;
cursor: pointer;
transition: all 0.3s ease;
&:hover {
transform: translateY(-2rpx);
}
.custom-checkbox {
width: 30rpx;
height: 30rpx;
border: 1rpx solid #D9D9D9;
border-radius: 50%;
margin-right: 10rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 20rpx;
color: #fff;
transition: all 0.3s ease;
&.checkbox-checked {
background-color: #409EFF;
border-color: #409EFF;
animation: checkboxScale 0.3s ease-in-out;
}
}
.checkbox-text {
font-size: 26rpx;
color: #666;
}
}
}
/* 单选框容器 */
.radio-container {
display: flex;
gap: 40rpx;
flex-wrap: wrap;
.radio-item {
display: flex;
align-items: center;
cursor: pointer;
transition: all 0.3s ease;
&:hover {
transform: translateY(-2rpx);
}
.custom-radio {
width: 30rpx;
height: 30rpx;
border: 1rpx solid #D9D9D9;
border-radius: 50%;
margin-right: 10rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 20rpx;
color: #fff;
transition: all 0.3s ease;
&.radio-checked {
background-color: #409EFF;
border-color: #409EFF;
animation: radioScale 0.3s ease-in-out;
}
}
.radio-text {
font-size: 26rpx;
color: #666;
}
}
}
/* 家庭成员列表 */
.family-list {
margin-bottom: 20rpx;
.family-item {
padding: 20rpx;
background-color: #F9F9F9;
border-radius: 10rpx;
margin-bottom: 20rpx;
transition: all 0.3s ease;
box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.05);
&:hover {
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
}
.item-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
.item-title {
font-size: 26rpx;
font-weight: bold;
color: #333;
}
.delete-btn {
cursor: pointer;
transition: all 0.3s ease;
&:hover {
color: #FF4D4F;
transform: scale(1.1);
}
}
}
}
}
/* 添加家庭成员按钮 */
.add-family-btn {
display: flex;
align-items: center;
justify-content: center;
padding: 20rpx;
border: 1rpx dashed #D9D9D9;
border-radius: 10rpx;
cursor: pointer;
color: #409EFF;
transition: all 0.3s ease;
&:hover {
border-color: #409EFF;
background-color: rgba(64, 158, 255, 0.05);
transform: translateY(-2rpx);
}
text {
margin-left: 10rpx;
font-size: 26rpx;
}
}
/* 承诺内容 */
.promise-content {
padding: 20rpx;
background-color: #F9F9F9;
border-radius: 10rpx;
margin-bottom: 20rpx;
text {
font-size: 24rpx;
color: #666;
line-height: 1.5;
}
}
/* 签名区域 */
.sign {
width: 200px;
height: 100px;
border: 1rpx solid #D9D9D9;
border-radius: 8rpx;
display: flex;
align-items: center;
justify-content: center;
color: #999;
cursor: pointer;
background-color: #F9F9F9;
transition: all 0.3s ease;
&:hover {
border-color: #409EFF;
background-color: #fff;
}
&.sign-disabled {
cursor: not-allowed;
opacity: 0.6;
&:hover {
border-color: #D9D9D9;
background-color: #F9F9F9;
}
}
}
.sign-img {
position: relative;
.re-sign-text {
position: absolute;
top: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.6);
color: #fff;
padding: 5rpx 10rpx;
font-size: 20rpx;
border-radius: 0 8rpx 0 8rpx;
cursor: pointer;
transition: all 0.3s ease;
&:hover {
background-color: rgba(64, 158, 255, 0.8);
transform: translateY(-2rpx);
}
}
}
/* 文件上传 */
.upload-btn {
width: 100%;
height: 100rpx;
border: 1rpx dashed #D9D9D9;
border-radius: 10rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
background-color: #F9F9F9;
transition: all 0.3s ease;
&:hover {
border-color: #409EFF;
background-color: rgba(64, 158, 255, 0.05);
transform: translateY(-2rpx);
}
.upload-icon {
font-size: 40rpx;
color: #999;
margin-bottom: 10rpx;
transition: all 0.3s ease;
}
text {
font-size: 24rpx;
color: #999;
transition: all 0.3s ease;
}
&:hover {
.upload-icon {
color: #409EFF;
}
text {
color: #409EFF;
}
}
&.upload-disabled {
cursor: not-allowed;
opacity: 0.6;
&:hover {
border-color: #D9D9D9;
background-color: #F9F9F9;
transform: none;
.upload-icon {
color: #999;
}
text {
color: #999;
}
}
}
}
.file-list {
margin-top: 20rpx;
.file-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15rpx;
background-color: #F9F9F9;
border-radius: 8rpx;
margin-bottom: 10rpx;
transition: all 0.3s ease;
&:hover {
background-color: #F0F0F0;
transform: translateX(5rpx);
}
.file-name {
font-size: 24rpx;
color: #666;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
transition: all 0.3s ease;
&:hover {
color: #409EFF;
}
}
.delete-btn {
cursor: pointer;
transition: all 0.3s ease;
&:hover {
color: #FF4D4F;
transform: scale(1.1);
}
}
}
}
.upload-tip {
font-size: 22rpx;
color: #999;
margin-top: 10rpx;
line-height: 1.4;
}
/* 审核意见区域 */
.approval-section {
margin-bottom: 30rpx;
.section-title {
font-size: 26rpx;
font-weight: bold;
color: #333;
margin-bottom: 15rpx;
}
.approval-content {
padding: 20rpx;
background-color: #F9F9F9;
border-radius: 10rpx;
margin-bottom: 10rpx;
transition: all 0.3s ease;
&:hover {
background-color: #F0F0F0;
}
.approval-text {
font-size: 24rpx;
color: #666;
line-height: 1.5;
}
.no-content {
font-size: 24rpx;
color: #999;
}
}
.approval-info {
display: flex;
justify-content: space-between;
font-size: 22rpx;
color: #999;
padding: 0 20rpx;
}
}
/* 提交按钮区域 */
.submit-area {
margin: 20rpx;
.submit-btn {
width: 100%;
height: 80rpx;
background-color: #4A90E2;
color: white;
font-size: 32rpx;
border-radius: 40rpx;
border: none;
outline: none;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4rpx 8rpx rgba(74, 144, 226, 0.3);
&:hover {
background-color: #3A80D2;
transform: translateY(-2rpx);
box-shadow: 0 6rpx 12rpx rgba(74, 144, 226, 0.4);
}
&:active {
transform: translateY(0);
}
&:disabled {
background-color: #C0C4CC;
cursor: not-allowed;
box-shadow: none;
&:hover {
background-color: #C0C4CC;
transform: none;
box-shadow: none;
}
}
}
}
/* 动画效果 */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20rpx);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes tabSlide {
from {
width: 0;
left: 50%;
right: 50%;
}
to {
width: auto;
left: 15rpx;
right: 15rpx;
}
}
@keyframes checkboxScale {
0% {
transform: scale(1);
}
50% {
transform: scale(1.2);
}
100% {
transform: scale(1);
}
}
@keyframes radioScale {
0% {
transform: scale(1);
}
50% {
transform: scale(1.2);
}
100% {
transform: scale(1);
}
}
/* 响应式设计 */
@media screen and (max-width: 375px) {
.page-header {
padding: 25rpx 15rpx;
.title {
font-size: 32rpx;
}
.back {
font-size: 36rpx;
}
}
.form-scroll {
padding: 15rpx;
}
.tab-panel {
padding: 15rpx;
}
.form-item {
margin-bottom: 20rpx;
.form-label {
font-size: 24rpx;
}
.form-input {
height: 65rpx;
font-size: 24rpx;
}
.form-textarea {
font-size: 24rpx;
}
.picker-input {
height: 65rpx;
font-size: 24rpx;
}
.value {
font-size: 24rpx;
}
}
.submit-area {
margin: 15rpx;
.submit-btn {
height: 75rpx;
font-size: 28rpx;
}
}
.sign {
width: 180px;
height: 90px;
}
}
</style>