calendar-records-api-guide.md 34 KB

日历记录API接口 - 前端开发指南

版本信息

  • 版本: v1.0.0
  • 更新日期: 2024-01-15
  • 适用范围: DataOps平台日历记录功能

概述

本文档提供日历记录相关API接口的详细说明,包括保存日历记录和获取日历记录功能。这些接口用于管理用户的月度日历内容,支持插入新记录和更新现有记录。

重要说明

  1. 认证方式: 使用微信用户的 openid 作为用户标识
  2. 数据格式: 所有请求和响应均使用 JSON 格式
  3. 字符编码: UTF-8
  4. 时区: 所有时间字段均为东八区时间 (UTC+8)
  5. 月份格式: 统一使用 YYYY-MM 格式(如:2024-01)

API接口列表

接口名称 请求方法 路径 功能描述
保存日历记录 POST /api/parse/save-calendar-record 保存或更新用户日历记录
获取日历记录 GET /api/parse/get-calendar-record 查询用户指定月份的日历记录

1. 保存日历记录接口

基本信息

  • 接口路径: /api/parse/save-calendar-record
  • 请求方法: POST
  • Content-Type: application/json
  • 功能: 保存用户的日历内容记录,如果记录已存在则更新,不存在则创建新记录

请求参数

请求头 (Headers)

Content-Type: application/json

请求体 (Request Body)

参数名 类型 必填 说明 示例值
openid string 微信用户openid,28位字符串 "wx_openid_abcd1234567890123456"
month_key string 月份标识,格式为YYYY-MM "2024-01"
calendar_content array 日历内容,JSON数组格式 见下方示例

calendar_content 数组元素结构

字段名 类型 必填 说明 示例值
date string 日期,格式为YYYY-MM-DD "2024-01-01"
events array 事件列表,字符串数组 ["会议", "约会"]
notes string 备注信息 "重要日程"

请求示例

JavaScript (Fetch API)

async function saveCalendarRecord(openid, monthKey, calendarContent) {
    const url = '/api/parse/save-calendar-record';
    
    const requestData = {
        openid: openid,
        month_key: monthKey,
        calendar_content: calendarContent
    };
    
    try {
        const response = await fetch(url, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify(requestData)
        });
        
        const result = await response.json();
        
        if (result.return_code === 200) {
            console.log('保存成功:', result.result);
            return { success: true, data: result.result };
        } else {
            console.error('保存失败:', result.error);
            return { success: false, error: result.error };
        }
    } catch (error) {
        console.error('请求异常:', error);
        return { success: false, error: '网络请求失败' };
    }
}

// 使用示例
const calendarData = [
    {
        date: "2024-01-01",
        events: ["元旦节"],
        notes: "新年快乐"
    },
    {
        date: "2024-01-15",
        events: ["会议", "约会"],
        notes: "重要日程"
    }
];

saveCalendarRecord("wx_openid_abcd1234567890123456", "2024-01", calendarData);

jQuery Ajax

function saveCalendarRecord(openid, monthKey, calendarContent) {
    $.ajax({
        url: '/api/parse/save-calendar-record',
        type: 'POST',
        contentType: 'application/json',
        data: JSON.stringify({
            openid: openid,
            month_key: monthKey,
            calendar_content: calendarContent
        }),
        success: function(result) {
            if (result.return_code === 200) {
                console.log('保存成功:', result.result);
            } else {
                console.error('保存失败:', result.error);
            }
        },
        error: function(xhr, status, error) {
            console.error('请求失败:', error);
        }
    });
}

微信小程序

// 微信小程序保存日历记录
function saveCalendarRecord(openid, monthKey, calendarContent) {
    wx.request({
        url: 'https://your-domain.com/api/parse/save-calendar-record',
        method: 'POST',
        header: {
            'content-type': 'application/json'
        },
        data: {
            openid: openid,
            month_key: monthKey,
            calendar_content: calendarContent
        },
        success: function(res) {
            if (res.data.return_code === 200) {
                console.log('保存成功:', res.data.result);
                wx.showToast({
                    title: '保存成功',
                    icon: 'success'
                });
            } else {
                console.error('保存失败:', res.data.error);
                wx.showToast({
                    title: '保存失败',
                    icon: 'error'
                });
            }
        },
        fail: function(error) {
            console.error('请求失败:', error);
            wx.showToast({
                title: '网络错误',
                icon: 'error'
            });
        }
    });
}

