diff --git a/pages/attendanceStatus/attendanceStatistics.vue b/pages/attendanceStatus/attendanceStatistics.vue index 340d5e8..888877a 100644 --- a/pages/attendanceStatus/attendanceStatistics.vue +++ b/pages/attendanceStatus/attendanceStatistics.vue @@ -40,7 +40,7 @@ {{ selectDate ? $util.cutDate(new Date(selectDate), 'YYYY-MM') : "" - }} + }} @@ -56,33 +56,37 @@ - + 📋 {{ getSummaryData().totalSchedule }} 总排班 + - + {{ getSummaryData().totalAttend }} 总出勤 + - + {{ getSummaryData().totalLate }} 迟到次数 + - + 🏃 {{ getSummaryData().totalEarly }} 早退次数 + @@ -184,6 +188,47 @@ + + + + + {{ getModalTitle() }} + × + + + + + 总计:{{ getCurrentModalTotal() }} + {{ attendanceStatisticsData.length }}人 + + + + + 人员排名 + + + + + + {{ index + 1 }} + + + {{ item.userName || "-" }} + {{ item.phone || item.userCode || "-" }} + + + + {{ getCurrentValue(item) }}{{ getCurrentUnit() + }} + + + + + + + + @@ -207,7 +252,10 @@ export default { seatInfo: {}, loading: false, hasLoaded: false, // 是否已经完成过初始加载 - retryCount: 0 + retryCount: 0, + // 详情弹窗相关 + showDetailPopup: false, + currentDetailType: 'schedule' // 'schedule', 'attend', 'late', 'early' } }, onLoad() { @@ -266,6 +314,75 @@ export default { } }, + // 显示详情弹窗 + showDetailModal(type) { + this.currentDetailType = type + this.showDetailPopup = true + this.showPopup = true // 禁止页面滚动 + }, + + // 关闭详情弹窗 + closeDetailModal() { + this.showDetailPopup = false + this.showPopup = false // 恢复页面滚动 + }, + + // 获取弹窗标题 + getModalTitle() { + const titles = { + schedule: '排班情况详情', + attend: '出勤情况详情', + late: '迟到情况详情', + early: '早退情况详情' + } + return titles[this.currentDetailType] || '详情' + }, + + // 获取当前模态总数 + getCurrentModalTotal() { + const summary = this.getSummaryData() + const totals = { + schedule: summary.totalSchedule + '天', + attend: summary.totalAttend + '天', + late: summary.totalLate + '次', + early: summary.totalEarly + '次' + } + return totals[this.currentDetailType] || '0' + }, + + // 获取单位 + getCurrentUnit() { + const units = { + schedule: '天', + attend: '天', + late: '次', + early: '次' + } + return units[this.currentDetailType] || '天' + }, + + // 获取当前项的值 + getCurrentValue(item) { + const values = { + schedule: item.scheduleTotal || 0, + attend: item.attendTotal || 0, + late: item.lateTotal || 0, + early: item.earlyTotal || 0 + } + return values[this.currentDetailType] || 0 + }, + + // 获取排序后的数据 + getSortedData() { + const data = [...this.attendanceStatisticsData] + return data.sort((a, b) => { + const valueA = this.getCurrentValue(a) + const valueB = this.getCurrentValue(b) + return valueB - valueA // 从大到小排序 + }) + }, + + // 显示日历 showCalendar() { this.$refs.calendar.open() @@ -599,6 +716,17 @@ export default { box-shadow: @shadow; display: flex; align-items: center; + position: relative; + + &.clickable { + cursor: pointer; + transition: all 0.3s ease; + + &:active { + transform: scale(0.98); + background: #f8f9fa; + } + } .cardIcon { font-size: 40rpx; @@ -640,6 +768,13 @@ export default { color: @muted; } } + + .cardArrow { + font-size: 32rpx; + color: #ccc; + font-weight: bold; + margin-left: 8rpx; + } } } @@ -955,5 +1090,217 @@ export default { } } } + + // 详情弹窗样式 + .detailModal { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background: rgba(0, 0, 0, 0.5); + z-index: 9999; + display: flex; + align-items: center; + justify-content: center; + box-sizing: border-box; + padding: 60rpx 40rpx; + + .modalContent { + width: calc(100vw - 64rpx); + max-height: 80vh; + background: #fff; + border-radius: 24rpx; + overflow: hidden; + box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.2); + + .modalHeader { + display: flex; + align-items: center; + justify-content: space-between; + padding: 32rpx 40rpx; + border-bottom: 2rpx solid #f5f5f5; + background: linear-gradient(135deg, @primary, @primary2); + + .modalTitle { + font-size: 32rpx; + font-weight: 700; + color: #fff; + } + + .closeBtn { + width: 48rpx; + height: 48rpx; + background: rgba(255, 255, 255, 0.2); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: 32rpx; + color: #fff; + font-weight: bold; + cursor: pointer; + + &:active { + background: rgba(255, 255, 255, 0.3); + } + } + } + + .modalBody { + padding: 32rpx 40rpx; + max-height: 60vh; + + .summaryInfo { + display: flex; + align-items: center; + justify-content: space-between; + padding: 24rpx; + background: #f8f9fa; + border-radius: 16rpx; + margin-bottom: 32rpx; + + .totalText { + font-size: 28rpx; + font-weight: 600; + color: #2c3e50; + } + + .countText { + font-size: 24rpx; + color: @muted; + background: #fff; + padding: 8rpx 16rpx; + border-radius: 20rpx; + } + } + + .employeeRankList { + .rankHeader { + margin-bottom: 24rpx; + + .rankTitle { + font-size: 28rpx; + font-weight: 600; + color: #2c3e50; + } + } + + .rankScrollArea { + max-height: 40vh; + overflow-y: auto; + + /* 隐藏滚动条 */ + &::-webkit-scrollbar { + display: none; + } + + /* 兼容其他浏览器 */ + -ms-overflow-style: none; + scrollbar-width: none; + } + + .rankItem { + display: flex; + align-items: center; + padding: 24rpx 20rpx; + background: #fff; + border-radius: 12rpx; + margin-bottom: 16rpx; + border: 2rpx solid #f5f5f5; + + &:nth-child(1) { + // 第一名 + border-color: #ffd700; + background: linear-gradient(135deg, #fff9e6, #fff); + } + + &:nth-child(2) { + // 第二名 + border-color: #c0c0c0; + background: linear-gradient(135deg, #f8f8f8, #fff); + } + + &:nth-child(3) { + // 第三名 + border-color: #cd7f32; + background: linear-gradient(135deg, #fdf2e9, #fff); + } + + .rankNumber { + width: 48rpx; + height: 48rpx; + background: @primary; + color: #fff; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: 24rpx; + font-weight: 700; + margin-right: 20rpx; + flex-shrink: 0; + + &.rank-1 { + background: linear-gradient(135deg, #ffd700, #ffed4e); + color: #333; + box-shadow: 0 4rpx 12rpx rgba(255, 215, 0, 0.3); + } + + &.rank-2 { + background: linear-gradient(135deg, #c0c0c0, #e8e8e8); + color: #333; + box-shadow: 0 4rpx 12rpx rgba(192, 192, 192, 0.3); + } + + &.rank-3 { + background: linear-gradient(135deg, #cd7f32, #daa560); + color: #fff; + box-shadow: 0 4rpx 12rpx rgba(205, 127, 50, 0.3); + } + } + + .employeeInfo { + flex: 1; + display: flex; + align-items: center; + + .employeeText { + flex: 1; + display: flex; + flex-direction: column; + + .name { + font-size: 28rpx; + font-weight: 600; + color: #2c3e50; + line-height: 1.3; + margin-bottom: 4rpx; + } + + .phone { + font-size: 24rpx; + color: @muted; + } + } + } + + .rankValue { + display: flex; + align-items: center; + justify-content: flex-end; + + .numberWithUnit { + font-size: 32rpx; + font-weight: 700; + color: @primary; + line-height: 1.2; + } + } + } + } + } + } + } } \ No newline at end of file diff --git a/pages/attendanceStatus/emergencyEvents.vue b/pages/attendanceStatus/emergencyEvents.vue index bc01744..48f0e04 100644 --- a/pages/attendanceStatus/emergencyEvents.vue +++ b/pages/attendanceStatus/emergencyEvents.vue @@ -1,43 +1,38 @@