基于Element-UI日历组件的待办事项例子

想实现一个日历提醒待办事项的功能,主要实现的功能是:

  • 日历上展示是否有待办的事情,如果有则为红色对勾,如果全部是已完成则用绿色对勾,没有事项时候则没有任何标识
  • 日历组件上侧有展开待办的列表功能(以Table形式展现)
    主要涉及的组件有
  • todoCellCheck.vue(用来检查每个日期是否有待办且是否全部完成)
  • todoItem.vue(点击日期时,弹出事项的列表)
  • todoItemTable.vue(通过折叠功能,展示Table形式的待办)
    测试数据中,Mock返回待办事项的数组,例如以下数据:
/**
 * abstract:概要
 * detail:明细
 * status:
 * 0 已办
 * 1 待办
 * 999 最大状态
 */
const todoThings = [
  {
    date: "2020-04-14",
    abstract: "王小虎1",
    detail: "上海市普陀区金沙江路 1518 弄",
    status: 1
  },
  {
    date: "2020-04-14",
    abstract: "王小虎2",
    detail: "上海市普陀区金沙江路 1518 弄",
    status: 0
  }]

业务相关的内容在src下新建bear,配置相关的modules扫描,并且加入到store中src>bear>index.js如下:

const modulesFiles = require.context("./modules", true, /\.js$/);

const bearmodules = modulesFiles.keys().reduce((modules, modulePath) => {
  const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, "$1");
  const value = modulesFiles(modulePath);
  modules[moduleName] = value.default;
  return modules;
}, {});

export default bearmodules;

在store的index.js中导入bearmodules。业务代码的modules在src>bear>modules>todoThings.js如下:

import { getTodoThingsByDate } from "@/api/todoThings/todoThings";

const actions = {
  getTodoThingsByDate(context, { beginDate, endDate }) {
    return new Promise((resolve, reject) => {
      getTodoThingsByDate(beginDate, endDate)
        .then(response => {
          const { data } = response;
          const resp = { code: 200, message: "Success", data: data };
          resolve(resp);
        })
        .catch(error => {
          reject(error);
        });
    });
  }
};

export default {
  namespaced: true,
  actions
};

在src>views下新建todothings目录,待办日历的index.vue如下:

<template>
  <el-row>
    <el-row>
      <el-button type="primary" :icon="collapseListIcon" @click="collapseList">
        {{ collapseListTitel }}
      </el-button>
    </el-row>
    <el-row>
      <el-col :span="calendarSpan">
        <div class="grid-content bg-purple">
          <el-calendar v-model="calendarValue">
            <template v-slot:dateCell="{ date, data }">
              <todoItem
                v-if="data.isSelected"
                :itemsDataGroupByDate="todoDataGroupByDate"
                :cellDate="data.day"
              >
              </todoItem>
              <!-- 初始化标记是否有事情要办 -->
              <todoCellCheck
                :itemsDataGroupByDate="todoDataGroupByDate"
                :cellDate="data.day"
              ></todoCellCheck>
              <p :class="data.isSelected ? 'is-selected' : ''">
                {{
                  data.day
                    .split("-")
                    .slice(1)
                    .join("-")
                }}
              </p>
            </template>
          </el-calendar>
        </div>
      </el-col>
      <el-col :span="todoItemSpan" v-if="isCollapseList">
        <todoItemTable :tableData="todoItemThings"></todoItemTable>
      </el-col>
    </el-row>
  </el-row>
</template>

<script>
import todoItem from "./components/todoItem";
import todoItemTable from "./components/todoItemTable";
import todoCellCheck from "./components/todoCellCheck";
import { jsonArraysGroupByValue } from "@/utils/jsonUtils.js";
import { prevMonthFirstDate, nextMonthLastDate } from "@/utils/date";

