feat: 新增prototype-designer角色,并生成B端与C端高保真UI原型

This commit is contained in:
史悦
2025-09-15 13:26:19 +08:00
parent e3a645d519
commit 8d228527d0
12 changed files with 1345 additions and 125 deletions

19
.kilocode/mcp.json Normal file
View File

@@ -0,0 +1,19 @@
{
"mcpServers": {
"promptx": {
"command": "npx",
"args": [
"-y",
"-f",
"--registry",
"https://registry.npmjs.org",
"dpml-prompt@beta",
"mcp-server"
],
"alwaysAllow": [
"promptx_action",
"promptx_init"
]
}
}
}

View File

@@ -3,96 +3,8 @@
"stateHistory": [ "stateHistory": [
{ {
"from": "initial", "from": "initial",
"command": "init",
"timestamp": "2025-08-12T05:01:27.557Z",
"args": [
{
"workingDirectory": "e:/我的项目/2023年12月21日"
}
]
},
{
"from": "initialized",
"command": "action", "command": "action",
"timestamp": "2025-08-12T05:01:34.425Z", "timestamp": "2025-08-15T00:58:32.454Z",
"args": [
"product-manager"
]
},
{
"from": "role_activated_with_memory",
"command": "action",
"timestamp": "2025-08-12T05:04:00.283Z",
"args": [
"project-manager"
]
},
{
"from": "role_activated_with_memory",
"command": "welcome",
"timestamp": "2025-08-12T05:04:14.605Z",
"args": []
},
{
"from": "service_discovery",
"command": "action",
"timestamp": "2025-08-12T05:04:21.900Z",
"args": [
"project_manager"
]
},
{
"from": "role_activated_with_memory",
"command": "init",
"timestamp": "2025-08-12T05:16:20.919Z",
"args": [
{
"workingDirectory": "e:\\我的项目\\2023年12月21日"
}
]
},
{
"from": "initialized",
"command": "welcome",
"timestamp": "2025-08-12T05:16:37.420Z",
"args": []
},
{
"from": "service_discovery",
"command": "action",
"timestamp": "2025-08-12T05:16:54.449Z",
"args": [
"product-manager"
]
},
{
"from": "role_activated_with_memory",
"command": "action",
"timestamp": "2025-08-12T05:19:49.360Z",
"args": [
"ui_ux_designer"
]
},
{
"from": "role_activated_with_memory",
"command": "action",
"timestamp": "2025-08-12T05:21:26.999Z",
"args": [
"product-manager"
]
},
{
"from": "role_activated_with_memory",
"command": "action",
"timestamp": "2025-08-12T05:28:19.872Z",
"args": [
"ui_ux_designer"
]
},
{
"from": "role_activated_with_memory",
"command": "action",
"timestamp": "2025-08-12T05:36:46.298Z",
"args": [ "args": [
"nuwa" "nuwa"
] ]
@@ -100,43 +12,65 @@
{ {
"from": "role_activated_with_memory", "from": "role_activated_with_memory",
"command": "init", "command": "init",
"timestamp": "2025-08-12T05:37:54.407Z", "timestamp": "2025-08-15T00:58:46.782Z",
"args": [ "args": [
{ {
"workingDirectory": "e:\\我的项目\\2023年12月21日" "workingDirectory": "e:\\我的项目\\2023年12月21日",
"ideType": "vscode"
} }
] ]
}, },
{ {
"from": "initialized", "from": "initialized",
"command": "welcome", "command": "action",
"timestamp": "2025-08-12T05:38:06.826Z", "timestamp": "2025-08-15T00:59:00.012Z",
"args": [] "args": [
"nuwa"
]
}, },
{ {
"from": "service_discovery", "from": "role_activated_with_memory",
"command": "action", "command": "init",
"timestamp": "2025-08-12T05:47:09.951Z", "timestamp": "2025-08-15T01:01:30.679Z",
"args": [ "args": [
"dev-manager" {
"workingDirectory": "e:\\我的项目\\2023年12月21日",
"ideType": "vscode"
}
]
},
{
"from": "initialized",
"command": "action",
"timestamp": "2025-08-15T01:02:09.276Z",
"args": [
"prototype-designer"
] ]
}, },
{ {
"from": "role_activated_with_memory", "from": "role_activated_with_memory",
"command": "action", "command": "action",
"timestamp": "2025-08-12T05:47:40.157Z", "timestamp": "2025-08-15T01:04:54.139Z",
"args": [ "args": [
"dev-manager" "prototype-designer"
] ]
}, },
{ {
"from": "role_activated_with_memory", "from": "role_activated_with_memory",
"command": "action", "command": "action",
"timestamp": "2025-08-12T05:48:23.606Z", "timestamp": "2025-08-15T01:22:41.214Z",
"args": [ "args": [
"dev-manager" "product-manager"
]
},
{
"from": "role_activated_with_memory",
"command": "action",
"timestamp": "2025-08-15T01:23:23.715Z",
"args": [
"prototype-designer"
] ]
} }
], ],
"lastUpdated": "2025-08-12T05:48:23.703Z" "lastUpdated": "2025-08-15T01:23:23.737Z"
} }

View File

