This commit is contained in:
guochunsi
2026-01-06 19:23:18 +08:00
parent 8af3aaa9b6
commit e1cb334fbf
33 changed files with 685 additions and 329 deletions

View File

@@ -0,0 +1,122 @@
<template>
<el-dialog v-model="visible" title="薪资导出" width="500px" :close-on-click-modal="false" destroy-on-close>
<el-form label-width="120px">
<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 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>
<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'
// 消息提示
const message = useMessage()
// 对话框显示状态
const visible = ref(false)
// 表单数据
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
}
// 日期改变
const handleChange = () => {
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()
}
})
}
// 导出薪资数据
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
}
}
// 暴露方法
defineExpose({
init
})
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,183 @@
<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
size="small"
v-if="permissions.professional_salary_import"
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 { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { useMessage } from '/@/hooks/message'
import { Session } from '/@/utils/storage'
import request from '/@/utils/request'
// Emits
const emit = defineEmits<{
(e: 'refreshData'): void
}>()
// 使用 Pinia store
const userInfoStore = useUserInfo()
const { userInfos } = storeToRefs(userInfoStore)
// 创建权限对象
const permissions = computed(() => {
const perms: Record<string, boolean> = {}
userInfos.value.authBtnList.forEach((perm: string) => {
perms[perm] = true
})
return perms
})
// 消息提示
const message = useMessage()
// 对话框显示状态
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 headers = computed(() => {
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
}
}
// 初始化
const init = () => {
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不会自动上传
}
// 导入提交
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
}
}
// 暴露方法
defineExpose({
init
})
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,183 @@
<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
size="small"
v-if="permissions.professional_salary_import"
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 { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { useMessage } from '/@/hooks/message'
import { Session } from '/@/utils/storage'
import request from '/@/utils/request'
// Emits
const emit = defineEmits<{
(e: 'refreshData'): void
}>()
// 使用 Pinia store
const userInfoStore = useUserInfo()
const { userInfos } = storeToRefs(userInfoStore)
// 创建权限对象
const permissions = computed(() => {
const perms: Record<string, boolean> = {}
userInfos.value.authBtnList.forEach((perm: string) => {
perms[perm] = true
})
return perms
})
// 消息提示
const message = useMessage()
// 对话框显示状态
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 headers = computed(() => {
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
}
}
// 初始化
const init = () => {
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不会自动上传
}
// 导入提交
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
}
}
// 暴露方法
defineExpose({
init
})
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,359 @@
<template>
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<!-- 操作按钮 -->
<el-row>
<div class="mb15" style="width: 100%;">
<el-button
size="small"
v-if="permissions.professional_salary_import"
type="primary"
@click="handleImportBaseSalary">工资条导入
</el-button>
<el-button
type="primary"
size="small"
v-if="permissions.professional_seach_auth"
@click="canSearch(1)">设置可查询
</el-button>
<el-button
type="primary"
size="small"
v-if="permissions.professional_seach_auth"
@click="canSearch(0)">设置不可查询
</el-button>
<el-button
type="primary"
size="small"
v-if="permissions.professional_professionalsalaries_del"
@click="delbatch">批量删除
</el-button>
</div>
</el-row>
<!-- 搜索表单 -->
<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
style="width: 200px"
/>
</el-form-item>
<el-form-item label="姓名" prop="realName">
<el-input
v-model="search.realName"
placeholder="请输入姓名"
clearable
style="width: 200px"
/>
</el-form-item>
<el-form-item label="身份证号" prop="idCard">
<el-input
v-model="search.idCard"
placeholder="请输入身份证号"
clearable
style="width: 200px"
/>
</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
style="width: 200px"
/>
</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
style="width: 200px"
/>
</el-form-item>
<el-form-item label="岗位类别" prop="stationTypeId">
<el-select
v-model="search.stationTypeId"
filterable
clearable
placeholder="请选择岗位类别"
style="width: 200px"
>
<el-option
v-for="item in stationLevelList"
:key="item.id"
:label="item.levelName"
:value="item.id"
/>
</el-select>
</el-form-item>
</template>
</template>
</search-form>
<!-- 表格 -->
<el-table
ref="tableRef"
:data="state.dataList"
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-column prop="numId" label="编号" width="100" align="center" show-overflow-tooltip />
<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>
<!-- 分页 -->
<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, computed, onMounted } from 'vue'
import { defineAsyncComponent } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { BasicTableProps, useTable } from '/@/hooks/table'
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'
import SalaryInfo from './salaryInfo.vue'
import ImportBaseSalary from './importBaseSalary.vue'
import ExportBaseSalary from './exportBaseSalary.vue'
const TeacherNameNo = defineAsyncComponent(() => import('/@/components/TeacherNameNo/index.vue'))
// 使用 Pinia store
const userInfoStore = useUserInfo()
const { userInfos } = storeToRefs(userInfoStore)
// 创建权限对象
const permissions = computed(() => {
const perms: Record<string, boolean> = {}
userInfos.value.authBtnList.forEach((perm: string) => {
perms[perm] = true
})
return perms
})
// 消息提示 hooks
const message = useMessage()
const messageBox = useMessageBox()
// 表格引用
const tableRef = ref()
const searchFormRef = ref()
const salaryInfoRef = ref()
const importBaseSalaryRef = ref()
const exportBaseSalaryRef = ref()
// 搜索表单显示状态
const showSearch = ref(true)
// 岗位类别列表
const stationLevelList = ref<any[]>([])
// 选中的行
const selectList = ref<any[]>([])
// 搜索表单数据
const search = reactive({
teacherNo: '',
realName: '',
idCard: '',
nf: '',
yf: '',
stationTypeId: ''
})
// 配置 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
})
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle } = useTable(state)
// 初始化
onMounted(() => {
init()
})
// 初始化数据
const init = async () => {
try {
const [stationRes, authRes] = await Promise.all([
getStationLevelList(),
checkAuth()
])
stationLevelList.value = stationRes.data || []
// 根据权限设置表格选项(如果需要)
// if (authRes.data.data === false) {
// // 设置普通表格选项
// }
} catch (error) {
// 初始化失败
}
}
// 查询
const handleFilter = () => {
getDataList() // 查询后跳转到第一页
}
// 选择变化
const selectionChange = (selection: any[]) => {
selectList.value = selection
}
// 查看
const handleEdit = (row: any) => {
salaryInfoRef.value?.init(row)
}
// 导入工资条
const handleImportBaseSalary = () => {
importBaseSalaryRef.value?.init()
}
// 批量删除
const delbatch = () => {
if (selectList.value.length === 0) {
message.info("请至少选择一名人员")
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.info("删除成功")
getDataList(false) // 删除后保持当前页
}
} catch (error: any) {
message.error(error?.msg || '删除失败')
}
}).catch(() => {
// 用户取消
})
}
// 设置可查询/不可查询
const canSearch = (val: number) => {
if (selectList.value.length === 0) {
message.info("请至少选择一名人员")
return
}
const params = {
canSearch: val,
selectList: selectList.value
}
messageBox.confirm('确认设置?').then(async () => {
try {
await setCanSearch(params)
message.success("设置成功")
getDataList(false) // 设置后保持当前页
} catch (error: any) {
message.error(error?.msg || '设置失败')
}
}).catch(() => {
// 用户取消
})
}
</script>
<style lang="scss" scoped>
.data-table {
width: 100% !important;
}
</style>

