This commit is contained in:
吴红兵
2026-03-07 12:35:45 +08:00
parent 271710e870
commit b997b3ba48
423 changed files with 79612 additions and 91574 deletions

View File

@@ -1,121 +1,113 @@
<template>
<el-dialog v-model="visible" title="薪资导出" width="650px" :close-on-click-modal="false" destroy-on-close>
<el-form label-width="100px">
<el-form-item label="日期">
<el-date-picker
v-model="chooseDate"
type="month"
format="YYYY-M"
value-format="YYYY-M"
placeholder="请选择日期"
@change="handleChange"
/>
</el-form-item>
<el-form-item label="劳务日期锁定">
<el-radio-group v-model="lockedLw">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label-width="0px">
<el-tag type="warning">选择是则本月其他造单批次无法指定到当前月份如需解锁请前往薪资导出记录删除记录即可</el-tag>
</el-form-item>
</el-form>
<template #footer>
<span v-if="showBtn" class="dialog-footer">
<el-button @click="visible = false"> </el-button>
<el-button type="primary" @click="exportSalaryData" :loading="btnLoading"> </el-button>
</span>
</template>
</el-dialog>
<el-dialog v-model="visible" title="薪资导出" width="650px" :close-on-click-modal="false" destroy-on-close>
<el-form label-width="100px">
<el-form-item label="日期">
<el-date-picker v-model="chooseDate" type="month" format="YYYY-M" value-format="YYYY-M" placeholder="请选择日期" @change="handleChange" />
</el-form-item>
<el-form-item label="劳务日期锁定">
<el-radio-group v-model="lockedLw">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label-width="0px">
<el-tag type="warning">选择是则本月其他造单批次无法指定到当前月份如需解锁请前往薪资导出记录删除记录即可</el-tag>
</el-form-item>
</el-form>
<template #footer>
<span v-if="showBtn" class="dialog-footer">
<el-button @click="visible = false"> </el-button>
<el-button type="primary" @click="exportSalaryData" :loading="btnLoading"> </el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useMessage } from '/@/hooks/message'
import { Session } from '/@/utils/storage'
import request from '/@/utils/request'
import { ref } from 'vue';
import { useMessage } from '/@/hooks/message';
import { Session } from '/@/utils/storage';
import request from '/@/utils/request';
// 消息提示
const message = useMessage()
const message = useMessage();
// 对话框显示状态
const visible = ref(false)
const visible = ref(false);
// 表单数据
const chooseDate = ref('')
const showBtn = ref(false)
const btnLoading = ref(false)
const lockedLw = ref(1)
const chooseDate = ref('');
const showBtn = ref(false);
const btnLoading = ref(false);
const lockedLw = ref(1);
// 初始化
const init = () => {
chooseDate.value = ''
showBtn.value = false
btnLoading.value = false
lockedLw.value = 1
visible.value = true
}
chooseDate.value = '';
showBtn.value = false;
btnLoading.value = false;
lockedLw.value = 1;
visible.value = true;
};
// 日期改变
const handleChange = () => {
if (chooseDate.value) {
showBtn.value = true
} else {
showBtn.value = false
}
}
if (chooseDate.value) {
showBtn.value = true;
} else {
showBtn.value = false;
}
};
// 下载文件
const downLoadFile = async (url: string) => {
return request({
method: 'get',
url: url,
responseType: 'blob',
headers: {
'Content-Type': 'application/json',
"Authorization": 'Bearer ' + Session.getToken()
}
})
}
return request({
method: 'get',
url: url,
responseType: 'blob',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + Session.getToken(),
},
});
};
// 导出薪资数据
const exportSalaryData = async () => {
if (!chooseDate.value) {
message.warning('请选择日期')
return
}
btnLoading.value = true
try {
const res = await downLoadFile(`/professional/file/exportSalary?chooseDate=${chooseDate.value}&state=${lockedLw.value}`)
// 处理返回的文件流
const blob = new Blob([res.data])
const elink = document.createElement('a')
elink.download = "薪资表.xls"
elink.style.display = 'none'
elink.href = URL.createObjectURL(blob)
document.body.appendChild(elink)
elink.click()
URL.revokeObjectURL(elink.href) // 释放URL 对象
document.body.removeChild(elink)
message.success('导出成功')
visible.value = false
} catch (error: any) {
message.error(error?.msg || '导出失败')
} finally {
btnLoading.value = false
}
}
if (!chooseDate.value) {
message.warning('请选择日期');
return;
}
btnLoading.value = true;
try {
const res = await downLoadFile(`/professional/file/exportSalary?chooseDate=${chooseDate.value}&state=${lockedLw.value}`);
// 处理返回的文件流
const blob = new Blob([res.data]);
const elink = document.createElement('a');
elink.download = '薪资表.xls';
elink.style.display = 'none';
elink.href = URL.createObjectURL(blob);
document.body.appendChild(elink);
elink.click();
URL.revokeObjectURL(elink.href); // 释放URL 对象
document.body.removeChild(elink);
message.success('导出成功');
visible.value = false;
} catch (error: any) {
message.error(error?.msg || '导出失败');
} finally {
btnLoading.value = false;
}
};
// 暴露方法
defineExpose({
init
})
init,
});
</script>
<style scoped>
</style>
<style scoped></style>

View File

@@ -1,170 +1,165 @@
<template>
<el-dialog v-model="visible" title="薪资导入" width="600px" :close-on-click-modal="false" destroy-on-close>
<el-form label-width="100px">
<el-form-item label="日期">
<el-date-picker
v-model="chooseDate"
type="month"
format="YYYY-M"
value-format="YYYY-M"
placeholder="请选择日期"
@change="handleChange"
style="width: 100%"
/>
</el-form-item>
<el-form-item>
<el-upload
v-if="showUpload"
:headers="headers"
class="upload-demo"
:action="url"
:limit="1"
:with-credentials="true"
:before-upload="beforeUpload"
>
<template #tip>
<div class="el-upload-list__item-name">{{ fileName }}</div>
</template>
<el-button
v-if="hasAuth('professional_salary_import')"
size="small"
type="primary">选择文件
</el-button>
</el-upload>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false"> </el-button>
<el-button type="primary" @click="submitUpload" :loading="btnLoading">导入</el-button>
</span>
</template>
</el-dialog>
<el-dialog v-model="visible" title="薪资导入" width="600px" :close-on-click-modal="false" destroy-on-close>
<el-form label-width="100px">
<el-form-item label="日期">
<el-date-picker
v-model="chooseDate"
type="month"
format="YYYY-M"
value-format="YYYY-M"
placeholder="请选择日期"
@change="handleChange"
style="width: 100%"
/>
</el-form-item>
<el-form-item>
<el-upload
v-if="showUpload"
:headers="headers"
class="upload-demo"
:action="url"
:limit="1"
:with-credentials="true"
:before-upload="beforeUpload"
>
<template #tip>
<div class="el-upload-list__item-name">{{ fileName }}</div>
</template>
<el-button v-if="hasAuth('professional_salary_import')" size="small" type="primary">选择文件 </el-button>
</el-upload>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false"> </el-button>
<el-button type="primary" @click="submitUpload" :loading="btnLoading">导入</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { useAuth } from '/@/hooks/auth'
import { useMessage } from '/@/hooks/message'
import { Session } from '/@/utils/storage'
import request from '/@/utils/request'
import { ref, computed } from 'vue';
import { useAuth } from '/@/hooks/auth';
import { useMessage } from '/@/hooks/message';
import { Session } from '/@/utils/storage';
import request from '/@/utils/request';
// Emits
const emit = defineEmits<{
(e: 'refreshData'): void
}>()
(e: 'refreshData'): void;
}>();
const { hasAuth } = useAuth()
const { hasAuth } = useAuth();
// 消息提示
const message = useMessage()
const message = useMessage();
// 对话框显示状态
const visible = ref(false)
const visible = ref(false);
// 表单数据
const chooseDate = ref('')
const url = ref('')
const showUpload = ref(false)
const fileList = ref<any[]>([])
const btnLoading = ref(false)
const fileName = ref('')
const files = ref<File | null>(null)
const chooseDate = ref('');
const url = ref('');
const showUpload = ref(false);
const fileList = ref<any[]>([]);
const btnLoading = ref(false);
const fileName = ref('');
const files = ref<File | null>(null);
// 请求头
const headers = computed(() => {
return {
"Authorization": 'Bearer ' + Session.getToken()
}
})
return {
Authorization: 'Bearer ' + Session.getToken(),
};
});
// 日期改变
const handleChange = () => {
if (chooseDate.value) {
showUpload.value = true
url.value = `/professional/file/importTeacherPayslpi?chooseDate=${chooseDate.value}`
} else {
showUpload.value = false
}
}
if (chooseDate.value) {
showUpload.value = true;
url.value = `/professional/file/importTeacherPayslpi?chooseDate=${chooseDate.value}`;
} else {
showUpload.value = false;
}
};
// 初始化
const init = () => {
fileList.value = []
files.value = null
fileName.value = ''
chooseDate.value = ''
showUpload.value = false
visible.value = true
}
fileList.value = [];
files.value = null;
fileName.value = '';
chooseDate.value = '';
showUpload.value = false;
visible.value = true;
};
// 上传前验证
const beforeUpload = (file: File) => {
files.value = file
const fileLast = file.name.split('.')
const extension = fileLast[fileLast.length - 1] === 'xls'
const extension2 = fileLast[fileLast.length - 1] === 'xlsx'
const isLt2M = file.size / 1024 / 1024 < 20
if (!extension && !extension2) {
message.warning('上传模板只能是 xls、xlsx格式!')
return false
}
if (!isLt2M) {
message.warning('上传模板大小不能超过 20MB!')
return false
}
fileName.value = file.name
return false // 返回false不会自动上传
}
files.value = file;
const fileLast = file.name.split('.');
const extension = fileLast[fileLast.length - 1] === 'xls';
const extension2 = fileLast[fileLast.length - 1] === 'xlsx';
const isLt2M = file.size / 1024 / 1024 < 20;
if (!extension && !extension2) {
message.warning('上传模板只能是 xls、xlsx格式!');
return false;
}
if (!isLt2M) {
message.warning('上传模板大小不能超过 20MB!');
return false;
}
fileName.value = file.name;
return false; // 返回false不会自动上传
};
// 导入提交
const submitUpload = async () => {
btnLoading.value = true
if (fileName.value === "") {
message.warning('请选择要上传的文件!')
btnLoading.value = false
return
}
if (!files.value) {
message.warning('请选择要上传的文件!')
btnLoading.value = false
return
}
const fileFormData = new FormData()
fileFormData.append('file', files.value, fileName.value)
try {
const res = await request({
url: url.value,
method: 'post',
data: fileFormData,
headers: {
'Content-Type': 'multipart/form-data'
}
})
if (res.data.data && res.data.data.code == 1) {
message.error(`导入失败,${res.data.data.title}: ${res.data.data.msg}`)
} else {
message.success("导入成功")
visible.value = false
emit('refreshData')
}
} catch (error: any) {
message.error(error?.msg || '导入失败')
} finally {
btnLoading.value = false
}
}
btnLoading.value = true;
if (fileName.value === '') {
message.warning('请选择要上传的文件!');
btnLoading.value = false;
return;
}
if (!files.value) {
message.warning('请选择要上传的文件!');
btnLoading.value = false;
return;
}
const fileFormData = new FormData();
fileFormData.append('file', files.value, fileName.value);
try {
const res = await request({
url: url.value,
method: 'post',
data: fileFormData,
headers: {
'Content-Type': 'multipart/form-data',
},
});
if (res.data.data && res.data.data.code == 1) {
message.error(`导入失败,${res.data.data.title}: ${res.data.data.msg}`);
} else {
message.success('导入成功');
visible.value = false;
emit('refreshData');
}
} catch (error: any) {
message.error(error?.msg || '导入失败');
} finally {
btnLoading.value = false;
}
};
// 暴露方法
defineExpose({
init
})
init,
});
</script>
<style scoped>
</style>
<style scoped></style>