响应结果

成功响应 (HTTP 200)

{
    "reason": "successed",
    "return_code": 200,
    "result": {
        "id": 1,
        "openid": "wx_openid_abcd1234567890123456",
        "month_key": "2024-01",
        "calendar_content": [
            {
                "date": "2024-01-01",
                "events": ["元旦节"],
                "notes": "新年快乐"
            },
            {
                "date": "2024-01-15",
                "events": ["会议", "约会"],
                "notes": "重要日程"
            }
        ],
        "created_at": "2024-01-15T10:30:00+08:00",
        "updated_at": "2024-01-15T14:30:00+08:00"
    }
}

错误响应

{
    "reason": "failed",
    "return_code": 400,
    "result": null,
    "error": "缺少必填参数: openid"
}

返回码说明

返回码 说明 处理建议
200 成功 继续后续操作
400 请求参数错误 检查请求参数格式和必填项
500 服务器内部错误 联系技术支持或稍后重试

2. 获取日历记录接口

基本信息

  • 接口路径: /api/parse/get-calendar-record
  • 请求方法: GET
  • 功能: 查询用户指定月份的日历记录

请求参数

查询参数 (Query Parameters)

参数名 类型 必填 说明 示例值
openid string 微信用户openid wx_openid_abcd1234567890123456
month_key string 月份标识,格式为YYYY-MM 2024-01

请求示例

JavaScript (Fetch API)

async function getCalendarRecord(openid, monthKey) {
    const url = `/api/parse/get-calendar-record?openid=${encodeURIComponent(openid)}&month_key=${encodeURIComponent(monthKey)}`;
    
    try {
        const response = await fetch(url, {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
            }
        });
        
        const result = await response.json();
        
        if (result.return_code === 200) {
            console.log('查询成功:', result.result);
            return { success: true, data: result.result };
        } else {
            console.error('查询失败:', result.error);
            return { success: false, error: result.error };
        }
    } catch (error) {
        console.error('请求异常:', error);
        return { success: false, error: '网络请求失败' };
    }
}

// 使用示例
getCalendarRecord("wx_openid_abcd1234567890123456", "2024-01")
    .then(result => {
        if (result.success) {
            // 处理成功结果
            const calendarData = result.data;
            if (calendarData.id) {
                console.log('找到日历记录:', calendarData.calendar_content);
            } else {
                console.log('该月份暂无记录');
            }
        } else {
            // 处理错误
            console.error('获取失败:', result.error);
        }
    });

jQuery Ajax

function getCalendarRecord(openid, monthKey) {
    $.ajax({
        url: '/api/parse/get-calendar-record',
        type: 'GET',
        data: {
            openid: openid,
            month_key: monthKey
        },
        success: function(result) {
            if (result.return_code === 200) {
                console.log('查询成功:', result.result);
                if (result.result.id) {
                    // 有记录
                    displayCalendarData(result.result.calendar_content);
                } else {
                    // 无记录
                    displayEmptyCalendar();
                }
            } else {
                console.error('查询失败:', result.error);
            }
        },
        error: function(xhr, status, error) {
            console.error('请求失败:', error);
        }
    });
}

微信小程序

