ccy_DIB/pages/attendanceStatus/attendanceStatistics.vue
ylj20011123 590499fb84 update
2025-08-18 19:09:14 +08:00

484 lines
17 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>
<page-meta :page-style="'overflow:' + (showPopup ? 'hidden' : 'visible')"></page-meta>
<view class="main">
<!-- 自定义的页面顶部内容 -->
<view class="summaryTab" :style="{ height: (menu.bottom + 14) + 'px' }">
<view class="leftArrow" :style="{ top: (menu.top + ((menu.height - 24) / 2)) + 'px' }">
<image class="img" src="https://eshangtech.com/ShopICO/ahyd-BID/commercial/navigation-left.svg"
@click="handleBack"></image>
<view class="picker" :style="{ top: (menu.bottom + 24) + 'px' }" @click="handleChangeService">
<view class="selectService">
<image class="img" src="https://eshangtech.com/ShopICO/ahyd-BID/commercial/fixed.svg"></image>
<view class="select">
<view class="content">
<view class="uni-input">{{ serviceInfo.SERVERPART_NAME ? serviceInfo.SERVERPART_NAME :
'' }}
</view>
<image class="rightArrow"
src="https://eshangtech.com/ShopICO/ahyd-BID/commercial/rightArrow.svg"></image>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 考勤统计的列表 -->
<view class="attendanceListBox" :style="{ paddingTop: (menu.bottom + 30) + 'px' }">
<view class="onDutyPersonBoxHeader">
<text class="title">考勤统计</text>
<!-- 居中的日历时间 -->
<view class="dateBox">
<view class="centerDateBox">
<image class="arrowIcon" src="https://eshangtech.com/cyy_DIB/leftArrowIcon.png"
@click="handleChangeDate(2)" />
<view class="center">
<text class="date-text">{{ selectDate ? $util.cutDate(new Date(selectDate), 'YYYY-MM') : ""
}}</text>
<!-- <text class="date-icon">📅</text> -->
</view>
<image class="arrowIcon" src="https://eshangtech.com/cyy_DIB/rightArrowIcon.png"
@click="handleChangeDate(1)" />
</view>
</view>
</view>
<view class="attendanceStatisticsItem" v-for="(item, index) in attendanceStatisticsData" :key="index"
:style="{
borderTopRightRadius: index === 0 ? '0' : '',
borderTopLeftRadius: index === 0 ? '0' : '',
marginBottom: index + 1 === attendanceStatisticsData.length ? '0' : '24rpx'
}">
<view class="attendanceStatisticsItemTop">
<view class="eventsItem" style="margin-bottom: 16rpx;">
<view class="eventsHaveImgLabel">
<image class="eventsHaveImg" src="https://eshangtech.com/cyy_DIB/personIcon.png" />
<view class="eventsHaveLabel">联系人</view>
</view>
<view class="eventsValue">{{ item.userName || "" }}</view>
</view>
<view class="eventsItem">
<view class="eventsHaveImgLabel">
<image class="eventsHaveImg" src="https://eshangtech.com/cyy_DIB/phoneLabelIcon.png" />
<view class="eventsHaveLabel">联系电话</view>
</view>
<view class="eventsValue">{{ item.phone || "" }}</view>
</view>
</view>
<view class="line"></view>
<view class="attendanceStatisticsItemTop attendanceStatisticsItemBottom">
<view class="eventsItem">
<view class="eventsHaveImgLabel">
<view class="eventsHaveLabel">当月排班</view>
</view>
<view class="eventsValue">{{ item.scheduleTotal || "" }}</view>
</view>
<view class="eventsItem">
<view class="eventsHaveImgLabel">
<view class="eventsHaveLabel">出勤</view>
</view>
<view class="eventsValue">{{ item.attendTotal || "" }}</view>
</view>
<view class="eventsItem">
<view class="eventsHaveImgLabel">
<view class="eventsHaveLabel">休息</view>
</view>
<view class="eventsValue">{{ item.restTotal || "" }}</view>
</view>
<view class="eventsItem">
<view class="eventsHaveImgLabel">
<view class="eventsHaveLabel">迟到</view>
</view>
<view class="eventsValue">{{ item.lateTotal || "" }}</view>
</view>
<view class="eventsItem" style="margin-bottom: 0;">
<view class="eventsHaveImgLabel">
<view class="eventsHaveLabel">早退</view>
</view>
<view class="eventsValue">{{ item.earlyTotal || "" }}</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import request from "@/util/index.js";
import { formatTime } from '@/util/dateTime/index.js'
export default {
data() {
const nowDay = this.$util.cutDate(new Date(), 'YYYY-MM-DD') // 有数据的最近日期
return {
menu: {},
serviceInfo: {},
showPopup: false,
selectDate: nowDay,// 选中的时间
attendanceStatisticsData: [],
isFirst: true,
seatInfo: {}
}
},
onLoad() {
this.menu = uni.getMenuButtonBoundingClientRect()
let currentService = uni.getStorageSync('currentService')
this.serviceInfo = currentService
this.handleGetServerpartDetail(currentService.Serverpart_ID || currentService.SERVERPART_ID)
this.handleGetData(currentService.SERVERPART_NAME)
},
async onShow() {
let currentService = uni.getStorageSync('currentService')
if (currentService.Serverpart_ID !== this.serviceInfo.SERVERPART_ID && !this.isFirst) {
this.handleGetServerpartDetail(currentService.Serverpart_ID)
this.handleGetData(currentService.SERVERPART_NAME)
}
this.isFirst = false
},
methods: {
// 拿到数据
async handleGetData(SERVERPART_NAME) {
let req = {
bsessionKey: "0B30475A94674D608022885F7763959B",
workTime: new Date(this.selectDate).getTime(),
saName: SERVERPART_NAME || "",// 服务区名称
phone: "",// 手机号码
}
uni.showLoading({
title: "加载中..."
})
const data = await new Promise((resolve, reject) => {
uni.request({
url: "https://fwqznxj.yciccloud.com:9081/ynjt/pushManage/queryUserSchedule",
method: "POST",
data: req,
header: {
"content-type": "application/x-www-form-urlencoded",
},
success(res) {
resolve(res.data.data)
},
});
});
uni.hideLoading()
let list = data
if (list && list.length > 0) {
list.forEach((item) => {
item.dutyClockInTime = item.dutyClockInTime ? formatTime(item.dutyClockInTime) : ""
item.offDutyClockInTime = item.offDutyClockInTime ? formatTime(item.offDutyClockInTime) : ""
})
}
this.attendanceStatisticsData = list
},
// 查询服务区详情
async handleGetServerpartDetail(id) {
let currentService = uni.getStorageSync("currentService");
let seatInfo = uni.getStorageSync("seatInfo");
this.seatInfo = JSON.parse(seatInfo);
let req = {
ServerpartId: id || currentService.Serverpart_ID || currentService.SERVERPART_ID,
latitude: this.seatInfo.latitude,
longitude: this.seatInfo.longitude,
};
console.log('req', req);
uni.showLoading({
title: "加载中...",
});
const data = await request.$webJavaGet(
"/third-party/getServerPartInfo",
req
);
uni.hideLoading();
let obj = data.Result_Data;
this.serviceInfo = obj;
this.$forceUpdate();
console.log('this.serviceInfo', this.serviceInfo);
},
// 改变服务区
handleChangeService() {
this.$util.toNextRoute("navigateTo", "/pages/map/index?type=attendanceStatus");
},
handleBack() {
uni.navigateBack({
delta: 1
});
},
// 修改日期
async handleChangeDate(type) {
this.attendanceStatisticsData = []
// type 1 加一天 2 减一天
// 兼容 iOS把 2025-08-15 转成 2025/08/15
const cur = new Date((this.selectDate || '').replace(/-/g, '/'));
if (Number.isNaN(cur.getTime())) return;
// 1加一月2减一月其他不变
const delta = type === 1 ? 1 : (type === 2 ? -1 : 0);
// 目标月份的最后一天new Date(年, 目标月+1, 0)
const last = new Date(cur.getFullYear(), cur.getMonth() + delta + 1, 0);
const y = last.getFullYear();
const m = String(last.getMonth() + 1).padStart(2, '0');
const d = String(last.getDate()).padStart(2, '0');
this.selectDate = `${y}-${m}-${d}`;
await this.handleGetData(this.serviceInfo.SERVERPART_NAME)
},
}
}
</script>
<style lang="less" scoped>
@bg: #f8f9fa;
@muted: #666;
@card: #fff;
@shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
@primary: #27B25F;
@primary2: #4CCC7F;
@ok: #2ed573;
@warn: #ff9f43;
@danger: #ff4757;
.main {
width: 100vw;
min-height: 100vh;
background-color: #f0f2f3;
box-sizing: border-box;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
.summaryTab {
position: fixed;
left: 0;
top: 0;
width: 100vw;
// background: #fff;
background-image: url("https://eshangtech.com/minTestImg/pageBg.png");
z-index: 99;
display: flex;
align-items: center;
box-sizing: border-box;
padding-bottom: 16px;
.leftArrow {
width: 100%;
height: 24px;
position: absolute;
// left: 16px;
z-index: 99999999999;
box-sizing: border-box;
display: flex;
align-items: center;
padding: 0 32rpx;
.img {
width: 24px;
height: 24px;
margin-right: 8px;
z-index: 99;
}
.picker {
.selectService {
display: flex;
align-items: center;
.img {
width: 40px;
height: 40px;
z-index: 2;
}
.select {
height: 32px;
background: #fff;
border-radius: 0 16px 16px 0;
transform: translateX(-40px);
box-sizing: border-box;
padding-left: 35px;
padding-right: 8rpx;
display: flex;
align-items: center;
.content {
display: flex;
align-items: center;
.uni-input {
padding: 0;
background: transparent;
font-size: 28rpx;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: #160002;
}
.area {
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #786B6C;
line-height: 40px;
margin-left: 4px;
}
.rightArrow {
width: 12px;
height: 12px;
}
.noticeText {
font-size: 24rpx;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
color: #B6BACB;
line-height: 40rpx;
white-space: nowrap;
}
}
}
}
}
}
}
.attendanceListBox {
width: 100%;
box-sizing: border-box;
padding: 0 32rpx;
.onDutyPersonBoxHeader {
background: @bg;
padding: 0 30rpx;
border-bottom: 1rpx solid #e9ecef;
font-weight: 700;
font-size: 28rpx;
color: #2c3e50;
display: flex;
justify-content: space-between;
align-items: center;
border-top-left-radius: 8rpx;
border-top-right-radius: 8rpx;
.dateBox {
box-sizing: border-box;
padding: 16rpx 0;
display: flex;
align-items: center;
justify-content: center;
.centerDateBox {
display: flex;
align-items: center;
gap: 10rpx;
padding: 10rpx 20rpx;
border-radius: 30rpx;
background-color: #fff;
// border: 2rpx solid #27B35F;
// background: rgba(255, 255, 255, .15);
.arrowIcon {
width: 40rpx;
height: 40rpx;
}
.center {
.date-text {
font-size: 28rpx;
font-weight: 700;
}
}
}
}
}
.attendanceStatisticsItem {
width: 100%;
box-sizing: border-box;
padding: 24rpx;
box-shadow: @shadow;
border-radius: 8rpx;
background-color: #fff;
.attendanceStatisticsItemTop {
width: 100%;
flex-wrap: wrap;
.eventsItem {
width: 50%;
display: inline-block;
display: flex;
align-items: center;
.eventsHaveImgLabel {
display: flex;
width: 200rpx;
align-items: center;
.eventsHaveImg {
width: 30rpx;
height: 30rpx;
margin-right: 16rpx;
margin-top: 6rpx;
}
.eventsHaveLabel {
width: 154rpx;
font-size: 24rpx;
}
}
.eventsLabel {
width: 200rpx;
text-align: left;
font-size: 24rpx;
}
.eventsValue {
flex: 1;
font-size: 24rpx;
}
}
}
.line {
width: 100%;
height: 2rpx;
background-color: #dad9d3;
margin: 24rpx 0;
}
.attendanceStatisticsItemBottom {
display: flex;
flex-wrap: wrap;
align-items: center;
.eventsItem {
margin-bottom: 16rpx;
}
}
}
}
}
</style>