外宿申请-申请表调整

This commit is contained in:
2025-12-12 16:59:57 +08:00
parent 2b7725ab91
commit 241d70bbf7
10 changed files with 981 additions and 449 deletions

View File

@@ -51,3 +51,12 @@ export function delOutsideAccommodationAttachment(id) {
method: 'post'
})
}
// 删除外宿申请附件
export function deleteOutsideAccommodationAttachmentNameAndStuName(query) {
return request({
url: '/dormitory/outsideAccommodationAttachment/OutsideAccommodationAttachment',
method: 'post',
params: query
})
}

View File

@@ -1,32 +1,46 @@
<template>
<div>
<el-upload :style="uploadStyle" action="" :class="['cm-affix', { 'is-disabled': inputDisabled }]"
:disabled="inputDisabled" :multiple="true" :http-request="handleUpload" :file-list="fileList" :accept="accpet"
:show-file-list="false" :before-upload="handleBeforeUpload">
<el-button v-if="inputDisabled !== true" id="affix1" :disabled="notupload" size="small" type="primary"><i
class='el-icon-upload2'></i>点击上传</el-button>
<el-button v-if="this.affixId !== null && this.affixId !== '' && this.fileList.length > 0" id="affix2"
size="small" @click.stop="downloadPack()">
<div v-if="downloading" class="el-icon-loading file-upload"
style="margin-left: 0px;margin-right: 3px;font-size: 14px;" />
<el-upload
:style="uploadStyle"
action=""
:class="['cm-affix', {'is-disabled': inputDisabled}]"
:disabled="inputDisabled"
:multiple="true"
:http-request="handleUpload"
:file-list="fileList"
:accept="accpet"
:show-file-list="false"
:before-upload="handleBeforeUpload"
>
<el-button v-if="inputDisabled !== true" id="affix1" :disabled="notupload" size="small" type="primary"><i class='el-icon-upload2'></i>点击上传</el-button>
<el-button
v-if="this.affixId !== null && this.affixId !== '' && this.fileList.length > 0"
id="affix2"
size="small"
@click.stop="downloadPack()"
>
<div v-if="downloading" class="el-icon-loading file-upload" style="margin-left: 0px;margin-right: 3px;font-size: 14px;" />
打包下载
</el-button>
</el-upload>
<div v-for="(item, index) in fileList" :key="index" class="file">
<div class="file-item" :class="[{ 'is-disabled': inputDisabled }]">
<div class="file-item" :class="[{'is-disabled': inputDisabled}]">
<div class="file-name">{{ item.name }}</div>
<div v-if="item.status === 1" class="el-icon-loading file-upload" title="上传中..." />
<div v-if="item.status === 2" class="el-icon-download file-download" title="下载" @click="downloadFile(item)" />
<div v-if="item.status === 2" class="el-icon-delete file-delete" title="删除" @click="deleteFile(item)" />
<div v-if="isImageURL(item.name) && item.status === 2" class="el-icon-picture" title="预览"
@click="preview(item)" />
<div v-if="item.status===1" class="el-icon-loading file-upload" title="上传中..." />
<div v-if="item.status===2" class="el-icon-download file-download" title="下载" @click="downloadFile(item)" />
<div v-if="item.status===2" class="el-icon-delete file-delete" title="删除" @click="deleteFile(item)" />
<div v-if="isImageURL(item.name) && item.status === 2" class="el-icon-picture" title="预览" @click="preview(item)" />
</div>
</div>
<el-image v-show="false" ref="preview" class="preview" :src="hiddenSrc" :preview-src-list="previewList" />
<el-image v-show="false" ref="preview"
class="preview"
:src="hiddenSrc"
:preview-src-list="previewList"
/>
</div>
</template>
@@ -35,379 +49,310 @@
import { deleteAffix, download, downloadAll, queryAffixs, upload } from '@/api/affix/affix'
export default {
name: 'CmAffix',
inject: {
elForm: {
default: ''
}
},
props: {
notupload: {
type: Boolean,
default: false
},
value: String, // 父组件值
disabled: Boolean,
maxSize: {
type: Number,
default: 20
},
accpet: {
type: String,
default: '*'
},
uploadStyle:
{
type: String,
default: ''
},
},
data() {
return {
uploadCnt: 0,
affixId: '',
fileList: [],
downloading: false,//控制打包下载loading动画
baseurl: process.env.VUE_APP_BASE_API,
hiddenSrc: '',
previewList: [],
// 解决重复提交的核心变量
isQuerying: false, // 请求锁:标记是否正在查询附件
retryCount: 0 // 重试次数:捕获重复提交错误时重试
}
},
computed: {
inputDisabled() {
return this.disabled || (this.elForm || {}).disabled
}
},
watch: {
// 父组件值监听事件
value: {
immediate: true, // 初始化立即执行
handler: function (newVal, oldVal) {
// 新旧值不同时,先清空所有旧数据(核心解决数据残留)
if (newVal !== oldVal) {
this.fileList = [];
this.previewList = [];
this.affixId = '';
this.retryCount = 0;
name: 'CmAffix',
inject: {
elForm: {
default: ''
}
// 满足条件才加载数据
if (newVal && newVal !== '' && newVal !== this.affixId) {
this.loadData();
},
props: {
notupload:{
type:Boolean,
default:false
},
value: String, // 父组件值
disabled: Boolean,
maxSize:{
type: Number,
default: 20
},
accpet:{
type:String,
default:'*'
},
uploadStyle:
{
type: String,
default: ''
},
},
data() {
return {
uploadCnt: 0,
affixId: '',
fileList: [],
downloading:false,//控制打包下载loading动画
baseurl: process.env.VUE_APP_BASE_API ,
hiddenSrc:'',
previewList:[],
}
}
}
},
created() {
this.loadData()
},
// 新增组件激活时清空旧数据适配keep-alive页面
activated() {
this.fileList = [];
this.previewList = [];
if (this.value) {
this.loadData();
}
},
methods: {
// 预览
preview(item) {
this.hiddenSrc = item.savePath
this.$refs.preview.showViewer = true
},
isImageURL(url) {
// let imgRegex = /(\jpg|\jpeg|\png|\gif|\webp)$/i;
const regex = /(\jpg|\jpeg|\png|\gif|\webp)$/i
return regex.test(url)
},
handleUpload(file) {
upload({ 'file': file.file, 'affixId': this.affixId }).then(res => {
this.uploadCnt--
if (res.code == 200) {
for (let i = 0; i < this.fileList.length; i++) {
let item = this.fileList[i]
console.log(res.savePath)
if (item.name == res.trueName && item.status == 1) {
this.fileList[i].id = res.id
this.fileList[i].status = 2
this.fileList[i].savePath = this.baseurl + res.savePath
if (this.isImageURL(res.savePath)) {
this.previewList.push(this.fileList[i].savePath)
}
// this.fileList[i].savePaths =[this.baseurl + res.savePath];
// 上传成功后向外传递当前文件的完整信息包含后端返回的res数据
this.$emit('fileUploaded', {
fileId: res.id, // 文件ID
fileName: res.trueName, // 文件名
filePath: res.savePath, // 文件相对路径不含baseurl
fullPath: this.fileList[i].savePath, // 完整路径含baseurl
fileType: this.getFileType(res.trueName), // 文件类型
originalFile: file.file // 原始文件对象(可选)
});
}
}
} else {
this.$message.error(res.message)
computed: {
inputDisabled() {
return this.disabled || (this.elForm || {}).disabled
}
}).catch(() => {
this.uploadCnt--
})
},
// 获取文件类型的方法Affix组件中新增
getFileType(fileName) {
if (!fileName) return '';
const lastDotIndex = fileName.lastIndexOf('.');
return lastDotIndex > -1 ? fileName.substring(lastDotIndex + 1).toLowerCase() : '';
},
handleBeforeUpload(file) {
if (this.affixId == null || this.affixId === '') {
this.affixId = this.$tool.uuid()
this.$emit('input', this.affixId)
}
let isLt20M = file.size / 1024 / 1024 < this.maxSize
if (!isLt20M) {
this.$message.error('上传大小不能超过 ' + this.maxSize + 'MB!')
} else {
this.fileList.push({ name: file.name, status: 1 })
this.uploadCnt++
}
return isLt20M
},
getFileName(id) {
for (let i = 0; i < this.fileList.length; i++) {
let item = this.fileList[i]
if (item.id == id) {
console.log(item)
return item.name
}
}
},
downloadFile(file) {
download(file.id).then((res) => {
console.log(res)
let fileName = this.getFileName(file.id).replace(/"/g, '')
var blob = new Blob([res], { type: 'application/octet-stream;' })
var downloadElement = document.createElement('a')
var href = window.URL.createObjectURL(blob) // 创建下载的链接
downloadElement.href = href
downloadElement.download = decodeURI(fileName) // 下载后文件名
document.body.appendChild(downloadElement)
downloadElement.click() // 点击下载
document.body.removeChild(downloadElement) // 下载完成移除元素
window.URL.revokeObjectURL(href) // 释放掉blob对象
}).catch((res) => {
this.$message.error(res.message)
})
},
downloadPack() {
if (this.affixId === null || this.affixId === '') {
this.$message.error('暂无附件!')
return
}
//如果只有一个文件就不打包下载
if (this.fileList.length == 1) {
this.downloadFile(this.fileList[0])
} else {
this.downloading = true
downloadAll(this.affixId).then((res) => {
var blob = new Blob([res], { type: 'application/octet-stream' })
var downloadElement = document.createElement('a')
var href = window.URL.createObjectURL(blob) // 创建下载的链接
downloadElement.href = href
downloadElement.download = decodeURI('download.zip') // 下载后文件名
document.body.appendChild(downloadElement)
downloadElement.click() // 点击下载
document.body.removeChild(downloadElement) // 下载完成移除元素
window.URL.revokeObjectURL(href) // 释放掉blob对象
this.downloading = false
}).catch(() => {
this.downloading = false
})
}
},
deleteFile(file) {
this.$confirm('请确认是否删除此文件?', '提示', { type: 'info' }).then(() => {
deleteAffix(file.id).then((res) => {
if (res.code == 200) {
this.fileList = this.fileList.filter(item => item.id !== file.id)
this.previewList = this.previewList.filter(item => item !== file.savePath)//删除图片
if (this.fileList.length == 0) {
this.affixId = ''
}
// 关键:触发自定义事件,传递被删除的文件名
// 事件名建议delete-file参数file.name文件名
this.$emit('delete-file', file.name);
} else {
this.$message.error(res.message)
}
})
})
},
loadData() {
// 1. 请求锁:防止同一时刻重复请求(解决重复提交)
if (this.isQuerying) return;
// 2. 清空旧数据(双重保障解决数据残留)
this.fileList = [];
this.previewList = [];
if (typeof this.value !== 'undefined' && this.value !== null && this.value !== '') {
this.isQuerying = true; // 加锁
// 带重试机制的查询方法
const queryWithRetry = () => {
queryAffixs(this.value).then((res) => {
this.isQuerying = false; // 解锁
if (res.code == 200) {
if (res.data.length > 0) {
this.affixId = this.value;
// 重新构建数组,避免引用污染
const newFileList = [];
const newPreviewList = [];
for (var i = 0; i < res.data.length; i++) {
const savePath = this.baseurl + res.data[i].savePath;
if (this.isImageURL(savePath)) {
newPreviewList.push(savePath);
}
newFileList.push({
name: res.data[i].trueName,
id: res.data[i].id,
status: 2,
savePath: savePath
});
watch: {
// 父组件值监听事件
value: {
handler: function(newVal/*, oldVal*/) {
if (newVal === undefined || newVal == null || newVal === ''
|| this.affixId === undefined || this.affixId == null || this.affixId === ''
|| newVal !== this.affixId) {
this.loadData()
}
// 直接替换数组,彻底解决残留
this.fileList = newFileList;
this.previewList = newPreviewList;
} else {
this.affixId = '';
}
} else {
// 捕获"重复提交"错误重试1次
if (res.msg.includes('请勿重复提交') && this.retryCount < 1) {
this.retryCount++;
this.isQuerying = true;
setTimeout(() => queryWithRetry(), 500); // 500ms后重试
return;
}
this.$message.error(res.msg);
}
}).catch((err) => {
this.isQuerying = false; // 解锁
// 捕获异常中的重复提交错误重试1次
if (err.message?.includes('请勿重复提交') && this.retryCount < 1) {
this.retryCount++;
setTimeout(() => queryWithRetry(), 500);
return;
}
this.$message.error(err.message || '查询附件失败');
});
};
// 执行查询
queryWithRetry();
} else {
this.affixId = '';
this.isQuerying = false;
}
}
},
clearData() {
this.affixId = '';
this.fileList = [];
this.previewList = [];
this.isQuerying = false;
this.retryCount = 0;
created() {
this.loadData()
},
methods: {
// 预览
preview(item){
this.hiddenSrc = item.savePath
this.$refs.preview.showViewer = true
},
isImageURL(url) {
// let imgRegex = /(\jpg|\jpeg|\png|\gif|\webp)$/i;
const regex = /(\jpg|\jpeg|\png|\gif|\webp)$/i
return regex.test(url)
},
handleUpload(file) {
upload({'file': file.file, 'affixId': this.affixId}).then(res => {
this.uploadCnt--
if (res.code == 200) {
for (let i = 0; i < this.fileList.length; i++) {
let item = this.fileList[i]
console.log(res.savePath)
if(item.name == res.trueName && item.status == 1){
this.fileList[i].id = res.id
this.fileList[i].status = 2
this.fileList[i].savePath = this.baseurl + res.savePath
if(this.isImageURL(res.savePath)){
this.previewList.push( this.fileList[i].savePath)
}
// this.fileList[i].savePaths =[this.baseurl + res.savePath];
// 上传成功后向外传递当前文件的完整信息包含后端返回的res数据
this.$emit('fileUploaded', {
fileId: res.id, // 文件ID
fileName: res.trueName, // 文件名
filePath: res.savePath, // 文件相对路径不含baseurl
fullPath: this.fileList[i].savePath, // 完整路径含baseurl
fileType: this.getFileType(res.trueName), // 文件类型
originalFile: file.file // 原始文件对象(可选)
});
}
}
} else {
this.$message.error(res.message)
}
}).catch(() => {
this.uploadCnt--
})
},
// 获取文件类型的方法Affix组件中新增
getFileType(fileName) {
if (!fileName) return '';
const lastDotIndex = fileName.lastIndexOf('.');
return lastDotIndex > -1 ? fileName.substring(lastDotIndex + 1).toLowerCase() : '';
},
handleBeforeUpload(file) {
if (this.affixId == null || this.affixId === '') {
this.affixId = this.$tool.uuid()
this.$emit('input', this.affixId)
}
let isLt20M = file.size / 1024 / 1024 < this.maxSize
if (!isLt20M) {
this.$message.error('上传大小不能超过 '+this.maxSize+'MB!')
} else {
this.fileList.push({name: file.name, status: 1})
this.uploadCnt++
}
return isLt20M
},
getFileName(id){
for (let i = 0; i < this.fileList.length; i++) {
let item = this.fileList[i]
if(item.id == id){
console.log(item)
return item.name
}
}
},
downloadFile(file) {
download(file.id).then((res) => {
console.log(res)
let fileName = this.getFileName(file.id).replace(/"/g, '')
var blob = new Blob([res], {type: 'application/octet-stream;'})
var downloadElement = document.createElement('a')
var href = window.URL.createObjectURL(blob) // 创建下载的链接
downloadElement.href = href
downloadElement.download = decodeURI(fileName) // 下载后文件名
document.body.appendChild(downloadElement)
downloadElement.click() // 点击下载
document.body.removeChild(downloadElement) // 下载完成移除元素
window.URL.revokeObjectURL(href) // 释放掉blob对象
}).catch((res) => {
this.$message.error(res.message)
})
},
downloadPack() {
if (this.affixId === null || this.affixId === '') {
this.$message.error('暂无附件!')
return
}
//如果只有一个文件就不打包下载
if(this.fileList.length == 1){
this.downloadFile(this.fileList[0])
}else{
this.downloading = true
downloadAll(this.affixId).then((res) => {
var blob = new Blob([res], {type: 'application/octet-stream'})
var downloadElement = document.createElement('a')
var href = window.URL.createObjectURL(blob) // 创建下载的链接
downloadElement.href = href
downloadElement.download = decodeURI('download.zip') // 下载后文件名
document.body.appendChild(downloadElement)
downloadElement.click() // 点击下载
document.body.removeChild(downloadElement) // 下载完成移除元素
window.URL.revokeObjectURL(href) // 释放掉blob对象
this.downloading = false
}).catch(() => {
this.downloading = false
})
}
},
deleteFile(file) {
this.$confirm('请确认是否删除此文件?', '提示', {type: 'info'}).then(() => {
deleteAffix(file.id).then((res) => {
if (res.code == 200) {
this.fileList = this.fileList.filter(item => item.id !== file.id)
this.previewList = this.previewList.filter(item => item !== file.savePath)//删除图片
if(this.fileList.length == 0){
this.affixId = ''
}
// 关键:触发自定义事件,传递被删除的文件名
// 事件名建议delete-file参数file.name文件名
this.$emit('delete-file', file.name);
} else {
this.$message.error(res.message)
}
})
})
},
loadData() {
this.fileList = []
if (typeof this.value !== 'undefined' && this.value !== null && this.value !== '') {
queryAffixs(this.value).then((res) => {
if (res.code ==200) {
if(res.data.length > 0){
this.affixId = this.value
for (var i=0;i<res.data.length;i++) {
if(this.isImageURL(res.data[i].savePath)){
this.previewList.push(this.baseurl+ res.data[i].savePath)
}
this.fileList.push({name: res.data[i].trueName, id: res.data[i].id, status: 2,savePath:this.baseurl+ res.data[i].savePath})
}
} else {
this.affixId = ''
}
} else {
this.$message.error(res.msg)
}
}).catch((res) => {
this.editLoading = false
this.$message.error(res.message)
})
} else {
this.affixId = ''
}
},
clearData() {
this.affixId = ''
this.fileList = []
}
}
}
}
</script>
<style scoped>
.cm-affix>>>.el-upload {
padding: 0px 10px;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
margin-bottom: 10px;
.cm-affix >>>.el-upload{
padding: 0px 10px;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
margin-bottom: 10px;
}
.file {
width: 100%;
}
.file-item {
.file {
width: 100%;
}
white-space: nowrap;
display: flex;
justify-content: start;
align-items: center;
gap: 8px;
}
.file-item div {
display: inline-block;
white-space: nowrap;
}
.file-upload {
font-size: 18px;
margin-left: 5px;
}
.file-download, .file-delete{
font-size: 18px;
cursor: pointer;
.file-item {
}
.file-download:hover, .file-delete:hover {
color: #409EFF;
}
.file-item[class~=is-disabled] .file-delete {
display: none;
}
.download-pack:hover {
background: #409eff;
border-color: #3999a8;
color: #fafbfd;
}
.preview .file-preview{
white-space: nowrap;
display: flex;
justify-content: start;
align-items: center;
gap: 8px;
}
.file-item div {
display: inline-block;
white-space: nowrap;
}
.file-upload {
font-size: 18px;
margin-left: 5px;
}
.file-download,
.file-delete {
font-size: 18px;
cursor: pointer;
}
.file-download:hover,
.file-delete:hover {
color: #409EFF;
}
.file-item[class~=is-disabled] .file-delete {
display: none;
}
.download-pack:hover {
background: #409eff;
border-color: #3999a8;
color: #fafbfd;
}
.preview .file-preview {
font-size: 19px;
cursor: pointer;
font-size: 19px;
cursor: pointer;
}
}
.preview>>>.el-image__inner {
.preview >>>.el-image__inner{
width: 18px;
height: 18px;
width: 18px;
height: 18px;
}
}
</style>

View File

@@ -112,7 +112,7 @@
<!-- 佐证附件 -->
<el-descriptions-item label="佐证附件" required>
<el-form-item prop="affixId" class="no-label-form-item">
<Affix v-model="form.affixId" @input="handleAffix" @fileUploaded="handleAffix"
<AffixIndex ref="affixComponent" v-model="form.affixId" @input="handleAffix" @fileUploaded="handleAffix"
@delete-file="handleDeleteFile" />
<div class="el-upload__tip">
支持上传jpg/png/pdf格式文件单个文件不超过10MB如病例住房证明等
@@ -330,15 +330,17 @@ import {
updateOutsideAccommodationApply,
addOutsideAccommodationApply
} from '@/api/dormitory/outsideAccommodation/outsideAccommodationApply'
import { batchAddOutsideAccommodationAttachment } from "@/api/dormitory/outsideAccommodation/outsideAccommodationAttachment";
import { batchAddOutsideAccommodationAttachment, deleteOutsideAccommodationAttachmentNameAndStuName } from "@/api/dormitory/outsideAccommodation/outsideAccommodationAttachment";
import { getUserProfile } from '@/api/system/user' // 获取当前登录用户
import { getOwnLog } from '@/api/dormitory/new/stuDom'
import {
pcaTextArr // 省市区联动数据,纯汉字
} from 'element-china-area-data'
import AffixIndex from "@/views/dormitory/outsideAccommodation/outsideAccommodationApply/components/affix/index"
export default {
name: 'OutsideAccommodationApply',
components: { AffixIndex },
data() {
return {
// 遮罩层
@@ -804,19 +806,26 @@ export default {
// 处理子组件传递的删除文件事件
handleDeleteFile(fileName) {
// 接收文件名后,可执行后续逻辑,删除在数据库的数据
// if (fileName) {
// deleteRtEnlistmentReserveAttachByFileNameAndStuName({fileName:fileName, studentName: this.formData.studentName}).then(res => {
// this.$message.success(`成功删除文件:${fileName}`);
// })
// }
if (fileName) {
deleteOutsideAccommodationAttachmentNameAndStuName({ attachmentName: fileName, studentName: this.form.studentName }).then(res => {
this.$message.success(`成功删除文件:${fileName}`);
})
}
},
goBack() {
// 关闭当前标签页并返回上个页面
// const obj = { path: 'disciplinaryApplication', query: { t: Date.now() } }
// this.$tab.closeOpenPage(obj)
this.$router.back()
// 关闭窗体 index 当前层索引
this.$tab.closePage()
// 1. 先清空附件组件数据(主动触发清理)
this.$nextTick(() => {
// 如果Affix组件有ref比如ref="affixComponent"主动调用clearData
if (this.$refs.affixComponent) {
this.$refs.affixComponent.clearData();
}
// 2. 优化退出逻辑先关闭tab再返回避免重复操作
this.$tab.closePage().then(() => {
// 仅当需要返回上一页时执行(根据业务场景选择)
// this.$router.back();
});
});
},
// 保存学生签名
saveStudentSignature() {

View File

@@ -0,0 +1,380 @@
<template>
<div>
<el-upload :style="uploadStyle" action="" :class="['cm-affix', { 'is-disabled': inputDisabled }]"
:disabled="inputDisabled" :multiple="true" :http-request="handleUpload" :file-list="fileList" :accept="accpet"
:show-file-list="false" :before-upload="handleBeforeUpload">
<el-button v-if="inputDisabled !== true" id="affix1" :disabled="notupload" size="small" type="primary"><i
class='el-icon-upload2'></i>点击上传</el-button>
<el-button v-if="this.affixId !== null && this.affixId !== '' && this.fileList.length > 0" id="affix2"
size="small" @click.stop="downloadPack()">
<div v-if="downloading" class="el-icon-loading file-upload"
style="margin-left: 0px;margin-right: 3px;font-size: 14px;" />
打包下载
</el-button>
</el-upload>
<div v-for="(item, index) in fileList" :key="`${item.id || item.name}_${index}_${affixId}`" class="file">
<div class="file-item" :class="[{ 'is-disabled': inputDisabled }]">
<div class="file-name">{{ item.name }}</div>
<div v-if="item.status === 1" class="el-icon-loading file-upload" title="上传中..." />
<div v-if="item.status === 2" class="el-icon-download file-download" title="下载" @click="downloadFile(item)" />
<div v-if="item.status === 2" class="el-icon-delete file-delete" title="删除" @click="deleteFile(item)" />
<div v-if="isImageURL(item.name) && item.status === 2" class="el-icon-picture" title="预览"
@click="preview(item)" />
</div>
</div>
<el-image v-show="false" ref="preview" class="preview" :src="hiddenSrc" :preview-src-list="previewList" />
</div>
</template>
<script>
import { deleteAffix, download, downloadAll, queryAffixs, upload } from '@/api/affix/affix'
export default {
name: 'CmAffix',
inject: {
elForm: {
default: ''
}
},
props: {
notupload: {
type: Boolean,
default: false
},
value: String,
disabled: Boolean,
maxSize: {
type: Number,
default: 20
},
accpet: {
type: String,
default: '*'
},
uploadStyle: {
type: String,
default: ''
},
},
data() {
return {
uploadCnt: 0,
affixId: '',
fileList: [],
downloading: false,
baseurl: process.env.VUE_APP_BASE_API,
hiddenSrc: '',
previewList: [],
requestLock: false, // 全局请求锁
retryTimes: 0, // 重试次数
cacheData: {} // 缓存已查询的附件数据
}
},
computed: {
inputDisabled() {
return this.disabled || (this.elForm || {}).disabled
}
},
watch: {
value: {
immediate: true,
handler(newVal) {
if (!newVal) {
this.fileList = []
this.affixId = ''
return
}
// 优先使用缓存,避免重复请求
if (this.cacheData[newVal]) {
this.fileList = [...this.cacheData[newVal].fileList]
this.previewList = [...this.cacheData[newVal].previewList]
this.affixId = newVal
return
}
// 无缓存则请求,加锁防重复
if (!this.requestLock) {
this.loadData(newVal)
}
}
}
},
beforeUnmount() {
this.requestLock = false
this.retryTimes = 0
},
methods: {
preview(item) {
this.hiddenSrc = item.savePath
this.$refs.preview.showViewer = true
},
isImageURL(url) {
const regex = /(\jpg|\jpeg|\png|\gif|\webp)$/i
return regex.test(url)
},
handleUpload(file) {
upload({ 'file': file.file, 'affixId': this.affixId }).then(res => {
this.uploadCnt--
if (res.code == 200) {
for (let i = 0; i < this.fileList.length; i++) {
let item = this.fileList[i]
if (item.name == res.trueName && item.status == 1) {
this.fileList[i].id = res.id
this.fileList[i].status = 2
this.fileList[i].savePath = this.baseurl + res.savePath
if (this.isImageURL(res.savePath)) {
this.previewList.push(this.fileList[i].savePath)
}
// 上传成功后向外传递当前文件的完整信息包含后端返回的res数据
this.$emit('fileUploaded', {
fileId: res.id,
fileName: res.trueName,
filePath: res.savePath,
fullPath: this.fileList[i].savePath,
fileType: this.getFileType(res.trueName),
originalFile: file.file
});
}
}
// 更新缓存
this.cacheData[this.affixId] = {
fileList: [...this.fileList],
previewList: [...this.previewList]
}
} else {
this.$message.error(res.message)
}
}).catch(() => {
this.uploadCnt--
})
},
getFileType(fileName) {
if (!fileName) return '';
const lastDotIndex = fileName.lastIndexOf('.');
return lastDotIndex > -1 ? fileName.substring(lastDotIndex + 1).toLowerCase() : '';
},
handleBeforeUpload(file) {
if (this.affixId == null || this.affixId === '') {
this.affixId = this.$tool.uuid()
this.$emit('input', this.affixId)
}
let isLt20M = file.size / 1024 / 1024 < this.maxSize
if (!isLt20M) {
this.$message.error('上传大小不能超过 ' + this.maxSize + 'MB!')
} else {
this.fileList.push({ name: file.name, status: 1 })
this.uploadCnt++
}
return isLt20M
},
getFileName(id) {
for (let i = 0; i < this.fileList.length; i++) {
let item = this.fileList[i]
if (item.id == id) {
return item.name
}
}
},
downloadFile(file) {
download(file.id).then((res) => {
let fileName = this.getFileName(file.id).replace(/"/g, '')
var blob = new Blob([res], { type: 'application/octet-stream;' })
var downloadElement = document.createElement('a')
var href = window.URL.createObjectURL(blob)
downloadElement.href = href
downloadElement.download = decodeURI(fileName)
document.body.appendChild(downloadElement)
downloadElement.click()
document.body.removeChild(downloadElement)
window.URL.revokeObjectURL(href)
}).catch((res) => {
this.$message.error(res.message)
})
},
downloadPack() {
if (this.affixId === null || this.affixId === '') {
this.$message.error('暂无附件!')
return
}
if (this.fileList.length == 1) {
this.downloadFile(this.fileList[0])
} else {
this.downloading = true
downloadAll(this.affixId).then((res) => {
var blob = new Blob([res], { type: 'application/octet-stream' })
var downloadElement = document.createElement('a')
var href = window.URL.createObjectURL(blob)
downloadElement.href = href
downloadElement.download = decodeURI('download.zip')
document.body.appendChild(downloadElement)
downloadElement.click()
document.body.removeChild(downloadElement)
window.URL.revokeObjectURL(href)
this.downloading = false
}).catch(() => {
this.downloading = false
})
}
},
deleteFile(file) {
this.$confirm('请确认是否删除此文件?', '提示', { type: 'info' }).then(() => {
deleteAffix(file.id).then((res) => {
if (res.code == 200) {
this.fileList = this.fileList.filter(item => item.id !== file.id)
this.previewList = this.previewList.filter(item => item !== file.savePath)
if (this.fileList.length == 0) {
this.affixId = ''
delete this.cacheData[this.affixId] // 清空缓存
} else {
// 更新缓存
this.cacheData[this.affixId] = {
fileList: [...this.fileList],
previewList: [...this.previewList]
}
}
// 关键:触发自定义事件,传递被删除的文件名
// 事件名建议delete-file参数file.name文件名
this.$emit('delete-file', file.name);
} else {
this.$message.error(res.message)
}
})
})
},
// 核心修改:静默处理"重复提交"错误最多重试1次不提示用户
async loadData(targetVal) {
// 加锁防止重复执行
if (this.requestLock || !targetVal) return;
this.requestLock = true;
try {
const res = await queryAffixs(targetVal);
if (res.code == 200) {
this.affixId = targetVal;
const newFileList = [];
const newPreviewList = [];
for (var i = 0; i < res.data.length; i++) {
const savePath = this.baseurl + res.data[i].savePath;
if (this.isImageURL(savePath)) {
newPreviewList.push(savePath);
}
newFileList.push({
name: res.data[i].trueName,
id: res.data[i].id,
status: 2,
savePath: savePath
});
}
this.fileList = newFileList;
this.previewList = newPreviewList;
// 缓存查询结果,后续直接使用
this.cacheData[targetVal] = {
fileList: [...newFileList],
previewList: [...newPreviewList]
};
this.retryTimes = 0; // 重置重试次数
} else {
this.$message.error(res.msg);
}
} catch (err) {
// 关键:只过滤"数据正在处理,请勿重复提交"错误,不提示用户
if (err.message?.includes('数据正在处理,请勿重复提交')) {
// 最多重试1次1秒后重新请求
if (this.retryTimes < 1) {
this.retryTimes++;
setTimeout(() => {
this.requestLock = false; // 释放锁
this.loadData(targetVal); // 重试
}, 1000);
} else {
// 重试失败后清空锁,避免卡死
this.requestLock = false;
this.retryTimes = 0;
}
} else {
// 其他错误正常提示
this.$message.error(err.message || '查询附件失败');
this.requestLock = false;
}
} finally {
// 非重试场景,最终释放锁
if (this.retryTimes === 0) {
this.requestLock = false;
}
}
},
clearData() {
this.affixId = '';
this.fileList = [];
this.previewList = [];
this.requestLock = false;
this.retryTimes = 0;
// 清空当前affixId的缓存
delete this.cacheData[this.affixId];
}
}
}
</script>
<style scoped>
.cm-affix>>>.el-upload {
padding: 0px 10px;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
margin-bottom: 10px;
}
.file {
width: 100%;
}
.file-item {
white-space: nowrap;
display: flex;
justify-content: start;
align-items: center;
gap: 8px;
}
.file-item div {
display: inline-block;
white-space: nowrap;
}
.file-upload {
font-size: 18px;
margin-left: 5px;
}
.file-download,
.file-delete {
font-size: 18px;
cursor: pointer;
}
.file-download:hover,
.file-delete:hover {
color: #409EFF;
}
.file-item[class~=is-disabled] .file-delete {
display: none;
}
.preview>>>.el-image__inner {
width: 18px;
height: 18px;
}
</style>

View File

@@ -26,11 +26,11 @@
<span v-if="renderData.gender == 1"></span>
<span v-else></span>
</el-descriptions-item>
<el-descriptions-item>
<el-descriptions-item class="birthDate">
<template slot="label"> 出生年月 </template>
{{ renderData.birthDate }}
</el-descriptions-item>
<el-descriptions-item span="2">
<el-descriptions-item>
<template slot="label"> 专业系 </template>
{{ renderData.majorName }}
</el-descriptions-item>
@@ -38,12 +38,12 @@
<template slot="label"> 班级 </template>
{{ renderData.className }}
</el-descriptions-item>
<el-descriptions-item>
<el-descriptions-item span="2">
<template slot="label"> 学号 </template>
{{ renderData.studentNo }}
</el-descriptions-item>
<el-descriptions-item span="4">
<template slot="label"> 宿费交纳情况只填写当年度交费情况 </template>
<template slot="label"> 宿费交纳情况</template>
{{ renderData.accommodationFee }}
<!-- 已交 绑定当前学年年度住宿费 人民币 -->
</el-descriptions-item>
@@ -61,7 +61,7 @@
<el-descriptions-item span="4">
<template slot="label"> 附件材料 </template>
<Affix v-model="renderData.affixId" :disabled="true" />
<AffixIndex ref="affixComponent" v-model="renderData.affixId" :disabled="true" />
</el-descriptions-item>
<el-descriptions-item span="4">
@@ -104,11 +104,11 @@
</el-descriptions-item> -->
<el-descriptions-item span="2">
<template slot="label"> 外宿详细地址具体到门牌号 </template>
<template slot="label"> 外宿详细地址</template>
{{ renderData.address + renderData.outsideAddress }}
</el-descriptions-item>
<el-descriptions-item span="2">
<template slot="label"> 外宿居所紧急联系电话 </template>
<template slot="label"> 紧急联系电话 </template>
{{ renderData.emergencyPhone }}
</el-descriptions-item>
<el-descriptions-item span="4">
@@ -203,6 +203,47 @@
</div>
</div>
</div>
<div style="margin-top: 20px;" v-if="isShwo">
<el-timeline>
<el-timeline-item v-for="(item, index) in flowRecordList" :key="index" :icon="setIcon(item.finishTime)"
:color="setColor(item.finishTime)">
<p style="font-weight: 700">{{ item.taskName }}</p>
<el-card :body-style="{ padding: '10px' }">
<el-descriptions class="margin-top" :column="1" size="small" border>
<el-descriptions-item v-if="item.assigneeName" label-class-name="my-label">
<template slot="label"><i class="el-icon-user" />办理人</template>
{{ item.assigneeName }}
<el-tag type="info" size="mini">{{ item.deptName }}</el-tag>
</el-descriptions-item>
<el-descriptions-item v-if="item.candidate" label-class-name="my-label">
<template slot="label"><i class="el-icon-user" />候选办理</template>
{{ item.candidate }}
</el-descriptions-item>
<el-descriptions-item label-class-name="my-label">
<template slot="label"><i class="el-icon-date" />接收时间</template>
{{ item.createTime }}
</el-descriptions-item>
<el-descriptions-item v-if="item.finishTime" label-class-name="my-label">
<template slot="label"><i class="el-icon-date" />处理时间</template>
{{ item.finishTime }}
</el-descriptions-item>
<el-descriptions-item v-if="item.duration" label-class-name="my-label">
<template slot="label"><i class="el-icon-time" />耗时</template>
{{ item.duration }}
</el-descriptions-item>
<el-descriptions-item v-if="item.comment" label-class-name="my-label">
<template slot="label"><i class="el-icon-tickets" />处理意见</template>
{{ item.comment.comment }}
</el-descriptions-item>
<!-- <el-descriptions-item v-if="item.finishTime" label-class-name="my-label">
<template slot="label"><i class="el-icon-date" />签名</template>
<img :src="baseurl + item.assigneeSign" width="300px" height="200px" class="avatar">
</el-descriptions-item> -->
</el-descriptions>
</el-card>
</el-timeline-item>
</el-timeline>
</div>
</el-card>
</div>
</template>
@@ -211,6 +252,9 @@
import {
getOutsideAccommodationApply,
} from '@/api/dormitory/outsideAccommodation/outsideAccommodationApply'
import { flowRecord } from '@/api/flowable/finished'
import AffixIndex from "@/views/dormitory/outsideAccommodation/outsideAccommodationApply/components/affix/index"
export default {
props: {
// props类型定义Object类型+默认空对象)
@@ -223,6 +267,7 @@ export default {
default: true
}
},
components: { AffixIndex },
data() {
return {
loading: false,
@@ -248,6 +293,7 @@ export default {
standard: '',
extraCss: '',
},
flowRecordList: [], // 流程流转数据
}
},
// 计算属性判断优先级
@@ -292,7 +338,8 @@ export default {
.then(res => {
// 修正Promise语法逗号改分号/换行)
this.detailData = { ...res.data }; // 接口数据存入独立变量
this.loading = false;
this.getFlowRecordList(this.detailData.processInstanceId, this.detailData.deployId)
// this.loading = false;
console.log(this.detailData);
})
// 添加异常捕获避免接口报错导致loading一直显示
@@ -311,12 +358,49 @@ export default {
},
methods: {
goBack() {
// 关闭当前标签页并返回上个页面
// const obj = { path: 'disciplinaryApplication', query: { t: Date.now() } }
// this.$tab.closeOpenPage(obj)
this.$router.back()
// 关闭窗体 index 当前层索引
this.$tab.closePage()
// 1. 先清空附件组件数据(主动触发清理)
this.$nextTick(() => {
// 如果Affix组件有ref比如ref="affixComponent"主动调用clearData
if (this.$refs.affixComponent) {
this.$refs.affixComponent.clearData();
}
// 2. 优化退出逻辑先关闭tab再返回避免重复操作
this.$tab.closePage().then(() => {
// 仅当需要返回上一页时执行(根据业务场景选择)
// this.$router.back();
});
});
},
/** 流程流转记录 */
getFlowRecordList(processInstanceId, deploy) {
let procInsId = processInstanceId
let deployId = deploy
const that = this
const params = { procInsId: procInsId, deployId: deployId }
flowRecord(params)
.then((res) => {
that.flowRecordList = res.data.flowList
this.loading = false
})
.catch((res) => {
this.loading = false
this.goBack()
})
},
setIcon(val) {
if (val) {
return 'el-icon-check'
} else {
return 'el-icon-time'
}
},
setColor(val) {
if (val) {
return '#2bc418'
} else {
return '#b3bdbb'
}
},
},
created() { },
@@ -333,9 +417,13 @@ export default {
font-family: "Source Han Sans CN", "PingFang SC", "Microsoft YaHei", sans-serif;
}
::v-deep .el-descriptions-item__label {
.el-container ::v-deep .el-descriptions-item__label {
text-align: center !important;
width: 100px;
width: 80px;
}
.el-container .birthDate ::v-deep .el-descriptions-item__label {
width: 50px;
}
.parentLabel {

View File

@@ -5,21 +5,21 @@
<el-form-item label="学号" prop="studentNo">
<el-input v-model="queryParams.studentNo" placeholder="请输入学号" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="学生姓名" prop="studentName">
<el-form-item label="学生姓名" prop="studentName" v-if="!roleGroup.includes('学生')">
<el-input v-model="queryParams.studentName" placeholder="请输入学生姓名" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="性别" prop="gender">
<!-- <el-form-item label="性别" prop="gender">
<el-input v-model="queryParams.gender" placeholder="请输入性别" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
</el-form-item> -->
<!-- <el-form-item label="出生年月" prop="birthDate">
<el-date-picker clearable v-model="queryParams.birthDate" type="date" value-format="yyyy-MM-dd"
placeholder="请选择出生年月">
</el-date-picker>
</el-form-item> -->
<!-- <el-form-item label="学院名称" prop="deptName">
<el-form-item label="学院名称" prop="deptName" v-if="!roleGroup.includes('二级学院')">
<el-input v-model="queryParams.deptName" placeholder="请输入学院名称" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="专业名称" prop="majorName">
<!-- <el-form-item label="专业名称" prop="majorName">
<el-input v-model="queryParams.majorName" placeholder="请输入专业名称" clearable @keyup.enter.native="handleQuery" />
</el-form-item> -->
<el-form-item label="班级名称" prop="className">
@@ -38,7 +38,7 @@
<!-- <el-form-item label="是否有效" prop="isValid">
<el-input v-model="queryParams.isValid" placeholder="请输入是否有效" clearable @keyup.enter.native="handleQuery" />
</el-form-item> -->
<el-form-item label="辅导员姓名" prop="teacherName" label-width="88px">
<el-form-item label="辅导员姓名" prop="teacherName" label-width="88px" v-if="!roleGroup.includes('辅导员')">
<el-input v-model="queryParams.teacherName" placeholder="请输入辅导员姓名" clearable
@keyup.enter.native="handleQuery" />
</el-form-item>
@@ -150,7 +150,7 @@
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['dormitory:outsideAccommodationApply:edit']"
>修改</el-button>
v-if="scope.row.status == 0 || getRejectInfo(scope.row.outsideAccommodationApprovals).isReject">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['dormitory:outsideAccommodationApply:remove']" v-if="scope.row.status == 0">删除</el-button>
<el-button v-if="scope.row.applyStatus != 0" size="mini" type="text" icon="el-icon-info"
@@ -295,6 +295,7 @@
<script>
import { listOutsideAccommodationApply, getOutsideAccommodationApply, delOutsideAccommodationApply, addOutsideAccommodationApply, updateOutsideAccommodationApply } from "@/api/dormitory/outsideAccommodation/outsideAccommodationApply";
import { getUserProfile } from '@/api/system/user' // 获取当前登录用户
export default {
name: "OutsideAccommodationApply",
@@ -474,7 +475,9 @@ export default {
teacherName: [
{ required: true, message: "辅导员姓名不能为空", trigger: "blur" }
],
}
},
roleGroup: '',
user: ''
};
},
created() {
@@ -484,7 +487,7 @@ export default {
beforeRouteEnter(to, from, next) {
next(vm => {
// vm 是组件实例,这里调用数据加载方法
vm.getList();
vm.getUser();
});
},
methods: {
@@ -497,6 +500,24 @@ export default {
this.loading = false;
});
},
getUser() {
getUserProfile().then(response => {
this.user = response.data
this.roleGroup = response.roleGroup;
// this.postGroup = response.postGroup;
if (this.roleGroup) {
if (this.roleGroup.includes("学生")) {
this.queryParams.studentName = this.user.nickName
} else if (this.roleGroup.includes("辅导员")) {
this.queryParams.teacherName = this.user.nickName
} else if (this.roleGroup.includes("二级学院")) {
this.queryParams.deptName = this.user.dept.deptName
}
this.getList()
}
})
},
// 取消按钮
cancel() {
this.open = false;

View File

@@ -8,7 +8,7 @@
<el-input v-model="queryParams.approvalNode" placeholder="请输入审批节点" clearable
@keyup.enter.native="handleQuery" />
</el-form-item> -->
<el-form-item label="审批人" prop="approverName">
<el-form-item label="审批人" prop="approverName" v-if="roleGroup.includes('管理员')">
<el-input v-model="queryParams.approverName" placeholder="请输入审批人姓名" clearable
@keyup.enter.native="handleQuery" />
</el-form-item>
@@ -75,10 +75,11 @@
<!-- <el-table-column label="流程实例ID" align="center" prop="processInstanceId" /> -->
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
<!-- <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['dormitory:outsideAccommodationApproval:edit']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['dormitory:outsideAccommodationApproval:remove']">删除</el-button>
v-hasPermi="['dormitory:outsideAccommodationApproval:remove']">删除</el-button> -->
<el-button size="mini" type="text" icon="el-icon-info" @click="detail(scope.row)">详情</el-button>
</template>
</el-table-column>
</el-table>
@@ -138,7 +139,7 @@
<script>
import { listOutsideAccommodationApproval, getOutsideAccommodationApproval, delOutsideAccommodationApproval, addOutsideAccommodationApproval, updateOutsideAccommodationApproval } from "@/api/dormitory/outsideAccommodation/outsideAccommodationApproval";
import { getUserProfile } from '@/api/system/user' // 获取当前登录用户
export default {
name: "OutsideAccommodationApproval",
data() {
@@ -212,11 +213,13 @@ export default {
studentNo: [
{ required: true, message: "学生学号不能为空", trigger: "blur" }
]
}
},
roleGroup: '',
user: ''
};
},
created() {
this.getList();
this.getUser();
},
methods: {
/** 查询外宿申请审批记录列表 */
@@ -228,6 +231,20 @@ export default {
this.loading = false;
});
},
getUser() {
getUserProfile().then(response => {
this.user = response.data
this.roleGroup = response.roleGroup;
// this.postGroup = response.postGroup;
if (this.roleGroup) {
if (!this.roleGroup.includes("管理员")) {
this.queryParams.approverName = this.user.nickName
}
this.getList()
}
})
},
// 取消按钮
cancel() {
this.open = false;
@@ -319,7 +336,13 @@ export default {
this.download('dormitory/outsideAccommodationApproval/export', {
...this.queryParams
}, `outsideAccommodationApproval_${new Date().getTime()}.xlsx`)
}
},
detail(row) {
this.$router.push({
path: "/dormitory/outsideAccommodation/detailApply",
query: { id: row.applyId } // 将 row.id 放在 query 中
});
},
}
};
</script>

View File

@@ -5,8 +5,8 @@
<el-input v-model="queryParams.attachmentName" placeholder="请输入附件名称" clearable
@keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="学生姓名" prop="studentName">
<el-input v-model="queryParams.studentName" placeholder="请输入学生姓名" clearable @keyup.enter.native="handleQuery" />
<el-form-item label="学生姓名" prop="studentName" v-if="!roleGroup.includes('学生')">
<el-input v-model="queryParams.studentName" placeholder="请输入学生姓名" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="学生学号" prop="studentNo">
<el-input v-model="queryParams.studentNo" placeholder="请输入学生学号" clearable @keyup.enter.native="handleQuery" />
@@ -73,9 +73,11 @@
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-if="getRejectInfo(scope.row.outsideAccommodationApplies[0].outsideAccommodationApprovals).isReject"
v-hasPermi="['dormitory:outsideAccommodationAttachment:edit']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['dormitory:outsideAccommodationAttachment:remove']">删除</el-button>
<!-- <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['dormitory:outsideAccommodationAttachment:remove']">删除</el-button> -->
<el-button size="mini" type="text" icon="el-icon-info" @click="detail(scope.row)">详情</el-button>
</template>
</el-table-column>
</el-table>
@@ -121,12 +123,12 @@
<script>
import { listOutsideAccommodationAttachment, getOutsideAccommodationAttachment, delOutsideAccommodationAttachment, addOutsideAccommodationAttachment, updateOutsideAccommodationAttachment } from "@/api/dormitory/outsideAccommodation/outsideAccommodationAttachment";
import { getUserProfile } from '@/api/system/user' // 获取当前登录用户
export default {
name: "OutsideAccommodationAttachment",
data() {
return {
baseUrl:process.env.VUE_APP_BASE_API,
baseUrl: process.env.VUE_APP_BASE_API,
// 遮罩层
loading: true,
// 选中数组
@@ -181,11 +183,13 @@ export default {
studentNo: [
{ required: true, message: "学生学号不能为空", trigger: "blur" }
]
}
},
roleGroup: '',
user: ''
};
},
created() {
this.getList();
this.getUser();
},
methods: {
/** 查询外宿申请附件列表 */
@@ -197,6 +201,20 @@ export default {
this.loading = false;
});
},
getUser() {
getUserProfile().then(response => {
this.user = response.data
this.roleGroup = response.roleGroup;
// this.postGroup = response.postGroup;
if (this.roleGroup) {
if (this.roleGroup.includes("学生")) {
this.queryParams.studentName = this.user.nickName
}
this.getList()
}
})
},
// 取消按钮
cancel() {
this.open = false;
@@ -243,12 +261,16 @@ export default {
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id || this.ids
getOutsideAccommodationAttachment(id).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改外宿申请附件";
// this.reset();
// const id = row.id || this.ids
// getOutsideAccommodationAttachment(id).then(response => {
// this.form = response.data;
// this.open = true;
// this.title = "修改外宿申请附件";
// });
this.$router.push({
path: "/dormitory/outsideAccommodation/applicationForm",
query: { id: row.outsideAccommodationApplies[0].id } // 将 row.id 放在 query 中
});
},
/** 提交按钮 */
@@ -286,14 +308,45 @@ export default {
this.download('dormitory/outsideAccommodationAttachment/export', {
...this.queryParams
}, `outsideAccommodationAttachment_${new Date().getTime()}.xlsx`)
}
},
/**
* 获取驳回信息(是否驳回 + 驳回文字)
* @param {Array} approvalList 审批意见列表
* @returns {Object} { isReject: 布尔值, rejectText: 驳回文字 }
*/
getRejectInfo(approvalList) {
// 空值保护:列表不存在/非数组/为空时,返回未驳回
if (!approvalList || !Array.isArray(approvalList) || approvalList.length === 0) {
return { isReject: false, rejectText: '' };
}
// 找到第一个审批结果为0驳回的记录
const rejectItem = approvalList.find(item => item.approvalResult === 0);
if (rejectItem) {
// 提取审批节点名称(如「辅导员审批」→ 截取「辅导员」)
const nodeName = rejectItem.approvalNode.replace('审批', '');
// 拼接驳回文字(如「辅导员驳回」)
return { isReject: true, rejectText: `${nodeName}驳回` };
} else {
// 无驳回记录
return { isReject: false, rejectText: '' };
}
},
detail(row) {
this.$router.push({
path: "/dormitory/outsideAccommodation/detailApply",
query: { id: row.outsideAccommodationApplies[0].id } // 将 row.id 放在 query 中
});
},
}
};
}
</script>
<style scoped>
.text-ellipsis {
white-space: nowrap; /* 防止文本换行 */
overflow: hidden; /* 隐藏溢出的内容 */
text-overflow: ellipsis; /* 显示省略号 */
white-space: nowrap;
/* 防止文本换行 */
overflow: hidden;
/* 隐藏溢出的内容 */
text-overflow: ellipsis;
/* 显示省略号 */
}
</style>

View File

@@ -12,8 +12,8 @@
<el-input v-model="queryParams.taskId" placeholder="请输入Flowable任务ID" clearable
@keyup.enter.native="handleQuery" />
</el-form-item> -->
<el-form-item label="审批节点" prop="nodeName">
<el-input v-model="queryParams.nodeName" placeholder="请输入审批节点" clearable @keyup.enter.native="handleQuery" />
<el-form-item label="学生姓名" prop="studentName">
<el-input v-model="queryParams.studentName" placeholder="请输入学生姓名" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
<!-- <el-form-item label="审批人ID" prop="approverId">
<el-input v-model="queryParams.approverId" placeholder="请输入审批人ID" clearable @keyup.enter.native="handleQuery" />
@@ -82,10 +82,11 @@
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
<!-- <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['routine:enlistmentReserveApproval:edit']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['routine:enlistmentReserveApproval:remove']">删除</el-button>
v-hasPermi="['routine:enlistmentReserveApproval:remove']">删除</el-button> -->
<el-button size="mini" type="text" icon="el-icon-info" @click="detail(scope.row)">详情</el-button>
</template>
</el-table-column>
</el-table>
@@ -171,7 +172,8 @@ export default {
approverName: null,
approvalOpinion: null,
approvalResult: null,
approvalTime: null
approvalTime: null,
studentName: null
},
// 表单参数
form: {},
@@ -230,7 +232,7 @@ export default {
}
this.getList()
}
})
},
// 取消按钮
@@ -321,7 +323,13 @@ export default {
this.download('routine/enlistmentReserveApproval/export', {
...this.queryParams
}, `enlistmentReserveApproval_${new Date().getTime()}.xlsx`)
}
},
detail(row) {
this.$router.push({
path: "/routine/enlistmentReserve/applicationForm",
query: { id: row.applyId, type: 'detail', deployId: row.deployId, processInstanceId: row.processInstanceId } // 将 row.id 放在 query 中
})
},
}
};
</script>

View File

@@ -124,7 +124,7 @@
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['routine:enlistmentReserve:edit']" v-if="scope.row.applyStatus == 0">修改</el-button>
v-hasPermi="['routine:enlistmentReserve:edit']" v-if="scope.row.applyStatus == 0">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['routine:enlistmentReserve:remove']" v-if="scope.row.applyStatus == 0">删除</el-button>
<el-button v-if="scope.row.applyStatus != 0" size="mini" type="text" icon="el-icon-info"
@@ -322,7 +322,7 @@ export default {
beforeRouteEnter(to, from, next) {
next(vm => {
// vm 是组件实例,这里调用数据加载方法
vm.getUser();
vm.getUser();
});
},
methods: {
@@ -344,11 +344,7 @@ export default {
if (this.roleGroup.includes("学生")) {
this.queryParams.studentName = this.user.nickName
} else if (this.roleGroup.includes("辅导员")) {
getOwnInfo().then(res => {
if (res.data) {
this.queryParams.teacherName = res.data.teacherName
}
})
this.queryParams.teacherName = this.user.nickName
}
this.getList()
}
@@ -463,7 +459,7 @@ export default {
// 跳转申请表
openForm() {
// 利用some方法快速判断是否存在重复申请找到匹配项后立即终止遍历
const isDuplicate = this.enlistmentReserveList?.some(element =>
const isDuplicate = this.enlistmentReserveList?.some(element =>
element.studentName === this.user?.nickName && element.studentNo === this.user?.userName
) || false;
@@ -476,7 +472,7 @@ export default {
detail(row) {
this.$router.push({
path: "/routine/enlistmentReserve/applicationForm",
query: { id: row.id, type: 'detail',deployId: row.deployId, processInstanceId: row.processInstanceId } // 将 row.id 放在 query 中
query: { id: row.id, type: 'detail', deployId: row.deployId, processInstanceId: row.processInstanceId } // 将 row.id 放在 query 中
})
},
}