Files

574 lines
29 KiB
HTML
Raw Permalink Normal View History

2026-03-12 11:27:23 +08:00
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>玉姐的菜单</title>
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700;800&family=ZCOOL+XiaoWei&family=Nunito:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/static/bootstrap.min.css">
<link rel="stylesheet" href="/static/bootstrap-icons.min.css">
<link rel="stylesheet" href="/static/css/app.css">
2026-03-12 11:27:23 +08:00
</head>
<body>
<!-- Search Panel -->
<div class="search-panel" id="search-panel">
<div class="search-panel-shell">
<div class="search-panel-header">
<div class="search-panel-title-row">
<button class="search-panel-back" id="btn-close-search" aria-label="关闭搜索">
<i class="bi bi-arrow-left"></i>
</button>
<div>
<div class="section-kicker"><i class="bi bi-journal-bookmark"></i> 菜谱检索</div>
<div class="search-panel-title">找一道今天想做的家常菜</div>
</div>
</div>
<div class="search-container" style="flex: 1;">
<i class="bi bi-search"></i>
<input type="text" placeholder="搜菜名、食材、凉菜或汤" id="search-input">
</div>
</div>
<div class="result-feedback" id="search-feedback">输入关键词后,这里会显示匹配到的菜谱。</div>
<div class="search-panel-results">
<div class="dish-grid search-results-grid" id="search-results"></div>
</div>
</div>
</div>
<!-- Menu Page -->
<div class="page active" id="page-menu">
<div class="menu-header">
<section class="cookbook-hero">
<div class="hero-bookmark"></div>
<div class="hero-intro">
<div class="hero-kicker"><i class="bi bi-journal-richtext"></i> 家庭菜谱本</div>
<h1 class="hero-title">今天做什么,翻开就知道。</h1>
<p class="hero-subtitle">先挑今天想做的,再翻翻常做菜和备菜安排。</p>
</div>
<div class="hero-actions">
<button class="hero-action" type="button" id="hero-search-trigger">
<span class="hero-action-icon"><i class="bi bi-search"></i></span>
<span class="hero-action-copy">
<strong>找菜</strong>
<span>菜名或食材</span>
</span>
</button>
<button class="hero-action" type="button" id="hero-order-trigger">
<span class="hero-action-icon"><i class="bi bi-basket2"></i></span>
<span class="hero-action-copy">
<strong>看聚会单</strong>
<span>整理备菜</span>
</span>
</button>
</div>
<div class="hero-search-shell">
<span class="visually-hidden" id="menu-current-filter">全部菜谱</span>
<div class="category-filter" id="category-filter">
<div class="category-chip active" data-id="">全部</div>
</div>
</div>
</section>
</div>
<section class="dish-section">
<div class="page-shell">
<div class="result-feedback" id="dish-feedback">正在整理菜谱目录…</div>
<div class="dish-grid" id="dish-list">
<div class="empty-state" style="grid-column: 1 / -1;">
<div class="empty-icon">
<i class="bi bi-cup-hot"></i>
</div>
<div class="empty-title">还没有菜品</div>
<div class="empty-desc">先记下第一道拿手菜,菜谱本就能慢慢丰富起来。</div>
</div>
</div>
</div>
</section>
</div>
<!-- Orders Page -->
<div class="page" id="page-orders">
<div class="orders-header">
<div class="page-header-card">
<div class="page-kicker">备菜清单</div>
<h2 class="page-title">聚会安排</h2>
<p class="page-subtitle">把时间、参与人和待做菜品收在一起,做饭前先把单子列清楚。</p>
<div class="filter-pills">
<div class="filter-pill active" data-status="">全部</div>
<div class="filter-pill" data-status="in_progress">进行中</div>
<div class="filter-pill" data-status="completed">已完成</div>
</div>
</div>
</div>
<div class="order-list" id="order-list">
<div class="empty-state">
<div class="empty-icon">
<i class="bi bi-receipt"></i>
</div>
<div class="empty-title">还没有聚会单</div>
<div class="empty-desc">点右下角新建一张备菜清单,把要做的菜先安排起来。</div>
</div>
</div>
</div>
<!-- Profile Page -->
<div class="page" id="page-profile">
<div class="profile-section">
<div class="page-header-card">
<div class="page-kicker">我的菜谱本</div>
<h2 class="page-title">收纳与备份</h2>
<p class="page-subtitle">把这本家里的菜谱本保存好,换设备时也能继续翻。</p>
</div>
<div class="profile-card">
<a href="/accounts/logout/" class="profile-menu-item" style="text-decoration: none; color: inherit;">
<div class="menu-icon" style="color: #dc3545;">
<i class="bi bi-box-arrow-right"></i>
</div>
<span class="menu-text" style="color: #dc3545;">退出登录</span>
<i class="bi bi-chevron-right menu-arrow"></i>
</a>
2026-03-12 11:27:23 +08:00
<div class="profile-menu-item" id="btn-export">
<div class="menu-icon">
<i class="bi bi-download"></i>
</div>
<span class="menu-text">导出数据备份</span>
<i class="bi bi-chevron-right menu-arrow"></i>
</div>
<div class="profile-menu-item">
<div class="menu-icon">
<i class="bi bi-info-circle"></i>
</div>
<span class="menu-text">版本 v1.0.0</span>
<i class="bi bi-chevron-right menu-arrow"></i>
</div>
</div>
</div>
</div>
<!-- Stats Page -->
<div class="page" id="page-stats">
<div class="stats-content">
<div class="page-header-card">
<div class="page-kicker">常做记录</div>
<h2 class="page-title">家里最常做什么</h2>
<p class="page-subtitle">从聚会次数和参与记录里,看看哪些菜最常上桌。</p>
</div>
<div class="stats-section">
<div class="stats-section-header">
<div class="stats-section-icon">
<i class="bi bi-trophy-fill"></i>
</div>
<div class="stats-section-title">
<h3>菜品排行榜</h3>
<p>按聚会次数排序</p>
</div>
</div>
<div class="dish-rank-list" id="dish-rank-list">
<div class="loading-text">加载中...</div>
</div>
</div>
<div class="stats-section">
<div class="stats-section-header">
<div class="stats-section-icon">
<i class="bi bi-bar-chart-fill"></i>
</div>
<div class="stats-section-title">
<h3>数据概览</h3>
<p>这本菜谱本目前记了多少内容</p>
</div>
</div>
<div class="stats-cards">
<div class="stat-card">
<div class="stat-icon">
<i class="bi bi-cup-hot" style="color: #a85a32;"></i>
</div>
<div class="stat-info">
<div class="stat-value" id="total-dishes">0</div>
<div class="stat-label">菜品总数</div>
</div>
</div>
<div class="stat-card">
<div class="stat-icon">
<i class="bi bi-basket2" style="color: #6f8b63;"></i>
</div>
<div class="stat-info">
<div class="stat-value" id="total-gatherings">0</div>
<div class="stat-label">聚会总数</div>
</div>
</div>
<div class="stat-card" style="cursor: pointer;" onclick="showParticipantRanking()">
<div class="stat-icon">
<i class="bi bi-people" style="color: #8a5634;"></i>
</div>
<div class="stat-info">
<div class="stat-value" id="total-participants">0</div>
<div class="stat-label">参与人数</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Bottom Navigation -->
<nav class="bottom-nav">
<div class="nav-items">
<div class="nav-item active" data-page="menu">
<i class="bi bi-book-fill"></i>
<span>菜单</span>
</div>
<div class="nav-item" data-page="orders">
<i class="bi bi-receipt"></i>
<span>聚会</span>
</div>
<div class="nav-item" data-page="stats">
<i class="bi bi-bar-chart-fill"></i>
<span>统计</span>
</div>
<div class="nav-item" data-page="profile">
<i class="bi bi-person-fill"></i>
<span>我的</span>
</div>
</div>
</nav>
<!-- Loading Modal -->
<div class="modal fade" id="loading-modal" tabindex="-1" data-bs-backdrop="static" data-bs-keyboard="false">
<div class="modal-dialog modal-dialog-centered modal-sm">
<div class="modal-content loading-paper">
<div class="modal-body text-center py-4">
<div class="loading-spinner-shell">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
<div class="modal-kicker">生成分享图</div>
<p class="mb-0 mt-3" style="font-size: 15px; font-weight: 700; color: var(--text-primary);">正在把聚会清单整理成一张好看的菜单卡…</p>
</div>
</div>
</div>
</div>
<!-- Participant Ranking Modal -->
<div class="modal fade" id="participant-ranking-modal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">参与次数排行</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div id="participant-ranking-list"></div>
</div>
</div>
</div>
</div>
<!-- FAB -->
<button class="fab fab-top" id="fab-top" onclick="window.scroll(0, 0)" aria-label="回到顶部">
<i class="bi bi-arrow-up"></i>
</button>
<button class="fab" id="fab-add" aria-label="新增">
<i class="bi bi-plus-lg"></i>
<span class="fab-label" id="fab-label">记菜</span>
</button>
<!-- Dish Detail Modal -->
<div class="modal fade" id="dish-detail-modal" tabindex="-1">
<div class="modal-dialog modal-fullscreen">
<div class="modal-content">
<div class="detail-cover-wrapper">
<img src="" alt="菜品封面" class="detail-cover" id="detail-cover">
<button class="detail-close-btn" data-bs-dismiss="modal" aria-label="关闭菜品详情">
<i class="bi bi-x-lg"></i>
</button>
</div>
<div class="detail-content">
<div class="detail-header-block">
<div class="modal-kicker">菜谱详情</div>
<h2 class="detail-name" id="detail-name"></h2>
<span class="detail-category-tag" id="detail-category"></span>
<div class="detail-summary" id="detail-summary-text">翻翻这道菜需要什么材料,再决定要不要加入聚会单。</div>
</div>
<div class="detail-section" id="detail-ingredients">
<h3 class="detail-section-title">
<i class="bi bi-basket-fill"></i>
所需材料
</h3>
<div id="detail-ingredients-list"></div>
</div>
<div class="detail-section">
<h3 class="detail-section-title">
<i class="bi bi-list-ol"></i>
做法步骤
</h3>
<div class="md-content" id="detail-description"></div>
</div>
</div>
<div class="detail-footer">
<button class="btn btn-secondary" id="btn-delete-dish">删除</button>
<button class="btn btn-primary" id="btn-edit-dish">编辑</button>
<button class="btn btn-success" id="btn-add-to-order">添加到聚会</button>
</div>
</div>
</div>
</div>
<!-- Dish Form Modal -->
<div class="modal fade" id="dish-form-modal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<div>
<div class="modal-kicker">记录一道新菜</div>
<h5 class="modal-title" id="dish-form-title">添加菜品</h5>
<div class="modal-subtitle">保留封面、材料和做法,方便下次直接翻出来做。</div>
</div>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="关闭添加菜品"></button>
</div>
<div class="modal-body">
<form id="dish-form">
<input type="hidden" id="dish-id">
<div class="form-group">
<label class="form-label">菜品名称</label>
<input type="text" class="form-control" id="dish-name" placeholder="请输入菜品名称" required>
</div>
<div class="form-group">
<label class="form-label">菜品分类</label>
<select class="form-select" id="dish-category"></select>
</div>
<div class="form-group">
<label class="form-label">封面图片</label>
<input type="file" class="form-control" id="dish-image" accept="image/*">
<input type="hidden" id="dish-image-url">
<div id="image-preview" class="mt-3" style="display: none;">
<img src="" style="width: 100px; height: 100px; border-radius: 12px; object-fit: cover;">
</div>
</div>
<div class="form-group">
<label class="form-label">材料清单</label>
<div id="ingredients-list"></div>
<button type="button" class="add-ingredient-btn" id="btn-add-ingredient">
<i class="bi bi-plus-lg"></i>
添加材料
</button>
</div>
<div class="form-group">
<div class="step-editor">
<div class="step-editor-header">
<div class="step-editor-title">
<i class="bi bi-list-ol"></i>
做法步骤
</div>
</div>
<div class="step-list" id="step-list"></div>
<button type="button" class="add-step-btn" id="btn-add-step">
<i class="bi bi-plus-lg"></i>
添加步骤
</button>
</div>
<input type="hidden" id="dish-description">
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary" id="btn-save-dish">保存菜品</button>
</div>
</div>
</div>
</div>
<!-- Parse Modal -->
<div class="modal fade" id="parse-modal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<div>
<div class="modal-kicker">链接导入</div>
<h5 class="modal-title">从链接解析菜品</h5>
<div class="modal-subtitle">粘贴外部菜谱地址,先抓取内容,再手动确认后保存。</div>
</div>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="关闭链接解析"></button>
</div>
<div class="modal-body">
<div class="form-group">
<label class="form-label">菜谱链接</label>
<input type="url" class="form-control" id="parse-url" placeholder="粘贴下厨房、美食杰等菜谱链接">
</div>
<div id="parse-result" style="display: none;">
<div class="parse-result-card">
<div class="parse-dish-name" id="parse-name"></div>
<div class="parse-info" id="parse-ingredients-count"></div>
</div>
<button class="btn btn-primary w-100 mt-3" id="btn-apply-parse">应用并编辑</button>
</div>
</div>
</div>
</div>
</div>
<!-- Order Form Modal -->
<div class="modal fade" id="order-form-modal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<div>
<div class="modal-kicker">备菜清单</div>
<h5 class="modal-title" id="order-form-title">新建聚会</h5>
<div class="modal-subtitle">先定时间和参与人,再把想做的菜一并放进这张清单里。</div>
</div>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="关闭聚会表单"></button>
</div>
<div class="modal-body">
<input type="hidden" id="order-id">
<div class="selection-section p-3 mb-3">
<div class="modal-section-head">
<div class="section-kicker">基础信息</div>
</div>
<div class="form-group mb-3">
<label class="form-label">聚会名称</label>
<input type="text" class="form-control" id="order-name" placeholder="例如:周末家宴、除夕晚餐" required>
</div>
<div class="form-group mb-0">
<label class="form-label">聚会时间</label>
<input type="datetime-local" class="form-control" id="order-party-date">
</div>
</div>
<div class="selection-section p-3 mb-3">
<div class="modal-section-head">
<div class="section-kicker">参与人</div>
<div class="modal-copy">输入人名回车即可加入,方便统计这次聚餐都有谁。</div>
</div>
<div id="order-participants-container">
<div class="input-group mb-2">
<input type="text" class="form-control participant-input" placeholder="输入人名后回车添加">
</div>
</div>
<div id="order-participants-tags" class="d-flex flex-wrap gap-1 mt-2"></div>
</div>
<div class="selection-section p-3">
<div class="modal-section-head">
<div class="section-kicker">已选菜品</div>
<div class="modal-copy" id="order-dish-count-label">从下面勾选想做的菜。</div>
</div>
<div id="order-dish-select" style="max-height: 320px; overflow-y: auto;"></div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary" id="btn-save-order">保存聚会</button>
</div>
</div>
</div>
</div>
<!-- Order Detail Modal -->
<div class="modal fade" id="order-detail-modal" tabindex="-1">
<div class="modal-dialog modal-fullscreen">
<div class="modal-content">
<div class="order-detail-header">
<div style="display: flex; justify-content: space-between; align-items: flex-start; gap: 14px;">
<div class="order-detail-heading">
<div class="modal-kicker" style="background: rgba(255,255,255,0.16); color: rgba(255,255,255,0.94); border-color: rgba(255,255,255,0.18);">聚会详情</div>
<h2 class="order-detail-title" id="order-detail-title">聚会名称</h2>
<div class="order-detail-meta">
<span class="order-detail-status" id="order-detail-status"></span>
<span class="order-detail-date" id="order-detail-date"></span>
</div>
<div class="order-summary-strip" id="order-detail-summary">看看这次备菜都安排了什么,再决定是否完成清单。</div>
</div>
<button class="detail-close-btn" data-bs-dismiss="modal" aria-label="关闭聚会详情">
<i class="bi bi-x-lg"></i>
</button>
</div>
</div>
<div class="order-detail-body">
<div class="order-detail-section">
<div class="order-detail-section-head">
<h3 class="order-detail-section-title">
<i class="bi bi-cup-hot-fill"></i>
已选菜品
</h3>
<div class="order-section-note" id="order-detail-dish-note">正在整理这次要做的菜。</div>
</div>
<div class="dish-list" id="order-detail-dishes"></div>
</div>
<div class="order-detail-section">
<h3 class="order-detail-section-title">
<i class="bi bi-people-fill"></i>
参与人员
</h3>
<div class="participant-edit-wrapper">
<div class="input-group participant-edit-input">
<input type="text" class="form-control" id="detail-participant-input" placeholder="输入人名后回车添加">
</div>
<div id="detail-participants-tags" class="d-flex flex-wrap gap-2 mt-2"></div>
</div>
2026-03-12 11:27:23 +08:00
</div>
<div class="order-detail-section" id="order-ingredients-section">
<h3 class="order-detail-section-title">
<i class="bi bi-basket-fill"></i>
食材汇总
</h3>
<div id="order-detail-ingredients"></div>
</div>
<div class="order-detail-section" id="order-images-section">
<h3 class="order-detail-section-title">
<i class="bi bi-camera-fill"></i>
聚会照片
</h3>
<div class="party-images-container" id="order-detail-images"></div>
<div class="upload-image-btn-wrapper">
<label class="upload-image-btn">
<i class="bi bi-plus-lg"></i> 上传照片
<input type="file" accept="image/*" multiple id="party-image-upload" style="display: none;">
</label>
</div>
</div>
</div>
<div class="detail-footer">
<button class="btn btn-primary" id="btn-share-order">
<i class="bi bi-share"></i> 分享
</button>
<button class="btn btn-danger" id="btn-delete-order">删除</button>
<button class="btn btn-success" id="btn-complete-order">完成</button>
</div>
</div>
</div>
</div>
<div class="toast-stack" id="toast-stack" aria-live="polite" aria-atomic="true"></div>
<!-- Confirm Modal -->
<div class="modal fade" id="confirm-modal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered confirm-sheet">
<div class="modal-content">
<div class="confirm-sheet-body">
<div class="confirm-sheet-icon">
<i class="bi bi-journal-check"></i>
</div>
<h5 class="confirm-sheet-title" id="confirm-modal-title">确认一下这步操作</h5>
<p class="confirm-sheet-text" id="confirm-modal-message">确定要继续吗?</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" id="confirm-modal-cancel">再想想</button>
<button type="button" class="btn btn-primary" id="confirm-modal-confirm">继续</button>
</div>
</div>
</div>
</div>
<script src="/static/bootstrap.min.js"></script>
<script src="/static/marked.min.js"></script>
<script src="/static/html2canvas.min.js"></script>
<script src="/static/js/app.js"></script>
2026-03-12 11:27:23 +08:00
</body>
</html>