外宿申请-佐证附件上传与删除

This commit is contained in:
962704835@qq.com
2025-12-18 23:42:58 +08:00
parent b69ea9f172
commit bc78f7d2dd
3 changed files with 184 additions and 91 deletions

View File

@@ -8,3 +8,14 @@ export function getAffixItems(data) {
data: data
})
}
// 删除附件
export function deleteAffix (fileId){
return request(
{
url:'/affix/delete',
method:'post',
data:{id: fileId}
}
)
}

View File

@@ -11,6 +11,7 @@
<!-- 选项卡容器 - 原生选项卡 -->
<view class="tabs-container">
<view class="tabs-header">
<!-- 详情模式下禁用选项卡切换 -->
<view class="tab-item" :class="{ active: activeTab === 0 }" @click="switchTab(0)">
<uni-icons type="contact" size="16" :color="activeTab === 0 ? '#409EFF' : '#666'"></uni-icons>
<text class="tab-text">基本信息</text>
@@ -44,19 +45,21 @@
<view class="card-title">基本信息</view>
<view class="form-item">
<label class="form-label">原宿舍号</label>
<!-- 详情模式下禁用输入框 -->
<input v-model="form.originalDormitory" placeholder="如1栋302"
class="form-input"></input>
class="form-input" :disabled="isDetailMode"></input>
</view>
<view class="form-item">
<label class="form-label">姓名</label>
<input v-model="form.studentName" placeholder="请输入姓名" class="form-input"></input>
<input v-model="form.studentName" placeholder="请输入姓名" class="form-input" :disabled="isDetailMode"></input>
</view>
<view class="form-item">
<label class="form-label">性别</label>
<!-- 详情模式下禁用选择器 -->
<picker mode="selector" :range="genderOptions" :range-key="'text'" v-model="form.gender"
@change="handleGenderChange">
@change="handleGenderChange" :disabled="isDetailMode">
<view class="picker-input">
{{ form.gender ? getGenderText(form.gender) : '请选择性别' }}
</view>
@@ -65,7 +68,7 @@
<view class="form-item">
<label class="form-label">出生年月</label>
<picker mode="date" :value="form.birthDate" @change="handleBirthDateChange">
<picker mode="date" :value="form.birthDate" @change="handleBirthDateChange" :disabled="isDetailMode">
<view class="picker-input">
{{ form.birthDate || '请选择出生年月' }}
</view>
@@ -74,28 +77,28 @@
<view class="form-item">
<label class="form-label">专业系</label>
<input v-model="form.majorName" placeholder="请输入专业系" class="form-input"></input>
<input v-model="form.majorName" placeholder="请输入专业系" class="form-input" :disabled="isDetailMode"></input>
</view>
<view class="form-item">
<label class="form-label">班级</label>
<input v-model="form.className" placeholder="请输入班级" class="form-input"></input>
<input v-model="form.className" placeholder="请输入班级" class="form-input" :disabled="isDetailMode"></input>
</view>
<view class="form-item">
<label class="form-label">学号</label>
<input v-model="form.studentNo" placeholder="请输入学号" class="form-input"></input>
<input v-model="form.studentNo" placeholder="请输入学号" class="form-input" :disabled="isDetailMode"></input>
</view>
<view class="form-item">
<label class="form-label">身份证号码</label>
<input v-model="form.idCard" placeholder="请输入身份证号码" class="form-input"></input>
<input v-model="form.idCard" placeholder="请输入身份证号码" class="form-input" :disabled="isDetailMode"></input>
</view>
<view class="form-item">
<label class="form-label">联系电话</label>
<input v-model="form.studentPhone" placeholder="请输入联系电话" class="form-input"
type="number"></input>
type="number" :disabled="isDetailMode"></input>
</view>
<view class="form-item">
@@ -112,22 +115,24 @@
<view class="form-item">
<label class="form-label">外宿原因</label>
<textarea v-model="form.applyReason" placeholder="请详细描述外宿原因" class="form-textarea"
rows="5"></textarea>
rows="5" :disabled="isDetailMode"></textarea>
</view>
<view class="form-item">
<label class="form-label">佐证附件</label>
<!-- <button type="default" size="mini" @click="chooseAffixFile"
class="upload-btn">选择文件</button> -->
<view class="upload-btn" @click="chooseAffixFile">
<!-- 详情模式下禁用文件上传 -->
<view class="upload-btn" @click="chooseAffixFile" v-if="!isDetailMode">
<text class="upload-icon">+</text>
<text>上传文件</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">{{ file.attachmentName }}</text>
<button size="mini" type="warn" @click="deleteAffixFile(index)"
class="delete-btn">删除</button>
<text class="file-name" @click="previewImage(baseUrl + file.savePath)">{{ file.attachmentName || file.trueName }}</text>
<!-- 详情模式下禁用删除按钮 -->
<!-- <button size="mini" type="warn" @click="deleteAffixFile(index)" v-if="!isDetailMode"
class="delete-btn" :disabled="isDetailMode">删除</button> -->
<uni-icons type="trash-filled" size="30" @click="deleteAffixFile(index)" v-if="!isDetailMode"
class="delete-btn"></uni-icons>
</view>
</view>
<!-- <uni-file-picker :auto-upload="false" @select="chooseAffixFile" @delete="deleteAffixFile"></uni-file-picker> -->
@@ -137,8 +142,9 @@
<view class="form-item">
<label class="form-label">电子签名</label>
<view class="signature-container">
<button size="mini" type="primary" @click="openSignature('student')"
class="sign-btn">
<!-- 详情模式下隐藏签名按钮 -->
<button size="mini" type="primary" @click="!isDetailMode && openSignature('student')"
class="sign-btn" v-if="!isDetailMode">
签署电子签名
</button>
<image v-if="form.studentSignature" :src="baseUrl + form.studentSignature"
@@ -156,7 +162,8 @@
<!-- 替换为省市区选择器 -->
<view class="form-item">
<label class="form-label">外宿地区</label>
<view class="area-picker" @click="showAreaPicker = true">
<!-- 详情模式下禁用省市区选择器 -->
<view class="area-picker" @click="!isDetailMode && (showAreaPicker = true)" :class="{disabled: isDetailMode}">
<text class="picker-text">{{ areaText || '请选择省/市/区' }}</text>
<uni-icons type="arrowright" size="16" color="#999" class="picker-icon"></uni-icons>
</view>
@@ -165,19 +172,19 @@
<view class="form-item">
<label class="form-label">详细门牌号</label>
<input v-model="form.outsideAddress" placeholder="请输入详细门牌号XX小区3栋502"
class="form-input"></input>
class="form-input" :disabled="isDetailMode"></input>
</view>
<view class="form-item">
<label class="form-label">紧急联系人</label>
<input v-model="form.emergencyContact" placeholder="请输入紧急联系人姓名"
class="form-input"></input>
class="form-input" :disabled="isDetailMode"></input>
</view>
<view class="form-item">
<label class="form-label">紧急联系电话</label>
<input v-model="form.emergencyPhone" placeholder="请输入紧急联系人电话" class="form-input"
type="number"></input>
type="number" :disabled="isDetailMode"></input>
</view>
</view>
</view>
@@ -188,8 +195,9 @@
<view class="card-title card-parent">家长意见及联系方式</view>
<view class="form-item">
<label class="form-label">家长意见</label>
<!-- 详情模式下禁用选择器 -->
<picker mode="selector" :range="parentOpinionOptions" :range-key="'text'"
v-model="form.parentOpinion" @change="handleParentOpinionChange">
v-model="form.parentOpinion" @change="handleParentOpinionChange" :disabled="isDetailMode">
<view class="picker-input">
{{ form.parentOpinion ? getParentOpinionText(form.parentOpinion) : '请选择家长意见' }}
</view>
@@ -198,12 +206,13 @@
<view class="form-item">
<label class="form-label">家长签字附件</label>
<view class="upload-btn" @click="handleUpload">
<!-- 详情模式下禁用图片上传 -->
<view class="upload-btn" @click="handleUpload" v-if="!isDetailMode">
<text class="upload-icon">+</text>
<text>上传图片</text>
</view>
<view class="upload-preview" v-if="parentSignFiles">
<image :src="parentSignFiles" mode="aspectFill" />
<view class="upload-preview" v-if="form.parentSignAttachment">
<image :src="baseUrl + form.parentSignAttachment" mode="aspectFill" />
</view>
<view class="upload-tip">只能上传jpg/png文件且不超过2M</view>
</view>
@@ -211,13 +220,14 @@
<view class="form-item">
<label class="form-label">家长联系电话</label>
<input v-model="form.parentPhone" placeholder="请输入家长联系电话" class="form-input"
type="number"></input>
type="number" :disabled="isDetailMode"></input>
</view>
<!-- 家长地址省市区选择器 -->
<view class="form-item">
<label class="form-label">家长通讯地区</label>
<view class="area-picker" @click="showParentAreaPicker = true">
<!-- 详情模式下禁用省市区选择器 -->
<view class="area-picker" @click="!isDetailMode && (showParentAreaPicker = true)" :class="{disabled: isDetailMode}">
<text class="picker-text">{{ parentAreaText || '请选择省/市/区' }}</text>
<uni-icons type="arrowright" size="16" color="#999" class="picker-icon"></uni-icons>
</view>
@@ -226,7 +236,7 @@
<view class="form-item">
<label class="form-label">家长详细地址</label>
<input v-model="form.parentDetailAddress" placeholder="请输入家长详细通讯地址"
class="form-input"></input>
class="form-input" :disabled="isDetailMode"></input>
</view>
</view>
</view>
@@ -248,8 +258,9 @@
<view class="form-item">
<label class="form-label">承诺签名</label>
<view class="signature-container">
<button size="mini" type="primary" @click="openSignature('promise')"
class="sign-btn">
<!-- 详情模式下隐藏签名按钮 -->
<button size="mini" type="primary" @click="!isDetailMode && openSignature('promise')"
class="sign-btn" v-if="!isDetailMode">
签署承诺签名
</button>
<image v-if="form.studentPromiseSign" :src="baseUrl + form.studentPromiseSign"
@@ -257,7 +268,8 @@
@click="previewImage(baseUrl + form.studentPromiseSign)"></image>
<view class="date-item">
<label class="form-label">签署日期</label>
<picker mode="date" :value="form.promiseDate" @change="handlePromiseDateChange">
<!-- 详情模式下禁用日期选择器 -->
<picker mode="date" :value="form.promiseDate" @change="handlePromiseDateChange" :disabled="isDetailMode">
<view class="picker-input">
{{ form.promiseDate || '请选择签署日期' }}
</view>
@@ -269,7 +281,8 @@
</view>
<!-- 提交按钮区域 -->
<view class="submit-container">
<!-- 详情模式下隐藏所有操作按钮 -->
<view class="submit-container" v-if="!isDetailMode">
<button type="primary" @click="submitForm(0)" class="submit-btn">
<uni-icons type="folder" size="16"></uni-icons> 保存
</button>
@@ -286,12 +299,11 @@
</view>
<!-- 申请须知弹窗5秒自动关闭 -->
<!-- 给mask添加.stop阻止事件冒泡避免点击mask关闭弹窗 -->
<!-- 模板给容器加过渡动画 -->
<transition name="popup-fade">
<!-- 详情模式下不显示该弹窗 -->
<transition name="popup-fade" v-if="!isDetailMode">
<view class="mask" v-if="showNoticePopup" @click.stop="() => {}"></view>
</transition>
<transition name="popup-slide">
<transition name="popup-slide" v-if="!isDetailMode">
<view class="notice-popup" v-if="showNoticePopup">
<view class="popup-header">
<text class="popup-title">申请须知</text>
@@ -312,8 +324,9 @@
</transition>
<!-- 通用签名弹窗使用 uni-app 内置绘图 API -->
<view class="mask" v-if="showSignPopup" @click="closeSignPopup"></view>
<view class="sign-popup" v-if="showSignPopup">
<!-- 详情模式下不显示签名弹窗 -->
<view class="mask" v-if="!isDetailMode && showSignPopup" @click="closeSignPopup"></view>
<view class="sign-popup" v-if="!isDetailMode && showSignPopup">
<view class="sign-popup-header">
<text class="sign-title">{{ currentSignType === 'student' ? '电子签名' : '承诺签名' }}</text>
<uni-icons type="close" size="20" @click="closeSignPopup" class="close-icon"></uni-icons>
@@ -329,8 +342,9 @@
</view>
<!-- 外宿地址省市区选择器弹窗 -->
<view class="mask" v-if="showAreaPicker" @click="showAreaPicker = false"></view>
<view class="area-popup" v-if="showAreaPicker">
<!-- 详情模式下不显示省市区选择器弹窗 -->
<view class="mask" v-if="!isDetailMode && showAreaPicker" @click="showAreaPicker = false"></view>
<view class="area-popup" v-if="!isDetailMode && showAreaPicker">
<view class="area-popup-header">
<button size="mini" type="default" @click="showAreaPicker = false" class="btn-cancel">取消</button>
<button size="mini" type="primary" @click="confirmArea" class="btn-confirm">确认</button>
@@ -349,8 +363,9 @@
</view>
<!-- 家长地址省市区选择器弹窗 -->
<view class="mask" v-if="showParentAreaPicker" @click="showParentAreaPicker = false"></view>
<view class="area-popup" v-if="showParentAreaPicker">
<!-- 详情模式下不显示省市区选择器弹窗 -->
<view class="mask" v-if="!isDetailMode && showParentAreaPicker" @click="showParentAreaPicker = false"></view>
<view class="area-popup" v-if="!isDetailMode && showParentAreaPicker">
<view class="area-popup-header">
<button size="mini" type="default" @click="showParentAreaPicker = false" class="btn-cancel">取消</button>
<button size="mini" type="primary" @click="confirmParentArea" class="btn-confirm">确认</button>
@@ -394,10 +409,15 @@
checkPic
} from "@/utils/checkPic.js";
import uploadFile from "@/plugins/upload.js";
import {
getAffixItems, deleteAffix
} from "@/api/affix.js";
export default {
name: 'OutsideAccommodationApply',
data() {
return {
// 新增:是否为详情查看模式(核心控制变量)
isDetailMode: false,
// 激活的标签页索引
activeTab: 0,
// 表单滚动高度
@@ -434,6 +454,8 @@
majorName: '',
className: '',
studentNo: '',
deptName: '',
teacherName: '',
idCard: '',
studentPhone: '',
accommodationFeeStatus: 1,
@@ -442,7 +464,7 @@
outsideAddress: '',
emergencyContact: '',
emergencyPhone: '',
parentOpinion: '1', // 默认同意
parentOpinion: 1, // 默认同意
parentPhone: '',
parentAddress: '', // 家长省市区拼接结果
parentDetailAddress: '',
@@ -455,7 +477,8 @@
status: 0,
id: '',
applyNo: '',
endDate: ''
endDate: '',
promiseContent: ''
},
// 下拉选项
genderOptions: [{
@@ -469,17 +492,16 @@
],
parentOpinionOptions: [{
text: '同意外宿',
value: '1'
value: 1
},
{
text: '不同意外宿',
value: '0'
value: 0
}
],
// 文件上传相关
affixFiles: [],
parentSignFiles: "",
reasonFileList: [],
// 页面状态
currentId: null,
loading: false,
@@ -490,6 +512,9 @@
}
},
onLoad(options) {
// 新增:判断是否为详情模式(核心逻辑)
this.isDetailMode = options.type === 'detail';
// 1. 初始化省市区数据
this.initAreaData();
// 2. 初始化页面高度
@@ -504,8 +529,11 @@
}
},
onReady() {
// 1. 打开申请须知弹窗
this.openNoticePopup();
// 新增:详情模式下不打开申请须知弹窗
if (!this.isDetailMode) {
// 1. 打开申请须知弹窗
this.openNoticePopup();
}
},
methods: {
// ========== 省市区选择器核心方法 ==========
@@ -872,7 +900,7 @@
const fileInfo = {
applyId: this.form.id || '',
attachmentName: file.name,
attachmentUrl: file.savePath, // 本地路径
attachmentUrl: result.savePath, // 本地路径
serverUrl: result.savePath || '', // 服务器返回的文件路径
fileId: result.id || '', // 服务器返回的文件ID
fileSize: file.size,
@@ -928,22 +956,25 @@
deleteAffixFile(index) {
const deletedFile = this.affixFiles[index];
this.affixFiles.splice(index, 1);
this.form.affixId = this.affixFiles.length ? 'uploaded' : '';
// this.form.affixId = this.affixFiles.length ? 'uploaded' : '';
let fileId = deletedFile.id || deletedFile.fileId
deleteAffix(fileId).then(() => {
deleteOutsideAccommodationAttachmentNameAndStuName({
attachmentName: deletedFile.trueName || deletedFile.attachmentName,
studentName: this.form.studentName
}).then(() => {
uni.showToast({
title: '删除成功',
icon: 'success'
});
}).catch(() => {
uni.showToast({
title: '删除失败',
icon: 'none'
});
});
})
deleteOutsideAccommodationAttachmentNameAndStuName({
attachmentName: deletedFile.name,
studentName: this.form.studentName
}).then(() => {
uni.showToast({
title: '删除成功',
icon: 'success'
});
}).catch(() => {
uni.showToast({
title: '删除失败',
icon: 'none'
});
});
},
// 家长附件上传
handleUpload() {
@@ -996,6 +1027,8 @@
// }];
// }
this.getAffixs(this.form.affixId)
this.loading = false;
}).catch(() => {
this.loading = false;
@@ -1018,8 +1051,10 @@
this.form.studentId = res.data.stuId;
this.form.studentNo = res.data.stuNo;
this.form.majorName = res.data.majorName;
this.form.deptName = res.data.deptName
this.form.className = res.data.className;
this.form.idCard = res.data.idCard;
this.form.teacherName = res.data.teacherName
this.form.studentPhone = res.data.stuPhone;
this.form.birthDate = res.data.birthday || '';
@@ -1084,6 +1119,7 @@
});
});
},
// 获取学生宿舍
getStuDom() {
listStudent({
stuNo: this.form.studentNo,
@@ -1105,6 +1141,14 @@
});
});
},
// 获取上传的附件数据
getAffixs(affix) {
getAffixItems({
affixId: affix
}).then(file => {
this.affixFiles = file.data;
})
},
submitForm(status) {
// 定义英文字段名和中文提示的映射关系
const fieldMap = {
@@ -1184,6 +1228,12 @@
}
this.form.endDate = this.getOutsideDefaultEndTime();
this.form.promiseContent = `
<p>1.自觉遵守国家法律、法规;</p>
<p>2.自觉遵守学生行为规范和学校的规章制度,遵守社会公德;</p>
<p>3.自觉遵守外宿住址所在社区的有关管理规定;</p>
<p>4.本人申请外宿,属个人自愿行为,外宿期间发生的一切事故,造成本人、他人或集体的人身、财产损害的,学校不负责任。</p>
`
const submitForm = {
...this.form,
status: this.form.status != 0 ? this.form.status : status
@@ -1195,11 +1245,11 @@
addOutsideAccommodationApply(submitForm);
requestPromise.then((response) => {
if (this.reasonFileList.length > 0) {
this.reasonFileList.forEach(item => {
if (this.affixFiles.length > 0) {
this.affixFiles.forEach(item => {
item.applyId = this.form.id || response.data.id;
});
batchAddOutsideAccommodationAttachment(this.reasonFileList);
batchAddOutsideAccommodationAttachment(this.affixFiles);
}
uni.showToast({
@@ -1251,7 +1301,6 @@
this.affixFiles = [];
this.parentSignFiles = "";
this.reasonFileList = [];
this.areaText = '';
this.parentAreaText = '';
@@ -1549,6 +1598,12 @@
border-color: #409EFF;
}
/* 新增:禁用状态样式(可选) */
.area-picker.disabled {
opacity: 0.7;
pointer-events: none;
}
.picker-text {
flex: 1;
overflow: hidden;
@@ -1633,8 +1688,8 @@
color: #ef4444;
border: 1px solid #fee2e2;
border-radius: 6rpx;
padding: 8rpx 16rpx;
font-size: 24rpx;
/* padding: 8rpx 16rpx; */
/* font-size: 24rpx; */
}
/* 上传提示 */
@@ -1909,30 +1964,39 @@
padding: 12rpx 24rpx;
font-size: 26rpx;
}
/* 添加过渡样式 */
.popup-fade-enter-active, .popup-fade-leave-active {
.popup-fade-enter-active,
.popup-fade-leave-active {
transition: opacity 0.3s ease;
}
.popup-fade-enter-from, .popup-fade-leave-to {
.popup-fade-enter-from,
.popup-fade-leave-to {
opacity: 0;
}
.popup-slide-enter-active, .popup-slide-leave-active {
.popup-slide-enter-active,
.popup-slide-leave-active {
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.popup-slide-enter-from {
opacity: 0;
transform: translate(-50%, -50%) translateY(50px);
}
.popup-slide-leave-to {
opacity: 0;
transform: translate(-50%, -50%) translateY(50px);
}
/* 蒙层渐入渐出动画 */
.popup-fade-enter-active,
.popup-fade-leave-active {
transition: opacity 0.3s ease;
}
/* 进入前/离开后状态(透明) */
.popup-fade-enter,
.popup-fade-leave-to {
@@ -1942,13 +2006,16 @@
/* 弹窗滑入滑出动画(核心) */
.popup-slide-enter-active,
.popup-slide-leave-active {
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); /* 缓动曲线更丝滑 */
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
/* 缓动曲线更丝滑 */
}
/* 进入前状态:透明 + 向下偏移50px */
.popup-slide-enter {
opacity: 0;
transform: translate(-50%, -50%) translateY(50px);
}
/* 离开后状态:透明 + 向下偏移50px */
.popup-slide-leave-to {
opacity: 0;

View File

@@ -166,10 +166,17 @@
<!-- 卡片操作区 -->
<view class="card-actions">
<uni-button type="text" size="mini" @click="detail(item)" class="detail-btn"
:disabled="!getSafeValue(item, 'id')">
<uni-icons type="info" size="14" class="mr-5"></uni-icons>查看详情
</uni-button>
<view>
<uni-button type="text" size="mini" @click="detail(item, '修改')" v-if="item.status == 0 || getRejectInfo(item.outsideAccommodationApprovals).isReject">
<uni-icons type="eye-filled" size="14" class="mr-5"></uni-icons>修改
</uni-button>
</view>
<view>
<uni-button type="text" size="mini" @click="detail(item, '详情')" class="detail-btn"
:disabled="!getSafeValue(item, 'id')">
<uni-icons type="info" size="14" class="mr-5"></uni-icons>查看详情
</uni-button>
</view>
</view>
</view>
</view>
@@ -243,7 +250,7 @@
return this.validDataList.length > 0;
}
},
onLoad() {
onShow() {
this.getUser();
},
methods: {
@@ -438,7 +445,7 @@
},
/** 查看详情 */
detail(item) {
detail(item, text) {
const id = this.getSafeValue(item, 'id');
if (!id) {
uni.showToast({
@@ -447,9 +454,15 @@
});
return;
}
uni.navigateTo({
url: `/pages/dormitory/outsideAccommodation/applicationForm?id=${id}`
});
if (text == '详情') {
uni.navigateTo({
url: `/pages/dormitory/outsideAccommodation/applicationForm?id=${id}&type=detail`
});
} else {
uni.navigateTo({
url: `/pages/dormitory/outsideAccommodation/applicationForm?id=${id}`
});
}
},
// 跳转添加页面
addOutsideAccommodation() {
@@ -895,6 +908,8 @@
.detail-btn {
color: #409eff;
font-size: 26rpx;
padding: 0 20rpx;
margin-left: 20rpx;
}
/* 适配小屏幕 */