Files
salaryAccounting/pages/attendanceManagement/attendanceManagement.vue
T
2025-05-29 14:06:15 +08:00

577 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="attendance-page">
<!-- 月份选择 -->
<view class="month-selector" @click="showDatePicker">
<view class="combination">
<text
class="current-month">{{ selectedYear }}年{{ selectedMonth < 10 ? '0' + selectedMonth : selectedMonth }}月</text>
<image class="arrow" src="/static/arr.png" mode="aspectFit"></image>
</view>
<text class="month-text">月度</text>
</view>
<!-- 内容 -->
<view class="box" v-for="(attendanceData,index) in attendanceDataList" :key="index">
<view class="title">{{attendanceData.status=="1"?"试用":"正式"}}</view>
<!-- 打卡统计 -->
<view class="stat-section">
<view class="section-title">打卡统计</view>
<view class="stat-grid">
<view class="stat-item">
<text class="label">迟到</text>
<text class="value red-text">{{ attendanceData.late }}次</text>
</view>
<view class="stat-item">
<text class="label">严重迟到</text>
<text class="value red-text">{{ attendanceData.seriousLate }}次</text>
</view>
<view class="stat-item">
<text class="label">旷工</text>
<text class="value">{{ attendanceData.absenteeism }}次</text>
</view>
<view class="stat-item">
<text class="label">早退</text>
<text class="value red-text">{{ attendanceData.early }}次</text>
</view>
<view class="stat-item">
<text class="label">未打卡</text>
<text class="value red-text">{{ attendanceData.absenceCount }}次</text>
</view>
<view class="stat-item">
<text class="label">未签到签退</text>
<text class="value red-text">{{ attendanceData.missedCount }}次</text>
</view>
<view class="stat-item">
<text class="label">未提交日志</text>
<text class="value red-text">{{ attendanceData.missingLogCount }}次</text>
</view>
</view>
</view>
<!-- 请假统计 -->
<view class="stat-section">
<view class="section-title">请假统计</view>
<view class="stat-grid">
<view class="stat-item">
<text class="label">事假</text>
<text class="value red-text">{{ attendanceData.personalLeave }}小时</text>
</view>
<view class="stat-item">
<text class="label">病假</text>
<text class="value red-text">{{ attendanceData.sickLeave }}天</text>
</view>
<view class="stat-item">
<text class="label">婚假</text>
<text class="value">{{ attendanceData.marriageLeave }}天</text>
</view>
<view class="stat-item">
<text class="label">产假</text>
<text class="value red-text">{{ attendanceData.maternityLeave }}天</text>
</view>
<view class="stat-item">
<text class="label">陪产假</text>
<text class="value red-text">{{ attendanceData.paternityLeave }}天</text>
</view>
<view class="stat-item">
<text class="label">丧假</text>
<text class="value red-text">{{ attendanceData.bereavementLeave }}天</text>
</view>
<view class="stat-item">
<text class="label">年休假</text>
<text class="value red-text">{{ attendanceData.annualLeave }}天</text>
</view>
<view class="stat-item">
<text class="label">年休假(管理岗)</text>
<text class="value red-text">{{ attendanceData.managementAnnualLeave }}天</text>
</view>
</view>
</view>
<!-- 加班、调休统计 -->
<view class="stat-section">
<view class="section-title">加班、调休统计</view>
<view class="stat-grid">
<view class="stat-item">
<text class="label">节假日加班</text>
<text class="value red-text">{{ attendanceData.holidayOvertime }}小时</text>
</view>
<view class="stat-item">
<text class="label">休息日加班</text>
<text class="value red-text">{{ attendanceData.restdayOvertime }}小时</text>
</view>
<view class="stat-item">
<text class="label">工作日加班</text>
<text class="value">{{ attendanceData.workdayOvertime }}小时</text>
</view>
<!-- <view class="stat-item">
<text class="label">调休</text>
<text class="value red-text">1小时</text>
</view> -->
</view>
</view>
<!-- 底部说明 -->
<view class="bottom-tips">说明:请核实当月考勤记录,确认无误请签字确认</view>
<!-- 员工签字 -->
<view class="sign" v-if="attendanceData.signatureImg">
<view class="sign-tit">
员工签字
<text>/保留员工签字</text>
</view>
<view class="signatureVersion">
<image :src="attendanceData.signatureImg" class="signImg" mode="scaleToFill">
</image>
</view>
</view>
<!-- 签字确认按钮 -->
<view class=" confirm-btn" v-if="attendanceData.flag=='7'" @click="goSignIt(attendanceData)">
<text>签字确认</text>
</view>
<!-- <view class=" confirm-btn" @click="goSignIt(attendanceData)">
<text>签字确认</text>
</view> -->
</view>
<!-- 日期选择模态框 -->
<view class="date-picker-modal" v-if="showModal" @click.stop="closeDatePicker">
<view class="modal-content" @click.stop>
<view class="modal-title">{{ currentStep === 'year' ? '选择年份' : '选择月份' }}</view>
<!-- 年份选择 -->
<view class="year-grid" v-if="currentStep === 'year'">
<view v-for="year in availableYears" :key="year" class="year-item"
:class="{ active: tempSelectedYear === year }" @click="selectYear(year)">
<view class="year-circle">
<text>{{ year }}年</text>
</view>
</view>
</view>
<!-- 月份选择 -->
<view class="month-grid" v-if="currentStep === 'month'">
<view v-for="month in months" :key="month" class="month-item"
:class="{ active: tempSelectedMonth === month }" @click="selectMonth(month)">
<view class="month-circle">
<text>{{ tempSelectedYear }}年{{ month < 10 ? '0' + month : month }}月</text>
</view>
</view>
</view>
<!-- 底部按钮 -->
<view class="modal-footer" v-if="currentStep === 'month'">
<view class="back-btn" @click="backToYearSelect">返回年份选择</view>
</view>
</view>
</view>
</view>
</template>
<script>
import {
getPerformanceAttendanceApi
} from '@/api/create.js';
export default {
data() {
const currentDate = new Date();
const currentYear = currentDate.getFullYear();
return {
showModal: false,
currentYear,
selectedYear: currentYear,
selectedMonth: currentDate.getMonth(),
months: Array.from({
length: 12
}, (_, i) => i + 1),
currentStep: 'year', // 'year' 或 'month'
tempSelectedYear: currentYear,
tempSelectedMonth: currentDate.getMonth() + 1,
availableYears: Array.from({
length: 7
}, (_, i) => currentYear - 3 + i),
attendanceDataList: [{
// 迟到
late: ' ',
// 严重迟到
seriousLate: ' ',
// 旷工
absenteeism: ' ',
// 早退
early: ' ',
// 未打卡
absenceCount: ' ',
// 未签到签退
missedCount: ' ',
// 未提交日志
missingLogCount: ' ',
// 事假
personalLeave: ' ',
// 病假
sickLeave: ' ',
// 婚假
marriageLeave: ' ',
// 产假
maternityLeave: ' ',
// 陪产假
paternityLeave: ' ',
// 丧假
bereavementLeave: ' ',
// 年休假
annualLeave: ' ',
// 年休假(管理岗)
managementAnnualLeave: ' ',
// 节假日加班
holidayOvertime: ' ',
// 休息日加班
restdayOvertime: ' ',
// 工作日加班
workdayOvertime: ' '
}]
};
},
onShow() {
this.getPerformanceAttendance();
this.$setNavigationBar('考勤管理');
},
methods: {
showDatePicker() {
this.showModal = true;
this.currentStep = 'year';
this.tempSelectedYear = this.selectedYear;
this.tempSelectedMonth = this.selectedMonth;
},
closeDatePicker() {
this.showModal = false;
this.currentStep = 'year';
},
selectYear(year) {
this.tempSelectedYear = year;
this.currentStep = 'month';
},
selectMonth(month) {
this.tempSelectedMonth = month;
this.selectedYear = this.tempSelectedYear;
this.selectedMonth = month;
this.showModal = false;
this.currentStep = 'year';
this.$emit('dateSelected', {
year: this.selectedYear,
month: this.selectedMonth
});
this.getPerformanceAttendance()
},
backToYearSelect() {
this.currentStep = 'year';
},
goSignIt(attendanceData) {
this.$navTo('/pages/sign/sign?id=' + attendanceData.id);
},
async getPerformanceAttendance() {
uni.showLoading({
mask: true,
title: '查询中...'
})
let res = await getPerformanceAttendanceApi(this.selectedYear, this.selectedMonth);
uni.hideLoading();
if (res.result.length) {
this.attendanceDataList = res.result;
} else {
uni.showModal({
title: '温馨提示',
content: '暂无相关数据',
showCancel: false,
confirmText: "确定",
success: function(res) {
if (res.confirm) {
uni.navigateBack({
delta: 1
});
}
}
});
}
}
}
};
</script>
<style lang="scss" scoped>
.attendance-page {
min-height: 100vh;
background-color: #f8f9fa;
padding: 0 30rpx 0 30rpx;
.month-selector {
padding: 0 28rpx 0 10rpx;
display: flex;
align-items: center;
margin: 40rpx 0;
justify-content: space-between;
.combination {
height: 40rpx;
line-height: 40rpx;
display: flex;
align-content: center;
.current-month {
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 28rpx;
color: #4b5563;
}
.arrow {
transform: rotate(90deg);
width: 40rpx;
height: 40rpx;
}
}
.month-text {
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 28rpx;
color: #2b5ce4;
}
}
.box {
.title {
padding-bottom: 28rpx;
}
}
.stat-section {
background: #fff;
border-radius: 12rpx;
padding: 35rpx 40rpx;
margin-bottom: 20rpx;
.section-title {
font-size: 32rpx;
color: #111827;
}
.stat-grid {
margin-top: 40rpx;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 40rpx 90rpx;
.stat-item {
display: flex;
flex-direction: column;
align-items: center;
.label {
font-size: 28rpx;
color: #4b5563;
margin-bottom: 15rpx;
}
.value {
font-size: 32rpx;
color: #666;
&.red-text {
color: #ff4d4f;
}
}
}
}
}
.bottom-tips {
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 24rpx;
color: #b9b9c2;
}
.sign {
margin-top: 32rpx;
margin-bottom: 32rpx;
.sign-tit {
margin-bottom: 32rpx;
margin-left: 8rpx;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 700;
font-size: 28rpx;
color: #000000;
text {
padding-left: 16rpx;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 24rpx;
color: #b9b9c2;
}
}
.signatureVersion {
width: 690rpx;
height: 280rpx;
background: #ffffff;
border-radius: 20rpx;
}
}
.confirm-btn {
left: 20rpx;
right: 20rpx;
height: 78rpx;
margin-bottom: 40rpx;
background: #ffffff;
border-radius: 20rpx;
display: flex;
align-items: center;
justify-content: center;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 30rpx;
color: #0078ff;
font-size: 32rpx;
border: 2rpx solid #0078ff;
}
.date-picker-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 999;
display: flex;
align-items: center;
justify-content: center;
.modal-content {
width: 690rpx;
background: #ffffff;
border-radius: 20rpx;
padding: 40rpx 30rpx;
.modal-title {
font-size: 32rpx;
color: #111827;
text-align: center;
margin-bottom: 40rpx;
font-weight: 500;
}
.year-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20rpx;
padding: 0 20rpx;
.year-item {
height: 88rpx;
display: flex;
align-items: center;
justify-content: center;
.year-circle {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8rpx;
border: 2rpx solid #e5e7eb;
text {
font-size: 28rpx;
color: #4b5563;
}
}
&.active {
.year-circle {
background: #eef2ff;
border-color: #2b5ce4;
text {
color: #2b5ce4;
}
}
}
}
}
.month-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20rpx;
padding: 0 20rpx;
.month-item {
height: 88rpx;
display: flex;
align-items: center;
justify-content: center;
.month-circle {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8rpx;
border: 2rpx solid #e5e7eb;
text {
font-size: 28rpx;
color: #4b5563;
}
}
&.active {
.month-circle {
background: #eef2ff;
border-color: #2b5ce4;
text {
color: #2b5ce4;
}
}
}
}
}
.modal-footer {
margin-top: 30rpx;
display: flex;
justify-content: center;
.back-btn {
padding: 20rpx 40rpx;
font-size: 28rpx;
color: #2b5ce4;
background: #eef2ff;
border-radius: 8rpx;
}
}
}
}
.signImg {
width: 280rpx;
height: 690rpx;
transform-origin: left top;
transform: rotate(-90deg) translateX(-280rpx);
}
}
</style>