el-calendar日历 简易排班

公司物流部要个简易的排班功能,由主管去设置线路,线路绑定上负责人。然后直接往日历里添加。
el-calendar日历 简易排班_第1张图片
el-calendar日历 简易排班_第2张图片
el-calendar日历 简易排班_第3张图片
el-calendar日历 简易排班_第4张图片

1、隐藏了自带的切换月份,改用了日期选择器。
2、禁用了非本月的点击事件,防止点击自动跳转到其他月份。
3、添加了点击多选,批量处理,也有单日排班处理。
4、拖拽删除排班,

代码如下

export function getFirstDay(monthValue) {
  let date = new Date(monthValue)
  let month = parseInt(date.getMonth() + 1)
  let day = date.setDate(1);
  if (month < 10) month = '0' + month
  if (day < 10) day = '0' + day
  return date.getFullYear() + '-' + month
}
export function getLastDay(monthValue){
  var year = new Date(monthValue).getFullYear(); //获取年份
  var month = new Date(monthValue).getMonth() + 1; //获取月份
  var lastDate = new Date(year, month , 0).getDate(); //获取当月最后一日
  month = month < 10 ? '0' + month : month ; //月份补 0
  return [ year,month ,lastDate ].join("-")
}
export function getNextDayByDay(dayValue) {
  let date = new Date(new Date(dayValue).getTime() + 3600 * 24 * 1000)
  let month = parseInt(date.getMonth() + 1)
  let day = date.getDate()
  if (month < 10) month = '0' + month
  if (day < 10) day = '0' + day
  return date.getFullYear() + '-' + month + '-' + day
}

时间过滤是因为我这边大部分后端接口让传2个日期,所以统一处理了。

