欢迎加入开源鸿蒙PC社区:
https://harmonypc.csdn.net/

atomgit仓库地址: https://atomgit.com/tizibanfan/gerenyueshi

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一、项目概述

个人月事记录表是一款帮助女性记录经期、追踪周期的健康管理应用。该应用提供日历视图、记录管理、周期预测、统计分析等功能,帮助用户更好地了解和管理自己的生理周期。

1.1 系统架构设计

┌─────────────────────────────────────────────────────────────┐
│                   个人月事记录表系统                        │
├─────────────────────────────────────────────────────────────┤
│                    UI层 (index.html)                        │
│  ┌───────────┬───────────┬───────────┬───────────┐        │
│  │  统计卡片  │  日历视图  │  记录表单  │  数据分析  │        │
│  └───────────┴───────────┴───────────┴───────────┘        │
├─────────────────────────────────────────────────────────────┤
│                  业务逻辑层 (app.js)                         │
│  ┌────────────┬────────────┬────────────┬────────────┐     │
│  │  数据管理   │  日历渲染   │  周期计算   │  统计分析   │     │
│  └────────────┴────────────┴────────────┴────────────┘     │
├─────────────────────────────────────────────────────────────┤
│                    数据持久层 (LocalStorage)                │
│  ┌──────────────────────────────────────────────────────┐  │
│  │              periodRecords (经期记录数据)             │  │
│  └──────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘

1.2 核心功能模块

模块 功能描述 技术要点
日历视图 月份切换、日期标记、状态显示 日期计算、DOM渲染
记录管理 添加/编辑/删除经期记录 表单处理、数据存储
周期预测 基于历史数据预测下次经期 统计分析、日期计算
统计分析 周期长度、经期天数统计 数据聚合、图表渲染

二、数据模型设计

2.1 记录数据结构

{
    id: 1672531200000,       // 唯一标识(时间戳)
    date: '2024-01-01',      // 日期(ISO格式)
    status: 'period',         // 状态:period/pms/fertile/normal
    flow: 'medium',           // 流量:light/medium/heavy(可选)
    note: '轻微腹痛'          // 备注(可选)
}

2.2 状态类型说明

状态 颜色标识 含义
经期中 period 🔴 红色 月经来潮期间
经前综合征 pms 🟠 橙色 经期前的不适症状
排卵期 fertile 🔵 蓝色 最佳受孕时期
正常 normal 🟢 绿色 无特殊状态

2.3 流量类型说明

流量 含义
少量 light 月经量较少
中等 medium 月经量适中
大量 heavy 月经量较大

三、核心代码实现详解

3.1 应用类设计

class PeriodTracker {
    constructor() {
        this.records = this.loadRecords();
        this.currentDate = new Date();
        this.currentMonth = this.currentDate.getMonth();
        this.currentYear = this.currentDate.getFullYear();
        this.init();
    }

    init() {
        this.initDOMReferences();
        this.bindEventListeners();
        this.renderCalendar();
        this.updateStats();
        this.renderRecordsList();
        this.renderCycleChart();
        this.setDefaultDate();
    }
}

初始化流程:

  1. 加载记录数据
  2. 设置当前日期
  3. 初始化DOM引用
  4. 绑定事件监听器
  5. 渲染日历、统计、记录列表和图表

3.2 数据持久化

loadRecords() {
    const saved = localStorage.getItem('periodRecords');
    if (saved) {
        return JSON.parse(saved);
    }
    return this.getMockData();
}

saveRecords() {
    localStorage.setItem('periodRecords', JSON.stringify(this.records));
}

Mock数据生成:

getMockData() {
    const now = new Date();
    const records = [];
    
    for (let i = 6; i >= 0; i--) {
        const cycleStart = new Date(now);
        cycleStart.setDate(cycleStart.getDate() - (i * 28));
        
        for (let j = 0; j < 5; j++) {
            const date = new Date(cycleStart);
            date.setDate(date.getDate() + j);
            records.push({
                id: Date.now() + j + i,
                date: date.toISOString().split('T')[0],
                status: 'period',
                flow: j === 0 ? 'medium' : j === 1 ? 'heavy' : j === 4 ? 'light' : 'medium',
                note: ''
            });
        }
    }
    
    return records.sort((a, b) => new Date(b.date) - new Date(a.date));
}

Mock数据特点:

  • 生成7个周期的模拟数据
  • 每个周期28天间隔
  • 经期持续5天
  • 流量分布:第一天中等,第二天大量,最后一天少量

3.3 日历渲染