export default {
  created() {
    this.initTodoThings();
  },

  data() {
    return {
      /**
       * calendarSpan 日历宽度
       * todoItemSpan 右侧列表宽度
       * isCollapseList 右侧折叠
       * cellDate 选中单元格的日期
       * cellData 选中单元格的数据
       * cellItemThings 选中单元格弹出层的待办事项
       * todoItemThings 当前月及前后各一月的事项
       * calendarValue 日历当前月
       * ---------------
       * todoDataGroupByDate 按日期分组的待办事项
       * ---------------
       *
       */
      calendarSpan: 12,
      todoItemSpan: 12,
      isCollapseList: true,
      cellDate: null,
      cellData: null,
      collapseListTitel: "收起列表",
      collapseListIcon: "el-icon-arrow-left",
      cellItemThings: null,
      // calendarData: null,
      calendarValue: new Date(),
      todoItemThings: null,
      todoDataGroupByDate: null,
      contextmenuVisible: false,
      top: 0,
      left: 0,
      editFormVisible: false
    };
  },
  components: { todoItem, todoItemTable, todoCellCheck },
  watch: {
    calendarValue() {
      this.initTodoThings();
    }
  },
  methods: {
    //查询选中日期及前后各一个月的todo
    initTodoThings() {
      const beginDate = prevMonthFirstDate(this.calendarValue);
      const endDate = nextMonthLastDate(this.calendarValue);
      this.$store
        .dispatch("todoThings/getTodoThingsByDate", {
          beginDate: beginDate,
          endDate: endDate
        })
        .then(response => {
          if (response.code === 200) {
            this.todoItemThings = response.data;
            this.todoDataGroupByDate = jsonArraysGroupByValue(
              this.todoItemThings,
              "date"
            );
          }
        });
    },
    collapseList() {
      if (this.isCollapseList) {
        this.calendarSpan = 24;
        this.todoItemSpan = 0;
      } else {
        this.calendarSpan = 12;
        this.todoItemSpan = 12;
        this.cellDate = null;
        this.cellData = null;
      }
      this.isCollapseList = !this.isCollapseList;
      this.collapseListTitel = !this.isCollapseList ? "展开列表" : "收起列表";
      this.collapseListIcon = !this.isCollapseList
        ? "el-icon-arrow-right el-icon--right"
        : "el-icon-arrow-left";
    }
  }
};
</script>

<style lang="scss" scoped>
.is-selected {
  color: #1989fa;
}
</style>

日历组件在初始化时查询相应的待办,并且将所有待办数据按日期进行分组,同时布局方面默认展开右侧的Table

作为检查日历中日期是否有待办,使用了todoCellCheck.vue组件,思路是先将所有待办事项按日期分组,之后和加载的日期想对比,根据分组内的status属性求和作为结果,status和为0则说明所有事项均以完成。代码如下:

<script>
export default {
  name: "todoCellCheck",
  functional: true,
  props: {
    itemsDataGroupByDate: {
      type: Object,
      default: null
    },
    cellDate: {
      type: String,
      default: ""
    }
  },
  render(h, context) {
    const { itemsDataGroupByDate, cellDate } = context.props;
    const vnodes = [];
    let status = 999;
    if (itemsDataGroupByDate !== null) {
      Object.keys(itemsDataGroupByDate).forEach(function(category) {
        if (category === cellDate) {
          status = itemsDataGroupByDate[category].reduce(
            (prev, currentValue) => {
              return prev + currentValue.status;
            },
            0
          );
          status === 0 && status !== 999
            ? // ? vnodes.push(<svg-icon icon-class="greenmark" />)
              vnodes.push("✔️")
            : vnodes.push(<svg-icon icon-class="redmark" />);
        }
      });
    }
    return vnodes;
  }
};
</script>

todoItem.vue组件绑定实现当点击日期时,弹出一个页面提示当前日期的待办事项。代码如下:

<template>
  <div class="todocell">
    <slot name="todoItems" :itemThings="cellItemThings"></slot>
    <el-popover placement="right" width="800" trigger="click" v-model="visible">
      <el-table :data="cellItemThings" :row-class-name="tableRowClassName">
        <el-table-column
          width="150"
          property="date"
          label="日期"
        ></el-table-column>
        <el-table-column
          width="100"
          property="abstract"
          label="概要"
        ></el-table-column>
        <el-table-column
          width="300"
          property="detail"
          label="明细"
        ></el-table-column>

        <el-table-column label="状态" width="100">
          <template slot-scope="scope">
            <i class="el-icon-time"></i>
            <span style="margin-left: 10px">{{
              scope.row.status === 0 ? "已完成" : "待完成"
            }}</span>
          </template>
        </el-table-column>
      </el-table>
    </el-popover>
  </div>
</template>

<script>
export default {
  props: {
    itemsDataGroupByDate: {
      type: Object,
      default: null
    },
    cellDate: {
      type: String,
      default: ""
    }
  },
  created() {
    this.initCellItemThings();
  },
  data() {
    return {
      visible: false,
      cellItemThings: null
    };
  },
  methods: {
    initCellItemThings() {
      if (this.itemsDataGroupByDate !== null) {
        this.cellItemThings = this.itemsDataGroupByDate[this.cellDate];
        if (
          this.cellItemThings !== null &&
          typeof this.cellItemThings !== "undefined"
        ) {
          this.visible = true;
        }
      }
    },
    tableRowClassName({ row }) {
      if (row.status === 0) {
        return "success-row";
      } else {
        return "warning-row";
      }
    }
  }
};
</script>
<style scoped>
.todocell {
  color: #1989fa;
}
.el-table .warning-row {
  background: oldlace;
}

.el-table .success-row {
  background: #f0f9eb;
}
</style>

目前展示效果如下截图

样式比较难弄,准备修改成vue-element-admin的Table样式

posted on 2020-04-29 14:58  学业未成  阅读(3845)  评论(2编辑  收藏  举报