<template>
  <div class="calender_body">
    <div class="calender-class">
      <div class="class-header">
        <el-date-picker
          v-model="currentMonth"
          type="month"
          format="yyyy 年 MM 月"
          value-format="yyyy-MM"
          placeholder="选择月份"
          @change="changeCurrentMonth"
        />
        <el-button
          type="primary"
          style="margin-left: 10px;"
          :disabled="!selectDateItems.length"
          @click="handleShowAddBatchDialog"
        >批量排班</el-button>
      </div>
      <div class="monthText">{{ currentMonth && currentMonth.replace(/-/,'年') }}月 排班表</div>
      <div v-if="isdraging" class="deleteDiv">
        <div
          class="delIconBox"
          @dragover.prevent
          @dragenter.prevent
          @drop="handleDeleteClassByDrop"
        >
          <i class="el-icon-delete" style="font-size: 40px;" />
        </div>
      </div>
    </div>
    <el-calendar v-model="currentMonth">
      <!-- 这里使用的是 2.5 slot 语法,对于新项目请使用 2.6 slot 语法-->
      <template slot="dateCell" slot-scope="{date, data}">
        <div
          class="day-content-class"
          :class="selectDateItems.some(el => el == data.day)? 'is-selected':''"
          @click.stop="handleSelectItem(data)"
        >
          <div class="header-class">
            <div class="day-class">{{ data.day.split('-').slice(1).join('-') }}</div>
            <div class="handle-class">
              <el-button
                icon="el-icon-edit"
                class="edit-color"
                circle
                @click.stop="handleWorkInfo(data)"
              />
            </div>
          </div>
          <template v-if="viewDate[data.day]">
            <div class="paiban-class">
              <!--  @dragenter="handleDragEnter($event, dayValue)"  @dragover.prevent="handleDragOver($event)"-->
              <div
                v-for="(dayValue, i,index) in viewDate[data.day]"
                :key="index"
                draggable="true"
                @dragstart="handleDragStart(dayValue)"
                @dragend="handleDragEnd()"
              >
                <div class="class-item-tag">
                  <span>{{ dayValue.logisticsRouteName }}</span>
                  <span v-if="dayValue.users">-{{ dayValue.users[0].userName }}</span>
                </div>
              </div>
            </div>
          </template>
          <template v-else>
            <div class="no-work-class">
              <div class="icon-class">
                <i class="el-icon-date" />
              </div>
              <div class="tips-class">暂无排班</div>
            </div>
          </template>
        </div>
      </template>
    </el-calendar>
    <!-- 批量排班 -->
    <el-dialog title="批量排班" :visible.sync="addBatchDialog" size="50%">
      <el-form :model="addBatchForm">
        <el-form-item label="值班路线" label-width="80px">
          <el-select
            v-model="addBatchForm.logisticsRouteCode"
            style="width:100%"
            placeholder="请选择"
            filterable
            multiple
            default-first-option
            clearable
          >
            <el-option
              v-for="item in routerDataList"
              :key="item.id"
              :label="item.name"
              :value="item.code"
              :disabled="selectDateItemsHasRouteArr.some(el => el == item.code)"
            >
              <span style="float: left">{{ item.name }}</span>
              <span
                style="float: right;margin-right: 12px; color: #8492a6; font-size: 13px"
              >{{ item.userInfos[0].userName }}</span>
            </el-option>
          </el-select>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="addBatchDialog = false">取 消</el-button>
        <el-button type="primary" @click="handleSubmitAddBatch">确 定</el-button>
      </span>
    </el-dialog>
    <!-- 排班详情-->
    <el-drawer :title="'【' + currentDay + '】排班'" :visible.sync="dayClassdrawer" size="50%">
      <div style="width: 99%;margin:0 auto">
        <el-button type="primary" style="margin-bottom: 4px;" @click="addDayClassDialog = true">添加排班</el-button>
        <el-table :data="workInfoList" border :height="`calc(100vh - 180px)`">
          <el-table-column prop="day" label="日期" width="90" show-overflow-tooltip />
          <el-table-column prop="logisticsRouteName" label="线路" width="140" show-overflow-tooltip />
          <el-table-column label="负责人" width="120" show-overflow-tooltip>
            <template slot-scope="scope">{{ scope.row.users.join('; ') }}</template>
          </el-table-column>
          <el-table-column label="途径医院" width="*" show-overflow-tooltip>
            <template slot-scope="scope">{{ scope.row.hospitals.join('; ') }}</template>
          </el-table-column>
          <el-table-column fixed="right" label="操作" width="100">
            <template slot-scope="scope">
              <el-button
                type="text"
                style="color:red"
                @click.native.prevent="deleteRow(scope.row)"
              >删除</el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>
    </el-drawer>
    <!-- 单日排班 -->
    <el-dialog :title="'添加【' + currentDay + '】排班'" :visible.sync="addDayClassDialog" size="50%">
      <el-form :model="addForm">
        <el-form-item label="值班路线" label-width="80px">
          <el-select
            v-model="addForm.logisticsRouteCode"
            style="width:100%"
            placeholder="请选择"
            filterable
            multiple
            default-first-option
            clearable
          >
            <el-option
              v-for="item in routerDataList"
              :key="item.id"
              :label="item.name"
              :value="item.code"
              :disabled="workInfoList.some(el => el.logisticsRouteCode == item.code)"
            >
              <span style="float: left">{{ item.name }}</span>
              <span
                style="float: right;margin-right: 12px; color: #8492a6; font-size: 13px"
              >{{ item.userInfos[0].userName }}</span>
            </el-option>
          </el-select>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="addDayClassDialog = false">取 消</el-button>
        <el-button type="primary" @click="handleSubmitAddDayClass">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>
   
