@@ -0,0 +1,260 @@ | |||
/** | |||
* 唯一的随机字符串,用来区分每条数据 | |||
* @returns {string} | |||
*/ | |||
export function getUid() { | |||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { | |||
const r = (Math.random() * 16) | 0; | |||
const v = c === 'x' ? r : (r & 0x3) | 0x8; | |||
return v.toString(16); | |||
}); | |||
} | |||
/** | |||
* 计算时间差 | |||
* @param beginTime:2022-01-13 | |||
* @param endTime:2022-01-13 | |||
* @returns {{hours: number, seconds: number, minutes: number, day: number}} | |||
*/ | |||
export function dealTime(beginTime, endTime) { | |||
var dateBegin = new Date(beginTime); | |||
var dateEnd = new Date(endTime); | |||
var dateDiff = dateEnd.getTime() - dateBegin.getTime(); //时间差的毫秒数 | |||
var day = Math.floor(dateDiff / (24 * 3600 * 1000)); //计算出相差天数 | |||
var leave1 = dateDiff % (24 * 3600 * 1000); //计算天数后剩余的毫秒数 | |||
var hours = Math.floor(leave1 / (3600 * 1000)); //计算出小时数 | |||
//计算相差分钟数 | |||
var leave2 = leave1 % (3600 * 1000); //计算小时数后剩余的毫秒数 | |||
var minutes = Math.floor(leave2 / (60 * 1000)); //计算相差分钟数 | |||
//计算相差秒数 | |||
var leave3 = leave2 % (60 * 1000); //计算分钟数后剩余的毫秒数 | |||
var seconds = Math.round(leave3 / 1000); | |||
return { | |||
day, | |||
hours, | |||
minutes, | |||
seconds | |||
} | |||
} | |||
/** | |||
* 获取当天时间 | |||
* @returns {string} | |||
*/ | |||
export function getCurDay() { | |||
var datetime = new Date(); | |||
var year = datetime.getFullYear(); | |||
var month = datetime.getMonth() + 1 < 10 ? "0" + (datetime.getMonth() + 1) : datetime.getMonth() + 1; | |||
var date = datetime.getDate() < 10 ? "0" + datetime.getDate() : datetime.getDate(); | |||
return `${year}-${month}-${date}` | |||
} | |||
// 日期格式处理 | |||
export function formatDate(date) { | |||
var year = date.getFullYear(); | |||
var months = date.getMonth() + 1; | |||
var month = (months < 10 ? '0' + months : months).toString(); | |||
var day = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()).toString(); | |||
return { | |||
year: year.toString(), | |||
month, | |||
day | |||
} | |||
} | |||
/** | |||
* 数组中,某个属性相同的数据放在一块,如把某个日期相同的相连一起 | |||
* @param list 传入的数组 | |||
* @param prop 那个属性相同的数据 | |||
* @returns {*[]} | |||
*/ | |||
export function margePropData(list = [], prop) { | |||
let arr = [], tempArr = {}; | |||
list.forEach(item => { | |||
if (!tempArr[item[prop]]) { | |||
tempArr[item[prop]] = [item] | |||
} else { | |||
tempArr[item[prop]].push(item) | |||
} | |||
}) | |||
for (const tempArrKey in tempArr) { | |||
arr = [...arr, ...tempArr[tempArrKey]] | |||
} | |||
return arr | |||
} | |||
/** | |||
* 合并行 | |||
* @param list | |||
* @param prop | |||
*/ | |||
export function mergeRows(list = [], prop) { | |||
list.forEach(ele => { | |||
ele.rowspan = 1 | |||
}) | |||
const len = list.length | |||
for (let i = 0; i < len; i++) { | |||
for (let j = i + 1; j < len; j++) { | |||
if (list[i][prop] === list[j][prop]) { | |||
list[i].rowspan++ | |||
list[j].rowspan-- | |||
} | |||
} | |||
// 这里跳过已经重复的数据 | |||
i = i + list[i].rowspan - 1 | |||
} | |||
return list | |||
} | |||
/** | |||
* 根据当前数据的位置,在数组中插入数据 | |||
* 如数组【1,2,4,5】想要在2后面插入3, | |||
*1:首先获取到2的下标, | |||
*2:然后获取要插入之前的数据,获取要插入之后的数据,中间就是插入的位置 | |||
*3:最后把这三个按顺序合并就得到在想要的位置插入数据 | |||
* @param list | |||
* @param index | |||
* @param target | |||
*/ | |||
export function insertArrPositionOfIndex(list = [], index = 0, target = {}) { | |||
//根据index 找出小于index的数据放在左边 | |||
const leftList = list.filter((t, i) => i < index); | |||
//根据index 找出大于index的数据放在右边 | |||
const rightList = list.filter((t, i) => i >= index); | |||
// 最终合并数据 | |||
return [...leftList, target, ...rightList] | |||
} | |||
/** | |||
* 校验规则 | |||
*/ | |||
export function verifyRules(list = [], require = []) { | |||
let message = null | |||
for (const key of require) { | |||
const isEmpty = list.every(it => !it[key.prop]) | |||
if (isEmpty) { | |||
message = key.message | |||
break; | |||
} | |||
} | |||
return message | |||
} | |||
/** | |||
* 获取元素下标 | |||
* @param dir 为 1:得到正序遍历方法;为 -1: 得到逆序遍历方法。 | |||
* @returns {(function(*, *, *=): (number|number|number))|*} | |||
*/ | |||
export function findArrIndex(dir = 1) { | |||
return function (array, cb, context) { | |||
let length = array.length; | |||
// 控制初始 index,0 或者 length-1 | |||
let index = dir >= 0 ? 0 : length - 1; | |||
// 条件: 在数组范围内; | |||
// 递增或递减:递加 1 或者 -1; 妙啊~ | |||
for (; index >= 0 && index <= length - 1; index += dir) { | |||
if (cb.call(context, array[index], index)) return index | |||
} | |||
return -1 | |||
} | |||
} | |||
/** | |||
* map转换成数组 | |||
* @param target | |||
* @returns {*[]} | |||
* @constructor | |||
*/ | |||
export function MapConvertArr(target = {}) { | |||
let list = []; | |||
for (let key in target) { | |||
list.push(target[key]); | |||
} | |||
return list; | |||
} | |||
/** | |||
* 对象数组去重 | |||
* @param arr 数组 | |||
* @param prop 根据什么字段去重 | |||
* @returns {any[]} | |||
*/ | |||
export function arrayDeduplication(arr, prop) { | |||
let map = new Map(); | |||
return arr.filter(item => !map.has(item[prop]) && map.set(item[prop], 1)); | |||
} | |||
/** | |||
* 获取当前天时间 | |||
* @param param 【Y:年;M:月;D:日;h:小时;m:分钟;s:秒;】 默认精确到秒 | |||
* @returns {*} | |||
*/ | |||
export function getCurrentDate(param = 's') { | |||
var now = new Date(); | |||
var year = now.getFullYear(); //得到年份 | |||
var month = now.getMonth();//得到月份 | |||
var date = now.getDate();//得到日期 | |||
var day = now.getDay();//得到周几 | |||
var hour = now.getHours();//得到小时 | |||
var minu = now.getMinutes();//得到分钟 | |||
var sec = now.getSeconds();//得到秒 | |||
month = month + 1; | |||
if (month < 10) month = "0" + month; | |||
if (date < 10) date = "0" + date; | |||
if (hour < 10) hour = "0" + hour; | |||
if (minu < 10) minu = "0" + minu; | |||
if (sec < 10) sec = "0" + sec; | |||
const arr = { | |||
'Y': year, | |||
'M': year + "-" + month, | |||
'D': year + "-" + month + "-" + date, | |||
'h': year + "-" + month + "-" + date + " " + hour, | |||
'm': year + "-" + month + "-" + date + " " + hour + ":" + minu, | |||
's': year + "-" + month + "-" + date + " " + hour + ":" + minu + ":" + sec | |||
} | |||
return arr[param]; | |||
} | |||
/** | |||
* 获取当天时间前后七天时间 | |||
* @param day day>0 当天时间的后几天 day<0 当天时间前几天 | |||
* @returns {string} | |||
*/ | |||
export function getRecentDate(day) { | |||
var date1 = new Date(), | |||
time1 = date1.getFullYear() + "-" + (date1.getMonth() + 1) + "-" + date1.getDate();//time1表示当前时间 | |||
var date2 = new Date(date1); | |||
date2.setDate(date1.getDate() + day); | |||
const y = date2.getFullYear(); | |||
const m = (date2.getMonth() + 1) > 9 ? (date2.getMonth() + 1) : '0' + (date2.getMonth() + 1) | |||
const d = date2.getDate() > 9 ? date2.getDate() : '0' + date2.getDate() | |||
return y + "-" + m + "-" + d; | |||
} | |||
export function MyDebounce(fn, duration = 100) { | |||
let timer = null | |||
return (...args) => { | |||
clearTimeout(timer) | |||
timer = setTimeout(() => { | |||
fn(...args); | |||
}, duration) | |||
} | |||
} | |||
export function MyThrottle(fn, duration = 100) { | |||
let target = true; | |||
return (...arg) => { | |||
if (!target) { | |||
return false; | |||
} | |||
target = false; | |||
setTimeout(() => { | |||
fn(...arg); | |||
target = true | |||
}, duration) | |||
} | |||
} |
@@ -0,0 +1,502 @@ | |||
<template> | |||
<div class="month-container"> | |||
<div class="month-top"> | |||
<div class="m-btn-wrap"> | |||
<span @click="handleShowLastMonth">上一月</span> | |||
<span @click="handleShowToday"> 当月 </span> | |||
<span @click="handleShowNextMonth">下一月</span> | |||
</div> | |||
<span class="m-today-date"> {{ year }}年{{ month > 9 ? month : `0${month}` }}月</span> | |||
<!-- <div class="m-card-status"> | |||
<div v-for="sta in cardStatus"> | |||
<span class="square" :style="{background:sta.color}"></span> | |||
<span class="title">{{ sta.title }}</span> | |||
</div> | |||
</div> --> | |||
</div> | |||
<div class="m-date-wrap"> | |||
<ul class="m-week"> | |||
<li>日</li> | |||
<li>一</li> | |||
<li>二</li> | |||
<li>三</li> | |||
<li>四</li> | |||
<li>五</li> | |||
<li>六</li> | |||
</ul> | |||
<ul class="m-day"> | |||
<li v-for="(myDay,index) in days" | |||
:class="{'m-isActive':myDay.isActive,'m-isCurToday':myDay.isCurToday}" | |||
:key="index" @click="handleChooseCard(myDay)"> | |||
<span class="m-date" :class="{'m-isCurMonth':myDay.isNextMonth||myDay.isLastMonth}"> | |||
{{ myDay.day }} | |||
</span> | |||
<slot :row="myDay"></slot> | |||
<!-- <template v-for="(plan,i) in myDay.planList"> | |||
<div v-if="i<hasNumExpend&&!myDay.isExpend" :key="`plan${i}`" @click="handleDetail(plan)" | |||
class="m-card-default" | |||
:style="{background: cardStatus[plan.status].color}"> | |||
<slot name="card" :row="plan"></slot> | |||
</div> | |||
<div v-if="myDay.isExpend" :key="`plan${i}`" @click="handleDetail(plan)" | |||
class="m-card-default" | |||
:style="{background: cardStatus[plan.status].color}"> | |||
<slot name="card" :row="plan"></slot> | |||
</div> | |||
</template> --> | |||
<div class="w_expand" v-if="myDay.planList.length>hasNumExpend&&!myDay.isExpend" @click="handleExpand(myDay)">展开 | |||
</div> | |||
<div class="w_shrink" v-if="myDay.planList.length>hasNumExpend&&myDay.isExpend" | |||
@click="handleExpand(myDay)">收缩 | |||
</div> | |||
</li> | |||
</ul> | |||
</div> | |||
<div class="m-card-status1"> | |||
<div v-for="sta in cardStatus"> | |||
<span class="square" :style="{background:sta.color}"></span> | |||
<span class="title">{{ sta.title }}</span> | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import {getCurDay} from "./MyTools"; | |||
export default { | |||
name: 'monthSchedule', | |||
props: { | |||
//日程数据 | |||
scheduleList: { | |||
type: Array, | |||
default:()=>[] | |||
}, | |||
//是否展开,默认不展开 | |||
isExpend:{ | |||
type: Boolean, | |||
default:false | |||
}, | |||
//多少进行展开 | |||
hasNumExpend:{ | |||
type: Number, | |||
default:2 | |||
}, | |||
//卡片状态 | |||
cardStatus: { | |||
type: Object, | |||
default: () => { | |||
return { | |||
1: { | |||
title: '已过期', | |||
color: '#9CADADB7' | |||
}, | |||
2: { | |||
title: '进行中', | |||
color: '#FF6200' | |||
}, | |||
3: { | |||
title: '未开始', | |||
color: '#3291F8' | |||
}, | |||
} | |||
} | |||
} | |||
}, | |||
data() { | |||
return { | |||
year: '',//年 | |||
month: '',//月 | |||
days: [],//日期 | |||
endTime: null, | |||
startTime: null, | |||
monthValue: '', | |||
} | |||
}, | |||
methods: { | |||
//展开与缩放操作 | |||
handleExpand (row) { | |||
row.isExpend = !row.isExpend | |||
}, | |||
changeMonth() { | |||
const date = this.monthValue && this.monthValue.split('-').map(Number) || [] | |||
if (date.length === 0) { | |||
return | |||
} | |||
this.year = date[0]; | |||
this.month = date[1] | |||
this.days = []; | |||
this.pushDays(); | |||
}, | |||
//得到当前年这个月分有多少天 | |||
getDays(Y, M) { | |||
return new Date(Y, M, 0).getDate(); | |||
}, | |||
//得到当前年,这个月的一号是周几 | |||
getWeek(Y, M) { | |||
let now = new Date() | |||
now.setFullYear(this.year) | |||
now.setMonth(this.month - 1) | |||
now.setDate(1); | |||
return now.getDay(); | |||
}, | |||
/** | |||
* 获取本月日期 | |||
*/ | |||
pushDays() { | |||
console.log(this.getDays(this.year, this.month)) | |||
//将这个月多少天加入数组days | |||
for (let i = 1; i <= this.getDays(this.year, this.month); i++) { | |||
const _day = `${i > 9 ? i : '0' + i}`, _month = `${this.month > 9 ? this.month : '0' + this.month}`, | |||
date = `${this.year}-${_month}-${_day}`; | |||
this.days.push({ | |||
day: _day,// | |||
date, | |||
isExpend:this.isExpend, | |||
planList:this.scheduleList.filter(item => item.date === date), | |||
isCurMonth: true, | |||
month: _month, | |||
year: `${this.year}`, | |||
timestamp: new Date(date).getTime(),//转换时间戳 | |||
}) | |||
} | |||
this.getLastMonthDays() | |||
this.getNextMonthDays() | |||
}, | |||
/** | |||
* 获取下个月的日期 | |||
*/ | |||
getNextMonthDays() { | |||
const month = this.month < 12 ? this.month + 1 : 1, | |||
year = this.month < 12 ? this.year : this.year + 1, | |||
len = 42 - this.getDays(this.year, this.month) - this.getWeek(this.year, this.month) | |||
//将下个月要显示的天数加入days | |||
for (let i = 1; i <= len; i++) { | |||
const _day = `${i > 9 ? i : '0' + i}`, _month = `${month > 9 ? month : '0' + month}`, | |||
date = `${year}-${_month}-${_day}`; | |||
this.days.push({ | |||
day: _day, | |||
date, | |||
isExpend:this.isExpend, | |||
month: _month, | |||
year: `${year}`, | |||
planList: this.scheduleList.filter(item => item.date === date), | |||
isNextMonth: true, | |||
timestamp: new Date(date).getTime() | |||
}) | |||
} | |||
}, | |||
/** | |||
* 获取上个月的日期 | |||
*/ | |||
getLastMonthDays() { | |||
const month = this.month > 1 ? this.month - 1 : this.year > 1970 ? 12 : 1, | |||
year = this.month > 1 ? this.year : this.year > 1970 ? this.year - 1 : 1970, | |||
len = this.getWeek(this.year, this.month), | |||
lastMonthDays = this.getDays(this.year, this.month - 1) | |||
//将上个月要显示的天数加入days | |||
for (let i = 0; i < len; i++) { | |||
const _month = month > 9 ? `${month}` : `0${month}`, | |||
date = `${year}-${_month}-${lastMonthDays - i}`; | |||
this.days.unshift({ | |||
day: `${lastMonthDays - i}`, | |||
date, | |||
month: _month, | |||
year: `${year}`, | |||
isExpend:this.isExpend, | |||
planList: this.scheduleList.filter(item => item.date === date), | |||
isLastMonth: true, | |||
timestamp: new Date(date).getTime(), | |||
}) | |||
} | |||
}, | |||
/** | |||
* 获取日期数据 | |||
*/ | |||
getDate() { | |||
let now = new Date(); | |||
this.year = now.getFullYear(); | |||
this.month = now.getMonth() + 1; | |||
this.pushDays(); | |||
}, | |||
/** | |||
* 下个月 | |||
*/ | |||
handleShowNextMonth() { | |||
if (this.month < 12) { | |||
this.month = this.month + 1; | |||
} else { | |||
this.month = this.month = 1; | |||
this.year = this.year + 1; | |||
} | |||
this.dealCurDay(); | |||
const dateObj = { | |||
date: `${this.year}-${this.month}`, | |||
timestamp: new Date(`${this.year}-${this.month}`).getTime() | |||
} | |||
this.$emit('changeMonth', dateObj) | |||
}, | |||
/** | |||
* 当天 | |||
*/ | |||
handleShowToday() { | |||
let now = new Date(); | |||
this.year = now.getFullYear(); | |||
this.month = now.getMonth() + 1; | |||
this.dealCurDay(); | |||
const dateObj = { | |||
date: `${this.year}-${this.month}`, | |||
timestamp: new Date(`${this.year}-${this.month}`).getTime() | |||
} | |||
this.$emit('changeMonth', dateObj) | |||
}, | |||
/** | |||
* 处理当天数据 | |||
*/ | |||
dealCurDay() { | |||
this.days = []; | |||
const curDate = getCurDay() | |||
this.pushDays(); | |||
this.days.forEach(item => { | |||
item.isCurToday = item.date === curDate | |||
}) | |||
}, | |||
/** | |||
* 上个月 | |||
*/ | |||
handleShowLastMonth() { | |||
this.days = []; | |||
if (this.month > 1) { | |||
this.month = this.month - 1; | |||
this.dealCurDay(); | |||
} else if (this.year > 1970) { | |||
this.month = 12; | |||
this.year = this.year - 1; | |||
this.dealCurDay(); | |||
} else { | |||
this.dealCurDay(); | |||
return new Error('只能查1970以后的月份') | |||
} | |||
const dateObj = { | |||
date: `${this.year}-${this.month}`, | |||
timestamp: new Date(`${this.year}-${this.month}`).getTime() | |||
} | |||
this.$emit('changeMonth', dateObj) | |||
}, | |||
/** | |||
* 选择日期卡片详情 | |||
* @param row | |||
*/ | |||
handleChooseCard(row = {}) { | |||
this.$emit('chooseEntireCard', row) | |||
}, | |||
/** | |||
* 查看单个日程详情 | |||
*/ | |||
handleDetail(row) { | |||
this.$emit('handleDetail', row) | |||
}, | |||
}, | |||
mounted() { | |||
this.getDate(); | |||
this.handleShowToday() | |||
}, | |||
} | |||
</script> | |||
<style> | |||
ul { | |||
list-style: none; | |||
} | |||
.month-container { | |||
width: 100%; | |||
border: 1px solid #ddd; | |||
padding: 20px; | |||
box-sizing: border-box; | |||
} | |||
.month-top { | |||
width: 100%; | |||
display: flex; | |||
justify-content: space-between; | |||
align-items: center; | |||
padding: 1% 0; | |||
box-sizing: border-box; | |||
} | |||
.month-top .m-btn-wrap { | |||
width: 200px; | |||
display: flex; | |||
justify-content: space-around; | |||
color: #409EFF; | |||
} | |||
.month-top .m-btn-wrap > span { | |||
cursor: pointer; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
font-size: 15px; | |||
} | |||
.month-top .m-card-status { | |||
display: flex; | |||
width: 20%; | |||
justify-content: flex-end; | |||
} | |||
.month-top .m-card-status > div { | |||
flex: 1; | |||
display: flex; | |||
padding: 0 2%; | |||
white-space: nowrap; | |||
line-height: 20px; | |||
box-sizing: border-box; | |||
} | |||
.month-top .m-card-status > div .square { | |||
display: flex; | |||
width: 16px; | |||
height: 16px; | |||
border-radius: 4px; | |||
box-sizing: border-box; | |||
} | |||
.month-top .m-card-status > div .title { | |||
display: flex; | |||
align-items: center; | |||
line-height: 16px; | |||
margin-left: 4px; | |||
font-size: 14px; | |||
} | |||
.m-date-wrap { | |||
width: 100%; | |||
height: auto; | |||
} | |||
.m-date-wrap .m-week { | |||
width: 100%; | |||
height: 40px; | |||
margin: 0; | |||
line-height: 40px; | |||
display: flex; | |||
flex-direction: row; | |||
font-size: 16px; | |||
background: #EAEDF2; | |||
box-sizing: border-box; | |||
padding-left: 0%; | |||
} | |||
.m-date-wrap .m-week > li { | |||
width: 14.28%; | |||
padding-left: 1%; | |||
box-sizing: border-box; | |||
text-align: center; | |||
} | |||
.m-date-wrap .m-day { | |||
width: 100%; | |||
display: flex; | |||
flex-direction: row; | |||
padding: 0; | |||
margin: 0; | |||
font-size: 14px; | |||
flex-wrap: wrap; | |||
box-sizing: border-box; | |||
} | |||
.m-day .m-date{ | |||
cursor: pointer; | |||
} | |||
.m-date-wrap .m-day > li { | |||
width: 14.28%; | |||
padding: 1%; | |||
min-height: 40px; | |||
box-sizing: border-box; | |||
border: 1px solid #ddd; | |||
} | |||
.m-date-wrap .m-day > li .m-card-default { | |||
cursor: pointer; | |||
width: 100%; | |||
min-height: 60px; | |||
border-radius: 8px; | |||
display: flex; | |||
margin: 6% 0; | |||
flex-direction: column; | |||
justify-content: space-around; | |||
white-space: nowrap; | |||
color: #fff; | |||
background: #FF6200; | |||
padding: 2% 4%; | |||
box-sizing: border-box; | |||
} | |||
.m-card-default span{ | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
} | |||
.m-date-wrap .m-day > li:nth-child(n+8) { | |||
border-top: none; | |||
} | |||
.m-date-wrap .m-day > li:nth-child(n+1) { | |||
border-right: none; | |||
} | |||
.m-date-wrap .m-day > li:nth-child(7n) { | |||
border-right: 1px solid #ddd | |||
} | |||
.m-isCurMonth { | |||
background: #fff; | |||
color: #c0c4cc; | |||
} | |||
/* .m-isCurToday { | |||
background: #ECF5FF; | |||
color: #FF2525; | |||
} */ | |||
.m-isActive { | |||
background: #ECF5FF; | |||
color: #409EFF; | |||
} | |||
.w_expand, .w_shrink { | |||
color: #0A98D5; | |||
cursor: pointer; | |||
width: 100%; | |||
padding: 2% 0; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
box-sizing: border-box; | |||
} | |||
.m-card-status1{ | |||
display: flex; | |||
} | |||
.m-card-status1 > div{ | |||
padding: 4px; | |||
} | |||
.m-card-status1 .square{ | |||
display: inline-block; | |||
margin-right: 4px; | |||
border-radius: 50%; | |||
width: 10px; | |||
height: 10px; | |||
} | |||
</style> |
@@ -400,7 +400,7 @@ | |||
"navigationBarTitleText": "考勤记录" | |||
} | |||
}, | |||
// 考勤打卡 | |||
// 教师考勤打卡 | |||
{ | |||
"path": "pages/AttendanceCard/list", | |||
"style": { | |||
@@ -1,79 +1,45 @@ | |||
<template> | |||
<view class="page"> | |||
<!-- 主列表页 --> | |||
<view :class="sideOpen ? 'show' : ''" class="mainpage" style="padding-top: 80rpx;"> | |||
<!-- 顶部条目/分页信息栏 --> | |||
<!-- @buttonClick="sideOpen = true" --> | |||
<l-customlist-banner >{{ tips }}</l-customlist-banner> | |||
<!-- 滚动列表,跨端支持上拉/下拉 --> | |||
<l-scroll-list v-if="ready" @pullDown="pullDown" @toBottom="fetchList()" ref="list"> | |||
<l-customlist :tips="loadState" showTips> | |||
<!-- 单条记录 --> | |||
<view class="customlist-item" v-for="item of list" :key="item.ID"> | |||
<view class="customlist-item-field"> | |||
<text class="customlist-item-field-title">打卡时间:</text> | |||
{{ displayListItem(item, 'ClockTime') }} | |||
</view> | |||
<view class="customlist-item-field"> | |||
<text class="customlist-item-field-title">考勤类型:</text> | |||
{{ showADTypeFormat(item, 'ADType') }} | |||
</view> | |||
<view class="customlist-item-field"> | |||
<text class="customlist-item-field-title">打卡结果:</text> | |||
{{ displayListItem(item, 'ClockStatus') }} | |||
</view> | |||
<!-- <l-customlist-action showEdit @edit="action('edit', item.ID)" showDelete @delete="action('delete', item.ID)" @view="action('view', item.ID)" /> --> | |||
</view> | |||
</l-customlist> | |||
</l-scroll-list> | |||
</view> | |||
<!-- 关闭侧边抽屉按钮 --> | |||
<view @click="sideOpen = false" :class="sideOpen ? 'show' : ''" class="sideclose"> | |||
<l-icon type="pullright" color="blue" /> | |||
</view> | |||
<!-- 侧边栏,用于设置查询条件 --> | |||
<scroll-view :class="sideOpen ? 'show' : ''" class="sidepage" scroll-y> | |||
<view v-if="ready" class="padding"> | |||
<l-customlist-sidepage-datefilter | |||
v-model="dateRange" | |||
@change="searchChange" | |||
title="按时间日期查询: " | |||
ref="datefilter" | |||
class="margin-bottom" | |||
/> | |||
<l-input | |||
v-model="queryData.ADDate" | |||
@change="searchChange" | |||
title ="文本框" | |||
placeholder="按文本框查询" | |||
/> | |||
<l-select | |||
v-model="queryData.ClockStatus" | |||
@change="searchChange" | |||
:range="dataSource.ClockStatus" | |||
title ="下拉框" | |||
placeholder="按下拉框查询" | |||
/> | |||
<!-- 重置查询条件按钮 --> | |||
<view class="padding-tb"> | |||
<l-button @click="reset" line="orange" class="block" block>重置查询条件</l-button> | |||
</view> | |||
</view> | |||
</scroll-view> | |||
<!-- <l-customlist-add v-if="!sideOpen" @click="action('add')" /> --> | |||
<monthSchedule :cardStatus="status" @chooseEntireCard="chooseEntireCard"> | |||
<template v-slot:default="{row}"> | |||
<div v-if="record[row.date]"> | |||
<span v-for="item in record[row.date]" class="statusCricle" :style="{background: item.color}"></span> | |||
</div> | |||
</template> | |||
</monthSchedule> | |||
<template v-if="record[chooseDay.date]"> | |||
<view class="pageBox customlist-item" v-for="(item, ind) in record[chooseDay.date]" :key="item.ADTime"> | |||
<view class=""> | |||
<text>打卡类型:</text> | |||
{{ item.ADType }} | |||
</view> | |||
<view class=""> | |||
<text>打卡时间:</text> | |||
{{ item.ADTime }} | |||
</view> | |||
<view class=""> | |||
<text>打卡状态:</text> | |||
{{ ClockStatus[item.ClockStatus] }} | |||
</view> | |||
<view class=""> | |||
<text>是否外勤:</text> | |||
{{ item.AIsOut?'是':'否' }} | |||
</view> | |||
<view v-if="item.ADPhoto"> | |||
<view> | |||
<text>地址:</text> | |||
{{ item.ClockPlace }} | |||
</view> | |||
<view> | |||
<text>备注:</text> | |||
{{ item.ARemark }} | |||
</view> | |||
<uploadImage :value="item.ADPhoto" readonly title="照片"/> | |||
</view> | |||
</view> | |||
</template> | |||
</view> | |||
</template> | |||
@@ -100,8 +66,16 @@ import get from 'lodash/get' | |||
import set from 'lodash/set' | |||
import pickBy from 'lodash/pickBy' | |||
import mapValues from 'lodash/mapValues' | |||
import monthSchedule from '@/components/monthSchedule/monthSchedule.vue' | |||
import { forEach, forIn } from 'lodash' | |||
import uploadImage from '@/components/uploadImage.vue' | |||
export default { | |||
components:{ | |||
monthSchedule, | |||
uploadImage | |||
}, | |||
data() { | |||
return { | |||
// 数据项的数据类型、结构 | |||
@@ -136,7 +110,38 @@ export default { | |||
// 列表与分页信息 | |||
page: 1, | |||
total: 2, | |||
list: [] | |||
list: [] , | |||
UserNo:'', | |||
// 打卡数据 | |||
record:{}, | |||
status:{ | |||
// 1: { | |||
// title: '缺勤', | |||
// color: '#F56C6C' | |||
// }, | |||
// 2: { | |||
// title: '正常', | |||
// color: '#67C23A' | |||
// }, | |||
// 3: { | |||
// title: '迟到早退', | |||
// color: '#E6A23C' | |||
// }, | |||
// 4: { | |||
// title: '未开始', | |||
// color: '#9CADADB7' | |||
// }, | |||
}, | |||
chooseDay:{}, | |||
ClockStatus:{ | |||
1:'正常', | |||
2:'迟到', | |||
3:'早退', | |||
4:'上班补签', | |||
5:'下半补签', | |||
6:'缺勤' | |||
} | |||
} | |||
}, | |||
@@ -172,7 +177,7 @@ export default { | |||
this.searchData.UserNo=userInfo.account; | |||
const result = await this.HTTP_GET( | |||
'learun/adms/attendance/getrecordpagelist', | |||
'learun/adms/attendance/GetTeacherRecord', | |||
{ | |||
// 这里 sidx 表示排序字段,sord 表示排序方式(DESC=降序,ASC=升序) | |||
// 代码生成器生成时默认按照主键排序,您可以修改成按创建时间的字段降序 | |||
@@ -183,13 +188,16 @@ export default { | |||
) | |||
if (!result) { return } | |||
this.total = result.total | |||
this.page = result.page + 1 | |||
this.list = isConcat?this.list.concat(result.rows):result.rows | |||
this.tips = `已加载 ${Math.min(result.page, result.total)} / ${result.total} 页,共 ${result.records} 项` | |||
this.loadState = result.page >= result.total ? '已加载所有项目' : '向下翻以加载更多' | |||
this.list = result.data.map(e=>{ | |||
// e.date = [e.ADYear,e.ADMonth,e.ADDay].join('-') | |||
e.date = e.ADTime.substring(0,10) | |||
e.color = e.ClockStatus == '1'?'#409EFF':'#E6A23C' | |||
this.record[e.date]?this.record[e.date].push(e):this.record[e.date] = [e] | |||
return e | |||
}) | |||
this.status = {} | |||
console.log(this.list,this.record) | |||
}, | |||
// 刷新清空列表 | |||
@@ -326,7 +334,50 @@ export default { | |||
} | |||
return type; | |||
} | |||
}, | |||
async uploadCo(val){ | |||
if (!val) { | |||
return [] | |||
} | |||
const uidList = val; | |||
const fileList = [] | |||
const wxlist = await this.FETCH_FILEList(uidList); | |||
for (const wxfile of wxlist) { | |||
const fileInfo = await this.FETCH_FILEINFO(wxfile.F_Id) | |||
if (!fileInfo) { | |||
continue | |||
} | |||
const fileType = fileInfo.F_FileType | |||
const fileSize = fileInfo.F_FileSize | |||
const fileName = fileInfo.F_FileName | |||
const path = this.API + '/learun/adms/annexes/wxdown?' + this.URL_QUERY(wxfile.F_Id, true) | |||
fileList.push({ | |||
path, | |||
type: fileType, | |||
uid:wxfile.F_Id, | |||
folderId:wxfile.F_FolderId, | |||
size: fileSize, | |||
name: fileName | |||
}) | |||
} | |||
return fileList | |||
}, | |||
async chooseEntireCard(e){ | |||
this.chooseDay.isActive = false | |||
e.isActive = true | |||
for (let s in this.record[e.date]) { | |||
let e1 = this.record[e.date] | |||
for (let s1 in e1) { | |||
if(e1[s1].ADPhoto) e1[s1].ADPhoto = await this.uploadCo(e1[s1].ADPhoto) | |||
} | |||
} | |||
this.status = {} | |||
this.chooseDay = e | |||
}, | |||
} | |||
} | |||
@@ -336,4 +387,11 @@ export default { | |||
<style lang="less" scoped> | |||
@import '~@/common/css/sidepage.less'; | |||
@import '~@/common/css/customlist.less'; | |||
.statusCricle{ | |||
display: inline-block; | |||
width: 5px; | |||
height: 5px; | |||
border-radius: 50%; | |||
margin-right: 4px; | |||
} | |||
</style> |
@@ -114,6 +114,10 @@ | |||
if ([5].includes(this.info.AttendanceType)) { | |||
return | |||
} | |||
if(!this.postData.ClockPlace){ | |||
this.TOAST('获取定位失败,无法打卡') | |||
return | |||
} | |||
if ([4].includes(this.info.AttendanceType)) { | |||
this.NAV_TO(`./single`, this.postData,true) | |||
return | |||
@@ -164,8 +168,14 @@ | |||
this.map = new BMapGL.Map('container'); | |||
await this.isFieldPersonnel() | |||
if(!this.postData.ClockPlace){ | |||
return true | |||
} | |||
this.timer1 = setInterval(async ()=>{ | |||
if(this.isGetingLocal)return | |||
if(!this.postData.ClockPlace){ | |||
clearInterval(this.timer1) | |||
} | |||
this.isGetingLocal = true | |||
await this.isFieldPersonnel() | |||
// console.log(this.postData) | |||
@@ -128,6 +128,10 @@ | |||
if ([5].includes(this.info.AttendanceType)) { | |||
return | |||
} | |||
if(!this.postData.ClockPlace){ | |||
this.TOAST('获取定位失败,无法打卡') | |||
return | |||
} | |||
if ([4].includes(this.info.AttendanceType)) { | |||
this.NAV_TO(`./single`, this.postData,true) | |||
return | |||
@@ -183,8 +187,14 @@ | |||
this.map = new BMapGL.Map('container'); | |||
await this.isFieldPersonnel() | |||
if(!this.postData.ClockPlace){ | |||
return true | |||
} | |||
this.timer1 = setInterval(async ()=>{ | |||
if(this.isGetingLocal)return | |||
if(!this.postData.ClockPlace){ | |||
clearInterval(this.timer1) | |||
} | |||
this.isGetingLocal = true | |||
await this.isFieldPersonnel() | |||
// console.log(this.postData) | |||