健身室器材管理系统鸿蒙PC Electron框架编写深度解析

欢迎加入开源鸿蒙PC社区:

https://harmonypc.csdn.net/

atomgit仓库地址: https://atomgit.com/ai_lingshi/jianshenqicai

一、项目概述

1.1 项目背景

健身房的器材管理是健身行业运营的核心环节。传统的器材管理方式依赖纸质记录或简单的电子表格,存在以下问题:

问题 影响
信息不集中 需要在多个地方查找器材信息
维护提醒不及时 容易错过器材维护时间
使用统计困难 难以分析器材使用频率
状态更新滞后 无法实时了解器材可用性

本项目旨在通过数字化手段,实现健身房器材的智能化管理,提升运营效率。

1.2 功能定位

核心功能

  • 器材信息集中管理
  • 实时状态追踪
  • 智能维护提醒
  • 使用数据分析

用户群体

  • 健身房管理员
  • 器材维护人员
  • 健身教练
  • 场馆运营者

1.3 技术架构

复制代码
┌─────────────────────────────────────────────────────────────┐
│                     视图层 (View)                           │
│    ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│    │   HTML     │  │    CSS      │  │  组件卡片    │     │
│    │  (结构)    │  │  (样式)    │  │  (渲染)    │     │
│    └─────────────┘  └─────────────┘  └─────────────┘     │
├─────────────────────────────────────────────────────────────┤
│                     控制层 (Controller)                     │
│    ┌─────────────────────────────────────────────────┐    │
│    │           EquipmentController                   │    │
│    │  - 事件监听与处理                               │    │
│    │  - 业务逻辑编排                                  │    │
│    │  - 视图更新协调                                  │    │
│    └─────────────────────────────────────────────────┘    │
├─────────────────────────────────────────────────────────────┤
│                     模型层 (Model)                          │
│    ┌─────────────────────────────────────────────────┐    │
│    │           EquipmentModel                        │    │
│    │  - 数据结构定义                                  │    │
│    │  - CRUD 操作实现                                │    │
│    │  - 业务规则校验                                  │    │
│    │  - 统计分析计算                                  │    │
│    └─────────────────────────────────────────────────┘    │
├─────────────────────────────────────────────────────────────┤
│                     存储层 (Storage)                        │
│              localStorage 本地持久化                        │
└─────────────────────────────────────────────────────────────┘

二、数据模型设计

2.1 器材数据结构

javascript 复制代码
{
    id: Number,                    // 唯一标识符
    name: String,                  // 器材名称
    category: String,              // 器材分类
    status: String,                // 当前状态
    purchaseDate: String,         // 购买日期
    lastMaintenance: String,       // 上次维护日期
    nextMaintenance: String,       // 下次维护日期
    usageCount: Number,            // 使用次数
    notes: String                  // 备注信息
}

2.2 分类枚举

javascript 复制代码
const CATEGORIES = {
    cardio: 'cardio',      // 有氧器材
    strength: 'strength',  // 力量器材
    freeweight: 'freeweight',  // 自由重量
    stretch: 'stretch',    // 拉伸器材
    other: 'other'         // 其他器材
};

器材分类详解

分类 代码 典型器材 特点
有氧器材 cardio 跑步机、椭圆机、划船机、动感单车 高频使用,需定期保养
力量器材 strength 卧推架、深蹲架、龙门架、腿举机 承重要求高,安全第一
自由重量 freeweight 哑铃组、杠铃组、壶铃 使用灵活,损耗较快
拉伸器材 stretch 瑜伽垫、泡沫轴、拉伸带 低损耗,使用频率高
其他器材 other 跳绳、健身球、战绳 辅助训练,易于管理

2.3 状态枚举

javascript 复制代码
const STATUS = {
    available: 'available',    // 可用
    inuse: 'inuse',            // 使用中
    maintenance: 'maintenance'  // 维护中
};

状态流转规则

复制代码
可用 ──────────→ 使用中
   ↑                  │
   │                  ↓
   └──────────←─── 使用完成
                   
可用 ──────────→ 维护中
   ↑                  │
   │                  ↓
   └──────────←─── 维护完成

三、核心功能实现

