Skip to main content ホーム クリエイター whyzsm tiny-agents software-manager-skill
software-manager-skill 软件产品经理/软件开发经理知识技能。当用户需要产品经理级别的专业支持时触发,包括: 需求分析、PRD撰写、产品设计、产品路线图规划、竞品分析、数据分析; 或用户询问产品经理职责、如何成为产品经理、产品经理技能要求; 或需要产品架构图、流程图、时序图、甘特图等 Mermaid 图表; 或需要从0到1输出PRD文档并自动生成可交互H5原型图; 或需要将PRD文档导出为Markdown(.md)或Word(.docx)格式。 注意:本 skill 采用主动式产品咨询流程。流程:确认需求 → 提问澄清 → 网络搜索 + RAG搜索 → 产品规划 → 方案对比 → 技术选型 → 需求确认 → PRD文档 + Mermaid图表 → 导出格式 → H5原型图(可选)。
インストールへ移動 Skills Marketplace コミュニティが作成したAIスキルを発見・探索
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
直接コマンドでは確認用 Prompt が省略されます。実行前にソースを確認してください。
npx skills add https://github.com/whyzsm/tiny-agents --skill software-manager-skillコマンドは1行のまま表示されます。コピー前に横へスクロールして全体を確認してください。
ローカルで確認しますか?SkillsMP が現在取得できるファイルをダウンロードできます。
Zipをダウンロード ダウンロード中... このリポジトリの他の Skills tech-tmax-backend-architect-team Single-Agent T-MAX Java backend architecture and engineering rule package. Use when Codex must design, implement, review, or diagnose T-MAX backend services involving Java 8, Spring Boot, Kylin, MyBatis XML, TiDB/MySQL, Apollo/Nacos, Feign, AnePageHelper, ResponseResult/DataGridResult, UEP export, Redis, RabbitMQ, or Maven multi-module repositories. Routes one Agent through repository intake, architecture decisions, API/data contracts, implementation diagnosis, quality/security review, and bounded evidence loops while keeping builds, tests, live calls, commits, and pushes as separate authority boundaries.
Create polished consulting-style single-file HTML research reports from messy business notes, screenshots, metrics, and iterative user feedback. Use this skill whenever the user asks for a 咨询风/艾瑞咨询风/研究报告/汇报报告/HTML报告, wants business or AI landing-practice material turned into a management-facing report, asks to add charts/diagrams, or asks to update report metrics and keep the whole HTML report consistent.
harmonyos-app-store-self-check Audit HarmonyOS applications for AppGallery/AGC release readiness, including Huawei UX/HMI controls, system-feature integrations, and performance gates for multi-input interaction, latency, frame rate, content display, memory, and CPU. Use when users ask for 鸿蒙上架自检、应用市场审核、AGC发布前检查、控件/系统特性/人机交互/签名/隐私/权限/截图/性能核对或 release 包门禁, especially for Stage-model projects with module.json5, build-profile.json5, hvigorw, and local-first data constraints.
name software-manager-skill description 软件产品经理/软件开发经理知识技能。当用户需要产品经理级别的专业支持时触发,包括: 需求分析、PRD撰写、产品设计、产品路线图规划、竞品分析、数据分析; 或用户询问产品经理职责、如何成为产品经理、产品经理技能要求; 或需要产品架构图、流程图、时序图、甘特图等 Mermaid 图表; 或需要从0到1输出PRD文档并自动生成可交互H5原型图; 或需要将PRD文档导出为Markdown(.md)或Word(.docx)格式。 注意:本 skill 采用主动式产品咨询流程。流程:确认需求 → 提问澄清 → 网络搜索 + RAG搜索 → 产品规划 → 方案对比 → 技术选型 → 需求确认 → PRD文档 + Mermaid图表 → 导出格式 → H5原型图(可选)。
license MIT metadata {"version":"2.2.0","trigger":"产品经理|PRD|产品需求文档|需求分析|产品设计|产品路线图|竞品分析|用户故事|敏捷开发|Scrum|产品从0到1|功能需求|非功能需求|产品经理职责|如何成为产品经理|Kano模型|RICE评分|MoSCoW|产品体验|用户旅程|产品架构|产品迭代|数据分析|DAU|MAU|留存率|转化率|NPS|登录注册流程|搜索功能|推荐系统|分享功能|支付功能|会员体系|通知系统|APP设计|小程序设计|Web端设计|H5设计|B端产品|C端产品|增长产品|策略产品|商业产品|数据产品|Mermaid|流程图|架构图|时序图|甘特图|H5原型图|纯H5|导出PRD|导出docx|导出Word|PRD导出","tags":["product-manager","pm","prd","product-design","requirements","agile","scrum","mermaid","flowchart"],"hermes":{"source":"https://github.com/{org}/software-manager-skill","tags":["product-manager","pm","prd","product-design","requirements","agile","scrum","mermaid","flowchart","h5","tailwindcss","icon-library"],"related_skills":["ios-dev-skill","frontend-design-skill"],"version":"2.0.8","last_updated":"2026-04-27"}}
软件产品经理(Product Manager)知识技能
使用场景:用户需要产品经理级别的专业支持,或询问产品经理相关知识。
注意:本 skill 采用主动式产品咨询流程,不是单向知识问答。
流程:确认需求 → 提问澄清 → 网络搜索 + RAG搜索 → 产品规划 → 方案对比(用户选择) → 需求确认 → PRD文档输出 + Mermaid图表整合 → 导出格式选择 → H5可交互原型图(可选,PRD后主动询问,所有页面集成在同一HTML文件,本地Tailwind CSS内联)。
可选依赖
DOCX 导出需要 python3 和 python-docx。
Mermaid 渲染需要 node、npm、@mermaid-js/mermaid-cli,以及 Chrome、Edge、Firefox 或 Chromium 之一。
如果只输出 Markdown PRD,可以跳过这些依赖。
主动式产品咨询流程
本 skill 不做单向知识问答,而是遵循以下流程:确认需求 → 提问澄清 → 网络搜索 + RAG资料搜索 → 产品规划 → 方案对比 → 技术选型 → 需求确认 → PRD文档 + Mermaid图表 → 导出格式 → H5原型图(可选)。
阶段一:确认需求(开口三问)
收到用户产品相关需求后,先用一段话确认理解,然后问三个核心问题:
问题1:产品方向
「你这个产品主要是做什么的?面向什么用户?解决什么核心问题?」
问题2:平台形态
「是移动端APP、小程序、Web端还是多端都要?C端还是B端?」
问题3:成熟度
「现在是从0到1的新产品,还是在现有产品上做迭代?有没有竞品可以参照?」
阶段二:多源资料搜索
根据用户回答,判断需要搜索哪些资料。可以灵活选择一种或两种方式组合使用:
2.1 网络搜索
搜索策略 :优先使用环境中最可靠的网络搜索工具(由系统自动选择)。若返回结果为空或结果数 ≤ 2,应立即尝试其他可用搜索工具。禁止在提示词中硬编码具体搜索工具名 。
降级触发条件 (满足任一即换工具重试):
搜索返回结果数 ≤ 2
搜索耗时异常长(>5s 无响应)
工具返回"不可用"或报错
示例搜索调用:
搜索「运动健身APP用户需求分析 2026」
搜索「装修APP用户痛点 业主 2026」
搜索「住小帮 齐家网 土巴兔 功能对比」
若第一个搜索工具返回不足,自动切换其他工具重试
2.2 RAG本地搜索
使用 WebFetch 工具获取官方文档,或用 Grep/Read 工具搜索本地参考文档。
本地文档映射:
需求分析类 → 调取 pm-responsibilities.md、sdlc-product-process.md
产品设计类 → 调取 prd-template.md、mermaid-guide.md
竞品分析类 → 调取 pm-framework.md(竞品分析框架)
数据分析类 → 调取 pm-framework.md(AARRR/留存分析)
路线图规划类 → 调取 pm-framework.md(OKR对齐)、sdlc-product-process.md
阶段三:产品规划
基于网络搜索结果和RAG资料,给出产品规划建议,包括:
产品定位一句话 :「[产品名称]是一个面向[目标用户]的[产品类型],解决[核心问题]。*
核心功能优先级 (MoSCoW):
Must(必须有):[核心路径功能,1-3个]
Should(应该有):[重要功能,2-4个]
Could(可以有):[增强功能,2-3个]
Won't(这次不做):[放未来规划的功能]
MVP范围定义 :最小可行产品只做哪几个功能,为什么这几个是核心。
用户旅程简化版 :
用户打开APP → [核心动作] → [得到什么价值] → [下一个动作/退出]
阶段四:方案对比(用户选择)
基于产品规划结果,输出2-3个不同方案供用户选择。
方案命名 :「简约版」「标准版」「增强版」或「A方案」「B方案」「C方案」
方案对比表 :
维度 方案A(简约版) 方案B(标准版) 方案C(增强版) 功能范围 MVP核心功能 核心+重要功能 全功能 开发周期 约X人天 约X人天 约X人天 技术复杂度 低 中 高 适用场景 快速验证 成熟产品 完整规划
各方案详细说明 :
方案A:只做核心路径,快速上线验证
方案B:在核心基础上增加重要辅助功能
方案C:完整规划,包含所有规划功能
用户决策 :等待用户选择某个方案,或提出修改意见。
阶段五:技术选型确认
用户选定方案后,输出技术选型确认,确认以下内容:
技术栈确认 :
分类 选项 说明 前端框架 React / Vue / 纯H5 影响H5原型实现方式 后端框架 Node.js / Python / Java / Go 影响API设计 数据库 MySQL / PostgreSQL / MongoDB 影响数据模型设计 部署方式 云服务 / 自建服务器 影响运维方案
技术约束确认 :
是否有现成技术栈要求?
是否有性能/并发/安全等技术要求?
第三方服务依赖(支付/地图/推送等)?
技术选型确认话术 :
请确认技术选型方向:
- 前端技术栈偏好(React/Vue/纯H5)
- 后端技术栈偏好(Node.js/Python/Java/Go)
- 数据库选型(关系型/文档型)
- 是否有现成框架或技术债务需继承
- 第三方服务依赖(支付/地图/推送等)
确认后进入需求确认阶段。如用户跳过,则使用合理默认值继续。
阶段六:需求确认
用户选定方案后,在正式输出PRD文档之前,先输出一份需求确认书 ,包含:
需求确认书模板
## 需求确认书(确认后进入PRD输出)
**产品名称**:[名称]
**选定方案**:[方案A/方案B/方案C]
**平台形态**:[APP/小程序/H5/Web端]
### 核心功能确认
| 功能模块 | 功能名称 | 优先级 | 确认 |
|---------|---------|--------|------|
| [模块] | [功能] | P0 | [✓/—] |
### 关键业务流程确认
[描述1-2个核心用户路径]
### 目标指标确认
| 指标 | 目标值 | 周期 |
|------|--------|------|
| [DAU/留存率/转化率等] | [数值] | [时间] |
### Mermaid图表预览
[产品架构图 / 用户旅程图]
**请确认以上内容是否准确,如有调整请告知,确认后输出完整PRD文档。**
确认完成后进入PRD输出阶段。如用户有调整,返回阶段三重新规划。
阶段七:PRD文档整合输出
整合网络搜索和RAG资料,输出完整PRD文档。如果用户明确要求保存,再使用 Write 工具保存文档。
询问存放路径
在输出PRD文档之前,必须先询问用户存放路径。
在开始输出PRD文档之前,请告诉我:
1. 存放文件夹路径(例如:`~/PRD/` 或 `D:\project\PRD` 或 `~/Desktop/`)
2. 文件命名(例如:`装修APP_PRD_v0.1`)
如果暂时不想保存,可以回复「不保存」,我会直接在回复中输出完整文档内容。
用户指定路径后,使用 Write 工具保存文件
用户未指定 → 在回复末尾输出完整文档内容,并说明「可保存为 ~/[用户主目录]/[产品名称]_PRD_v0.1.md」
禁止硬编码用户-specific路径 (如 C:\Users\yhong\...)
文件保存规范
不要在 skill 中硬编码用户-specific 的路径。 PRD 文档的保存路径应该由用户在对话中指定,或者使用通用的相对路径。如果用户没有指定保存位置,则在输出时说明「如需保存,请在下方复制文档内容」。
不正确的做法(会导致跨平台不兼容):
/home/{用户名}/projects/{产品名称}/PRD/... 或 C:\\Users\\{用户名}\\projects\\{产品名称}\\PRD\\...
这些都是用户-specific 路径,不应在 skill 中出现。
正确的做法(跨平台通用):
如果用户指定了路径,按用户指定路径保存
如果用户未指定,在回复末尾提供文档内容供用户复制,并说明「可保存为 ~/projects/{产品名称}/PRD/{产品名称}_PRD_v0.1.md」
Windows/WSL/macOS 用户可各自替换 ~ 为自己的主目录路径
PRD文档模板
# [产品名称] 产品需求文档 v0.1
## 1. 概述
### 1.1 背景
[为什么做这个产品,基于市场分析和用户需求]
### 1.2 产品定位
[一句话产品定位]
### 1.3 目标用户
[用户画像描述]
### 1.4 成功标准
| 指标 | 当前值 | 目标值 | 时间节点 |
|------|--------|--------|---------|
| [指标名] | [数值] | [数值] | [日期] |
### 1.5 竞品分析
[基于网络搜索的竞品对比]
### 1.6 参考资源
- [竞品官网/文章链接]
- [行业报告链接]
## 2. 用户与场景
### 2.1 用户画像
[用户画像描述:基本信息/使用场景/痛点/动机]
### 2.2 用户旅程
[文字描述关键步骤]
### 2.3 核心用例
| 用例编号 | 用例名称 | 触发条件 | 主路径 | 预期结果 |
|---------|---------|---------|--------|---------|
| UC-01 | [名称] | [条件] | [步骤] | [结果] |
## 3. 功能需求
### 3.1 功能列表
| 功能模块 | 功能名称 | 优先级 | 描述 |
|---------|---------|--------|------|
| [模块] | [功能] | P0 | [一句话描述] |
### 3.2 详细说明
[针对P0核心功能,详细描述功能逻辑]
### 3.3 验收标准
| 功能 | 验收条件 | 测试方法 |
|------|---------|---------|
| [功能] | [SMART标准] | [测试步骤] |
## 4. 非功能需求
| 类型 | 要求 |
|------|------|
| 性能 | [响应时间要求] |
| 安全 | [安全要求] |
| 兼容性 | [兼容要求] |
| 可靠性 | [可用性要求] |
## 5. 数据埋点
| 事件名称 | 触发时机 | 参数 |
|---------|---------|------|
| [事件] | [时机] | [参数] |
## 6. 风险与依赖
| 风险/依赖 | 影响 | 应对措施 |
|-----------|------|---------|
| [条目] | [描述] | [措施] |
## 7. 附录
- 修订记录
- 术语表
阶段八:Mermaid图表整合输出
从0到1新产品 → 输出:
产品架构图(系统分层)
核心用户旅程图
MVP功能优先级甘特图
迭代类产品 → 输出:
需求状态流转图
迭代计划甘特图
跨团队协作时序图(PM/设计/开发/QA)
竞品分析类 → 输出:
数据分析类 → 输出:
阶段九:导出格式选择
在PRD文档输出完成后,主动询问用户导出格式。
询问话术
✅ PRD文档已完成,请选择导出格式:
- 输入「md」或「Markdown」→ 保存为 .md 文件
- 输入「docx」或「Word」→ 保存为 .docx 文件(Mermaid图表自动渲染为PNG图片)
- 输入「不需要」→ 跳过导出
导出方式
Markdown(.md) :直接保存为 .md 文件,Mermaid图表保留为代码块格式。
Word(.docx) :
使用 python-docx 库生成 .docx 文件
Mermaid代码块自动渲染为PNG图片后嵌入文档
使用本地浏览器(Chrome/Edge/Firefox 之一)+ puppeteer渲染Mermaid(自动检测可用浏览器)
渲染脚本:scripts/prd_export.py(调用 scripts/mermaid_render_multi.js)
命令示例 :
python3 scripts/prd_export.py PRD文档.md 输出 PRD文档.docx
阶段十:H5可交互原型图(可选,导出后主动询问)
触发时机 :在PRD文档输出完成后,主动询问用户:「是否需要生成H5可交互原型图?」
询问话术
✅ PRD文档已完成,是否需要生成H5可交互原型图?
- 输入「需要」或「是」→ 生成原型图
- 输入「不需要」或「否」→ 结束流程
如果需要生成H5原型图,请同时告诉我存放路径(例如:`~/Desktop/` 或 `D:\project\`),原型图将保存为 `{产品名称}_prototype.html` 文件。
技术约束
语言限制 :纯 HTML + CSS + JavaScript(原生),不使用 Vue、React、Angular 或任何框架。
零外部依赖 :生成的 HTML 不依赖任何外部 CDN、网络资源或 npm 包。Tailwind CSS 通过脚本预下载并内联到 HTML 中,图标以内联 SVG 嵌入,字体使用系统默认字体。
Tailwind CSS 本地化流程
生成原型图前,无需准备 Tailwind CSS,直接在 HTML 中使用 CDN 链接 <script src="https://cdn.tailwindcss.com"></script> 即可。
第四步:生成 HTML
生成 HTML 时,直接使用 CDN 链接,<script> 标签自带加载容错:
<!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 >
<script src ="https://cdn.tailwindcss.com" > </script >
<style >
</style >
</head >
<body class ="bg-gray-100" >
<script >
</script >
</body >
</html >
关键原则 :
直接使用 CDN :<script src="https://cdn.tailwindcss.com"> 是最可靠的方式,无需本地文件
禁止内联 ~350KB CSS :不再要求将整个 tailwind.css 内联到 <style> 标签
跨平台零配置 :CDN 链接在 Windows/macOS/Linux 下均有效,无需路径适配
页面结构规范
单HTML文件 :所有页面集成在同一个HTML文件中,使用tab/section切换展示不同页面。
文件名命名 :{产品名称}_prototype.html
核心交互原则 :所有页面存在于同一个HTML文件中,页面之间的跳转通过 showPage() 函数切换 section 的显示/隐藏状态来实现,不依赖多文件或服务器。
UI设计规范 :
视觉层次 :使用 shadow-sm/shadow-md 给卡片增加层次感,不要只有纯底色
间距 :页面内 p-4 基础内边距,卡片之间使用 space-y-3(12px间距),组内元素 space-y-4(16px间距)
圆角 :卡片使用 rounded-xl(12px),按钮使用 rounded-lg(8px),输入框使用 rounded-lg
颜色 :bg-white 卡片搭配 bg-gray-50 背景形成对比,操作按钮使用主色 bg-blue-500/bg-blue-600
阴影 :shadow-sm 用于卡片,shadow-lg 用于弹窗/浮层
空状态 :列表为空时显示占位插图和提示文字
触摸反馈 :点击时使用 active:bg-gray-100 提升交互感
页面组织方式 :
<div id ="nav-tabs" class ="flex border-b bg-white sticky top-0 z-10" >
<button onclick ="showPage('login')" class ="tab-btn active flex-1 py-3 text-center border-b-2 border-blue-500 text-blue-500 font-medium" > 登录</button >
<button onclick ="showPage('home')" class ="tab-btn flex-1 py-3 text-center border-b-2 border-transparent text-gray-400 font-medium" > 首页</button >
<button onclick ="showPage('detail')" class ="tab-btn flex-1 py-3 text-center border-b-2 border-transparent text-gray-400 font-medium" > 详情</button >
<button onclick ="showPage('profile')" class ="tab-btn flex-1 py-3 text-center border-b-2 border-transparent text-gray-400 font-medium" > 我的</button >
</div >
<div id ="pages" class ="pb-16" >
<section id ="page-login" class ="page active" >
LOGO
产品名称
欢迎回来,请登录
登录
还没有账号? 立即注册
限时活动
新人专享福利
点击领取专属优惠券
📦
分类
🔥
热榜
🎁
福利
✨
精选
商品标题名称
商品简短描述,介绍核心功能和卖点,最多显示两行
¥99
¥199
📷
¥99
¥199
限时优惠
商品标题名称
这里是商品详细描述,包含核心卖点、功能介绍、规格参数等详细内容。
正品保证
急速发货
售后无忧
收藏
购物车
加入购物车
立即购买
个人中心内容
退出登录
页面模板
<!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 >
<script src ="https://cdn.tailwindcss.com" > </script >
<style >
</style >
</head >
<body class ="bg-gray-100" >
<script >
</script >
</body >
</html >
移动端适配要点
viewport:width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no
触摸目标最小 44×44px
设计基准宽度 750px(微信H5标准)
使用 flex 和 space-y-* 简化布局
底部固定导航使用 fixed bottom-0
页面导航
同一HTML文件内的页面通过 showPage() 函数切换不同 section 的显示状态实现跳转。不使用 window.location.href,不依赖多文件或服务器。
页面间跳转规则 :
列表页 → 点击列表项 → 进入详情页(传 id 参数)
详情页 → 返回按钮 → 返回列表页(保留位置)
表单提交 → 成功后跳转至目标页
底部Tab → 点击直接切换Tab高亮并跳转对应页面
传参方式(同一HTML内) :
<div onclick="goDetail(123)" class ="list-item" >商品A</div>
function goDetail (id ) {
window .historyState = window .historyState || {};
window .historyState .backPage = 'home' ;
window .currentDetailId = id;
showPage ('detail' );
}
<button onclick="goBack()" class ="fixed bottom-0 left-0" >返回</button>
function goBack ( ) {
const back = window .historyState ?.backPage || 'home' ;
showPage (back);
}
跨页面状态管理 :
localStorage .setItem ('isLoggedIn' , 'true' );
localStorage .setItem ('user' , JSON .stringify ({name : '张三' }));
function showPage (name ) {
if (name === 'profile' ) {
const user = JSON .parse (localStorage .getItem ('user' ) || '{}' );
document .querySelector ('#page-profile .username' ).textContent = user.name || '未登录' ;
}
}
常用交互模式
点击切换 :
document .querySelectorAll ('.tab-item' ).forEach (tab => {
tab.addEventListener ('click' , () => {
document .querySelectorAll ('.tab-item' ).forEach (t => t.classList .remove ('bg-blue-500' , 'text-white' ));
tab.classList .add ('bg-blue-500' , 'text-white' );
});
});
表单验证 :
form.addEventListener ('submit' , (e ) => {
e.preventDefault ();
if (!input.value .match (/^1[3-9]\d{9}$/ )) {
alert ('请输入正确手机号' );
return ;
}
});
列表项点击 :
document .querySelectorAll ('.list-item' ).forEach (item => {
item.addEventListener ('click' , () => {
const id = item.dataset .id ;
window .location .href = `detail.html?id=${id} ` ;
});
});
组件库(Tailwind CSS)
Tailwind CSS 已预下载并内联到 HTML 中,无需任何外部依赖。
按钮 :px-6 py-2 bg-blue-500 text-white rounded-full
输入框 :border rounded-lg px-4 py-2 w-full
卡片 :bg-white rounded-xl shadow p-4
底部导航 :fixed bottom-0 flex justify-around bg-white border-t
徽标 :absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full px-1.5 py-0.5
图标使用(内联SVG)
图标尺寸规范 :w-5 h-5(20×20px)或 w-6 h-6(24×24px)。禁止使用 w-8 h-8(32px)或更大尺寸 ——图标应与文字对齐,不应喧宾夺主。
常用图标以内联 SVG 方式嵌入,避免外部依赖:
<svg class ="w-5 h-5" fill ="none" stroke ="currentColor" viewBox ="0 0 24 24" > <path stroke-linecap ="round" stroke-linejoin ="round" stroke-width ="2" d ="M15 19l-7-7 7-7" /> </svg >
<svg class ="w-5 h-5" fill ="none" stroke ="currentColor" viewBox ="0 0 24 24" > <path stroke-linecap ="round" stroke-linejoin ="round" stroke-width ="2" d ="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-4 0a1 1 0 01-1-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 01-1 1h-2" /> </svg >
<svg class ="w-5 h-5" fill ="none" stroke ="currentColor" viewBox ="0 0 24 24" > < = = = = />
输出格式
当用户确认需要生成H5原型时,输出:
完整的单HTML文件(所有页面集成在一个文件中,不是多个html文件)
顶部Tab导航 + 底部固定导航(多Tab应用),点击可跳转到对应页面
每个页面有独立的section容器,showPage()切换
列表项点击跳转详情页、详情页返回按钮返回列表页
表单提交成功后自动跳转
H5原型页面列表 (写在PRD文档末尾或在PRD后单独说明):
**H5原型图已生成**
文件名:`{产品名称}_prototype.html`
**重要**:所有页面存在于同一个HTML文件中,不生成多个html文件,不依赖服务器。直接在浏览器打开即可体验完整交互。
**页面导航**:
- 顶部Tab切换(首页/详情/我的/...)
- 列表页点击 → 跳转详情页
- 详情页底部「返回」按钮 → 返回列表页
- 表单提交成功 → 自动跳转目标页
**技术实现**:
- 纯HTML/CSS/JS,无框架依赖
- Tailwind CSS 本地内联,无CDN依赖
- showPage() 切换 section 显示状态实现页面跳转
- localStorage 存储登录态等简单状态
**打开方式**:在浏览器中打开 `{产品名称}_prototype.html`,点击Tab、列表项、按钮体验完整交互流程。
完整示例:记账APP原型(真实可运行HTML)
以下是一个完整的单文件HTML原型示例,展示了所有交互机制。生成时以此为模板替换具体业务内容:
<!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 > 记账APP原型</title >
<script src ="https://cdn.tailwindcss.com" > </script >
<style >
.page { display : none; }
.page .active { display : block; }
.hidden { display : none !important ; }
.tab-btn { transition : all 0.2s ; }
.list-item { transition : background 0.15s ; }
.list-item :active { background : #f3f4f6 ; }
</style >
</head >
<body class ="bg-gray-100 font-sans" >
首页
记一笔
预算
我的
本月支出
¥2,847.50
环比上月 +12.3%
🍔
餐饮
今天 12:30
-¥38.50
🚇
交通
今天 09:15
-¥4.00
🛒
购物
昨天 20:45
-¥156.00
记一笔
¥
🍔
餐饮
🚇
交通
🛒
购物
🎮
娱乐
日期
今天
保存
本月预算
¥5,000
已花费 57% · 剩余 ¥2,152.50
分类支出
🍔 餐饮 ¥1,234/¥2,000
🛒 购物 ¥980/¥1,500
🚇 交通 ¥234/¥500
👤
未登录
记账第 128 天
月度报告
预算设置
关于我们
账单详情
分类 餐饮
金额 ¥38.50
日期 2026-04-26 12:30
备注 午餐
删除
知识速查
需求优先级三剑客
Kano模型 — 将需求分为基本型(没有就强烈不满)、期望型(越多越满意)、兴奋型(超出预期)。资源有限时优先保基本型。
RICE评分 — RICE = (影响人数 × 转化率提升 × 信心指数) ÷ 工作量(人天)。按分数排序。
MoSCoW分类 — Must必须有(核心路径,无则产品不可用,占比约60%)、Should应该有(重要但可延期,占比约20%)、Could可以有(锦上添花,占比约15%)、Won't这次不做(放未来规划,占比约5%)。
PRD核心结构
PRD的核心不是说清楚要做什么功能,而是说清楚「为什么做、做到什么程度、怎么才算成功」。标准7章:概述→用户与场景→功能需求→非功能需求→数据埋点→风险与依赖→附录。
PRD评审流程
flowchart TD
A([PM起草PRD]) --> B[内部评审\nPM+设计+开发]
B --> C{评审通过?}
C -->|否| D[修改PRD]
D --> A
C -->|是| E[技术方案设计]
E --> F[开发任务分解]
F --> G[Sprint Planning\n纳入迭代]
G --> H([PRD归档])
AARRR海盗模型
Acquisition获取(新增用户数、获客成本CAC)、Activation激活(新用户激活率、首单转化率)、Retention留存(次日/7日/30日留存率)、Revenue变现(ARPU、LTV)、Referral推荐(NPS、裂变系数K因子)。
产品KPI体系
flowchart LR
subgraph 获取 Acquisition
A1[新增用户] --> A2[获客成本CAC]
A1 --> A3[渠道分布]
end
subgraph 激活 Activation
B1[激活率] --> B2[首单转化]
end
subgraph 留存 Retention
C1[次日留存] --> C2[7日留存] --> C3[30日留存]
end
subgraph 变现 Revenue
D1[ARPU] --> D2[LTV]
end
subgraph 推荐 Referral
E1[NPS] --> E2[K因子]
end
A1 --> B1 --> C1 --> D1 --> E1
Agile/Scrum速查
三个角色:Product Owner负责产品待办列表优先级排序、Scrum Master确保团队遵循Scrum流程清除障碍、Development Team跨职能团队负责交付。
五个仪式:Sprint Planning(每Sprint第一天2-4h规划内容)、Daily Standup(每天15min同步进展识别阻塞)、Sprint Review(每Sprint结束演示成果收集反馈)、Sprint Retrospective(每Sprint结束团队内部复盘)、Backlog Refinement(每周准备下个Sprint需求)。
Tailwind CSS H5原型速查
Tailwind CSS 内容已预下载并内联到 HTML 中,生成 H5 原型时无需任何外部依赖。
布局
类名 作用 flex / inline-flexflex 容器 gridgrid 容器 block / inline-block / hidden块级/行内块/隐藏 w-full / w-1/2 / w-32宽度 h-full / h-screen高度 max-w-md / max-w-lg最大宽度 mx-auto水平居中 p-4 / px-4 / py-2内边距 m-4 / mb-4 / mt-2外边距 space-y-4子元素垂直间距 gap-4grid/flex 间距
移动端适配
类名 作用 container响应式容器(max-width breakpoints) sm: / md: / lg:响应式断点前缀 max-width: 750px + mx-auto固定宽度居中(原型基准)
颜色与背景
类名 作用 bg-white / bg-gray-100 / bg-blue-500背景色 text-gray-500 / text-white文字颜色 text-xs / text-sm / text-base / text-lg字号 font-bold / font-medium字重 opacity-50透明度
边框与阴影
类名 作用 border / border-2边框 border-gray-200边框颜色 rounded / rounded-lg / rounded-full圆角 shadow / shadow-lg阴影
定位
类名 作用 relative / absolute / fixed定位方式 top-0 / bottom-0 / left-0 / right-0位置 inset-0四边全定位 z-10层级 fixed bottom-0底部固定导航
交互状态
类名 作用 hover:bg-blue-600悬停状态 active:bg-blue-700按下状态 disabled:opacity-50禁用状态 focus:outline-none聚焦状态
常用 H5 组件
组件 类名组合 主按钮 px-6 py-2 bg-blue-500 text-white rounded-full hover:bg-blue-600次按钮 px-6 py-2 border border-blue-500 text-blue-500 rounded-full输入框 border rounded-lg px-4 py-2 w-full focus:outline-none focus:border-blue-500卡片 bg-white rounded-xl shadow p-4列表项 flex items-center p-4 bg-white border-b border-gray-100底部导航 fixed bottom-0 flex justify-around bg-white border-t border-gray-200 py-2徽标/角标 absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full px-1.5 py-0.5头像 w-10 h-10 rounded-full bg-gray-200Tab 栏 flex border-b bg-whiteTab 项 flex-1 text-center py-3 text-blue-500 border-b-2 border-blue-500
Mermaid图表速查
图表 关键词 用途 流程图 flowchart TD/LR用户核心路径和分支 时序图 sequenceDiagram系统/角色调用顺序 状态图 stateDiagram-v2实体状态流转 甘特图 gantt项目计划和时间线 架构图 flowchart TB系统分层和模块关系 ER图 erDiagram数据库表结构 用户旅程 journey用户体验全流程情感
用户登录流程
flowchart TD
A([开始]) --> B[/输入手机号/]
B --> C{格式校验}
C -->|错误| D[提示格式错误]
D --> B
C -->|正确| E[获取验证码]
E --> F[输入验证码]
F --> G{验证正确?}
G -->|错误| H[提示验证码错误]
H --> F
G -->|正确| I[登录成功]
I --> J([跳转首页])
订单状态流转
stateDiagram-v2
[*] --> 待支付
待支付 --> 已取消: 用户取消/超时
待支付 --> 待发货: 支付成功
待发货 --> 配送中: 商家发货
配送中 --> 待收货: 确认收货
待收货 --> 已完成: 用户确认
待收货 --> 退货中: 申请退货
退货中 --> 已退款: 退款成功
已完成 --> [*]
产品迭代甘特图
gantt
title 产品v2.0迭代计划
dateFormat YYYY-MM-DD
section 产品设计
需求调研 :d1, 2026-01-01, 14d
PRD撰写 :d3, after d1, 10d
section 开发
核心功能开发 :d6, after d3, 30d
辅助功能开发 :d7, after d6, 15d
section 测试
功能测试 :d9, after d6, 20d
回归测试 :d10, after d9, 7d
section 上线
灰度发布 :d11, after d10, 3d
全量发布 :d12, after d11, 2d
用户注册时序图
sequenceDiagram
participant U as 用户
participant FE as 前端
participant BE as 后端服务
participant DB as 数据库
U->>FE: 填写注册信息
FE->>BE: POST /api/register
BE->>DB: 查询是否已注册
DB-->>BE: 返回结果
alt 已注册
BE-->>FE: 错误:手机号已注册
FE-->>U: 显示错误提示
else 未注册
BE->>DB: 创建用户记录
DB-->>BE: 返回用户ID
BE-->>FE: 注册成功
FE-->>U: 跳转验证页
end
系统架构图
flowchart TB
subgraph 客户端层
WEB["Web端 (Vue.js)"]
APP["App端 (React Native)"]
end
subgraph 网关层
GW["API网关 (Kong)"]
end
subgraph 服务层
USER["用户服务"]
ORDER["订单服务"]
PAY["支付服务"]
end
subgraph 数据层
DB[("MySQL")]
REDIS[("Redis")]
MQ["Kafka"]
end
WEB & APP --> GW
GW --> USER & ORDER & PAY
USER & ORDER --> DB
ORDER --> MQ
避坑指南
十大常见误区
误区 正确做法 ❌「我觉得用户需要这个」凭直觉做决策 ✅ 用用户访谈、数据分析验证假设 ❌ 功能越多越好,堆砌功能 ✅ 少即是多,先做核心路径 ❌ PRD写完就丢,不跟进落地 ✅ 持续跟进,上线后跟踪数据 ❌ 忽略技术边界,拍脑袋定排期 ✅ 需求评审拉上技术,确认可行性 ❌ 需求变更口头通知,不走流程 ✅ 需求变更走正式流程,评估影响 ❌ 只看转化率,忽略留存 ✅ 结合留存、NPS、DAU综合评估 ❌ 竞品有什么我就抄什么 ✅ 理解定位,找差异化机会 ❌ 排期过于乐观,不留Buffer ✅ 评估工期乘以1.5-2倍风险系数 ❌ 忽视非功能需求 ✅ 性能/安全/兼容性需求阶段定义 ❌ 上线无监控,不知道效果 ✅ 上线前配置埋点和监控告警
PRD写作常见错误
错误 正确做法 ❌ 背景写成了功能介绍(「我们要做分享功能」) ✅ 背景说清市场/用户/机会 ❌ 目标不可量化(「提升用户体验」) ✅ 「注册转化率从60%提升到75%」 ❌ 验收标准模糊(「界面美观大方」) ✅ 「点击按钮后2秒内显示结果」 ❌ 功能边界不清晰(「等等这个应该不算」) ✅ 明确定义包含/不包含
快速参考
需求优先级
级别 含义 占比 P0 / Must 核心路径,无则不可用 60% P1 / Should 重要但可延期 20% P2 / Could 锦上添花 15% P3 / Won't 未来规划,本次不做 5%
核心指标
维度 指标 活跃 DAU/MAU/日均使用时长 留存 次日/7日/30日留存率 转化 注册转化率/付费转化率 变现 ARPU/LTV/客单价 口碑 NPS/评分/评论数
PRD快速清单
输出格式规范
必须遵守
输出必须是一段干净连贯的文字,不能出现「根据参考文档」「第一层/第二层」「用XX框架分析」等分层标记或内部推理过程
不使用列表编号(如「1. 2. 3.」)做主要叙述方式,用自然段落
代码块用于展示具体内容,如Mermaid图表代码、PRD片段、用户故事模板
Mermaid图表用 ```mermaid 代码块包裹
表格用于对比、矩阵等需要对照的场景
禁用格式
❌ 「根据搜索结果/参考文档/知识库」
❌ 「第一层/第二层/第三层」「认知操作系统」「蒸馏过程」
❌ 「用Kano框架分析」「用RICE评分方法」
❌ 刻意使用大量列表编号(超过5个连续列表项)
回复结构
知识讲解类先用一段话定义核心概念,再说具体方法/工具/场景,最后补充注意事项。需求分析类先确认用户的产品方向/平台/功能,再给出建议用自然段落,最后提供可操作的文档结构或图表代码。文档生成类先确认需求细节,直接输出文档内容含Mermaid图表代码,最后附上填写说明。
附件列表
参考文档共11个,覆盖PM职责、PRD模板、SDLC流程、Mermaid图表、分析框架、技能体系、职业路径、敏捷开发,以及前端组件库和H5原型资源:
references/pm-responsibilities.md — 产品经理职责与职业素养(554行)
references/prd-template.md — PRD产品需求文档模板(489行)
references/sdlc-product-process.md — 软件开发生命周期与产品流程(344行)
references/mermaid-guide.md — Mermaid产品图表绘制规范(490行)
references/pm-framework.md — PM分析框架(AARRR/RFM/SWOT/5W1H/Ansoff/波特五力/留存/竞品/商业模式画布,528行)
references/pm-skills.md — PM技能体系(硬技能/软技能/工具技能/行业知识,476行)
references/pm-career-path.md — PM职业发展路径(AP→CPO/转行/面试/薪资,498行)
references/agile-dev.md — 敏捷开发实践(Scrum/Kanban/用户故事/DoD/技术债务,609行)
references/tailwind-core/ — Tailwind CSS核心文档(9个文件:utility-first/responsive-design/dark-mode/animation/configuration/content-configuration/theme/hover-focus-and-other-states/functions-and-directives)
references/icon-libraries/icon-sources.txt — 图标库资源(Heroicons/Lucide/Iconify/SVGRepo,许可证/CDN信息)
references/h5-prototype/ — H5移动端最佳实践(tailwind安装/browser-support/h5-mobile-best-practices)
来源: 2026-04-24(更新频率:季度更新)
数据库ER图
erDiagram
USER {
bigint id PK
string username
string mobile UK
string email UK
tinyint status
}
ORDER {
bigint id PK
bigint user_id FK
string order_no UK
decimal total_amount
tinyint status
}
USER ||--o{ ORDER : places
用户旅程图
journey
title 用户购物流程
section 购物流程
搜索商品: 5: 用户
浏览详情: 3: 用户
加入购物车: 5: 用户
结算: 4: 用户
选择支付: 4: 用户
支付: 3: 用户
下单成功: 5: 用户
<div class ="p-6 space-y-5" >
<div class ="text-center mb-6" >
<div class ="w-16 h-16 bg-blue-500 rounded-2xl mx-auto mb-3 flex items-center justify-center shadow-lg" >
<span class ="text-white text-2xl font-bold" >
</span >
</div >
<h1 class ="text-xl font-bold text-gray-800" >
</h1 >
<p class ="text-gray-400 text-sm mt-1" >
</p >
</div >
<input type ="text" placeholder ="请输入手机号" class ="w-full border border-gray-200 rounded-xl px-4 py-3.5 bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition" />
<input type ="password" placeholder ="请输入密码" class ="w-full border border-gray-200 rounded-xl px-4 py-3.5 bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition" />
<button onclick ="showPage('home')" class ="w-full bg-blue-500 text-white py-3.5 rounded-xl font-medium shadow-md hover:bg-blue-600 active:bg-blue-700 transition" >
</button >
<p class ="text-center text-sm text-gray-400" >
<span class ="text-blue-500" >
</span >
</p >
</div >
</section >
<section id ="page-home" class ="page hidden" >
<div class ="p-4 space-y-4" >
<div class ="bg-gradient-to-r from-blue-500 to-blue-600 rounded-2xl p-5 text-white shadow-lg" >
<p class ="text-sm opacity-90" >
</p >
<h2 class ="text-lg font-bold mt-1" >
</h2 >
<p class ="text-xs opacity-80 mt-1" >
</p >
</div >
<div class ="grid grid-cols-4 gap-3" >
<div class ="flex flex-col items-center gap-1 py-2" >
<div class ="w-10 h-10 bg-blue-50 rounded-xl flex items-center justify-center" >
<span class ="text-base" >
</span >
</div >
<span class ="text-xs text-gray-500" >
</span >
</div >
<div class ="flex flex-col items-center gap-1 py-2" >
<div class ="w-10 h-10 bg-orange-50 rounded-xl flex items-center justify-center" >
<span class ="text-base" >
</span >
</div >
<span class ="text-xs text-gray-500" >
</span >
</div >
<div class ="flex flex-col items-center gap-1 py-2" >
<div class ="w-10 h-10 bg-green-50 rounded-xl flex items-center justify-center" >
<span class ="text-base" >
</span >
</div >
<span class ="text-xs text-gray-500" >
</span >
</div >
<div class ="flex flex-col items-center gap-1 py-2" >
<div class ="w-10 h-10 bg-purple-50 rounded-xl flex items-center justify-center" >
<span class ="text-base" >
</span >
</div >
<span class ="text-xs text-gray-500" >
</span >
</div >
</div >
<div onclick ="showPage('detail')" class ="bg-white rounded-xl p-4 shadow-sm cursor-pointer hover:shadow-md active:bg-gray-50 transition" >
<div class ="flex gap-3" >
<div class ="w-20 h-20 bg-gray-100 rounded-lg flex-shrink-0" >
</div >
<div class ="flex-1 min-w-0" >
<h3 class ="font-medium text-gray-800 truncate" >
</h3 >
<p class ="text-gray-400 text-xs mt-1 line-clamp-2" >
</p >
<div class ="flex items-baseline gap-1 mt-2" >
<span class ="text-red-500 font-bold" >
</span >
<span class ="text-gray-300 text-xs line-through" >
</span >
</div >
</div >
</div >
</div >
</div >
</section >
<section id ="page-detail" class ="page hidden" >
<div >
<div class ="bg-gray-100 h-64 flex items-center justify-center" >
<span class ="text-gray-300 text-4xl" >
</span >
</div >
<div class ="p-4" >
<div class ="flex items-baseline gap-2" >
<span class ="text-red-500 text-2xl font-bold" >
</span >
<span class ="text-gray-400 text-sm line-through" >
</span >
<span class ="text-orange-500 text-xs bg-orange-50 px-2 py-0.5 rounded" >
</span >
</div >
<h1 class ="text-lg font-bold text-gray-800 mt-3" >
</h1 >
<p class ="text-gray-400 text-sm mt-2" >
</p >
<div class ="flex flex-wrap gap-2 mt-3" >
<span class ="bg-blue-50 text-blue-500 text-xs px-2 py-1 rounded-full" >
</span >
<span class ="bg-green-50 text-green-500 text-xs px-2 py-1 rounded-full" >
</span >
<span class ="bg-purple-50 text-purple-500 text-xs px-2 py-1 rounded-full" >
</span >
</div >
</div >
<div class ="fixed bottom-0 left-0 right-0 bg-white border-t px-4 py-3 flex gap-3 shadow-lg" >
<div class ="flex items-center gap-1 text-gray-400" >
<svg class ="w-5 h-5" fill ="none" stroke ="currentColor" viewBox ="0 0 24 24" >
<path stroke-linecap ="round" stroke-linejoin ="round" stroke-width ="2" d ="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" />
</svg >
<span class ="text-xs" >
</span >
</div >
<div class ="flex items-center gap-1 text-gray-400" >
<svg class ="w-5 h-5" fill ="none" stroke ="currentColor" viewBox ="0 0 24 24" >
<path stroke-linecap ="round" stroke-linejoin ="round" stroke-width ="2" d ="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z" />
</svg >
<span class ="text-xs" >
</span >
</div >
<button onclick ="showPage('home')" class ="flex-1 py-3 bg-gray-100 text-gray-600 rounded-xl font-medium active:bg-gray-200 transition" >
</button >
<button class ="flex-1 py-3 bg-blue-500 text-white rounded-xl font-medium shadow-md active:bg-blue-600 transition" >
</button >
</div >
</div >
</section >
<section id ="page-profile" class ="page hidden" >
<div class ="p-4" >
<div class ="bg-white p-4 rounded-xl shadow mb-4" >
<p class ="text-gray-500" >
</p >
</div >
<button onclick ="showPage('login')" class ="w-full py-3 text-red-500 border border-red-500 rounded-lg" >
</button >
</div >
</section >
</div >
<style >
.page { display : none; }
.page .active { display : block; }
.hidden { display : none !important ; }
</style >
<script >
function showPage (name ) {
document .querySelectorAll ('.page' ).forEach (p => {
p.classList .remove ('active' );
p.classList .add ('hidden' );
});
const target = document .getElementById ('page-' + name);
if (target) {
target.classList .remove ('hidden' );
target.classList .add ('active' );
}
document .querySelectorAll ('.tab-btn' ).forEach (btn => {
if (btn.getAttribute ('onclick' ).includes ("'" + name + "'" )) {
btn.classList .add ('border-blue-500' , 'text-blue-500' );
btn.classList .remove ('border-transparent' , 'text-gray-500' );
} else {
btn.classList .remove ('border-blue-500' , 'text-blue-500' );
btn.classList .add ('border-transparent' , 'text-gray-500' );
}
});
window .scrollTo (0 , 0 );
}
window .addEventListener ('popstate' , () => {
const hash = window .location .hash .replace ('#' , '' ) || 'login' ;
showPage (hash);
});
</script >
path
stroke-linecap
"round"
stroke-linejoin
"round"
stroke-width
"2"
d
"M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
</svg >
<div id ="nav-tabs" class ="flex border-b bg-white sticky top-0 z-10" >
<button onclick ="showPage('home')" class ="tab-btn active flex-1 py-3 text-center border-b-2 border-blue-500 text-blue-500 font-medium" >
</button >
<button onclick ="showPage('add')" class ="tab-btn flex-1 py-3 text-center border-b-2 border-transparent text-gray-500" >
</button >
<button onclick ="showPage('budget')" class ="tab-btn flex-1 py-3 text-center border-b-2 border-transparent text-gray-500" >
</button >
<button onclick ="showPage('profile')" class ="tab-btn flex-1 py-3 text-center border-b-2 border-transparent text-gray-500" >
</button >
</div >
<div id ="pages" class ="pb-20" >
<section id ="page-home" class ="page active" >
<div class ="p-4" >
<div class ="bg-gradient-to-r from-blue-500 to-blue-600 rounded-2xl p-5 text-white mb-4" >
<p class ="text-sm opacity-80" >
</p >
<p class ="text-3xl font-bold mt-1" >
</p >
<p class ="text-sm opacity-80 mt-2" >
</p >
</div >
<div class ="space-y-3" >
<div onclick ="showDetail()" class ="list-item bg-white p-4 rounded-xl shadow cursor-pointer" >
<div class ="flex justify-between items-center" >
<div class ="flex items-center gap-3" >
<div class ="w-10 h-10 bg-orange-100 rounded-full flex items-center justify-center" >
</div >
<div >
<p class ="font-medium" >
</p >
<p class ="text-gray-400 text-sm" >
</p >
</div >
</div >
<p class ="font-bold text-red-500" >
</p >
</div >
</div >
<div onclick ="showDetail()" class ="list-item bg-white p-4 rounded-xl shadow cursor-pointer" >
<div class ="flex justify-between items-center" >
<div class ="flex items-center gap-3" >
<div class ="w-10 h-10 bg-blue-100 rounded-full flex items-center justify-center" >
</div >
<div >
<p class ="font-medium" >
</p >
<p class ="text-gray-400 text-sm" >
</p >
</div >
</div >
<p class ="font-bold text-red-500" >
</p >
</div >
</div >
<div onclick ="showDetail()" class ="list-item bg-white p-4 rounded-xl shadow cursor-pointer" >
<div class ="flex justify-between items-center" >
<div class ="flex items-center gap-3" >
<div class ="w-10 h-10 bg-green-100 rounded-full flex items-center justify-center" >
</div >
<div >
<p class ="font-medium" >
</p >
<p class ="text-gray-400 text-sm" >
</p >
</div >
</div >
<p class ="font-bold text-red-500" >
</p >
</div >
</div >
</div >
</div >
</section >
<section id ="page-add" class ="page hidden" >
<div class ="p-4" >
<div class ="bg-white rounded-2xl p-5 shadow" >
<h2 class ="text-lg font-bold mb-4" >
</h2 >
<div class ="flex items-center gap-2 mb-6 border-b pb-4" >
<span class ="text-2xl font-bold" >
</span >
<input id ="amount-input" type ="number" placeholder ="0.00" class ="text-3xl font-bold flex-1 outline-none" >
</div >
<div class ="grid grid-cols-4 gap-3 mb-6" >
<div onclick ="selectCategory(this, '餐饮')" class ="cat-btn flex flex-col items-center p-3 rounded-xl bg-gray-50 cursor-pointer" >
<span class ="text-2xl" >
</span >
<span class ="text-xs mt-1" >
</span >
</div >
<div onclick ="selectCategory(this, '交通')" class ="cat-btn flex flex-col items-center p-3 rounded-xl bg-gray-50 cursor-pointer" >
<span class ="text-2xl" >
</span >
<span class ="text-xs mt-1" >
</span >
</div >
<div onclick ="selectCategory(this, '购物')" class ="cat-btn flex flex-col items-center p-3 rounded-xl bg-gray-50 cursor-pointer" >
<span class ="text-2xl" >
</span >
<span class ="text-xs mt-1" >
</span >
</div >
<div onclick ="selectCategory(this, '娱乐')" class ="cat-btn flex flex-col items-center p-3 rounded-xl bg-gray-50 cursor-pointer" >
<span class ="text-2xl" >
</span >
<span class ="text-xs mt-1" >
</span >
</div >
</div >
<div class ="flex items-center justify-between py-3 border-t" >
<span class ="text-gray-500" >
</span >
<span id ="date-display" class ="font-medium" >
</span >
</div >
<button onclick ="submitExpense()" class ="w-full py-3 bg-blue-500 text-white rounded-xl font-medium mt-4" >
</button >
</div >
</div >
</section >
<section id ="page-budget" class ="page hidden" >
<div class ="p-4" >
<div class ="bg-white rounded-2xl p-5 shadow mb-4" >
<div class ="flex justify-between items-center mb-3" >
<span class ="text-gray-500" >
</span >
<span class ="font-bold text-xl" >
</span >
</div >
<div class ="w-full bg-gray-200 rounded-full h-3" >
<div class ="bg-blue-500 h-3 rounded-full" style ="width: 57%" >
</div >
</div >
<p class ="text-sm text-gray-400 mt-2" >
</p >
</div >
<div class ="bg-white rounded-2xl p-5 shadow space-y-4" >
<h3 class ="font-bold" >
</h3 >
<div >
<div class ="flex justify-between text-sm mb-1" >
<span >
</span >
<span >
</span >
</div >
<div class ="w-full bg-gray-200 rounded-full h-2" >
<div class ="bg-orange-500 h-2 rounded-full" style ="width: 62%" >
</div >
</div >
</div >
<div >
<div class ="flex justify-between text-sm mb-1" >
<span >
</span >
<span >
</span >
</div >
<div class ="w-full bg-gray-200 rounded-full h-2" >
<div class ="bg-green-500 h-2 rounded-full" style ="width: 65%" >
</div >
</div >
</div >
<div >
<div class ="flex justify-between text-sm mb-1" >
<span >
</span >
<span >
</span >
</div >
<div class ="w-full bg-gray-200 rounded-full h-2" >
<div class ="bg-blue-500 h-2 rounded-full" style ="width: 47%" >
</div >
</div >
</div >
</div >
</div >
</section >
<section id ="page-profile" class ="page hidden" >
<div class ="p-4" >
<div class ="bg-white rounded-2xl p-5 shadow mb-4" >
<div class ="flex items-center gap-4" >
<div class ="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center text-2xl" >
</div >
<div >
<p class ="font-bold text-lg username" >
</p >
<p class ="text-gray-400 text-sm" >
</p >
</div >
</div >
</div >
<div class ="bg-white rounded-2xl shadow overflow-hidden" >
<div class ="flex justify-between items-center p-4 border-b cursor-pointer hover:bg-gray-50" >
<span >
</span >
<svg class ="w-5 h-5 text-gray-400" fill ="none" stroke ="currentColor" viewBox ="0 0 24 24" >
<path stroke-linecap ="round" stroke-linejoin ="round" stroke-width ="2" d ="M9 5l7 7-7 7" />
</svg >
</div >
<div class ="flex justify-between items-center p-4 border-b cursor-pointer hover:bg-gray-50" >
<span >
</span >
<svg class ="w-5 h-5 text-gray-400" fill ="none" stroke ="currentColor" viewBox ="0 0 24 24" >
<path stroke-linecap ="round" stroke-linejoin ="round" stroke-width ="2" d ="M9 5l7 7-7 7" />
</svg >
</div >
<div class ="flex justify-between items-center p-4 cursor-pointer hover:bg-gray-50" >
<span >
</span >
<svg class ="w-5 h-5 text-gray-400" fill ="none" stroke ="currentColor" viewBox ="0 0 24 24" >
<path stroke-linecap ="round" stroke-linejoin ="round" stroke-width ="2" d ="M9 5l7 7-7 7" />
</svg >
</div >
</div >
</div >
</section >
<div id ="detail-overlay" class ="fixed inset-0 bg-black/50 z-50 hidden" >
<div class ="absolute bottom-0 left-0 right-0 bg-white rounded-t-3xl p-5 max-h-[70vh] overflow-y-auto" >
<div class ="flex justify-between items-center mb-4" >
<h2 class ="text-xl font-bold" >
</h2 >
<button onclick ="closeDetail()" class ="text-gray-400 p-2" >
<svg class ="w-6 h-6" fill ="none" stroke ="currentColor" viewBox ="0 0 24 24" >
<path stroke-linecap ="round" stroke-linejoin ="round" stroke-width ="2" d ="M6 18L18 6M6 6l12 12" />
</svg >
</button >
</div >
<div class ="space-y-3 text-sm" >
<div class ="flex justify-between" >
<span class ="text-gray-500" >
</span >
<span >
</span >
</div >
<div class ="flex justify-between" >
<span class ="text-gray-500" >
</span >
<span class ="font-bold text-red-500" >
</span >
</div >
<div class ="flex justify-between" >
<span class ="text-gray-500" >
</span >
<span >
</span >
</div >
<div class ="flex justify-between" >
<span class ="text-gray-500" >
</span >
<span >
</span >
</div >
</div >
<button class ="w-full py-3 bg-red-50 text-red-500 rounded-xl font-medium mt-4" >
</button >
</div >
</div >
</div >
<script >
let selectedCategory = '' ;
function showPage (name ) {
document .querySelectorAll ('.page' ).forEach (p => {
p.classList .remove ('active' );
p.classList .add ('hidden' );
});
const target = document .getElementById ('page-' + name);
if (target) {
target.classList .remove ('hidden' );
target.classList .add ('active' );
}
document .querySelectorAll ('.tab-btn' ).forEach (btn => {
if (btn.getAttribute ('onclick' ).includes ("'" + name + "'" )) {
btn.classList .add ('border-blue-500' , 'text-blue-500' );
btn.classList .remove ('border-transparent' , 'text-gray-500' );
} else {
btn.classList .remove ('border-blue-500' , 'text-blue-500' );
btn.classList .add ('border-transparent' , 'text-gray-500' );
}
});
window .scrollTo (0 , 0 );
}
function selectCategory (el, category ) {
document .querySelectorAll ('.cat-btn' ).forEach (b => b.classList .remove ('bg-blue-100' , 'ring-2' , 'ring-blue-500' ));
el.classList .add ('bg-blue-100' , 'ring-2' , 'ring-blue-500' );
selectedCategory = category;
}
function submitExpense ( ) {
const amount = document .getElementById ('amount-input' ).value ;
if (!amount || !selectedCategory) {
alert ('请填写金额和选择分类' );
return ;
}
alert ('保存成功:¥' + amount + ' (' + selectedCategory + ')' );
showPage ('home' );
}
function showDetail ( ) {
document .getElementById ('detail-overlay' ).classList .remove ('hidden' );
}
function closeDetail ( ) {
document .getElementById ('detail-overlay' ).classList .add ('hidden' );
}
</script >
</body >
</html >