View File

@@ -1,172 +1,167 @@
<template>
<el-dialog v-model="visible" title="税金导入" width="600px" :close-on-click-modal="false" destroy-on-close>
<el-form label-width="100px">
<el-form-item label="日期">
<el-date-picker
v-model="chooseDate"
type="month"
format="YYYY-M"
value-format="YYYY-M"
placeholder="请选择日期"
@change="handleChange"
style="width: 100%"
/>
</el-form-item>
<el-form-item>
<el-upload
v-if="showUpload"
:headers="headers"
class="upload-demo"
:action="url"
:limit="1"
:with-credentials="true"
:before-upload="beforeUpload"
>
<template #tip>
<div class="el-upload-list__item-name">{{ fileName }}</div>
</template>
<el-button
v-if="hasAuth('professional_salary_import')"
size="small"
type="primary">选择文件
</el-button>
</el-upload>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false"> </el-button>
<el-button type="primary" @click="submitUpload" :loading="btnLoading">导入</el-button>
</span>
</template>
</el-dialog>
<el-dialog v-model="visible" title="税金导入" width="600px" :close-on-click-modal="false" destroy-on-close>
<el-form label-width="100px">
<el-form-item label="日期">
<el-date-picker
v-model="chooseDate"
type="month"
format="YYYY-M"
value-format="YYYY-M"
placeholder="请选择日期"
@change="handleChange"
style="width: 100%"
/>
</el-form-item>
<el-form-item>
<el-upload
v-if="showUpload"
:headers="headers"
class="upload-demo"
:action="url"
:limit="1"
:with-credentials="true"
:before-upload="beforeUpload"
>
<template #tip>
<div class="el-upload-list__item-name">{{ fileName }}</div>
</template>
<el-button v-if="hasAuth('professional_salary_import')" size="small" type="primary">选择文件 </el-button>
</el-upload>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false"> </el-button>
<el-button type="primary" @click="submitUpload" :loading="btnLoading">导入</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { useAuth } from '/@/hooks/auth'
import { useMessage } from '/@/hooks/message'
import { Session } from '/@/utils/storage'
import request from '/@/utils/request'
import { ref, computed } from 'vue';
import { useAuth } from '/@/hooks/auth';
import { useMessage } from '/@/hooks/message';
import { Session } from '/@/utils/storage';
import request from '/@/utils/request';
// Emits
const emit = defineEmits<{
(e: 'refreshData'): void
}>()
(e: 'refreshData'): void;
}>();
// 无权限即无节点
const { hasAuth } = useAuth()
const { hasAuth } = useAuth();
// 消息提示
const message = useMessage()
const message = useMessage();
// 对话框显示状态
const visible = ref(false)
const visible = ref(false);
// 表单数据
const chooseDate = ref('')
const url = ref('')
const showUpload = ref(false)
const fileList = ref<any[]>([])
const btnLoading = ref(false)
const fileName = ref('')
const files = ref<File | null>(null)
const chooseDate = ref('');
const url = ref('');
const showUpload = ref(false);
const fileList = ref<any[]>([]);
const btnLoading = ref(false);
const fileName = ref('');
const files = ref<File | null>(null);
// 请求头
const headers = computed(() => {
return {
"Authorization": 'Bearer ' + Session.getToken()
}
})
return {
Authorization: 'Bearer ' + Session.getToken(),
};
});
// 日期改变
const handleChange = () => {
if (chooseDate.value) {
showUpload.value = true
url.value = `/professional/file/importTaxSalary?chooseDate=${chooseDate.value}`
} else {
showUpload.value = false
}
}
if (chooseDate.value) {
showUpload.value = true;
url.value = `/professional/file/importTaxSalary?chooseDate=${chooseDate.value}`;
} else {
showUpload.value = false;
}
};
// 初始化
const init = () => {
fileList.value = []
files.value = null
fileName.value = ''
chooseDate.value = ''
showUpload.value = false
visible.value = true
}
fileList.value = [];
files.value = null;
fileName.value = '';
chooseDate.value = '';
showUpload.value = false;
visible.value = true;
};
// 上传前验证
const beforeUpload = (file: File) => {
files.value = file
const fileLast = file.name.split('.')
const extension = fileLast[fileLast.length - 1] === 'xls'
const extension2 = fileLast[fileLast.length - 1] === 'xlsx'
const isLt2M = file.size / 1024 / 1024 < 20
if (!extension && !extension2) {
message.warning('上传模板只能是 xls、xlsx格式!')
return false
}
if (!isLt2M) {
message.warning('上传模板大小不能超过 20MB!')
return false
}
fileName.value = file.name
return false // 返回false不会自动上传
}
files.value = file;
const fileLast = file.name.split('.');
const extension = fileLast[fileLast.length - 1] === 'xls';
const extension2 = fileLast[fileLast.length - 1] === 'xlsx';
const isLt2M = file.size / 1024 / 1024 < 20;
if (!extension && !extension2) {
message.warning('上传模板只能是 xls、xlsx格式!');
return false;
}
if (!isLt2M) {
message.warning('上传模板大小不能超过 20MB!');
return false;
}
fileName.value = file.name;
return false; // 返回false不会自动上传
};
// 导入提交
const submitUpload = async () => {
btnLoading.value = true
if (fileName.value === "") {
message.warning('请选择要上传的文件!')
btnLoading.value = false
return
}
if (!files.value) {
message.warning('请选择要上传的文件!')
btnLoading.value = false
return
}
const fileFormData = new FormData()
fileFormData.append('file', files.value, fileName.value)
try {
const res = await request({
url: url.value,
method: 'post',
data: fileFormData,
headers: {
'Content-Type': 'multipart/form-data'
}
})
if (res.data.data && res.data.data.code == 1) {
message.error(`导入失败,${res.data.data.title}: ${res.data.data.msg}`)
} else {
message.success("导入成功")
visible.value = false
emit('refreshData')
}
} catch (error: any) {
message.error(error?.msg || '导入失败')
} finally {
btnLoading.value = false
}
}
btnLoading.value = true;
if (fileName.value === '') {
message.warning('请选择要上传的文件!');
btnLoading.value = false;
return;
}
if (!files.value) {
message.warning('请选择要上传的文件!');
btnLoading.value = false;
return;
}
const fileFormData = new FormData();
fileFormData.append('file', files.value, fileName.value);
try {
const res = await request({
url: url.value,
method: 'post',
data: fileFormData,
headers: {
'Content-Type': 'multipart/form-data',
},
});
if (res.data.data && res.data.data.code == 1) {
message.error(`导入失败,${res.data.data.title}: ${res.data.data.msg}`);
} else {
message.success('导入成功');
visible.value = false;
emit('refreshData');
}
} catch (error: any) {
message.error(error?.msg || '导入失败');
} finally {
btnLoading.value = false;
}
};
// 暴露方法
defineExpose({
init
})
init,
});
</script>
<style scoped>
</style>
<style scoped></style>

