vue-待辦日歷和Table


基於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樣式


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM