添加工资查看功能

This commit is contained in:
1147680382@qq.com
2025-05-23 11:29:08 +08:00
parent df432367c6
commit 0ee4dd28b2
5 changed files with 1379 additions and 17 deletions
@@ -52,6 +52,11 @@
</template>
</el-table-column>
<el-table-column prop="name" label="姓名" width="100" show-overflow-tooltip fixed="left" />
<el-table-column prop="baseSalary" label="基本工资" width="120" align="right" show-overflow-tooltip>
<template #default="scope">
{{ formatMoney(scope.row.baseSalary) }}
</template>
</el-table-column>
<el-table-column prop="workDays" label="工作天数" width="100" align="center" />
<el-table-column prop="status" label="状态" width="100" align="center">
<template #default="scope">
@@ -82,8 +87,36 @@
<el-table-column prop="annualPerformance" label="年度绩效" width="100" align="center" show-overflow-tooltip></el-table-column>
<el-table-column prop="monthlyPerformance" label="月度绩效" width="100" align="center" show-overflow-tooltip></el-table-column>
<el-table-column prop="penaltyAmount" label="违纪扣奖" width="100" align="center" show-overflow-tooltip />
<el-table-column label="操作" width="120" fixed="right" align="center">
<el-table-column label="签名" width="100" align="center">
<template #default="scope">
<div class="signature-cell">
<el-image
v-if="scope.row.signatureImg"
:src="scope.row.signatureImg"
fit="contain"
style="width: 40px; height: 40px; cursor: pointer;"
@click="handlePreviewSignature(scope.row.signatureImg)"
>
<template #error>
<div class="image-slot">
<el-icon><Picture /></el-icon>
</div>
</template>
</el-image>
<span v-else>无签名</span>
</div>
</template>
</el-table-column>
<el-table-column label="操作" width="240" fixed="right" align="center">
<template #default="scope">
<el-button
type="primary"
link
size="small"
@click="handleViewDetail(scope.row)"
>
查看详情
</el-button>
<el-button
type="primary"
link
@@ -150,19 +183,142 @@
</el-table>
</div>
</el-dialog>
<!-- 工资条详情对话框 -->
<el-dialog
v-model="detailDialogVisible"
title="考勤详情"
width="800px"
>
<div v-if="currentDetail" class="attendance-detail">
<div class="detail-header">
<div class="employee-info">
<el-avatar :size="64" :src="currentDetail.avatar" />
<div class="info-content">
<h3>{{ currentDetail.name }}</h3>
<p>{{ currentDetail.position }}</p>
</div>
</div>
<div class="attendance-period">
{{ currentDetail.year }}{{ currentDetail.month }}月考勤
</div>
</div>
<el-descriptions :column="2" border>
<el-descriptions-item label="基本工资">{{ formatMoney(currentDetail.baseSalary) }}</el-descriptions-item>
<el-descriptions-item label="工作天数">{{ currentDetail.workDays }}</el-descriptions-item>
<el-descriptions-item label="状态">
<el-tag :type="currentDetail.status === 0 ? 'success' : 'warning'" size="small">
{{ currentDetail.status === 0 ? '正式' : '试用' }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="事假">{{ currentDetail.personalLeave }}</el-descriptions-item>
<el-descriptions-item label="病假">{{ currentDetail.sickLeave }}</el-descriptions-item>
<el-descriptions-item label="产假">{{ currentDetail.maternityLeave }}</el-descriptions-item>
<el-descriptions-item label="陪产假">{{ currentDetail.paternityLeave }}</el-descriptions-item>
<el-descriptions-item label="婚假">{{ currentDetail.marriageLeave }}</el-descriptions-item>
<el-descriptions-item label="丧假">{{ currentDetail.bereavementLeave }}</el-descriptions-item>
<el-descriptions-item label="年休假">{{ currentDetail.annualLeave }}</el-descriptions-item>
<el-descriptions-item label="年休假(管理岗)">{{ currentDetail.managementAnnualLeave }}</el-descriptions-item>
<el-descriptions-item label="调休假">{{ currentDetail.compensatoryLeave }}</el-descriptions-item>
<el-descriptions-item label="早退次数">{{ currentDetail.early }}</el-descriptions-item>
<el-descriptions-item label="迟到次数">{{ currentDetail.late }}</el-descriptions-item>
<el-descriptions-item label="严重迟到">{{ currentDetail.seriousLate }}</el-descriptions-item>
<el-descriptions-item label="旷工次数">{{ currentDetail.absenteeism }}</el-descriptions-item>
<el-descriptions-item label="缺卡次数">{{ currentDetail.missedCount }}</el-descriptions-item>
<el-descriptions-item label="缺勤次数">{{ currentDetail.absenceCount }}</el-descriptions-item>
<el-descriptions-item label="未提交日志">{{ currentDetail.missingLogCount }}</el-descriptions-item>
<el-descriptions-item label="工作日加班">{{ currentDetail.workdayOvertime }}</el-descriptions-item>
<el-descriptions-item label="休息日加班">{{ currentDetail.restdayOvertime }}</el-descriptions-item>
<el-descriptions-item label="节假日加班">{{ currentDetail.holidayOvertime }}</el-descriptions-item>
<el-descriptions-item label="年度绩效">{{ currentDetail.annualPerformance }}</el-descriptions-item>
<el-descriptions-item label="月度绩效">{{ currentDetail.monthlyPerformance }}</el-descriptions-item>
<el-descriptions-item label="违纪扣奖">{{ formatMoney(currentDetail.penaltyAmount) }}</el-descriptions-item>
</el-descriptions>
<div class="detail-footer">
<div class="signature-section">
<div class="signature-item">
<div class="label">员工签名</div>
<div class="signature-image" v-if="currentDetail.signatureImg">
<el-image
:src="currentDetail.signatureImg"
fit="contain"
style="width: 100%; height: 100%;"
@click="handlePreviewSignature(currentDetail.signatureImg)"
>
<template #error>
<div class="image-slot">
<el-icon><Picture /></el-icon>
</div>
</template>
</el-image>
</div>
<div class="no-signature" v-else>未签名</div>
</div>
</div>
</div>
</div>
</el-dialog>
<!-- 签名预览对话框 -->
<el-dialog
v-model="signaturePreviewVisible"
title="签名预览"
width="500px"
:show-close="true"
:close-on-click-modal="true"
:close-on-press-escape="true"
class="signature-preview-dialog"
>
<div class="signature-preview-content">
<el-image
v-if="currentSignatureImg"
:src="currentSignatureImg"
fit="contain"
style="width: 100%; height: 300px;"
>
<template #error>
<div class="image-slot">
<el-icon><Picture /></el-icon>
</div>
</template>
</el-image>
</div>
</el-dialog>
</div>
</template>
<script setup>
import { ref, onMounted } from "vue";
import { ElMessage } from "element-plus";
import { Search } from '@element-plus/icons-vue';
import { Search, Picture } from '@element-plus/icons-vue';
import dayjs from 'dayjs';
import {
getFinanceAttendanceList,
getAbnormalAttendanceDetail,
} from "../../../../api/modules/index";
// 格式化金额
const formatMoney = (value) => {
if (value === undefined || value === null) return '0.00';
// 将输入转换为数字
const num = Number(value);
// 检查是否为有效数字
if (isNaN(num)) return '0.00';
// 使用toFixed(2)保留两位小数
const fixedNum = num.toFixed(2);
// 添加千分位分隔符
const parts = fixedNum.split('.');
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
return parts.join('.');
};
// 权限检查
const userInfo = JSON.parse(sessionStorage.getItem("userInfo") || "{}");
// if (userInfo.role !== 3) {
@@ -175,6 +331,10 @@ const attendanceList = ref([]);
const originalList = ref([]);
const searchKeyword = ref('');
// 详情对话框
const detailDialogVisible = ref(false);
const currentDetail = ref(null);
// 日期范围
const dateRange = ref(null);
const defaultTime = new Date(2000, 1, 1, 0, 0, 0);
@@ -330,6 +490,24 @@ const handleViewAbnormal = async (row) => {
}
};
// 查看详情
const handleViewDetail = (row) => {
currentDetail.value = row;
detailDialogVisible.value = true;
};
// 签名预览
const signaturePreviewVisible = ref(false);
const currentSignatureImg = ref('');
const handlePreviewSignature = (url) => {
if (!url) return;
const img = new Image();
img.src = url;
const newWindow = window.open('');
newWindow.document.write(img.outerHTML);
};
// 页面加载时设置默认日期范围并获取数据
onMounted(() => {
setDefaultDateRange();
@@ -387,11 +565,13 @@ onMounted(() => {
.el-table__fixed-right {
height: 100% !important;
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.15);
z-index: 1;
}
.el-table__fixed {
height: 100% !important;
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.15);
z-index: 1;
}
}
@@ -415,6 +595,39 @@ onMounted(() => {
gap: 8px;
}
}
.signature-cell {
position: relative;
z-index: 2;
}
:deep(.el-image-viewer__wrapper) {
z-index: 9999;
}
:deep(.el-image-viewer__mask) {
z-index: 9998;
}
:deep(.el-image-viewer__btn) {
z-index: 10000;
}
:deep(.el-image-viewer__actions) {
z-index: 10000;
}
:deep(.el-image-viewer__canvas) {
z-index: 9999;
}
:deep(.el-dialog__wrapper) {
z-index: 2000;
}
:deep(.el-dialog) {
z-index: 2001;
}
}
.abnormal-date-group {
@@ -472,4 +685,193 @@ onMounted(() => {
border-radius: 8px;
overflow: hidden;
}
.image-slot {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
background: #ffffff;
color: #909399;
font-size: 20px;
}
.signature-image {
height: 100px;
border: 1px solid var(--el-border-color);
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
background: #ffffff;
position: relative;
z-index: 3000;
:deep(.el-image) {
width: 100%;
height: 100%;
background: #ffffff;
position: relative;
z-index: 3000;
}
}
:deep(.el-image-viewer__wrapper) {
z-index: 3000;
.el-image-viewer__canvas {
background: #ffffff;
}
}
:deep(.el-dialog) {
.el-dialog__body {
position: relative;
z-index: 2000;
}
}
.signature-cell {
position: relative;
z-index: 2;
}
:deep(.el-table) {
.el-table__fixed-right {
z-index: 2000;
}
.el-table__fixed {
z-index: 2000;
}
}
:deep(.el-image-viewer__wrapper) {
z-index: 9999;
}
:deep(.el-image-viewer__mask) {
z-index: 9998;
}
.signature-preview-dialog {
:deep(.el-dialog__body) {
padding: 20px;
}
.signature-preview-content {
display: flex;
justify-content: center;
align-items: center;
background: #ffffff;
border-radius: 4px;
overflow: hidden;
}
}
:deep(.el-dialog__wrapper) {
z-index: 2000;
}
:deep(.el-dialog) {
z-index: 2001;
}
.attendance-detail {
.detail-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 20px;
border-bottom: 1px solid #ebeef5;
.employee-info {
display: flex;
align-items: center;
gap: 16px;
.info-content {
h3 {
margin: 0;
font-size: 18px;
color: #303133;
}
p {
margin: 4px 0 0;
font-size: 14px;
color: #909399;
}
}
}
.attendance-period {
font-size: 16px;
color: #606266;
font-weight: 500;
}
}
.detail-footer {
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid #ebeef5;
.signature-section {
display: flex;
justify-content: flex-end;
gap: 40px;
.signature-item {
display: flex;
align-items: center;
gap: 12px;
.label {
font-size: 14px;
color: #606266;
}
.signature-image {
width: 120px;
height: 60px;
border: 1px solid #dcdfe6;
border-radius: 4px;
overflow: hidden;
cursor: pointer;
&:hover {
border-color: #409eff;
}
}
.no-signature {
width: 120px;
height: 60px;
display: flex;
align-items: center;
justify-content: center;
color: #909399;
font-size: 14px;
border: 1px dashed #dcdfe6;
border-radius: 4px;
}
}
}
}
}
:deep(.el-descriptions) {
.el-descriptions__label {
width: 120px;
color: #606266;
}
.el-descriptions__content {
color: #303133;
}
}
</style>