// 微信小程序获取日历记录
function getCalendarRecord(openid, monthKey) {
    wx.request({
        url: 'https://your-domain.com/api/parse/get-calendar-record',
        method: 'GET',
        data: {
            openid: openid,
            month_key: monthKey
        },
        success: function(res) {
            if (res.data.return_code === 200) {
                console.log('查询成功:', res.data.result);
                const calendarData = res.data.result;
                
                if (calendarData.id) {
                    // 有记录,显示日历内容
                    this.setData({
                        calendarContent: calendarData.calendar_content,
                        hasRecord: true
                    });
                } else {
                    // 无记录,显示空日历
                    this.setData({
                        calendarContent: [],
                        hasRecord: false
                    });
                }
            } else {
                console.error('查询失败:', res.data.error);
                wx.showToast({
                    title: '查询失败',
                    icon: 'error'
                });
            }
        },
        fail: function(error) {
            console.error('请求失败:', error);
            wx.showToast({
                title: '网络错误',
                icon: 'error'
            });
        }
    });
}

响应结果

有记录时的成功响应 (HTTP 200)

{
    "reason": "successed",
    "return_code": 200,
    "result": {
        "id": 1,
        "openid": "wx_openid_abcd1234567890123456",
        "month_key": "2024-01",
        "calendar_content": [
            {
                "date": "2024-01-01",
                "events": ["元旦节"],
                "notes": "新年快乐"
            },
            {
                "date": "2024-01-15",
                "events": ["会议", "约会"],
                "notes": "重要日程"
            }
        ],
        "created_at": "2024-01-15T10:30:00+08:00",
        "updated_at": "2024-01-15T14:30:00+08:00"
    }
}

无记录时的成功响应 (HTTP 200)

{
    "reason": "successed",
    "return_code": 200,
    "result": {
        "id": null,
        "openid": "wx_openid_abcd1234567890123456",
        "month_key": "2024-01",
        "calendar_content": [],
        "created_at": null,
        "updated_at": null
    }
}

错误响应

{
    "reason": "failed",
    "return_code": 400,
    "result": null,
    "error": "缺少必填参数: month_key"
}

前端集成指南

1. 完整的日历管理类

class CalendarRecordManager {
    constructor(baseUrl = '') {
        this.baseUrl = baseUrl;
    }
    
    /**
     * 保存日历记录
     * @param {string} openid - 微信用户openid
     * @param {string} monthKey - 月份标识 (YYYY-MM)
     * @param {Array} calendarContent - 日历内容数组
     * @returns {Promise<Object>} 返回操作结果
     */
    async saveRecord(openid, monthKey, calendarContent) {
        const url = `${this.baseUrl}/api/parse/save-calendar-record`;
        
        try {
            const response = await fetch(url, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    openid: openid,
                    month_key: monthKey,
                    calendar_content: calendarContent
                })
            });
            
            const result = await response.json();
            return {
                success: result.return_code === 200,
                data: result.result,
                error: result.error,
                code: result.return_code
            };
        } catch (error) {
            return {
                success: false,
                data: null,
                error: error.message,
                code: -1
            };
        }
    }
    
    /**
     * 获取日历记录
     * @param {string} openid - 微信用户openid
     * @param {string} monthKey - 月份标识 (YYYY-MM)
     * @returns {Promise<Object>} 返回查询结果
     */
    async getRecord(openid, monthKey) {
        const url = `${this.baseUrl}/api/parse/get-calendar-record?openid=${encodeURIComponent(openid)}&month_key=${encodeURIComponent(monthKey)}`;
        
        try {
            const response = await fetch(url, {
                method: 'GET',
                headers: {
                    'Content-Type': 'application/json',
                }
            });
            
            const result = await response.json();
            return {
                success: result.return_code === 200,
                data: result.result,
                error: result.error,
                code: result.return_code,
                hasRecord: result.result && result.result.id !== null
            };
        } catch (error) {
            return {
                success: false,
                data: null,
                error: error.message,
                code: -1,
                hasRecord: false
            };
        }
    }
    
    /**
     * 格式化月份键
     * @param {Date} date - 日期对象
     * @returns {string} 格式化的月份键 (YYYY-MM)
     */
    formatMonthKey(date = new Date()) {
        const year = date.getFullYear();
        const month = String(date.getMonth() + 1).padStart(2, '0');
        return `${year}-${month}`;
    }
    
    /**
     * 验证月份键格式
     * @param {string} monthKey - 月份键
     * @returns {boolean} 是否有效
     */
    validateMonthKey(monthKey) {
        const pattern = /^\d{4}-\d{2}$/;
        return pattern.test(monthKey);
    }
    
    /**
     * 验证openid格式
     * @param {string} openid - 微信openid
     * @returns {boolean} 是否有效
     */
    validateOpenid(openid) {
        return openid && typeof openid === 'string' && openid.length === 28;
    }
}

