Electron+Vue3 MAC 版日历开发记录(23)——事件完整功能完成

931 阅读3分钟

这是我参与更文挑战的第23天,活动详情查看: 更文挑战

今天本来想着利用 Github Action 打包的 Dmg 文件发给伙伴们安装看看效果。但发现他们那边安装后,Event 事件和天气预报获取不了。

原来问题在于我没把 env 放到代码库中,导致没法获取 VITE 变量:

VITE_APP_WIDTH=700
VITE_APP_HEIGHT=600
VITE_WEATHER_API=<your-weather-api>
VITE_NOtion_VERSION=2021-05-13
VITE_NOTION_DATABASE_API=https://api.notion.com/v1/databases/
VITE_NOTION_PAGE_API=https://api.notion.com/v1/pages

然后也发现我把 notion 的 apikey 和数据库 id 也放在了 env 里,感觉不是很科学,而且大家都因人而异,所以今天接着把 env 放到代码库的同时,把事件也放在 Setting 里做配置,每个人根据自己的情况,填写 apikey 和 database id。

具体看看效果:

创建 Setting Tab 页

这个就很简单了:

      <n-tab-pane name="eventSetting" tab="事件设置">
        <n-form>
          <n-form-item-row label="NOTION_API_KEY">
            <n-input
              v-model:value="notion_api_key"
            />
          </n-form-item-row>
          <n-form-item-row label="NOTION_DATABASE_ID">
            <n-input
              v-model:value="notion_database_id"
              :minlength="32"
              :maxlength="32"
            />
          </n-form-item-row>
        </n-form>
        <n-button type="primary" block @click="updateNotion">更新</n-button>
        <n-divider dashed />
        <n-button
        type="info"
        :disabled="createNotionDisabled"
        block
        @click="$emit('goCreateEventView')">
          创建新事件
        </n-button>
      </n-tab-pane>

这里有几个需要说明的:

  1. notion_api_key 和 notion_database_id 两个 Model 需要保存在 Vuex 状态中,便于多处调用。
  2. 我把「创建事件」的入口也放在这里了,简单根据是否填入两个参数来判定,是否可以有「创建事件」功能。(这个未来会做优化)
  3. 只要两个参数变化了,触发「更新」事件,我们都可以重新去获取自己存储在 Notion 里的事件列表。

就因为 notion_api_key 和 notion_database_id 在 Vuex 中,而我们创建的 EventService 独立出一个 “项目”,所以没法借助 Vuex 的逻辑功能,只能改为传参的形式:

'use strict';
import axios from 'axios';
import wrapper from 'axios-cache-plugin';

export default class EventService {
  notion_api_key: string;
  notion_database_id: string;
  constructor(notion_api_key: string, notion_database_id: string) {
    this.notion_api_key = notion_api_key;
    this.notion_database_id = notion_database_id;
  }

  /**
   * 提交title和start、end 到 Notion API
   */
  async postEvent(
    title: string,
    start: Date,
    end: Date,
    ) {
      const http = wrapper(axios, {
        maxCacheSize: 15,
      });
      const res = await http({
        url: import.meta.env.VITE_NOTION_PAGE_API,
        method: 'post',
        headers: this.getHeaders(),
        data: {
          'parent': { 'type': 'database_id', 'database_id': this.notion_database_id },
          'properties': this.getParams(title, start, end),
        },
      });

      return res;
  }

  /**
   * 更新 title 或者 start、end 到 Notion API
   */
  async patchEvent(
    id: string,
    title: string,
    start: Date,
    end: Date,
    ) {
      const http = wrapper(axios, {
        maxCacheSize: 15,
      });
      const res = await http({
        url: import.meta.env.VITE_NOTION_PAGE_API + '/' + id,
        method: 'patch',
        headers: this.getHeaders(),
        data: {
          'properties': this.getParams(title, start, end),
        },
      });

      return res;
  }

  async getEvents() {
    const http = wrapper(axios, {
      maxCacheSize: 15,
      ttl: 60000, //ms
    });
    const res = await http({
      url: import.meta.env.VITE_NOTION_DATABASE_API + this.notion_database_id + '/query',
      method: 'post',
      headers: this.getHeaders(),
    });

    return this.list2Events(res.data.results);
  }

  list2Events(results: []) {
    const events = results.map((element: any) => {
      return {
        'id': element.id,
        'title': element.properties?.title?.rich_text[0].plain_text,
        'start': element.properties?.start?.date.start,
        'end': element.properties?.end?.date.start,
      };
    });

    return events;
  }

  // 增加 set
  setApiKey(notion_api_key: string): this {
    if (notion_api_key === '') {
      return this;
    }
    this.notion_api_key = notion_api_key;
    return this;
  }

  setDatabaseId(notion_database_id: string): this {
    if (notion_database_id === '') {
      return this;
    }
    this.notion_database_id = notion_database_id;
    return this;
  }

  getHeaders(): any {
    return {
      'Notion-Version': import.meta.env.VITE_NOtion_VERSION,
      'Authorization': 'Bearer '+ this.notion_api_key,
    };
  }

  getParams(
    title: string,
    start: Date,
    end: Date,
  ): any {
    return {
      'title': {
        'type': 'rich_text',
        'rich_text': [{
          'type': 'text',
          'text': { 'content': title },
        }],
      },
      'start': {
        'type': 'date',
        'date': { 'start': start },
      },
      'end': {
        'type': 'date',
        'date': { 'start': end },
      },
    };
  }
}

这里未来还可以继续优化。

增加 Store 项

同样的,在 Vuex 中增加 Notion 参数:

// store/index.ts

export interface FNotion {
  api_key: string, // api key
  database_id: string,  // 数据库 id
}

export interface State {
  notion: FNotion,
}

export const store = createStore<State>({
  state: {
    notion: {
      api_key: '******',
      database_id: '******',
    } as FNotion,
    focusTime: 40,
  },
  mutations: {
    changeNotion(state, notion) {
      state.notion = {
        api_key: notion.api_key,
        database_id: notion.database_id,
      } as FNotion;
    },
  },
  actions: {
    changeNotion({ commit }) {
      commit('changeNotion');
    },
  },
  plugins: [dataState],
});

小结

把「创建事件」移入 Setting 中了,那我们对外的 Menu 主要就保留「设置」和「退出应用」两个就好:

或者未来增加一些其他操作。

每天改一点,让代码也严谨一些。这段时间比较忙,能坚持下来已经不容易了。未完待续!

代码已同步到 Github 上了,也把 env 放进去了,可以之际打包成 dmg 安装包,有需要的评论留言我~