@@ -4,9 +4,9 @@
"metadata": { "metadata": {
"version": "2.0.0", "version": "2.0.0",
"description": "project 级资源注册表", "description": "project 级资源注册表",
"createdAt": "2025-08-12T05:37:54.415Z", "createdAt": "2025-08-15T01:01:30.684Z",
"updatedAt": "2025-08-12T05:37:54.422Z", "updatedAt": "2025-08-15T01:01:30.691Z",
"resourceCount": 5 "resourceCount": 9
}, },
"resources": [ "resources": [
{ {
@@ -17,9 +17,9 @@
"description": "执行模式,定义具体的行为模式", "description": "执行模式,定义具体的行为模式",
"reference": "@project://.promptx/resource/domain/product-manager/execution/workflow.execution.md", "reference": "@project://.promptx/resource/domain/product-manager/execution/workflow.execution.md",
"metadata": { "metadata": {
"createdAt": "2025-08-12T05:37:54.418Z", "createdAt": "2025-08-15T01:01:30.686Z",
"updatedAt": "2025-08-12T05:37:54.418Z", "updatedAt": "2025-08-15T01:01:30.686Z",
"scannedAt": "2025-08-12T05:37:54.418Z", "scannedAt": "2025-08-15T01:01:30.686Z",
"path": "domain/product-manager/execution/workflow.execution.md" "path": "domain/product-manager/execution/workflow.execution.md"
} }
}, },
@@ -31,9 +31,9 @@
"description": "专业角色,提供特定领域的专业能力", "description": "专业角色,提供特定领域的专业能力",
"reference": "@project://.promptx/resource/domain/product-manager/product-manager.role.md", "reference": "@project://.promptx/resource/domain/product-manager/product-manager.role.md",
"metadata": { "metadata": {
"createdAt": "2025-08-12T05:37:54.418Z", "createdAt": "2025-08-15T01:01:30.686Z",
"updatedAt": "2025-08-12T05:37:54.418Z", "updatedAt": "2025-08-15T01:01:30.686Z",
"scannedAt": "2025-08-12T05:37:54.418Z", "scannedAt": "2025-08-15T01:01:30.686Z",
"path": "domain/product-manager/product-manager.role.md" "path": "domain/product-manager/product-manager.role.md"
} }
}, },
@@ -45,9 +45,9 @@
"description": "专业角色,提供特定领域的专业能力", "description": "专业角色,提供特定领域的专业能力",
"reference": "@project://.promptx/resource/domain/project_manager/project_manager.role.md", "reference": "@project://.promptx/resource/domain/project_manager/project_manager.role.md",
"metadata": { "metadata": {
"createdAt": "2025-08-12T05:37:54.419Z", "createdAt": "2025-08-15T01:01:30.687Z",
"updatedAt": "2025-08-12T05:37:54.419Z", "updatedAt": "2025-08-15T01:01:30.687Z",
"scannedAt": "2025-08-12T05:37:54.419Z", "scannedAt": "2025-08-15T01:01:30.687Z",
"path": "domain/project_manager/project_manager.role.md" "path": "domain/project_manager/project_manager.role.md"
} }
}, },
@@ -59,9 +59,9 @@
"description": "专业角色,提供特定领域的专业能力", "description": "专业角色,提供特定领域的专业能力",
"reference": "@project://.promptx/resource/domain/ui_ux_designer/ui_ux_designer.role.md", "reference": "@project://.promptx/resource/domain/ui_ux_designer/ui_ux_designer.role.md",
"metadata": { "metadata": {
"createdAt": "2025-08-12T05:37:54.420Z", "createdAt": "2025-08-15T01:01:30.687Z",
"updatedAt": "2025-08-12T05:37:54.420Z", "updatedAt": "2025-08-15T01:01:30.687Z",
"scannedAt": "2025-08-12T05:37:54.420Z", "scannedAt": "2025-08-15T01:01:30.687Z",
"path": "domain/ui_ux_designer/ui_ux_designer.role.md" "path": "domain/ui_ux_designer/ui_ux_designer.role.md"
} }
}, },
@@ -73,21 +73,79 @@
"description": "专业角色,提供特定领域的专业能力", "description": "专业角色,提供特定领域的专业能力",
"reference": "@project://.promptx/resource/role/dev-manager/dev-manager.role.md", "reference": "@project://.promptx/resource/role/dev-manager/dev-manager.role.md",
"metadata": { "metadata": {
"createdAt": "2025-08-12T05:37:54.421Z", "createdAt": "2025-08-15T01:01:30.688Z",
"updatedAt": "2025-08-12T05:37:54.421Z", "updatedAt": "2025-08-15T01:01:30.688Z",
"scannedAt": "2025-08-12T05:37:54.421Z", "scannedAt": "2025-08-15T01:01:30.688Z",
"path": "role/dev-manager/dev-manager.role.md" "path": "role/dev-manager/dev-manager.role.md"
} }
},
{
"id": "design-process",
"source": "project",
"protocol": "execution",
"name": "Design Process 执行模式",
"description": "执行模式,定义具体的行为模式",
"reference": "@project://.promptx/resource/role/prototype-designer/execution/design-process.execution.md",
"metadata": {
"createdAt": "2025-08-15T01:01:30.689Z",
"updatedAt": "2025-08-15T01:01:30.689Z",
"scannedAt": "2025-08-15T01:01:30.689Z",
"path": "role/prototype-designer/execution/design-process.execution.md"
}
},
{
"id": "design-specs",
"source": "project",
"protocol": "knowledge",
"name": "Design Specs 知识库",
"description": "知识库,提供专业知识和信息",
"reference": "@project://.promptx/resource/role/prototype-designer/knowledge/design-specs.knowledge.md",
"metadata": {
"createdAt": "2025-08-15T01:01:30.690Z",
"updatedAt": "2025-08-15T01:01:30.690Z",
"scannedAt": "2025-08-15T01:01:30.690Z",
"path": "role/prototype-designer/knowledge/design-specs.knowledge.md"
}
},
{
"id": "prototype-designer",
"source": "project",
"protocol": "role",
"name": "Prototype Designer 角色",
"description": "专业角色,提供特定领域的专业能力",
"reference": "@project://.promptx/resource/role/prototype-designer/prototype-designer.role.md",
"metadata": {
"createdAt": "2025-08-15T01:01:30.690Z",
"updatedAt": "2025-08-15T01:01:30.690Z",
"scannedAt": "2025-08-15T01:01:30.690Z",
"path": "role/prototype-designer/prototype-designer.role.md"
}
},
{
"id": "design-thinking",
"source": "project",
"protocol": "thought",
"name": "Design Thinking 思维模式",
"description": "思维模式指导AI的思考方式",
"reference": "@project://.promptx/resource/role/prototype-designer/thought/design-thinking.thought.md",
"metadata": {
"createdAt": "2025-08-15T01:01:30.691Z",
"updatedAt": "2025-08-15T01:01:30.691Z",
"scannedAt": "2025-08-15T01:01:30.691Z",
"path": "role/prototype-designer/thought/design-thinking.thought.md"
}
} }
], ],
"stats": { "stats": {
"totalResources": 5, "totalResources": 9,
"byProtocol": { "byProtocol": {
"execution": 1, "execution": 2,
"role": 4 "role": 5,
"knowledge": 1,
"thought": 1
}, },
"bySource": { "bySource": {
"project": 5 "project": 9
} }
} }
} }

View File

@@ -0,0 +1,22 @@
<execution>
<constraint>
## 任务约束
- **输入**: 接收并等待用户提供明确的产品需求、功能设计和信息架构。
- **输出**: 根据用户的具体需求,结合{设计风格}和{技术规格}输出一套UI设计方案并生成一个`UI.html`文件。
- **页面要求**: 遵循用户的具体页面设计和布局要求。
</constraint>
<rule>
## 执行规则
1. **严格遵守技术规格**: 所有设计产出必须严格符合`design-specs.knowledge.md`中定义的技术规格。
2. **代码实现**: 最终产出物为包含所有页面的单个`UI.html`文件。
3. **内容填充**: 使用免费的无版权图片完成空白照片的填充。
4. **布局**: 页面布局需按照“一横排四个”的要求完成。
</rule>
<process>
## 工作流程
1. **需求沟通**: 主动与用户沟通,获取并确认产品需求、目标用户、核心功能和页面布局等信息。
2. **原型设计**: 根据确认的需求进行UI设计并编写HTML和Tailwind CSS代码。
3. **交付与反馈**: 将生成的`UI.html`文件交付给用户,并请求反馈。
4. **迭代修改**: 根据用户的反馈进行修改,直到用户满意为止。
</process>
</execution>

View File

@@ -0,0 +1,11 @@
<knowledge>
## 技术规格清单
- **页面尺寸**: 单个页面尺寸为 375x812px带有描边模拟手机边框。
- **图标**: 引用在线矢量图标库内的图标 (任何图标都不要带有背景色块、底板、外框)。
- **图片**: 使用开源图片网站链接的形式引入 (例如: Unsplash, Pexels)。
- **样式**: 必须引入 Tailwind CSS CDN 来完成。
- **显示**:
- 不要显示状态栏以及时间、信号等信息。
- 不要显示非移动端元素,如滚动条。
- **文字**: 所有文字只可以使用黑色或白色。
</knowledge>

View File

@@ -0,0 +1,15 @@
<role>
<personality>
# 角色:资深原型设计师 & 前端开发工程师
我是一位在设计与前端开发领域拥有丰富经验的专家,致力于在优雅的极简主义美学与强大的功能性之间找到完美的平衡点。
@!thought://design-thinking
</personality>
<principle>
@!execution://design-process
</principle>
<knowledge>
@!knowledge://design-specs
</knowledge>
</role>

View File