// 使用示例
const calendarManager = new CalendarRecordManager();

// 保存记录
async function saveCurrentMonthRecord(openid, events) {
    const monthKey = calendarManager.formatMonthKey(new Date());
    const result = await calendarManager.saveRecord(openid, monthKey, events);
    
    if (result.success) {
        console.log('保存成功:', result.data);
    } else {
        console.error('保存失败:', result.error);
    }
}

// 获取记录
async function loadCurrentMonthRecord(openid) {
    const monthKey = calendarManager.formatMonthKey(new Date());
    const result = await calendarManager.getRecord(openid, monthKey);
    
    if (result.success) {
        if (result.hasRecord) {
            console.log('找到记录:', result.data.calendar_content);
            return result.data.calendar_content;
        } else {
            console.log('暂无记录');
            return [];
        }
    } else {
        console.error('获取失败:', result.error);
        return null;
    }
}

2. Vue.js 集成示例

<template>
  <div class="calendar-container">
    <h2>{{ currentMonthText }}日历</h2>
    
    <!-- 日历内容显示 -->
    <div v-if="hasRecord" class="calendar-content">
      <div v-for="item in calendarContent" :key="item.date" class="calendar-item">
        <div class="date">{{ item.date }}</div>
        <div class="events">
          <span v-for="event in item.events" :key="event" class="event-tag">
            {{ event }}
          </span>
        </div>
        <div class="notes">{{ item.notes }}</div>
      </div>
    </div>
    
    <!-- 无记录提示 -->
    <div v-else class="no-record">
      <p>本月暂无日历记录</p>
    </div>
    
    <!-- 操作按钮 -->
    <div class="actions">
      <button @click="loadRecord" :disabled="loading">刷新</button>
      <button @click="saveRecord" :disabled="loading">保存</button>
    </div>
  </div>
</template>

<script>
export default {
  name: 'CalendarRecord',
  data() {
    return {
      openid: 'wx_openid_abcd1234567890123456', // 从登录状态获取
      currentMonth: new Date(),
      calendarContent: [],
      hasRecord: false,
      loading: false
    };
  },
  computed: {
    currentMonthText() {
      return `${this.currentMonth.getFullYear()}年${this.currentMonth.getMonth() + 1}月`;
    },
    monthKey() {
      const year = this.currentMonth.getFullYear();
      const month = String(this.currentMonth.getMonth() + 1).padStart(2, '0');
      return `${year}-${month}`;
    }
  },
  mounted() {
    this.loadRecord();
  },
  methods: {
    async loadRecord() {
      this.loading = true;
      
      try {
        const response = await fetch(`/api/parse/get-calendar-record?openid=${this.openid}&month_key=${this.monthKey}`);
        const result = await response.json();
        
        if (result.return_code === 200) {
          this.hasRecord = result.result.id !== null;
          this.calendarContent = result.result.calendar_content || [];
        } else {
          this.$message.error('获取日历记录失败: ' + result.error);
        }
      } catch (error) {
        this.$message.error('网络请求失败: ' + error.message);
      } finally {
        this.loading = false;
      }
    },
    
    async saveRecord() {
      // 这里应该从表单或编辑器获取要保存的数据
      const dataToSave = [
        {
          date: "2024-01-15",
          events: ["会议", "约会"],
          notes: "重要日程"
        }
      ];
      
      this.loading = true;
      
      try {
        const response = await fetch('/api/parse/save-calendar-record', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            openid: this.openid,
            month_key: this.monthKey,
            calendar_content: dataToSave
          })
        });
        
        const result = await response.json();
        
        if (result.return_code === 200) {
          this.$message.success('保存成功');
          this.loadRecord(); // 重新加载数据
        } else {
          this.$message.error('保存失败: ' + result.error);
        }
      } catch (error) {
        this.$message.error('网络请求失败: ' + error.message);
      } finally {
        this.loading = false;
      }
    }
  }
};
</script>

