Files
zhxg_app/pages/finance/knzzZzq/apply.vue
2026-03-11 11:18:05 +08:00

1498 lines
57 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="knzz-zzq-apply">
<!-- 选项卡容器 -->
<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="compose" 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="chat" 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="document" size="12" :color="activeTab === 3 ? '#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="type === 'detail'"></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="type === 'detail'"></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="type === 'detail'">
<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.birthMonth" placeholder="请输入出生年月" class="form-input" :disabled="type === 'detail'"></input>
</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="type === 'detail'"></input>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>政治面貌</label>
<input v-model="formData.zzmm" placeholder="请输入政治面貌" class="form-input" :disabled="type === 'detail'"></input>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>学院</label>
<input v-model="formData.deptName" placeholder="请输入学院" class="form-input" :disabled="type === 'detail'"></input>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>专业</label>
<input v-model="formData.majorName" placeholder="请输入专业" class="form-input" :disabled="type === 'detail'"></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="type === 'detail'"></input>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>所在年级</label>
<input v-model="formData.gradeName" placeholder="请输入所在年级" class="form-input" :disabled="type === 'detail'"></input>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>入学时间</label>
<input v-model="formData.inTime" placeholder="请输入入学时间" class="form-input" :disabled="type === 'detail'"></input>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>身份证号码</label>
<input v-model="formData.idCard" placeholder="请输入身份证号码" class="form-input" :disabled="type === 'detail'"></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" :disabled="type === 'detail'"></input>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>曾获何种奖励</label>
<textarea v-model="formData.helpHis" placeholder="请输入曾获何种奖励" class="form-textarea" :disabled="type === 'detail'"></textarea>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>证件照</label>
<!-- 编辑模式显示上传组件 -->
<view class="example-body" v-if="type !== 'detail'">
<uni-file-picker
@select="handlePhotoUpload"
@delete="deletePhoto"
:auto-upload="false"
limit="1"
:disabled="type === 'detail'"
mode="grid"
:value="filePickerValue"
></uni-file-picker>
</view>
<view class="upload-tip" v-if="type !== 'detail'">支持上传jpg/png格式照片单个文件不超过5MB</view>
<!-- 详情模式显示照片预览 -->
<view class="photo-preview-container" v-if="formData.pic && type === 'detail'">
<image :src="getFullImageUrl(formData.pic)" mode="aspectFill"></image>
</view>
</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="rank-container">
<input v-model="formData.majorRank" placeholder="名次" class="rank-input" :disabled="type === 'detail'" type="number"></input>
<span class="rank-separator">/</span>
<input v-model="formData.majorNum" placeholder="总人数" class="rank-input" :disabled="type === 'detail'" type="number"></input>
</view>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>实行综合考评排名</label>
<view class="radio-container">
<view class="radio-item" @click="setIsCph('是')" :class="{ active: formData.isCph === '是' }">
<view class="radio-circle"></view>
<span class="radio-text"></span>
</view>
<view class="radio-item" @click="setIsCph('否')" :class="{ active: formData.isCph === '否' }">
<view class="radio-circle"></view>
<span class="radio-text"></span>
</view>
</view>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>必修课</label>
<view class="course-container">
<input v-model="formData.bxk" placeholder="门数" class="course-input" :disabled="type === 'detail'" type="number"></input>
<span class="course-text">其中及格以上</span>
<input v-model="formData.jg" placeholder="门数" class="course-input" :disabled="type === 'detail'" type="number"></input>
<span class="course-text"></span>
</view>
</view>
<view class="form-item" v-if="formData.isCph === '是'">
<label class="form-label"><span class="red-tip">*</span>如是排名班级</label>
<view class="rank-container">
<input v-model="formData.classRank" placeholder="名次" class="rank-input" :disabled="type === 'detail'" type="number"></input>
<span class="rank-separator">/</span>
<input v-model="formData.classNum" placeholder="总人数" class="rank-input" :disabled="type === 'detail'" type="number"></input>
</view>
</view>
</view>
</view>
<!-- 3. 申请理由标签页 -->
<view v-show="activeTab === 2" 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 v-model="formData.applyReason" placeholder="请输入申请理由" class="form-textarea" :disabled="type === 'detail'"></textarea>
<view class="word-count">{{ formData.applyReason.length }}/150</view>
</view>
<view class="form-item">
<label class="form-label"><span class="red-tip">*</span>证明材料</label>
<view class="upload-container">
<view class="upload-btn" @click="handleHardFileUpload" :class="{ 'upload-disabled': type === 'detail' }">
<text class="upload-icon">+</text>
<text>{{ type === 'detail' ? '已上传证明材料' : '上传文件' }}</text>
</view>
<view class="file-list" v-if="hardFiles.length">
<view class="file-item" v-for="(file, index) in hardFiles" :key="index">
<text class="file-name" @click="previewFile(file.url)">{{ file.name }}</text>
<uni-icons type="trash-filled" size="30" @click="deleteHardFile(index)" v-if="type !== 'detail'" class="delete-btn"></uni-icons>
</view>
</view>
<view class="upload-tip">请上传 大小不超过 10MB 格式为 doc/docx/xls/ppt/txt/pdf/xlsx 的文件</view>
</view>
</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;"></image>
<text @tap="signToggle" class="re-sign-text">重新签名</text>
</view>
<view v-else class="sign" @tap="signToggle" :class="{ 'sign-disabled': type === 'detail' }">
点击签名
</view>
</view>
</view>
</view>
<!-- 4. 审核意见标签页 -->
<view v-show="activeTab === 3" 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>
<!-- 签名组件 -->
<jp-signature-popup ref="jpSignature" :required="true" popup @change="uploadSign" />
<!-- 提交按钮 -->
<view class="submit-container" v-if="type !== 'detail'">
<button class="submit-btn" @click="submitForm">{{ isReApply ? '重新提交' : '提交申请' }}</button>
</view>
</view>
</template>
<script>
import { getDetail, doApply, doEdit, doReApply, getOwnInfo, getOwnExtraInfo, getYearByTag } from '@/api/finance/knzzZzq';
import { getOwnSign } from '@/api/workStudy/post';
import uploadFile from "@/plugins/upload.js";
import config from "@/config.js";
export default {
name: "KnzzZzqApply",
data() {
return {
// 表单数据
formData: {
id: '',
stuNo: '',
stuName: '',
gender: '',
birthMonth: '',
mz: '',
zzmm: '',
inTime: '',
gradeName: '',
idCard: '',
stuPhone: '',
deptName: '',
majorName: '',
className: '',
pic: '',
helpHis: '',
majorRank: '',
majorNum: '',
isCph: '',
bxk: '',
jg: '',
classRank: '',
classNum: '',
applyReason: '',
applySign: '',
applyFile: '',
applyDate: '',
fdyCmt: '',
fdyDate: '',
fdyName: '',
deptCmt: '',
deptDate: '',
xwName: '',
xgCmt: '',
xgDate: '',
xgName: '',
leaderCmt: '',
leaderDate: '',
leaderName: ''
},
// 签名图片
signImg: '',
// 基础URL
baseUrl: config.baseUrl || '',
// 选项卡状态
activeTab: 0,
// 表单滚动高度
formScrollHeight: '',
// 类型detail 查看edit 编辑add 新增
type: 'add',
// 是否重新提交
isReApply: false,
// 性别选项
genderOptions: [
{ value: '男', text: '男' },
{ value: '女', text: '女' }
],
// 证件照文件列表
photoFiles: [],
// 证明材料文件列表
hardFiles: []
};
},
onLoad(option) {
const id = option.id;
this.type = option.type || 'add';
this.isReApply = option.isReApply === 'true';
if (id) {
this.formData.id = id;
this.getDetail(id);
} else {
this.initData();
}
this.calculateFormHeight();
},
onShow() {
this.calculateFormHeight();
},
onResize() {
this.calculateFormHeight();
},
computed: {
filePickerValue() {
if (this.formData.pic) {
return [{
url: this.getFullImageUrl(this.formData.pic),
name: '证件照',
size: 0
}];
}
return [];
}
},
methods: {
// 计算表单高度
calculateFormHeight() {
const windowHeight = uni.getSystemInfoSync().windowHeight;
const tabsHeight = 80;
const submitHeight = this.type !== 'detail' ? 100 : 0;
this.formScrollHeight = `${windowHeight - tabsHeight - submitHeight}px`;
},
// 切换选项卡
switchTab(index) {
this.activeTab = index;
},
// 处理性别选择
handleGenderChange(e) {
const index = e.detail.value;
this.formData.gender = this.genderOptions[index].value;
},
// 初始化数据
async initData() {
try {
// 获取学年信息
await this.fetchYearData();
// 并行请求所有基础信息
const [infoRes, signRes] = await Promise.all([
getOwnInfo(),
getOwnSign()
]);
const infoData = infoRes.data || {};
// 填充基本信息
this.formData.stuNo = infoData.stuNo || infoData.userName || '';
this.formData.stuName = infoData.name || '';
this.formData.gender = infoData.gender || '';
this.formData.deptName = infoData.dept?.deptName || '';
this.formData.majorName = infoData.srsMajors?.majorName || infoData.major?.majorName || '';
this.formData.className = infoData.srsClass?.className || infoData.className || '';
this.formData.gradeName = infoData.gradeName || '';
this.formData.stuPhone = infoData.phone || infoData.mobile || '';
this.formData.idCard = infoData.idCard || '';
// 处理出生年月
if (infoData.birthday) {
const date = new Date(infoData.birthday);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
this.formData.birthMonth = `${year}${month}`;
}
// 处理签名信息
if (signRes && signRes.data) {
this.formData.applySign = signRes.data;
this.signImg = this.baseUrl + signRes.data;
}
// 获取个人扩展信息
const extraRes = await getOwnExtraInfo();
const extraData = extraRes.data || {};
// 填充扩展信息
this.formData.mz = extraData.mz || '';
this.formData.zzmm = extraData.zzmm || '';
// 处理证件照
if (extraData.whitePhoto) {
this.formData.pic = extraData.whitePhoto;
// 从文件路径中提取文件名
const fileName = extraData.whitePhoto.split('/').pop();
// 构造完整的URL
const fullUrl = this.baseUrl + extraData.whitePhoto;
// 更新 photoFiles 数组,使 uni-file-picker 组件显示已有的证件照
this.photoFiles = [{
name: fileName,
path: extraData.whitePhoto,
url: fullUrl
}];
}
} catch (error) {
console.error('获取数据失败:', error);
uni.showToast({
title: '获取数据失败',
icon: 'none'
});
}
},
// 获取学年信息
async fetchYearData() {
try {
const response = await getYearByTag('RMZF');
this.leaderList = response.data || [];
} catch (error) {
console.error('获取学年信息失败:', error);
}
},
// 获取详情
async getDetail(id) {
try {
const response = await getDetail(id);
const data = response.data || {};
// 填充表单数据
this.formData = {
...this.formData,
...data
};
// 处理证件照
if (data.pic) {
// 从文件路径中提取文件名
const fileName = data.pic.split('/').pop();
// 构造完整的URL
const fullUrl = this.getFullImageUrl(data.pic);
// 更新 photoFiles 数组,使编辑模式下能够预览图片
this.photoFiles = [{
name: fileName,
path: data.pic,
url: fullUrl
}];
console.log('处理证件照formData.pic:', this.formData.pic);
console.log('fullUrl:', fullUrl);
console.log('photoFiles:', this.photoFiles);
}
// 处理证明材料
if (data.applyFile) {
const filePaths = data.applyFile.split(',');
this.hardFiles = filePaths.map(filePath => {
const fileName = filePath.split('/').pop();
return {
name: fileName,
path: filePath,
url: filePath
};
});
}
// 处理签名图片
if (data.applySign) {
this.formData.applySign = data.applySign;
this.signImg = this.baseUrl + data.applySign;
} else {
this.signImg = '';
}
} catch (error) {
console.error('获取详情失败:', error);
uni.showToast({
title: '获取详情失败',
icon: 'none'
});
}
},
// 处理证件照上传
handlePhotoUpload(e) {
// 如果是详情模式,不执行上传操作
if (this.type === 'detail') {
return;
}
const tempFiles = e.tempFilePaths || [];
// 遍历选择的文件,逐个上传
for (const file of e.tempFiles) {
this.uploadFile(file);
}
},
// 上传文件的通用方法
async uploadFile(file) {
try {
// 检查文件大小5MB = 5 * 1024 * 1024 bytes
if (file.size > 5 * 1024 * 1024) {
uni.showToast({
title: `文件 ${file.name} 大小超过5MB请重新选择`,
icon: 'none'
});
return;
}
// 检查文件格式
const ext = file.name.split('.').pop().toLowerCase();
const allowedExts = ['jpg', 'jpeg', 'png'];
if (!allowedExts.includes(ext)) {
uni.showToast({
title: `文件 ${file.name} 格式不支持,请选择 JPG、PNG 格式的文件`,
icon: 'none'
});
return;
}
// 上传文件
const uploadRes = await uploadFile('/common/upload', file.path);
const result = typeof uploadRes === 'string' ? JSON.parse(uploadRes) : uploadRes;
// 上传结果校验
if (result && (result.code === 200 || !result.code)) {
// 构造文件信息对象
const fileUrl = result.savePath || result.fileName;
const fullUrl = this.getFullImageUrl(fileUrl);
const fileInfo = {
name: file.name,
path: fileUrl,
url: fullUrl
};
// 更新 formData.pic
this.formData.pic = fileUrl;
// 更新 photoFiles 数组,确保 uni-file-picker 组件能获取预览路径
this.photoFiles = [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} 上传异常:${error.message || '请检查网络连接'}`,
icon: 'none',
duration: 2000
});
}
},
// 删除证件照
deletePhoto() {
this.formData.pic = '';
this.photoFiles = [];
uni.showToast({
title: '删除成功',
icon: 'success'
});
},
// 获取完整图片URL
getFullImageUrl(path) {
if (!path) return '';
// 调试信息
console.log('getFullImageUrl调用path:', path);
// 如果已经是完整URL则直接返回
if (path.startsWith('http://') || path.startsWith('https://')) {
return path;
}
// 使用配置文件中的baseUrl
const currentBaseUrl = config.baseUrl || '';
console.log('当前baseUrl:', currentBaseUrl);
// 处理baseUrl确保结尾没有斜杠
const baseUrlClean = currentBaseUrl.replace(/\/$/, '');
// 处理path确保开头没有斜杠
const pathClean = path.replace(/^\//, '');
// 拼接URL
const fullUrl = `${baseUrlClean}/${pathClean}`;
console.log('拼接后的完整URL:', fullUrl);
return fullUrl;
},
// 预览证件照
previewPhoto() {
if (this.photoFiles.length > 0) {
uni.previewImage({
urls: [this.photoFiles[0].url]
});
}
},
// 处理证明材料上传
handleHardFileUpload() {
// 如果是详情模式,不执行上传操作
if (this.type === 'detail') {
return;
}
uni.chooseFile({
count: 5 - this.hardFiles.length, // 最多选择剩余的文件数
extension: ['doc', 'docx', 'xls', 'ppt', 'txt', 'pdf', 'xlsx'], // 限制文件类型
success: async (chooseRes) => {
// 遍历选择的文件,逐个上传
for (const file of chooseRes.tempFiles) {
try {
// 检查文件大小10MB = 10 * 1024 * 1024 bytes
if (file.size > 10 * 1024 * 1024) {
uni.showToast({
title: `文件 ${file.name} 大小超过10MB请重新选择`,
icon: 'none'
});
continue;
}
// 检查文件格式
const ext = file.name.split('.').pop().toLowerCase();
const allowedExts = ['doc', 'docx', 'xls', 'ppt', 'txt', 'pdf', 'xlsx'];
if (!allowedExts.includes(ext)) {
uni.showToast({
title: `文件 ${file.name} 格式不支持,请选择 doc/docx/xls/ppt/txt/pdf/xlsx 格式的文件`,
icon: 'none'
});
continue;
}
// 上传文件
const uploadRes = await uploadFile('/common/upload', file.path);
const result = typeof uploadRes === 'string' ? JSON.parse(uploadRes) : uploadRes;
// 上传结果校验
if (result && (result.code === 200 || !result.code)) {
// 构造文件信息对象
const fileInfo = {
name: file.name,
path: result.savePath || result.fileName,
url: result.savePath || result.fileName
};
// 去重逻辑
const isDuplicate = this.hardFiles.some(item =>
item.name === file.name && item.url === fileInfo.url
);
if (!isDuplicate) {
this.hardFiles.push(fileInfo);
}
// 更新 formData.applyFile
this.formData.applyFile = this.hardFiles.map(file => file.url).join(',');
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} 上传异常:${error.message || '请检查网络连接'}`,
icon: 'none',
duration: 2000
});
}
}
},
// 取消选择文件的处理
fail: (err) => {
console.error('选择文件失败:', err);
uni.showToast({
title: '选择文件失败,请重试',
icon: 'none'
});
}
});
},
// 删除证明材料
deleteHardFile(index) {
this.hardFiles.splice(index, 1);
// 更新 formData.applyFile
this.formData.applyFile = this.hardFiles.map(file => file.url).join(',');
uni.showToast({
title: '删除成功',
icon: 'success'
});
},
// 预览文件
previewFile(url) {
uni.showToast({
title: '正在预览文件',
icon: 'none'
});
// 这里可以添加文件预览逻辑,根据文件类型选择不同的预览方式
// 例如,对于图片可以使用 uni.previewImage对于PDF可以使用web-view等
},
// 签名切换
signToggle() {
if (this.$refs.jpSignature) {
this.$refs.jpSignature.toPop();
}
},
// 上传签名
async uploadSign(data) {
if (data) {
try {
// 上传签名图片到后端
const uploadRes = await uploadFile('/common/upload', data);
const result = typeof uploadRes === 'string' ? JSON.parse(uploadRes) : uploadRes;
if (result && (result.code === 200 || !result.code)) {
this.formData.applySign = result.fileName || result.savePath;
this.signImg = result.url || (this.baseUrl + (result.fileName || result.savePath));
} else {
uni.showToast({
title: '签名上传失败,请重试',
icon: 'none'
});
}
} catch (error) {
console.error('签名上传失败:', error);
uni.showToast({
title: `签名上传失败:${error.message || '请检查网络连接'}`,
icon: 'none'
});
}
}
},
// 设置是否实行综合考评排名
setIsCph(value) {
this.formData.isCph = value;
},
// 表单验证
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.birthMonth) {
uni.showToast({ title: '请输入出生年月', icon: 'none' });
return false;
}
if (!this.formData.mz) {
uni.showToast({ title: '请输入民族', icon: 'none' });
return false;
}
if (!this.formData.zzmm) {
uni.showToast({ title: '请输入政治面貌', icon: 'none' });
return false;
}
if (!this.formData.deptName) {
uni.showToast({ title: '请输入学院', icon: 'none' });
return false;
}
if (!this.formData.majorName) {
uni.showToast({ title: '请输入专业', icon: 'none' });
return false;
}
if (!this.formData.className) {
uni.showToast({ title: '请输入班级', icon: 'none' });
return false;
}
if (!this.formData.gradeName) {
uni.showToast({ title: '请输入所在年级', icon: 'none' });
return false;
}
if (!this.formData.inTime) {
uni.showToast({ title: '请输入入学时间', icon: 'none' });
return false;
}
if (!this.formData.idCard) {
uni.showToast({ title: '请输入身份证号码', icon: 'none' });
return false;
}
if (!this.formData.stuPhone) {
uni.showToast({ title: '请输入联系电话', icon: 'none' });
return false;
}
if (!this.formData.helpHis) {
uni.showToast({ title: '请输入曾获何种奖励', icon: 'none' });
return false;
}
if (!this.formData.pic) {
uni.showToast({ title: '请上传证件照', icon: 'none' });
return false;
}
// 学习情况验证
if (!this.formData.majorRank) {
uni.showToast({ title: '请输入专业排名', icon: 'none' });
return false;
}
if (!this.formData.majorNum) {
uni.showToast({ title: '请输入专业总人数', icon: 'none' });
return false;
}
if (!this.formData.isCph) {
uni.showToast({ title: '请选择是否实行综合考评排名', icon: 'none' });
return false;
}
if (!this.formData.bxk) {
uni.showToast({ title: '请输入必修课门数', icon: 'none' });
return false;
}
if (!this.formData.jg) {
uni.showToast({ title: '请输入及格门数', icon: 'none' });
return false;
}
if (this.formData.isCph === '是') {
if (!this.formData.classRank) {
uni.showToast({ title: '请输入班级排名', icon: 'none' });
return false;
}
if (!this.formData.classNum) {
uni.showToast({ title: '请输入班级总人数', icon: 'none' });
return false;
}
}
// 申请理由验证
if (!this.formData.applyReason) {
uni.showToast({ title: '请输入申请理由', icon: 'none' });
return false;
}
if (this.formData.applyReason.length < 100 || this.formData.applyReason.length > 150) {
uni.showToast({ title: '申请理由必须为100-150字', icon: 'none' });
return false;
}
if (!this.formData.applyFile) {
uni.showToast({ title: '请上传证明材料', icon: 'none' });
return false;
}
if (!this.formData.applySign) {
uni.showToast({ title: '请上传申请人签名', icon: 'none' });
return false;
}
return true;
},
// 提交表单
async submitForm() {
if (!this.validateForm()) {
return;
}
const submitData = { ...this.formData };
// 设置申请日期
submitData.applyDate = new Date();
try {
let res;
if (this.formData.id) {
if (this.isReApply) {
// 重新提交
res = await doReApply(submitData);
} else {
// 修改
res = await doEdit(submitData);
}
} else {
// 提交申请
res = await doApply(submitData);
}
if (res.code === 200 || res.code === 0) {
uni.showToast({
title: this.isReApply ? '重新提交成功' : (this.formData.id ? '修改成功' : '提交成功'),
icon: 'success'
});
setTimeout(() => {
uni.navigateBack();
}, 1500);
} else {
uni.showToast({
title: res.msg || '操作失败',
icon: 'none'
});
}
} catch (error) {
console.error('操作失败:', error);
uni.showToast({
title: '操作失败',
icon: 'none'
});
}
}
}
};
</script>
<style scoped>
.knzz-zzq-apply {
background-color: #F3F4F6;
min-height: 100vh;
}
.tabs-container {
background-color: white;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
}
.tabs-header {
display: flex;
justify-content: space-around;
align-items: center;
padding: 20rpx 0;
position: relative;
}
.tabs-header::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 1rpx;
background-color: #f0f0f0;
}
.tab-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 10rpx 20rpx;
position: relative;
cursor: pointer;
transition: all 0.3s ease;
}
.tab-item.active {
color: #409EFF;
}
.tab-item.active::after {
content: '';
position: absolute;
bottom: -1rpx;
left: 10%;
width: 80%;
height: 4rpx;
background-color: #409EFF;
border-radius: 2rpx;
}
.tab-text {
font-size: 26rpx;
margin-top: 5rpx;
}
.form-scroll {
width: 100%;
overflow-y: auto;
}
.form-wrapper {
padding: 20rpx;
}
.form-card {
background-color: white;
border-radius: 10rpx;
padding: 20rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
}
.card-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
padding-bottom: 10rpx;
border-bottom: 1rpx solid #f0f0f0;
}
.form-item {
margin-bottom: 20rpx;
}
.form-label {
display: block;
font-size: 28rpx;
color: #666;
margin-bottom: 10rpx;
}
.red-tip {
color: #f56c6c;
margin-right: 5rpx;
}
.form-input {
width: 100%;
height: 80rpx;
border: 1rpx solid #dcdfe6;
border-radius: 5rpx;
padding: 0 20rpx;
font-size: 28rpx;
color: #333;
background-color: #fafafa;
}
.form-input:disabled {
background-color: #f5f7fa;
color: #c0c4cc;
}
.picker-input {
width: 100%;
height: 80rpx;
border: 1rpx solid #dcdfe6;
border-radius: 5rpx;
padding: 0 20rpx;
font-size: 28rpx;
color: #333;
background-color: #fafafa;
display: flex;
align-items: center;
}
.form-textarea {
width: 100%;
min-height: 200rpx;
border: 1rpx solid #dcdfe6;
border-radius: 5rpx;
padding: 20rpx;
font-size: 28rpx;
color: #333;
background-color: #fafafa;
resize: none;
}
.form-textarea:disabled {
background-color: #f5f7fa;
color: #c0c4cc;
}
.upload-container {
margin-top: 10rpx;
}
.upload-tip {
font-size: 24rpx;
color: #909399;
margin-top: 10rpx;
}
.sign {
width: 200px;
height: 50px;
border: 1rpx solid #dcdfe6;
border-radius: 10rpx;
display: flex;
align-items: center;
justify-content: center;
background-color: #fafafa;
cursor: pointer;
font-size: 24rpx;
color: #606266;
}
.sign-disabled {
opacity: 0.6;
cursor: not-allowed;
}
.sign-img {
display: flex;
flex-direction: column;
align-items: flex-start;
}
.re-sign-text {
margin-top: 10rpx;
font-size: 24rpx;
color: #409EFF;
cursor: pointer;
}
/* 排名输入容器 */
.rank-container {
display: flex;
align-items: center;
gap: 10rpx;
}
.rank-input {
flex: 1;
height: 80rpx;
border: 1rpx solid #dcdfe6;
border-radius: 5rpx;
padding: 0 20rpx;
font-size: 28rpx;
color: #333;
background-color: #fafafa;
}
.rank-separator {
font-size: 28rpx;
color: #666;
}
/* 课程输入容器 */
.course-container {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 10rpx;
}
.course-input {
width: 120rpx;
height: 80rpx;
border: 1rpx solid #dcdfe6;
border-radius: 5rpx;
padding: 0 20rpx;
font-size: 28rpx;
color: #333;
background-color: #fafafa;
}
.course-text {
font-size: 28rpx;
color: #666;
}
/* 单选框容器 */
.radio-container {
display: flex;
gap: 40rpx;
}
.radio-item {
display: flex;
align-items: center;
gap: 10rpx;
cursor: pointer;
}
.radio-circle {
width: 30rpx;
height: 30rpx;
border: 2rpx solid #dcdfe6;
border-radius: 50%;
position: relative;
}
.radio-item.active .radio-circle {
border-color: #409EFF;
}
.radio-item.active .radio-circle::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 16rpx;
height: 16rpx;
background-color: #409EFF;
border-radius: 50%;
}
.radio-text {
font-size: 28rpx;
color: #666;
}
/* 字数统计 */
.word-count {
font-size: 24rpx;
color: #909399;
text-align: right;
margin-top: 10rpx;
}
/* 审核意见区域 */
.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;
}
.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;
}
.approval-item {
margin-bottom: 20rpx;
}
.approval-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10rpx;
}
.approval-node {
font-size: 28rpx;
color: #666;
}
.approval-time {
font-size: 24rpx;
color: #909399;
}
.approval-content {
margin-left: 20rpx;
}
.approval-textarea {
width: 100%;
min-height: 150rpx;
border: 1rpx solid #dcdfe6;
border-radius: 5rpx;
padding: 20rpx;
font-size: 28rpx;
color: #333;
background-color: #f5f7fa;
resize: none;
}
.submit-container {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: white;
padding: 20rpx;
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1);
z-index: 999;
}
.submit-btn {
width: 100%;
height: 80rpx;
background-color: #409EFF;
color: white;
font-size: 32rpx;
font-weight: bold;
border: none;
border-radius: 5rpx;
cursor: pointer;
transition: all 0.3s ease;
}
.submit-btn:hover {
background-color: #66b1ff;
}
.submit-btn:active {
background-color: #3a8ee6;
}
/* 上传容器 */
.upload-container {
margin-top: 10rpx;
}
/* 上传按钮 */
.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;
.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 {
border-color: #409EFF;
background-color: rgba(64, 158, 255, 0.05);
transform: translateY(-2rpx);
.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;
}
/* 证件照上传容器 */
.example-body {
margin-top: 10rpx;
}
/* 照片预览容器 */
.photo-preview-container {
margin-top: 20rpx;
border-radius: 8rpx;
overflow: hidden;
}
.photo-preview-container image {
width: 200rpx;
height: 200rpx;
border-radius: 8rpx;
}
</style>