@@ -0,0 +1,25 @@
<thought>
<exploration>
## 设计风格探索
- **美学核心**: 优雅的极简主义美学与功能的完美平衡。
- **色彩策略**: 清新柔和的渐变配色与品牌色系浑然一体强调色根据APP类型灵活选择。
- **空间感**: 恰到好处的留白设计,营造轻盈通透的沉浸式体验。
- **信息架构**: 通过微妙的阴影过渡与模块化卡片布局,呈现清晰的信息层级,引导用户视线自然聚焦核心功能。
- **细节打磨**: 精心打磨的圆角、细腻的微交互、舒适的视觉比例,共同提升产品质感。
</exploration>
<reasoning>
## 设计理念推理
- 极简不是简单,而是为了突出核心功能,减少用户认知负荷。
- 色彩和渐变服务于品牌表达和用户情绪引导。
- 留白和布局是构建呼吸感和秩序感的关键。
- 细节决定体验,微交互能创造情感连接。
</reasoning>
<plan>
## 设计执行计划
1. **理解需求**: 深入理解产品经理的功能设计和信息架构。
2. **确立风格**: 根据产品类型(如旅游攻略)确定主色和强调色。
3. **布局优先**: 先进行模块化卡片布局和信息层级规划。
4. **视觉细化**: 填充色彩、图片、图标,并调整间距、圆角等细节。
5. **交互点缀**: 在关键操作上增加细腻的微交互效果。
</plan>
</thought>

View File