3. React 集成示例

import React, { useState, useEffect, useCallback } from 'react';

const CalendarRecord = ({ openid }) => {
    const [calendarContent, setCalendarContent] = useState([]);
    const [hasRecord, setHasRecord] = useState(false);
    const [loading, setLoading] = useState(false);
    const [currentMonth, setCurrentMonth] = useState(new Date());
    
    // 格式化月份键
    const formatMonthKey = useCallback((date) => {
        const year = date.getFullYear();
        const month = String(date.getMonth() + 1).padStart(2, '0');
        return `${year}-${month}`;
    }, []);
    
    const monthKey = formatMonthKey(currentMonth);
    
    // 加载日历记录
    const loadRecord = useCallback(async () => {
        setLoading(true);
        
        try {
            const response = await fetch(`/api/parse/get-calendar-record?openid=${openid}&month_key=${monthKey}`);
            const result = await response.json();
            
            if (result.return_code === 200) {
                setHasRecord(result.result.id !== null);
                setCalendarContent(result.result.calendar_content || []);
            } else {
                console.error('获取失败:', result.error);
            }
        } catch (error) {
            console.error('网络错误:', error);
        } finally {
            setLoading(false);
        }
    }, [openid, monthKey]);
    
    // 保存日历记录
    const saveRecord = async (dataToSave) => {
        setLoading(true);
        
        try {
            const response = await fetch('/api/parse/save-calendar-record', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    openid: openid,
                    month_key: monthKey,
                    calendar_content: dataToSave
                })
            });
            
            const result = await response.json();
            
            if (result.return_code === 200) {
                console.log('保存成功');
                loadRecord(); // 重新加载
            } else {
                console.error('保存失败:', result.error);
            }
        } catch (error) {
            console.error('网络错误:', error);
        } finally {
            setLoading(false);
        }
    };
    
    useEffect(() => {
        if (openid) {
            loadRecord();
        }
    }, [openid, loadRecord]);
    
    return (
        <div className="calendar-container">
            <h2>{currentMonth.getFullYear()}年{currentMonth.getMonth() + 1}月日历</h2>
            
            {hasRecord ? (
                <div className="calendar-content">
                    {calendarContent.map((item, index) => (
                        <div key={index} className="calendar-item">
                            <div className="date">{item.date}</div>
                            <div className="events">
                                {item.events?.map((event, idx) => (
                                    <span key={idx} className="event-tag">{event}</span>
                                ))}
                            </div>
                            <div className="notes">{item.notes}</div>
                        </div>
                    ))}
                </div>
            ) : (
                <div className="no-record">
                    <p>本月暂无日历记录</p>
                </div>
            )}
            
            <div className="actions">
                <button onClick={loadRecord} disabled={loading}>
                    {loading ? '加载中...' : '刷新'}
                </button>
            </div>
        </div>
    );
};

export default CalendarRecord;

错误处理指南

常见错误码及处理方案

错误码 错误信息 原因 解决方案
400 请求体不能为空 POST请求未提供请求体 检查请求体格式
400 缺少必填参数: openid 未提供openid参数 确保传递有效的openid
400 缺少必填参数: month_key 未提供month_key参数 确保传递正确格式的月份键
400 缺少必填参数: calendar_content 未提供calendar_content参数 确保传递日历内容数组
400 无效的openid格式 openid格式不正确 检查openid是否为28位字符串
400 无效的月份格式 month_key格式错误 确保使用YYYY-MM格式
500 数据库连接失败 服务器数据库问题 联系技术支持
500 服务器内部错误 其他服务器错误 稍后重试或联系技术支持

错误处理最佳实践