3.1 数据模型类实现

javascript 复制代码
class EquipmentModel {
    constructor() {
        this.equipment = [];
        this.loadData();
    }

    // 加载数据
    loadData() {
        const saved = localStorage.getItem('fitnessEquipment');
        if (saved) {
            try {
                this.equipment = JSON.parse(saved);
            } catch (e) {
                this.equipment = this.getDefaultData();
            }
        } else {
            this.equipment = this.getDefaultData();
            this.saveData();
        }
    }

    // 保存数据
    saveData() {
        localStorage.setItem('fitnessEquipment', 
            JSON.stringify(this.equipment));
    }
}

3.2 CRUD 操作实现

javascript 复制代码
// 添加器材
add(equipment) {
    const newId = Math.max(0, ...this.equipment.map(e => e.id)) + 1;
    const newEquipment = {
        id: newId,
        ...equipment,
        usageCount: equipment.usageCount || 0
    };
    this.equipment.push(newEquipment);
    this.saveData();
    return newEquipment;
}

// 更新器材
update(id, data) {
    const index = this.equipment.findIndex(e => e.id === id);
    if (index !== -1) {
        this.equipment[index] = { 
            ...this.equipment[index], 
            ...data 
        };
        this.saveData();
        return this.equipment[index];
    }
    return null;
}

// 删除器材
delete(id) {
    const index = this.equipment.findIndex(e => e.id === id);
    if (index !== -1) {
        const deleted = this.equipment.splice(index, 1)[0];
        this.saveData();
        return deleted;
    }
    return null;
}

3.3 搜索与筛选

javascript 复制代码
// 搜索器材
search(keyword) {
    const lowerKeyword = keyword.toLowerCase();
    return this.equipment.filter(e => 
        e.name.toLowerCase().includes(lowerKeyword) ||
        e.category.toLowerCase().includes(lowerKeyword) ||
        (e.notes && e.notes.toLowerCase().includes(lowerKeyword))
    );
}

// 按分类筛选
filterByCategory(category) {
    if (category === 'all') return this.getAll();
    return this.equipment.filter(e => e.category === category);
}

// 按状态筛选
filterByStatus(status) {
    if (status === 'all') return this.getAll();
    return this.equipment.filter(e => e.status === status);
}

搜索优化策略

策略 说明 适用场景
模糊匹配 支持部分关键词搜索 用户输入不完整时
大小写不敏感 忽略大小写差异 提高搜索灵活性
多字段搜索 同时搜索名称、分类、备注 增加搜索覆盖面

四、统计分析功能

4.1 统计数据计算

javascript 复制代码
// 获取统计数据
getStats() {
    const total = this.equipment.length;
    const available = this.equipment
        .filter(e => e.status === 'available').length;
    const inuse = this.equipment
        .filter(e => e.status === 'inuse').length;
    const maintenance = this.equipment
        .filter(e => e.status === 'maintenance').length;
    
    return { total, available, inuse, maintenance };
}

4.2 使用频率排行

javascript 复制代码
// 获取使用频率TOP5
getTopUsage() {
    return [...this.equipment]
        .sort((a, b) => b.usageCount - a.usageCount)
        .slice(0, 5);
}

排序算法分析

javascript 复制代码
// 时间复杂度: O(n log n)
// 空间复杂度: O(n)

const sorted = [...this.equipment]
    .sort((a, b) => b.usageCount - a.usageCount)
    .slice(0, 5);

// 或者使用更高效的方式(只需找到前5个)
const sorted = this.equipment
    .sort((a, b) => b.usageCount - a.usageCount)
    .slice(0, 5);

4.3 维护提醒系统

javascript 复制代码
// 获取维护提醒
getMaintenanceAlerts() {
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    
    return this.equipment
        .filter(e => e.nextMaintenance)
        .map(e => {
            const nextDate = new Date(e.nextMaintenance);
            nextDate.setHours(0, 0, 0, 0);
            const daysUntil = Math.ceil(
                (nextDate - today) / (1000 * 60 * 60 * 24)
            );
            
            return {
                ...e,
                daysUntil,
                isOverdue: daysUntil < 0,
                isUrgent: daysUntil >= 0 && daysUntil <= 7
            };
        })
        .filter(e => e.isOverdue || e.isUrgent)
        .sort((a, b) => a.daysUntil - b.daysUntil);
}

维护提醒等级

等级 条件 提示颜色 优先级
逾期 daysUntil < 0 红色 P0
紧急 0 <= daysUntil <= 3 橙色 P1
预警 4 <= daysUntil <= 7 黄色 P2

五、控制器设计

5.1 控制器职责

javascript 复制代码
class EquipmentController {
    constructor() {
        this.model = new EquipmentModel();
        this.initDOMReferences();
        this.bindEventListeners();
        this.render();
    }
}

控制器核心职责

职责 方法 说明
DOM 引用初始化 initDOMReferences() 缓存 DOM 元素引用
事件绑定 bindEventListeners() 注册事件监听器
渲染协调 render() 协调各模块渲染
表单处理 handleSave() 处理新增/编辑表单提交
搜索处理 handleSearch() 处理搜索请求
使用记录 handleRecordUsage() 处理使用记录

5.2 事件处理机制

javascript 复制代码
bindEventListeners() {
    // 搜索
    this.searchBtn.addEventListener('click', () => this.handleSearch());
    this.searchInput.addEventListener('keypress', (e) => {
        if (e.key === 'Enter') this.handleSearch();
    });

    // 筛选
    this.categoryFilter.addEventListener('change', () => this.render());
    this.statusFilter.addEventListener('change', () => this.render());

    // 添加按钮
    this.addBtn.addEventListener('click', () => this.openAddModal());

    // 器材表单
    this.equipmentForm.addEventListener('submit', (e) => {
        e.preventDefault();
        this.handleSave();
    });
}

5.3 渲染策略

javascript 复制代码
render() {
    // 获取筛选条件
    const category = this.categoryFilter.value;
    const status = this.statusFilter.value;
    
    // 获取数据
    let equipment = this.model.getAll();
    
    // 应用筛选
    if (category !== 'all') {
        equipment = equipment.filter(e => e.category === category);
    }
    if (status !== 'all') {
        equipment = equipment.filter(e => e.status === status);
    }
    
    // 渲染各模块
    this.renderEquipmentList(equipment);
    this.renderStats();
    this.renderTopUsage();
    this.renderMaintenanceAlerts();
}

渲染优化

优化点 实现方式 效果
DOM 缓存 初始化时缓存所有 DOM 引用 减少 DOM 查询
条件渲染 器材列表为空时显示空状态 提升用户体验
批量更新 一次性生成 HTML 字符串 减少重绘次数

六、卡片组件设计

6.1 器材卡片模板

javascript 复制代码
renderEquipmentCard(item) {
    const categoryNames = {
        cardio: '有氧器材',
        strength: '力量器材',
        freeweight: '自由重量',
        stretch: '拉伸器材',
        other: '其他器材'
    };

    const statusNames = {
        available: '可用',
        inuse: '使用中',
        maintenance: '维护中'
    };

    // 计算维护提醒
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    const nextDate = item.nextMaintenance ? 
        new Date(item.nextMaintenance) : null;
    if (nextDate) nextDate.setHours(0, 0, 0, 0);
    const daysUntilMaintenance = nextDate ? 
        Math.ceil((nextDate - today) / (1000 * 60 * 60 * 24)) : null;
    const showMaintenanceWarning = 
        daysUntilMaintenance !== null && daysUntilMaintenance <= 7;

    let warningHtml = '';
    if (showMaintenanceWarning) {
        if (daysUntilMaintenance < 0) {
            warningHtml = `
                <div class="maintenance-warning">
                    ⚠️ 维护已逾期 ${Math.abs(daysUntilMaintenance)} 天
                </div>`;
        } else if (daysUntilMaintenance <= 3) {
            warningHtml = `
                <div class="maintenance-warning">
                    ⚠️ ${daysUntilMaintenance} 天后需要维护
                </div>`;
        }
    }

    return `
        <div class="equipment-card" data-id="${item.id}">
            <div class="card-header">
                <div class="card-title">${item.name}</div>
                <span class="status-badge ${item.status}">
                    ${statusNames[item.status]}
                </span>
            </div>
            <span class="card-category">
                ${categoryNames[item.category]}
            </span>
            <div class="card-stats">
                <span>📊 ${item.usageCount} 次</span>
                ${item.purchaseDate ? 
                    `<span>📅 ${item.purchaseDate}</span>` : ''}
            </div>
            ${item.notes ? 
                `<div class="card-info"><div>${item.notes}</div></div>` : ''}
            ${warningHtml}
            <div class="card-actions">
                <button class="card-btn primary" 
                    onclick="equipmentController.openRecordUsageModal(${item.id})">
                    📝 使用
                </button>
                <button class="card-btn secondary" 
                    onclick="equipmentController.openEditModal(${item.id})">
                    ✏️ 编辑
                </button>
                <button class="card-btn danger" 
                    onclick="equipmentController.deleteEquipment(${item.id})">
                    🗑️ 删除
                </button>
            </div>
        </div>
    `;
}

6.2 卡片布局设计

css 复制代码
.equipment-card {
    background: rgba(255, 255, 255, 0.95);
    border-radius: 16px;
    padding: 20px;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
    transition: all 0.3s ease;
}

.equipment-card:hover {
    transform: translateY(-4px);
    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.15);
}

卡片信息层级

层级 内容 视觉权重
1 器材名称、状态标签 高(标题级)
2 器材分类、统计数据 中(信息级)
3 备注、维护警告 低(辅助级)
4 操作按钮 功能入口

七、弹窗组件设计

7.1 添加/编辑弹窗

javascript 复制代码
openAddModal() {
    this.modalTitle.textContent = '添加器材';
    document.getElementById('equipmentId').value = '';
    this.equipmentForm.reset();
    this.equipmentModal.classList.add('active');
}

openEditModal(id) {
    const equipment = this.model.getById(id);
    if (!equipment) return;

    this.modalTitle.textContent = '编辑器材';
    document.getElementById('equipmentId').value = equipment.id;
    document.getElementById('name').value = equipment.name;
    document.getElementById('category').value = equipment.category;
    document.getElementById('status').value = equipment.status;
    // ... 其他字段
    
    this.equipmentModal.classList.add('active');
}

7.2 使用记录弹窗

javascript 复制代码
openRecordUsageModal(id) {
    const equipment = this.model.getById(id);
    if (!equipment) return;

    document.getElementById('usageEquipmentId').value = id;
    this.usageEquipmentName.textContent = `正在记录: ${equipment.name}`;
    document.getElementById('usageDuration').value = '30';
    document.getElementById('usageDate').value = 
        new Date().toISOString().split('T')[0];
    
    this.usageModal.classList.add('active');
}

7.3 弹窗样式

css 复制代码
.modal {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.6);
    backdrop-filter: blur(4px);
    z-index: 1000;
    align-items: center;
    justify-content: center;
}

.modal.active {
    display: flex;
}

.modal-content {
    background: #fff;
    border-radius: 16px;
    width: 100%;
    max-width: 500px;
    max-height: 90vh;
    overflow-y: auto;
    animation: modalSlideIn 0.3s ease;
}

@keyframes modalSlideIn {
    from {
        opacity: 0;
        transform: translateY(-20px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

八、统计面板设计

8.1 统计数据展示

javascript 复制代码
renderStats() {
    const stats = this.model.getStats();
    this.totalEquipment.textContent = stats.total;
    this.availableCount.textContent = stats.available;
    this.inuseCount.textContent = stats.inuse;
    this.maintenanceCount.textContent = stats.maintenance;
}

统计面板布局

css 复制代码
.stats-list {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 15px;
}

.stat-item {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 15px;
    background: #f8f9fa;
    border-radius: 12px;
}

.stat-value {
    font-size: 1.8rem;
    font-weight: 700;
    font-family: 'Courier New', monospace;
}

.stat-value.available { color: #28a745; }
.stat-value.inuse { color: #ffc107; }
.stat-value.maintenance { color: #dc3545; }

8.2 TOP 5 排行榜

javascript 复制代码
renderTopUsage() {
    const top = this.model.getTopUsage();
    
    if (top.length === 0) {
        this.topEquipment.innerHTML = 
            '<p style="color: #888; text-align: center;">暂无数据</p>';
        return;
    }

    this.topEquipment.innerHTML = top.map((item, index) => `
        <div class="top-item">
            <div class="top-rank">${index + 1}</div>
            <div class="top-name">${item.name}</div>
            <div class="top-count">${item.usageCount}次</div>
        </div>
    `).join('');
}

九、持久化存储

9.1 localStorage 策略

javascript 复制代码
saveData() {
    localStorage.setItem('fitnessEquipment', 
        JSON.stringify(this.equipment));
}

loadData() {
    const saved = localStorage.getItem('fitnessEquipment');
    if (saved) {
        try {
            this.equipment = JSON.parse(saved);
        } catch (e) {
            // JSON 解析失败,使用默认数据
            this.equipment = this.getDefaultData();
        }
    } else {
        // 首次使用,初始化默认数据
        this.equipment = this.getDefaultData();
        this.saveData();
    }
}

9.2 数据安全处理

javascript 复制代码
// 异常处理
try {
    this.equipment = JSON.parse(saved);
} catch (e) {
    console.error('数据解析失败:', e);
    this.equipment = this.getDefaultData();
}

// 数据备份建议
// 1. 定期导出 JSON 文件
// 2. 实现数据版本管理
// 3. 添加数据校验机制

十、扩展性设计

10.1 可配置化

javascript 复制代码
// 分类配置
const CATEGORY_CONFIG = {
    cardio: { 
        name: '有氧器材', 
        icon: '🏃',
        maintenanceInterval: 30  // 天
    },
    strength: {
        name: '力量器材',
        icon: '🏋️',
        maintenanceInterval: 60
    },
    // ...
};

10.2 扩展功能建议

功能 优先级 实现难度 说明
数据导出 CSV/Excel 导出
二维码管理 器材扫码识别
预约系统 器材使用预约
使用分析 图表统计分析
权限管理 多用户权限控制
移动端适配 响应式优化

十一、总结

11.1 架构设计亮点

设计点 实现方式 优势
MVC 模式 Model/View/Controller 分离 职责清晰,易于维护
数据驱动 localStorage 持久化 数据不丢失
事件委托 Controller 统一处理 减少事件绑定
组件化 卡片、弹窗独立 可复用性强

11.2 性能优化

优化项 实现方式 效果
DOM 缓存 初始化时缓存引用 减少查询次数
批量渲染 一次性生成 HTML 减少重绘
条件渲染 空状态独立显示 提升首屏速度

11.3 用户体验

特性 实现方式 价值
实时反馈 Toast 提示 操作确认
智能提醒 维护预警系统 预防性维护
视觉反馈 状态颜色区分 信息直观
快捷操作 键盘支持 提升效率

健身室器材管理系统通过现代化的前端架构设计,实现了器材管理的数字化、智能化,提升了健身房运营效率,降低了管理成本。

相关推荐
Pocker_Spades_A1 小时前
[鸿蒙PC命令行移植适配]移植rust三方库ox到鸿蒙PC的完整实践
华为·rust·harmonyos
如烟花的信页1 小时前
易盾点选逆向分析
javascript·爬虫·python·js逆向
EterNity_TiMe_1 小时前
[鸿蒙PC命令行移植适配]移植rust三方库choose到鸿蒙PC的完整实践
华为·rust·harmonyos
Pocker_Spades_A1 小时前
[鸿蒙PC命令行移植适配]移植rust三方库tojson到鸿蒙PC的完整实践
华为·rust·harmonyos
Pocker_Spades_A1 小时前
[鸿蒙PC命令行移植适配]移植rust三方库hexyl到鸿蒙PC的完整实践
华为·rust·harmonyos
ZC跨境爬虫2 小时前
跟着 MDN 学 JavaScript day_2:JavaScript 初体验
开发语言·前端·javascript·学习·ecmascript
假如让我当三天老蒯2 小时前
useCallback 详细解释(从原理到用法)(自学用)
前端·react.js
小妖6662 小时前
Hydration completed but contains mismatches
javascript·vue·vuepress