|
|
@@ -10,7 +10,67 @@
|
|
|
</picker>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 数据统计区域 -->
|
|
|
+ <!-- 今日签到信息区域 -->
|
|
|
+ <view class="todayCheckIn" :class="{ 'show': shouldShow }">
|
|
|
+ <view class="check-in-container">
|
|
|
+ <text class="todayAttTitle">今日签到信息</text>
|
|
|
+ <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">晨签时间:</text>
|
|
|
+ </view>
|
|
|
+ <text class="label">{{ todayData.startTime || '未打卡' }} </text>
|
|
|
+ </view>
|
|
|
+ <view class="info-row">
|
|
|
+ <view>
|
|
|
+ <text class="ygoa-icon icon-night"></text>
|
|
|
+ <text class="value">晚签时间:</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <text class="label">{{ todayData.endTime || '未打卡' }} </text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ </view>
|
|
|
+ <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>
|
|
|
+ </view>
|
|
|
+
|
|
|
+
|
|
|
+ <!-- 周,月数据统计区域 -->
|
|
|
<view class="statistics" :class="{ 'show': chartShow }">
|
|
|
<view class="statistic-card">
|
|
|
<view class="statistic-title">{{ selectedTimeRange }}考勤统计</view>
|
|
|
@@ -53,43 +113,6 @@
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 今日签到信息区域 -->
|
|
|
- <view class="todayCheckIn" :class="{ 'show': shouldShow }">
|
|
|
- <view class="check-in-container">
|
|
|
- <text class="title2">今日签到信息</text>
|
|
|
- <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">晨签时间:</text>
|
|
|
- </view>
|
|
|
- <text class="label">{{ todayData.startTime || '未打卡' }} </text>
|
|
|
- </view>
|
|
|
- <view class="info-row">
|
|
|
- <view>
|
|
|
- <text class="ygoa-icon icon-night"></text>
|
|
|
- <text class="value">晚签时间:</text>
|
|
|
- </view>
|
|
|
-
|
|
|
- <text class="label">{{ todayData.endTime || '未打卡' }} </text>
|
|
|
- </view>
|
|
|
- <view class="info-row">
|
|
|
- <view>
|
|
|
- <text class="ygoa-icon icon-checkInStatus"></text>
|
|
|
- <text class="value">状态:</text>
|
|
|
- </view>
|
|
|
-
|
|
|
- <text class="label">{{ todayData.status }}</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
|
|
|
<!-- 图表区域 -->
|
|
|
<view class="chart-container" :class="{ 'show': chartShow }">
|
|
|
@@ -105,484 +128,641 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { ref, onMounted, reactive } from 'vue';
|
|
|
-import { checkAttendance, getMyTotalCount } from '@/api/mine.js'
|
|
|
-import { useUserStore } from '@/store/user.js';
|
|
|
-const userStore = useUserStore();
|
|
|
-
|
|
|
-// 创建一个响应式对象记录今天的考勤数据
|
|
|
-const todayData = reactive({
|
|
|
- day: '2024-11-11', // 当前日期
|
|
|
- startTime: '', // 晨签到时间
|
|
|
- endTime: '', // 晚签到时间
|
|
|
- status: '未打卡' // 签到状态
|
|
|
-})
|
|
|
-
|
|
|
-// 控制今日签到信息和图表显示的状态
|
|
|
-const shouldShow = ref(true) // 今日签到信息是否显示
|
|
|
-const chartShow = ref(false) // 图表是否显示
|
|
|
-
|
|
|
-// 图表类型的响应式引用
|
|
|
-const chartsType = ref('')
|
|
|
-
|
|
|
-// 图表要填充的数据
|
|
|
-const chartData = ref({})
|
|
|
-
|
|
|
-// 图表配置选项
|
|
|
-const opts = ref({
|
|
|
- color: ["#1890FF", "#91CB74", "#FAC858", "#EE6666", "#73C0DE", "#3CA272", "#FC8452", "#9A60B4",
|
|
|
- "#ea7ccc"
|
|
|
- ], // 设定图表颜色
|
|
|
- padding: [15, 15, 0, 5],
|
|
|
- enableScroll: false, // 禁用滚动
|
|
|
- legend: {}, // 图例设置
|
|
|
- xAxis: {
|
|
|
- disableGrid: true // 禁用网格线
|
|
|
- },
|
|
|
- yAxis: {
|
|
|
- data: [{
|
|
|
- min: 0 // y轴最小值
|
|
|
- }]
|
|
|
- },
|
|
|
- extra: {
|
|
|
- column: {
|
|
|
- type: "group",
|
|
|
- width: 30,
|
|
|
- activeBgColor: "#000000",
|
|
|
- activeBgOpacity: 0.08
|
|
|
+ import {
|
|
|
+ ref,
|
|
|
+ onMounted,
|
|
|
+ reactive
|
|
|
+ } from 'vue';
|
|
|
+ import {
|
|
|
+ checkAttendance,
|
|
|
+ getMyTotalCount,
|
|
|
+ getMyQDQtAttendance
|
|
|
+ } from '@/api/mine.js'
|
|
|
+ import {
|
|
|
+ useUserStore
|
|
|
+ } from '@/store/user.js';
|
|
|
+ const userStore = useUserStore();
|
|
|
+
|
|
|
+ // 创建一个响应式对象记录今天的考勤数据
|
|
|
+ const todayData = reactive({
|
|
|
+ day: '', // 当前日期
|
|
|
+ startTime: '', // 晨签到时间
|
|
|
+ endTime: '', // 晚签到时间
|
|
|
+ })
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ // 控制今日签到信息和图表显示的状态
|
|
|
+ const shouldShow = ref(true) // 今日签到信息是否显示
|
|
|
+ const chartShow = ref(false) // 图表是否显示
|
|
|
+
|
|
|
+ // 图表类型的响应式引用
|
|
|
+ const chartsType = ref('')
|
|
|
+
|
|
|
+ // 图表要填充的数据
|
|
|
+ const chartData = ref({})
|
|
|
+
|
|
|
+ // 图表配置选项
|
|
|
+ const opts = ref({
|
|
|
+ color: ["#1890FF", "#91CB74", "#FAC858", "#EE6666", "#73C0DE", "#3CA272", "#FC8452", "#9A60B4",
|
|
|
+ "#ea7ccc"
|
|
|
+ ], // 设定图表颜色
|
|
|
+ padding: [15, 15, 0, 5],
|
|
|
+ enableScroll: false, // 禁用滚动
|
|
|
+ legend: {}, // 图例设置
|
|
|
+ xAxis: {
|
|
|
+ disableGrid: 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('');
|
|
|
+
|
|
|
+ onMounted(() => {
|
|
|
+ initAttData(); //初始化日考勤数据
|
|
|
+ });
|
|
|
+
|
|
|
+ //初始化考勤数据
|
|
|
+ function initAttData() {
|
|
|
+ const nowDate = new Date();
|
|
|
+ todayData.day = formatDate(nowDate);
|
|
|
+ getthisMondayDate(nowDate);
|
|
|
+ getDayAttData();
|
|
|
+
|
|
|
}
|
|
|
-});
|
|
|
-
|
|
|
-// 时间范围选择数组
|
|
|
-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 = ref('');
|
|
|
-//当前周的周一日期
|
|
|
-const thisMondayDate = ref('');
|
|
|
-
|
|
|
-onMounted(() => {
|
|
|
- userId.value = userStore.user.useId;//拿到用户id
|
|
|
- initAttData(); //初始化日考勤数据
|
|
|
-});
|
|
|
-
|
|
|
-//初始化考勤数据
|
|
|
-function initAttData() {
|
|
|
- const nowDate = new Date();
|
|
|
- todayData.day = formatDate(nowDate);
|
|
|
- getDayAttData();
|
|
|
- getthisMondayDate();
|
|
|
-}
|
|
|
-
|
|
|
-//格式化日期
|
|
|
-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}`;
|
|
|
-}
|
|
|
-
|
|
|
-//获取日考勤数据
|
|
|
-function getDayAttData() {
|
|
|
- const params = {
|
|
|
- universalid: userId.value,
|
|
|
- rizi: todayData.day
|
|
|
- }
|
|
|
- checkAttendance(params).then(res => {
|
|
|
- if ("success" == res.returnMsg) {
|
|
|
- const attList = res.returnParams.list;
|
|
|
- const time1 = attList.find(item => item.att_type_id === '1');
|
|
|
- const time2 = attList.filter(item => item.att_type_id === '2').pop();
|
|
|
- if (time1 !== undefined) {
|
|
|
- todayData.startTime = time1.att_time.split(' ')[1];
|
|
|
- todayData.status = '早签完成'
|
|
|
- }
|
|
|
- if (time2 !== undefined) {
|
|
|
- todayData.endTime = time2.att_time.split(' ')[1];
|
|
|
- todayData.status = '晚签完成'
|
|
|
+
|
|
|
+ //格式化日期
|
|
|
+ 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}`;
|
|
|
+ }
|
|
|
+
|
|
|
+ //获取日考勤数据
|
|
|
+ function getDayAttData() {
|
|
|
+ const params = {
|
|
|
+ universalid: userId,
|
|
|
+ rizi: todayData.day
|
|
|
+ }
|
|
|
+ checkAttendance(params).then(res => {
|
|
|
+ if ("success" == res.returnMsg) {
|
|
|
+ const attList = res.returnParams.list;
|
|
|
+ const time1 = attList.find(item => item.att_type_id === '1');
|
|
|
+ const time2 = attList.filter(item => item.att_type_id === '2').pop();
|
|
|
+ if (time1 !== undefined) {
|
|
|
+ todayData.startTime = time1.att_time.split(' ')[1];
|
|
|
+ // todayData.status = '早签完成'
|
|
|
+ }
|
|
|
+ if (time2 !== undefined) {
|
|
|
+ todayData.endTime = time2.att_time.split(' ')[1];
|
|
|
+ // todayData.status = '晚签完成'
|
|
|
+ }
|
|
|
}
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ const paging = ref(null)
|
|
|
+ const pSize = ref(5)
|
|
|
+
|
|
|
+ function complete(list, total, pageNo) {
|
|
|
+ console.log('000', pageNo);
|
|
|
+ if (pageNo == 1) {
|
|
|
+ paging.value.complete(list);
|
|
|
+ return
|
|
|
}
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
-// 时间范围切换事件
|
|
|
-function onTimeRangeChange(event) {
|
|
|
- const selectedIndex = event.detail.value;
|
|
|
- selectedTimeRange.value = timeRanges.value[selectedIndex]; // 设置选择的时间范围(日周月)
|
|
|
- // fetchAttendanceData(); // 获取考勤数据
|
|
|
- // 根据选择的时间范围更新展示内容
|
|
|
- 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().then(message => {
|
|
|
- console.log('message', message);
|
|
|
- showWeekAndMonth();
|
|
|
- updateChart(message);
|
|
|
- })
|
|
|
- .catch(error => {
|
|
|
- console.error(error); // 如果失败,打印错误消息
|
|
|
- });
|
|
|
- break;
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 显示今日考勤数据
|
|
|
-function showDay() {
|
|
|
- shouldShow.value = true; // 显示今日签到信息
|
|
|
- chartShow.value = false; // 隐藏图表
|
|
|
-}
|
|
|
-
|
|
|
-// 显示周或者月考勤
|
|
|
-function showWeekAndMonth() {
|
|
|
- shouldShow.value = false; // 隐藏今日签到信息
|
|
|
- chartShow.value = true; // 显示图表
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-//计算本周周一日期
|
|
|
-function getthisMondayDate() {
|
|
|
- const today = new Date();
|
|
|
- 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) => {
|
|
|
+ // 防止重复获取最后一次信息
|
|
|
+ if (pSize.value * pageNo < total) {
|
|
|
+ paging.value.complete(list)
|
|
|
+ } else {
|
|
|
+ console.log('complete([])');
|
|
|
+ paging.value.complete([])
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //日考勤历史记录
|
|
|
+ const clockRecords = ref([])
|
|
|
+
|
|
|
+ //获取日考勤历史
|
|
|
+ function getDayAttHistory() {
|
|
|
const params = {
|
|
|
- staffId: userId.value,
|
|
|
- start_date: thisMondayDate.value,
|
|
|
- end_date: todayData.day
|
|
|
+ type: 1, //不设时间区间
|
|
|
+ universalid: userId,
|
|
|
+ ks_att_time: '',
|
|
|
+ js_att_time: '',
|
|
|
+ pSize: pSize.value,
|
|
|
+ p: 1
|
|
|
}
|
|
|
- getMyTotalCount(params).then(res => {
|
|
|
- const myWeekAttData = res.returnParams;
|
|
|
- const mockData = {
|
|
|
- series: [{
|
|
|
- data: [{
|
|
|
- "name": "出勤",
|
|
|
- "value": myWeekAttData.type0,
|
|
|
- "labelText": "出勤:" + myWeekAttData.type0 + "次"
|
|
|
- },
|
|
|
- {
|
|
|
- "name": "外出",
|
|
|
- "value": myWeekAttData.type1
|
|
|
- },
|
|
|
- {
|
|
|
- "name": "公休",
|
|
|
- "value": myWeekAttData.type2
|
|
|
- },
|
|
|
- {
|
|
|
- "name": "未排班",
|
|
|
- "value": myWeekAttData.type3,
|
|
|
- },
|
|
|
- {
|
|
|
- "name": "迟到",
|
|
|
- "value": myWeekAttData.type4
|
|
|
- },
|
|
|
- {
|
|
|
- "name": "早退",
|
|
|
- "value": myWeekAttData.type5
|
|
|
- },
|
|
|
- {
|
|
|
- "name": "缺勤",
|
|
|
- "value": myWeekAttData.type6
|
|
|
- }
|
|
|
- ]
|
|
|
- }],
|
|
|
-
|
|
|
- };
|
|
|
- const weekData = mockData.series[0].data;
|
|
|
- attendanceCount.value = weekData[0].value;
|
|
|
- goOutCount.value = weekData[2].value;
|
|
|
- lateCount.value = weekData[4].value;
|
|
|
- leaveEarlyCount.value = weekData[5].value;
|
|
|
- absenteeismCount.value = weekData[6].value;
|
|
|
- resolve(mockData)
|
|
|
- }).catch(error => {
|
|
|
- reject(error)
|
|
|
+ getMyQDQtAttendance(params).then(({
|
|
|
+ returnParams
|
|
|
+ }) => {
|
|
|
+ const list = returnParams.list;
|
|
|
+ const records = [];
|
|
|
+ list.forEach(item => {
|
|
|
+ const record = {
|
|
|
+ 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")],
|
|
|
+ };
|
|
|
+ records.push(record);
|
|
|
+ });
|
|
|
+ clockRecords.value = records;
|
|
|
+ complete(clockRecords.value, returnParams.total, returnParams.current)
|
|
|
})
|
|
|
- })
|
|
|
+ }
|
|
|
|
|
|
-}
|
|
|
-
|
|
|
-// 获取月考勤记录
|
|
|
-function fetchMonthAttData() {
|
|
|
- return new Promise((resolve, reject) => {
|
|
|
- const weekNodeList = [];
|
|
|
- weekNodeList.unshift(thisMondayDate.value, todayData.day);
|
|
|
- while (weekNodeList.length !== 8) {
|
|
|
- const weekNode = getOneDaysAgo(weekNodeList[0]);
|
|
|
- weekNodeList.unshift(weekNode);
|
|
|
- weekNodeList.unshift(getSixDaysAgo(weekNode));
|
|
|
+ // 刷新
|
|
|
+ function queryData(pageNo, pSize, queryType) {
|
|
|
+ switch (queryType) {
|
|
|
+ case 0: // 下拉刷新
|
|
|
+ case 1: // 初始加载
|
|
|
+ getDayAttHistory()
|
|
|
+ break
|
|
|
+ case 3: // 上拉加载
|
|
|
+ scrollQuery(pageNo, pSize)
|
|
|
+ break
|
|
|
+ default: // 默认刷新
|
|
|
+ getDayAttHistory()
|
|
|
+ break
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- const data1 = [];
|
|
|
- const data2 = [];
|
|
|
- const data3 = [];
|
|
|
- const dataFetchPromises = [];// 存储所有数据请求的promise
|
|
|
-
|
|
|
- for (let i = 0; i < weekNodeList.length - 1; i += 2) {
|
|
|
- const params = {
|
|
|
- staffId: userId.value,
|
|
|
- start_date: weekNodeList[i],
|
|
|
- end_date: weekNodeList[i + 1]
|
|
|
- };
|
|
|
- const fetchPromise = getMyTotalCount(params).then(res => {
|
|
|
- // for (const type in res.returnParams) {
|
|
|
- // console.log('type', type);
|
|
|
- // }
|
|
|
- console.log('res.returnParams', res.returnParams);
|
|
|
-
|
|
|
- data1.push(res.returnParams.type0);
|
|
|
- data2.push(res.returnParams.type1);
|
|
|
- data3.push(res.returnParams.type4);
|
|
|
+ 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")],
|
|
|
+ }
|
|
|
});
|
|
|
- dataFetchPromises.push(fetchPromise);
|
|
|
+ console.log('list', list);
|
|
|
+
|
|
|
+ // clockRecords.value.push(...list);
|
|
|
+ // complete(list,returnParams.total,pageNo)
|
|
|
+
|
|
|
+ // 去重逻辑
|
|
|
+ const existingDates = new Set(clockRecords.value.map(record => record.date));
|
|
|
+ const newRecords = list.filter(item => !existingDates.has(item.date));
|
|
|
+
|
|
|
+ // 更新 clockRecords
|
|
|
+ clockRecords.value.push(...newRecords);
|
|
|
+
|
|
|
+ // 调用 complete 函数,传入新记录和总数
|
|
|
+ complete(newRecords, returnParams.total, pageNo);
|
|
|
+
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 时间范围切换事件
|
|
|
+ function onTimeRangeChange(event) {
|
|
|
+ const selectedIndex = event.detail.value;
|
|
|
+ selectedTimeRange.value = timeRanges.value[selectedIndex]; // 设置选择的时间范围(日周月)
|
|
|
+ // fetchAttendanceData(); // 获取考勤数据
|
|
|
+ // 根据选择的时间范围更新展示内容
|
|
|
+ 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().then(message => {
|
|
|
+ console.log('message', message);
|
|
|
+ showWeekAndMonth();
|
|
|
+ updateChart(message);
|
|
|
+ })
|
|
|
+ .catch(error => {
|
|
|
+ console.error(error); // 如果失败,打印错误消息
|
|
|
+ });
|
|
|
+ break;
|
|
|
}
|
|
|
+ };
|
|
|
|
|
|
- // 等待所有数据请求完成
|
|
|
- Promise.all(dataFetchPromises).then(() => {
|
|
|
+ // 显示今日考勤数据
|
|
|
+ function showDay() {
|
|
|
+ shouldShow.value = true; // 显示今日签到信息
|
|
|
+ chartShow.value = false; // 隐藏图表
|
|
|
+ }
|
|
|
+
|
|
|
+ // 显示周或者月考勤
|
|
|
+ function showWeekAndMonth() {
|
|
|
+ shouldShow.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.value,
|
|
|
- start_date: weekNodeList[0],
|
|
|
- end_date: weekNodeList[weekNodeList.length - 1]
|
|
|
- };
|
|
|
- return getMyTotalCount(params);
|
|
|
- }).then(res => {
|
|
|
- const myMonthAttData = res.returnParams;
|
|
|
- attendanceCount.value = myMonthAttData.type0;
|
|
|
- goOutCount.value = myMonthAttData.type2;
|
|
|
- lateCount.value = myMonthAttData.type4;
|
|
|
- leaveEarlyCount.value = myMonthAttData.type5;
|
|
|
- absenteeismCount.value = myMonthAttData.type6;
|
|
|
-
|
|
|
- const mockData = {
|
|
|
- categories: ["第1周", "第2周", "第3周", "第4周"],
|
|
|
- series: [{
|
|
|
- name: "出勤",
|
|
|
- data: data1
|
|
|
- }, {
|
|
|
- name: "出差",
|
|
|
- data: data2
|
|
|
- }, {
|
|
|
- name: "迟到",
|
|
|
- data: data3
|
|
|
- }]
|
|
|
- };
|
|
|
- // console.log(data1); // 打印data1检查内容
|
|
|
- resolve(mockData);
|
|
|
- }).catch(error => {
|
|
|
- reject(error);
|
|
|
- });
|
|
|
- });
|
|
|
-}
|
|
|
+ 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.type0,
|
|
|
+ "labelText": "出勤:" + myWeekAttData.type0 + "次"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "name": "外出",
|
|
|
+ "value": myWeekAttData.type1
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "name": "公休",
|
|
|
+ "value": myWeekAttData.type2
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "name": "未排班",
|
|
|
+ "value": myWeekAttData.type3,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "name": "迟到",
|
|
|
+ "value": myWeekAttData.type4
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "name": "早退",
|
|
|
+ "value": myWeekAttData.type5
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "name": "缺勤",
|
|
|
+ "value": myWeekAttData.type6
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }],
|
|
|
+
|
|
|
+ };
|
|
|
+ const weekData = mockData.series[0].data;
|
|
|
+ attendanceCount.value = weekData[0].value;
|
|
|
+ goOutCount.value = weekData[2].value;
|
|
|
+ lateCount.value = weekData[4].value;
|
|
|
+ leaveEarlyCount.value = weekData[5].value;
|
|
|
+ absenteeismCount.value = weekData[6].value;
|
|
|
+ resolve(mockData)
|
|
|
+ }).catch(error => {
|
|
|
+ reject(error)
|
|
|
+ })
|
|
|
+ })
|
|
|
|
|
|
+ }
|
|
|
|
|
|
-//获取六天前的日期
|
|
|
-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 fetchMonthAttData() {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ const weekNodeList = [];
|
|
|
+ weekNodeList.unshift(thisMondayDate.value, todayData.day);
|
|
|
+ while (weekNodeList.length !== 8) {
|
|
|
+ const weekNode = getOneDaysAgo(weekNodeList[0]);
|
|
|
+ weekNodeList.unshift(weekNode);
|
|
|
+ weekNodeList.unshift(getSixDaysAgo(weekNode));
|
|
|
+ }
|
|
|
|
|
|
+ const data1 = [];
|
|
|
+ const data2 = [];
|
|
|
+ const data3 = [];
|
|
|
+ const dataFetchPromises = []; // 存储所有数据请求的promise
|
|
|
+
|
|
|
+ for (let i = 0; i < weekNodeList.length - 1; i += 2) {
|
|
|
+ const params = {
|
|
|
+ staffId: userId,
|
|
|
+ start_date: weekNodeList[i],
|
|
|
+ end_date: weekNodeList[i + 1]
|
|
|
+ };
|
|
|
+ const fetchPromise = getMyTotalCount(params).then(res => {
|
|
|
+ // for (const type in res.returnParams) {
|
|
|
+ // console.log('type', type);
|
|
|
+ // }
|
|
|
+ console.log('res.returnParams', res.returnParams);
|
|
|
+
|
|
|
+ data1.push(res.returnParams.type0);
|
|
|
+ data2.push(res.returnParams.type1);
|
|
|
+ data3.push(res.returnParams.type4);
|
|
|
+ });
|
|
|
+ dataFetchPromises.push(fetchPromise);
|
|
|
+ }
|
|
|
|
|
|
-// 更新图表数据
|
|
|
-function updateChart(res) {
|
|
|
- chartData.value = JSON.parse(JSON.stringify(res)); // 更新图表数据
|
|
|
-}
|
|
|
+ // 等待所有数据请求完成
|
|
|
+ Promise.all(dataFetchPromises).then(() => {
|
|
|
+ const params = {
|
|
|
+ staffId: userId,
|
|
|
+ start_date: weekNodeList[0],
|
|
|
+ end_date: weekNodeList[weekNodeList.length - 1]
|
|
|
+ };
|
|
|
+ return getMyTotalCount(params);
|
|
|
+ }).then(res => {
|
|
|
+ const myMonthAttData = res.returnParams;
|
|
|
+ attendanceCount.value = myMonthAttData.type0;
|
|
|
+ goOutCount.value = myMonthAttData.type2;
|
|
|
+ lateCount.value = myMonthAttData.type4;
|
|
|
+ leaveEarlyCount.value = myMonthAttData.type5;
|
|
|
+ absenteeismCount.value = myMonthAttData.type6;
|
|
|
+
|
|
|
+ const mockData = {
|
|
|
+ categories: ["第1周", "第2周", "第3周", "第4周"],
|
|
|
+ series: [{
|
|
|
+ name: "出勤",
|
|
|
+ data: data1
|
|
|
+ }, {
|
|
|
+ name: "出差",
|
|
|
+ data: data2
|
|
|
+ }, {
|
|
|
+ name: "迟到",
|
|
|
+ data: data3
|
|
|
+ }]
|
|
|
+ };
|
|
|
+ // console.log(data1); // 打印data1检查内容
|
|
|
+ resolve(mockData);
|
|
|
+ }).catch(error => {
|
|
|
+ reject(error);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ //获取六天前的日期
|
|
|
+ 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 scoped>
|
|
|
-@import "@/static/font/ygoa/iconfont.css";
|
|
|
-
|
|
|
-.ygoa-icon {
|
|
|
- margin-right: 0.5rem;
|
|
|
- font-size: 2.1rem;
|
|
|
- vertical-align: middle;
|
|
|
- /* 确保图标与文本竖直居中 */
|
|
|
-}
|
|
|
-
|
|
|
-.attendance-page {
|
|
|
- padding: 20px;
|
|
|
- background-color: #f9f9f9;
|
|
|
-}
|
|
|
-
|
|
|
-.header {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- margin-bottom: 20px;
|
|
|
-}
|
|
|
-
|
|
|
-.title {
|
|
|
- font-size: 24px;
|
|
|
- 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: 20px;
|
|
|
- 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: 18px;
|
|
|
- font-weight: bold;
|
|
|
- color: #333;
|
|
|
-}
|
|
|
-
|
|
|
-.value,
|
|
|
-.label {
|
|
|
- line-height: 50rpx;
|
|
|
- /* 与图标高度一致,确保垂直对齐 */
|
|
|
-}
|
|
|
-
|
|
|
-.chart-container {
|
|
|
- margin-top: 20px;
|
|
|
-}
|
|
|
-
|
|
|
-.chart-title {
|
|
|
- font-size: 20px;
|
|
|
- font-weight: bold;
|
|
|
- text-align: center;
|
|
|
- margin-bottom: 10px;
|
|
|
- color: #333;
|
|
|
-}
|
|
|
-
|
|
|
-.charts-box {
|
|
|
- width: 100%;
|
|
|
- height: 300px;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-.todayCheckIn {
|
|
|
-
|
|
|
- background-color: #ffffff;
|
|
|
- padding: 20px;
|
|
|
- box-sizing: border-box;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-.check-in-container {
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
-}
|
|
|
-
|
|
|
-.title2 {
|
|
|
- font-size: 22px;
|
|
|
- font-weight: bold;
|
|
|
- margin-bottom: 20px;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-.info-row {
|
|
|
- width: 100%;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: space-between;
|
|
|
- margin-bottom: 10px;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-.todayCheckIn,
|
|
|
-.chart-container,
|
|
|
-.statistics {
|
|
|
- /* 默认隐藏 */
|
|
|
- display: none;
|
|
|
-}
|
|
|
-
|
|
|
-/* 当需要显示时,可以添加一个额外的类 */
|
|
|
-.todayCheckIn.show,
|
|
|
-.chart-container.show,
|
|
|
-.statistics.show {
|
|
|
- display: block;
|
|
|
-}
|
|
|
-
|
|
|
-.icon {
|
|
|
- width: 50rpx;
|
|
|
- height: 50rpx;
|
|
|
- margin-right: 20rpx;
|
|
|
- vertical-align: middle;
|
|
|
- /* 确保图标与文本竖直居中 */
|
|
|
-}
|
|
|
+<style lang="scss" scoped>
|
|
|
+ @import "@/static/font/ygoa/iconfont.css";
|
|
|
+
|
|
|
+ .ygoa-icon {
|
|
|
+ margin-right: 0.5rem;
|
|
|
+ font-size: 2.1rem;
|
|
|
+ vertical-align: middle;
|
|
|
+ /* 确保图标与文本竖直居中 */
|
|
|
+ }
|
|
|
+
|
|
|
+ .attendance-page {
|
|
|
+ padding: 20px;
|
|
|
+ background-color: #f9f9f9;
|
|
|
+ }
|
|
|
+
|
|
|
+ .header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 20px;
|
|
|
+
|
|
|
+ .clockRecordTitle {
|
|
|
+ font-size: 1.25rem;
|
|
|
+ margin: auto;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .title {
|
|
|
+ font-size: 24px;
|
|
|
+ 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: 20px;
|
|
|
+ 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: 18px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #333;
|
|
|
+ }
|
|
|
+
|
|
|
+ .value,
|
|
|
+ .label {
|
|
|
+ line-height: 50rpx;
|
|
|
+ /* 与图标高度一致,确保垂直对齐 */
|
|
|
+ }
|
|
|
+
|
|
|
+ .chart-container {
|
|
|
+ margin-top: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .chart-title {
|
|
|
+ font-size: 20px;
|
|
|
+ font-weight: bold;
|
|
|
+ text-align: center;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ color: #333;
|
|
|
+ }
|
|
|
+
|
|
|
+ .charts-box {
|
|
|
+ width: 100%;
|
|
|
+ height: 300px;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ .todayCheckIn {
|
|
|
+ background-color: #ffffff;
|
|
|
+ padding: 20px;
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ .todayAttTitle {
|
|
|
+ font-size: 22px;
|
|
|
+ font-weight: bold;
|
|
|
+ margin-bottom: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ .info-row {
|
|
|
+ width: 100%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ .todayCheckIn,
|
|
|
+ .chart-container,
|
|
|
+ .statistics {
|
|
|
+ /* 默认隐藏 */
|
|
|
+ display: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 当需要显示时,可以添加一个额外的类 */
|
|
|
+ .todayCheckIn.show,
|
|
|
+ .chart-container.show,
|
|
|
+ .statistics.show {
|
|
|
+ display: block;
|
|
|
+ }
|
|
|
+
|
|
|
+ .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;
|
|
|
+ }
|
|
|
</style>
|