| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151 |
- <template>
- <page-meta root-font-size="system" />
- <view class="attendance-page">
- <view class="header">
- <text class="title">我的考勤记录</text>
- <picker mode="selector" :range="timeRanges" @change="onTimeRangeChange">
- <view class="picker">
- {{ selectedTimeRange }}/切换
- </view>
- </picker>
- </view>
- <!-- 今日签到信息区域 -->
- <view class="todayCheckIn" v-if="todayInfoShow">
- <view class="check-in-container">
- <text class="todayAttTitle">今日签到信息</text>
- <view class="action-buttons">
- <text class="exceptionText" v-if="lackCardState" @click="toBuKa">处理异常</text>
- <text class="viewMoreText" @click="showAllRecords">查看更多</text>
- </view>
- <view class="info-row">
- <view>
- <text class="ygoa_icon icon-date"></text>
- <text class="value">日期:</text>
- </view>
- <text class="label">{{ todayData.day }}</text>
- </view>
- <view class="info-row">
- <view>
- <text class="ygoa-icon icon-day"></text>
- <text class="value" v-if="!clockMultiple">晨签时间:</text>
- <text class="value" v-if="clockMultiple">早上签到:</text>
- </view>
- <view>
- <text class="label">{{ todayData.startTime || '未打卡' }}</text>
- <text class="att_status" v-if="config.companyCode !== 'yz'">{{todayData.startStatus}}</text>
- </view>
- </view>
- <view class="info-row" v-if="clockMultiple">
- <view>
- <text class="ygoa-icon icon-day"></text>
- <text class="value">早上签退:</text>
- </view>
- <view>
- <text class="label">{{ todayData.endTimeAm || '未打卡' }}</text>
- <text class="att_status" v-if="config.companyCode !== 'yz'">{{todayData.endStatusForAm}}</text>
- </view>
- </view>
- <view class="info-row" v-if="clockMultiple">
- <view>
- <text class="ygoa-icon icon-night"></text>
- <text class="value">下午签到:</text>
- </view>
- <view>
- <text class="label">{{ todayData.startTimePm || '未打卡' }}</text>
- <text class="att_status" v-if="config.companyCode !== 'yz'">{{todayData.startStatusForPm}}</text>
- </view>
- </view>
- <view class="info-row">
- <view>
- <text class="ygoa-icon icon-night"></text>
- <text class="value" v-if="!clockMultiple">晚签时间:</text>
- <text class="value" v-if="clockMultiple">下午签退:</text>
- </view>
- <view>
- <text class="label">{{ todayData.endTime || '未打卡' }}</text>
- <text class="att_status" v-if="config.companyCode !== 'yz'">{{todayData.endStatus}}</text>
- </view>
- </view>
- </view>
-
- <!-- 查看所有记录的弹窗 -->
- <uni-popup ref="allRecordsPopup" type="bottom">
- <view class="popup-content">
- <view class="popup-header">
- <text class="popup-title">当日所有打卡记录</text>
- <text class="popup-close" @click="closeDialog">×</text>
- </view>
- <scroll-view scroll-y class="popup-body">
- <view v-if="allAttList.length === 0" class="empty-tip">
- 暂无打卡记录
- </view>
- <view v-for="(item, index) in allAttList" :key="index" class="record-item">
- <view class="record-info">
- <text class="record-type">{{ formatAttType(item.att_type_id) }}</text>
- <text class="record-time">{{ item.att_time }}</text>
- </view>
- <view class="record-detail" v-if="item.location">
- <text class="detail-label">位置:</text>
- <text class="detail-value">{{ item.location }}</text>
- </view>
- <view class="record-detail" v-if="item.remark">
- <text class="detail-label">备注:</text>
- <text class="detail-value">{{ item.remark }}</text>
- </view>
- </view>
- </scroll-view>
- </view>
- </uni-popup>
- <!-- 分界线 -->
- <view class="divider"></view>
- <!-- 打卡记录 -->
- <!-- <view class="container">
- <view class="header">
- <text class="clockRecordTitle">打卡记录</text>
- </view>
- <view class="content" style="height: 41vh;">
- <z-paging :fixed="false" :default-page-size="pSize" default-page-no="1" @query="queryData" ref="paging">
- <view class="clockRecord" v-for="clockRecord in clockRecords" :key="clockRecord.date">
- <text class="date">{{ clockRecord.date }}</text>
- <view class="shifts">
- <view class="shift">
- <text class="shift-label">晨签:</text>
- <text class="shift-time">{{ clockRecord.morning||'没有该记录'}}</text>
- </view>
- <view class="shift">
- <text class="shift-label">晚签:</text>
- <text class="shift-time">{{ clockRecord.evening ||'没有该记录'}}</text>
- </view>
- </view>
- </view>
- </z-paging>
- </view>
- </view> -->
- <!-- 日历板块 -->
- <template>
- <view class="calendar-content">
- <view>
- <uni-calendar class="uni-calendar--hook" :selected="calenderData" :showMonth="true" @change="changeDate"
- @monthSwitch="monthSwitch" />
- </view>
- </view>
- </template>
- </view>
- <!-- 周,月数据统计区域 -->
- <view class="statistics" v-if="chartShow">
- <view class="statistic-card">
- <view class="statistic-title">{{ selectedTimeRange }}考勤统计</view>
- <view class="statistic-item">
- <view>
- <text class="ygoa_icon icon-attendance"></text>
- <text class="label">出勤:</text>
- </view>
- <text class="value">{{ attendanceCount }}</text>
- </view>
- <view class="statistic-item">
- <view>
- <text class="ygoa_icon icon-goOut"></text>
- <text class="label">外出:</text>
- </view>
- <text class="value">{{ goOutCount }}</text>
- </view>
- <view class="statistic-item" v-if="config.companyCode !== 'yz'">
- <view>
- <text class="ygoa_icon icon-late"></text>
- <text class="label">迟到:</text>
- </view>
- <text class="value">{{ lateCount }}</text>
- </view>
- <view class="statistic-item" v-if="config.companyCode !== 'yz'">
- <view>
- <text class="ygoa_icon icon-leaveEarly"></text>
- <text class="label">早退:</text>
- </view>
- <text class="value">{{ leaveEarlyCount }}</text>
- </view>
- <view class="statistic-item">
- <view>
- <text class="ygoa_icon icon-absenteeism"></text>
- <text class="label">缺勤:</text>
- </view>
- <text class="value">{{ absenteeismCount }}</text>
- </view>
- </view>
- </view>
- <!-- 图表区域 -->
- <view class="chart-container" v-if="chartShow">
- <view class="">
- <text class="chart-title">考勤趋势图</text>
- <view class="charts-box">
- <qiun-data-charts :type="chartsType" :opts="opts" :chartData="chartData" />
- </view>
- </view>
- </view>
- </view>
- </template>
- <script setup lang="ts">
- import {ref,onMounted,reactive} from 'vue';
- import { getProcessList } from '@/api/work.js'
- import {checkAttendance,getMyTotalCount,getMyQDQtAttendance,getMyTotalMonthCount} from '@/api/mine.js'
- import {useUserStore} from '@/store/user.js';
- import { useConfigStore } from '@/store/config'
- import $tab from '@/plugins/tab.js'
- import config from '@/config.js';
- import UniPopup from '@/uni_modules/uni-popup/components/uni-popup/uni-popup.vue';
- const userStore = useUserStore();
- //考勤规则数据
- const configStore = useConfigStore();
- // 创建一个响应式对象记录今天的考勤数据
- const todayData = reactive({
- day: '', // 当前日期
- startTime: '', // 晨签到时间
- startStatus:'',//晨签状态
- endTime: '', // 晚签到时间
- endStatus:'',//晚签状态
- endTimeAm: '',//早上下班签退时间
- endStatusForAm:'',//早上下班签退状态
- startTimePm: '', // 下午上班签到时间
- startStatusForPm:'',//下午上班签到状态
- })
- // 控制今日签到信息和图表显示的状态
- const todayInfoShow = ref(true) // 今日签到信息是否显示
- const chartShow = ref(false) // 图表是否显示
- // 图表类型的响应式引用
- const chartsType = ref('')
- // 图表要填充的数据
- const chartData = ref({})
- // 图表配置选项
- const opts = ref({
- color: ["#EE6666", "#FAC858", "#FC8452", "#73C0DE", "#3CA272", "#1890FF", "#91CB74", "#9A60B4",
- "#ea7ccc"
- ], // 设定图表颜色
- padding: [15, 15, 0, 5],
- enableScroll: false, // 滚动
- legend: {}, // 图例设置
- xAxis: {
- disableGrid: true ,// 禁用网格线
- // scrollShow: true,
- },
- yAxis: {
- data: [{
- min: 0 // y轴最小值
- }]
- },
- extra: {
- column: {
- type: "group",
- width: 30,
- activeBgColor: "#000000",
- activeBgOpacity: 0.08
- }
- }
- });
- // 时间范围选择数组
- const timeRanges = ref(['日', '周', '月']);
- const selectedTimeRange = ref('日'); // 初始化选择的时间范围为“日”
- // 考勤相关统计数据
- const attendanceCount = ref(0); // 出勤次数
- const goOutCount = ref(0); // 外出次数
- const lateCount = ref(0); // 迟到次数
- const leaveEarlyCount = ref(0); // 早退次数
- const absenteeismCount = ref(0); // 缺勤次数
- //用户id
- const userId = userStore.user.useId; //拿到用户id
- //当前周的周一日期
- const thisMondayDate = ref('');
-
- const clockMultiple = ref(false)
- if(config.clock && config.clock == 'multiple'){
- clockMultiple.value = true;
- }else{
- clockMultiple.value = false;
- }
- onMounted(() => {
- initAttData(); //初始化日考勤数据
- });
- //初始化考勤数据
- function initAttData() {
- const nowDate = new Date();
- todayData.day = formatDate(nowDate);
- getthisMondayDate(nowDate);
- getDayAttData();
- initCalenderData();
- }
- //格式化日期
- function formatDate(date) {
- const year = date.getFullYear(); // 获取年份
- const month = date.getMonth() + 1; // 获取月份
- const day = date.getDate(); // 获取日期
- // 格式化月份和日期为两位数
- const formattedMonth = month < 10 ? '0' + month : month;
- const formattedDay = day < 10 ? '0' + day : day;
- return `${year}-${formattedMonth}-${formattedDay}`;
- }
- //获取日考勤数据
- const currentAttList = ref([]) // 保存当前完整的考勤记录列表
-
- function getDayAttData() {
- const params = {
- universalid: userId,
- rizi: todayData.day
- }
- checkAttendance(params).then(res => {
- if ("success" == res.returnMsg) {
- //数据初始化
- todayData.startTime = ''
- todayData.endTime = ''
- todayData.startTimePm = ''
- todayData.endTimeAm = ''
- todayData.startStatus=''
- todayData.endStatus=''
- todayData.startStatusForPm=''
- todayData.endStatusForAm=''
- if (res.returnParams.list.length == 0) {
- currentAttList.value = []
- return
- }
- const attList = res.returnParams.list;
- // 保存完整列表供弹窗使用
- currentAttList.value = attList
-
- let time1;
- let time2;
- let time3;
- let time4;
- const filteredRecord1 = attList.filter(item => item.att_type_id === '1');
- if (filteredRecord1.length > 0) {
- time1 = filteredRecord1.reduce((latest, current) => {
- const latestTime = new Date(latest.att_time);
- const currentTime = new Date(current.att_time);
- return (currentTime < latestTime) ? current : latest;
- });
- }
-
- //上午下班,取最大时间的那个
- const filteredRecord3 = attList.filter(item => item.att_type_id === '7');
- if (filteredRecord3.length > 0) {
- time3 = filteredRecord3.reduce((latest, current) => {
- const latestTime = new Date(latest.att_time);
- const currentTime = new Date(current.att_time);
- return (currentTime > latestTime) ? current : latest;
- });
- }
-
- //下午上班,取最小时间
- const filteredRecord4 = attList.filter(item => item.att_type_id === '8');
- if (filteredRecord4.length > 0) {
- time4 = filteredRecord4.reduce((latest, current) => {
- const latestTime = new Date(latest.att_time);
- const currentTime = new Date(current.att_time);
- return (currentTime < latestTime) ? current : latest;
- });
- }
-
- //拿到所有签退数据后,取最大时间的那个
- const filteredRecord2 = attList.filter(item => item.att_type_id === '2');
- if (filteredRecord2.length > 0) {
- time2 = filteredRecord2.reduce((latest, current) => {
- const latestTime = new Date(latest.att_time);
- const currentTime = new Date(current.att_time);
- return (currentTime > latestTime) ? current : latest;
- });
- }
-
- if (time1 !== undefined) {
- todayData.startTime = time1.att_time.split(' ')[1];
- if(subOneMinute(todayData.startTime)>=configStore.signInTimeRange[0][1]){
- todayData.startStatus='(迟到)'
- }
- }
- if (time3 !== undefined) {
- todayData.endTimeAm = time3.att_time.split(' ')[1];
- if(todayData.endTimeAm<configStore.signOutTimeRange[0][0]){
- todayData.endStatusForAm='(早退)'
- }
- }
- if (time4 !== undefined) {
- todayData.startTimePm = time4.att_time.split(' ')[1];
- if(subOneMinute(todayData.startTimePm)>=configStore.signInTimeRange[1][1]){
- todayData.startStatusForPm='(迟到)'
- }
- }
- if (time2 !== undefined) {
- todayData.endTime = time2.att_time.split(' ')[1];
- if(todayData.endTime<configStore.signOutTimeRange[1][0]){
- todayData.endStatus='(早退)'
- }
- }
- }
- })
- }
- //减一分钟
- function subOneMinute(timeStr) {
- // 将时间字符串转换为 Date 对象
- const [hours, minutes, seconds] = timeStr.split(':').map(Number);
- const date = new Date();
- date.setHours(hours, minutes, seconds, 0); // 设置时间为给定的时分秒
- // 减去一分钟
- date.setMinutes(date.getMinutes() - 1);
- return date.toTimeString().slice(0, 8);
- }
- //打卡历史记录(日历版)
- //日历表数据
- const calenderData = ref([])
- // 初始化此月日历数据
- function initCalenderData() {
- const params = {
- type: 2, //设置时间区间
- universalid: userId,
- ks_att_time: todayData.day.slice(0, 8) + '01',
- js_att_time: todayData.day,
- pSize: parseInt(todayData.day.slice(8, 10), 10),//当前天数
- p: 1
- }
- getCalenderData(params)
- }
- //日历数据的刷新
- function getCalenderData(params){
- getMyQDQtAttendance(params).then(({ returnParams }) => {
- //定义一个数组用于接收日历data
- const thisCalenderData=[]
- returnParams.list.forEach(item => {
- if ((!item.type.includes('1') || !item.type.includes('2'))&&item.att_date.slice(0, 10)!==todayData.day) {
- const calenderDataInfo = {
- date: item.att_date.slice(0, 10),
- info: '缺卡'
- }
- thisCalenderData.push(calenderDataInfo)
- }
- });
- calenderData.value=thisCalenderData
- })
- }
-
- const lackCardState=ref(false)//缺卡异常处理状态
- // 查看所有记录的弹窗
- const allRecordsPopup = ref(null)
- const showAllRecordsDialog = ref(false)
- const allAttList = ref([]) // 弹窗中显示的列表
-
- // 显示所有考勤记录弹窗 - 直接使用已获取的数据
- function showAllRecords() {
- allAttList.value = currentAttList.value || []
- showAllRecordsDialog.value = true
- if (allRecordsPopup.value) {
- allRecordsPopup.value.open()
- }
- }
-
- // 格式化考勤类型
- function formatAttType(typeId) {
- const typeMap = {
- '1': '上午上班',
- '7': '上午下班',
- '8': '下午上班',
- '2': '下午下班'
- }
- return typeMap[typeId] || '未知类型'
- }
-
- // 关闭弹窗
- function closeDialog() {
- showAllRecordsDialog.value = false
- if (allRecordsPopup.value) {
- allRecordsPopup.value.close()
- }
- }
- //日历点击日期切换事件
- function changeDate(e) {
- // console.log('changeDate: ',e);
- // console.log("3:calenderData.value " + JSON.stringify(calenderData.value));
- if(config.companyCode && config.companyCode == 'yg'){
- lackCardState.value = !!e.extraInfo.info;//!!转布尔值
- }
- todayData.day = e.fulldate
- getDayAttData()
- }
-
- //补卡页面跳转
- function toBuKa(){
- const bukaType=todayData.startTime?'下班':'上班'
- getProcessList(userStore.user.useId, userStore.user.unitId).then(res => {
- const { modelName, modelId, control } = res.returnParams.fList.find(item => item.modelName === "补卡申请")
- $tab.navigateTo('/pages/work/edit/index?modelName=' + modelName + '&modelId=' + modelId + '&control=' + control+'&bukaDate='+todayData.day+'&bukaType='+bukaType)
- })
- // $tab.switchTab('/pages/tabbar-work/index?bukaDate='+todayData.day+'&bukaType='+bukaType)
- }
- //传入年份月份,返回此月天数
- function getDaysInMonth(year, month) {
- const date = new Date(year, month - 1, 1);
- // 将日期设置为下一个月的第0天,即当前月的最后一天
- date.setMonth(date.getMonth() + 1);
- date.setDate(0);
- // 返回当前月的最后一天的日期,即该月的天数
- return date.getDate();
- }
- //月份切换事件
- function monthSwitch(e) {
- const days=getDaysInMonth(e.year,e.month);
- //月份小于10前面补零
- const month = String(e.month).padStart(2, '0');
- const params = {
- type: 2, //设置时间区间
- universalid: userId,
- ks_att_time: e.year+'-'+month+'-' + '01',
- js_att_time: e.year+'-'+month+'-' +days,
- pSize: days,
- p: 1
- }
- getCalenderData(params);
- }
- // //打卡历史记录(下拉刷新版)
- // const paging = ref(null)
- // const pSize = ref(5)
- // function complete(list, total, pageNo) {
- // if (pageNo == 1) {
- // paging.value.complete(list);
- // return
- // }
- // // 防止重复获取最后一次信息
- // if (pSize.value * pageNo < total) {
- // paging.value.complete(list)
- // } else {
- // paging.value.complete([])
- // }
- // }
- // //日考勤历史记录
- // const clockRecords = ref([])
- // const totalPage = ref(0)
- // //获取日考勤历史(下拉刷新)
- // function getDayAttHistory() {
- // const params = {
- // type: 1, //不设时间区间
- // universalid: userId,
- // ks_att_time: '',
- // js_att_time: '',
- // pSize: pSize.value,
- // p: 1
- // }
- // getMyQDQtAttendance(params).then(({ returnParams }) => {
- // totalPage.value = Math.ceil(returnParams.total / pSize.value)
- // const list = returnParams.list.map(item => {
- // return {
- // date: item.att_date.substring(0, 10),
- // morning: item.time.split(',')[item.type.split(',').indexOf("1")],
- // evening: item.time.split(',')[item.type.split(',').indexOf("2")],
- // }
- // });
- // clockRecords.value = list;
- // complete(clockRecords.value, returnParams.total, returnParams.current)
- // })
- // }
- // // 刷新
- // function queryData(pageNo, pSize, queryType) {
- // switch (queryType) {
- // case 0: // 下拉刷新
- // case 1: // 初始加载
- // getDayAttHistory()
- // break
- // case 3: // 上拉加载
- // scrollQuery(pageNo, pSize)
- // break
- // default: // 默认刷新
- // getDayAttHistory()
- // break
- // }
- // }
- // //上拉加载事件
- // function scrollQuery(pageNo, pSize) {
- // const params = {
- // type: 1, //不设时间区间
- // universalid: userId,
- // ks_att_time: '',
- // js_att_time: '',
- // pSize: pSize,
- // p: pageNo
- // }
- // getMyQDQtAttendance(params).then(({ returnParams }) => {
- // const list = returnParams.list.map(item => {
- // return {
- // date: item.att_date.substring(0, 10),
- // morning: item.time.split(',')[item.type.split(',').indexOf("1")],
- // evening: item.time.split(',')[item.type.split(',').indexOf("2")],
- // }
- // });
- // if (pageNo <= totalPage.value) {
- // clockRecords.value.push(...list);
- // }
- // complete(list, returnParams.total, pageNo)
- // })
- // }
- // 日周月时间范围切换事件
- function onTimeRangeChange(event) {
- const selectedIndex = event.detail.value;
- selectedTimeRange.value = timeRanges.value[selectedIndex]; // 设置选择的时间范围(日周月)
- // 根据选择的时间范围更新展示内容
- switch (selectedTimeRange.value) {
- case '日':
- getDayAttData();
- showDay(); // 显示今日考勤
- break;
- case '周':
- chartsType.value = 'pie'; // 设置图表类型为饼图
- fetchWeekAttData().then(message => {
- // console.log(message);
- showWeekAndMonth();
- updateChart(message);
- })
- .catch(error => {
- console.error(error);
- });
- break;
- case '月':
- chartsType.value = 'column'; // 设置图表类型为柱状图
- fetchMonthAttData();
- showWeekAndMonth();
- // fetchMonthAttData().then(message => {
- // console.log('message', message);
- // showWeekAndMonth();
- // updateChart(message);
- // })
- // .catch(error => {
- // console.error(error);
- // });
- break;
- }
- };
- // 显示今日考勤数据
- function showDay() {
- todayInfoShow.value = true; // 显示今日签到信息
- chartShow.value = false; // 隐藏图表
- }
- // 显示周或者月考勤
- function showWeekAndMonth() {
- todayInfoShow.value = false; // 隐藏今日签到信息
- chartShow.value = true; // 显示图表
- }
- //计算本周周一日期
- function getthisMondayDate(today) {
- const dayOfWeek = today.getDay(); // 0 (周日) 到 6 (周六)
- const dayOfMonth = today.getDate();
- // 计算本周周一的日期
- const offset = dayOfWeek === 0 ? -6 : 1; // 如果今天是周日,则偏移量为-6,否则为1
- const thisMonday = new Date(today);
- thisMonday.setDate(dayOfMonth - dayOfWeek + offset);
- thisMondayDate.value = formatDate(thisMonday);
- }
- //获取周考勤记录
- function fetchWeekAttData() {
- return new Promise((resolve, reject) => {
- const params = {
- staffId: userId,
- start_date: thisMondayDate.value,
- end_date: todayData.day
- }
- getMyTotalCount(params).then(res => {
- const myWeekAttData = res.returnParams;
-
- const mockData = {
- series: [{
- data: [
- {
- "name": "缺勤",
- "value": myWeekAttData.type6,
- "labelText": "缺勤:" + myWeekAttData.type6 + "次"
- },
- ...(config.companyCode !== 'yz' ? [{
- "name": "迟到",
- "value": myWeekAttData.type4,
- "labelText": "迟到:" + myWeekAttData.type4 + "次"
- }] : []),
- ...(config.companyCode !== 'yz' ? [{
- "name": "早退",
- "value": myWeekAttData.type5,
- "labelText": "早退:" + myWeekAttData.type5 + "次"
- }] : []),
- {
- "name": "出勤",
- "value": myWeekAttData.attDays,
- "labelText": "出勤:" + myWeekAttData.attDays + "次"
- },
- {
- "name": "外出",
- "value": myWeekAttData.type2,
- "labelText": "外出:" + myWeekAttData.type2 + "次"
- },
- {
- "name": "公休",
- "value": myWeekAttData.type1,
- "labelText": "公休:" + myWeekAttData.type1 + "次"
- },
- // {
- // "name": "未排班",
- // "value": myWeekAttData.type3,
- // "labelText": "未排班:" + myWeekAttData.type3 + "次"
- // }
- ]
- }],
- };
- // const weekData = mockData.series[0].data;
- attendanceCount.value = myWeekAttData.attDays;
- goOutCount.value = myWeekAttData.type2;
- if(config.companyCode !== 'yz') {
- lateCount.value = myWeekAttData.type4;
- leaveEarlyCount.value = myWeekAttData.type5;
- }
- absenteeismCount.value = myWeekAttData.type6;
- resolve(mockData)
- }).catch(error => {
- reject(error)
- })
- })
- }
- // 获取月考勤记录
- function fetchMonthAttData() {
- //数据初始化
- attendanceCount.value = 0;
- goOutCount.value = 0;
- lateCount.value = 0;
- leaveEarlyCount.value = 0;
- absenteeismCount.value = 0;
- const params = {
- staffId: userId,
- now_date: todayData.day
- }
- getMyTotalMonthCount(params).then(res=>{
- const myMonthAttData = res.returnParams;
- let data1 = []; // 收集 type6 的值
- let data2 = []; // 收集 type4 的值
- let data3 = []; // 收集 type5 的值
- // console.log('attendanceCount: ',attendanceCount.value);
- // 遍历 myMonthAttData 并收集指定类型的值
- myMonthAttData.forEach(item => {
- data1.push(item.type6);
- if(config.companyCode !== 'yz') {
- data2.push(item.type4);
- data3.push(item.type5);
- }
- attendanceCount.value += item.attDays;
- goOutCount.value += item.type2;
- if(config.companyCode !== 'yz') {
- lateCount.value += item.type4;
- leaveEarlyCount.value += item.type5;
- }
- absenteeismCount.value += item.type6;
- });
-
- // 定义一个常量数组生成器
- const generateWeekArray = n => Array.from({ length: n }, (_, i) => `第${i + 1}周`);
- let categoriesArr=generateWeekArray(myMonthAttData.length)
- // console.log(categoriesArr);
- const mockData = {
- categories: categoriesArr,
- series: [{
- name: "缺勤",
- data: data1
- }, ...(config.companyCode !== 'yz' ? [{
- name: "迟到",
- data: data2
- }, {
- name: "早退",
- data: data3
- }] : [])]
- };
- updateChart(mockData)
- })
- }
-
- // //获取六天前的日期
- // function getSixDaysAgo(dateStr) {
- // const date = new Date(dateStr);
- // date.setDate(date.getDate() - 6);
- // return date.toISOString().split('T')[0]; // 返回格式为'YYYY-MM-DD'的字符串
- // }
- // //获取一天前的日期
- // function getOneDaysAgo(dateStr) {
- // const date = new Date(dateStr);
- // date.setDate(date.getDate() - 1);
- // return date.toISOString().split('T')[0]; // 返回格式为'YYYY-MM-DD'的字符串
- // }
- // 更新图表数据
- function updateChart(res) {
- chartData.value = JSON.parse(JSON.stringify(res)); // 更新图表数据
- }
- </script>
- <style lang="scss" scoped>
- // @import "@/static/font/ygoa/iconfont.css";
- .ygoa_icon {
- margin-right: 0.5rem;
- font-size: calc(2rem + 0px) !important;
- vertical-align: middle;
- /* 确保图标与文本竖直居中 */
- }
- .attendance-page {
- padding: 20px;
- background-color: #f9f9f9;
- ::v-deep .calendar-content {
- margin: -20px;
- margin-top: 20px;
- .uni-calendar__header {
- .uni-calendar__header-text {
- font-size: calc(14px + .5*(1rem - 16px)) !important;
- }
- .uni-calendar__backtoday {
- padding: 2px 8px 2px 10px !important;
- font-size: calc(0.75rem + 0px) !important;
- }
- }
- .uni-calendar__box {
- .uni-calendar__weeks {
- .uni-calendar__weeks-day {
- .uni-calendar__weeks-day-text {
- font-size: calc(14px + .5*(1rem - 16px)) !important;
- }
- }
- .uni-calendar__weeks-item {
- .uni-calendar-item__weeks-box-item {
- .uni-calendar-item__weeks-box-circle {
- width: calc(8px + .5*(1rem - 16px)) !important;
- height: calc(8px + .5*(1rem - 16px)) !important;
- top: calc(5px - .25*(1rem - 16px)) !important;
- right: calc(5px - .25*(1rem - 16px)) !important;
- }
- .uni-calendar-item__weeks-box-text {
- font-size: calc(14px + .5*(1rem - 16px)) !important;
- }
- .uni-calendar-item__weeks-lunar-text {
- font-size: calc(12px + .5*(1rem - 16px)) !important;
- }
- }
- }
- }
- }
- }
- }
- .header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 20px;
- .clockRecordTitle {
- font-size: calc(1.25rem + 0px) !important;
- margin: auto;
- }
- }
- .title {
- font-size: calc(1.5rem + 0px) !important;
- font-weight: bold;
- color: #333;
- }
- .picker {
- border: 1px solid #3498db;
- border-radius: 5px;
- padding: 10px;
- background-color: #ecf6fc;
- color: #3498db;
- }
- .statistics {
- // display: flex;
- justify-content: center;
- }
- .statistic-card {
- background: white;
- border-radius: 10px;
- padding: 20px;
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
- /* width: 100%; */
- max-width: 600px;
- }
- .statistic-title {
- text-align: center;
- font-size: calc(1.25rem + 0px) !important;
- font-weight: bold;
- color: #333;
- }
- .statistic-item {
- display: flex;
- justify-content: space-between;
- border-bottom: 1px solid #eee;
- padding: 10px 0;
- }
- .label {
- color: #666;
- }
- .value {
- font-size: calc(1.125rem + 0px) !important;
- font-weight: bold;
- line-height: calc(2rem + 0px) !important;
- color: #333;
- }
- .label {
- font-size: calc(1rem + 0px) !important;
- line-height: calc(2rem + 0px) !important;
- }
- .chart-container {
- margin-top: 20px;
- }
- .chart-title {
- font-size: calc(1.25rem + 0px) !important;
- font-weight: bold;
- text-align: center;
- margin-bottom: 10px;
- color: #333;
- }
- .charts-box {
- width: 100%;
- height: 300px;
- }
- .todayCheckIn {
- background-color: #ffffff;
- padding: 20px;
- margin: auto -20px; //抵消父级padding
- box-sizing: border-box;
- border-radius: 10px;
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
- }
- .check-in-container {
- width: 100%;
- height: 100%;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- position: relative;
- .exceptionText{
- /*position: absolute;
- top: 10px;
- right: 10px;
- color: blue;
- text-decoration: underline;*/
- color: #1890FF;
- text-decoration: underline;
- font-size: calc(14px + .5*(1rem - 16px));
- cursor: pointer;
- }
- .action-buttons {
- position: absolute;
- top: 5px;
- right: 10px;
- display: flex;
- flex-direction: column;
- align-items: flex-end;
- gap: 5px;
- }
- .viewMoreText {
- color: #1890FF;
- text-decoration: underline;
- font-size: calc(14px + .5*(1rem - 16px));
- cursor: pointer;
- }
- }
- .todayAttTitle {
- font-size: calc(1.375rem + 0px) !important;
- font-weight: bold;
- margin-bottom: 20px;
- }
- .info-row {
- width: 100%;
- display: flex;
- align-items: center;
- justify-content: space-between;
- margin-bottom: 10px;
- .att_status{
- color: red;
- }
- }
- .icon {
- width: 50rpx;
- height: 50rpx;
- margin-right: 20rpx;
- vertical-align: middle;
- /* 确保图标与文本竖直居中 */
- }
- .clockRecord {
- margin-bottom: 20px;
- padding: 10px;
- border: 1px solid #ccc;
- border-radius: 8px;
- }
- .date {
- font-size: 16px;
- font-weight: bold;
- margin-bottom: 5px;
- }
- .name {
- font-size: 14px;
- color: #666;
- margin-bottom: 10px;
- }
- .divider {
- border-bottom: 5px dashed #ccc; //虚线
- margin: 10px 0;
- }
- .shift-label {
- font-size: 14px;
- color: #333;
- }
- .shift-time {
- font-size: 14px;
- color: #333;
- }
-
- /* 弹窗样式 */
- .popup-content {
- background: white;
- border-radius: 10px 10px 0 0;
- overflow: hidden;
- }
-
- .popup-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 15px 20px;
- border-bottom: 1px solid #eee;
- }
-
- .popup-title {
- font-size: calc(16px + .5*(1rem - 16px));
- font-weight: bold;
- color: #333;
- }
-
- .popup-close {
- font-size: calc(24px + .5*(1rem - 16px));
- color: #999;
- cursor: pointer;
- padding: 0 5px;
- }
-
- .popup-body {
- max-height: 60vh;
- overflow-y: auto;
- padding: 15px 20px;
- }
-
- .empty-tip {
- text-align: center;
- padding: 30px 0;
- color: #999;
- font-size: calc(14px + .5*(1rem - 16px));
- }
-
- .record-item {
- padding: 12px 10px;
- border-bottom: 1px solid #f0f0f0;
- }
-
- .record-item:last-child {
- border-bottom: none;
- }
-
- .record-info {
- display: flex;
- align-items: center;
- margin-bottom: 8px;
- padding-right: 15px;
- }
-
- .record-type {
- font-size: calc(14px + .5*(1rem - 16px));
- font-weight: bold;
- color: #333;
- }
-
- .record-time {
- font-size: calc(14px + .5*(1rem - 16px));
- color: #666;
- margin-left: 30px;
- }
-
- .record-detail {
- display: flex;
- margin-top: 5px;
- font-size: calc(12px + .5*(1rem - 16px));
- }
-
- .detail-label {
- color: #999;
- margin-right: 5px;
- }
-
- .detail-value {
- color: #666;
- flex: 1;
- }
- </style>
|