renderCalendar() {
    const firstDay = new Date(this.currentYear, this.currentMonth, 1);
    const lastDay = new Date(this.currentYear, this.currentMonth + 1, 0);
    const startDay = firstDay.getDay();
    const daysInMonth = lastDay.getDate();
    const today = new Date();
    const todayStr = today.toISOString().split('T')[0];
    const nextPeriodDate = this.predictNextPeriod();
    
    this.currentMonthEl.textContent = `${this.currentYear}${this.currentMonth + 1}`;
    
    let html = '';
    
    for (let i = 0; i < startDay; i++) {
        html += '<div class="calendar-day empty"></div>';
    }
    
    for (let day = 1; day <= daysInMonth; day++) {
        const date = new Date(this.currentYear, this.currentMonth, day);
        const dateStr = date.toISOString().split('T')[0];
        const record = this.records.find(r => r.date === dateStr);
        const isToday = dateStr === todayStr;
        const isNextPeriod = nextPeriodDate && dateStr === nextPeriodDate;
        
        let classes = 'calendar-day';
        
        if (isToday) classes += ' today';
        if (record) {
            classes += ` ${record.status}`;
            if (this.isPeriodStart(dateStr)) {
                classes += ' period-start';
            }
        }
        if (isNextPeriod && !record) classes += ' next-period';
        
        html += `<div class="${classes}">${day}</div>`;
    }
    
    this.calendarGrid.innerHTML = html;
}

日历渲染流程:

  1. 计算当月第一天和最后一天
  2. 计算第一天是星期几
  3. 生成空白格子填充第一周
  4. 遍历每一天,判断状态并添加样式类
  5. 渲染到DOM

3.4 经期开始判断

isPeriodStart(dateStr) {
    const date = new Date(dateStr);
    const prevDate = new Date(date);
    prevDate.setDate(prevDate.getDate() - 1);
    const prevDateStr = prevDate.toISOString().split('T')[0];
    const prevRecord = this.records.find(r => r.date === prevDateStr);
    const currRecord = this.records.find(r => r.date === dateStr);
    return currRecord?.status === 'period' && (!prevRecord || prevRecord.status !== 'period');
}

判断逻辑:

  • 当前记录状态为经期
  • 前一天没有记录或前一天状态不是经期
  • 使用可选链操作符处理undefined情况

3.5 周期计算算法

getCycles() {
    const periodStarts = this.records
        .filter(r => r.status === 'period')
        .map(r => new Date(r.date))
        .sort((a, b) => a - b);
    
    const cycles = [];
    for (let i = 1; i < periodStarts.length; i++) {
        const diff = Math.round((periodStarts[i] - periodStarts[i-1]) / (1000 * 60 * 60 * 24));
        if (diff > 10 && diff < 60) {
            cycles.push(diff);
        }
    }
    return cycles;
}

算法说明:

  1. 筛选所有经期记录
  2. 转换为日期对象并排序
  3. 计算相邻经期开始日期间隔
  4. 过滤异常值(10-60天范围)

3.6 周期预测算法

predictNextPeriod() {
    const cycles = this.getCycles();
    if (cycles.length === 0) return null;
    
    const avgCycle = cycles.reduce((a, b) => a + b, 0) / cycles.length;
    const lastPeriodStart = this.records
        .filter(r => r.status === 'period')
        .map(r => new Date(r.date))
        .sort((a, b) => b - a)[0];
    
    if (!lastPeriodStart) return null;
    
    const nextDate = new Date(lastPeriodStart);
    nextDate.setDate(nextDate.getDate() + Math.round(avgCycle));
    return nextDate.toISOString().split('T')[0];
}

预测逻辑:

  1. 获取所有周期长度
  2. 计算平均周期长度
  3. 获取最后一次经期开始日期
  4. 加上平均周期长度得到预测日期

3.7 经期长度统计

getPeriodLengths() {
    const periods = [];
    let currentLength = 0;
    const sortedRecords = [...this.records]
        .filter(r => r.status === 'period')
        .map(r => new Date(r.date))
        .sort((a, b) => a - b);
    
    for (let i = 0; i < sortedRecords.length; i++) {
        if (i === 0 || this.daysBetweenDates(sortedRecords[i-1], sortedRecords[i]) === 1) {
            currentLength++;
        } else {
            if (currentLength > 0) periods.push(currentLength);
            currentLength = 1;
        }
    }
    if (currentLength > 0) periods.push(currentLength);
    
    return periods;
}

统计逻辑:

  1. 筛选并排序经期记录
  2. 遍历记录,连续日期计数+1
  3. 遇到不连续日期时保存当前长度并重置

3.8 记录管理

handleFormSubmit(e) {
    e.preventDefault();
    
    const record = {
        id: Date.now(),
        date: this.recordDate.value,
        status: this.recordStatus.value,
        flow: this.flowLevel.value,
        note: this.recordNote.value.trim()
    };
    
    const existingIndex = this.records.findIndex(r => r.date === record.date);
    if (existingIndex >= 0) {
        this.records[existingIndex] = record;
    } else {
        this.records.unshift(record);
    }
    
    this.saveRecords();
    this.renderCalendar();
    this.updateStats();
    this.renderRecordsList();
    this.renderCycleChart();
    
    this.recordForm.reset();
    this.setDefaultDate();
}