async function handleApiCall(apiFunction) {
    try {
        const result = await apiFunction();
        
        switch (result.code) {
            case 200:
                return { success: true, data: result.data };
                
            case 400:
                // 参数错误,显示具体错误信息
                console.warn('参数错误:', result.error);
                return { success: false, error: result.error, needsRetry: false };
                
            case 500:
                // 服务器错误,可以重试
                console.error('服务器错误:', result.error);
                return { success: false, error: '服务器暂时不可用,请稍后重试', needsRetry: true };
                
            default:
                console.error('未知错误:', result.error);
                return { success: false, error: '操作失败,请重试', needsRetry: true };
        }
    } catch (error) {
        console.error('网络错误:', error);
        return { success: false, error: '网络连接失败,请检查网络', needsRetry: true };
    }
}

// 带重试的API调用
async function apiCallWithRetry(apiFunction, maxRetries = 3) {
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
        const result = await handleApiCall(apiFunction);
        
        if (result.success || !result.needsRetry) {
            return result;
        }
        
        if (attempt < maxRetries) {
            console.log(`第${attempt}次尝试失败,${1000 * attempt}ms后重试...`);
            await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
        }
    }
    
    return { success: false, error: '多次重试失败,请稍后再试' };
}

开发环境配置

环境变量配置

在开发环境中,需要配置以下环境变量:

# .env.development
REACT_APP_API_BASE_URL=http://localhost:5000
VUE_APP_API_BASE_URL=http://localhost:5000

# .env.production  
REACT_APP_API_BASE_URL=https://your-production-domain.com
VUE_APP_API_BASE_URL=https://your-production-domain.com

代理配置

Webpack Dev Server (React/Vue)

// webpack.config.js 或 vue.config.js
module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'http://localhost:5000',
        changeOrigin: true,
        secure: false
      }
    }
  }
};

Create React App

// package.json
{
  "name": "your-app",
  "proxy": "http://localhost:5000",
  // ...
}

测试用例

单元测试示例

// calendar-api.test.js
import { CalendarRecordManager } from './calendar-manager';

describe('CalendarRecordManager', () => {
    let manager;
    const mockOpenid = 'wx_openid_test1234567890123456';
    const mockMonthKey = '2024-01';
    
    beforeEach(() => {
        manager = new CalendarRecordManager();
        // Mock fetch
        global.fetch = jest.fn();
    });
    
    afterEach(() => {
        jest.resetAllMocks();
    });
    
    test('保存日历记录 - 成功', async () => {
        const mockResponse = {
            reason: 'successed',
            return_code: 200,
            result: {
                id: 1,
                openid: mockOpenid,
                month_key: mockMonthKey,
                calendar_content: [
                    {
                        date: '2024-01-01',
                        events: ['测试事件'],
                        notes: '测试备注'
                    }
                ]
            }
        };
        
        fetch.mockResolvedValueOnce({
            json: async () => mockResponse
        });
        
        const result = await manager.saveRecord(mockOpenid, mockMonthKey, [
            {
                date: '2024-01-01',
                events: ['测试事件'],
                notes: '测试备注'
            }
        ]);
        
        expect(result.success).toBe(true);
        expect(result.data.id).toBe(1);
        expect(fetch).toHaveBeenCalledWith(
            '/api/parse/save-calendar-record',
            expect.objectContaining({
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    openid: mockOpenid,
                    month_key: mockMonthKey,
                    calendar_content: [
                        {
                            date: '2024-01-01',
                            events: ['测试事件'],
                            notes: '测试备注'
                        }
                    ]
                })
            })
        );
    });
    
    test('获取日历记录 - 有记录', async () => {
        const mockResponse = {
            reason: 'successed',
            return_code: 200,
            result: {
                id: 1,
                openid: mockOpenid,
                month_key: mockMonthKey,
                calendar_content: [
                    {
                        date: '2024-01-01',
                        events: ['测试事件'],
                        notes: '测试备注'
                    }
                ]
            }
        };
        
        fetch.mockResolvedValueOnce({
            json: async () => mockResponse
        });
        
        const result = await manager.getRecord(mockOpenid, mockMonthKey);
        
        expect(result.success).toBe(true);
        expect(result.hasRecord).toBe(true);
        expect(result.data.calendar_content).toHaveLength(1);
    });
    
    test('获取日历记录 - 无记录', async () => {
        const mockResponse = {
            reason: 'successed',
            return_code: 200,
            result: {
                id: null,
                openid: mockOpenid,
                month_key: mockMonthKey,
                calendar_content: [],
                created_at: null,
                updated_at: null
            }
        };
        
        fetch.mockResolvedValueOnce({
            json: async () => mockResponse
        });
        
        const result = await manager.getRecord(mockOpenid, mockMonthKey);
        
        expect(result.success).toBe(true);
        expect(result.hasRecord).toBe(false);
        expect(result.data.calendar_content).toEqual([]);
    });
    
    test('参数验证 - 无效的openid', async () => {
        const isValid = manager.validateOpenid('invalid_openid');
        expect(isValid).toBe(false);
    });
    
    test('参数验证 - 有效的openid', async () => {
        const isValid = manager.validateOpenid(mockOpenid);
        expect(isValid).toBe(true);
    });
    
    test('月份键格式化', () => {
        const date = new Date('2024-01-15');
        const monthKey = manager.formatMonthKey(date);
        expect(monthKey).toBe('2024-01');
    });
    
    test('月份键验证 - 有效格式', () => {
        expect(manager.validateMonthKey('2024-01')).toBe(true);
        expect(manager.validateMonthKey('2024-12')).toBe(true);
    });
    
    test('月份键验证 - 无效格式', () => {
        expect(manager.validateMonthKey('2024-1')).toBe(false);
        expect(manager.validateMonthKey('24-01')).toBe(false);
        expect(manager.validateMonthKey('2024/01')).toBe(false);
    });
});