@@ -0,0 +1,303 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>绿邻回收 - B端高保真原型</title>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Theme & Fonts -->
<link rel="stylesheet" href="green_neighbor_theme_b.css">
<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@400;500;700&family=Poppins:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<!-- Icons -->
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.min.js"></script>
<!-- Chart.js -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
:root {
--bg-color: var(--background, oklch(0.99 0.01 240));
--fg-color: var(--foreground, oklch(0.1 0.02 250));
--card-color: var(--card, oklch(1 0 0));
--primary-color: var(--primary, oklch(0.6 0.18 250));
--primary-fg-color: var(--primary-foreground, oklch(0.99 0.01 250));
--destructive-color: var(--destructive, oklch(0.7 0.2 25));
--success-color: var(--success, oklch(0.65 0.15 150));
--radius-val: var(--radius, 0.5rem);
--font-sans-val: var(--font-sans, 'Poppins', 'Noto Sans SC', sans-serif);
--shadow-md-val: var(--shadow-md, 0 4px 6px -1px oklch(0.1 0.02 250 / 0.1), 0 2px 4px -2px oklch(0.1 0.02 250 / 0.1));
}
body {
background-color: #e9ebee; /* A neutral desktop background */
font-family: var(--font-sans-val) !important;
color: var(--fg-color) !important;
display: flex;
justify-content: center;
align-items: flex-start;
min-height: 100vh;
padding: 2rem;
}
.mobile-container {
position: relative;
width: 375px;
height: 812px;
}
.mobile-frame {
width: 100%;
height: 100%;
border: 8px solid black;
border-radius: 40px;
background-color: var(--bg-color);
overflow: hidden;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
position: absolute;
top: 0;
left: 0;
display: flex;
flex-direction: column;
transition: transform 0.35s ease-out, opacity 0.35s ease-out;
z-index: 1;
}
.mobile-frame.hidden-right {
transform: translateX(100%);
opacity: 0;
pointer-events: none;
z-index: 0;
}
.mobile-frame.hidden-left {
transform: translateX(-50%);
opacity: 0;
pointer-events: none;
z-index: 0;
}
.screen {
width: 100%;
flex-grow: 1;
overflow-y: auto;
background-color: var(--bg-color);
}
.screen::-webkit-scrollbar { display: none; }
.bottom-nav {
width: 100%;
height: 70px;
background-color: var(--card-color);
border-top: 1px solid var(--border, #eee);
display: flex;
justify-content: space-around;
align-items: center;
flex-shrink: 0;
box-shadow: 0 -4px 10px rgba(0,0,0,0.05);
}
.card {
background-color: var(--card-color);
border-radius: var(--radius-val);
box-shadow: var(--shadow-md-val);
padding: 1.25rem;
}
/* Animations */
@keyframes shake {
10%, 90% { transform: translate3d(-1px, 0, 0); }
20%, 80% { transform: translate3d(2px, 0, 0); }
30%, 50%, 70% { transform: translate3d(-3px, 0, 0); }
40%, 60% { transform: translate3d(3px, 0, 0); }
}
.animate-shake {
animation: shake 0.7s cubic-bezier(.36,.07,.19,.97) both;
animation-iteration-count: 2;
}
</style>
</head>
<body>
<div class="mobile-container">
<!-- Frame 1: Main Screens (Workbench & Bills) -->
<div id="frame-main" class="mobile-frame">
<div id="screen-workbench" class="screen p-5">
<header class="mb-6">
<div class="flex justify-between items-center">
<div>
<h1 class="text-2xl font-bold">李老板</h1>
<p class="text-gray-500">社区便民超市站</p>
</div>
<i data-lucide="log-out" class="text-gray-400"></i>
</div>
</header>
<main>
<section class="text-center my-8">
<button id="start-recycling-btn" class="w-full py-8 rounded-xl text-white shadow-lg flex flex-col items-center justify-center transition-transform active:scale-95" style="background-color: var(--primary-color);">
<i data-lucide="scan-line" class="w-16 h-16"></i>
<span class="block text-2xl font-bold mt-4">开始回收</span>
</button>
</section>
<section class="card mb-4">
<h3 class="font-bold text-lg mb-3">今日汇总</h3>
<div class="grid grid-cols-3 text-center">
<div><p class="text-2xl font-bold">32</p><p class="text-sm text-gray-500">总单数</p></div>
<div><p class="text-2xl font-bold">158.7</p><p class="text-sm text-gray-500">总重量(kg)</p></div>
<div><p class="text-2xl font-bold" style="color: var(--success-color);">¥245.50</p><p class="text-sm text-gray-500">总金额</p></div>
</div>
</section>
<section class="card">
<div class="flex justify-between items-center mb-3">
<h3 class="font-bold text-lg">库存盘点</h3>
<span class="text-sm font-semibold flex items-center px-2 py-1 rounded animate-shake" style="background-color: oklch(var(--destructive) / 0.1); color: var(--destructive-color);">
<i data-lucide="alert-triangle" class="w-4 h-4 mr-1"></i>库存预警
</span>
</div>
<div class="space-y-3">
<div class="grid grid-cols-[auto_1fr_auto] gap-3 items-center">
<span class="font-medium">废纸壳</span>
<div class="w-full bg-gray-200 rounded-full h-2.5"><div style="width: 90%; background-color: var(--destructive-color);" class="h-2.5 rounded-full"></div></div>
<span class="font-bold text-sm">90%</span>
</div>
<div class="grid grid-cols-[auto_1fr_auto] gap-3 items-center">
<span class="font-medium">塑料瓶</span>
<div class="w-full bg-gray-200 rounded-full h-2.5"><div style="width: 45%; background-color: var(--primary-color);" class="h-2.5 rounded-full"></div></div>
<span class="font-bold text-sm">45%</span>
</div>
</div>
<button class="mt-5 w-full font-bold py-3 rounded-lg flex items-center justify-center" style="background-color: var(--secondary, #eee); color: var(--secondary-foreground, #333);"><i data-lucide="truck" class="w-5 h-5 mr-2"></i>一键通知物流交接</button>
</section>
<div class="card mt-4">
<h3 class="font-bold text-lg mb-2"><i data-lucide="bar-chart-3" class="w-5 h-5 mr-2 inline-block" style="color: var(--primary-color);"></i>近7日回收量 (kg)</h3>
<canvas id="bHistoryChart" height="180"></canvas>
</div>
</main>
</div>
<div class="bottom-nav">
<div class="flex flex-col items-center" style="color: var(--primary-color);"><i data-lucide="layout-dashboard"></i><span class="text-xs mt-1 font-bold">工作台</span></div>
<div class="flex flex-col items-center text-gray-400"><i data-lucide="book-marked"></i><span class="text-xs mt-1">账单</span></div>
</div>
</div>
<!-- Frame 2: Recycling Flow -->
<div id="frame-flow" class="mobile-frame hidden-right">
<div class="screen flex flex-col">
<header class="p-4 border-b flex items-center flex-shrink-0">
<button id="back-to-main-btn"><i data-lucide="arrow-left" class="w-6 h-6"></i></button>
<h1 class="font-bold text-xl flex-grow text-center mr-6">回收流程</h1>
</header>
<div class="p-5 flex-grow">
<div class="text-center bg-gray-100 p-3 rounded-lg mb-5">
<p class="text-sm text-gray-600">已识别用户</p>
<p class="font-bold text-2xl text-gray-800">王大妈</p>
</div>
<div class="mb-5">
<label class="font-bold text-lg">1. 选择品类</label>
<div class="grid grid-cols-3 gap-3 mt-2">
<button class="flow-category-btn active bg-blue-600 text-white p-4 rounded-lg font-bold text-lg">纸壳</button>
<button class="flow-category-btn bg-gray-200 text-gray-800 p-4 rounded-lg font-bold text-lg">塑料瓶</button>
<button class="flow-category-btn bg-gray-200 text-gray-800 p-4 rounded-lg font-bold text-lg">旧衣物</button>
</div>
</div>
<div>
<label class="font-bold text-lg">2. 输入重量 (斤)</label>
<input type="number" value="5.8" class="text-center text-6xl font-extrabold w-full mt-2 p-4 border-2 border-gray-200 rounded-lg focus:border-blue-500 focus:outline-none bg-gray-50">
</div>
</div>
<footer class="p-4 bg-white border-t-2 flex-shrink-0">
<div class="text-center">
<p class="text-gray-600">合计金额</p>
<p class="text-5xl font-bold mb-4" style="color: var(--primary-color);">¥4.93</p>
</div>
<button class="w-full text-white font-bold py-4 rounded-lg text-xl flex items-center justify-center active:scale-[0.98] transition-transform" style="background-color: var(--primary-color);">
<i data-lucide="volume-2" class="w-6 h-6 mr-2"></i>
<span>确认并语音播报</span>
</button>
</footer>
</div>
</div>
</div>
<script>
lucide.createIcons();
// Screen/Frame Navigation Logic
const frameMain = document.getElementById('frame-main');
const frameFlow = document.getElementById('frame-flow');
const startRecyclingBtn = document.getElementById('start-recycling-btn');
const backToMainBtn = document.getElementById('back-to-main-btn');
startRecyclingBtn.addEventListener('click', () => {
frameMain.classList.add('hidden-left');
frameFlow.classList.remove('hidden-right');
});
backToMainBtn.addEventListener('click', () => {
frameFlow.classList.add('hidden-right');
frameMain.classList.remove('hidden-left');
});
// Recycling Flow Category Buttons
const categoryBtns = document.querySelectorAll('.flow-category-btn');
categoryBtns.forEach(btn => {
btn.addEventListener('click', () => {
categoryBtns.forEach(b => {
b.classList.remove('active', 'bg-blue-600', 'text-white');
b.classList.add('bg-gray-200', 'text-gray-800');
});
btn.classList.add('active', 'bg-blue-600', 'text-white');
btn.classList.remove('bg-gray-200', 'text-gray-800');
});
});
// Chart.js for B-side
setTimeout(() => {
const bHistoryCtx = document.getElementById('bHistoryChart')?.getContext('2d');
if (bHistoryCtx) {
new Chart(bHistoryCtx, {
type: 'line',
data: {
labels: ['8/09', '8/10', '8/11', '8/12', '8/13', '8/14', '8/15'],
datasets: [{
label: '回收总量 (kg)',
data: [120, 150, 135, 180, 165, 210, 158.7],
fill: true,
backgroundColor: oklch(0.6 0.18 250 / 0.1),
borderColor: 'var(--chart-1)',
tension: 0.3,
pointBackgroundColor: 'var(--chart-1)',
pointRadius: 4,
pointHoverRadius: 6
}]
},
options: {
responsive: true,
plugins: { legend: { display: false } },
scales: {
y: { beginAtZero: false, grid: { drawBorder: false } },
x: { grid: { display: false } }
}
}
});
}
}, 100);
</script>
</body>
</html>

View File

@@ -0,0 +1,358 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>绿邻回收 - C端高保真原型</title>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Theme & Fonts -->
<link rel="stylesheet" href="green_neighbor_theme_c.css">
<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@400;500;700&family=Poppins:wght@400;500;600;700&display=swap" rel="stylesheet">
<!-- Icons -->
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.min.js"></script>
<!-- Chart.js -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
:root {
/* Mapped from theme file for easy access in this style block */
--bg-color: var(--background, oklch(0.99 0.01 240));
--fg-color: var(--foreground, oklch(0.15 0.01 240));
--card-color: var(--card, oklch(1 0 0));
--primary-color: var(--primary, oklch(0.65 0.15 150));
--primary-fg-color: var(--primary-foreground, oklch(0.98 0.01 150));
--secondary-color: var(--secondary, oklch(0.9 0.18 85));
--muted-fg-color: var(--muted-foreground, oklch(0.55 0.01 240));
--radius-val: var(--radius, 0.75rem);
--font-sans-val: var(--font-sans, 'Poppins', 'Noto Sans SC', sans-serif);
--shadow-md-val: var(--shadow-md, 0 4px 6px -1px oklch(0.15 0.01 240 / 0.1), 0 2px 4px -2px oklch(0.15 0.01 240 / 0.1));
}
body {
background-color: #e9ebee; /* A neutral desktop background */
font-family: var(--font-sans-val) !important;
color: var(--fg-color) !important;
display: flex;
justify-content: center;
align-items: flex-start;
min-height: 100vh;
padding: 2rem;
}
.mobile-frame {
width: 375px;
height: 812px;
border: 8px solid black;
border-radius: 40px;
background-color: var(--bg-color);
overflow: hidden;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
position: relative;
display: flex;
flex-direction: column;
}
.screen {
width: 100%;
flex-grow: 1;
overflow-y: auto;
display: none; /* Hidden by default */
}
.screen.active {
display: block; /* Show active screen */
}
.screen::-webkit-scrollbar { display: none; }
.bottom-nav {
width: 100%;
height: 70px; /* Increased height for better touch area */
background-color: var(--card-color);
border-top: 1px solid var(--border, #eee);
display: flex;
justify-content: space-around;
align-items: center;
flex-shrink: 0;
box-shadow: 0 -4px 10px rgba(0,0,0,0.05);
}
.nav-item {
display: flex;
flex-direction: column;
align-items: center;
font-size: 12px;
font-weight: 500;
color: var(--muted-fg-color);
cursor: pointer;
transition: color 0.2s ease-in-out, transform 0.2s ease-in-out;
}
.nav-item:hover {
color: var(--primary-color);
transform: translateY(-2px);
}
.nav-item.active {
color: var(--primary-color);
}
.card {
background-color: var(--card-color);
border-radius: var(--radius-val);
box-shadow: var(--shadow-md-val);
padding: 1.25rem;
margin-bottom: 1rem;
}
/* Animations */
@keyframes slide-up-in {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animate-slide-up-in {
animation: slide-up-in 0.5s ease-out forwards;
}
.stagger-1 { animation-delay: 100ms; }
.stagger-2 { animation-delay: 200ms; }
.stagger-3 { animation-delay: 300ms; }
@keyframes pulse {
0%, 100% {
transform: scale(1);
box-shadow: var(--shadow-lg-val);
}
50% {
transform: scale(1.02);
box-shadow: var(--shadow-xl-val);
}
}
.animate-pulse-gentle {
animation: pulse 2.5s infinite ease-in-out;
}
</style>
</head>
<body>
<div class="mobile-frame">
<!-- Screen: Home -->
<div id="screen-home" class="screen active p-5">
<header class="flex items-center mb-6 animate-slide-up-in">
<img src="https://images.unsplash.com/photo-1529665253569-6d01c0eaf7b6?q=80&w=40&auto=format&fit=crop" class="w-10 h-10 rounded-full object-cover mr-3" alt="avatar">
<div>
<p class="font-medium text-lg leading-tight">欢迎, 王大妈!</p>
<p class="text-sm text-gray-500">今天也是环保的一天</p>
</div>
</header>
<main>
<section class="text-center my-8 animate-slide-up-in stagger-1">
<button class="w-full py-8 rounded-2xl text-white shadow-lg flex flex-col items-center justify-center animate-pulse-gentle" style="background-color: var(--primary-color);">
<i data-lucide="qr-code" class="w-16 h-16"></i>
<span class="block text-2xl font-bold mt-4">我的卖品码</span>
</button>
<p class="text-center text-sm text-gray-500 mt-3">向小站站长出示此码,即可开始回收</p>
</section>
<section class="card animate-slide-up-in stagger-2">
<h3 class="font-bold text-lg mb-3 flex items-center">
<i data-lucide="tag" class="w-5 h-5 mr-2" style="color: var(--primary-color);"></i>
今日回收价
</h3>
<div class="space-y-3 text-lg">
<div class="flex justify-between items-baseline">
<span class="font-medium">废纸壳</span>
<span class="font-bold" style="color: var(--primary-color);">0.85 <span class="text-sm font-normal">元/斤</span></span>
</div>
<div class="flex justify-between items-baseline">
<span class="font-medium">塑料瓶</span>
<span class="font-bold" style="color: var(--primary-color);">0.10 <span class="text-sm font-normal">元/个</span></span>
</div>
<div class="flex justify-between items-baseline">
<span class="font-medium">旧衣物</span>
<span class="font-bold" style="color: var(--primary-color);">0.50 <span class="text-sm font-normal">元/斤</span></span>
</div>
</div>
</section>
<section class="card animate-slide-up-in stagger-3">
<h3 class="font-bold text-lg mb-4 flex items-center">
<i data-lucide="store" class="w-5 h-5 mr-2" style="color: var(--primary-color);"></i>
附近小站
</h3>
<div class="space-y-4">
<div class="flex items-center">
<div class="flex-grow">
<p class="font-bold">社区便民超市</p>
<p class="text-sm text-gray-500">距离您 200米</p>
</div>
<span class="text-sm font-semibold px-3 py-1 rounded-full" style="background-color: var(--secondary-color); color: var(--secondary-foreground);">营业中</span>
</div>
<div class="flex items-center">
<div class="flex-grow">
<p class="font-bold">好邻居快递驿站</p>
<p class="text-sm text-gray-500">距离您 500米</p>
</div>
<span class="text-sm font-semibold text-gray-500 bg-gray-200 px-3 py-1 rounded-full">休息中</span>
</div>
</div>
</section>
</main>
</div>
<!-- Screen: My -->
<div id="screen-my" class="screen p-5">
<header class="text-center pt-4 mb-6">
<img src="https://images.unsplash.com/photo-1529665253569-6d01c0eaf7b6?q=80&w=80&auto=format&fit=crop" class="w-20 h-20 rounded-full object-cover mx-auto mb-3 border-4 border-white shadow-lg" alt="avatar">
<h2 class="text-2xl font-bold">王大妈</h2>
<p class="text-gray-500 text-sm">环保积分: 1,280</p>
</header>
<main>
<section class="text-white p-6 rounded-2xl shadow-lg text-center mb-6" style="background: linear-gradient(45deg, var(--primary-color), oklch(0.7 0.15 140));">
<p class="text-lg opacity-90">我的余额 (元)</p>
<p class="text-5xl font-bold my-2">128.50</p>
<button class="mt-2 bg-white/20 hover:bg-white/30 text-white font-bold py-2 px-6 rounded-full text-sm">去提现</button>
</section>
<section class="space-y-3 text-lg">
<div class="flex justify-between items-center p-4 card">
<div class="flex items-center"><i data-lucide="receipt" class="w-6 h-6 mr-4" style="color: var(--primary-color);"></i><span>交易记录</span></div>
<i data-lucide="chevron-right" class="text-gray-400"></i>
</div>
<div class="flex justify-between items-center p-4 card">
<div class="flex items-center"><i data-lucide="message-square" class="w-6 h-6 mr-4" style="color: var(--primary-color);"></i><span>联系客服</span></div>
<i data-lucide="chevron-right" class="text-gray-400"></i>
</div>
</section>
<div class="card mt-6">
<h3 class="font-bold text-lg mb-2 flex items-center"><i data-lucide="pie-chart" class="w-5 h-5 mr-2" style="color: var(--primary-color);"></i>我的回收分布</h3>
<canvas id="cUserChart" height="180"></canvas>
</div>
<div class="card mt-2">
<h3 class="font-bold text-lg mb-2 flex items-center"><i data-lucide="bar-chart-3" class="w-5 h-5 mr-2" style="color: var(--primary-color);"></i>历史收入</h3>
<canvas id="cHistoryChart" height="180"></canvas>
</div>
</main>
</div>
<!-- Bottom Navigation -->
<div class="bottom-nav">
<div class="nav-item active" data-screen="home">
<i data-lucide="home"></i>
<span class="mt-1">首页</span>
</div>
<div class="nav-item" data-screen="my">
<i data-lucide="user-round"></i>
<span class="mt-1">我的</span>
</div>
</div>
</div>
<script>
// Initialize Lucide Icons
lucide.createIcons();
// Screen Navigation
const navItems = document.querySelectorAll('.nav-item');
const screens = document.querySelectorAll('.screen');
navItems.forEach(item => {
item.addEventListener('click', () => {
// Update nav active state
navItems.forEach(i => i.classList.remove('active'));
item.classList.add('active');
// Show the correct screen
const screenId = `screen-${item.dataset.screen}`;
screens.forEach(s => {
s.classList.remove('active');
if (s.id === screenId) {
s.classList.add('active');
// Reset scroll to top when switching
s.scrollTop = 0;
}
});
});
});
// Chart.js Initialization
// We wrap it in a timeout to ensure the canvas is visible when the chart is initialized, preventing rendering issues.
setTimeout(() => {
const chartFont = { family: "'Poppins', 'Noto Sans SC', sans-serif" };
// C端 - 我的回收分布
const cUserCtx = document.getElementById('cUserChart')?.getContext('2d');
if(cUserCtx) {
new Chart(cUserCtx, {
type: 'pie',
data: {
labels: ['废纸壳', '旧衣物', '塑料瓶'],
datasets: [{
label: '回收分布',
data: [60, 25, 15],
backgroundColor: ['var(--chart-1)', 'var(--chart-2)', 'var(--chart-3)'],
borderColor: 'var(--card-color)',
borderWidth: 2,
hoverOffset: 8
}]
},
options: {
responsive: true,
plugins: {
legend: {
position: 'bottom',
labels: { font: chartFont }
}
}
}
});
}
// C端 - 历史收入
const cHistoryCtx = document.getElementById('cHistoryChart')?.getContext('2d');
if(cHistoryCtx) {
new Chart(cHistoryCtx, {
type: 'bar',
data: {
labels: ['8/09', '8/10', '8/11', '8/12', '8/13', '8/14', '8/15'],
datasets: [{
label: '收入 (元)',
data: [5.2, 0, 12.5, 8.0, 0, 12.5, 4.93],
backgroundColor: 'var(--chart-1)',
borderRadius: 6,
}]
},
options: {
responsive: true,
plugins: {
legend: { display: false }
},
scales: {
y: { beginAtZero: true, grid: { drawBorder: false } },
x: { grid: { display: false } }
}
}
});
}
}, 100);
</script>
</body>
</html>

View File

@@ -0,0 +1,45 @@
:root {
--background: oklch(0.99 0.01 240);
--foreground: oklch(0.1 0.02 250);
--card: oklch(1 0 0);
--card-foreground: oklch(0.1 0.02 250);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.1 0.02 250);
--primary: oklch(0.6 0.18 250);
--primary-foreground: oklch(0.99 0.01 250);
--secondary: oklch(0.95 0.02 250);
--secondary-foreground: oklch(0.2 0.1 250);
--muted: oklch(0.96 0.01 240);
--muted-foreground: oklch(0.55 0.02 250);
--accent: oklch(0.97 0.03 250);
--accent-foreground: oklch(0.25 0.1 250);
--destructive: oklch(0.7 0.2 25);
--destructive-foreground: oklch(0.98 0.01 25);
--border: oklch(0.92 0.01 240);
--input: oklch(0.92 0.01 240);
--ring: oklch(0.6 0.18 250);
--success: oklch(0.65 0.15 150);
--chart-1: oklch(0.6 0.18 250);
--chart-2: oklch(0.7 0.2 25);
--chart-3: oklch(0.8 0.18 85);
--chart-4: oklch(0.5 0.1 290);
--chart-5: oklch(0.55 0.1 200);
--sidebar: oklch(0.99 0.01 240);
--sidebar-foreground: oklch(0.1 0.02 250);
--sidebar-primary: oklch(0.6 0.18 250);
--sidebar-primary-foreground: oklch(0.99 0.01 250);
--sidebar-accent: oklch(0.97 0.03 250);
--sidebar-accent-foreground: oklch(0.25 0.1 250);
--sidebar-border: oklch(0.92 0.01 240);
--sidebar-ring: oklch(0.6 0.18 250);
--font-sans: 'Poppins', 'Noto Sans SC', sans-serif;
--font-serif: 'Merriweather', 'Noto Serif SC', serif;
--font-mono: 'Geist Mono', monospace;
--radius: 0.5rem;
--shadow-sm: 0 1px 2px 0 oklch(0.1 0.02 250 / 0.05);
--shadow: 0 1px 3px 0 oklch(0.1 0.02 250 / 0.1), 0 1px 2px -1px oklch(0.1 0.02 250 / 0.1);
--shadow-md: 0 4px 6px -1px oklch(0.1 0.02 250 / 0.1), 0 2px 4px -2px oklch(0.1 0.02 250 / 0.1);
--shadow-lg: 0 10px 15px -3px oklch(0.1 0.02 250 / 0.1), 0 4px 6px -4px oklch(0.1 0.02 250 / 0.1);
--shadow-xl: 0 20px 25px -5px oklch(0.1 0.02 250 / 0.1), 0 8px 10px -6px oklch(0.1 0.02 250 / 0.1);
--shadow-2xl: 0 25px 50px -12px oklch(0.1 0.02 250 / 0.25);
}

View File

@@ -0,0 +1,44 @@
:root {
--background: oklch(0.99 0.01 240);
--foreground: oklch(0.15 0.01 240);
--card: oklch(1 0 0);
--card-foreground: oklch(0.15 0.01 240);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.15 0.01 240);
--primary: oklch(0.65 0.15 150);
--primary-foreground: oklch(0.98 0.01 150);
--secondary: oklch(0.9 0.18 85);
--secondary-foreground: oklch(0.3 0.1 85);
--muted: oklch(0.96 0.01 240);
--muted-foreground: oklch(0.55 0.01 240);
--accent: oklch(0.98 0.02 150);
--accent-foreground: oklch(0.3 0.1 150);
--destructive: oklch(0.7 0.2 20);
--destructive-foreground: oklch(0.98 0.01 20);
--border: oklch(0.92 0.01 240);
--input: oklch(0.92 0.01 240);
--ring: oklch(0.65 0.15 150);
--chart-1: oklch(0.65 0.15 150);
--chart-2: oklch(0.8 0.18 85);
--chart-3: oklch(0.7 0.2 280);
--chart-4: oklch(0.75 0.2 50);
--chart-5: oklch(0.6 0.2 200);
--sidebar: oklch(0.99 0.01 240);
--sidebar-foreground: oklch(0.15 0.01 240);
--sidebar-primary: oklch(0.65 0.15 150);
--sidebar-primary-foreground: oklch(0.98 0.01 150);
--sidebar-accent: oklch(0.98 0.02 150);
--sidebar-accent-foreground: oklch(0.3 0.1 150);
--sidebar-border: oklch(0.92 0.01 240);
--sidebar-ring: oklch(0.65 0.15 150);
--font-sans: 'Poppins', 'Noto Sans SC', sans-serif;
--font-serif: 'Merriweather', 'Noto Serif SC', serif;
--font-mono: 'Geist Mono', monospace;
--radius: 0.75rem;
--shadow-sm: 0 1px 2px 0 oklch(0.15 0.01 240 / 0.05);
--shadow: 0 1px 3px 0 oklch(0.15 0.01 240 / 0.1), 0 1px 2px -1px oklch(0.15 0.01 240 / 0.1);
--shadow-md: 0 4px 6px -1px oklch(0.15 0.01 240 / 0.1), 0 2px 4px -2px oklch(0.15 0.01 240 / 0.1);
--shadow-lg: 0 10px 15px -3px oklch(0.15 0.01 240 / 0.1), 0 4px 6px -4px oklch(0.15 0.01 240 / 0.1);
--shadow-xl: 0 20px 25px -5px oklch(0.15 0.01 240 / 0.1), 0 8px 10px -6px oklch(0.15 0.01 240 / 0.1);
--shadow-2xl: 0 25px 50px -12px oklch(0.15 0.01 240 / 0.25);
}

386
UI.html Normal file
View File

@@ -0,0 +1,386 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>绿邻回收 - 全端原型</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdn.jsdelivr.net/npm/remixicon@2.5.0/fonts/remixicon.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
body {
background-color: #f0f2f5;
}
.mobile-frame {
width: 375px;
height: 812px;
border: 8px solid black;
border-radius: 40px;
background-color: #f7f8fa;
overflow: hidden;
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
position: relative;
display: flex;
flex-direction: column;
}
.screen {
width: 100%;
flex-grow: 1;
overflow-y: auto;
}
.screen::-webkit-scrollbar {
display: none;
}
.bottom-nav {
width: 100%;
height: 60px;
background-color: white;
border-top: 1px solid #e5e7eb;
display: flex;
justify-content: space-around;
align-items: center;
}
.nav-item {
display: flex;
flex-direction: column;
align-items: center;
font-size: 12px;
color: #6b7280;
}
.nav-item.active {
color: #28a745;
}
</style>
</head>
<body>
<div class="w-full flex flex-col items-center p-5">
<!-- C端 分组 -->
<div class="w-full max-w-screen-2xl mb-12">
<h1 class="text-3xl font-bold text-center mb-6 text-gray-700">C端 (居民端)</h1>
<div class="flex flex-wrap justify-center gap-5">
<!-- C端 - 首页 -->
<div class="mobile-frame">
<div class="screen p-4">
<div class="text-center my-8">
<button class="bg-green-500 text-white rounded-lg shadow-lg w-full py-6">
<i class="ri-qr-code-line text-6xl"></i>
<span class="block text-2xl font-bold mt-2">我的卖品码</span>
</button>
<p class="text-center text-sm text-gray-500 mt-2">向小站站长出示此码,即可开始回收</p>
</div>
<div class="bg-white p-4 rounded-lg shadow mb-4">
<h3 class="font-bold text-lg mb-2 flex items-center"><i class="ri-price-tag-3-line mr-2 text-green-500"></i>今日回收价</h3>
<div class="space-y-2 text-lg">
<div class="flex justify-between"><span>废纸壳</span><span class="font-bold text-green-600">0.85 元/斤</span></div>
<div class="flex justify-between"><span>塑料瓶</span><span class="font-bold text-green-600">0.10 元/个</span></div>
<div class="flex justify-between"><span>旧衣物</span><span class="font-bold text-green-600">0.50 元/斤</span></div>
</div>
</div>
<div class="bg-white p-4 rounded-lg shadow">
<h3 class="font-bold text-lg mb-2 flex items-center"><i class="ri-store-2-line mr-2 text-green-500"></i>附近小站</h3>
<div class="space-y-3">
<div class="flex items-center">
<div class="flex-grow">
<p class="font-bold">社区便民超市</p>
<p class="text-sm text-gray-500">距离您 200米</p>
</div>
<span class="text-sm font-semibold text-green-600 bg-green-100 px-2 py-1 rounded-full">营业中</span>
</div>
<div class="flex items-center">
<div class="flex-grow">
<p class="font-bold">好邻居快递驿站</p>
<p class="text-sm text-gray-500">距离您 500米</p>
</div>
<span class="text-sm font-semibold text-gray-500 bg-gray-200 px-2 py-1 rounded-full">休息中</span>
</div>
</div>
</div>
</div>
<div class="bottom-nav">
<div class="nav-item active"><i class="ri-home-4-fill text-2xl"></i><span>首页</span></div>
<div class="nav-item"><i class="ri-user-fill text-2xl"></i><span>我的</span></div>
</div>
</div>
<!-- C端 - 我的页面 -->
<div class="mobile-frame">
<div class="screen p-4">
<div class="flex items-center mb-6">
<img src="https://images.unsplash.com/photo-1529665253569-6d01c0eaf7b6?q=80&w=200&auto=format&fit=crop" class="w-16 h-16 rounded-full object-cover mr-4" alt="avatar">
<div>
<h2 class="text-2xl font-bold">王大妈</h2>
<p class="text-gray-500">欢迎使用绿邻回收</p>
</div>
</div>
<div class="bg-green-500 text-white p-6 rounded-lg shadow-lg text-center mb-6">
<p class="text-lg">我的余额 (元)</p>
<p class="text-5xl font-bold my-2">128.50</p>
<!-- V1.1功能MVP版本中移除 -->
</div>
<div class="space-y-3 text-lg">
<div class="flex justify-between items-center p-4 bg-white rounded-lg shadow-sm">
<div class="flex items-center"><i class="ri-bill-line mr-3 text-green-500"></i><span>交易记录</span></div>
<i class="ri-arrow-right-s-line"></i>
</div>
<div class="flex justify-between items-center p-4 bg-white rounded-lg shadow-sm">
<div class="flex items-center"><i class="ri-customer-service-2-line mr-3 text-green-500"></i><span>联系客服</span></div>
<i class="ri-arrow-right-s-line"></i>
</div>
</div>
<!-- C端图表 -->
<div class="bg-white p-4 rounded-lg shadow mt-4">
<h3 class="font-bold text-lg mb-2 flex items-center"><i class="ri-pie-chart-2-line mr-2 text-green-500"></i>我的回收分布</h3>
<canvas id="cUserChart" height="180"></canvas>
</div>
<div class="bg-white p-4 rounded-lg shadow mt-4">
<h3 class="font-bold text-lg mb-2 flex items-center"><i class="ri-bar-chart-line mr-2 text-green-500"></i>历史收入</h3>
<canvas id="cHistoryChart" height="180"></canvas>
</div>
</div>
<div class="bottom-nav">
<div class="nav-item"><i class="ri-home-4-line text-2xl"></i><span>首页</span></div>
<div class="nav-item active"><i class="ri-user-fill text-2xl"></i><span>我的</span></div>
</div>
</div>
<!-- C端 - 交易记录 -->
<div class="mobile-frame">
<div class="screen">
<div class="p-4 bg-white border-b sticky top-0">
<div class="flex items-center"><i class="ri-arrow-left-s-line text-2xl mr-2"></i><h1 class="font-bold text-xl flex-grow text-center">交易记录</h1></div>
</div>
<!-- 列表有数据时 -->
<div class="p-4 space-y-3">
<div class="bg-white p-3 rounded-lg shadow-sm">
<div class="flex justify-between items-center mb-2"><span class="font-bold">社区便民超市</span><span class="text-xl font-bold text-green-600">+4.93</span></div>
<p class="text-sm text-gray-500">2025-08-15 10:30:45</p>
<div class="text-sm text-gray-600 mt-2 pt-2 border-t"><p>废纸壳: 5.8斤 x 0.85元/斤</p></div>
</div>
<div class="bg-white p-3 rounded-lg shadow-sm">
<div class="flex justify-between items-center mb-2"><span class="font-bold">好邻居快递驿站</span><span class="text-xl font-bold text-green-600">+12.50</span></div>
<p class="text-sm text-gray-500">2025-08-14 16:21:10</p>
<div class="text-sm text-gray-600 mt-2 pt-2 border-t"><p>旧衣物: 25.0斤 x 0.50元/斤</p></div>
</div>
</div>
<!-- 空状态 -->
<div class="p-4 text-center mt-16">
<i class="ri-file-text-line text-6xl text-gray-300"></i>
<p class="mt-4 text-gray-500">您还没有交易记录哦</p>
<p class="text-sm text-gray-400">快去楼下小站卖一次吧!</p>
</div>
</div>
</div>
</div>
</div>
<!-- B端 分组 -->
<div class="w-full max-w-screen-2xl mb-12 border-t pt-8 mt-8">
<h1 class="text-3xl font-bold text-center mb-6 text-gray-700">B端 (小站端)</h1>
<div class="flex flex-wrap justify-center gap-5">
<!-- B端 - 工作台 -->
<div class="mobile-frame">
<div class="screen p-4">
<div class="flex justify-between items-center mb-6">
<div><h2 class="text-2xl font-bold">李老板</h2><p class="text-gray-500">社区便民超市站</p></div>
<i class="ri-logout-box-r-line text-2xl text-gray-500"></i>
</div>
<div class="text-center my-8">
<button class="bg-blue-600 text-white rounded-lg shadow-lg w-full py-6"><i class="ri-scan-2-line text-6xl"></i><span class="block text-2xl font-bold mt-2">开始回收</span></button>
</div>
<div class="bg-white p-4 rounded-lg shadow mb-4">
<h3 class="font-bold text-lg mb-2 flex items-center"><i class="ri-price-tag-3-line mr-2 text-blue-600"></i>今日回收价</h3>
<div class="space-y-2 text-lg">
<div class="flex justify-between"><span>废纸壳</span><span class="font-bold text-green-600">0.85 元/斤</span></div>
<div class="flex justify-between"><span>塑料瓶</span><span class="font-bold text-green-600">0.10 元/个</span></div>
<div class="flex justify-between"><span>旧衣物</span><span class="font-bold text-green-600">0.50 元/斤</span></div>
</div>
</div>
<div class="bg-white p-4 rounded-lg shadow mb-4">
<h3 class="font-bold text-lg mb-3">今日汇总</h3>
<div class="grid grid-cols-3 text-center">
<div><p class="text-2xl font-bold">32</p><p class="text-sm text-gray-500">总单数</p></div>
<div><p class="text-2xl font-bold">158.7</p><p class="text-sm text-gray-500">总重量 (kg)</p></div>
<div><p class="text-2xl font-bold text-blue-600">¥245.50</p><p class="text-sm text-gray-500">总金额</p></div>
</div>
</div>
<div class="bg-white p-4 rounded-lg shadow">
<div class="flex justify-between items-center mb-3"><h3 class="font-bold text-lg">库存盘点</h3><span class="text-red-500 font-semibold flex items-center"><i class="ri-error-warning-fill mr-1"></i>库存预警</span></div>
<div class="space-y-2">
<div class="flex justify-between items-center"><span>废纸壳</span><div class="w-1/2 bg-gray-200 rounded-full h-2.5"><div class="bg-red-500 h-2.5 rounded-full" style="width: 90%"></div></div><span class="font-bold">90 kg</span></div>
<div class="flex justify-between items-center"><span>塑料瓶</span><div class="w-1/2 bg-gray-200 rounded-full h-2.5"><div class="bg-blue-600 h-2.5 rounded-full" style="width: 45%"></div></div><span class="font-bold">45 kg</span></div>
</div>
<button class="mt-4 w-full bg-blue-100 text-blue-700 font-bold py-3 rounded-lg"><i class="ri-truck-line mr-2"></i>一键通知物流交接</button>
</div>
<!-- B端图表 -->
<div class="bg-white p-4 rounded-lg shadow mt-4">
<h3 class="font-bold text-lg mb-2 flex items-center"><i class="ri-pie-chart-box-line mr-2 text-blue-600"></i>今日品类分布 (按重量)</h3>
<canvas id="bCategoryChart" height="180"></canvas>
</div>
<div class="bg-white p-4 rounded-lg shadow mt-4">
<h3 class="font-bold text-lg mb-2 flex items-center"><i class="ri-bar-chart-box-line mr-2 text-blue-600"></i>近7日回收量 (kg)</h3>
<canvas id="bHistoryChart" height="180"></canvas>
</div>
</div>
<div class="bottom-nav">
<div class="nav-item active"><i class="ri-dashboard-fill text-2xl"></i><span>工作台</span></div>
<div class="nav-item"><i class="ri-bill-fill text-2xl"></i><span>账单</span></div>
</div>
</div>
<!-- B端 - 回收流程 -->
<div class="mobile-frame">
<div class="screen p-4 flex flex-col">
<div class="flex items-center mb-4"><i class="ri-arrow-left-s-line text-2xl mr-2"></i><h1 class="font-bold text-xl flex-grow">回收流程</h1></div>
<div class="text-center bg-gray-100 p-4 rounded-lg mb-4"><p>已识别用户</p><p class="font-bold text-2xl">王大妈</p></div>
<div class="mb-4">
<label class="font-bold text-lg">1. 选择品类</label>
<div class="grid grid-cols-3 gap-3 mt-2">
<button class="bg-blue-600 text-white p-4 rounded-lg font-bold">纸壳</button>
<button class="bg-gray-200 p-4 rounded-lg font-bold">塑料瓶</button>
<button class="bg-gray-200 p-4 rounded-lg font-bold">旧衣物</button>
</div>
</div>
<div class="mb-4">
<label class="font-bold text-lg">2. 输入重量 (斤)</label>
<input type="number" value="5.8" class="text-center text-4xl font-bold w-full mt-2 p-4 border-2 border-gray-300 rounded-lg focus:border-blue-500 focus:outline-none">
</div>
<div class="flex-grow"></div>
<div class="text-center p-4 bg-white border-t-2">
<p class="text-gray-600">合计金额</p><p class="text-4xl font-bold text-blue-600 mb-4">¥4.93</p>
<button class="w-full bg-blue-600 text-white font-bold py-4 rounded-lg text-xl flex items-center justify-center"><i class="ri-volume-up-fill mr-2 text-2xl"></i><span>确认并语音播报</span></button>
</div>
</div>
</div>
<!-- B端 - 账单 -->
<div class="mobile-frame">
<div class="screen">
<div class="p-4 bg-white border-b sticky top-0">
<div class="flex items-center"><i class="ri-arrow-left-s-line text-2xl mr-2"></i><h1 class="font-bold text-xl flex-grow text-center">账单</h1></div>
</div>
<div class="p-4">
<div class="text-center mb-4"><p class="text-gray-500">2025年8月 总收入</p><p class="text-4xl font-bold text-blue-600">¥ 3,450.70</p></div>
<div class="space-y-3">
<div class="bg-white p-3 rounded-lg shadow-sm flex justify-between items-center">
<div><p class="font-bold">8月15日 (今日)</p><p class="text-sm text-gray-500">共 32 笔</p></div>
<span class="text-xl font-bold">¥245.50</span>
</div>
<div class="bg-white p-3 rounded-lg shadow-sm flex justify-between items-center">
<div><p class="font-bold">8月14日</p><p class="text-sm text-gray-500">共 45 笔</p></div>
<span class="text-xl font-bold">¥312.80</span>
</div>
</div>
</div>
</div>
</div>
<!-- B端 - 物流交接单 -->
<div class="mobile-frame">
<div class="screen p-4 flex flex-col items-center">
<h1 class="font-bold text-2xl mt-4 mb-2">出库交接单</h1>
<p class="text-gray-500 mb-6">请向物流司机出示此码</p>
<div class="bg-white p-4 rounded-lg shadow-lg"><img src="https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=STATION_001_OUT_20250815" alt="QR Code"></div>
<div class="w-full mt-6 p-4 bg-white rounded-lg shadow-sm">
<h3 class="font-bold text-lg mb-2">待交接物品</h3>
<div class="space-y-2">
<div class="flex justify-between"><span>废纸壳</span><span class="font-bold">90 kg</span></div>
<div class="flex justify-between"><span>塑料瓶</span><span class="font-bold">45 kg</span></div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 物流端 (V1.1功能MVP版本中移除) -->
</div>
<script>
// C端图表
const cUserCtx = document.getElementById('cUserChart').getContext('2d');
new Chart(cUserCtx, {
type: 'pie',
data: {
labels: ['废纸壳', '旧衣物', '塑料瓶'],
datasets: [{
label: '回收分布',
data: [60, 25, 15],
backgroundColor: ['#28a745', '#20c997', '#6f42c1'],
hoverOffset: 4
}]
},
options: {
responsive: true,
plugins: {
legend: {
position: 'top',
}
}
}
});
const cHistoryCtx = document.getElementById('cHistoryChart').getContext('2d');
new Chart(cHistoryCtx, {
type: 'bar',
data: {
labels: ['8/09', '8/10', '8/11', '8/12', '8/13', '8/14', '8/15'],
datasets: [{
label: '收入 (元)',
data: [5.2, 0, 12.5, 8.0, 0, 12.5, 4.93],
backgroundColor: '#28a745',
}]
},
options: {
responsive: true,
scales: {
y: {
beginAtZero: true
}
}
}
});
// B端图表
const bCategoryCtx = document.getElementById('bCategoryChart').getContext('2d');
new Chart(bCategoryCtx, {
type: 'doughnut',
data: {
labels: ['废纸壳', '塑料瓶', '旧衣物', '其他'],
datasets: [{
label: '品类分布',
data: [90, 45, 20.5, 3.2],
backgroundColor: ['#0d6efd', '#dc3545', '#ffc107', '#6c757d'],
hoverOffset: 4
}]
},
options: {
responsive: true,
plugins: {
legend: {
position: 'top',
}
}
}
});
const bHistoryCtx = document.getElementById('bHistoryChart').getContext('2d');
new Chart(bHistoryCtx, {
type: 'line',
data: {
labels: ['8/09', '8/10', '8/11', '8/12', '8/13', '8/14', '8/15'],
datasets: [{
label: '回收总量 (kg)',
data: [120, 150, 135, 180, 165, 210, 158.7],
fill: false,
borderColor: '#0d6efd',
tension: 0.1
}]
},
options: {
responsive: true,
scales: {
y: {
beginAtZero: true
}
}
}
});
</script>
</body>
</html>