View File

@@ -0,0 +1,323 @@
<template>
<el-dialog v-model="visible" width="100%" v-loading="baseLoading" top="0" :close-on-click-modal="false" destroy-on-close>
<!--基本信息-->
<el-card shadow="hover">
<el-row :span="24">
<el-col>
<el-table
:data="salaryData.baseInfo"
style="width: 100%">
<el-table-column
prop="realName"
label="姓名"
width="80">
</el-table-column>
<el-table-column
prop="idCard"
label="身份证号"
width="200">
</el-table-column>
<el-table-column
label="年份"
width="300">
<template #default>
<el-date-picker
v-model="nowUser.nf"
type="year"
format="YYYY"
value-format="YYYY"
style="width: 200px"
placeholder="选择年">
</el-date-picker>
</template>
</el-table-column>
<el-table-column
label="月份"
width="300">
<template #default>
<el-date-picker
v-model="nowUser.yff"
type="month"
format="M"
value-format="M"
style="width: 200px"
placeholder="选择月">
</el-date-picker>
</template>
</el-table-column>
<el-table-column
label="操作"
width="200">
<template #default>
<el-button @click="searchUserInfo" type="primary" size="small">搜索</el-button>
</template>
</el-table-column>
</el-table>
</el-col>
</el-row>
</el-card>
<el-card shadow="hover">
<!--应发部分-->
<el-row>
<el-col :span="24">
<el-table
:data="salaryData.baseInfo"
size="small"
border
>
<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>
<el-tag type="danger">基础工资应税收入= 岗位工资 +薪级工资+见习期工资+生活补贴+岗位津贴+教龄津贴+特教补贴+特级教师津贴+特岗津贴1+特岗津贴2+奖励绩效性工资+乡镇工作补贴+临时补贴+保留津贴+应休未休假-个人补缴-其他扣款-医疗救助金 </el-tag>
</el-col>
</el-row>
<!--应扣部分-->
<el-row>
<el-col :span="24">
<el-table
size="small"
border
:data="salaryData.baseInfo"
style="width: 100%">
<el-table-column label="应扣部分">
<el-table-column label="住房公积金" width="90" prop="houseFund"></el-table-column>
<el-table-column label="医疗保险金" width="90" prop="medicalInsurance"></el-table-column>
<el-table-column label="失业保险金" width="90" prop="unemployInsurance"></el-table-column>
<el-table-column label="养老保险金" width="90" prop="endowInsurance"></el-table-column>
<el-table-column label="工会费" width="60" prop="unionFee"></el-table-column>
<el-table-column label="儿童统筹" width="90" prop="childrenWhole"></el-table-column>
<el-table-column label="个人所得税" width="90" prop="personalTax"></el-table-column>
<el-table-column label="其他扣款" width="90" prop="otherDeduction"></el-table-column>
<el-table-column label="病事假扣款" width="90" prop="sickDeduction"></el-table-column>
<el-table-column label="医疗救助基金" width="90" prop="medicalFund"></el-table-column>
<el-table-column label="工伤保险" width="90" prop="inductrialInjury"></el-table-column>
<el-table-column label="个人补缴" width="90" prop="personalPay"></el-table-column>
<el-table-column label="应扣合计" width="90" prop="withhold"></el-table-column>
</el-table-column>
</el-table>
<el-tag>个人所得税 = 个税计算数据中的 累计应补(退)税额 </el-tag>
</el-col>
</el-row>
<!--劳务费-->
<el-row v-if="showAllContent">
<el-col :span="24">
<el-table size="small" border :data="allProjectData">
<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>
</el-col>
</el-row>
<!--专项扣除-->
<el-row v-if="showAllContent">
<el-col :span="24">
<el-table
size="small"
border
:data="salaryExtendData"
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>
<el-tag type="warning">应税收入= 基础工资应税收入+造单收入 </el-tag> &nbsp;&nbsp;
<el-tag type="success">累计专项扣除=当年累计个人承担的住房公积金+医疗保险金+失业保险金+养老保险金 </el-tag>
</el-col>
</el-row>
<!--实发合计-->
<el-row>
<el-col :span="24">
<el-table
size="small"
border
:data="[staticsData]"
empty-text=" ">
<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>
<el-tag type="primary">实发工资= 应发工资-应扣合计 </el-tag>
</el-col>
</el-row>
</el-card>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, nextTick } from 'vue'
import { queryUserInfo, queryExtendSalaryInfo } from '/@/api/professional/salaries/teacherpayslip'
import { checkAuth } from '/@/api/professional/salaries/teachersalary'
// 对话框显示状态
const visible = ref(false)
// 数据
const salaryData = reactive({
baseInfo: [] as 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)
// 检查权限
const checkAuthMethod = async () => {
try {
const res = await checkAuth()
showAllContent.value = res.data.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)
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.data.salaryTax)
allProjectData.value = res.data.data.allProject
staticsData.orderMoney = res.data.data.totalMoney
} catch (error) {
// 查询失败
}
}
// 搜索用户信息
const searchUserInfo = async () => {
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) {
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
makeUserInfo(resData)
await queryExtendSalaryInfoMethod(resData)
}
} catch (error) {
// 查询失败
} 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)
})
}
// 暴露方法
defineExpose({
init
})
</script>
<style scoped>
</style>