性能优化建议

1. 请求优化

  • 使用防抖(debounce)避免频繁保存
  • 实现本地缓存减少重复请求
  • 使用 Loading 状态提升用户体验

2. 数据处理优化

  • 对大量日历数据进行分页处理
  • 使用虚拟滚动处理长列表
  • 实现增量更新而非全量替换

3. 缓存策略

class CachedCalendarManager extends CalendarRecordManager {
    constructor(baseUrl = '', cacheTimeout = 5 * 60 * 1000) { // 5分钟缓存
        super(baseUrl);
        this.cache = new Map();
        this.cacheTimeout = cacheTimeout;
    }
    
    getCacheKey(openid, monthKey) {
        return `${openid}:${monthKey}`;
    }
    
    async getRecord(openid, monthKey) {
        const cacheKey = this.getCacheKey(openid, monthKey);
        const cached = this.cache.get(cacheKey);
        
        // 检查缓存是否有效
        if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
            return cached.data;
        }
        
        // 从服务器获取数据
        const result = await super.getRecord(openid, monthKey);
        
        // 缓存成功结果
        if (result.success) {
            this.cache.set(cacheKey, {
                data: result,
                timestamp: Date.now()
            });
        }
        
        return result;
    }
    
    async saveRecord(openid, monthKey, calendarContent) {
        const result = await super.saveRecord(openid, monthKey, calendarContent);
        
        // 保存成功后清除缓存
        if (result.success) {
            const cacheKey = this.getCacheKey(openid, monthKey);
            this.cache.delete(cacheKey);
        }
        
        return result;
    }
    
    clearCache(openid = null, monthKey = null) {
        if (openid && monthKey) {
            // 清除特定缓存
            const cacheKey = this.getCacheKey(openid, monthKey);
            this.cache.delete(cacheKey);
        } else {
            // 清除所有缓存
            this.cache.clear();
        }
    }
}

联系与支持

如有技术问题或需要支持,请联系:


更新日志

v1.0.0 (2024-01-15)

  • 初始版本发布
  • 支持保存日历记录功能
  • 支持获取日历记录功能
  • 提供完整的前端集成示例
  • 包含错误处理和性能优化建议