244 lines
6.1 KiB
Vue
244 lines
6.1 KiB
Vue
|
|
<!-- components/SalaryUploadDialog.vue -->
|
|||
|
|
<template>
|
|||
|
|
<el-dialog
|
|||
|
|
title="薪资计算"
|
|||
|
|
:visible.sync="localVisible"
|
|||
|
|
width="30%"
|
|||
|
|
@closed="handleClose"
|
|||
|
|
:close-on-click-modal="false">
|
|||
|
|
<!-- 全局加载状态 -->
|
|||
|
|
<div v-if="globalLoading" class="global-loading">
|
|||
|
|
<div class="loading-content">
|
|||
|
|
<i class="el-icon-loading"></i>
|
|||
|
|
<p>{{ loadingText }}</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<el-form ref="calcForm">
|
|||
|
|
<el-form-item label="计算月份" required>
|
|||
|
|
<el-date-picker
|
|||
|
|
v-model="month"
|
|||
|
|
type="month"
|
|||
|
|
value-format="yyyyMM"
|
|||
|
|
placeholder="选择月份"
|
|||
|
|
style="width: 100%"
|
|||
|
|
:disabled="isProcessing">
|
|||
|
|
</el-date-picker>
|
|||
|
|
</el-form-item>
|
|||
|
|
|
|||
|
|
<el-form-item label="薪资文件" required>
|
|||
|
|
<el-upload
|
|||
|
|
class="upload-demo"
|
|||
|
|
drag
|
|||
|
|
:auto-upload="false"
|
|||
|
|
:on-change="handleFileChange"
|
|||
|
|
:file-list="fileList"
|
|||
|
|
action=""
|
|||
|
|
:disabled="isProcessing">
|
|||
|
|
<i class="el-icon-upload"></i>
|
|||
|
|
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
|||
|
|
<div class="el-upload__tip" slot="tip">仅支持xlsx格式文件</div>
|
|||
|
|
</el-upload>
|
|||
|
|
</el-form-item>
|
|||
|
|
</el-form>
|
|||
|
|
|
|||
|
|
<span slot="footer" class="dialog-footer">
|
|||
|
|
<el-button
|
|||
|
|
@click="localVisible = false"
|
|||
|
|
:disabled="isProcessing">
|
|||
|
|
取消
|
|||
|
|
</el-button>
|
|||
|
|
<el-button
|
|||
|
|
@click="handleUpload"
|
|||
|
|
:disabled="!canUpload"
|
|||
|
|
:loading="uploading">
|
|||
|
|
{{ uploadButtonText }}
|
|||
|
|
</el-button>
|
|||
|
|
<el-button
|
|||
|
|
type="primary"
|
|||
|
|
@click="handleSubmit"
|
|||
|
|
:disabled="!canSubmit"
|
|||
|
|
:loading="calculating">
|
|||
|
|
开始计算
|
|||
|
|
</el-button>
|
|||
|
|
</span>
|
|||
|
|
</el-dialog>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
import { uploadOssFile } from '@/api/oa/salary'
|
|||
|
|
|
|||
|
|
export default {
|
|||
|
|
name: 'SalaryUploadDialog',
|
|||
|
|
props: {
|
|||
|
|
visible: {
|
|||
|
|
type: Boolean,
|
|||
|
|
default: false
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
data() {
|
|||
|
|
return {
|
|||
|
|
localVisible: this.visible,
|
|||
|
|
isProcessing: false, // 整体处理状态
|
|||
|
|
uploading: false, // 上传中状态
|
|||
|
|
calculating: false, // 计算中状态
|
|||
|
|
month: '',
|
|||
|
|
fileList: [],
|
|||
|
|
filePath: '',
|
|||
|
|
currentFileKey: null, // 文件唯一标识
|
|||
|
|
globalLoading: false,
|
|||
|
|
loadingText: ''
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
computed: {
|
|||
|
|
// 是否可以上传(有文件且未处理)
|
|||
|
|
canUpload() {
|
|||
|
|
return this.fileList.length > 0 && !this.uploading && !this.currentFileKey
|
|||
|
|
},
|
|||
|
|
// 是否可以提交计算
|
|||
|
|
canSubmit() {
|
|||
|
|
return Boolean(this.filePath) && !this.calculating
|
|||
|
|
},
|
|||
|
|
uploadButtonText() {
|
|||
|
|
return this.uploading ? '上传中...' : '确认上传'
|
|||
|
|
},
|
|||
|
|
// 生成文件唯一标识
|
|||
|
|
fileIdentifier() {
|
|||
|
|
if (!this.fileList.length) return null
|
|||
|
|
const file = this.fileList[0].raw
|
|||
|
|
return `${file.name}-${file.lastModified}-${file.size}`
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
watch: {
|
|||
|
|
visible(newVal) {
|
|||
|
|
this.localVisible = newVal
|
|||
|
|
},
|
|||
|
|
localVisible(newVal) {
|
|||
|
|
this.$emit('update:visible', newVal)
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
methods: {
|
|||
|
|
handleFileChange(file, fileList) {
|
|||
|
|
this.fileList = [fileList[fileList.length - 1]]
|
|||
|
|
// 检测到文件变化时重置状态
|
|||
|
|
if (this.fileIdentifier !== this.currentFileKey) {
|
|||
|
|
this.currentFileKey = null
|
|||
|
|
this.filePath = ''
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
async handleUpload() {
|
|||
|
|
try {
|
|||
|
|
this.uploading = true
|
|||
|
|
this.isProcessing = true
|
|||
|
|
this.showGlobalLoading('文件上传中...')
|
|||
|
|
const formData = new FormData()
|
|||
|
|
formData.append('file', this.fileList[0].raw)
|
|||
|
|
|
|||
|
|
const { data } = await uploadOssFile(formData)
|
|||
|
|
this.filePath = '/data' + data.url.split('/data')[1]
|
|||
|
|
this.currentFileKey = this.fileIdentifier
|
|||
|
|
this.$message.success('文件上传成功')
|
|||
|
|
} catch (error) {
|
|||
|
|
this.$message.error('文件上传失败')
|
|||
|
|
} finally {
|
|||
|
|
this.uploading = false
|
|||
|
|
this.isProcessing = false
|
|||
|
|
this.hideGlobalLoading()
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
async handleSubmit() {
|
|||
|
|
if (!this.validateForm()) return
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
this.calculating = true
|
|||
|
|
this.isProcessing = true
|
|||
|
|
this.showGlobalLoading('薪资计算中...')
|
|||
|
|
|
|||
|
|
// 触发父组件计算
|
|||
|
|
this.$emit('submit', {
|
|||
|
|
monthStr: this.month,
|
|||
|
|
filePath: this.filePath
|
|||
|
|
})
|
|||
|
|
} catch (error) {
|
|||
|
|
this.$message.error(error.message || '计算失败')
|
|||
|
|
} finally {
|
|||
|
|
this.calculating = false
|
|||
|
|
this.isProcessing = false
|
|||
|
|
this.hideGlobalLoading()
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
validateForm() {
|
|||
|
|
if (!this.month) {
|
|||
|
|
this.$message.warning('请选择计算月份')
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
if (!this.filePath) {
|
|||
|
|
this.$message.warning('请先上传薪资文件')
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
return true
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
showGlobalLoading(text) {
|
|||
|
|
this.globalLoading = true
|
|||
|
|
this.loadingText = text
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
hideGlobalLoading() {
|
|||
|
|
this.globalLoading = false
|
|||
|
|
this.loadingText = ''
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
handleClose() {
|
|||
|
|
this.resetForm()
|
|||
|
|
this.$emit('closed')
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
resetForm() {
|
|||
|
|
this.fileList = []
|
|||
|
|
this.month = ''
|
|||
|
|
this.filePath = ''
|
|||
|
|
this.currentFileKey = null
|
|||
|
|
this.isProcessing = false
|
|||
|
|
this.uploading = false
|
|||
|
|
this.calculating = false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style scoped>
|
|||
|
|
/* 全局加载样式 */
|
|||
|
|
.global-loading {
|
|||
|
|
position: fixed;
|
|||
|
|
top: 0;
|
|||
|
|
left: 0;
|
|||
|
|
right: 0;
|
|||
|
|
bottom: 0;
|
|||
|
|
background: rgba(255, 255, 255, 0.8);
|
|||
|
|
z-index: 9999;
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.loading-content {
|
|||
|
|
text-align: center;
|
|||
|
|
padding: 20px;
|
|||
|
|
background: rgba(0, 0, 0, 0.7);
|
|||
|
|
border-radius: 4px;
|
|||
|
|
color: #fff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.loading-content i {
|
|||
|
|
font-size: 40px;
|
|||
|
|
margin-bottom: 10px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.upload-demo {
|
|||
|
|
text-align: center;
|
|||
|
|
}
|
|||
|
|
</style>
|