467 lines
19 KiB
HTML
467 lines
19 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>酒库管理系统 — 项目 TODO</title>
|
||
<style>
|
||
* { box-sizing: border-box; }
|
||
body {
|
||
margin: 0; padding: 0 0 80px;
|
||
font-family: "Noto Sans SC", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||
color: #1f2933; background: #f7f9fb; line-height: 1.6;
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
header {
|
||
background: linear-gradient(135deg, #0A1F3B 0%, #15407D 100%);
|
||
color: #fff; padding: 36px 32px 28px;
|
||
}
|
||
header h1 { margin: 0 0 6px; font-size: 24px; font-weight: 700; }
|
||
header .header-meta { color: #ADC9EA; font-size: 13px; margin-top: 4px; }
|
||
.stats { display: flex; gap: 16px; margin-top: 14px; }
|
||
.stat-pill {
|
||
background: rgba(255,255,255,0.12); border-radius: 20px;
|
||
padding: 4px 14px; font-size: 13px; color: #fff;
|
||
}
|
||
.stat-pill strong { font-size: 18px; font-weight: 700; margin-right: 2px; }
|
||
|
||
/* ── 筛选栏 ── */
|
||
.filter-bar {
|
||
position: sticky; top: 0; z-index: 10;
|
||
background: #fff; border-bottom: 1px solid #e4e9ef;
|
||
padding: 10px 28px; display: flex; flex-wrap: wrap; gap: 10px; align-items: center;
|
||
}
|
||
.filter-group { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
|
||
.filter-label { font-size: 12px; color: #7b8794; white-space: nowrap; }
|
||
.filter-chip, .filter-btn {
|
||
padding: 3px 12px; border-radius: 14px; border: 1.5px solid #d1d9e6;
|
||
background: #f7f9fb; color: #52606d; font-size: 12.5px; cursor: pointer;
|
||
transition: all .15s; white-space: nowrap;
|
||
}
|
||
.filter-chip:hover, .filter-btn:hover { border-color: #2563AC; color: #2563AC; }
|
||
.filter-chip.active, .filter-btn.active {
|
||
background: #2563AC; border-color: #2563AC; color: #fff;
|
||
}
|
||
.filter-sep { width: 1px; height: 20px; background: #e4e9ef; margin: 0 4px; }
|
||
|
||
/* ── 内容区 ── */
|
||
.wrap { max-width: 980px; margin: 0 auto; padding: 0 24px; }
|
||
.section-title {
|
||
font-size: 16px; font-weight: 700; color: #0A1F3B;
|
||
border-left: 4px solid #2563AC; padding-left: 12px;
|
||
margin: 28px 0 12px;
|
||
}
|
||
.section-title.done-title { border-color: #6cbb8a; }
|
||
ul.todo-list { list-style: none; margin: 0; padding: 0; }
|
||
.todo-card {
|
||
background: #fff; border: 1px solid #e4e9ef; border-radius: 10px;
|
||
padding: 14px 18px; margin-bottom: 10px;
|
||
}
|
||
.todo-card.done { background: #f3faf5; border-color: #b7e4c7; opacity: .75; }
|
||
.card-header { display: flex; align-items: flex-start; gap: 10px; flex-wrap: wrap; }
|
||
.item-title { font-weight: 600; font-size: 15px; flex: 1; }
|
||
.todo-card.done .item-title { text-decoration: line-through; color: #52606d; }
|
||
.item-desc { font-size: 13.5px; color: #52606d; margin-top: 6px; }
|
||
.item-desc code {
|
||
background: #f0f2f5; padding: 1px 5px; border-radius: 3px;
|
||
font-family: "JetBrains Mono", monospace; font-size: 12.5px; color: #b91c1c;
|
||
}
|
||
.card-footer { display: flex; align-items: center; gap: 10px; margin-top: 10px; flex-wrap: wrap; }
|
||
.tag-row { display: flex; flex-wrap: wrap; gap: 6px; flex: 1; }
|
||
.item-meta { display: flex; flex-wrap: wrap; gap: 8px; font-size: 12px; color: #8aa3c4; }
|
||
.meta-date { white-space: nowrap; }
|
||
|
||
/* ── tags ── */
|
||
.tag { display: inline-block; padding: 2px 9px; border-radius: 10px; font-size: 12px; font-weight: 600; white-space: nowrap; }
|
||
.t-block { background: #fde8e8; color: #b91c1c; }
|
||
.t-high { background: #fef0d8; color: #9a6700; }
|
||
.t-low { background: #e6f0fb; color: #1d4ed8; }
|
||
.t-tag { background: #efefef; color: #555; cursor: pointer; transition: .12s; }
|
||
.t-tag:hover { background: #d9e8fb; color: #1d4ed8; }
|
||
.ver-badge { font-weight: 700; color: #1f7a44; }
|
||
|
||
/* ── 折叠 ── */
|
||
.done-section { margin-bottom: 24px; }
|
||
.done-toggle {
|
||
background: none; border: 1.5px solid #d1d9e6; border-radius: 6px;
|
||
padding: 4px 14px; cursor: pointer; font-size: 13px; color: #52606d;
|
||
margin-bottom: 10px; transition: .15s;
|
||
}
|
||
.done-toggle:hover { border-color: #6cbb8a; color: #1f7a44; }
|
||
.empty-tip { font-size: 14px; color: #8aa3c4; margin: 8px 0 24px; }
|
||
|
||
/* 隐藏 */
|
||
.hidden { display: none !important; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<header>
|
||
<div class="wrap">
|
||
<h1>酒库管理系统 — 项目 TODO</h1>
|
||
<div class="header-meta">生成于 2026-06-08 · 真相源 todo/todo.json</div>
|
||
<div class="stats">
|
||
<div class="stat-pill"><strong>13</strong>全部</div>
|
||
<div class="stat-pill"><strong>11</strong>未完成</div>
|
||
<div class="stat-pill"><strong>2</strong>已完成</div>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="filter-bar" id="filterBar">
|
||
<div class="filter-group">
|
||
<span class="filter-label">重要度</span>
|
||
<button class="filter-btn active" data-filter-level="all">全部</button>
|
||
<button class="filter-btn" data-filter-level="high">高优</button>
|
||
<button class="filter-btn" data-filter-level="mid">重要</button>
|
||
<button class="filter-btn" data-filter-level="low">一般</button>
|
||
</div>
|
||
<div class="filter-sep"></div>
|
||
<div class="filter-group">
|
||
<span class="filter-label">状态</span>
|
||
<button class="filter-btn active" data-filter-done="all">全部</button>
|
||
<button class="filter-btn" data-filter-done="0">未完成</button>
|
||
<button class="filter-btn" data-filter-done="1">已完成</button>
|
||
</div>
|
||
<div class="filter-sep"></div>
|
||
<div class="filter-group">
|
||
<span class="filter-label">平台 / 标签</span>
|
||
<button class="filter-chip" data-filter-tag="Android">Android</button><button class="filter-chip" data-filter-tag="Web">Web</button><button class="filter-chip" data-filter-tag="iOS">iOS</button><button class="filter-chip" data-filter-tag="前端">前端</button><button class="filter-chip" data-filter-tag="后端">后端</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="wrap">
|
||
|
||
<div class="section-title">📋 未完成(11)</div>
|
||
<ul class="todo-list" id="pendingList">
|
||
|
||
<li class="todo-card"
|
||
data-id="2"
|
||
data-level="high"
|
||
data-tags="Web"
|
||
data-done="0">
|
||
<div class="card-header">
|
||
<span class="item-title">备案号为占位假值</span>
|
||
<span class="tag t-block">高优 · 紧急</span>
|
||
</div>
|
||
<div class="item-desc">现为沪ICP备2026000000号(全0),上线前必须替换真实备案号。</div>
|
||
<div class="card-footer">
|
||
<div class="tag-row"><span class="tag t-tag" data-tag="Web">Web</span></div>
|
||
<div class="item-meta">
|
||
<span class="meta-date">🕐 2026-06-08</span>
|
||
|
||
</div>
|
||
</div>
|
||
</li>
|
||
|
||
<li class="todo-card"
|
||
data-id="8"
|
||
data-level="mid"
|
||
data-tags="前端,iOS,Android"
|
||
data-done="0">
|
||
<div class="card-header">
|
||
<span class="item-title">补全「查看本店其他商品」功能</span>
|
||
<span class="tag t-high">重要</span>
|
||
</div>
|
||
<div class="item-desc">PublicProductScreen _ShopCard 底部按钮 onPressed: () {} 为空,需实现跳转至该门店商品列表页。client/lib/screens/public/public_product_screen.dart:1240</div>
|
||
<div class="card-footer">
|
||
<div class="tag-row"><span class="tag t-tag" data-tag="前端">前端</span> <span class="tag t-tag" data-tag="iOS">iOS</span> <span class="tag t-tag" data-tag="Android">Android</span></div>
|
||
<div class="item-meta">
|
||
<span class="meta-date">🕐 2026-06-08</span>
|
||
|
||
</div>
|
||
</div>
|
||
</li>
|
||
|
||
<li class="todo-card"
|
||
data-id="9"
|
||
data-level="mid"
|
||
data-tags="前端,iOS,Android"
|
||
data-done="0">
|
||
<div class="card-header">
|
||
<span class="item-title">设计并实现添加门店微信功能</span>
|
||
<span class="tag t-high">重要</span>
|
||
</div>
|
||
<div class="item-desc">PublicProductScreen _ShopCard「添加门店微信」按钮 onPressed: () {} 为空。需设计方案:门店维护微信号字段 or 二维码图片,扫码页展示。涉及后端 shop model 扩展 + 前端展示。client/lib/screens/public/public_product_screen.dart:1255</div>
|
||
<div class="card-footer">
|
||
<div class="tag-row"><span class="tag t-tag" data-tag="前端">前端</span> <span class="tag t-tag" data-tag="iOS">iOS</span> <span class="tag t-tag" data-tag="Android">Android</span></div>
|
||
<div class="item-meta">
|
||
<span class="meta-date">🕐 2026-06-08</span>
|
||
|
||
</div>
|
||
</div>
|
||
</li>
|
||
|
||
<li class="todo-card"
|
||
data-id="10"
|
||
data-level="mid"
|
||
data-tags="前端,后端,iOS,Android"
|
||
data-done="0">
|
||
<div class="card-header">
|
||
<span class="item-title">公开商品 API 补充 sale_price 并在页面展示价格</span>
|
||
<span class="tag t-high">重要</span>
|
||
</div>
|
||
<div class="item-desc">product model 有 sale_price 字段但 public.go GetProduct 未返回。需:1) 后端 batchData/productData 加 sale_price;2) Flutter _TitleBlock 或单独区块展示建议零售价。client: public_product_screen.dart, backend: handler/public.go</div>
|
||
<div class="card-footer">
|
||
<div class="tag-row"><span class="tag t-tag" data-tag="前端">前端</span> <span class="tag t-tag" data-tag="后端">后端</span> <span class="tag t-tag" data-tag="iOS">iOS</span> <span class="tag t-tag" data-tag="Android">Android</span></div>
|
||
<div class="item-meta">
|
||
<span class="meta-date">🕐 2026-06-08</span>
|
||
|
||
</div>
|
||
</div>
|
||
</li>
|
||
|
||
<li class="todo-card"
|
||
data-id="11"
|
||
data-level="mid"
|
||
data-tags="前端,iOS,Android"
|
||
data-done="0">
|
||
<div class="card-header">
|
||
<span class="item-title">清除 _ParamsCard 硬编码占位数据</span>
|
||
<span class="tag t-high">重要</span>
|
||
</div>
|
||
<div class="item-desc">public_product_screen.dart _ParamsCard 硬编码了「产地:贵州省仁怀市茅台镇」「生产日期:2024-01-01」「保质期:无限期(适饮)」「储存方式:阴凉干燥…」,非茅台商品显示错误信息。无数据时应不显示该行,或从 custom_fields 读取。line:1089-1092</div>
|
||
<div class="card-footer">
|
||
<div class="tag-row"><span class="tag t-tag" data-tag="前端">前端</span> <span class="tag t-tag" data-tag="iOS">iOS</span> <span class="tag t-tag" data-tag="Android">Android</span></div>
|
||
<div class="item-meta">
|
||
<span class="meta-date">🕐 2026-06-08</span>
|
||
|
||
</div>
|
||
</div>
|
||
</li>
|
||
|
||
<li class="todo-card"
|
||
data-id="12"
|
||
data-level="mid"
|
||
data-tags="前端,iOS,Android"
|
||
data-done="0">
|
||
<div class="card-header">
|
||
<span class="item-title">移除 _DescriptionSection 茅台 mock 文本</span>
|
||
<span class="tag t-high">重要</span>
|
||
</div>
|
||
<div class="item-desc">无商品描述时 fallback 显示飞天茅台硬编码文案和 mock 关键词,其他商品扫码看到茅台介绍。无描述时应隐藏该区块。public_product_screen.dart:819-825</div>
|
||
<div class="card-footer">
|
||
<div class="tag-row"><span class="tag t-tag" data-tag="前端">前端</span> <span class="tag t-tag" data-tag="iOS">iOS</span> <span class="tag t-tag" data-tag="Android">Android</span></div>
|
||
<div class="item-meta">
|
||
<span class="meta-date">🕐 2026-06-08</span>
|
||
|
||
</div>
|
||
</div>
|
||
</li>
|
||
|
||
<li class="todo-card"
|
||
data-id="3"
|
||
data-level="low"
|
||
data-tags="前端,Web"
|
||
data-done="0">
|
||
<div class="card-header">
|
||
<span class="item-title">注册接口同源依赖问题</span>
|
||
<span class="tag t-low">一般 / 优化</span>
|
||
</div>
|
||
<div class="item-desc">用 window.location.origin+'/api/v1/public/register',要求同源部署;分离部署时指错。需确认部署形态。</div>
|
||
<div class="card-footer">
|
||
<div class="tag-row"><span class="tag t-tag" data-tag="前端">前端</span> <span class="tag t-tag" data-tag="Web">Web</span></div>
|
||
<div class="item-meta">
|
||
<span class="meta-date">🕐 2026-06-08</span>
|
||
|
||
</div>
|
||
</div>
|
||
</li>
|
||
|
||
<li class="todo-card"
|
||
data-id="5"
|
||
data-level="low"
|
||
data-tags="前端,Web"
|
||
data-done="0">
|
||
<div class="card-header">
|
||
<span class="item-title">页脚双份维护</span>
|
||
<span class="tag t-low">一般 / 优化</span>
|
||
</div>
|
||
<div class="item-desc">njk 站点用 footer.njk 读变量,功能页把页脚硬编码各写一份,改一处不同步。根因同「两套模板」。</div>
|
||
<div class="card-footer">
|
||
<div class="tag-row"><span class="tag t-tag" data-tag="前端">前端</span> <span class="tag t-tag" data-tag="Web">Web</span></div>
|
||
<div class="item-meta">
|
||
<span class="meta-date">🕐 2026-06-08</span>
|
||
|
||
</div>
|
||
</div>
|
||
</li>
|
||
|
||
<li class="todo-card"
|
||
data-id="6"
|
||
data-level="low"
|
||
data-tags="前端,Web"
|
||
data-done="0">
|
||
<div class="card-header">
|
||
<span class="item-title">注册成功提示路径需核对</span>
|
||
<span class="tag t-low">一般 / 优化</span>
|
||
</div>
|
||
<div class="item-desc">提示「忘记门店编码可在「系统设置→关于」查看」,需与实际客户端菜单路径一致。</div>
|
||
<div class="card-footer">
|
||
<div class="tag-row"><span class="tag t-tag" data-tag="前端">前端</span> <span class="tag t-tag" data-tag="Web">Web</span></div>
|
||
<div class="item-meta">
|
||
<span class="meta-date">🕐 2026-06-08</span>
|
||
|
||
</div>
|
||
</div>
|
||
</li>
|
||
|
||
<li class="todo-card"
|
||
data-id="13"
|
||
data-level="low"
|
||
data-tags="后端,iOS,Android"
|
||
data-done="0">
|
||
<div class="card-header">
|
||
<span class="item-title">公开商品 API 补充 batch.quantity 和 product code/barcode</span>
|
||
<span class="tag t-low">一般 / 优化</span>
|
||
</div>
|
||
<div class="item-desc">Flutter _AuthenticityCard 读取 batch['quantity'] 但后端 public.go batchData 未返回 quantity。另 product code/barcode 未暴露,参数卡无法显示商品编码。handler/public.go GetProduct</div>
|
||
<div class="card-footer">
|
||
<div class="tag-row"><span class="tag t-tag" data-tag="后端">后端</span> <span class="tag t-tag" data-tag="iOS">iOS</span> <span class="tag t-tag" data-tag="Android">Android</span></div>
|
||
<div class="item-meta">
|
||
<span class="meta-date">🕐 2026-06-08</span>
|
||
|
||
</div>
|
||
</div>
|
||
</li>
|
||
|
||
<li class="todo-card"
|
||
data-id="14"
|
||
data-level="low"
|
||
data-tags="前端,iOS,Android"
|
||
data-done="0">
|
||
<div class="card-header">
|
||
<span class="item-title">Footer「商品报错」「意见反馈」补充实际功能</span>
|
||
<span class="tag t-low">一般 / 优化</span>
|
||
</div>
|
||
<div class="item-desc">public_product_screen.dart _Footer 底部两个链接无 url/action,点击静默。需设计方案:跳转反馈表单、弹出联系方式、或发邮件。line:1353-1355</div>
|
||
<div class="card-footer">
|
||
<div class="tag-row"><span class="tag t-tag" data-tag="前端">前端</span> <span class="tag t-tag" data-tag="iOS">iOS</span> <span class="tag t-tag" data-tag="Android">Android</span></div>
|
||
<div class="item-meta">
|
||
<span class="meta-date">🕐 2026-06-08</span>
|
||
|
||
</div>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
|
||
<div class="done-section">
|
||
<div class="section-title done-title">✅ 已完成(2)</div>
|
||
<button class="done-toggle" id="doneToggle">▾ 展开已完成列表</button>
|
||
<ul class="todo-list hidden" id="doneList">
|
||
|
||
<li class="todo-card done"
|
||
data-id="4"
|
||
data-level="low"
|
||
data-tags="前端,Web"
|
||
data-done="1">
|
||
<div class="card-header">
|
||
<span class="item-title">scan.html / features 走 passthrough 不享模板</span>
|
||
<span class="tag t-low">一般 / 优化</span>
|
||
</div>
|
||
<div class="item-desc">features/scan.html 直接复制,不经 njk 模板,页脚/备案/CSS 都得手动同步。建议长期改造为模板化。</div>
|
||
<div class="card-footer">
|
||
<div class="tag-row"><span class="tag t-tag" data-tag="前端">前端</span> <span class="tag t-tag" data-tag="Web">Web</span></div>
|
||
<div class="item-meta">
|
||
<span class="meta-date">🕐 2026-06-08</span>
|
||
<span class="meta-date">✅ 完成 2026-06-08 · <span class="ver-badge">v1.0.23</span></span>
|
||
</div>
|
||
</div>
|
||
</li>
|
||
|
||
<li class="todo-card done"
|
||
data-id="1"
|
||
data-level="mid"
|
||
data-tags="前端,Web"
|
||
data-done="1">
|
||
<div class="card-header">
|
||
<span class="item-title">两套 CSS / 设计令牌并存</span>
|
||
<span class="tag t-high">重要</span>
|
||
</div>
|
||
<div class="item-desc">主站 njk 用 color.css+style.css,功能页用 colors_and_type.css,导航/页脚各写一份,维护分裂。建议合并到一套,功能页走 base.njk 模板。</div>
|
||
<div class="card-footer">
|
||
<div class="tag-row"><span class="tag t-tag" data-tag="前端">前端</span> <span class="tag t-tag" data-tag="Web">Web</span></div>
|
||
<div class="item-meta">
|
||
<span class="meta-date">🕐 2026-06-08</span>
|
||
<span class="meta-date">✅ 完成 2026-06-08 · <span class="ver-badge">v1.0.23</span></span>
|
||
</div>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<script>
|
||
(function() {
|
||
// 筛选状态
|
||
let curLevel = 'all';
|
||
let curDone = 'all';
|
||
let curTags = new Set();
|
||
|
||
function applyFilter() {
|
||
document.querySelectorAll('.todo-card').forEach(card => {
|
||
const lvl = card.dataset.level;
|
||
const dn = card.dataset.done;
|
||
const tags = card.dataset.tags ? card.dataset.tags.split(',') : [];
|
||
|
||
let show = true;
|
||
if (curLevel !== 'all' && lvl !== curLevel) show = false;
|
||
if (curDone !== 'all' && dn !== curDone) show = false;
|
||
if (curTags.size > 0 && ![...curTags].some(t => tags.includes(t))) show = false;
|
||
|
||
card.classList.toggle('hidden', !show);
|
||
});
|
||
}
|
||
|
||
// 重要度
|
||
document.querySelectorAll('[data-filter-level]').forEach(btn => {
|
||
btn.addEventListener('click', () => {
|
||
curLevel = btn.dataset.filterLevel;
|
||
document.querySelectorAll('[data-filter-level]').forEach(b => b.classList.toggle('active', b === btn));
|
||
applyFilter();
|
||
});
|
||
});
|
||
|
||
// 状态
|
||
document.querySelectorAll('[data-filter-done]').forEach(btn => {
|
||
btn.addEventListener('click', () => {
|
||
curDone = btn.dataset.filterDone;
|
||
document.querySelectorAll('[data-filter-done]').forEach(b => b.classList.toggle('active', b === btn));
|
||
applyFilter();
|
||
});
|
||
});
|
||
|
||
// 标签(多选)
|
||
document.querySelectorAll('[data-filter-tag]').forEach(btn => {
|
||
btn.addEventListener('click', () => {
|
||
const t = btn.dataset.filterTag;
|
||
if (curTags.has(t)) { curTags.delete(t); btn.classList.remove('active'); }
|
||
else { curTags.add(t); btn.classList.add('active'); }
|
||
applyFilter();
|
||
});
|
||
});
|
||
|
||
// 点击卡片标签 → 快速筛选
|
||
document.querySelectorAll('.t-tag').forEach(tag => {
|
||
tag.addEventListener('click', e => {
|
||
e.stopPropagation();
|
||
const t = tag.dataset.tag;
|
||
const chip = document.querySelector('[data-filter-tag="'+t+'"]');
|
||
if (chip) chip.click();
|
||
});
|
||
});
|
||
|
||
// 已完成折叠
|
||
const toggle = document.getElementById('doneToggle');
|
||
const doneList = document.getElementById('doneList');
|
||
if (toggle && doneList) {
|
||
toggle.addEventListener('click', () => {
|
||
const collapsed = doneList.classList.toggle('hidden');
|
||
toggle.textContent = collapsed ? '▾ 展开已完成列表' : '▴ 收起已完成列表';
|
||
});
|
||
}
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html> |