表单处理流程:

  1. 阻止默认提交行为
  2. 构建记录对象
  3. 判断是否已存在同一天记录
  4. 更新或添加记录
  5. 保存并刷新UI

3.9 周期图表渲染

renderCycleChart() {
    const cycles = this.getCycles();
    
    if (cycles.length === 0) {
        this.cycleChart.innerHTML = '<p style="text-align: center; color: #999; padding: 20px;">暂无足够数据</p>';
        return;
    }
    
    const maxCycle = Math.max(...cycles);
    
    this.cycleChart.innerHTML = cycles.map((cycle, index) => {
        const height = (cycle / maxCycle) * 100;
        return `<div class="cycle-bar" style="height: ${Math.max(height, 5)}%" data-value="${cycle}" title="第${cycles.length - index}个周期: ${cycle}天"></div>`;
    }).join('');
}

图表渲染逻辑:

  1. 获取周期数据
  2. 计算最大周期作为基准
  3. 按比例计算每个周期的高度
  4. 生成柱状图HTML

四、UI交互设计

4.1 渐变背景设计

body {
    background: linear-gradient(135deg, #fce4ec 0%, #f8bbd9 30%, #e1bee7 60%, #d1c4e9 100%);
}

配色方案:

  • 粉色渐变主题,符合女性健康应用定位
  • 从浅粉到紫色的过渡
  • 温暖柔和的视觉效果

4.2 状态颜色编码

.calendar-day.period {
    background: #ffcdd2;
    border: 2px solid #e91e63;
}

.calendar-day.period-start {
    background: linear-gradient(135deg, #e91e63 0%, #ffcdd2 100%);
    border-radius: 50%;
}

.calendar-day.pms {
    background: #fff3e0;
    border: 2px solid #ff9800;
}

.calendar-day.fertile {
    background: #e3f2fd;
    border: 2px solid #2196f3;
}

.calendar-day.next-period {
    background: #f3e5f5;
    border: 2px dashed #9c27b0;
}

视觉设计:

  • 经期:红色背景+红色边框
  • 经期开始:渐变圆形标记
  • 经前综合征:橙色边框
  • 排卵期:蓝色边框
  • 下次预测:紫色虚线边框

4.3 响应式布局

@media (max-width: 768px) {
    .stats-section {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (max-width: 480px) {
    .stats-section {
        grid-template-columns: 1fr;
    }
    
    .record-item {
        flex-direction: column;
        gap: 10px;
        align-items: flex-start;
    }
}

布局适配:

  • 桌面端:4列统计卡片
  • 平板端:2列统计卡片
  • 移动端:1列布局,记录项垂直排列

4.4 交互动画

.nav-btn:hover {
    transform: scale(1.1);
    box-shadow: 0 4px 15px rgba(248, 187, 217, 0.4);
}

.submit-btn:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 20px rgba(233, 30, 99, 0.4);
}

.action-btn:hover {
    transform: scale(1.1);
}

交互效果:

  • 导航按钮:悬停放大+阴影
  • 提交按钮:悬停上移+阴影
  • 操作按钮:悬停放大

五、功能扩展建议

5.1 提醒功能

setReminder(date, message) {
    const reminderDate = new Date(date);
    const now = new Date();
    const delay = reminderDate - now;
    
    if (delay > 0) {
        setTimeout(() => {
            if (Notification.permission === 'granted') {
                new Notification('经期提醒', {
                    body: message,
                    icon: '🌸'
                });
            }
        }, delay);
    }
}

5.2 数据导出

exportData() {
    const data = JSON.stringify(this.records, null, 2);
    const blob = new Blob([data], { type: 'application/json' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `period_records_${new Date().toISOString().split('T')[0]}.json`;
    a.click();
    URL.revokeObjectURL(url);
}

5.3 症状追踪

// 扩展记录数据结构
{
    id: 1672531200000,
    date: '2024-01-01',
    status: 'period',
    flow: 'medium',
    note: '轻微腹痛',
    symptoms: ['腹痛', '疲劳'],  // 新增症状字段
    mood: '一般'                // 新增心情字段
}

六、总结

个人月事记录表应用通过完整的功能实现,帮助用户记录和管理经期信息。核心功能包括:

  1. 日历视图:可视化展示经期记录
  2. 记录管理:完整的CRUD操作
  3. 周期预测:基于历史数据的智能预测
  4. 统计分析:周期长度、经期天数统计
  5. 健康建议:饮食、运动、休息建议

技术亮点

  • 数据持久化:LocalStorage保存记录
  • 智能预测:基于历史数据的周期预测算法
  • 响应式设计:适配各种设备尺寸
  • 视觉友好:粉色主题、颜色编码状态

未来扩展方向

  1. 通知提醒:经期前提醒、排卵期提醒
  2. 数据导出:支持Excel/CSV格式
  3. 症状追踪:记录更多健康信息
  4. 云端同步:数据备份和多设备同步
  5. 健康报告:生成周期分析报告
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