View File

@@ -1,364 +1,295 @@
<template>
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<!-- 搜索表单 -->
<search-form
v-show="showSearch"
:model="search"
ref="searchFormRef"
@keyup-enter="handleFilter"
>
<template #default="{ visible }">
<template v-if="visible">
<el-form-item label="工号" prop="teacherNo">
<el-input
v-model="search.teacherNo"
placeholder="请输入工号"
clearable
/>
</el-form-item>
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<!-- 搜索表单 -->
<search-form v-show="showSearch" :model="search" ref="searchFormRef" @keyup-enter="handleFilter">
<template #default="{ visible }">
<template v-if="visible">
<el-form-item label="工号" prop="teacherNo">
<el-input v-model="search.teacherNo" placeholder="请输入工号" clearable />
</el-form-item>
<el-form-item label="姓名" prop="realName">
<el-input
v-model="search.realName"
placeholder="请输入姓名"
clearable
/>
</el-form-item>
<el-form-item label="姓名" prop="realName">
<el-input v-model="search.realName" placeholder="请输入姓名" clearable />
</el-form-item>
<el-form-item label="身份证号" prop="idCard">
<el-input
v-model="search.idCard"
placeholder="请输入身份证号"
clearable
/>
</el-form-item>
<el-form-item label="身份证号" prop="idCard">
<el-input v-model="search.idCard" placeholder="请输入身份证号" clearable />
</el-form-item>
<el-form-item label="年份" prop="nf">
<el-date-picker
v-model="search.nf"
type="year"
format="YYYY"
value-format="YYYY"
placeholder="请选择年份"
clearable
/>
</el-form-item>
<el-form-item label="年份" prop="nf">
<el-date-picker v-model="search.nf" type="year" format="YYYY" value-format="YYYY" placeholder="请选择年份" clearable />
</el-form-item>
<el-form-item label="月份" prop="yf">
<el-date-picker
v-model="search.yf"
type="month"
format="M"
value-format="M"
placeholder="请选择月份"
clearable
/>
</el-form-item>
<el-form-item label="月份" prop="yf">
<el-date-picker v-model="search.yf" type="month" format="M" value-format="M" placeholder="请选择月份" clearable />
</el-form-item>
<el-form-item label="岗位级别" prop="stationTypeId">
<el-select
v-model="search.stationTypeId"
filterable
clearable
placeholder="请选择岗位级别"
>
<el-option
v-for="item in stationLevelList"
:key="item.id"
:label="item.levelName"
:value="item.id"
/>
</el-select>
</el-form-item>
</template>
</template>
<el-form-item label="岗位级别" prop="stationTypeId">
<el-select v-model="search.stationTypeId" filterable clearable placeholder="请选择岗位级别">
<el-option v-for="item in stationLevelList" :key="item.id" :label="item.levelName" :value="item.id" />
</el-select>
</el-form-item>
</template>
</template>
<!-- 查询和重置按钮 -->
<template #actions>
<el-form-item>
<el-button type="primary" @click="handleFilter" icon="Search">查询</el-button>
<el-button @click="resetQuery" icon="Refresh">重置</el-button>
</el-form-item>
</template>
</search-form>
<!-- 查询和重置按钮 -->
<template #actions>
<el-form-item>
<el-button type="primary" @click="handleFilter" icon="Search">查询</el-button>
<el-button @click="resetQuery" icon="Refresh">重置</el-button>
</el-form-item>
</template>
</search-form>
<!-- 操作按钮 -->
<el-row>
<div class="mb15">
<el-button
v-if="hasAuth('professional_salary_import')"
type="primary"
plain
icon="UploadFilled"
@click="handleImportBaseSalary">工资条导入
</el-button>
<el-button
v-if="hasAuth('professional_seach_auth')"
icon="View"
class="ml10"
@click="canSearch(1)">设置可查询
</el-button>
<el-button
v-if="hasAuth('professional_seach_auth')"
icon="Hide"
class="ml10"
@click="canSearch(0)">设置不可查询
</el-button>
<el-button
v-if="hasAuth('professional_professionalsalaries_del')"
type="danger"
plain
icon="Delete"
class="ml10"
@click="delbatch">批量删除
</el-button>
</div>
</el-row>
<!-- 操作按钮 -->
<el-row>
<div class="mb15">
<el-button v-if="hasAuth('professional_salary_import')" type="primary" plain icon="UploadFilled" @click="handleImportBaseSalary"
>工资条导入
</el-button>
<el-button v-if="hasAuth('professional_seach_auth')" icon="View" class="ml10" @click="canSearch(1)">设置可查询 </el-button>
<el-button v-if="hasAuth('professional_seach_auth')" icon="Hide" class="ml10" @click="canSearch(0)">设置不可查询 </el-button>
<el-button v-if="hasAuth('professional_professionalsalaries_del')" type="danger" plain icon="Delete" class="ml10" @click="delbatch"
>批量删除
</el-button>
</div>
</el-row>
<!-- 表格 -->
<el-table
ref="tableRef"
:data="state.dataList"
row-key="id"
v-loading="state.loading"
border
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
class="data-table"
@selection-change="selectionChange"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column type="index" label="序号" width="60" align="center" />
<!-- 表格 -->
<el-table
ref="tableRef"
:data="state.dataList"
row-key="id"
v-loading="state.loading"
border
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
class="data-table"
@selection-change="selectionChange"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="姓名/工号" min-width="150" align="center">
<template #default="scope">
<TeacherNameNo :name="scope.row.realName" :no="scope.row.teacherNo" />
</template>
</el-table-column>
<el-table-column prop="postSalary" label="岗位工资" min-width="120" align="center" show-overflow-tooltip />
<el-table-column prop="nf" label="年份" width="100" align="center" />
<el-table-column prop="yf" label="月份" width="100" align="center" />
<el-table-column prop="idCard" label="身份证号" min-width="180" align="center" show-overflow-tooltip />
<el-table-column prop="shouldPay" label="应发工资" min-width="120" align="center" show-overflow-tooltip />
<el-table-column prop="realWage" label="实发工资" width="120" align="center" show-overflow-tooltip />
<el-table-column prop="normalView" label="职工查看" width="120" align="center">
<template #default="scope">
<el-tag :type="scope.row.normalView === '1' ? 'success' : 'info'">
{{ scope.row.normalView === '1' ? '可查询' : '不可查询' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" min-width="150" align="center" fixed="right">
<template #default="scope">
<el-button
icon="document"
link
type="primary"
@click="handleEdit(scope.row)">查看
</el-button>
</template>
</el-table-column>
</el-table>
<el-table-column type="index" label="号" width="60" align="center" />
<!-- 分页 -->
<pagination
v-bind="state.pagination"
@current-change="currentChangeHandle"
@size-change="sizeChangeHandle"
/>
<el-table-column label="姓名/工号" min-width="150" align="center">
<template #default="scope">
<TeacherNameNo :name="scope.row.realName" :no="scope.row.teacherNo" />
</template>
</el-table-column>
<!-- 子组件 -->
<salary-info ref="salaryInfoRef" />
<import-base-salary ref="importBaseSalaryRef" @refreshData="handleFilter" />
<export-base-salary ref="exportBaseSalaryRef" />
</div>
</div>
<el-table-column prop="postSalary" label="岗位工资" min-width="120" align="center" show-overflow-tooltip />
<el-table-column prop="nf" label="年份" width="100" align="center" />
<el-table-column prop="yf" label="月份" width="100" align="center" />
<el-table-column prop="idCard" label="身份证号" min-width="180" align="center" show-overflow-tooltip />
<el-table-column prop="shouldPay" label="应发工资" min-width="120" align="center" show-overflow-tooltip />
<el-table-column prop="realWage" label="实发工资" width="120" align="center" show-overflow-tooltip />
<el-table-column prop="normalView" label="职工查看" width="120" align="center">
<template #default="scope">
<el-tag :type="scope.row.normalView === '1' ? 'success' : 'info'">
{{ scope.row.normalView === '1' ? '可查询' : '不可查询' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" min-width="150" align="center" fixed="right">
<template #default="scope">
<el-button icon="document" link type="primary" @click="handleEdit(scope.row)">查看 </el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination v-bind="state.pagination" @current-change="currentChangeHandle" @size-change="sizeChangeHandle" />
<!-- 子组件 -->
<salary-info ref="salaryInfoRef" />
<import-base-salary ref="importBaseSalaryRef" @refreshData="handleFilter" />
<export-base-salary ref="exportBaseSalaryRef" />
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { defineAsyncComponent } from 'vue'
import { BasicTableProps, useTable } from '/@/hooks/table'
import { useAuth } from '/@/hooks/auth'
import { useMessage, useMessageBox } from '/@/hooks/message'
import { fetchList, delBatch, setCanSearch } from '/@/api/professional/salaries/teacherpayslip'
import { checkAuth } from '/@/api/professional/salaries/teachersalary'
import { getStationLevelList } from '/@/api/professional/professionalstationlevelconfig'
const SalaryInfo = defineAsyncComponent(() => import('./salaryInfo.vue'))
const ImportBaseSalary = defineAsyncComponent(() => import('./importBaseSalary.vue'))
const ExportBaseSalary = defineAsyncComponent(() => import('./exportBaseSalary.vue'))
import { ref, reactive, onMounted } from 'vue';
import { defineAsyncComponent } from 'vue';
import { BasicTableProps, useTable } from '/@/hooks/table';
import { useAuth } from '/@/hooks/auth';
import { useMessage, useMessageBox } from '/@/hooks/message';
import { fetchList, delBatch, setCanSearch } from '/@/api/professional/salaries/teacherpayslip';
import { checkAuth } from '/@/api/professional/salaries/teachersalary';
import { getStationLevelList } from '/@/api/professional/professionalstationlevelconfig';
const SalaryInfo = defineAsyncComponent(() => import('./salaryInfo.vue'));
const ImportBaseSalary = defineAsyncComponent(() => import('./importBaseSalary.vue'));
const ExportBaseSalary = defineAsyncComponent(() => import('./exportBaseSalary.vue'));
const TeacherNameNo = defineAsyncComponent(() => import('/@/components/TeacherNameNo/index.vue'))
const TeacherNameNo = defineAsyncComponent(() => import('/@/components/TeacherNameNo/index.vue'));
// 无权限即无节点
const { hasAuth } = useAuth()
const { hasAuth } = useAuth();
// 消息提示 hooks
const message = useMessage()
const messageBox = useMessageBox()
const message = useMessage();
const messageBox = useMessageBox();
// 表格引用
const tableRef = ref()
const searchFormRef = ref()
const salaryInfoRef = ref()
const importBaseSalaryRef = ref()
const exportBaseSalaryRef = ref()
const tableRef = ref();
const searchFormRef = ref();
const salaryInfoRef = ref();
const importBaseSalaryRef = ref();
const exportBaseSalaryRef = ref();
// 搜索表单显示状态
const showSearch = ref(true)
const showSearch = ref(true);
// 岗位类别列表
const stationLevelList = ref<any[]>([])
const stationLevelList = ref<any[]>([]);
// 选中的行
const selectList = ref<any[]>([])
const selectList = ref<any[]>([]);
// 搜索表单数据
const search = reactive({
teacherNo: '',
realName: '',
idCard: '',
nf: '',
yf: '',
stationTypeId: '',
canSearch: 0,
selectList:[]
})
teacherNo: '',
realName: '',
idCard: '',
nf: '',
yf: '',
stationTypeId: '',
canSearch: 0,
selectList: [],
});
// 配置 useTable
const state: BasicTableProps = reactive<BasicTableProps>({
pageList: async (params: any) => {
const response = await fetchList(params)
return {
data: {
records: response.data.records || [],
total: response.data.total || 0
}
}
},
queryForm: search
})
pageList: async (params: any) => {
const response = await fetchList(params);
return {
data: {
records: response.data.records || [],
total: response.data.total || 0,
},
};
},
queryForm: search,
});
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle } = useTable(state)
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle } = useTable(state);
// 初始化
onMounted(() => {
init()
})
init();
});
// 初始化数据
const init = async () => {
try {
const [stationRes, authRes] = await Promise.all([
getStationLevelList(),
checkAuth()
])
stationLevelList.value = stationRes.data || []
// 根据权限设置表格选项(如果需要)
// if (authRes.data.data === false) {
// // 设置普通表格选项
// }
} catch (error) {
// 初始化失败
}
}
try {
const [stationRes, authRes] = await Promise.all([getStationLevelList(), checkAuth()]);
stationLevelList.value = stationRes.data || [];
// 根据权限设置表格选项(如果需要)
// if (authRes.data.data === false) {
// // 设置普通表格选项
// }
} catch (error) {
// 初始化失败
}
};
// 查询
const handleFilter = () => {
getDataList() // 查询后跳转到第一页
}
getDataList(); // 查询后跳转到第一页
};
// 重置
const resetQuery = () => {
searchFormRef.value?.formRef?.resetFields()
Object.assign(search, {
teacherNo: '',
realName: '',
idCard: '',
nf: '',
yf: '',
stationTypeId: ''
})
handleFilter()
}
searchFormRef.value?.formRef?.resetFields();
Object.assign(search, {
teacherNo: '',
realName: '',
idCard: '',
nf: '',
yf: '',
stationTypeId: '',
});
handleFilter();
};
// 选择变化
const selectionChange = (selection: any[]) => {
selectList.value = selection
}
selectList.value = selection;
};
// 查看
const handleEdit = (row: any) => {
salaryInfoRef.value?.init(row)
}
salaryInfoRef.value?.init(row);
};
// 导入工资条
const handleImportBaseSalary = () => {
importBaseSalaryRef.value?.init()
}
importBaseSalaryRef.value?.init();
};
// 批量删除
const delbatch = () => {
if (selectList.value.length === 0) {
message.warning("请至少选择一名人员")
return
}
messageBox.confirm(`确认删除当前${selectList.value.length}条记录`).then(async () => {
try {
const data = { selectList: selectList.value }
const response = await delBatch(data)
if (response.data.code == -1) {
message.error(response.data.data)
} else {
message.success("删除成功")
getDataList(false) // 删除后保持当前页
}
} catch (error: any) {
// 错误处理已在数据请求层统一处理,此处不需要提示
}
}).catch(() => {
// 用户取消
})
}
if (selectList.value.length === 0) {
message.warning('请至少选择一名人员');
return;
}
messageBox
.confirm(`确认删除当前${selectList.value.length}条记录`)
.then(async () => {
try {
const data = { selectList: selectList.value };
const response = await delBatch(data);
if (response.data.code == -1) {
message.error(response.data.data);
} else {
message.success('删除成功');
getDataList(false); // 删除后保持当前页
}
} catch (error: any) {
// 错误处理已在数据请求层统一处理,此处不需要提示
}
})
.catch(() => {
// 用户取消
});
};
// 设置可查询/不可查询
const canSearch = (val: number) => {
search.canSearch = val;
search.selectList = selectList.value;
search.canSearch=val
search.selectList=selectList.value
messageBox.confirm('确认设置?').then(async () => {
try {
await setCanSearch(search)
message.success("设置成功")
getDataList(false) // 设置后保持当前页
} catch (error: any) {
// 错误处理已在数据请求层统一处理,此处不需要提示
}
}).catch(() => {
// 用户取消
})
}
messageBox
.confirm('确认设置?')
.then(async () => {
try {
await setCanSearch(search);
message.success('设置成功');
getDataList(false); // 设置后保持当前页
} catch (error: any) {
// 错误处理已在数据请求层统一处理,此处不需要提示
}
})
.catch(() => {
// 用户取消
});
};
</script>
<style lang="scss" scoped>
.data-table {
width: 100% !important;
width: 100% !important;
}
</style>

