Files
jinbooks/jinbooks-ui/src/views/hr/salary-summary.vue
2025-06-15 18:36:06 +08:00

546 lines
20 KiB
Vue

<template>
<div class="app-container">
<el-card class="common-card query-box">
<div class="queryForm">
<el-form :model="queryParams" ref="queryRef" :inline="true" label-width="68px">
<!-- <el-form-item label="发放标签" prop="label">
<el-input
v-model="queryParams.label"
placeholder="请输入发放标签"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>-->
<el-form-item label="所属月份" prop="belongDate">
<el-date-picker
v-model="queryParams.belongDateRange"
type="monthrange"
unlink-panels
range-separator=""
start-placeholder="起始月份"
end-placeholder="结束月份"
value-format="YYYY-MM"
:shortcuts="shortcuts"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">{{ t('org.button.query') }}</el-button>
<el-button @click="resetQuery">{{ t('org.button.reset') }}</el-button>
</el-form-item>
</el-form>
</div>
</el-card>
<el-card class="common-card">
<div class="btn-form">
<el-button type="primary"
@click="submitForm()">
汇总工资
</el-button>
</div>
<el-table v-loading="loading" :data="dataList" show-summary :summary-method="getSummaries" border stripe>
<el-table-column fixed prop="belongDate" label="月份" align="center" width="80"
:show-overflow-tooltip="true">
</el-table-column>
<el-table-column fixed prop="label" label="标签" align="center" width="80"
:show-overflow-tooltip="true">
<template #default="scope">
<div v-if="scope.row.label === 'salary'">职工</div>
<div v-if="scope.row.label === 'labor'">兼职</div>
</template>
</el-table-column>
<el-table-column fixed prop="peopleNumber" label="人数" align="center" width="70"
:show-overflow-tooltip="true">
</el-table-column>
<!-- <el-table-column :label="$t('jbx.text.description')" align="center" width="110"
:show-overflow-tooltip="true" prop="description"/>-->
<el-table-column label="应发金额" align="center">
<el-table-column prop="payBasic" label="工资" align="center" width="100"
:show-overflow-tooltip="true">
<template #default="scope">
{{ formatAmount(scope.row.payBasic + scope.row.payPost + scope.row.payMerit + scope.row.laborFee) }}
</template>
</el-table-column>
<el-table-column prop="payBasic" label="基本工资" align="center" width="100"
:show-overflow-tooltip="true">
<template #default="scope">
{{ formatAmount(scope.row.payBasic) }}
</template>
</el-table-column>
<el-table-column prop="payPost" label="岗位工资" align="center" width="100"
:show-overflow-tooltip="true">
<template #default="scope">
{{ formatAmount(scope.row.payPost) }}
</template>
</el-table-column>
<el-table-column prop="payMerit" label="绩效" align="center" width="100"
:show-overflow-tooltip="true">
<template #default="scope">
{{ formatAmount(scope.row.payMerit) }}
</template>
</el-table-column>
<el-table-column prop="laborFee" label="劳务费" align="center" width="100"
:show-overflow-tooltip="true">
<template #default="scope">
{{ formatAmount(scope.row.laborFee) }}
</template>
</el-table-column>
<el-table-column prop="bonus" label="奖金" align="center" width="100"
:show-overflow-tooltip="true">
<template #default="scope">
{{ formatAmount(scope.row.bonus) }}
</template>
</el-table-column>
<el-table-column prop="overtime" label="加班补贴" align="center" width="100"
:show-overflow-tooltip="true">
<template #default="scope">
{{ formatAmount(scope.row.overtime) }}
</template>
</el-table-column>
<el-table-column prop="allowance" label="津贴" align="center" width="100"
:show-overflow-tooltip="true">
<template #default="scope">
{{ formatAmount(scope.row.allowance) }}
</template>
</el-table-column>
<el-table-column prop="backPay" label="补发工资" align="center" width="100"
:show-overflow-tooltip="true">
<template #default="scope">
{{ formatAmount(scope.row.backPay) }}
</template>
</el-table-column>
</el-table-column>
<el-table-column label="应扣金额" align="center">
<el-table-column prop="totalSocialInsurance" label="代扣社保" align="center" width="110"
:show-overflow-tooltip="true">
<template #default="scope">
<span :class="{ 'red-font': scope.row.totalSocialInsurance > 0 }">{{ formatAmount(scope.row.totalSocialInsurance) }}</span>
</template>
</el-table-column>
<el-table-column prop="providentFund" label="代扣公积金" align="center" width="100"
:show-overflow-tooltip="true">
<template #default="scope">
<span :class="{ 'red-font': scope.row.providentFund > 0 }">{{ formatAmount(scope.row.providentFund) }}</span>
</template>
</el-table-column>
<el-table-column prop="attendance" label="请假考勤" align="center" width="100"
:show-overflow-tooltip="true">
<template #default="scope">
<span :class="{ 'red-font': scope.row.attendance > 0 }">{{ formatAmount(scope.row.attendance) }}</span>
</template>
</el-table-column>
<el-table-column prop="otherDeductions" label="其他扣额" align="center" width="100"
:show-overflow-tooltip="true">
<template #default="scope">
<span :class="{ 'red-font': scope.row.otherDeductions > 0 }">{{ formatAmount(scope.row.otherDeductions) }}</span>
</template>
</el-table-column>
<el-table-column prop="personalTax" label="个税" align="center" width="100"
:show-overflow-tooltip="true">
<template #default="scope">
<span :class="{ 'red-font': scope.row.personalTax > 0 }">{{ formatAmount(scope.row.personalTax) }}</span>
</template>
</el-table-column>
</el-table-column>
<el-table-column label="企业缴纳" align="center">
<el-table-column prop="businessSocialInsurance" label="社保(公司)" align="center" width="110"
:show-overflow-tooltip="true">
<template #default="scope">
{{ formatAmount(scope.row.businessSocialInsurance) }}
</template>
</el-table-column>
<el-table-column prop="businessProvidentFund" label="公积金(公司)" align="center" width="120"
:show-overflow-tooltip="true">
<template #default="scope">
{{ formatAmount(scope.row.businessProvidentFund) }}
</template>
</el-table-column>
</el-table-column>
<!-- <el-table-column prop="taxDeduction" label="税务抵扣" align="center" width="110"
:show-overflow-tooltip="true">
<template #default="scope">
{{ formatAmount(scope.row.taxDeduction) }}
</template>
</el-table-column>
-->
<el-table-column prop="payAmount" label="应发工资" align="right" width="110"
:show-overflow-tooltip="true">
<template #default="scope">
{{ formatAmount(scope.row.payAmount) }}
</template>
</el-table-column>
<el-table-column prop="taxableWages" label="应税工资" align="center" width="110"
:show-overflow-tooltip="true">
<template #default="scope">
{{ formatAmount(scope.row.taxableWages) }}
</template>
</el-table-column>
<el-table-column prop="totalAmount" label="实发合计" align="center" width="110"
:show-overflow-tooltip="true">
<template #default="scope">
{{ formatAmount(scope.row.totalAmount) }}
</template>
</el-table-column>
<el-table-column fixed="right" prop="businessExpenditureCosts" label="公司成本" align="center" width="110"
:show-overflow-tooltip="true">
<template #default="scope">
<b>{{ formatAmount(scope.row.businessExpenditureCosts) }}</b>
</template>
</el-table-column>
<el-table-column prop="accrualVoucherId" label="计提/收票凭证" align="center" fixed="right" width="90">
<template #default="scope">
<el-button v-if="(scope.row.accrualVoucherId === null ||scope.row.accrualVoucherId ==='') && scope.row.label === 'salary'" type="text"
@click="generateVoucher(scope.row,0)">
生成
</el-button>
<el-button v-if="scope.row.accrualVoucherId !== null &&scope.row.accrualVoucherId !=='' && scope.row.label === 'salary'" type="text"
@click="viewVoucher(scope.row.accrualVoucherId)">
查看
</el-button>
</template>
</el-table-column>
<el-table-column prop="salaryVoucherId" label="发放凭证" align="center" fixed="right" width="90">
<template #default="scope">
<el-button v-if="(scope.row.salaryVoucherId === null ||scope.row.salaryVoucherId ==='') && scope.row.label === 'salary'" type="text"
@click="generateVoucher(scope.row,1)">
生成
</el-button>
<el-button v-if="scope.row.salaryVoucherId !== null &&scope.row.salaryVoucherId !=='' && scope.row.label === 'salary'" type="text"
@click="viewVoucher(scope.row.salaryVoucherId)">
查看
</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNumber"
v-model:limit="queryParams.pageSize"
:page-sizes="queryParams.pageSizeOptions"
@pagination="getList"
/>
</el-card>
<el-dialog v-model="editFlag" width="500px" append-to-body :title="editTitle" :close-on-click-modal="false"
@close="cancel">
<el-form :model="form" :rules="rules" ref="formRef" label-width="110px" inline-message>
<el-form-item prop="belongDate" label="工资所属月份" :required="true">
<el-date-picker
style="width: 100%"
v-model="form.belongDate"
type="month"
format="YYYY-MM"
value-format="YYYY-MM"
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="cancel">{{ $t('systemCancel') }}</el-button>
<el-button type="primary" @click="submitForm">{{ t('org.confirm') }}</el-button>
</div>
</el-dialog>
<el-dialog v-model="voucherFlag" width="500px" append-to-body :title="editTitle" :close-on-click-modal="false"
@close="cancel">
<el-form :model="formVoucher" :rules="rulesVoucher" ref="voucherRef" inline-message>
<el-form-item prop="voucherType" :required="true">
<el-radio-group v-model="formVoucher.voucherType">
<el-radio-button label="计提工资费用凭证" :value="0"/>
<el-radio-button label="发放工资凭证" :value="1"/>
</el-radio-group>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="cancel">{{ $t('systemCancel') }}</el-button>
<el-button type="primary" @click="submitVoucherForm">{{ t('org.confirm') }}</el-button>
</div>
</el-dialog>
<!-- 添加或修改凭证记录对话框 -->
<el-drawer :title="voucherTitle" v-model="voucherOpen" :close-on-click-modal="false" @close="getList" size="1200px">
<template #header>
<h4>{{ voucherTitle }}</h4>
</template>
<voucher-edit v-if="voucherOpen" v-model="voucherForm" :edit="!voucherPreviewMode" :dialog="true" :auto="false"
@submit="submitForm"></voucher-edit>
</el-drawer>
</div>
</template>
<script setup lang="ts">
import {formatAmount} from "@/utils";
import {reactive, ref, toRefs} from "vue";
import * as voucherApis from "@/api/system/voucher/voucher";
import {fetchPage, generateVoucherSubmit, saveSummary, salarySummary} from "@/api/system/hr/employee-summary";
import {useI18n} from "vue-i18n";
import {ElForm} from "element-plus";
import modal from "@/plugins/modal";
import {useRouter} from "vue-router";
import {h} from 'vue'
import type {VNode} from 'vue'
import voucherEdit from "@/views/voucher/voucher-edit.vue";
const router: any = useRouter();
const editFlag: any = ref(false);
const voucherFlag: any = ref(false);
const editTitle: any = ref('');
const formRef = ref<InstanceType<typeof ElForm> | null>(null);
const voucherRef = ref<InstanceType<typeof ElForm> | null>(null);
let tableSummary: any = ref([]);
const voucherOpen = ref(false);
const voucherPreviewMode = ref(false);
const voucherTitle = ref("");
const shortcuts = [
{
text: '本月',
value: [new Date(), new Date()],
},
{
text: '本年',
value: () => {
const end = new Date()
const start = new Date(new Date().getFullYear(), 0)
return [start, end]
},
},
{
text: '过去6个月',
value: () => {
const end = new Date()
const start = new Date()
start.setMonth(start.getMonth() - 6)
return [start, end]
},
},
]
const {t} = useI18n()
const data: any = reactive({
queryParams: {
pageNumber: 1,
pageSize: 10,
belongDateRange: [new Date().getFullYear() + "-01", getCurrentYearMonth()],//默认查本年数据
pageSizeOptions: [10, 20, 50]
},
form: {
belongDate: getCurrentYearMonth()
},
formVoucher: {
voucherType: 0
},
voucherForm: {},
rules: {
belongDate: [
{required: true, message: "请选择月份", trigger: "blur"},
],
},
rulesVoucher: {
voucherType: [
{required: true, message: "请选择生成凭证的方式", trigger: "blur"},
],
}
});
const {queryParams, form, formVoucher, voucherForm, rules, rulesVoucher} = toRefs(data);
const dataList = ref([]);
const loading = ref(true);
const total = ref(0);
const id: any = ref(undefined);
function getList() {
fetchPage(queryParams.value).then((response: any) => {
dataList.value = response.data.records;
total.value = response.data.total;
loading.value = false;
});
salarySummary(queryParams.value).then((res: any) => {
console.log(res.data);
tableSummary = res.data;
});
}
const getSummaries = () => {
const sums: (string | VNode)[] = []
if (tableSummary != null) {
let sumsIndex = 0;
sums[sumsIndex++] = h('div', {style: {textDecoration: 'underline'}}, ['合计',])
console.log("tableSummary " + tableSummary);
sums[sumsIndex++] = "";
sums[sumsIndex++] = "";
sums[sumsIndex++] = tableSummary.payBasic + tableSummary.payPost + tableSummary.payMerit + tableSummary.laborFee;
sums[sumsIndex++] = tableSummary.payBasic;
sums[sumsIndex++] = tableSummary.payPost;
sums[sumsIndex++] = tableSummary.payMerit;
sums[sumsIndex++] = tableSummary.laborFee;
sums[sumsIndex++] = tableSummary.bonus;
sums[sumsIndex++] = tableSummary.overtime;
sums[sumsIndex++] = tableSummary.allowance;
sums[sumsIndex++] = tableSummary.backPay;
sums[sumsIndex++] = h('div', {
style: {
color: tableSummary.totalSocialInsurance > 0 ? 'red' : '',
}
}, [formatAmount(tableSummary.totalSocialInsurance),]);
sums[sumsIndex++] = h('div', {
style: {
color: tableSummary.providentFund > 0 ? 'red' : '',
}
}, [formatAmount(tableSummary.providentFund),]);
sums[sumsIndex++] = h('div', {
style: {
color: tableSummary.attendance > 0 ? 'red' : '',
}
}, [formatAmount(tableSummary.attendance),]);
sums[sumsIndex++] = h('div', {
style: {
color: tableSummary.otherDeductions > 0 ? 'red' : '',
}
}, [formatAmount(tableSummary.otherDeductions),]);
sums[sumsIndex++] = h('div', {
style: {
color: tableSummary.personalTax > 0 ? 'red' : '',
}
}, [formatAmount(tableSummary.personalTax),]);
sums[sumsIndex++] = tableSummary.businessSocialInsurance;
sums[sumsIndex++] = tableSummary.businessProvidentFund;
sums[sumsIndex++] = formatAmount(tableSummary.totalAmount);
sums[sumsIndex++] = h('div', {
style: {
textDecoration: 'underline',
fontWeight: "bold"
}
}, [formatAmount(tableSummary.businessExpenditureCosts),]);
}
return sums
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
// queryParams.value.label = undefined;
queryParams.value.belongDateRange = undefined;
handleQuery();
}
function totalSalary() {
editFlag.value = true;
editTitle.value = "合计"
}
function cancel(): any {
editFlag.value = false;
voucherFlag.value = false;
resetForm();
}
function resetForm() {
form.value = {
belongDate: getCurrentYearMonth()
};
formVoucher.value = {
voucherType: 0
};
formRef?.value?.resetFields();
voucherRef?.value?.resetFields();
}
function getCurrentYearMonth() {
const date = new Date();
date.setMonth(date.getMonth() - 1);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
return `${year}-${month}`;
}
function submitForm() {
const handleResponse: any = (res: any, successMessage: any) => {
if (res.code === 0) {
getList();
modal.msgSuccess(successMessage);
cancel();
} else {
modal.msgError(res.message);
}
};
const operation: any = saveSummary;
const successMessage: any = "操作成功"
operation(form.value).then((res: any) => handleResponse(res, successMessage));
}
function submitVoucherForm() {
const handleResponse: any = (res: any, successMessage: any) => {
if (res.code === 0) {
getList();
modal.msgSuccess(res.data);
cancel();
} else {
modal.msgError(res.message);
}
};
console.log("validate " + formVoucher.value.voucherType);
voucherRef?.value?.validate((valid: any) => {
console.log("valid " + valid);
if (valid) {
const operation: any = generateVoucherSubmit;
const successMessage: any = "操作成功"
//formVoucher.value.id = id.value;
operation(formVoucher.value).then((res: any) => handleResponse(res, successMessage));
}
});
}
function generateVoucher(row: any, voucherType: number) {
generateVoucherSubmit({id: row.id, voucherType: voucherType}).then((res: any) => {
console.log(res.data);
if (res.code === 0) {
getList();
modal.msgSuccess("操作成功");
viewVoucher(res.data)
}
});
}
/** 查看操作 */
function viewVoucher(voucherId: any) {
voucherApis.getOneVoucher(voucherId).then((response: any) => {
response.data.items.forEach((t: any) => {
t.subjectCode = t.subjectName.split("-")[0]
// t.detailedSubjectCode = t.detailedAccounts.split("-")[0]
})
voucherForm.value = response.data
voucherOpen.value = true;
voucherPreviewMode.value = false;
voucherTitle.value = "凭证记录";
});
}
getList();
</script>
<style lang="scss" scoped>
.btn-form {
margin-bottom: 10px;
}
.common-card {
margin-bottom: 15px;
}
.app-container {
padding: 0;
background-color: #f5f7fa;
}
.red-font {
color: red;
}
</style>