<script>
import { getFirstDay, getNextDayByDay, getLastDay } from "@/utils/index";
export default {
  data() {
    return {
      isdraging: false,
      selectDateItems: [], // 当前选择日期
      selectDateItemsHasRouteArr: [], // 当前日期包含的线路
      routerDataList: [], // 线路
      currentMonth: "",
      viewDate: {},
      thisDay: null,
      thisDayWork: null,
      ending: null,
      dragging: null,

      addBatchDialog: false,
      // 批量添加
      addBatchForm: {
        logisticsRouteCode: []
      },
      // 单日添加
      addForm: {
        logisticsRouteCode: []
      },
      dayClassdrawer: false,
      currentDay: "",
      addDayClassDialog: false,
      workInfoList: [],
      dialogLoading: false
    };
  },
  mounted() {
    this.getRouteListData();
    this.currentMonth = getFirstDay(new Date().getTime());
    this.getCurrentMonthClass();
  },
  methods: {
    handleDragStart(item) {
      this.isdraging = true;
      this.dragging = item;
    },
    handleDragEnd() {
      this.isdraging = false;
    },
    // 拖动删除排班
    handleDeleteClassByDrop(e) {
      let params = [this.dragging.id];
      this.$api.LogisticsScheduleApi.DeleteLogisticsSchedule(params).then(
        res => {
          this.$message.success("删除成功");
          this.getCurrentMonthClass();
        }
      );
    },
    // handleDragOver(e) {
    //   // 首先把div变成可以放置的元素,即重写dragenter/dragover
    //   e.dataTransfer.dropEffect = "move"; // e.dataTransfer.dropEffect="move";//在dragenter中针对放置目标来设置!
    // },
    // handleDragEnter(e, item) {
    //   e.dataTransfer.effectAllowed = "move"; // 为需要移动的元素设置dragstart事件
    //   this.ending = item;
    // },

    // 获取线路列表
    getRouteListData() {
      let params = {
        pageIndex: 1,
        pageSize: 999
      };
      this.$api.LogisticsScheduleApi.PageLogisticsRoute(params).then(res => {
        this.routerDataList = res.data.items;
      });
    },
    // 切换月份
    changeCurrentMonth(e) {
      this.currentMonth = e;
      this.getCurrentMonthClass();
    },
    // 获取当前月物流排班
    getCurrentMonthClass() {
      let params = {
        StartDay: this.currentMonth + "-01",
        EndDay: getLastDay(this.currentMonth + "-01")
      };
      this.$api.LogisticsScheduleApi.QueryLogisticsSchedule(params).then(
        res => {
          let obj = {};
          if (res.data.length) {
            for (let i of res.data) {
              if (obj[i.day]) {
                obj[i.day].push({ ...i });
              } else {
                obj[i.day] = [{ ...i }];
              }
            }
          }
          this.viewDate = obj;
        }
      );
    },
    // 单日排班详情抽屉
    handleWorkInfo(data) {
      this.currentDay = data.day;
      let params = {
        StartDay: this.currentDay,
        EndDay: getNextDayByDay(this.currentDay)
      };
      this.$api.LogisticsScheduleApi.QueryLogisticsSchedule(params).then(
        res => {
          this.workInfoList = res.data.map(el => {
            el.hospitals = el.hospitals.map(item => item.hospitalName);
            el.users = el.users.map(item => item.userName);
            return el;
          });
        }
      );
      this.dayClassdrawer = true;
    },
    // 添加单日排班
    handleSubmitAddDayClass() {
      let params = {
        logisticsRouteCode: this.addForm.logisticsRouteCode,
        day: [this.currentDay]
      };
      this.dialogLoading = true;
      this.$api.LogisticsScheduleApi.CreateLogisticsSchedule(params)
        .then(res => {
          this.$message.success("添加成功");
          let parmas = {
            day: this.currentDay
          };
          this.handleWorkInfo(parmas);
          this.getCurrentMonthClass();
          this.addDayClassDialog = false;
        })
        .finally(() => {
          this.dialogLoading = false;
        });
    },
    // 删除排班
    deleteRow(row) {
      this.$confirm("此操作将会删除此条排班记录, 是否继续?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      }).then(() => {
        let params = [row.id];
        this.$api.LogisticsScheduleApi.DeleteLogisticsSchedule(params).then(
          res => {
            this.$message.success("删除成功");
            this.getCurrentMonthClass();
            let date = {
              day: this.currentDay
            };
            this.handleWorkInfo(date);
          }
        );
      });
    },
    // 选中事件
    handleSelectItem(data) {
      let dataStr = data.day;
      if (this.selectDateItems.findIndex(el => el == dataStr) > -1) {
        this.selectDateItems.splice(
          this.selectDateItems.findIndex(el => el == dataStr),
          1
        );
      } else {
        this.selectDateItems.push(dataStr);
      }
    },
    //批量弹窗
    handleShowAddBatchDialog() {
      let arr = [];
      for (let i of this.selectDateItems) {
        if (this.viewDate[i]) {
          for (let j of this.viewDate[i]) {
            arr.push(j.logisticsRouteCode);
          }
        }
      }
      const newArr = [...new Set(arr)];
      this.selectDateItemsHasRouteArr = newArr;
      this.addBatchDialog = true;
    },
    //批量排班提交
    handleSubmitAddBatch() {
      let params = {
        logisticsRouteCode: this.addBatchForm.logisticsRouteCode,
        day: this.selectDateItems
      };
      this.dialogLoading = true;
      this.$api.LogisticsScheduleApi.CreateLogisticsSchedule(params)
        .then(res => {
          this.$message.success("添加成功");
          this.getCurrentMonthClass();
          this.selectDateItems = [];
          this.addBatchForm = this.$options.data().addBatchForm;
          this.addBatchDialog = false;
        })
        .finally(() => {
          this.dialogLoading = false;
        });
    }
  }
};
</script>
   
