这里写自定义目录标题
- vue之排班日历的 实现
- index.vue
- 排班日历组件 calendar.vue
- calendar.js
vue之排班日历的 实现
- 查询日期和数据,展示对于的排班日历,蓝色为高亮区,代表排班的日期
index.vue
<template>
<div class="inspect_schedule_page repair_page spotCheck-page" v-cloak>
<div class="content">
<div class="do_content">
<div class="content-top">
<div class="search-left">
<el-form :model="ruleForm" :rules="rules" ref="ruleFormRef" label-width="100px">
<el-col :span="8">
<el-form-item :label="年月份" prop="date">
<el-date-picker v-model="ruleForm.date" type="month" format="yyyy-MM" value-format="yyyy-MM"
:placeholder="选择月份" clearable>
</el-date-picker>
</el-form-item>
</el-col>
</el-form>
</div>
<el-col :span="8">
<div style="text-align:right">
<el-button type="primary" @click="search">查询</el-button>
<el-button @click="reset('ruleFormRef')">清除'</el-button>
</div>
</el-col>
</div>
<div class="content-button">
<el-button type="primary" @click="setSchedule">排班设置</el-button>
ruleForm - {{ ruleForm}}
</div>
<div class="table_wrapper table-wrap">
<div class="current-time">
{{ currentShowMonthDate }}
</div>
<div class="btn-wrap">
<el-button :class="['baseBtn', activeMonth ==='prev' ? 'activeBtn':'']" @click="monthChange('prev')"
:disabled="activeMonth ==='prev'">上个月</el-button>
<el-button :class="['baseBtn', activeMonth ==='current' ? 'activeBtn':'']" @click="monthChange('current')"
:disabled="activeMonth ==='current'">本月
</el-button>
<el-button :class="['baseBtn', activeMonth ==='next' ? 'activeBtn':'']" @click="monthChange('next')"
:disabled="activeMonth ==='next'">下个月
</el-button>
</div>
<calendar class="calendar" :width="'100%'" :currentShowMonth="currentShowMonth"
:calendarData="currentTableData" userType="show">
</calendar>
</div>
</div>
</div>
<!-- 设置弹窗 -->
<ScheduleSetting v-if="showSchedule" :showSchedule="showSchedule" @changeScheduleDialog="changeScheduleDialog">
</ScheduleSetting>
</div>
</template>
<script>
import calendar from './components/calendar.vue'
import ScheduleSetting from "./components/ScheduleSetting.vue"
import "@/views/repair/assets/css/repair.css"
export default {
components: {
calendar,
ScheduleSetting,
},
name: 'index',
data() {
return {
ruleForm: {
date: "",
},
rules: {
],
date: [
{ required: true, message: '请选择年月份', trigger: ['blur', 'change'] }
]
},
groupList: [], // 班组列表 数据
currentMonth: "",// 当前月份
currentShowMonth: "",// 当前月份的 临时变量
activeMonth: "current", //当前月份 active
currentTableData: [], // 当前 查询的tabel数据
showSchedule: false, // 是否展示排班
};
},
computed: {
currentShowMonthDate() {
let resMonth = "";
if (this.currentShowMonth) {
let tempArr = this.currentShowMonth.split("-");
resMonth = tempArr[0] + " 年 " + parseInt(tempArr[1]) + " 月"
} else {
resMonth = ""
}
return resMonth;
}
},
watch: {
currentMonth(newV) {
// console.log("监听", newV);
this.currentShowMonth = newV;
this.activeMonth = "current"
}
},
methods: {
// 上一个月份
getPreMonth(date) {
let arr = String(date).split('-');
let year = arr[0]; //获取当前日期的年份
let month = arr[1]; //获取当前日期的月份
let year2 = year;
let month2 = parseInt(month) - 1;
if (month2 == 0) {
year2 = parseInt(year2) - 1;
month2 = 12;
}
if (month2 < 10) {
month2 = '0' + month2;
}
let t2 = year2 + '-' + month2
return t2;
},
// 下一个月份
getNextMonth(date) {
var arr = String(date).split('-');
var year = arr[0]; //获取当前日期的年份
var month = arr[1]; //获取当前日期的月份
var year2 = year;
var month2 = parseInt(month) + 1;
if (month2 == 13) {
year2 = parseInt(year2) + 1;
month2 = 1;
}
if (month2 < 10) {
month2 = '0' + month2;
}
var t2 = year2 + '-' + month2;
return t2;
},
// 查询
search() {
console.log("查询", this.ruleForm);
// 校验 班组与年月的必填
this.$refs.ruleFormRef.validate((valid) => {
if (valid) {
this.searchSucObj.date = this.ruleForm.date;
// 控制月份的展示
this.currentMonth = this.ruleForm.date;
this.currentShowMonth = this.ruleForm.date;
this.activeMonth = "current";
// 请求 table日历数据
if (this.ruleForm.date == "2022-04") {
this.currentTableData = ["2022-04-01", "2022-04-02", "2022-04-03", "2022-04-04", "2022-04-05", "2022-04-08"];
} else if (this.ruleForm.date == "2022-05") {
this.currentTableData = ["2022-05-08", "2022-05-09", "2022-05-10", "2022-05-11", "2022-05-13", "2022-05-17"];
}
console.log("currentTableData", this.currentTableData);
} else {
return false;
}
});
},
// 清除
reset(formName) {
// Object.keys(this.ruleForm).forEach(key => { this.ruleForm[key] = '' })
this.$refs[formName].resetFields();
this.currentShowMonth = "";
this.activeMonth = "current"
console.log("清除", this.ruleForm);
},
// 排班设置
setSchedule() {
this.showSchedule = true;
},
// 关闭 排班设置
changeScheduleDialog(flag) {
this.showSchedule = flag;
},
// 月份的改变
monthChange(type) {
this.activeMonth = type;
if (type == "prev") {
this.currentShowMonth = this.getPreMonth(this.currentMonth);
} else if (type == "next") {
this.currentShowMonth = this.getNextMonth(this.currentMonth);
} else {
this.currentShowMonth = this.currentMonth
}
},
},
}
</script>
<style lang="scss" scoped>
.spotCheck-page {
height: calc(100% - 20px);
.content {
&-top {
position: relative;
margin: 10px 0px;
height: 60px;
border-bottom: 1px solid #d9d9d9;
}
&-button {
position: relative;
top: -5px;
margin-bottom: 10px;
}
}
.table-wrap {
.current-time {
font-weight: 900;
font-size: 18px;
}
.btn-wrap {
position: relative;
right: 0;
margin-bottom: 5px;
text-align: right;
/deep/ .el-button + .el-button {
margin-left: 0;
}
.baseBtn {
color: #001e48;
background: #0e91e3;
}
.activeBtn {
background: #dbdbdb;
}
}
}
}
</style>
排班日历组件 calendar.vue
<template>
<div class="calendar">
<table class="calendar-table" :style="{width}">
<thead>
<tr>
<th v-for="(item, i) in weeks" :key="i">{{ item }}</th>
</tr>
</thead>
<tbody class="tbody">
<tr v-for="(dates, i) in res" :key="i" :style="{height: tbodyHeight}">
<td v-for="(item, index) in dates" :key="index"
:class="{notCurMonth: !item.isCurMonth, currentDay: item.date === curDate, selectDay: item.isSelected, rangeSelectd: item.isRangeSelected, weekend: item.isWeekend}"
@click="handleItemClick(item, i, index)">
<span v-if="item.isCurMonth">{{ item.date }}</span>
<slot :data="item" />
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
/**
* 参数介绍
* canSelect:是否禁用,点击table高亮; currentShowMonth:当前月份的值(eg:2022-04);calendarData:当前要展示高亮的日历数据(数组)
* startOfWeek:开始第一周的起始位置;
*/
import { getDaysInMonth, handleCrateDate,parseTime} from './calendar.js'
export default {
props: {
userType: {
type: String,
default: "show"
},
canSelect: {
type: Boolean,
default: false
},
currentShowMonth: {
type: String,
default: "",
},
calendarData: {
type: Array,
default() {
return []
}
},
startOfWeek: {
type: Number,
default: 1
},
width: {
type: String,
default: '70%'
},
tbodyHeight: {
type: String,
default: '60px'
}
},
data() {
return {
weeks: ['一', '二', '三', '四', '五', '六', '日'],
days: 0, // 当前月总共天数
curDate: parseTime(new Date().getTime()), // 当前日期 yyyy-MM-dd 格式,用来匹配是否是当前日期
showDays: [], // 总共展示的42个日期
res: [], // 二维数组
selectedDates: [], // 选中的日期
}
},
watch: {
// 监听当前月份 更新日历数据
'currentShowMonth': {
immediate: true,
handler(newV) {
if (this.userType == "show") {
if (!this.calendarData.length) return;
let curYear = newV.split('-')[0];
let curMonth = newV.split('-')[1] * 1 - 1; // 月份从0开始的 因此要-1
this.handleGetDays(curYear, curMonth, this.startOfWeek) // 渲染月份数据
// console.log("有数据执行", this.showDays);
// 有后台 日历数据 选中 isSelected
this.showDays = this.showDays.map(item => {
this.calendarData.forEach(it => {
if (it == item.date) {
item.isSelected = true;
}
})
return item;
})
} else if (this.userType = "edit") {
console.log("编辑的", newV);
let curYear = newV.split('-')[0];
let curMonth = newV.split('-')[1] * 1 - 1; // 月份从0开始的 因此要-1
this.handleGetDays(curYear, curMonth, this.startOfWeek) // 渲染月份数据
// // 有后台 日历数据 选中 isSelected
// this.showDays = this.showDays.map(item => {
// this.calendarData.forEach(it => {
// if (it == item.date) {
// item.isSelected = true;
// }
// })
// return item;
// })
}
}
}
},
created() {
this.weeks.unshift(...this.weeks.splice(this.startOfWeek - 1))
},
mounted() {
// if (localStorage.selectedDates) this.selectedDates = JSON.parse(localStorage.selectedDates)
},
methods: {
// 处理 日期
handleGetDays(year, month, startOfWeek) {
this.showDays = []
this.days = getDaysInMonth(year, month); // 拿到当前月份天数
let firstDayOfWeek = new Date(`${year}-${month + 1}-01`).getDay() // 开始第一周 从那天排起
// console.log("开始第一周 从周几排起", firstDayOfWeek);
// 处理周起始日
const obj = {
1: '一',
2: '二',
3: '三',
4: '四',
5: '五',
6: '六',
0: '日'
}
const firstDayInCN = obj[firstDayOfWeek]
const index = this.weeks.indexOf(firstDayInCN)
// console.log("开始第一周 从周几排起索引", firstDayOfWeek, index)
if (firstDayOfWeek === 0) { // 星期天为0 星期一为1 ,以此类推
firstDayOfWeek = 7
}
let prevDays = handleCrateDate(year, month - 1, 1, index + 1, 'prev')
// console.log("上个月prevDays", prevDays);
let rearDays = handleCrateDate(year, month * 1 + 1, 1, 42 - this.days - (index), 'rear')
// console.log("下个月rearDays", rearDays);
let curDays = handleCrateDate(year, month, 1, this.days)
// console.log("本月curDays", curDays);
this.showDays.unshift(...prevDays)
this.showDays.push(...curDays)
this.showDays.push(...rearDays)
this.res = this.handleFormatDates(this.showDays)
// this.res.splice(5,1)
// 清除表格的空行
// let countEmpty=0
this.res.forEach((item, index) => {
// console.log(Array.from(item).filter(i=>i.isCurMonth==false))
if (Array.from(item).filter(i => i.isCurMonth == false).length == 7) {
this.res.splice(index, 1)
}
// console.log(item,index)
})
// console.log('输出日历表二维数组', this.res)
},
// 传入长度42的原数组,最终转换成二维数组
handleFormatDates(arr, size = 7) {
const arr2 = []
for (let i = 0; i < size; i++) {
const temp = arr.slice(i * size, i * size + size)
arr2.push(temp)
}
// console.log(arr2)
return arr2
},
// 处理 日历 头部的展示
handleTableHead(start) {
const sliceDates = this.weeks.splice(start - 1)
this.weeks.unshift(...sliceDates)
},
// 日历点击事件
handleItemClick(item, i, j) {
// 若是 为展示状态的 则不可点击触发之,否则可以点击勾选选中日历排班
if (!this.canSelect) return
console.log('单元格点击', item)
// console.log('选中的selectedDates', this.selectedDates)
this.$nextTick(() => {
this.res[i][j].isSelected = !this.res[i][j].isSelected
if (this.res[i][j].isSelected) {
this.selectedDates.push(this.res[i][j].date)
this.selectedDates = Array.from(new Set(this.selectedDates))
} else {
this.selectedDates.splice(this.selectedDates.indexOf(item.date), 1)
}
console.log('选中的selectedDates22', this.selectedDates)
this.$emit('dateSelected', this.selectedDates)
})
},
}
}
</script>
<style scoped lang="scss">
.calendar {
display: flex;
flex-direction: column;
}
.calendar-table {
table-layout: fixed;
border-collapse: collapse;
transition: 0.3s;
thead tr {
height: 45px;
line-height: 45px;
}
tbody tr {
&:first-child td {
border-top: 1px solid #08a8a0;
}
td {
cursor: pointer;
border-right: 1px solid #08a8a0;
border-bottom: 1px solid #08a8a0;
&:first-child {
border-left: 1px solid #08a8a0;
}
}
}
}
.notCurMonth {
color: #c0c4cc;
}
.currentDay {
background-color: #f8f8de;
}
.selectDay {
color: #fff;
background-color: #409eff;
}
.rangeSelectd {
color: #606266;
background-color: #dee2e9;
}
.weekend {
color: #f73131;
}
</style>
calendar.js
- 注意点:需要监听 日期数据的 变化 再进行验证
// 获取该月的天数
export const getDaysInMonth = (year, month) => {
const day = new Date(year, month + 1, 0).getDate()
// console.log("获取当前年", month, "当前月", month, "的天数", day);
return day
}
// 创建日期 yyyy-MM-dd 格式, 用于创建非当前月的日期
export const handleCrateDate = (year, month, start, end, type) => {
const arr = []
if (type === 'prev') { // 上一月
if (start === end) return []
const daysInLastMonth = getDaysInMonth(year, month - 1) // 获取上一个月有多少天
// console.log(`当前月是${month + 1}月, 上一月${month}月的天数是${daysInLastMonth}天`)
for (let i = daysInLastMonth - end + 2; i <= daysInLastMonth; i++) {
arr.push({
// date: `${month === 0 ? year - 1 : year}-${(month + 1) < 10 ? month === 0 ? 12 : `0${month}` : month}-${i < 10 ? `0${i}` : i}`,
date: parseTime(new Date(year, month - 1, i)),
isCurMonth: false,
isSelected: false,
isRangeSelected: false
})
}
} else if (type === 'rear') { // 下一月
for (let i = start; i <= end; i++) {
arr.push({
// date: `${month === 11 ? year + 1 : year}-${(month + 1) < 9 ? `0${month + 2}` : month + 2 <= 12 ? month + 2 : (month + 2) % 12 < 10 ? `0${(month + 2) % 12}` : (month + 2) % 12}-${i < 10 ? `0${i}` : i}`,
date: parseTime(new Date(year, month + 1, i)),
isCurMonth: false,
isSelected: false,
isRangeSelected: false
})
}
} else { // 本月
for (let i = start; i <= end; i++) {
arr.push({
// date: `${year}-${(month + 1) < 10 ? `0${month + 1}` : month + 1}-${i < 10 ? `0${i}` : i}`,
date: parseTime(new Date(year, month, i)),
isCurMonth: true,
isSelected: false,
isRangeSelected: false
})
}
}
// console.log(arr)
return arr
}
// 创建年月时间 函数
export const handleCreateDatePicker = () => {
const years = []
const months = []
for (let i = 1970; i <= 2099; i++) {
years.push({
label: `${i}年`,
value: i
})
}
for (let i = 0; i <= 11; i++) {
months.push({
label: `${i + 1}月`,
value: i
})
}
return {
years,
months
}
}
/**
* Parse the time to string
* @param {(Object|string|number)} time
* @param {string} cFormat
* @returns {string | null}
*/
export function parseTime(time, cFormat) {
if (arguments.length === 0 || !time) {
return null
}
const format = cFormat || '{y}-{m}-{d}'
let date
if (typeof time === 'object') {
date = time
} else {
if ((typeof time === 'string')) {
if ((/^[0-9]+$/.test(time))) {
// support "1548221490638"
time = parseInt(time)
} else {
// support safari
// https://stackoverflow.com/questions/4310953/invalid-date-in-safari
time = time.replace(new RegExp(/-/gm), '/')
}
}
if ((typeof time === 'number') && (time.toString().length === 10)) {
time = time * 1000
}
date = new Date(time)
}
const formatObj = {
y: date.getFullYear(),
m: date.getMonth() + 1,
d: date.getDate(),
h: date.getHours(),
i: date.getMinutes(),
s: date.getSeconds(),
a: date.getDay()
}
const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
const value = formatObj[key]
// Note: getDay() returns 0 on Sunday
if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
return value.toString().padStart(2, '0')
})
return time_str
}
- 效果