View File

@@ -1,571 +1,528 @@
<template>
<el-dialog
v-model="visible"
width="95%"
v-loading="baseLoading"
top="2vh"
:close-on-click-modal="false"
destroy-on-close
class="salary-info-dialog"
>
<div class="salary-info-container">
<!--基本信息-->
<div class="base-info-section">
<div class="base-info-content">
<div class="info-group">
<div class="info-item">
<span class="info-label">姓名</span>
<el-tag v-if="salaryData.baseInfo[0]?.realName">{{ salaryData.baseInfo[0].realName }}</el-tag>
<span v-else class="info-value">-</span>
</div>
<div class="info-item">
<span class="info-label">身份证号</span>
<el-tag v-if="salaryData.baseInfo[0]?.idCard">{{ salaryData.baseInfo[0].idCard }}</el-tag>
<span v-else class="info-value">-</span>
</div>
</div>
<el-form :model="nowUser" :inline="true" class="search-form">
<el-form-item label="年份">
<el-date-picker
v-model="nowUser.nf"
type="year"
format="YYYY"
value-format="YYYY"
placeholder="选择年"
style="width: 150px">
</el-date-picker>
</el-form-item>
<el-form-item label="月份">
<el-date-picker
v-model="nowUser.yff"
type="month"
format="M"
value-format="M"
placeholder="选择月"
style="width: 150px">
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button @click="searchUserInfo" type="primary" icon="Search">
查询
</el-button>
</el-form-item>
</el-form>
</div>
</div>
<el-dialog
v-model="visible"
width="95%"
v-loading="baseLoading"
top="2vh"
:close-on-click-modal="false"
destroy-on-close
class="salary-info-dialog"
>
<div class="salary-info-container">
<!--基本信息-->
<div class="base-info-section">
<div class="base-info-content">
<div class="info-group">
<div class="info-item">
<span class="info-label">姓名</span>
<el-tag v-if="salaryData.baseInfo[0]?.realName">{{ salaryData.baseInfo[0].realName }}</el-tag>
<span v-else class="info-value">-</span>
</div>
<div class="info-item">
<span class="info-label">身份证号</span>
<el-tag v-if="salaryData.baseInfo[0]?.idCard">{{ salaryData.baseInfo[0].idCard }}</el-tag>
<span v-else class="info-value">-</span>
</div>
</div>
<el-form :model="nowUser" :inline="true" class="search-form">
<el-form-item label="年份">
<el-date-picker v-model="nowUser.nf" type="year" format="YYYY" value-format="YYYY" placeholder="选择年" style="width: 150px">
</el-date-picker>
</el-form-item>
<el-form-item label="月份">
<el-date-picker v-model="nowUser.yff" type="month" format="M" value-format="M" placeholder="选择月" style="width: 150px">
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button @click="searchUserInfo" type="primary" icon="Search"> 查询 </el-button>
</el-form-item>
</el-form>
</div>
</div>
<el-card shadow="hover" class="info-card">
<template #header>
<div class="card-header">
<el-icon><Money /></el-icon>
<span>工资明细</span>
</div>
</template>
<!--应发部分-->
<div class="section-title">
<el-icon><TrendCharts /></el-icon>
<span>应发部分</span>
</div>
<el-table
:data="salaryData.baseInfo"
size="small"
border
class="salary-table"
style="width: 100%"
>
<el-table-column label="应发部分">
<el-table-column prop="baseSalary" label="基础专项绩效" min-width="60" align="center"></el-table-column>
<el-table-column prop="postSalary" label="岗位工资" min-width="60" align="center"></el-table-column>
<el-table-column prop="payWage" label="薪级工资" min-width="60" align="center"></el-table-column>
<el-table-column label="见习期工资" prop="studentPay" min-width="60" align="center"></el-table-column>
<el-table-column prop="liveAllowance" label="生活补贴" min-width="60" align="center"></el-table-column>
<el-table-column prop="postAllowance" label="岗位津贴" min-width="60" align="center"></el-table-column>
<el-table-column label="住房(租金)补贴" prop="houseSubsidies" min-width="60" align="center"></el-table-column>
<el-table-column label="新职工住房补贴" prop="newHouseSubsidies" min-width="60" align="center"></el-table-column>
<el-table-column label="回民补贴" prop="huiSubsidies" min-width="60" align="center"></el-table-column>
<el-table-column label="养老保险补贴" prop="oldSubsidies" min-width="60" align="center"></el-table-column>
<el-table-column label="教龄津贴" prop="ageAllowance" min-width="60" align="center"></el-table-column>
<el-table-column label="特教补贴" prop="specialSubsidies" min-width="60" align="center"></el-table-column>
<el-table-column label="特级教师津贴" prop="teacherAllowance" min-width="60" align="center"></el-table-column>
<el-table-column label="特岗津贴(一)" prop="sPostAllowance1" min-width="60" align="center"></el-table-column>
<el-table-column label="特岗津贴(二)" prop="sPostAllowance2" min-width="60" align="center"></el-table-column>
<el-table-column label="其他" prop="other" min-width="60" align="center"></el-table-column>
<el-table-column label="奖励性绩效工资" prop="meritPay" min-width="60" align="center"></el-table-column>
<el-table-column label="乡镇工作补贴" prop="villageSubsidies" min-width="60" align="center"></el-table-column>
<el-table-column label="临时性补贴" prop="temporarySubsidies" min-width="60" align="center"></el-table-column>
<el-table-column label="上下班交通补贴" prop="trafficSubsidies" min-width="60" align="center"></el-table-column>
<el-table-column label="保留津贴" prop="keepAllowance" min-width="60" align="center"></el-table-column>
<el-table-column label="补发工资" prop="retroactivePay" min-width="60" align="center"></el-table-column>
<el-table-column label="应休未休假补贴" prop="vacationMoney" min-width="60" align="center"></el-table-column>
<el-table-column label="应发工资" prop="shouldPay" min-width="60" align="center"></el-table-column>
<el-table-column label="基础专项绩效" prop="baseSalary" min-width="60" align="center"></el-table-column>
<el-table-column label="基础工资应税收入" prop="shouldTaxMoney" min-width="60" align="center"></el-table-column>
</el-table-column>
</el-table>
<div class="formula-tag">
<el-tag type="danger" size="small">基础工资应税收入= 岗位工资 +薪级工资+见习期工资+生活补贴+岗位津贴+教龄津贴+特教补贴+特级教师津贴+特岗津贴1+特岗津贴2+奖励绩效性工资+乡镇工作补贴+临时补贴+保留津贴+应休未休假-个人补缴-其他扣款-医疗救助金</el-tag>
</div>
<!--应扣部分-->
<div class="section-title">
<el-icon><Remove /></el-icon>
<span>应扣部分</span>
</div>
<el-table
size="small"
border
:data="salaryData.baseInfo"
class="salary-table"
style="width: 100%">
<el-table-column label="应扣部分">
<el-table-column label="住房公积金" min-width="90" prop="houseFund"></el-table-column>
<el-table-column label="医疗保险金" min-width="90" prop="medicalInsurance"></el-table-column>
<el-table-column label="失业保险金" min-width="90" prop="unemployInsurance"></el-table-column>
<el-table-column label="养老保险金" min-width="90" prop="endowInsurance"></el-table-column>
<el-table-column label="工会费" min-width="60" prop="unionFee"></el-table-column>
<el-table-column label="儿童统筹" min-width="90" prop="childrenWhole"></el-table-column>
<el-table-column label="个人所得税" width="90" prop="personalTax"></el-table-column>
<el-table-column label="其他扣款" min-width="90" prop="otherDeduction"></el-table-column>
<el-table-column label="病事假扣款" min-width="90" prop="sickDeduction"></el-table-column>
<el-table-column label="医疗救助基金" min-width="90" prop="medicalFund"></el-table-column>
<el-table-column label="工伤保险" min-width="90" prop="inductrialInjury"></el-table-column>
<el-table-column label="个人补缴" min-width="90" prop="personalPay"></el-table-column>
<el-table-column label="应扣合计" min-width="90" prop="withhold"></el-table-column>
</el-table-column>
</el-table>
<div class="formula-tag">
<el-tag size="small">个人所得税 = 个税计算数据中的 累计应补(退)税额 </el-tag>
</div>
<el-card shadow="hover" class="info-card">
<template #header>
<div class="card-header">
<el-icon><Money /></el-icon>
<span>工资明细</span>
</div>
</template>
<!--应发部分-->
<div class="section-title">
<el-icon><TrendCharts /></el-icon>
<span>应发部分</span>
</div>
<el-table :data="salaryData.baseInfo" size="small" border class="salary-table" style="width: 100%">
<el-table-column label="应发部分">
<el-table-column prop="baseSalary" label="基础专项绩效" min-width="60" align="center"></el-table-column>
<el-table-column prop="postSalary" label="岗位工资" min-width="60" align="center"></el-table-column>
<el-table-column prop="payWage" label="薪级工资" min-width="60" align="center"></el-table-column>
<el-table-column label="见习期工资" prop="studentPay" min-width="60" align="center"></el-table-column>
<el-table-column prop="liveAllowance" label="生活补贴" min-width="60" align="center"></el-table-column>
<el-table-column prop="postAllowance" label="岗位津贴" min-width="60" align="center"></el-table-column>
<el-table-column label="住房(租金)补贴" prop="houseSubsidies" min-width="60" align="center"></el-table-column>
<el-table-column label="新职工住房补贴" prop="newHouseSubsidies" min-width="60" align="center"></el-table-column>
<el-table-column label="回民补贴" prop="huiSubsidies" min-width="60" align="center"></el-table-column>
<el-table-column label="养老保险补贴" prop="oldSubsidies" min-width="60" align="center"></el-table-column>
<el-table-column label="教龄津贴" prop="ageAllowance" min-width="60" align="center"></el-table-column>
<el-table-column label="特教补贴" prop="specialSubsidies" min-width="60" align="center"></el-table-column>
<el-table-column label="特级教师津贴" prop="teacherAllowance" min-width="60" align="center"></el-table-column>
<el-table-column label="特岗津贴(一)" prop="sPostAllowance1" min-width="60" align="center"></el-table-column>
<el-table-column label="特岗津贴(二)" prop="sPostAllowance2" min-width="60" align="center"></el-table-column>
<el-table-column label="其他" prop="other" min-width="60" align="center"></el-table-column>
<el-table-column label="奖励性绩效工资" prop="meritPay" min-width="60" align="center"></el-table-column>
<el-table-column label="乡镇工作补贴" prop="villageSubsidies" min-width="60" align="center"></el-table-column>
<el-table-column label="临时性补贴" prop="temporarySubsidies" min-width="60" align="center"></el-table-column>
<el-table-column label="上下班交通补贴" prop="trafficSubsidies" min-width="60" align="center"></el-table-column>
<el-table-column label="保留津贴" prop="keepAllowance" min-width="60" align="center"></el-table-column>
<el-table-column label="补发工资" prop="retroactivePay" min-width="60" align="center"></el-table-column>
<el-table-column label="应休未休假补贴" prop="vacationMoney" min-width="60" align="center"></el-table-column>
<el-table-column label="应发工资" prop="shouldPay" min-width="60" align="center"></el-table-column>
<el-table-column label="基础专项绩效" prop="baseSalary" min-width="60" align="center"></el-table-column>
<el-table-column label="基础工资应税收入" prop="shouldTaxMoney" min-width="60" align="center"></el-table-column>
</el-table-column>
</el-table>
<div class="formula-tag">
<el-tag type="danger" size="small"
>基础工资应税收入= 岗位工资
+薪级工资+见习期工资+生活补贴+岗位津贴+教龄津贴+特教补贴+特级教师津贴+特岗津贴1+特岗津贴2+奖励绩效性工资+乡镇工作补贴+临时补贴+保留津贴+应休未休假-个人补缴-其他扣款-医疗救助金</el-tag
>
</div>
<!--劳务费-->
<div v-if="showAllContent" class="section-title">
<el-icon><Document /></el-icon>
<span>造单收入清单</span>
</div>
<el-table
v-if="showAllContent"
size="small"
border
:data="allProjectData"
class="salary-table"
style="width: 100%">
<el-table-column label="造单收入清单">
<el-table-column label="造单部门" prop="deptName"></el-table-column>
<el-table-column label="造单人" prop="createName"></el-table-column>
<el-table-column label="项目编号" prop="projectNo"></el-table-column>
<el-table-column label="项目名" prop="title"></el-table-column>
<el-table-column label="金额" prop="realMoney"></el-table-column>
<el-table-column label="付讫时间" prop="payTime"></el-table-column>
<el-table-column label="免税或暂不交税" prop="freeTax">
<template #default="scope">
<span v-if="scope.row.freeTax=='1'"></span>
</template>
</el-table-column>
</el-table-column>
</el-table>
<!--应扣部分-->
<div class="section-title">
<el-icon><Remove /></el-icon>
<span>应扣部分</span>
</div>
<el-table size="small" border :data="salaryData.baseInfo" class="salary-table" style="width: 100%">
<el-table-column label="应扣部分">
<el-table-column label="住房公积金" min-width="90" prop="houseFund"></el-table-column>
<el-table-column label="医疗保险金" min-width="90" prop="medicalInsurance"></el-table-column>
<el-table-column label="失业保险金" min-width="90" prop="unemployInsurance"></el-table-column>
<el-table-column label="养老保险金" min-width="90" prop="endowInsurance"></el-table-column>
<el-table-column label="工会费" min-width="60" prop="unionFee"></el-table-column>
<el-table-column label="儿童统筹" min-width="90" prop="childrenWhole"></el-table-column>
<el-table-column label="个人所得税" width="90" prop="personalTax"></el-table-column>
<el-table-column label="其他扣款" min-width="90" prop="otherDeduction"></el-table-column>
<el-table-column label="病事假扣款" min-width="90" prop="sickDeduction"></el-table-column>
<el-table-column label="医疗救助基金" min-width="90" prop="medicalFund"></el-table-column>
<el-table-column label="工伤保险" min-width="90" prop="inductrialInjury"></el-table-column>
<el-table-column label="个人补缴" min-width="90" prop="personalPay"></el-table-column>
<el-table-column label="应扣合计" min-width="90" prop="withhold"></el-table-column>
</el-table-column>
</el-table>
<div class="formula-tag">
<el-tag size="small">个人所得税 = 个税计算数据中的 累计应补(退)税额 </el-tag>
</div>
<!--专项扣除-->
<div v-if="showAllContent" class="section-title">
<el-icon><DataAnalysis /></el-icon>
<span>个税计算数据</span>
</div>
<el-table
v-if="showAllContent"
size="small"
border
:data="salaryExtendData"
class="salary-table"
style="width: 100%">
<el-table-column label="个税计算数据">
<el-table-column prop="currentIncome" label="应税收入" min-width="60" align="center"></el-table-column>
<el-table-column prop="totalIncome" label="累计收入额" min-width="60" align="center"></el-table-column>
<el-table-column prop="totalDeduction" label="累计减除费用" min-width="60" align="center"></el-table-column>
<el-table-column prop="totalSpecialDecution" label="累计专项扣除" min-width="60" align="center"></el-table-column>
<el-table-column label="累计专项扣除附加" align="center">
<el-table-column prop="totalChildEdu" label="累计子女教育" min-width="60" align="center"></el-table-column>
<el-table-column prop="totalConEdu" label="累计继续教育" min-width="60" align="center"> </el-table-column>
<el-table-column prop="totalHouseInterest" label="累计住房贷款利息" min-width="60" align="center"></el-table-column>
<el-table-column prop="totalHouse" label="累计住房租金" min-width="60" align="center"></el-table-column>
<el-table-column prop="totalSupportOld" label="累计赡养老人" min-width="60" align="center"></el-table-column>
<el-table-column prop="totalBabyMoney" label="累计婴幼儿照护费用" min-width="60" align="center"></el-table-column>
</el-table-column>
<el-table-column prop="totalTaxMoney" label="累计应纳税所得额" min-width="60" align="center"></el-table-column>
<el-table-column prop="taxRate" label="税率" min-width="60" align="center"></el-table-column>
<el-table-column prop="quickDecution" label="速算扣除数" min-width="60" align="center"></el-table-column>
<el-table-column prop="totalRealTaxPay" label="累计应扣缴税额" min-width="60" align="center"></el-table-column>
<el-table-column prop="totalPrePayTax" label="累计已预缴税额" min-width="60" align="center"></el-table-column>
<el-table-column prop="totalRetrieveTax" label="累计应补(退)税额" min-width="60" align="center"></el-table-column>
</el-table-column>
</el-table>
<div v-if="showAllContent" class="formula-tag">
<el-tag type="warning" size="small">应税收入= 基础工资应税收入+造单收入</el-tag>
<el-tag type="success" size="small" class="ml10">累计专项扣除=当年累计个人承担的住房公积金+医疗保险金+失业保险金+养老保险金</el-tag>
</div>
<!--劳务费-->
<div v-if="showAllContent" class="section-title">
<el-icon><Document /></el-icon>
<span>造单收入清单</span>
</div>
<el-table v-if="showAllContent" size="small" border :data="allProjectData" class="salary-table" style="width: 100%">
<el-table-column label="造单收入清单">
<el-table-column label="造单部门" prop="deptName"></el-table-column>
<el-table-column label="造单人" prop="createName"></el-table-column>
<el-table-column label="项目编号" prop="projectNo"></el-table-column>
<el-table-column label="项目名" prop="title"></el-table-column>
<el-table-column label="金额" prop="realMoney"></el-table-column>
<el-table-column label="付讫时间" prop="payTime"></el-table-column>
<el-table-column label="免税或暂不交税" prop="freeTax">
<template #default="scope">
<span v-if="scope.row.freeTax == '1'"></span>
</template>
</el-table-column>
</el-table-column>
</el-table>
<!--实发合计-->
<div class="section-title">
<el-icon><Wallet /></el-icon>
<span>实发合计</span>
</div>
<el-table
size="small"
border
:data="[staticsData]"
class="salary-table summary-table"
empty-text=" "
style="width: 100%">
<el-table-column label="小计">
<el-table-column label="应发工资" prop="shouldPay"></el-table-column>
<el-table-column label="应扣合计" prop="shouldDedu"></el-table-column>
<el-table-column label="实发工资" prop="realWage"></el-table-column>
</el-table-column>
</el-table>
<div class="formula-tag">
<el-tag type="primary" size="small">实发工资= 应发工资-应扣合计</el-tag>
</div>
</el-card>
</div>
</el-dialog>
<!--专项扣除-->
<div v-if="showAllContent" class="section-title">
<el-icon><DataAnalysis /></el-icon>
<span>个税计算数据</span>
</div>
<el-table v-if="showAllContent" size="small" border :data="salaryExtendData" class="salary-table" style="width: 100%">
<el-table-column label="个税计算数据">
<el-table-column prop="currentIncome" label="应税收入" min-width="60" align="center"></el-table-column>
<el-table-column prop="totalIncome" label="累计收入额" min-width="60" align="center"></el-table-column>
<el-table-column prop="totalDeduction" label="累计减除费用" min-width="60" align="center"></el-table-column>
<el-table-column prop="totalSpecialDecution" label="累计专项扣除" min-width="60" align="center"></el-table-column>
<el-table-column label="累计专项扣除附加" align="center">
<el-table-column prop="totalChildEdu" label="累计子女教育" min-width="60" align="center"></el-table-column>
<el-table-column prop="totalConEdu" label="累计继续教育" min-width="60" align="center"> </el-table-column>
<el-table-column prop="totalHouseInterest" label="累计住房贷款利息" min-width="60" align="center"></el-table-column>
<el-table-column prop="totalHouse" label="累计住房租金" min-width="60" align="center"></el-table-column>
<el-table-column prop="totalSupportOld" label="累计赡养老人" min-width="60" align="center"></el-table-column>
<el-table-column prop="totalBabyMoney" label="累计婴幼儿照护费用" min-width="60" align="center"></el-table-column>
</el-table-column>
<el-table-column prop="totalTaxMoney" label="累计应纳税所得额" min-width="60" align="center"></el-table-column>
<el-table-column prop="taxRate" label="税率" min-width="60" align="center"></el-table-column>
<el-table-column prop="quickDecution" label="速算扣除数" min-width="60" align="center"></el-table-column>
<el-table-column prop="totalRealTaxPay" label="累计应扣缴税额" min-width="60" align="center"></el-table-column>
<el-table-column prop="totalPrePayTax" label="累计已预缴税额" min-width="60" align="center"></el-table-column>
<el-table-column prop="totalRetrieveTax" label="累计应补(退)税额" min-width="60" align="center"></el-table-column>
</el-table-column>
</el-table>
<div v-if="showAllContent" class="formula-tag">
<el-tag type="warning" size="small">应税收入= 基础工资应税收入+造单收入</el-tag>
<el-tag type="success" size="small" class="ml10">累计专项扣除=当年累计个人承担的住房公积金+医疗保险金+失业保险金+养老保险金</el-tag>
</div>
<!--实发合计-->
<div class="section-title">
<el-icon><Wallet /></el-icon>
<span>实发合计</span>
</div>
<el-table size="small" border :data="[staticsData]" class="salary-table summary-table" empty-text=" " style="width: 100%">
<el-table-column label="小计">
<el-table-column label="应发工资" prop="shouldPay"></el-table-column>
<el-table-column label="应扣合计" prop="shouldDedu"></el-table-column>
<el-table-column label="实发工资" prop="realWage"></el-table-column>
</el-table-column>
</el-table>
<div class="formula-tag">
<el-tag type="primary" size="small">实发工资= 应发工资-应扣合计</el-tag>
</div>
</el-card>
</div>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, nextTick } from 'vue'
import { Money, TrendCharts, Remove, Document, DataAnalysis, Wallet, Search } from '@element-plus/icons-vue'
import { useMessage } from '/@/hooks/message'
import { queryUserInfo, queryExtendSalaryInfo } from '/@/api/professional/salaries/teacherpayslip'
import { checkAuth } from '/@/api/professional/salaries/teachersalary'
import { ref, reactive, nextTick } from 'vue';
import { Money, TrendCharts, Remove, Document, DataAnalysis, Wallet, Search } from '@element-plus/icons-vue';
import { useMessage } from '/@/hooks/message';
import { queryUserInfo, queryExtendSalaryInfo } from '/@/api/professional/salaries/teacherpayslip';
import { checkAuth } from '/@/api/professional/salaries/teachersalary';
const message = useMessage()
const message = useMessage();
// 对话框显示状态
const visible = ref(false)
const visible = ref(false);
// 数据
const salaryData = reactive({
baseInfo: [] as any[]
})
baseInfo: [] as any[],
});
const nowUser = ref<any>({})
const baseLoading = ref(false)
const salaryExtendData = ref<any[]>([])
const allProjectData = ref<any[]>([])
const nowUser = ref<any>({});
const baseLoading = ref(false);
const salaryExtendData = ref<any[]>([]);
const allProjectData = ref<any[]>([]);
const staticsData = reactive({
shouldPay: 0,
shouldDedu: 0,
realWage: 0,
orderMoney: 0,
personTax: 0
})
const showAllContent = ref(false)
shouldPay: 0,
shouldDedu: 0,
realWage: 0,
orderMoney: 0,
personTax: 0,
});
const showAllContent = ref(false);
// 检查权限
const checkAuthMethod = async () => {
try {
const res = await checkAuth()
showAllContent.value = res.data
} catch (error) {
// 检查权限失败
}
}
try {
const res = await checkAuth();
showAllContent.value = res.data;
} catch (error) {
// 检查权限失败
}
};
// 构建用户信息
const makeUserInfo = (data: any) => {
const row = JSON.parse(JSON.stringify(data))
salaryData.baseInfo = []
row.realName = (row.realName == "" || row.realName == null ? row.userName : row.realName)
salaryData.baseInfo.push(row)
const row = JSON.parse(JSON.stringify(data));
salaryData.baseInfo = [];
row.realName = row.realName == '' || row.realName == null ? row.userName : row.realName;
salaryData.baseInfo.push(row);
staticsData.shouldPay = row.shouldPay || 0
staticsData.shouldDedu = row.withhold || 0
staticsData.realWage = row.realWage || 0
staticsData.personTax = (row.personalTax as number) || 0
}
staticsData.shouldPay = row.shouldPay || 0;
staticsData.shouldDedu = row.withhold || 0;
staticsData.realWage = row.realWage || 0;
staticsData.personTax = (row.personalTax as number) || 0;
};
// 查询扩展薪资信息
const queryExtendSalaryInfoMethod = async (row: any) => {
salaryExtendData.value = []
const params = { nf: row.nf, yf: row.yf, teacherNo: row.teacherNo }
try {
const res = await queryExtendSalaryInfo(params)
salaryExtendData.value.push(res.data.salaryTax)
allProjectData.value = res.data.allProject
staticsData.orderMoney = res.data.totalMoney
} catch (error) {
// 查询失败
}
}
salaryExtendData.value = [];
const params = { nf: row.nf, yf: row.yf, teacherNo: row.teacherNo };
try {
const res = await queryExtendSalaryInfo(params);
salaryExtendData.value.push(res.data.salaryTax);
allProjectData.value = res.data.allProject;
staticsData.orderMoney = res.data.totalMoney;
} catch (error) {
// 查询失败
}
};
// 搜索用户信息
const searchUserInfo = async () => {
if (!nowUser.value.idCard) {
message.warning('请输入身份证号')
return
}
if (!nowUser.value.nf) {
message.warning('请选择年份')
return
}
if (!nowUser.value.yff) {
message.warning('请选择月份')
return
}
if (!nowUser.value.idCard) {
message.warning('请输入身份证号');
return;
}
if (!nowUser.value.nf) {
message.warning('请选择年份');
return;
}
if (!nowUser.value.yff) {
message.warning('请选择月份');
return;
}
baseLoading.value = true
const data = { idCard: nowUser.value.idCard, nf: nowUser.value.nf, yf: nowUser.value.yff }
try {
const response = await queryUserInfo(data)
if (response.data.data == null) {
message.info('未查询到该时间段的数据')
salaryData.baseInfo = []
const obj: any = {}
obj.realName = nowUser.value.realName
obj.idCard = nowUser.value.idCard
salaryData.baseInfo.push(obj)
baseLoading.value = true;
const data = { idCard: nowUser.value.idCard, nf: nowUser.value.nf, yf: nowUser.value.yff };
try {
const response = await queryUserInfo(data);
if (response.data.data == null) {
message.info('未查询到该时间段的数据');
salaryData.baseInfo = [];
const obj: any = {};
obj.realName = nowUser.value.realName;
obj.idCard = nowUser.value.idCard;
salaryData.baseInfo.push(obj);
salaryExtendData.value = []
Object.assign(staticsData, {
shouldPay: 0,
shouldDedu: 0,
realWage: 0,
orderMoney: 0,
personTax: 0
})
} else {
const resData = response.data.data
resData.realName = nowUser.value.realName
resData.nf = nowUser.value.nf
resData.yf = nowUser.value.yff
resData.teacherNo = nowUser.value.teacherNo
makeUserInfo(resData)
await queryExtendSalaryInfoMethod(resData)
message.success('查询成功')
}
} catch (error: any) {
message.error(error?.msg || '查询失败')
} finally {
baseLoading.value = false
}
}
salaryExtendData.value = [];
Object.assign(staticsData, {
shouldPay: 0,
shouldDedu: 0,
realWage: 0,
orderMoney: 0,
personTax: 0,
});
} else {
const resData = response.data.data;
resData.realName = nowUser.value.realName;
resData.nf = nowUser.value.nf;
resData.yf = nowUser.value.yff;
resData.teacherNo = nowUser.value.teacherNo;
makeUserInfo(resData);
await queryExtendSalaryInfoMethod(resData);
message.success('查询成功');
}
} catch (error: any) {
message.error(error?.msg || '查询失败');
} finally {
baseLoading.value = false;
}
};
// 初始化
const init = (row: any) => {
visible.value = true
nextTick(() => {
checkAuthMethod()
nowUser.value = JSON.parse(JSON.stringify(row))
nowUser.value.yff = row.yf
makeUserInfo(row)
queryExtendSalaryInfoMethod(row)
})
}
visible.value = true;
nextTick(() => {
checkAuthMethod();
nowUser.value = JSON.parse(JSON.stringify(row));
nowUser.value.yff = row.yf;
makeUserInfo(row);
queryExtendSalaryInfoMethod(row);
});
};
// 暴露方法
defineExpose({
init
})
init,
});
</script>
<style lang="scss" scoped>
.salary-info-dialog {
:deep(.el-dialog__body) {
padding: 10px !important;
max-height: calc(100vh - 120px);
overflow-y: auto;
}
:deep(.el-dialog__body) {
padding: 10px !important;
max-height: calc(100vh - 120px);
overflow-y: auto;
}
}
.salary-info-container {
display: flex;
flex-direction: column;
gap: 20px;
display: flex;
flex-direction: column;
gap: 20px;
}
.section-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 16px;
padding-bottom: 12px;
border-bottom: 1px solid #ebeef5;
font-size: 16px;
font-weight: 600;
color: #303133;
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 16px;
padding-bottom: 12px;
border-bottom: 1px solid #ebeef5;
font-size: 16px;
font-weight: 600;
color: #303133;
.el-icon {
font-size: 18px;
color: var(--el-color-primary);
}
.el-icon {
font-size: 18px;
color: var(--el-color-primary);
}
}
.section-header-inline {
display: flex;
align-items: center;
gap: 6px;
font-size: 14px;
font-weight: 600;
color: #303133;
margin-right: 16px;
display: flex;
align-items: center;
gap: 6px;
font-size: 14px;
font-weight: 600;
color: #303133;
margin-right: 16px;
.el-icon {
font-size: 16px;
color: var(--el-color-primary);
}
.el-icon {
font-size: 16px;
color: var(--el-color-primary);
}
}
.info-card {
:deep(.el-card__header) {
padding: 16px 20px;
background: #f5f7fa;
border-bottom: 1px solid #ebeef5;
}
:deep(.el-card__header) {
padding: 16px 20px;
background: #f5f7fa;
border-bottom: 1px solid #ebeef5;
}
:deep(.el-card__body) {
padding: 20px;
}
:deep(.el-card__body) {
padding: 20px;
}
}
.base-info-content {
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 16px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 16px;
}
.info-group {
display: flex;
flex-direction: row;
gap: 16px;
flex-wrap: wrap;
display: flex;
flex-direction: row;
gap: 16px;
flex-wrap: wrap;
}
.info-item {
display: flex;
// align-items: center;
gap: 6px;
display: flex;
// align-items: center;
gap: 6px;
.info-label {
font-weight: 500;
color: #606266;
font-size: 13px;
}
.info-label {
font-weight: 500;
color: #606266;
font-size: 13px;
}
.info-value {
color: #303133;
font-size: 13px;
font-weight: 500;
}
.info-value {
color: #303133;
font-size: 13px;
font-weight: 500;
}
}
.search-form {
margin-left: auto;
margin-bottom: 0;
margin-left: auto;
margin-bottom: 0;
}
.section-title {
display: flex;
align-items: center;
gap: 8px;
margin: 24px 0 12px 0;
padding-bottom: 8px;
border-bottom: 2px solid #e4e7ed;
font-size: 15px;
font-weight: 600;
color: #303133;
display: flex;
align-items: center;
gap: 8px;
margin: 24px 0 12px 0;
padding-bottom: 8px;
border-bottom: 2px solid #e4e7ed;
font-size: 15px;
font-weight: 600;
color: #303133;
.el-icon {
font-size: 16px;
color: var(--el-color-primary);
}
.el-icon {
font-size: 16px;
color: var(--el-color-primary);
}
&:first-child {
margin-top: 0;
}
&:first-child {
margin-top: 0;
}
}
.salary-table {
margin-bottom: 16px;
margin-bottom: 16px;
:deep(.el-table__header) {
th {
background: #f5f7fa;
color: #606266;
font-weight: 600;
}
}
:deep(.el-table__header) {
th {
background: #f5f7fa;
color: #606266;
font-weight: 600;
}
}
:deep(.el-table__body) {
td {
padding: 8px 0;
}
}
:deep(.el-table__body) {
td {
padding: 8px 0;
}
}
:deep(.el-table__cell) {
padding: 8px 4px;
font-size: 13px;
}
:deep(.el-table__cell) {
padding: 8px 4px;
font-size: 13px;
}
}
.summary-table {
:deep(.el-table__body) {
td {
font-weight: 600;
font-size: 14px;
color: var(--el-color-primary);
}
}
:deep(.el-table__body) {
td {
font-weight: 600;
font-size: 14px;
color: var(--el-color-primary);
}
}
}
.formula-tag {
margin-top: 12px;
margin-bottom: 8px;
line-height: 1.6;
margin-top: 12px;
margin-bottom: 8px;
line-height: 1.6;
.el-tag {
margin-right: 8px;
padding: 6px 12px;
font-size: 12px;
white-space: normal;
word-break: break-all;
}
.el-tag {
margin-right: 8px;
padding: 6px 12px;
font-size: 12px;
white-space: normal;
word-break: break-all;
}
.ml10 {
margin-left: 10px;
}
.ml10 {
margin-left: 10px;
}
}
// 响应式优化
@media (max-width: 1400px) {
.salary-info-dialog {
:deep(.el-dialog) {
width: 98% !important;
}
}
.salary-info-dialog {
:deep(.el-dialog) {
width: 98% !important;
}
}
}
// 滚动条优化
.salary-info-dialog {
:deep(.el-dialog__body) {
&::-webkit-scrollbar {
width: 8px;
height: 8px;
}
:deep(.el-dialog__body) {
&::-webkit-scrollbar {
width: 8px;
height: 8px;
}
&::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 4px;
}
&::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 4px;
}
&::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 4px;
&::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 4px;
&:hover {
background: #a8a8a8;
}
}
}
&:hover {
background: #a8a8a8;
}
}
}
}
</style>