<style lang="scss" scoped>
.calender_body {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
}

.el-table__fixed-right {
  height: 100% !important;
}

.calender-class {
  position: relative;
  width: 100%;
  height: 70px;
}
.class-header {
  position: relative;
  padding: 10px;
  display: flex;
}
.deleteDiv {
  position: absolute;
  width: 100%;
  height: 70px;
  line-height: 70px;
  text-align: center;
  z-index: 11;
  top: 0;
  left: 0;
  background: rgba(155, 155, 155, 0.6);
}
.delIconBox {
  width: 160px;
  height: 60px;
  border-radius: 10px;
  background: rgba(155, 155, 155, 0.9);
  box-shadow: 0 0 10px #fff;
  margin: 5px auto;
}
.monthText {
  width: 100%;
  text-align: center;
  font-size: 16px;
  font-weight: 500;
  line-height: 20px;
  color: #666;
  height: 20px;
}
::v-deep .el-calendar-table thead th {
  box-shadow: inset 0 0 2px rgba(0, 0, 0, 0.3);
}
.is-selected {
  color: #1989fa;
  background: #ddeffb;
}

::v-deep .el-calendar__body {
  height: 85vh;
}

::v-deep .el-calendar-table {
  width: 100%;
  height: 100%;
  //使不是本月的日期不可点击,不会跳转到其他月份
  &:not(.is-range) {
    td.next {
      pointer-events: none;
    }
    td.prev {
      pointer-events: none;
    }
  }
  td.is-selected {
    background: none !important;
  }
  .prev,
  .next {
    .icon-class,
    .tips-class,
    .edit-color {
      color: #e1e1e1;
    }
  }
  td.is-today {
    .day-class {
      background: #44a2f3;
      width: 50px;
      text-align: center;
      height: 20px;
      border-radius: 4px;
      color: #fff;
      font-weight: 500;
    }
  }
}

::v-deep .el-calendar-day {
  height: 100% !important;
  padding: 1px;
}
::v-deep .el-calendar__header {
  display: none;
}

.day-content-class {
  height: 100%;
  display: flex;
  flex-direction: column;
  padding: 7px;
}

.header-class {
  display: flex;
  height: 24px;
  justify-content: space-between;
  align-items: center;
}

.paiban-class {
  display: flex;
  flex-flow: wrap;
  align-items: center;
  .class-item-tag {
    font-size: 12px;
    line-height: 20px;
    color: #fff;
    width: auto;
    border-radius: 4px;
    padding: 0 4px;
    margin: 4px;
    background: #11be11;
  }
}

.paiban-icon-class {
  font-size: 22px;
  margin: 8px 0 10px 0;
}

.paiban-name-class {
  padding-top: 10px;
}

.no-work-class {
  text-align: center;
  color: #cacaca;
}

.icon-class {
  font-size: 20px;
  color: #777;
  margin-bottom: 20px;
}
.tips-class {
  font-size: 14px;
  color: #777;
}
.edit-color {
  color: #333;
}
</style>

文章参考: https://blog.csdn.net/qq_40601005/article/details/131376086

你可能感兴趣的:(javascript,vue.js,前端)