基于轻服务开发的工作日历

228 阅读4分钟

效果展示

账号密码都是demo

轻服务是什么

轻服务提供开箱即用的云服务和多终端可用的 Web IDE,让开发者无需关心服务器搭建、数据库部署、环境配置和线上运维等繁琐之事,只需专注于产品开发本身。 参考链接

对于我这种后端菜鸟来说,可以减轻非常大的负担(现在免费试用哦,快来白嫖)。

工作日历是什么

  1. 首先最基本的是日历。
  2. 然后就是能够插入当天的工作计划。

效果截图

在本项目中所使用的技术栈

  1. Vue3(Web开发框架
  2. Vue-router4(实现路由功能,简单点就是切换页面
  3. Element Plus(懒癌福音,一套完整的组件库

需要解决的几个问题

1.日历功能

首先我们解决显示日历的问题,这里借鉴了日历Demo的参考链接

基本思路

  1. 首先获取当前时间,包括年、月、日。
  2. 得到日历中的第一天。
  3. 日历一共展示的天数。
  4. 使用循环,渲染出每一天。
// 1.获取当前时间
const curDate = new Date()
const year = curDate.getFullYear() // 年
const month = curDate.getMonth() // 月
const day = curDate.getDate() // 日
// 2. 获取日历中的第一天
// 这里举个例子,
// 假如12月1号是周三,那么日历中的第一天是11月28号。(参考上图)
// 计作开始时间startTime。

const getStartTime = (year, month) => {
  // 获取当月第一天
  let curMonthFirst = new Date(year, month, 1);
  let weekDay = curMonthFirst.getDay();
  return curMonthFirst - weekDay * 24 * 60 * 60 * 1000;
};

// 3.日历一共展示的天数
// (下一个月1号 - 这个月1号) / 一天的时间 = 这个月的天数
// 日历有时展示6周,有时展示5周

const getDayNum = (year, month) => {
  // 获取当月第一天
  let curMonthFirst = new Date(year, month, 1);
  let nextMonthFirst = new Date(year, month + 1, 1);
  let curTotalDays = (nextMonthFirst - curMonthFirst) / (24 * 60 * 60 * 1000);
  // 当月第一天是周几
  let weekDay = curMonthFirst.getDay();
  if (36 - curTotalDays <= weekDay) {
    return 42;
  } else {
    return 35;
  }
};
// 4.使用循环,渲染出每一天
// 获取阳历可以使用new Date()
// 获取农历参考:

  computed:{
    monthDayNum() {
      return getDayNum(this.year, this.month);
    },
    
    visibleCalendar() {
      const calendatArr = [];
      const startTime = getStartTime(this.year, this.month);
      const monthDayNum = this.monthDayNum;
      
      for (let i = 0; i < monthDayNum; i++) {
        // 阳历
        const date = new Date(startTime + i * 24 * 60 * 60 * 1000);
        const year = date.getFullYear();
        const month = date.getMonth();
        const day = date.getDate(); //这个月第几号
        // 农历
        const lunar = calendar.solar2lunar(year, month + 1, day);
        const IDayCn = lunar.IDayCn; //日
        const IMonthCn = lunar.IMonthCn; //月
        
        calendatArr.push({
          date,
          year,
          month,
          day,
          IDayCn, 
          IMonthCn, 
          contents: [], // 当日计划
          index: i, 
        });
      }
      return calendatArr;
    },
  }
<temple>
      <ul class="calendar-view">
        <li
          v-for="(item, index) in visibleCalendar"
          :key="index"
          class="date-view"
          :class="[
            { todayBg: isCurrentDay(item.day) }, //判断是否是当前
            { 'month-class': !isCurrentMonth(item.month) }, // 判断是否是当月
          ]"
          @click="handleClickDay(item)"
        >
        
        //...
        //这里可以渲染每一天的样式
        
        </li>
      </ul>
</temple>

显示农历的问题

参考了 github.com/jjonline/ca…

2. 切换月份

通过修改数据中的year、month的值来实现

  methods:{
    // 上一个月
    handlePrevMonth() {
      this.contentsDays = {};
      let prevMonth = new Date(this.year, this.month, 1);
      prevMonth.setMonth(prevMonth.getMonth() - 1);
      
      this.year = new Date(prevMonth).getFullYear();
      this.month = new Date(prevMonth).getMonth();
    },
    
    // 下一个月
    handleNextMonth() {
      this.contentsDays = {};
      let nextMonth = new Date(this.year, this.month, 1);
      nextMonth.setMonth(nextMonth.getMonth() + 1);
      
      this.year = new Date(nextMonth).getFullYear();
      this.month = new Date(nextMonth).getMonth();
    },
    
    // 回到今天
    handleToday() {
      this.year = new Date().getFullYear();
      this.month = new Date().getMonth();
    },
  }

3. 添加/删除工作内容

首先用v-model="addContent" 来双向绑定输入框的内容,如下图的展示效果。 image.png

添加内容: content是需要添加的内容,根据年月日调用 添加接口 删除内容: 获取删除的contentId,根据年月日调用 删除接口

  methods:{
    //添加内容
    handleAddContent() {
      const activateDay = this.visibleCalendar[this.activateIndex];
      const { year, month, day } = activateDay;
     
      const content = this.addContent;
      this.addContent = "";
      this.addLoading = true;
      
      // 调用API
      inspirecloud
        .run("addRecord", { year, month, content, day: day - 1 })
        .then((res) => {
          if (res.success) {
            this.getContentsByMonth();
            this.addLoading = false;
            ElMessage({
              message: "添加成功",
              type: "success",
            });
          } else {
            this.addLoading = false;
            ElMessage({
              message: "添加失败",
              type: "error",
            });
          }
        });
    },
    
    // 删除内容
    handleDelContent(index) {
      const activateDay = this.visibleCalendar[this.activateIndex];
      const { year, month } = activateDay;

      const contentId = this.contentIdsDays[this.activateIndex][index];
      this.addLoading = true;

      // 调用API
      inspirecloud
        .run("deleteRecord", { year, month, contentId })
        .then((res) => {
          if (res) {
            this.addLoading = false;
            this.getContentsByMonth();
            ElMessage({
              message: "删除成功",
              type: "success",
            });
          } else {
            ElMessage({
              message: "删除失败",
              type: "error",
            });
            this.addLoading = true;
          }
        });
    },
  }
  
  

渲染出当天全部工作计划,这个结合小节1中的<template>模块。indexvisibleCalendar 的下标。

      <template>
        <!-- 渲染某一天的全部计划 -->
          <ul class="date-todoList">
            <span
              v-for="(content, index) in contentsDays[index]"
              :key="index"
              >{{ content }}</span
            >
          </ul>
      </template>

4. 用户注册、登录问题

在轻服务中的云函数就是对应一个API,具体可以参考云函数nodejs版

同时轻服务提供了完整的用户系统API,具体可以参考用户系统教程

这里展示登录和注册的云函数

// loginByUsername.js
module.exports = async function (params, context) {
  const { username, password } = params;

  try {
    const userInfo = await inspirecloud.user.login(
      context, // 注意,调用所有 inspirecloud.user 相关接口时,都需要传入云函数中的 context
      username,
      password
    );

    return {
      success: true,
      userInfo,
    };
  } catch (e) {
    return {
      success: false,
      message: e.message,
    };
  }
};

// createUser.js
module.exports = async function (params, context) {
  // 从 params 中获取账号密码等参数
  const { username, password } = params;

  try {
    const userInfo = await inspirecloud.user.register(
      context, // 注意,调用所有 inspirecloud.user 相关接口时,都需要传入云函数中的 context
      username,
      password
    );

    return {
      success: true,
      userInfo,
    };
  } catch (e) {
    return {
      success: false,
      message: e.message,
    };
  }
};

在前端项目中调用API

首先下载好SDK,

npm i @byteinspire/js-sdk 

然后在页面中引用

import InspireCloud from "@byteinspire/js-sdk";
const serviceId = XXX; // 你的serviceId
const inspirecloud = new InspireCloud({ serviceId });

// 调用API
//inspirecloud.run('云函数的文件名',{参数}).then(res => {
//  console.log(res)
//}

inspirecloud
  .run("loginByUsername", { username, password })
  .then((res) => {
    if (res.success) {
      this.formLabelAlign = {};
      ElMessage({
        message: "登录成功",
        center: true,
        type: "success",
      });
      this.$router.push("/home/calendar");
    } else {
      ElMessage({
        message: res.message,
        center: true,
        type: "error",
      });
      this.isLogining = false;
    }
  })
  .catch((error) => {
    console.log(error);
  });