优化个人中心页面,调整导航栏布局以避让右上角胶囊,增强用户体验。更新匹配功能逻辑,增加未开放提示,确保用户在使用时获得明确反馈。
12
.cursor/agent/产品经理/evolution/2026-03-05.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# 产品经理 经验记录 - 2026-03-05
|
||||
|
||||
## 分支冲突后功能完整性分析会议
|
||||
|
||||
- **分支冲突后需优先核对需求文档与实现一致性**:避免「文档在合并中丢失」导致需求与实现脱节。重点核对 `开发文档/1、需求/`、`临时需求池/` 与当前实现是否一致。
|
||||
- **重点确认项**:个人资料页、增值版/普通版计价、找伙伴联系方式完善弹窗等近期需求是否按文档落地。
|
||||
|
||||
## 文章详情 @某人 高亮与一键加好友方案讨论
|
||||
|
||||
- **需求**:文章中支持 @某人,名称高亮、点击添加好友;编辑侧能插入 @用户并落库(含用户 id)。
|
||||
- **验收**:详情页 @ 高亮可点击;点击调起添加好友并提示;管理端插入 @ 后保存再编辑不错位。
|
||||
- **待确认**:添加好友接口 path、入参/出参及业务规则(已是好友、重复请求等);开发文档中接口放置位置。
|
||||
@@ -2,3 +2,5 @@
|
||||
|
||||
| 日期 | 摘要 | 文件 |
|
||||
|------|------|------|
|
||||
| 2026-03-05 | 分支冲突后需求文档与实现一致性核对 | [2026-03-05.md](./2026-03-05.md) |
|
||||
| 2026-03-05 | 文章详情@某人高亮与一键加好友验收标准与待确认 | [2026-03-05.md](./2026-03-05.md) |
|
||||
|
||||
13
.cursor/agent/后端工程师/evolution/2026-03-05.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# 后端工程师 经验记录 - 2026-03-05
|
||||
|
||||
## 分支冲突后功能完整性分析会议
|
||||
|
||||
- **soul-api 被 gitignore 时**:需在 soul-api 所在位置单独确认 git 状态与合并情况,无法从本仓库直接检查。
|
||||
- **重点核对接口**:`/api/miniprogram/orders`(购买记录)、`/api/db/distribution`(分销)是否已实现并挂载到对应路由组。
|
||||
- **建议**:对照「三端需求业务对齐」文档逐项核对接口注册与实现;明确 soul-api 的版本管理与合并策略。
|
||||
|
||||
## 文章详情 @某人 高亮与一键加好友方案讨论
|
||||
|
||||
- **内容存储**:推荐正文内嵌 @ 标记,格式 `@[昵称](userId)`(或 `{{@userId:昵称}}`),后端只存不解析;章节/文章接口原样返回 content。
|
||||
- **添加好友接口**:在 miniprogram 路由组新增,如 `POST /api/miniprogram/friend/add`,入参 `targetUserId`;与存客宝 api_v1 分离,在开发文档中单独说明或 api_v1 新增小节。
|
||||
- **数据模型**:无需单独 mention 表,扩展内容表 content 存带 @ 标记字符串即可。
|
||||
@@ -2,3 +2,5 @@
|
||||
|
||||
| 日期 | 摘要 | 文件 |
|
||||
|------|------|------|
|
||||
| 2026-03-05 | soul-api 合并状态确认;orders、distribution 接口核对 | [2026-03-05.md](./2026-03-05.md) |
|
||||
| 2026-03-05 | 文章详情@某人:content 内嵌 @ 标记、miniprogram 添加好友接口 | [2026-03-05.md](./2026-03-05.md) |
|
||||
|
||||
17
.cursor/agent/团队/evolution/2026-03-05.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# 团队 经验记录 - 2026-03-05
|
||||
|
||||
## 分支冲突后功能完整性分析会议(跨角色共享)
|
||||
|
||||
- **分支冲突后各端需做完整性自查**:
|
||||
- 产品:核对需求文档与实现一致性
|
||||
- 后端:在 soul-api 确认合并状态,核对 orders、distribution 等接口
|
||||
- 管理端:全功能自测,记录 404/异常接口
|
||||
- 小程序:核心流程自测,确认 orders 接口;修正 app.json 格式
|
||||
- 测试:制定「分支合并后回归清单」
|
||||
- **待确认**:`完整的` 分支上的提交是否已全部并入 devlop;soul-api 的版本管理与合并策略。
|
||||
|
||||
## 文章详情 @某人 高亮与一键加好友方案讨论(跨角色共享)
|
||||
|
||||
- **内容格式**:正文内嵌 @ 标记,统一格式 `@[昵称](userId)`(或约定等价格式),后端/管理端/小程序共用。
|
||||
- **添加好友接口**:归属 soul-api 的 miniprogram 组,与存客宝 api_v1 分离;path、入参由后端/产品确认后写入开发文档。
|
||||
- **分工**:管理端编辑侧插入 @ 并写入 content;小程序解析、高亮、点击调添加好友;后端提供章节 content 与添加好友接口。
|
||||
@@ -4,3 +4,4 @@
|
||||
|
||||
| 日期 | 摘要 | 文件 |
|
||||
|------|------|------|
|
||||
| 2026-03-05 | 分支冲突后各端完整性自查流程 | [2026-03-05.md](./2026-03-05.md) |
|
||||
|
||||
13
.cursor/agent/小程序开发工程师/evolution/2026-03-05.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# 小程序开发工程师 经验记录 - 2026-03-05
|
||||
|
||||
## 分支冲突后功能完整性分析会议
|
||||
|
||||
- **app.json 多页面配置**:建议拆行便于维护,避免多页面写在同一行(如第 21 行)。
|
||||
- **分支合并后需做核心流程自测**:登录→阅读→购买→提现→找伙伴→个人资料→VIP,确认无白屏、无接口报错。
|
||||
- **重点确认**:`/api/miniprogram/orders`(购买记录)是否已实现;`完整的` 分支上的优化(如 5a5f0087 卡片边距)是否已并入 devlop。
|
||||
|
||||
## 文章详情 @某人 高亮与一键加好友方案讨论
|
||||
|
||||
- **展示**:阅读页 content 需解析「@ 标记」格式(如 `@[昵称](userId)`),将 @ 片段渲染为高亮可点击 `<text data-user-id>`,点击调 miniprogram 添加好友接口。
|
||||
- **接口**:添加好友接口由后端在 miniprogram 组提供(如 `POST /api/miniprogram/friend/add`),入参 `targetUserId`;不调用 api_v1 存客宝接口。
|
||||
- **实现要点**:在现有 contentParagraphs 按行渲染基础上,对每行再做 mention 解析,得到 text/mention 片段数组后 WXML 分支渲染;不改动现有阅读权限、进度、购买逻辑。
|
||||
@@ -4,3 +4,5 @@
|
||||
|------|------|------|
|
||||
| 2026-02-28 | input 边距口诀、match 资源对接弹窗修正 | [2026-02-28.md](./2026-02-28.md) |
|
||||
| 2026-03-03 | 我的页面卡片区边距优化,16rpx 推荐值 | [2026-03-03.md](./2026-03-03.md) |
|
||||
| 2026-03-05 | 分支合并后核心流程自测;app.json 拆行;orders 接口确认 | [2026-03-05.md](./2026-03-05.md) |
|
||||
| 2026-03-05 | 文章详情@某人高亮与一键加好友(解析@、调添加好友接口) | [2026-03-05.md](./2026-03-05.md) |
|
||||
|
||||
@@ -17,9 +17,11 @@ Soul 创业派对产品定位:面向创业者的社区/工具型小程序。
|
||||
| 2026-02-26 | 项目索引初始化,.cursor 规则优化完成 | 已完成 |
|
||||
| 2026-02-27 | 开发进度同步会议:汇报进度,待办「资料不解锁」补充、≥3 章弹窗明确 | 已完成 |
|
||||
| 2026-02-28 | stitch_soul 需求评审:内容→会员→导师变现路径,待产品补充正式需求文档 | 待续 |
|
||||
| 2026-03-05 | 分支冲突后功能完整性分析会议:核对需求文档与实现一致性 | 待续 |
|
||||
| 2026-03-05 | 文章详情@某人加好友方案讨论:验收标准、添加好友接口 path 待确认 | 待续 |
|
||||
|
||||
> **格式说明**:每次开发后在此追加一行,日期格式 YYYY-MM-DD,状态用:已完成 / 进行中 / 待续 / 搁置
|
||||
|
||||
---
|
||||
|
||||
**最后更新**:2026-02-28
|
||||
**最后更新**:2026-03-05
|
||||
|
||||
@@ -18,9 +18,11 @@ soul-api(Go + Gin + GORM + MySQL)提供三组路由:`/api/miniprogram/*`
|
||||
| 2026-02-27 | 开发进度汇报:computeOrderCommission 会员分润差异化(20%/10%)已实现;vip_roles、vip_activated_at、referral_config 扩展已完成;miniprogram/admin/db 三组路由就绪 | 已完成 |
|
||||
| 2026-02-27 | 开发进度同步会议:进度已同步至开发文档,待办资料完善校验 | 已完成 |
|
||||
| 2026-02-28 | stitch_soul 需求评审:需梳理 chapter/book/vip,设计导师/预约/会员权益模型与接口 | 待续 |
|
||||
| 2026-03-05 | 分支冲突后功能完整性分析会议:在 soul-api 确认合并状态,核对 orders、distribution 接口 | 待续 |
|
||||
| 2026-03-05 | 文章详情@某人加好友方案讨论:content 内嵌 @ 标记、miniprogram 添加好友接口 | 待续 |
|
||||
|
||||
> **格式说明**:每次开发后在此追加一行,日期格式 YYYY-MM-DD,状态用:已完成 / 进行中 / 待续 / 搁置
|
||||
|
||||
---
|
||||
|
||||
**最后更新**:2026-02-28
|
||||
**最后更新**:2026-03-05
|
||||
|
||||
@@ -21,9 +21,11 @@
|
||||
| 2026-02-28 | stitch_soul 需求评审:首页/目录/导师/会员/资料五类页面,待需求与接口确定后分阶段实现 | 待续 |
|
||||
| 2026-02-28 | 吸收经验:input 边距口诀「外边包 view、内部 width 100%」写入 Skill §6;match 资源对接弹窗已按规范修正 | 已完成 |
|
||||
| 2026-03-03 | 吸收经验:我的页面卡片区边距优化,16rpx 为个人中心类页面推荐值,已升级 SKILL §8 | 已完成 |
|
||||
| 2026-03-05 | 分支冲突后功能完整性分析会议:修正 app.json 拆行、核心流程自测、确认 orders 接口 | 待续 |
|
||||
| 2026-03-05 | 文章详情@某人加好友方案讨论:阅读页解析 @、高亮可点击、调添加好友接口 | 待续 |
|
||||
|
||||
> **格式说明**:每次开发后在此追加一行,日期格式 YYYY-MM-DD,状态用:已完成 / 进行中 / 待续 / 搁置
|
||||
|
||||
---
|
||||
|
||||
**最后更新**:2026-03-03
|
||||
**最后更新**:2026-03-05
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
| 2026-02-27 | 测试人员角色与 Skill 初始化 | 已完成 |
|
||||
| 2026-02-27 | 小程序静态审查(API 路径、页面接口、手工验证建议) | 已完成 |
|
||||
| 2026-02-28 | stitch_soul 需求评审:关键场景为阅读/付费/会员/导师预约/资料;待需求确定后补充联调用例 | 待续 |
|
||||
| 2026-03-05 | 分支冲突后功能完整性分析会议:制定「分支合并后回归清单」 | 待续 |
|
||||
| 2026-03-05 | 文章详情@某人加好友方案讨论:@ 展示与添加好友用例、联调与回归 | 待续 |
|
||||
|
||||
---
|
||||
|
||||
**最后更新**:2026-02-28
|
||||
**最后更新**:2026-03-05
|
||||
|
||||
@@ -18,9 +18,11 @@
|
||||
| 2026-02-27 | 开发进度汇报:内容管理仅 API 按钮、推广中心、SetVipModal、VIP 角色管理、推广设置会员分润配置、VIP 排序等均已落地 | 已完成 |
|
||||
| 2026-02-27 | 开发进度同步会议:进度已同步至运营与变更 | 已完成 |
|
||||
| 2026-02-28 | stitch_soul 需求评审:待后端方案确定后规划章节/导师/会员/预约管理页面 | 待续 |
|
||||
| 2026-03-05 | 分支冲突后功能完整性分析会议:全功能自测,记录 404/异常接口 | 待续 |
|
||||
| 2026-03-05 | 文章详情@某人加好友方案讨论:编辑页插入 @用户、保存约定 content 格式 | 待续 |
|
||||
|
||||
> **格式说明**:每次开发后在此追加一行,日期格式 YYYY-MM-DD,状态用:已完成 / 进行中 / 待续 / 搁置
|
||||
|
||||
---
|
||||
|
||||
**最后更新**:2026-02-28
|
||||
**最后更新**:2026-03-05
|
||||
|
||||
12
.cursor/agent/管理端开发工程师/evolution/2026-03-05.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# 管理端开发工程师 经验记录 - 2026-03-05
|
||||
|
||||
## 分支冲突后功能完整性分析会议
|
||||
|
||||
- **路由与页面结构完整时**:主要风险在接口可用性。全功能自测可快速暴露 404 或异常接口。
|
||||
- **重点确认**:`DistributionPage` 调用的 `GET /api/db/distribution` 是否已实现;`OrdersPage` 的订单接口路径是否与 soul-api 一致。
|
||||
- **建议**:分支合并后做一次管理端全流程自测(登录→订单→提现→分销→VIP 角色→导师→配置),记录异常接口反馈后端。
|
||||
|
||||
## 文章详情 @某人 高亮与一键加好友方案讨论
|
||||
|
||||
- **编辑侧**:文章/章节编辑页增加「插入 @用户」,选择用户后插入到光标位置,保存时写入约定格式 content(如 `@[昵称](userId)`);仅调 `/api/admin/*`、`/api/db/*`。
|
||||
- **一致性**:与小程序、后端共用同一 content 格式,避免多套标记;列表/预览可简单高亮或原样显示。
|
||||
@@ -2,3 +2,5 @@
|
||||
|
||||
| 日期 | 摘要 | 文件 |
|
||||
|------|------|------|
|
||||
| 2026-03-05 | 分支合并后全功能自测,404/异常接口记录 | [2026-03-05.md](./2026-03-05.md) |
|
||||
| 2026-03-05 | 文章详情@某人:编辑页插入 @用户、保存约定 content 格式 | [2026-03-05.md](./2026-03-05.md) |
|
||||
|
||||
13
.cursor/agent/软件测试/evolution/2026-03-05.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# 软件测试 经验记录 - 2026-03-05
|
||||
|
||||
## 分支冲突后功能完整性分析会议
|
||||
|
||||
- **分支合并后应制定「回归清单」**:覆盖三端联调关键路径(登录、VIP、阅读、分销、提现、找伙伴、个人资料、导师、购买记录)。
|
||||
- **soul-api 不在仓库时**:需与后端协作确认接口契约,无法在仓库内直接检查。
|
||||
- **多分支合并**:`完整的`、`soul-content`、`yongpxu-soul` 等分支合并结果需确认,各端自测 + 测试抽检。
|
||||
|
||||
## 文章详情 @某人 高亮与一键加好友方案讨论
|
||||
|
||||
- **用例**:无 @ 行为不变;有 @ 高亮且点击调起添加好友并提示;重复点击、未登录、无权限等边界;管理端插入 @ 后保存再编辑不错位。
|
||||
- **联调**:小程序↔章节接口(content 含 @)、小程序↔添加好友接口;管理端↔内容保存与用户列表。
|
||||
- **回归**:阅读页进度、购买、分享等不受 @ 功能影响。
|
||||
@@ -2,3 +2,5 @@
|
||||
|
||||
| 日期 | 摘要 | 文件 |
|
||||
|------|------|------|
|
||||
| 2026-03-05 | 分支合并后回归清单制定;三端联调验证 | [2026-03-05.md](./2026-03-05.md) |
|
||||
| 2026-03-05 | 文章详情@某人:@ 展示与添加好友用例、联调与回归点 | [2026-03-05.md](./2026-03-05.md) |
|
||||
|
||||
122
.cursor/meeting/2026-03-05_分支冲突后功能完整性分析.md
Normal file
@@ -0,0 +1,122 @@
|
||||
# 会议纪要 - 2026-03-05 | 分支冲突后功能完整性分析
|
||||
|
||||
> 本文件由**助理橙子**在会议结束后自动生成。
|
||||
|
||||
---
|
||||
|
||||
## 基本信息
|
||||
|
||||
- **时间**:2026-03-05
|
||||
- **议题**:分支冲突后可能有功能缺失,各成员分析自身项目完整性
|
||||
- **触发方式**:开个会议
|
||||
- **参与角色**:产品经理、后端开发、管理端开发工程师、小程序开发工程师、测试人员
|
||||
|
||||
---
|
||||
|
||||
## 各角色发言
|
||||
|
||||
### 【产品经理】
|
||||
|
||||
- 需求文档(stitch_soul、个人资料页、文章类型等)已记录,需核对 `开发文档/1、需求/`、`临时需求池/` 与实现是否一致
|
||||
- 风险:分支合并后文档可能被覆盖,导致需求与实现脱节
|
||||
- 重点确认:个人资料页、增值版/普通版计价、找伙伴联系方式完善弹窗
|
||||
|
||||
### 【后端开发】
|
||||
|
||||
- soul-api 被 .gitignore 排除,当前仓库无法直接检查
|
||||
- 风险:`/api/miniprogram/orders`、`/api/db/distribution` 等接口是否已实现需在 soul-api 所在位置核对
|
||||
- 建议:在 soul-api 仓库/目录确认合并状态,对照「三端需求业务对齐」逐项核对接口
|
||||
|
||||
### 【管理端开发工程师】
|
||||
|
||||
- 21 个路由与页面一一对应,无缺失;仅调用 `/api/admin/*`、`/api/db/*`,符合边界
|
||||
- 风险:`DistributionPage` 的 `GET /api/db/distribution` 若未实现会 404
|
||||
- 建议:全功能自测,记录 404 或异常接口反馈后端
|
||||
|
||||
### 【小程序开发工程师】
|
||||
|
||||
- 21 个页面均有对应目录和文件,无缺失;全部 `/api/miniprogram/*`,符合边界
|
||||
- 小问题:app.json 第 21 行多页面写同一行,建议拆行
|
||||
- 风险:`/api/miniprogram/orders` 是否已实现;`完整的` 分支上的优化(如 5a5f0087 卡片边距)是否已并入 devlop
|
||||
- 建议:核心流程自测(登录→阅读→购买→提现→找伙伴→个人资料→VIP)
|
||||
|
||||
### 【测试人员】
|
||||
|
||||
- 三端联调需逐项验证;回归清单应覆盖登录、VIP、阅读、分销、提现、找伙伴、个人资料、导师、购买记录
|
||||
- 风险:soul-api 无法在仓库内检查;多分支(完整的、soul-content、yongpxu-soul)合并结果需确认
|
||||
- 建议:制定「分支合并后回归清单」,各端自测 + 抽检
|
||||
|
||||
---
|
||||
|
||||
## 讨论过程
|
||||
|
||||
- **乘风**:reflog 显示 devlop 曾 reset 到 58d4c0b6,后又提交 7e3d36d6;`完整的` 分支有 5a5f0087 等提交,是否已并入 devlop?
|
||||
- **小程序**:需对比 devlop 与 `完整的` 的 miniprogram 差异,确认 2026-03-03 卡片边距等优化是否保留
|
||||
- **后端**:soul-api 不在本仓库,需在 soul-api 所在位置单独确认 git 状态与合并情况
|
||||
- **管理端**:结构完整,主要风险在接口可用性,需联调确认
|
||||
|
||||
---
|
||||
|
||||
## 会议决议
|
||||
|
||||
1. **小程序端**:修正 app.json 第 21 行多页面拆行;核心流程自测;确认 `/api/miniprogram/orders` 是否可用
|
||||
2. **管理端**:全功能自测,记录 404/异常接口反馈后端
|
||||
3. **后端**:在 soul-api 所在仓库确认当前分支与合并状态;核对 orders、distribution 等接口是否已实现并挂载
|
||||
4. **产品**:核对 `开发文档/`、`临时需求池/` 与实现一致性;重点确认个人资料、增值版/普通版、找伙伴
|
||||
5. **测试**:制定「分支合并后回归清单」,覆盖登录、VIP、阅读、分销、提现、找伙伴、个人资料、导师、购买记录
|
||||
6. **待确认**:`完整的` 分支上的提交是否已全部并入 devlop;soul-api 的版本管理与合并策略
|
||||
|
||||
---
|
||||
|
||||
## 待办事项
|
||||
|
||||
| 责任角色 | 任务 | 优先级 | 截止建议 |
|
||||
|---------|------|--------|---------|
|
||||
| 小程序开发工程师 | 修正 app.json 第 21 行;核心流程自测;确认 orders 接口 | 高 | 2026-03-06 |
|
||||
| 管理端开发工程师 | 全功能自测,记录 404/异常接口 | 高 | 2026-03-06 |
|
||||
| 后端开发 | 在 soul-api 确认合并状态;核对 orders、distribution 接口 | 高 | 2026-03-06 |
|
||||
| 产品经理 | 核对需求文档与实现一致性 | 中 | 2026-03-06 |
|
||||
| 测试人员 | 制定「分支合并后回归清单」 | 中 | 2026-03-06 |
|
||||
|
||||
---
|
||||
|
||||
## 问题与作答区
|
||||
|
||||
| # | 问题 | 责任角色 | 作答 |
|
||||
|---|------|---------|------|
|
||||
| 1 | `完整的` 分支上的提交(5a5f0087 等)是否已全部并入 devlop? | 小程序开发工程师 | (待补充) |
|
||||
| 2 | soul-api 的版本管理与合并策略是什么?是否在独立仓库? | 后端开发 | (待补充) |
|
||||
| 3 | `/api/miniprogram/orders` 是否已实现并挂载到 miniprogram 组? | 后端开发 | (待补充) |
|
||||
| 4 | `/api/db/distribution` 是否已实现? | 后端开发 | (待补充) |
|
||||
|
||||
---
|
||||
|
||||
## 各角色经验与业务理解更新
|
||||
|
||||
### 产品经理
|
||||
|
||||
- 分支冲突后需优先核对需求文档与实现一致性,避免「文档在合并中丢失」导致需求脱节
|
||||
|
||||
### 后端开发
|
||||
|
||||
- soul-api 被 gitignore 时,需在 soul-api 所在位置单独确认合并状态;重点核对 orders、distribution 等接口是否已实现并挂载
|
||||
|
||||
### 管理端开发工程师
|
||||
|
||||
- 路由与页面结构完整时,主要风险在接口可用性;全功能自测可快速暴露 404 或异常接口
|
||||
|
||||
### 小程序开发工程师
|
||||
|
||||
- app.json 多页面配置建议拆行便于维护;分支合并后需做核心流程自测,确认 orders 等依赖接口可用
|
||||
|
||||
### 测试人员
|
||||
|
||||
- 分支合并后应制定「回归清单」,覆盖三端联调关键路径;soul-api 不在仓库时需与后端协作确认接口契约
|
||||
|
||||
### 团队共享
|
||||
|
||||
- 分支冲突后各端需做完整性自查:产品核对需求文档、后端核对接口、管理端/小程序核对页面与功能、测试制定回归清单
|
||||
|
||||
---
|
||||
|
||||
*会议纪要由助理橙子生成 | 各角色经验已同步至 `agent/{角色}/evolution/2026-03-05.md`*
|
||||
95
.cursor/meeting/2026-03-05_文章详情@某人加好友方案讨论.md
Normal file
@@ -0,0 +1,95 @@
|
||||
# 会议纪要 - 2026-03-05 | 文章详情 @某人 高亮与一键加好友方案讨论
|
||||
|
||||
> 本文件由**助理橙子**在会议结束后自动生成。
|
||||
|
||||
---
|
||||
|
||||
## 基本信息
|
||||
|
||||
- **时间**:2026-03-05
|
||||
- **议题**:小程序文章详情中「@某人」高亮、点击添加好友;内容编辑时如何插入并存储用户信息(含用户 id),以及是否有更优实现方式
|
||||
- **触发方式**:开一个开发大会,讨论一下
|
||||
- **参与角色**:产品经理、后端开发、管理端开发工程师、小程序开发工程师、测试人员
|
||||
|
||||
---
|
||||
|
||||
## 各角色发言
|
||||
|
||||
### 【产品经理】
|
||||
|
||||
- 需求:文章中可出现「@某某人」,名称高亮,用户点击后执行添加该人为好友;添加好友能力以接口为准。
|
||||
- 用户价值:从内容到人的关系链沉淀,提升互动与转化。
|
||||
- 业务规则:仅支持 @ 已存在用户;展示名以昵称为准;点击统一为「发起添加好友」。
|
||||
- 验收标准:文章详情内 @ 名称高亮且可点击;点击后调用添加好友流程;管理端/编辑侧能插入 @用户 并落库(含用户 id)。
|
||||
|
||||
### 【后端开发】
|
||||
|
||||
- 添加好友接口需在 soul-api 的 **miniprogram** 路由组下提供(如 `POST /api/miniprogram/friend/add` 或 `POST /api/miniprogram/user/add-friend`),入参建议 `targetUserId`;`开发文档/api_v1.md` 当前为存客宝文档,添加好友接口应单独约定或在该文档中新增小节。
|
||||
- 内容存储推荐**方案 A**:正文存带 @ 标记的字符串,如 `@[昵称](userId)` 或 `{{@userId:昵称}}`,后端只存不解析,由前端解析;方案 B(正文 + mentions 位置表)需维护偏移量,正文变更易错位。
|
||||
- 数据模型:内容表扩展 content 存带 @ 标记的字符串即可,无需单独表。
|
||||
|
||||
### 【管理端开发工程师】
|
||||
|
||||
- 文章/章节编辑页增加「插入 @用户」:选择用户后插入到光标位置,保存时写入约定格式的 content;仅调 `/api/admin/*`、`/api/db/*`。
|
||||
- 管理端列表/预览可简单高亮或原样显示,与小程序约定同一 content 格式即可。
|
||||
|
||||
### 【小程序开发工程师】
|
||||
|
||||
- 阅读页当前为按行渲染纯文本;需将 content 解析为「段落 + 片段」(普通文本 / mention),WXML 中对 mention 渲染为可点击 `<text data-user-id>` 并高亮,点击时调用 miniprogram 添加好友接口。
|
||||
- 继续使用现有章节内容接口,保证返回的 content 含 @ 标记;添加好友调用 miniprogram 组新接口。
|
||||
|
||||
### 【测试人员】
|
||||
|
||||
- 用例:无 @ 行为不变;有 @ 高亮且点击调起添加好友并提示;重复点击、未登录、无权限等边界;管理端插入 @ 后保存再编辑,内容与用户 id 不错位。
|
||||
- 联调:小程序 ↔ 章节接口、添加好友接口;管理端 ↔ 内容保存与用户列表。回归:阅读页其他功能不受影响。
|
||||
|
||||
---
|
||||
|
||||
## 讨论过程
|
||||
|
||||
- 一致同意采用「正文内嵌 @ 标记」方案,格式统一为 `@[昵称](userId)`(或约定等价格式)。
|
||||
- 添加好友接口不混用存客宝 api_v1,在 soul-api miniprogram 组新增并在开发文档中明确。
|
||||
- 管理端负责插入 @ 并写入同一 content 格式;小程序负责解析、展示与点击加好友。
|
||||
|
||||
---
|
||||
|
||||
## 会议决议
|
||||
|
||||
1. **内容格式**:正文使用内嵌 @ 标记,格式 `@[昵称](userId)`(或团队约定的等价格式),后端/管理端/小程序统一。
|
||||
2. **小程序**:阅读页解析 content 中 @,渲染为高亮可点击;点击时调 miniprogram 添加好友接口(如 `targetUserId`),并做结果提示。
|
||||
3. **管理端**:编辑页支持「插入 @用户」,保存时写入约定格式的 content。
|
||||
4. **后端**:提供 miniprogram 添加好友接口;章节/文章接口返回的 content 支持带 @ 标记的字符串。
|
||||
5. **待确认**:添加好友接口的最终 path、入参/出参;若已有好友/关注模型需对齐。
|
||||
|
||||
---
|
||||
|
||||
## 待办事项
|
||||
|
||||
| 责任角色 | 任务 | 优先级 | 截止建议 |
|
||||
|---------|------|--------|---------|
|
||||
| 后端开发 | 在 miniprogram 组新增添加好友接口并更新开发文档 | 高 | 排期后 |
|
||||
| 管理端开发工程师 | 文章/章节编辑页支持插入 @用户并保存为约定 content 格式 | 高 | 后端接口与格式确定后 |
|
||||
| 小程序开发工程师 | 阅读页解析 @ 并高亮可点击,点击调添加好友接口 | 高 | 后端接口就绪后 |
|
||||
| 产品经理 | 确认添加好友接口 path 与业务规则(已是好友/重复请求等) | 中 | 开发前 |
|
||||
| 测试人员 | 编写 @ 展示与添加好友用例及回归清单 | 中 | 联调前 |
|
||||
|
||||
---
|
||||
|
||||
## 问题与作答区
|
||||
|
||||
| # | 问题 | 责任角色 | 作答 |
|
||||
|---|------|---------|------|
|
||||
| 1 | 添加好友接口的最终 path、入参(如 targetUserId)、出参及错误码? | 后端开发 | (待补充) |
|
||||
| 2 | 开发文档中添加好友接口放在 api_v1.md 新小节还是单独文档? | 后端/产品 | (待补充) |
|
||||
| 3 | 是否已有「好友/关注」表或接口需与本次对接? | 后端开发 | (待补充) |
|
||||
|
||||
---
|
||||
|
||||
## 各角色经验与业务理解更新
|
||||
|
||||
- 本次会议结论已同步至各角色当日经验文件(见 `agent/{角色}/evolution/2026-03-05.md`)。
|
||||
- 团队共享:内容 @ 采用「正文内嵌 `@[昵称](userId)`」方案;添加好友接口归属 miniprogram 组,与存客宝 api_v1 分离。
|
||||
|
||||
---
|
||||
|
||||
*会议纪要由助理橙子生成 | 各角色经验已同步至 `agent/{角色}/evolution/2026-03-05.md`*
|
||||
78
.cursor/meeting/2026-03-05_超级个体解锁眼睛需求分析.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# 需求分析 - 超级个体解锁眼睛交互改造
|
||||
|
||||
## 基本信息
|
||||
- **时间**:2026-03-05
|
||||
- **需求来源**:用户反馈
|
||||
- **涉及页面**:`miniprogram/pages/member-detail/member-detail`
|
||||
|
||||
---
|
||||
|
||||
## 一、需求描述
|
||||
|
||||
超级个体详情页点击「解锁眼睛」图标时,需调整交互逻辑:
|
||||
|
||||
| 原逻辑 | 新逻辑 |
|
||||
|--------|--------|
|
||||
| 弹窗「成为VIP会员并完成匹配后,即可查看完整联系方式」→ 确认跳转**找伙伴/匹配页** | **不跳转匹配页**;未登录先登录;已登录按权益处理 |
|
||||
|
||||
### 新逻辑细则
|
||||
|
||||
1. **未登录**:弹窗「请先登录」→ 确认跳转「我的」页,用户登录后再返回操作
|
||||
2. **已登录**:
|
||||
- **VIP 会员**(`hasFullBook`):直接解锁,可无限次解锁任意超级个体
|
||||
- **非 VIP**:每人 **1 次免费解锁**,第 2 次起弹窗「免费次数已用完,开通 VIP(¥1980/年)可无限解锁」→ 确认跳转 **VIP 会员页**(1980 付款页)
|
||||
|
||||
---
|
||||
|
||||
## 二、已实现修改(小程序端)
|
||||
|
||||
### 修改文件
|
||||
- `miniprogram/pages/member-detail/member-detail.js`
|
||||
|
||||
### 实现要点
|
||||
|
||||
1. **解锁状态存储**(本地 `wx.setStorageSync`)
|
||||
- Key:`member_unlocks_{userId}`
|
||||
- 值:已解锁的 `memberId` 数组
|
||||
- 用于判断是否已解锁、是否已用掉免费次数
|
||||
|
||||
2. **`unlockContact()` 流程**
|
||||
```
|
||||
点击眼睛
|
||||
→ 未登录:Modal「需要登录」→ 去登录 → switchTab 我的
|
||||
→ 已登录 + VIP:直接解锁并写入存储
|
||||
→ 已登录 + 非VIP + 首次:免费解锁并写入存储
|
||||
→ 已登录 + 非VIP + 非首次:Modal「去开通」→ navigateTo VIP 页
|
||||
```
|
||||
|
||||
3. **`enrichAndFormat` 中 `contactUnlocked` / `wechatUnlocked`**
|
||||
- 原:仅 `isMatched`(匹配过的人)
|
||||
- 现:`isMatched || localUnlocked`(本地解锁列表也视为已解锁)
|
||||
|
||||
---
|
||||
|
||||
## 三、后续可选优化(后端/管理端)
|
||||
|
||||
### 1. 后端持久化(可选)
|
||||
|
||||
当前免费次数与解锁记录存于**本地**,换设备或清缓存会丢失。若需跨设备、防作弊,可:
|
||||
|
||||
- 新增接口:`POST /api/miniprogram/member/unlock`
|
||||
- 入参:`memberId`、`userId`
|
||||
- 逻辑:校验免费次数 / VIP 权益,记录解锁关系
|
||||
- 小程序改为调用该接口,成功后更新本地展示
|
||||
|
||||
### 2. 管理端统计(可选)
|
||||
|
||||
- 统计「超级个体联系方式解锁」次数
|
||||
- 按用户、按超级个体维度统计
|
||||
|
||||
---
|
||||
|
||||
## 四、验收要点
|
||||
|
||||
- [ ] 未登录点击眼睛 → 弹窗「需要登录」→ 确认跳转「我的」
|
||||
- [ ] 已登录 + 非 VIP + 首次 → 免费解锁,展示完整联系方式
|
||||
- [ ] 已登录 + 非 VIP + 第 2 次起 → 弹窗「去开通」→ 确认跳转 VIP 页(¥1980)
|
||||
- [ ] 已登录 + VIP → 直接解锁,不限次数
|
||||
- [ ] 不跳转匹配页
|
||||
@@ -62,3 +62,6 @@ YYYY-MM-DD_会议主题.md
|
||||
| 2026-02-28 | 临时需求池 stitch_soul 需求评审(含页面重构专项·10 张图全覆盖) | 产品、后端、管理端、小程序、测试 | [2026-02-28_临时需求池stitch_soul需求评审.md](2026-02-28_临时需求池stitch_soul需求评审.md) |
|
||||
| 2026-02-28 | 个人资料页实现评估(profile-show / profile-edit) | 产品、后端、管理端、小程序、测试 | [2026-02-28_个人资料页实现评估.md](2026-02-28_个人资料页实现评估.md) |
|
||||
| 2026-02-28 | 文章类型(普通版/增值版)需求分析 | 产品、后端、管理端、小程序、测试 | [2026-02-28_文章类型普通版增值版需求分析.md](2026-02-28_文章类型普通版增值版需求分析.md) |
|
||||
| 2026-03-05 | 分支冲突后功能完整性分析 | 产品、后端、管理端、小程序、测试 | [2026-03-05_分支冲突后功能完整性分析.md](2026-03-05_分支冲突后功能完整性分析.md) |
|
||||
| 2026-03-05 | 超级个体解锁眼睛需求分析 | 产品、小程序 | [2026-03-05_超级个体解锁眼睛需求分析.md](2026-03-05_超级个体解锁眼睛需求分析.md) |
|
||||
| 2026-03-05 | 文章详情 @某人 高亮与一键加好友方案讨论 | 产品、后端、管理端、小程序、测试 | [2026-03-05_文章详情@某人加好友方案讨论.md](2026-03-05_文章详情@某人加好友方案讨论.md) |
|
||||
|
||||
@@ -8,9 +8,9 @@ const { parseScene } = require('./utils/scene.js')
|
||||
App({
|
||||
globalData: {
|
||||
// API基础地址 - 连接真实后端
|
||||
baseUrl: 'https://soulapi.quwanzhi.com',
|
||||
// baseUrl: 'https://soulapi.quwanzhi.com',
|
||||
// baseUrl: 'https://souldev.quwanzhi.com',
|
||||
// baseUrl: 'http://localhost:8080',
|
||||
baseUrl: 'http://localhost:8080',
|
||||
|
||||
|
||||
// 小程序配置 - 真实AppID
|
||||
|
||||
@@ -53,14 +53,6 @@
|
||||
},
|
||||
"usingComponents": {},
|
||||
"__usePrivacyCheck__": true,
|
||||
"permission": {
|
||||
"scope.userLocation": {
|
||||
"desc": "用于匹配附近的书友"
|
||||
}
|
||||
},
|
||||
"requiredPrivateInfos": [
|
||||
"getLocation"
|
||||
],
|
||||
"lazyCodeLoading": "requiredComponents",
|
||||
"style": "v2",
|
||||
"sitemapLocation": "sitemap.json"
|
||||
|
||||
4
miniprogram/assets/icons/edit-gray.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" stroke="#9CA3AF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" stroke="#9CA3AF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 385 B |
4
miniprogram/assets/icons/user-edit-gray.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" stroke="#9CA3AF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="12" cy="7" r="4" stroke="#9CA3AF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 331 B |
@@ -54,7 +54,11 @@ Page({
|
||||
partCount: 0,
|
||||
|
||||
// 加载状态
|
||||
loading: true
|
||||
loading: true,
|
||||
|
||||
// 链接卡若 - 留资弹窗
|
||||
showLeadModal: false,
|
||||
leadPhone: ''
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
@@ -124,8 +128,8 @@ Page({
|
||||
// 不再过滤无头像用户,无头像时用首字母展示
|
||||
members = (Array.isArray(res.data) ? res.data : []).slice(0, 4).map(u => ({
|
||||
id: u.id,
|
||||
name: u.vipName || u.vip_name || u.nickname || '会员',
|
||||
avatar: u.vipAvatar || u.vip_avatar || u.avatar || '',
|
||||
name: u.nickname || u.vipName || u.vip_name || '会员', // 超级个体:用户资料优先,随「我的」修改实时生效
|
||||
avatar: u.avatar || '',
|
||||
isVip: true
|
||||
}))
|
||||
if (members.length > 0) {
|
||||
@@ -301,6 +305,113 @@ Page({
|
||||
wx.navigateTo({ url: '/pages/about/about' })
|
||||
},
|
||||
|
||||
async onLinkKaruo() {
|
||||
const app = getApp()
|
||||
if (!app.globalData.isLoggedIn || !app.globalData.userInfo) {
|
||||
wx.showModal({
|
||||
title: '提示',
|
||||
content: '请先登录后再链接卡若',
|
||||
confirmText: '去登录',
|
||||
cancelText: '取消',
|
||||
success: (res) => {
|
||||
if (res.confirm) wx.switchTab({ url: '/pages/my/my' })
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
const userId = app.globalData.userInfo.id
|
||||
const leadKey = 'karuo_lead_' + userId
|
||||
let phone = (app.globalData.userInfo.phone || '').trim()
|
||||
let wechatId = (app.globalData.userInfo.wechatId || app.globalData.userInfo.wechat_id || '').trim()
|
||||
if (!phone && !wechatId) {
|
||||
try {
|
||||
const profileRes = await app.request({ url: `/api/miniprogram/user/profile?userId=${userId}`, silent: true })
|
||||
if (profileRes?.success && profileRes.data) {
|
||||
phone = (profileRes.data.phone || '').trim()
|
||||
wechatId = (profileRes.data.wechatId || profileRes.data.wechat_id || '').trim()
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
if (phone || wechatId) {
|
||||
const hasLead = wx.getStorageSync(leadKey)
|
||||
if (hasLead) {
|
||||
wx.showToast({ title: '已提交联系方式,卡若会尽快联系你', icon: 'none' })
|
||||
return
|
||||
}
|
||||
wx.showLoading({ title: '提交中...', mask: true })
|
||||
try {
|
||||
const res = await app.request({
|
||||
url: '/api/miniprogram/ckb/lead',
|
||||
method: 'POST',
|
||||
data: {
|
||||
userId,
|
||||
phone: phone || undefined,
|
||||
wechatId: wechatId || undefined,
|
||||
name: (app.globalData.userInfo.nickname || '').trim() || undefined
|
||||
}
|
||||
})
|
||||
wx.hideLoading()
|
||||
if (res && res.success) {
|
||||
wx.setStorageSync(leadKey, true)
|
||||
wx.showToast({ title: res.message || '提交成功', icon: 'success' })
|
||||
} else {
|
||||
wx.showToast({ title: (res && res.message) || '提交失败', icon: 'none' })
|
||||
}
|
||||
} catch (e) {
|
||||
wx.hideLoading()
|
||||
wx.showToast({ title: e.message || '提交失败', icon: 'none' })
|
||||
}
|
||||
return
|
||||
}
|
||||
this.setData({ showLeadModal: true, leadPhone: '' })
|
||||
},
|
||||
|
||||
closeLeadModal() {
|
||||
this.setData({ showLeadModal: false, leadPhone: '' })
|
||||
},
|
||||
|
||||
onLeadPhoneInput(e) {
|
||||
this.setData({ leadPhone: (e.detail.value || '').trim() })
|
||||
},
|
||||
|
||||
async submitLead() {
|
||||
const phone = (this.data.leadPhone || '').trim().replace(/\s/g, '')
|
||||
if (!phone) {
|
||||
wx.showToast({ title: '请输入手机号', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (phone.length < 11) {
|
||||
wx.showToast({ title: '请输入正确的手机号', icon: 'none' })
|
||||
return
|
||||
}
|
||||
const app = getApp()
|
||||
const userId = app.globalData.userInfo?.id
|
||||
const leadKey = userId ? ('karuo_lead_' + userId) : ''
|
||||
wx.showLoading({ title: '提交中...', mask: true })
|
||||
try {
|
||||
const res = await app.request({
|
||||
url: '/api/miniprogram/ckb/lead',
|
||||
method: 'POST',
|
||||
data: {
|
||||
userId,
|
||||
phone,
|
||||
name: (app.globalData.userInfo?.nickname || '').trim() || undefined
|
||||
}
|
||||
})
|
||||
wx.hideLoading()
|
||||
this.setData({ showLeadModal: false, leadPhone: '' })
|
||||
if (res && res.success) {
|
||||
if (leadKey) wx.setStorageSync(leadKey, true)
|
||||
wx.showToast({ title: res.message || '提交成功,卡若会尽快联系您', icon: 'success' })
|
||||
} else {
|
||||
wx.showToast({ title: (res && res.message) || '提交失败', icon: 'none' })
|
||||
}
|
||||
} catch (e) {
|
||||
wx.hideLoading()
|
||||
wx.showToast({ title: e.message || '提交失败', icon: 'none' })
|
||||
}
|
||||
},
|
||||
|
||||
goToSuperList() {
|
||||
wx.switchTab({ url: '/pages/match/match' })
|
||||
},
|
||||
@@ -316,8 +427,22 @@ Page({
|
||||
if (candidates.length === 0) {
|
||||
candidates = chapters.filter(exclude)
|
||||
}
|
||||
// 解析「第X场」用于倒序,最新(场次大)放在最上方
|
||||
const sessionNum = (c) => {
|
||||
const title = c.section_title || c.sectionTitle || c.title || c.chapterTitle || ''
|
||||
const m = title.match(/第\s*(\d+)\s*场/) || title.match(/第(\d+)场/)
|
||||
if (m) return parseInt(m[1], 10)
|
||||
const id = c.id != null ? String(c.id) : ''
|
||||
if (/^\d+$/.test(id)) return parseInt(id, 10)
|
||||
return 0
|
||||
}
|
||||
const latest = candidates
|
||||
.sort((a, b) => new Date(b.updatedAt || b.updated_at || 0) - new Date(a.updatedAt || a.updated_at || 0))
|
||||
.sort((a, b) => {
|
||||
const na = sessionNum(a)
|
||||
const nb = sessionNum(b)
|
||||
if (na !== nb) return nb - na // 场次倒序:最新在上
|
||||
return new Date(b.updatedAt || b.updated_at || 0) - new Date(a.updatedAt || a.updated_at || 0)
|
||||
})
|
||||
.slice(0, 10)
|
||||
.map(c => {
|
||||
const d = new Date(c.updatedAt || c.updated_at || Date.now())
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</view>
|
||||
</view>
|
||||
<view class="header-right">
|
||||
<view class="contact-btn" bindtap="goToAbout">
|
||||
<view class="contact-btn" bindtap="onLinkKaruo">
|
||||
<image class="contact-avatar" src="/assets/images/author-avatar.png" mode="aspectFill"/>
|
||||
<text class="contact-text">点击链接卡若</text>
|
||||
</view>
|
||||
@@ -186,4 +186,17 @@
|
||||
|
||||
<!-- 底部留白 -->
|
||||
<view class="bottom-space"></view>
|
||||
|
||||
<!-- 链接卡若 - 留资弹窗(未填手机/微信号时) -->
|
||||
<view class="lead-mask" wx:if="{{showLeadModal}}" catchtap="closeLeadModal">
|
||||
<view class="lead-box" catchtap="">
|
||||
<text class="lead-title">留下联系方式</text>
|
||||
<text class="lead-desc">方便卡若与您联系</text>
|
||||
<input class="lead-input" placeholder="请输入手机号" type="number" maxlength="11" value="{{leadPhone}}" bindinput="onLeadPhoneInput"/>
|
||||
<view class="lead-actions">
|
||||
<button class="lead-btn lead-btn-cancel" bindtap="closeLeadModal">取消</button>
|
||||
<button class="lead-btn lead-btn-submit" bindtap="submitLead">提交</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -842,3 +842,73 @@
|
||||
.bottom-space {
|
||||
height: 40rpx;
|
||||
}
|
||||
|
||||
/* ===== 链接卡若 - 留资弹窗 ===== */
|
||||
.lead-mask {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 48rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.lead-box {
|
||||
width: 100%;
|
||||
max-width: 560rpx;
|
||||
background: #1C1C1E;
|
||||
border-radius: 24rpx;
|
||||
padding: 48rpx 40rpx;
|
||||
border: 2rpx solid rgba(56, 189, 172, 0.3);
|
||||
}
|
||||
.lead-title {
|
||||
display: block;
|
||||
font-size: 34rpx;
|
||||
font-weight: 600;
|
||||
color: #ffffff;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.lead-desc {
|
||||
display: block;
|
||||
font-size: 26rpx;
|
||||
color: #A0AEC0;
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
.lead-input {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
background: #0a1628;
|
||||
border: 2rpx solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 16rpx;
|
||||
padding: 0 24rpx;
|
||||
box-sizing: border-box;
|
||||
font-size: 30rpx;
|
||||
color: #ffffff;
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
.lead-actions {
|
||||
display: flex;
|
||||
gap: 24rpx;
|
||||
}
|
||||
.lead-btn {
|
||||
flex: 1;
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
border-radius: 16rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
border: none;
|
||||
}
|
||||
.lead-btn-cancel {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: #A0AEC0;
|
||||
}
|
||||
.lead-btn-submit {
|
||||
background: #38bdac;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ const app = getApp()
|
||||
let MATCH_TYPES = [
|
||||
{ id: 'partner', label: '找伙伴', matchLabel: '找伙伴', icon: '⭐', matchFromDB: true, showJoinAfterMatch: false },
|
||||
{ id: 'investor', label: '资源对接', matchLabel: '资源对接', icon: '👥', matchFromDB: true, showJoinAfterMatch: true, requirePurchase: true },
|
||||
{ id: 'mentor', label: '导师顾问', matchLabel: '立即咨询', icon: '❤️', matchFromDB: true, showJoinAfterMatch: true },
|
||||
{ id: 'mentor', label: '导师顾问', matchLabel: '导师顾问', icon: '❤️', matchFromDB: true, showJoinAfterMatch: true },
|
||||
{ id: 'team', label: '团队招募', matchLabel: '团队招募', icon: '🎮', matchFromDB: true, showJoinAfterMatch: true }
|
||||
]
|
||||
|
||||
@@ -108,8 +108,15 @@ Page({
|
||||
})
|
||||
|
||||
if (res.success && res.data) {
|
||||
// 更新全局配置
|
||||
MATCH_TYPES = res.data.matchTypes || MATCH_TYPES
|
||||
// 更新全局配置,导师顾问类型强制显示「导师顾问」
|
||||
let types = res.data.matchTypes || MATCH_TYPES
|
||||
types = types.map(t => {
|
||||
if (t.id === 'mentor') {
|
||||
return { ...t, label: '导师顾问', matchLabel: '导师顾问' }
|
||||
}
|
||||
return t
|
||||
})
|
||||
MATCH_TYPES = types
|
||||
FREE_MATCH_LIMIT = res.data.freeMatchLimit || FREE_MATCH_LIMIT
|
||||
const matchPrice = res.data.matchPrice || 1
|
||||
|
||||
@@ -459,7 +466,7 @@ Page({
|
||||
|
||||
// 生成模拟匹配数据
|
||||
generateMockMatch() {
|
||||
const nicknames = ['创业先锋', '资源整合者', '私域专家', '商业导师', '连续创业者']
|
||||
const nicknames = ['创业先锋', '资源整合者', '私域专家', '导师顾问', '连续创业者']
|
||||
const concepts = [
|
||||
'专注私域流量运营5年,帮助100+品牌实现从0到1的增长。',
|
||||
'连续创业者,擅长商业模式设计和资源整合。',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Soul创业派对 - 超级个体/会员详情页
|
||||
* 接口:优先 /api/miniprogram/vip/members?id=xx(VIP),回退 /api/miniprogram/users?id=xx(任意用户)
|
||||
* 字段映射:name/vipName, avatar/vipAvatar, contact/vipContact/phone, wechatId, project/vipProject/projectIntro,
|
||||
* 头像/昵称:统一用用户资料(nickname/avatar)优先,随「我的」修改实时生效
|
||||
* mbti, region, industry, position, businessScale, skills,
|
||||
* storyBestMonth→bestMonth, storyAchievement→achievement, storyTurning→turningPoint,
|
||||
* helpOffer→canHelp, helpNeed→needHelp
|
||||
@@ -32,8 +32,8 @@ Page({
|
||||
const u = Array.isArray(dbRes.data) ? dbRes.data[0] : dbRes.data
|
||||
if (u) {
|
||||
this.setData({ member: this.enrichAndFormat({
|
||||
id: u.id, name: u.vipName || u.vip_name || u.nickname || '创业者',
|
||||
avatar: u.vipAvatar || u.vip_avatar || u.avatar || '', isVip: !!(u.is_vip),
|
||||
id: u.id, name: u.nickname || u.vipName || u.vip_name || '创业者',
|
||||
avatar: u.avatar || u.vipAvatar || u.vip_avatar || '', isVip: !!(u.is_vip),
|
||||
contactRaw: u.vipContact || u.vip_contact || u.phone || '',
|
||||
wechatId: u.wechatId || u.wechat_id,
|
||||
project: u.vipProject || u.vip_project || u.projectIntro || u.project_intro || '',
|
||||
@@ -63,7 +63,7 @@ Page({
|
||||
const e = (v) => this._emptyIfPlaceholder(v)
|
||||
const merged = {
|
||||
id: raw.id,
|
||||
name: raw.name || raw.vipName || raw.vip_name || raw.nickname || '创业者',
|
||||
name: raw.nickname || raw.name || raw.vipName || raw.vip_name || '创业者',
|
||||
avatar: raw.avatar || raw.vipAvatar || raw.vip_avatar || '',
|
||||
isVip: !!(raw.isVip || raw.is_vip),
|
||||
mbti: e(raw.mbti),
|
||||
@@ -85,20 +85,84 @@ Page({
|
||||
const contact = merged.contactRaw || ''
|
||||
const wechat = merged.wechatRaw || ''
|
||||
const isMatched = (app.globalData.matchedUsers || []).includes(merged.id)
|
||||
const unlockData = this._getUnlockData(merged.id)
|
||||
merged.contactDisplay = contact ? (contact.slice(0, 3) + '****' + (contact.length > 7 ? contact.slice(-2) : '')) : ''
|
||||
merged.contactUnlocked = isMatched
|
||||
merged.contactUnlocked = isMatched || unlockData.contact
|
||||
merged.contactFull = contact
|
||||
merged.wechatDisplay = wechat ? (wechat.slice(0, 4) + '****' + (wechat.length > 8 ? wechat.slice(-3) : '')) : ''
|
||||
merged.wechatUnlocked = isMatched
|
||||
merged.wechatUnlocked = isMatched || unlockData.wechat
|
||||
merged.wechatFull = wechat
|
||||
return merged
|
||||
},
|
||||
|
||||
unlockContact() {
|
||||
_getUnlockData(memberId) {
|
||||
const userId = app.globalData.userInfo?.id
|
||||
if (!userId || !memberId) return { contact: false, wechat: false }
|
||||
try {
|
||||
const raw = wx.getStorageSync('member_unlocks_' + userId)
|
||||
if (Array.isArray(raw) && raw.includes(memberId)) {
|
||||
return { contact: true, wechat: true }
|
||||
}
|
||||
const data = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : {}
|
||||
const member = data[memberId]
|
||||
return {
|
||||
contact: !!(member && member.contact),
|
||||
wechat: !!(member && member.wechat)
|
||||
}
|
||||
} catch (e) { return { contact: false, wechat: false } }
|
||||
},
|
||||
|
||||
_addUnlock(memberId, field) {
|
||||
const userId = app.globalData.userInfo?.id
|
||||
if (!userId || !memberId || !field) return
|
||||
let obj = wx.getStorageSync('member_unlocks_' + userId)
|
||||
if (Array.isArray(obj)) {
|
||||
obj = obj.reduce((o, id) => { o[id] = { contact: true, wechat: true }; return o }, {})
|
||||
}
|
||||
obj = obj && typeof obj === 'object' ? obj : {}
|
||||
if (!obj[memberId]) obj[memberId] = {}
|
||||
obj[memberId][field] = true
|
||||
wx.setStorageSync('member_unlocks_' + userId, obj)
|
||||
},
|
||||
|
||||
_hasUsedFreeForMember(memberId) {
|
||||
const d = this._getUnlockData(memberId)
|
||||
return d.contact || d.wechat
|
||||
},
|
||||
|
||||
unlockField(e) {
|
||||
const field = e.currentTarget.dataset.field
|
||||
if (!field) return
|
||||
const member = this.data.member
|
||||
if (!member?.id || (field !== 'contact' && field !== 'wechat')) return
|
||||
const isLoggedIn = app.globalData.isLoggedIn
|
||||
if (!isLoggedIn) {
|
||||
wx.showModal({
|
||||
title: '需要登录',
|
||||
content: '请先登录后再解锁超级个体联系方式',
|
||||
confirmText: '去登录',
|
||||
cancelText: '取消',
|
||||
success: (res) => { if (res.confirm) wx.switchTab({ url: '/pages/my/my' }) }
|
||||
})
|
||||
return
|
||||
}
|
||||
const d = this._getUnlockData(member.id)
|
||||
if (d[field]) return
|
||||
const isVip = app.globalData.hasFullBook
|
||||
const usedFree = this._hasUsedFreeForMember(member.id)
|
||||
if (isVip || !usedFree) {
|
||||
this._addUnlock(member.id, field)
|
||||
const m = this.enrichAndFormat(member)
|
||||
this.setData({ member: m })
|
||||
wx.showToast({ title: field === 'contact' ? '已解锁联系方式' : '已解锁微信号', icon: 'success' })
|
||||
return
|
||||
}
|
||||
wx.showModal({
|
||||
title: '解锁完整联系方式', content: '成为VIP会员并完成匹配后,即可查看完整联系方式',
|
||||
confirmText: '去匹配', cancelText: '知道了',
|
||||
success: (res) => { if (res.confirm) wx.switchTab({ url: '/pages/match/match' }) }
|
||||
title: '解锁' + (field === 'contact' ? '联系方式' : '微信号'),
|
||||
content: '您的免费解锁次数已用完,开通VIP会员(¥1980/年)可无限解锁',
|
||||
confirmText: '去开通',
|
||||
cancelText: '取消',
|
||||
success: (res) => { if (res.confirm) wx.navigateTo({ url: '/pages/vip/vip' }) }
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
@@ -57,8 +57,8 @@
|
||||
<view class="field" wx:if="{{member.contactRaw || member.contactDisplay}}">
|
||||
<text class="f-key">联系方式</text>
|
||||
<view class="f-row">
|
||||
<text class="f-val mono">{{member.contactDisplay || member.contactRaw}}</text>
|
||||
<view class="icon-copy icon-eye-off" wx:if="{{member.contactRaw && !member.contactUnlocked}}" bindtap="unlockContact">
|
||||
<text class="f-val mono">{{member.contactUnlocked ? member.contactFull : (member.contactDisplay || member.contactRaw)}}</text>
|
||||
<view class="icon-copy icon-eye-off" wx:if="{{member.contactRaw && !member.contactUnlocked}}" bindtap="unlockField" data-field="contact">
|
||||
<image class="icon-img" src="/assets/icons/eye-off.svg" mode="aspectFit"/>
|
||||
</view>
|
||||
<view class="icon-copy" wx:elif="{{member.contactRaw && member.contactUnlocked}}" bindtap="copyContact">📋</view>
|
||||
@@ -67,8 +67,8 @@
|
||||
<view class="field" wx:if="{{member.wechatRaw || member.wechatDisplay}}">
|
||||
<text class="f-key">微信号</text>
|
||||
<view class="f-row">
|
||||
<text class="f-val mono">{{member.wechatDisplay || member.wechatRaw}}</text>
|
||||
<view class="icon-copy icon-eye-off" wx:if="{{member.wechatRaw && !member.wechatUnlocked}}" bindtap="unlockContact">
|
||||
<text class="f-val mono">{{member.wechatUnlocked ? member.wechatFull : (member.wechatDisplay || member.wechatRaw)}}</text>
|
||||
<view class="icon-copy icon-eye-off" wx:if="{{member.wechatRaw && !member.wechatUnlocked}}" bindtap="unlockField" data-field="wechat">
|
||||
<image class="icon-img" src="/assets/icons/eye-off.svg" mode="aspectFit"/>
|
||||
</view>
|
||||
<view class="icon-copy" wx:elif="{{member.wechatRaw && member.wechatUnlocked}}" bindtap="copyWechat">📋</view>
|
||||
|
||||
@@ -621,7 +621,7 @@ Page({
|
||||
wx.switchTab({ url: '/pages/match/match' })
|
||||
},
|
||||
|
||||
// 跳转到推广中心
|
||||
// 跳转到推广中心(需登录)
|
||||
goToReferral() {
|
||||
if (!this.data.isLoggedIn) {
|
||||
this.showLogin()
|
||||
@@ -630,7 +630,7 @@ Page({
|
||||
wx.navigateTo({ url: '/pages/referral/referral' })
|
||||
},
|
||||
|
||||
// 跳转到找伙伴页面
|
||||
// 跳转到找伙伴
|
||||
goToMatch() {
|
||||
wx.switchTab({ url: '/pages/match/match' })
|
||||
},
|
||||
@@ -650,14 +650,20 @@ Page({
|
||||
})
|
||||
},
|
||||
|
||||
// VIP状态查询
|
||||
// VIP状态查询(hasFullBook 优先,兼容模拟支付等本地已置 VIP 的情况)
|
||||
async loadVipStatus() {
|
||||
if (app.globalData.hasFullBook) {
|
||||
this.setData({ isVip: true, vipExpireDate: this.data.vipExpireDate || '' })
|
||||
}
|
||||
const userId = app.globalData.userInfo?.id
|
||||
if (!userId) return
|
||||
try {
|
||||
const res = await app.request({ url: `/api/miniprogram/vip/status?userId=${userId}`, silent: true })
|
||||
if (res?.success) {
|
||||
this.setData({ isVip: res.data?.isVip, vipExpireDate: res.data?.expireDate || '' })
|
||||
this.setData({
|
||||
isVip: res.data?.isVip || app.globalData.hasFullBook,
|
||||
vipExpireDate: res.data?.expireDate || this.data.vipExpireDate || ''
|
||||
})
|
||||
}
|
||||
} catch (e) { console.log('[My] VIP查询失败', e) }
|
||||
},
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<!-- 我的页 - 设计稿 1:1 还原 -->
|
||||
<view class="page">
|
||||
<!-- 顶部导航:标题 + 右侧设置齿轮 -->
|
||||
<!-- 顶部导航:左侧资料编辑 + 标题 -->
|
||||
<view class="nav-bar" style="padding-top: {{statusBarHeight}}px;">
|
||||
<text class="nav-title">我的</text>
|
||||
<view class="nav-settings" bindtap="handleMenuTap" data-id="settings">
|
||||
<image class="nav-settings-icon" src="/assets/icons/settings-gray.svg" mode="aspectFit"/>
|
||||
<view class="nav-settings" bindtap="goToProfileEdit">
|
||||
<image class="nav-settings-icon" src="/assets/icons/edit-gray.svg" mode="aspectFit"/>
|
||||
</view>
|
||||
<text class="nav-title">我的</text>
|
||||
</view>
|
||||
<view class="nav-placeholder" style="height: {{statusBarHeight + 44}}px;"></view>
|
||||
|
||||
@@ -38,22 +38,22 @@
|
||||
</view>
|
||||
<view class="vip-tags">
|
||||
<text class="vip-tag {{isVip ? 'vip-tag-active' : ''}}" bindtap="goToVip">会员</text>
|
||||
<text class="vip-tag {{isVip ? 'vip-tag-active' : ''}}" bindtap="goToVip">匹配</text>
|
||||
<text class="vip-tag {{isVip ? 'vip-tag-active' : ''}}" bindtap="goToMatch">匹配</text>
|
||||
<text class="vip-tag {{isVip ? 'vip-tag-active' : ''}}" bindtap="goToVip">排行</text>
|
||||
</view>
|
||||
<text class="user-wechat" bindtap="copyUserId">微信号: {{userWechat || userIdShort || '--'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="profile-stats-row">
|
||||
<view class="profile-stat">
|
||||
<view class="profile-stat" bindtap="goToChapters">
|
||||
<text class="profile-stat-val">{{readCount}}</text>
|
||||
<text class="profile-stat-label">已读章节</text>
|
||||
</view>
|
||||
<view class="profile-stat">
|
||||
<view class="profile-stat" bindtap="goToReferral">
|
||||
<text class="profile-stat-val">{{referralCount}}</text>
|
||||
<text class="profile-stat-label">推荐好友</text>
|
||||
</view>
|
||||
<view class="profile-stat">
|
||||
<view class="profile-stat" bindtap="goToReferral">
|
||||
<text class="profile-stat-val">{{earnings === '-' ? '--' : earnings}}</text>
|
||||
<text class="profile-stat-label">我的收益</text>
|
||||
</view>
|
||||
@@ -70,17 +70,17 @@
|
||||
<text class="card-title">阅读统计</text>
|
||||
</view>
|
||||
<view class="stats-grid">
|
||||
<view class="stat-box">
|
||||
<view class="stat-box" bindtap="goToChapters">
|
||||
<image class="stat-icon-img" src="/assets/icons/book-open-teal.svg" mode="aspectFit"/>
|
||||
<text class="stat-num">{{readCount}}</text>
|
||||
<text class="stat-label">已读章节</text>
|
||||
</view>
|
||||
<view class="stat-box">
|
||||
<view class="stat-box" bindtap="goToChapters">
|
||||
<image class="stat-icon-img" src="/assets/icons/clock-teal.svg" mode="aspectFit"/>
|
||||
<text class="stat-num">{{totalReadTime}}</text>
|
||||
<text class="stat-label">阅读分钟</text>
|
||||
</view>
|
||||
<view class="stat-box">
|
||||
<view class="stat-box" bindtap="goToMatch">
|
||||
<image class="stat-icon-img" src="/assets/icons/users-teal.svg" mode="aspectFit"/>
|
||||
<text class="stat-num">{{matchHistory}}</text>
|
||||
<text class="stat-label">匹配伙伴</text>
|
||||
@@ -208,7 +208,9 @@
|
||||
<text class="modal-title">修改昵称</text>
|
||||
</view>
|
||||
<view class="nickname-input-wrap">
|
||||
<input class="nickname-input" type="nickname" value="{{editingNickname}}" placeholder="点击输入昵称" placeholder-class="nickname-placeholder" bindchange="onNicknameChange" bindinput="onNicknameInput" maxlength="20"/>
|
||||
<view class="nickname-input-inner">
|
||||
<input class="nickname-input" type="nickname" value="{{editingNickname}}" placeholder="点击输入昵称" placeholder-class="nickname-placeholder" bindchange="onNicknameChange" bindinput="onNicknameInput" maxlength="20"/>
|
||||
</view>
|
||||
<text class="input-tip">微信用户可点击自动填充昵称</text>
|
||||
</view>
|
||||
<view class="modal-actions">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
padding-bottom: calc(220rpx + env(safe-area-inset-bottom, 0px));
|
||||
}
|
||||
|
||||
/* ===== 导航栏(避让右上角系统胶囊) ===== */
|
||||
/* ===== 导航栏(左侧设置 + 标题居中,右侧避让胶囊) ===== */
|
||||
.nav-bar {
|
||||
position: fixed; top: 0; left: 0; right: 0; z-index: 100;
|
||||
background: rgba(18,18,18,0.9); backdrop-filter: blur(8rpx);
|
||||
@@ -18,8 +18,8 @@
|
||||
padding: 0 120rpx 0 32rpx; /* 右侧避让胶囊 */
|
||||
border-bottom: 1rpx solid rgba(255,255,255,0.05);
|
||||
}
|
||||
.nav-title { font-size: 40rpx; font-weight: bold; color: #4FD1C5; flex: 1; }
|
||||
.nav-settings { width: 64rpx; height: 64rpx; display: flex; align-items: center; justify-content: center; margin-right: 16rpx; }
|
||||
.nav-settings { width: 64rpx; height: 64rpx; flex-shrink: 0; display: flex; align-items: center; justify-content: center; margin-right: 16rpx; }
|
||||
.nav-title { font-size: 40rpx; font-weight: bold; color: #4FD1C5; flex: 1; text-align: center; }
|
||||
.nav-settings-icon { width: 44rpx; height: 44rpx; opacity: 0.7; }
|
||||
.nav-placeholder { width: 100%; }
|
||||
|
||||
@@ -217,7 +217,11 @@
|
||||
.nickname-modal .modal-icon { font-size: 48rpx; }
|
||||
.nickname-modal .modal-title { font-size: 36rpx; font-weight: bold; }
|
||||
.nickname-input-wrap { margin-bottom: 32rpx; }
|
||||
.nickname-input { width: 100%; padding: 24rpx; background: #262626; border-radius: 20rpx; font-size: 28rpx; color: #fff; box-sizing: border-box; }
|
||||
.nickname-input-inner {
|
||||
padding: 24rpx 32rpx; background: #262626; border-radius: 20rpx;
|
||||
}
|
||||
.nickname-input { width: 100%; font-size: 28rpx; color: #fff; background: transparent; box-sizing: border-box; }
|
||||
.nickname-placeholder { color: #9CA3AF; }
|
||||
.input-tip { display: block; font-size: 22rpx; color: #9CA3AF; margin-top: 12rpx; }
|
||||
.modal-actions { display: flex; gap: 24rpx; }
|
||||
.modal-btn { flex: 1; height: 80rpx; line-height: 80rpx; text-align: center; border-radius: 20rpx; font-size: 28rpx; }
|
||||
|
||||
@@ -18,8 +18,10 @@
|
||||
<!-- 头像 -->
|
||||
<view class="avatar-section">
|
||||
<view class="avatar-wrap" bindtap="chooseAvatar">
|
||||
<image wx:if="{{avatar}}" class="avatar-img" src="{{avatar}}" mode="aspectFill"/>
|
||||
<view wx:else class="avatar-placeholder">{{nickname ? nickname[0] : '?'}}</view>
|
||||
<view class="avatar-inner">
|
||||
<image wx:if="{{avatar}}" class="avatar-img" src="{{avatar}}" mode="aspectFill"/>
|
||||
<view wx:else class="avatar-placeholder">{{nickname ? nickname[0] : '?'}}</view>
|
||||
</view>
|
||||
<view class="avatar-camera">📷</view>
|
||||
</view>
|
||||
<text class="avatar-change">更换头像</text>
|
||||
|
||||
@@ -31,18 +31,22 @@
|
||||
|
||||
.avatar-section { display: flex; flex-direction: column; align-items: center; margin-bottom: 48rpx; }
|
||||
.avatar-wrap {
|
||||
position: relative; width: 192rpx; height: 192rpx; border-radius: 50%; overflow: hidden;
|
||||
position: relative; width: 192rpx; height: 192rpx; border-radius: 50%;
|
||||
border: 4rpx solid #5EEAD4; box-shadow: 0 0 30rpx rgba(94,234,212,0.3);
|
||||
}
|
||||
.avatar-inner {
|
||||
width: 100%; height: 100%; border-radius: 50%; overflow: hidden;
|
||||
}
|
||||
.avatar-img { width: 100%; height: 100%; display: block; }
|
||||
.avatar-placeholder {
|
||||
width: 100%; height: 100%; display: flex; align-items: center; justify-content: center;
|
||||
font-size: 72rpx; font-weight: bold; color: #5EEAD4; background: rgba(94,234,212,0.2);
|
||||
}
|
||||
.avatar-camera {
|
||||
position: absolute; bottom: 0; right: 0;
|
||||
position: absolute; bottom: -8rpx; right: -8rpx;
|
||||
width: 56rpx; height: 56rpx; background: #5EEAD4; color: #000;
|
||||
border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 28rpx;
|
||||
border: 4rpx solid #050B14; box-sizing: border-box;
|
||||
}
|
||||
.avatar-change { font-size: 28rpx; color: #5EEAD4; font-weight: 500; margin-top: 16rpx; }
|
||||
|
||||
|
||||
@@ -81,6 +81,8 @@ Page({
|
||||
if (app.globalData.initialSectionMid) delete app.globalData.initialSectionMid
|
||||
if (app.globalData.initialSectionId) delete app.globalData.initialSectionId
|
||||
|
||||
console.log("页面:",mid);
|
||||
|
||||
// mid 有值但无 id 时,从 bookData 或 API 解析 id
|
||||
if (mid && !id) {
|
||||
const bookData = app.globalData.bookData || []
|
||||
@@ -126,7 +128,7 @@ Page({
|
||||
})
|
||||
|
||||
// 统一:先拉章节数据,用 isFree/price===0 判断免费
|
||||
const chapterRes = await app.request({ url: `/api/miniprogram/book/chapter/${id}`, silent: true })
|
||||
const chapterRes = await app.request({ url: this._getChapterUrl({ id, mid }), silent: true })
|
||||
const accessState = await accessManager.determineAccessState(id, chapterRes)
|
||||
const canAccess = accessManager.canAccessFullContent(accessState)
|
||||
|
||||
@@ -196,7 +198,7 @@ Page({
|
||||
const sectionPrice = this.data.sectionPrice ?? 1
|
||||
let res = prefetchedChapter
|
||||
if (!res || !res.content) {
|
||||
res = await app.request({ url: `/api/miniprogram/book/chapter/${id}`, silent: true })
|
||||
res = await app.request({ url: this._getChapterUrl({ id }), silent: true })
|
||||
}
|
||||
const section = {
|
||||
id: res.id || id,
|
||||
@@ -295,6 +297,17 @@ Page({
|
||||
return titles[id] || `章节 ${id}`
|
||||
},
|
||||
|
||||
// 根据 id/mid 构造章节接口路径(优先使用 mid)
|
||||
_getChapterUrl(params = {}) {
|
||||
const { id, mid } = params
|
||||
const finalMid = (mid !== undefined && mid !== null) ? mid : this.data.sectionMid
|
||||
if (finalMid) {
|
||||
return `/api/miniprogram/book/chapter/by-mid/${finalMid}`
|
||||
}
|
||||
const finalId = id || this.data.sectionId
|
||||
return `/api/miniprogram/book/chapter/${finalId}`
|
||||
},
|
||||
|
||||
// 加载内容 - 三级降级方案:API → 本地缓存 → 备用API
|
||||
async loadContent(id) {
|
||||
const cacheKey = `chapter_${id}`
|
||||
@@ -344,7 +357,7 @@ Page({
|
||||
reject(new Error('请求超时'))
|
||||
}, timeout)
|
||||
|
||||
app.request(`/api/miniprogram/book/chapter/${id}`)
|
||||
app.request(this._getChapterUrl({ id }))
|
||||
.then(res => {
|
||||
clearTimeout(timer)
|
||||
resolve(res)
|
||||
@@ -360,14 +373,24 @@ Page({
|
||||
setChapterContent(res) {
|
||||
const lines = res.content.split('\n').filter(line => line.trim())
|
||||
const previewCount = Math.ceil(lines.length * 0.2)
|
||||
const sectionPrice = this.data.sectionPrice ?? 1
|
||||
const sectionTitle = (res.sectionTitle || res.title || '').trim()
|
||||
|
||||
this.setData({
|
||||
// 文章详情标题:只使用后端提供的 sectionTitle,不再拼接其他本地标题信息
|
||||
section: {
|
||||
id: res.id || this.data.sectionId,
|
||||
title: sectionTitle,
|
||||
isFree: res.isFree === true || (res.price !== undefined && res.price === 0),
|
||||
price: res.price ?? sectionPrice
|
||||
},
|
||||
content: res.content,
|
||||
previewContent: lines.slice(0, previewCount).join('\n'),
|
||||
contentParagraphs: lines,
|
||||
previewParagraphs: lines.slice(0, previewCount),
|
||||
partTitle: res.partTitle || '',
|
||||
chapterTitle: res.chapterTitle || ''
|
||||
// 导航栏、分享等使用的文章标题,同样统一为 sectionTitle
|
||||
chapterTitle: sectionTitle
|
||||
})
|
||||
},
|
||||
|
||||
@@ -504,11 +527,16 @@ Page({
|
||||
}
|
||||
},
|
||||
|
||||
// 分享到朋友圈:带文章标题,过长时截断(朋友圈卡片标题显示有限)
|
||||
onShareTimeline() {
|
||||
const { section, sectionId, sectionMid } = this.data
|
||||
const { section, sectionId, sectionMid, chapterTitle } = this.data
|
||||
const ref = app.getMyReferralCode()
|
||||
const q = sectionMid ? `mid=${sectionMid}` : `id=${sectionId}`
|
||||
return { title: section?.title ? `📚 ${section.title}` : 'Soul创业派对 - 真实商业故事', query: ref ? `${q}&ref=${ref}` : q }
|
||||
const articleTitle = (section?.title || chapterTitle || '').trim()
|
||||
const title = articleTitle
|
||||
? (articleTitle.length > 28 ? articleTitle.slice(0, 28) + '...' : articleTitle)
|
||||
: 'Soul创业派对 - 真实商业故事'
|
||||
return { title, query: ref ? `${q}&ref=${ref}` : q }
|
||||
},
|
||||
|
||||
// 显示登录弹窗(每次打开协议未勾选,符合审核要求)
|
||||
@@ -588,7 +616,7 @@ Page({
|
||||
|
||||
// 2. 重新拉取章节数据,用 isFree/price 判断免费
|
||||
const chapterRes = await app.request({
|
||||
url: `/api/miniprogram/book/chapter/${this.data.sectionId}`,
|
||||
url: this._getChapterUrl({}),
|
||||
silent: true
|
||||
})
|
||||
const newAccessState = await accessManager.determineAccessState(
|
||||
@@ -859,7 +887,7 @@ Page({
|
||||
|
||||
// 3. 重新拉取章节并判断权限(应为 unlocked_purchased)
|
||||
const chapterRes = await app.request({
|
||||
url: `/api/miniprogram/book/chapter/${this.data.sectionId}`,
|
||||
url: this._getChapterUrl({}),
|
||||
silent: true
|
||||
})
|
||||
let newAccessState = await accessManager.determineAccessState(
|
||||
@@ -1201,7 +1229,7 @@ Page({
|
||||
|
||||
// 重新拉取章节,用 isFree/price 判断免费
|
||||
const chapterRes = await app.request({
|
||||
url: `/api/miniprogram/book/chapter/${this.data.sectionId}`,
|
||||
url: this._getChapterUrl({}),
|
||||
silent: true
|
||||
})
|
||||
const newAccessState = await accessManager.determineAccessState(
|
||||
|
||||
@@ -13,8 +13,7 @@
|
||||
<text class="back-arrow">←</text>
|
||||
</view>
|
||||
<view class="nav-info">
|
||||
<text class="nav-part" wx:if="{{partTitle}}">{{partTitle}}</text>
|
||||
<text class="nav-chapter" wx:if="{{chapterTitle}}">{{chapterTitle}}</text>
|
||||
<text class="nav-chapter" wx:if="{{section.title || chapterTitle}}">{{section.title || chapterTitle}}</text>
|
||||
</view>
|
||||
<view class="nav-right-placeholder"></view>
|
||||
</view>
|
||||
|
||||
@@ -64,67 +64,6 @@ Page({
|
||||
}
|
||||
},
|
||||
|
||||
// 一键获取收货地址
|
||||
getAddress() {
|
||||
wx.chooseAddress({
|
||||
success: (res) => {
|
||||
console.log('[Settings] 获取地址成功:', res)
|
||||
const fullAddress = `${res.provinceName || ''}${res.cityName || ''}${res.countyName || ''}${res.detailInfo || ''}`
|
||||
|
||||
if (fullAddress.trim()) {
|
||||
wx.setStorageSync('user_address', fullAddress)
|
||||
this.setData({ address: fullAddress })
|
||||
|
||||
// 更新用户信息
|
||||
if (app.globalData.userInfo) {
|
||||
app.globalData.userInfo.address = fullAddress
|
||||
wx.setStorageSync('userInfo', app.globalData.userInfo)
|
||||
}
|
||||
|
||||
// 同步到服务器
|
||||
this.syncAddressToServer(fullAddress)
|
||||
|
||||
wx.showToast({ title: '地址已获取', icon: 'success' })
|
||||
}
|
||||
},
|
||||
fail: (e) => {
|
||||
console.log('[Settings] 获取地址失败:', e)
|
||||
if (e.errMsg?.includes('cancel')) {
|
||||
// 用户取消,不提示
|
||||
return
|
||||
}
|
||||
if (e.errMsg?.includes('auth deny') || e.errMsg?.includes('authorize')) {
|
||||
wx.showModal({
|
||||
title: '需要授权',
|
||||
content: '请在设置中允许获取收货地址',
|
||||
confirmText: '去设置',
|
||||
success: (res) => {
|
||||
if (res.confirm) wx.openSetting()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
wx.showToast({ title: '获取失败,请重试', icon: 'none' })
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 同步地址到服务器
|
||||
async syncAddressToServer(address) {
|
||||
try {
|
||||
const userId = app.globalData.userInfo?.id
|
||||
if (!userId) return
|
||||
|
||||
await app.request('/api/miniprogram/user/update', {
|
||||
method: 'POST',
|
||||
data: { userId, address }
|
||||
})
|
||||
console.log('[Settings] 地址已同步到服务器')
|
||||
} catch (e) {
|
||||
console.log('[Settings] 同步地址失败:', e)
|
||||
}
|
||||
},
|
||||
|
||||
// 切换自动提现
|
||||
async toggleAutoWithdraw(e) {
|
||||
const enabled = e.detail.value
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import accessManager from '../../utils/chapterAccessManager'
|
||||
const app = getApp()
|
||||
|
||||
Page({
|
||||
@@ -88,9 +89,9 @@ Page({
|
||||
if (payRes?.success && payRes.data?.payParams) {
|
||||
wx.requestPayment({
|
||||
...payRes.data.payParams,
|
||||
success: () => {
|
||||
success: async () => {
|
||||
wx.showToast({ title: 'VIP开通成功', icon: 'success' })
|
||||
this.loadVipInfo()
|
||||
await this._onVipPaymentSuccess()
|
||||
},
|
||||
fail: () => wx.showToast({ title: '支付取消', icon: 'none' })
|
||||
})
|
||||
@@ -103,6 +104,28 @@ Page({
|
||||
} finally { this.setData({ purchasing: false }) }
|
||||
},
|
||||
|
||||
async _onVipPaymentSuccess() {
|
||||
wx.showLoading({ title: '同步权益中...', mask: true })
|
||||
try {
|
||||
await new Promise(r => setTimeout(r, 1500))
|
||||
await accessManager.refreshUserPurchaseStatus()
|
||||
await this.loadVipInfo()
|
||||
app.globalData.hasFullBook = true
|
||||
const userInfo = app.globalData.userInfo || {}
|
||||
userInfo.hasFullBook = true
|
||||
app.globalData.userInfo = userInfo
|
||||
wx.setStorageSync('userInfo', userInfo)
|
||||
const pages = getCurrentPages()
|
||||
pages.forEach(p => {
|
||||
if (typeof p.initUserStatus === 'function') p.initUserStatus()
|
||||
else if (typeof p.updateUserStatus === 'function') p.updateUserStatus()
|
||||
})
|
||||
} catch (e) {
|
||||
console.error('[VIP] 支付后同步失败:', e)
|
||||
}
|
||||
wx.hideLoading()
|
||||
},
|
||||
|
||||
goBack() { wx.navigateBack() },
|
||||
|
||||
onShareAppMessage() {
|
||||
|
||||
@@ -24,81 +24,11 @@
|
||||
"miniprogram": {
|
||||
"list": [
|
||||
{
|
||||
"name": "pages/vip/vip",
|
||||
"pathName": "pages/vip/vip",
|
||||
"query": "",
|
||||
"name": "pages/read/read",
|
||||
"pathName": "pages/read/read",
|
||||
"query": "mid=1",
|
||||
"scene": null,
|
||||
"launchMode": "default"
|
||||
},
|
||||
{
|
||||
"name": "pages/member-detail/member-detail",
|
||||
"pathName": "pages/member-detail/member-detail",
|
||||
"query": "id=ogpTW5QBRQNUOm4-zvg8it2XySrI",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
},
|
||||
{
|
||||
"name": "pages/vip/vip",
|
||||
"pathName": "pages/vip/vip",
|
||||
"query": "",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
},
|
||||
{
|
||||
"name": "pages/member-detail/member-detail",
|
||||
"pathName": "pages/member-detail/member-detail",
|
||||
"query": "id=ogpTW5cteGWqwOsRzh_CCIdKWGSE",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
},
|
||||
{
|
||||
"name": "pages/about/about",
|
||||
"pathName": "pages/about/about",
|
||||
"query": "",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
},
|
||||
{
|
||||
"name": "pages/about/about",
|
||||
"pathName": "pages/about/about",
|
||||
"query": "",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
},
|
||||
{
|
||||
"name": "pages/vip/vip",
|
||||
"pathName": "pages/vip/vip",
|
||||
"query": "",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
},
|
||||
{
|
||||
"name": "pages/profile-edit/profile-edit",
|
||||
"pathName": "pages/profile-edit/profile-edit",
|
||||
"query": "",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
},
|
||||
{
|
||||
"name": "个人资料",
|
||||
"pathName": "pages/profile-show/profile-show",
|
||||
"query": "",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
},
|
||||
{
|
||||
"name": "pages/mentors/mentors",
|
||||
"pathName": "pages/mentors/mentors",
|
||||
"query": "",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
},
|
||||
{
|
||||
"name": "我的",
|
||||
"pathName": "pages/my/my",
|
||||
"query": "",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
470
soul-admin/dist/assets/index-CAf6YeOV.js
vendored
Normal file
465
soul-admin/dist/assets/index-CKRjkwdJ.js
vendored
1
soul-admin/dist/assets/index-D0nEGm4H.css
vendored
1
soul-admin/dist/assets/index-DP984f3K.css
vendored
Normal file
4
soul-admin/dist/index.html
vendored
@@ -4,8 +4,8 @@
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>管理后台 - Soul创业派对</title>
|
||||
<script type="module" crossorigin src="/assets/index-CKRjkwdJ.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-D0nEGm4H.css">
|
||||
<script type="module" crossorigin src="/assets/index-CAf6YeOV.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-DP984f3K.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -20,20 +20,20 @@ import {
|
||||
import { get, post } from '@/api/client'
|
||||
import { clearAdminToken } from '@/api/auth'
|
||||
|
||||
// 主菜单(折叠后可见 4-5 项)
|
||||
// 主菜单(核心运营 3 项)
|
||||
const primaryMenuItems = [
|
||||
{ icon: LayoutDashboard, label: '数据概览', href: '/dashboard' },
|
||||
{ icon: BookOpen, label: '内容管理', href: '/content' },
|
||||
{ icon: Users, label: '用户管理', href: '/users' },
|
||||
]
|
||||
// 折叠区「更多」(字典类 + 业务)
|
||||
const moreMenuItems = [
|
||||
{ icon: Crown, label: 'VIP 角色', href: '/vip-roles' },
|
||||
{ icon: User, label: '作者详情', href: '/author-settings' },
|
||||
]
|
||||
// 折叠区「更多」
|
||||
const moreMenuItems = [
|
||||
{ icon: ShieldCheck, label: '管理员', href: '/admin-users' },
|
||||
{ icon: GraduationCap, label: '导师管理', href: '/mentors' },
|
||||
{ icon: Calendar, label: '导师预约', href: '/mentor-consultations' },
|
||||
{ icon: Wallet, label: '交易中心', href: '/distribution' },
|
||||
{ icon: Wallet, label: '推广中心', href: '/distribution' },
|
||||
{ icon: GitMerge, label: '匹配记录', href: '/match-records' },
|
||||
{ icon: CreditCard, label: '推广设置', href: '/referral-settings' },
|
||||
]
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
* 章节树 - 仿照 catalog 设计,支持篇、章、节拖拽排序
|
||||
* 整行可拖拽;节和章可跨篇
|
||||
*/
|
||||
import { useCallback } from 'react'
|
||||
import { ChevronRight, ChevronDown, BookOpen, Eye, Edit3, Trash2 } from 'lucide-react'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { ChevronRight, ChevronDown, BookOpen, Eye, Edit3, Trash2, GripVertical, Plus } from 'lucide-react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
|
||||
const PART_LABELS = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十']
|
||||
@@ -51,6 +51,9 @@ interface ChapterTreeProps {
|
||||
onReorder: (items: { id: string; partId: string; partTitle: string; chapterId: string; chapterTitle: string }[]) => Promise<void>
|
||||
onReadSection: (s: SectionItem) => void
|
||||
onDeleteSection: (s: SectionItem) => void
|
||||
onAddSectionInPart?: (part: PartItem) => void
|
||||
onEditPart?: (part: PartItem) => void
|
||||
onDeletePart?: (part: PartItem) => void
|
||||
}
|
||||
|
||||
export function ChapterTree({
|
||||
@@ -60,7 +63,16 @@ export function ChapterTree({
|
||||
onReorder,
|
||||
onReadSection,
|
||||
onDeleteSection,
|
||||
onAddSectionInPart,
|
||||
onEditPart,
|
||||
onDeletePart,
|
||||
}: ChapterTreeProps) {
|
||||
const [draggingItem, setDraggingItem] = useState<{ type: DragType; id: string } | null>(null)
|
||||
const [dragOverTarget, setDragOverTarget] = useState<{ type: DragType; id: string } | null>(null)
|
||||
|
||||
const isDragging = (type: DragType, id: string) => draggingItem?.type === type && draggingItem?.id === id
|
||||
const isDragOver = (type: DragType, id: string) => dragOverTarget?.type === type && dragOverTarget?.id === id
|
||||
|
||||
const buildSectionsList = useCallback(
|
||||
(): { id: string; partId: string; partTitle: string; chapterId: string; chapterTitle: string }[] => {
|
||||
const list: { id: string; partId: string; partTitle: string; chapterId: string; chapterTitle: string }[] = []
|
||||
@@ -223,13 +235,17 @@ export function ChapterTree({
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
e.dataTransfer.dropEffect = 'move'
|
||||
setDragOverTarget({ type, id })
|
||||
},
|
||||
onDragOver: (e: React.DragEvent) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
e.dataTransfer.dropEffect = 'move'
|
||||
setDragOverTarget({ type, id })
|
||||
},
|
||||
onDragLeave: () => setDragOverTarget(null),
|
||||
onDrop: (e: React.DragEvent) => {
|
||||
setDragOverTarget(null)
|
||||
const from = parseDragData(e.dataTransfer.getData('text/plain'))
|
||||
if (!from) return
|
||||
if (type === 'section' && from.type === 'section' && from.id === id) return
|
||||
@@ -395,10 +411,11 @@ export function ChapterTree({
|
||||
}
|
||||
|
||||
// 普通篇:卡片 + 章/节
|
||||
const partDragOver = isDragOver('part', part.id)
|
||||
return (
|
||||
<div
|
||||
key={part.id}
|
||||
className="rounded-xl border border-gray-700/50 bg-[#1C1C1E] overflow-hidden"
|
||||
className={`rounded-xl border bg-[#1C1C1E] overflow-hidden transition-all duration-200 ${partDragOver ? 'border-[#38bdac] ring-2 ring-[#38bdac]/40 bg-[#38bdac]/5' : 'border-gray-700/50'}`}
|
||||
{...droppableHandlers('part', part.id, {
|
||||
partId: part.id,
|
||||
partTitle: part.title,
|
||||
@@ -412,11 +429,14 @@ export function ChapterTree({
|
||||
e.stopPropagation()
|
||||
e.dataTransfer.setData('text/plain', 'part:' + part.id)
|
||||
e.dataTransfer.effectAllowed = 'move'
|
||||
setDraggingItem({ type: 'part', id: part.id })
|
||||
}}
|
||||
className="flex items-center justify-between p-4 cursor-grab active:cursor-grabbing select-none hover:bg-[#162840]/50 transition-colors"
|
||||
onDragEnd={() => { setDraggingItem(null); setDragOverTarget(null) }}
|
||||
className={`flex items-center justify-between p-4 cursor-grab active:cursor-grabbing select-none transition-all duration-200 ${isDragging('part', part.id) ? 'opacity-60 scale-[0.98] ring-2 ring-[#38bdac] rounded-xl shadow-xl shadow-[#38bdac]/20' : 'hover:bg-[#162840]/50'}`}
|
||||
onClick={() => onTogglePart(part.id)}
|
||||
>
|
||||
<div className="flex items-center gap-3 min-w-0">
|
||||
<GripVertical className="w-5 h-5 text-gray-500 shrink-0 opacity-60" />
|
||||
<div className="w-10 h-10 rounded-xl bg-[#38bdac] flex items-center justify-center text-white font-bold shadow-lg shadow-[#38bdac]/30 shrink-0">
|
||||
{partLabel(partIndex)}
|
||||
</div>
|
||||
@@ -425,7 +445,26 @@ export function ChapterTree({
|
||||
<p className="text-xs text-gray-500 mt-0.5">共 {sectionCount} 节</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 shrink-0">
|
||||
<div
|
||||
className="flex items-center gap-2 shrink-0"
|
||||
onMouseDown={(e) => e.stopPropagation()}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{onAddSectionInPart && (
|
||||
<Button draggable={false} variant="ghost" size="sm" onClick={() => onAddSectionInPart(part)} className="text-gray-500 hover:text-[#38bdac] h-7 px-2" title="在本篇下新增章节">
|
||||
<Plus className="w-3.5 h-3.5" />
|
||||
</Button>
|
||||
)}
|
||||
{onEditPart && (
|
||||
<Button draggable={false} variant="ghost" size="sm" onClick={() => onEditPart(part)} className="text-gray-500 hover:text-[#38bdac] h-7 px-2" title="编辑篇名">
|
||||
<Edit3 className="w-3.5 h-3.5" />
|
||||
</Button>
|
||||
)}
|
||||
{onDeletePart && (
|
||||
<Button draggable={false} variant="ghost" size="sm" onClick={() => onDeletePart(part)} className="text-gray-500 hover:text-red-400 h-7 px-2" title="删除本篇">
|
||||
<Trash2 className="w-3.5 h-3.5" />
|
||||
</Button>
|
||||
)}
|
||||
<span className="text-xs text-gray-500">{chapterCount}章</span>
|
||||
{isExpanded ? (
|
||||
<ChevronDown className="w-5 h-5 text-gray-500" />
|
||||
@@ -437,7 +476,9 @@ export function ChapterTree({
|
||||
|
||||
{isExpanded && (
|
||||
<div className="border-t border-gray-700/50 pl-4 pr-4 pb-4 pt-3 space-y-4">
|
||||
{part.chapters.map((chapter, chIndex) => (
|
||||
{part.chapters.map((chapter, chIndex) => {
|
||||
const chDragOver = isDragOver('chapter', chapter.id)
|
||||
return (
|
||||
<div key={chapter.id} className="space-y-2">
|
||||
<div
|
||||
draggable
|
||||
@@ -445,30 +486,39 @@ export function ChapterTree({
|
||||
e.stopPropagation()
|
||||
e.dataTransfer.setData('text/plain', 'chapter:' + chapter.id)
|
||||
e.dataTransfer.effectAllowed = 'move'
|
||||
setDraggingItem({ type: 'chapter', id: chapter.id })
|
||||
}}
|
||||
className="py-2 px-2 rounded cursor-grab active:cursor-grabbing select-none hover:bg-[#162840]/30 -mx-2"
|
||||
onDragEnd={() => { setDraggingItem(null); setDragOverTarget(null) }}
|
||||
onDragEnter={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
e.dataTransfer.dropEffect = 'move'
|
||||
setDragOverTarget({ type: 'chapter', id: chapter.id })
|
||||
}}
|
||||
onDragOver={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
e.dataTransfer.dropEffect = 'move'
|
||||
setDragOverTarget({ type: 'chapter', id: chapter.id })
|
||||
}}
|
||||
onDragLeave={() => setDragOverTarget(null)}
|
||||
onDrop={(e) => {
|
||||
setDragOverTarget(null)
|
||||
const from = parseDragData(e.dataTransfer.getData('text/plain'))
|
||||
if (!from) return
|
||||
const ctx = { partId: part.id, partTitle: part.title, chapterId: chapter.id, chapterTitle: chapter.title }
|
||||
if (from.type === 'section') handleDrop(e, 'chapter', chapter.id, ctx)
|
||||
else if (from.type === 'chapter') handleDrop(e, 'chapter', chapter.id, ctx)
|
||||
}}
|
||||
className={`py-2 px-2 rounded cursor-grab active:cursor-grabbing select-none -mx-2 transition-all duration-200 flex items-center gap-2 ${chDragOver ? 'bg-[#38bdac]/15 ring-1 ring-[#38bdac]/50' : ''} ${isDragging('chapter', chapter.id) ? 'opacity-60 scale-[0.98] ring-2 ring-[#38bdac]' : 'hover:bg-[#162840]/30'}`}
|
||||
>
|
||||
<GripVertical className="w-4 h-4 text-gray-500 shrink-0 opacity-50" />
|
||||
<p className="text-xs text-gray-500 pb-1">第{chIndex + 1}章 | {chapter.title}</p>
|
||||
</div>
|
||||
<div className="space-y-1 pl-2">
|
||||
{chapter.sections.map((section) => (
|
||||
{chapter.sections.map((section) => {
|
||||
const secDragOver = isDragOver('section', section.id)
|
||||
return (
|
||||
<div
|
||||
key={section.id}
|
||||
draggable
|
||||
@@ -476,8 +526,10 @@ export function ChapterTree({
|
||||
e.stopPropagation()
|
||||
e.dataTransfer.setData('text/plain', 'section:' + section.id)
|
||||
e.dataTransfer.effectAllowed = 'move'
|
||||
setDraggingItem({ type: 'section', id: section.id })
|
||||
}}
|
||||
className="flex items-center justify-between py-2 px-3 rounded-lg hover:bg-[#162840]/50 group cursor-grab active:cursor-grabbing select-none min-h-[40px]"
|
||||
onDragEnd={() => { setDraggingItem(null); setDragOverTarget(null) }}
|
||||
className={`flex items-center justify-between py-2 px-3 rounded-lg group cursor-grab active:cursor-grabbing select-none min-h-[40px] transition-all duration-200 ${secDragOver ? 'bg-[#38bdac]/15 ring-2 ring-[#38bdac]/50' : ''} ${isDragging('section', section.id) ? 'opacity-60 scale-[0.98] ring-2 ring-[#38bdac] shadow-lg' : 'hover:bg-[#162840]/50'}`}
|
||||
{...droppableHandlers('section', section.id, {
|
||||
partId: part.id,
|
||||
partTitle: part.title,
|
||||
@@ -486,6 +538,7 @@ export function ChapterTree({
|
||||
})}
|
||||
>
|
||||
<div className="flex items-center gap-3 min-w-0 flex-1">
|
||||
<GripVertical className="w-4 h-4 text-gray-500 shrink-0 opacity-50" />
|
||||
<div
|
||||
className={`w-2 h-2 rounded-full shrink-0 ${section.price === 0 || section.isFree ? 'border-2 border-[#38bdac] bg-transparent' : 'bg-gray-500'}`}
|
||||
/>
|
||||
@@ -520,10 +573,12 @@ export function ChapterTree({
|
||||
<ChevronRight className="w-4 h-4 text-gray-500" />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -33,7 +33,6 @@ import {
|
||||
X,
|
||||
RefreshCw,
|
||||
Link2,
|
||||
Eye,
|
||||
Plus,
|
||||
Image as ImageIcon,
|
||||
Search,
|
||||
@@ -154,6 +153,9 @@ export function ContentPage() {
|
||||
content: '',
|
||||
})
|
||||
|
||||
const [editingPart, setEditingPart] = useState<{ id: string; title: string } | null>(null)
|
||||
const [isSavingPartTitle, setIsSavingPartTitle] = useState(false)
|
||||
|
||||
const tree = buildTree(sectionsList)
|
||||
const totalSections = sectionsList.length
|
||||
|
||||
@@ -342,6 +344,63 @@ export function ContentPage() {
|
||||
}
|
||||
}
|
||||
|
||||
const handleAddSectionInPart = (part: Part) => {
|
||||
setNewSection((prev) => ({
|
||||
...prev,
|
||||
partId: part.id,
|
||||
chapterId: part.chapters[0]?.id ?? 'chapter-1',
|
||||
}))
|
||||
setShowNewSectionModal(true)
|
||||
}
|
||||
|
||||
const handleEditPartTitle = (part: Part) => {
|
||||
setEditingPart({ id: part.id, title: part.title })
|
||||
}
|
||||
|
||||
const handleSavePartTitle = async () => {
|
||||
if (!editingPart?.title?.trim()) return
|
||||
setIsSavingPartTitle(true)
|
||||
try {
|
||||
const items = sectionsList.map((s) => ({
|
||||
id: s.id,
|
||||
partId: s.partId || 'part-1',
|
||||
partTitle: s.partId === editingPart.id ? editingPart.title.trim() : (s.partTitle || ''),
|
||||
chapterId: s.chapterId || 'chapter-1',
|
||||
chapterTitle: s.chapterTitle || '',
|
||||
}))
|
||||
const res = await put<{ success?: boolean; error?: string }>('/api/db/book', {
|
||||
action: 'reorder',
|
||||
items,
|
||||
})
|
||||
if (res && (res as { success?: boolean }).success !== false) {
|
||||
setEditingPart(null)
|
||||
loadList()
|
||||
} else {
|
||||
alert('更新篇名失败: ' + (res && typeof res === 'object' && 'error' in res ? (res as { error?: string }).error : '未知错误'))
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
alert('更新篇名失败')
|
||||
} finally {
|
||||
setIsSavingPartTitle(false)
|
||||
}
|
||||
}
|
||||
|
||||
const handleDeletePart = async (part: Part) => {
|
||||
const sectionIds = sectionsList.filter((s) => s.partId === part.id).map((s) => s.id)
|
||||
if (sectionIds.length === 0) return
|
||||
if (!confirm(`确定要删除「${part.title}」整篇吗?将删除共 ${sectionIds.length} 节内容,此操作不可恢复。`)) return
|
||||
try {
|
||||
for (const id of sectionIds) {
|
||||
await del<{ success?: boolean; error?: string }>(`/api/db/book?id=${encodeURIComponent(id)}`)
|
||||
}
|
||||
loadList()
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
alert('删除失败')
|
||||
}
|
||||
}
|
||||
|
||||
const handleImageUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = e.target.files?.[0]
|
||||
if (!file) return
|
||||
@@ -542,6 +601,57 @@ export function ContentPage() {
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* 编辑篇名弹窗 */}
|
||||
<Dialog open={!!editingPart} onOpenChange={(open) => !open && setEditingPart(null)}>
|
||||
<DialogContent className="bg-[#0f2137] border-gray-700 text-white max-w-md" showCloseButton>
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-white flex items-center gap-2">
|
||||
<Edit3 className="w-5 h-5 text-[#38bdac]" />
|
||||
编辑篇名
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
{editingPart && (
|
||||
<div className="space-y-4 py-4">
|
||||
<div className="space-y-2">
|
||||
<Label className="text-gray-300">篇名</Label>
|
||||
<Input
|
||||
className="bg-[#0a1628] border-gray-700 text-white"
|
||||
value={editingPart.title}
|
||||
onChange={(e) => setEditingPart({ ...editingPart, title: e.target.value })}
|
||||
placeholder="输入篇名"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<DialogFooter>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => setEditingPart(null)}
|
||||
className="border-gray-600 text-gray-300 hover:bg-gray-700/50 bg-transparent"
|
||||
>
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleSavePartTitle}
|
||||
disabled={isSavingPartTitle || !editingPart?.title?.trim()}
|
||||
className="bg-[#38bdac] hover:bg-[#2da396] text-white"
|
||||
>
|
||||
{isSavingPartTitle ? (
|
||||
<>
|
||||
<RefreshCw className="w-4 h-4 mr-2 animate-spin" />
|
||||
保存中...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Save className="w-4 h-4 mr-2" />
|
||||
保存
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* 章节编辑弹窗 */}
|
||||
<Dialog open={!!editingSection} onOpenChange={() => setEditingSection(null)}>
|
||||
<DialogContent className="bg-[#0f2137] border-gray-700 text-white max-w-4xl max-h-[90vh] overflow-y-auto" showCloseButton>
|
||||
@@ -752,6 +862,9 @@ export function ContentPage() {
|
||||
onReorder={handleReorderTree}
|
||||
onReadSection={handleReadSection}
|
||||
onDeleteSection={handleDeleteSection}
|
||||
onAddSectionInPart={handleAddSectionInPart}
|
||||
onEditPart={handleEditPartTitle}
|
||||
onDeletePart={handleDeletePart}
|
||||
/>
|
||||
)}
|
||||
</TabsContent>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useState, useEffect, useRef } from 'react'
|
||||
import { Card, CardContent } from '@/components/ui/card'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Button } from '@/components/ui/button'
|
||||
@@ -18,8 +18,9 @@ import {
|
||||
DialogTitle,
|
||||
DialogFooter,
|
||||
} from '@/components/ui/dialog'
|
||||
import { Users, Plus, Edit3, Trash2, X, Save } from 'lucide-react'
|
||||
import { get, post, put, del } from '@/api/client'
|
||||
import { Users, Plus, Edit3, Trash2, X, Save, Upload } from 'lucide-react'
|
||||
import { get, post, put, del, apiUrl } from '@/api/client'
|
||||
import { getAdminToken } from '@/api/auth'
|
||||
|
||||
interface Mentor {
|
||||
id: number
|
||||
@@ -59,6 +60,40 @@ export function MentorsPage() {
|
||||
enabled: true,
|
||||
})
|
||||
const [saving, setSaving] = useState(false)
|
||||
const [uploadingAvatar, setUploadingAvatar] = useState(false)
|
||||
const avatarInputRef = useRef<HTMLInputElement>(null)
|
||||
|
||||
const handleAvatarUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = e.target.files?.[0]
|
||||
if (!file) return
|
||||
setUploadingAvatar(true)
|
||||
try {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
formData.append('folder', 'mentors')
|
||||
const token = getAdminToken()
|
||||
const headers: HeadersInit = {}
|
||||
if (token) headers['Authorization'] = `Bearer ${token}`
|
||||
const res = await fetch(apiUrl('/api/upload'), {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
credentials: 'include',
|
||||
headers,
|
||||
})
|
||||
const data = await res.json()
|
||||
if (data?.success && data?.url) {
|
||||
setForm((f) => ({ ...f, avatar: data.url }))
|
||||
} else {
|
||||
alert('上传失败: ' + (data?.error || '未知错误'))
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
alert('上传失败')
|
||||
} finally {
|
||||
setUploadingAvatar(false)
|
||||
if (avatarInputRef.current) avatarInputRef.current.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
async function load() {
|
||||
setLoading(true)
|
||||
@@ -293,13 +328,42 @@ export function MentorsPage() {
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label className="text-gray-300">头像 URL</Label>
|
||||
<Input
|
||||
className="bg-[#0a1628] border-gray-700 text-white"
|
||||
placeholder="https://..."
|
||||
value={form.avatar}
|
||||
onChange={(e) => setForm((f) => ({ ...f, avatar: e.target.value }))}
|
||||
/>
|
||||
<Label className="text-gray-300">头像</Label>
|
||||
<div className="flex gap-3 items-center">
|
||||
<Input
|
||||
className="flex-1 bg-[#0a1628] border-gray-700 text-white"
|
||||
value={form.avatar}
|
||||
onChange={(e) => setForm((f) => ({ ...f, avatar: e.target.value }))}
|
||||
placeholder="点击上传或粘贴图片地址"
|
||||
/>
|
||||
<input
|
||||
ref={avatarInputRef}
|
||||
type="file"
|
||||
accept="image/*"
|
||||
className="hidden"
|
||||
onChange={handleAvatarUpload}
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="border-gray-600 text-gray-400 shrink-0"
|
||||
disabled={uploadingAvatar}
|
||||
onClick={() => avatarInputRef.current?.click()}
|
||||
>
|
||||
<Upload className="w-4 h-4 mr-2" />
|
||||
{uploadingAvatar ? '上传中...' : '上传'}
|
||||
</Button>
|
||||
</div>
|
||||
{form.avatar && (
|
||||
<div className="mt-2">
|
||||
<img
|
||||
src={form.avatar.startsWith('http') ? form.avatar : apiUrl(form.avatar)}
|
||||
alt="头像预览"
|
||||
className="w-20 h-20 rounded-full object-cover border border-gray-600"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label className="text-gray-300">简介</Label>
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/api/auth.ts","./src/api/client.ts","./src/components/modules/user/setvipmodal.tsx","./src/components/modules/user/userdetailmodal.tsx","./src/components/ui/pagination.tsx","./src/components/ui/badge.tsx","./src/components/ui/button.tsx","./src/components/ui/card.tsx","./src/components/ui/dialog.tsx","./src/components/ui/input.tsx","./src/components/ui/label.tsx","./src/components/ui/select.tsx","./src/components/ui/slider.tsx","./src/components/ui/switch.tsx","./src/components/ui/table.tsx","./src/components/ui/tabs.tsx","./src/components/ui/textarea.tsx","./src/hooks/usedebounce.ts","./src/layouts/adminlayout.tsx","./src/lib/utils.ts","./src/pages/admin-users/adminuserspage.tsx","./src/pages/api-doc/apidocpage.tsx","./src/pages/author-settings/authorsettingspage.tsx","./src/pages/content/chaptertree.tsx","./src/pages/content/contentpage.tsx","./src/pages/dashboard/dashboardpage.tsx","./src/pages/distribution/distributionpage.tsx","./src/pages/login/loginpage.tsx","./src/pages/match/matchpage.tsx","./src/pages/match-records/matchrecordspage.tsx","./src/pages/mentor-consultations/mentorconsultationspage.tsx","./src/pages/mentors/mentorspage.tsx","./src/pages/not-found/notfoundpage.tsx","./src/pages/orders/orderspage.tsx","./src/pages/payment/paymentpage.tsx","./src/pages/qrcodes/qrcodespage.tsx","./src/pages/referral-settings/referralsettingspage.tsx","./src/pages/settings/settingspage.tsx","./src/pages/site/sitepage.tsx","./src/pages/users/userspage.tsx","./src/pages/vip-roles/viprolespage.tsx","./src/pages/withdrawals/withdrawalspage.tsx"],"errors":true,"version":"5.6.3"}
|
||||
{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/api/auth.ts","./src/api/client.ts","./src/components/modules/user/setvipmodal.tsx","./src/components/modules/user/userdetailmodal.tsx","./src/components/ui/pagination.tsx","./src/components/ui/badge.tsx","./src/components/ui/button.tsx","./src/components/ui/card.tsx","./src/components/ui/dialog.tsx","./src/components/ui/input.tsx","./src/components/ui/label.tsx","./src/components/ui/select.tsx","./src/components/ui/slider.tsx","./src/components/ui/switch.tsx","./src/components/ui/table.tsx","./src/components/ui/tabs.tsx","./src/components/ui/textarea.tsx","./src/hooks/usedebounce.ts","./src/layouts/adminlayout.tsx","./src/lib/utils.ts","./src/pages/admin-users/adminuserspage.tsx","./src/pages/api-doc/apidocpage.tsx","./src/pages/author-settings/authorsettingspage.tsx","./src/pages/content/chaptertree.tsx","./src/pages/content/contentpage.tsx","./src/pages/dashboard/dashboardpage.tsx","./src/pages/distribution/distributionpage.tsx","./src/pages/login/loginpage.tsx","./src/pages/match/matchpage.tsx","./src/pages/match-records/matchrecordspage.tsx","./src/pages/mentor-consultations/mentorconsultationspage.tsx","./src/pages/mentors/mentorspage.tsx","./src/pages/not-found/notfoundpage.tsx","./src/pages/orders/orderspage.tsx","./src/pages/payment/paymentpage.tsx","./src/pages/qrcodes/qrcodespage.tsx","./src/pages/referral-settings/referralsettingspage.tsx","./src/pages/settings/settingspage.tsx","./src/pages/site/sitepage.tsx","./src/pages/users/userspage.tsx","./src/pages/vip-roles/viprolespage.tsx","./src/pages/withdrawals/withdrawalspage.tsx"],"version":"5.6.3"}
|
||||
@@ -1,291 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="dark" lang="zh-CN"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>Clean Dark Mode Catalog with NEW Tags</title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,typography"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"/>
|
||||
<script>
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: "#4FD1C5",
|
||||
"background-light": "#f3f4f6",
|
||||
"background-dark": "#000000",
|
||||
"card-light": "#ffffff",
|
||||
"card-dark": "#1C1C1E",
|
||||
"text-secondary-dark": "#8E8E93",
|
||||
"accent-dark": "#2C2C2E",
|
||||
},
|
||||
fontFamily: {
|
||||
display: ["Noto Sans SC", "sans-serif"],
|
||||
},
|
||||
borderRadius: {
|
||||
DEFAULT: "12px",
|
||||
"xl": "16px",
|
||||
"2xl": "20px",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.no-scrollbar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
.no-scrollbar {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
.fab-shadow {
|
||||
box-shadow: 0 4px 15px rgba(79, 209, 197, 0.4);
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-background-light dark:bg-background-dark font-display text-gray-900 dark:text-gray-100 min-h-screen pb-24">
|
||||
<header class="fixed top-0 left-0 right-0 z-50 bg-background-light/95 dark:bg-background-dark/95 backdrop-blur-sm px-4 pt-4 pb-2 flex justify-between items-center border-b border-gray-200 dark:border-gray-800">
|
||||
<button class="w-9 h-9 rounded-full bg-gray-200 dark:bg-accent-dark flex items-center justify-center text-gray-500 dark:text-gray-400">
|
||||
<span class="material-icons text-lg">search</span>
|
||||
</button>
|
||||
<h1 class="text-lg font-bold text-primary tracking-wide">目录</h1>
|
||||
<div class="flex gap-3">
|
||||
<button class="w-9 h-9 rounded-full bg-gray-200 dark:bg-accent-dark flex items-center justify-center text-gray-500 dark:text-gray-400">
|
||||
<span class="material-icons text-lg">more_horiz</span>
|
||||
</button>
|
||||
<button class="w-9 h-9 rounded-full bg-gray-200 dark:bg-accent-dark flex items-center justify-center text-gray-500 dark:text-gray-400">
|
||||
<span class="material-icons text-lg">radio_button_checked</span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
<main class="mt-20 px-4 space-y-4">
|
||||
<div class="bg-white dark:bg-card-dark rounded-2xl p-4 flex items-center justify-between shadow-sm border border-gray-100 dark:border-gray-800/30">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-12 h-12 bg-primary rounded-xl flex items-center justify-center text-white shadow-lg shadow-primary/20">
|
||||
<span class="material-icons text-2xl">menu_book</span>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="font-bold text-base dark:text-white leading-tight mb-1">一场SOUL的创业实验场</h2>
|
||||
<p class="text-xs text-gray-500 dark:text-text-secondary-dark">来自Soul派对房的真实商业故事</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<span class="block text-2xl font-bold text-primary">73</span>
|
||||
<span class="text-xs text-gray-500 dark:text-gray-500">章节</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white dark:bg-card-dark rounded-xl p-4 flex items-center justify-between shadow-sm border border-gray-100 dark:border-gray-800/30">
|
||||
<div class="flex items-center gap-3 overflow-hidden">
|
||||
<div class="w-8 h-8 bg-gray-700/50 dark:bg-accent-dark rounded-lg flex items-center justify-center flex-shrink-0">
|
||||
<span class="material-icons text-white dark:text-gray-400 text-sm">import_contacts</span>
|
||||
</div>
|
||||
<h3 class="font-medium text-sm truncate dark:text-gray-200">序言 | 为什么我每天早上6点在...</h3>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<span class="px-2 py-1 bg-primary/20 text-primary text-[10px] font-medium rounded">免费</span>
|
||||
<span class="material-icons text-gray-500 text-sm">arrow_forward</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white dark:bg-card-dark rounded-2xl p-4 shadow-sm border border-gray-100 dark:border-gray-800/30">
|
||||
<div class="flex items-start justify-between mb-4">
|
||||
<div class="flex gap-3">
|
||||
<div class="w-10 h-10 bg-primary rounded-xl flex items-center justify-center flex-shrink-0 text-white font-bold shadow-lg shadow-primary/30">
|
||||
一
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-bold dark:text-white text-base">真实的人</h3>
|
||||
<p class="text-xs text-gray-500 dark:text-text-secondary-dark mt-0.5">人与人之间的底层逻辑</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-xs text-gray-500">2章</span>
|
||||
<span class="material-icons text-gray-500 text-sm">arrow_downward</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-4 pl-1">
|
||||
<p class="text-xs text-gray-500 dark:text-gray-500 pt-2 pb-1">第1章 | 人与人之间的底层逻辑</p>
|
||||
<div class="flex items-center justify-between group">
|
||||
<div class="flex items-center gap-3 overflow-hidden">
|
||||
<div class="w-2 h-2 rounded-full border border-primary flex-shrink-0"></div>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-200 truncate">1.1 荷包:电动车出租的被动收入模式</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<span class="px-2 py-1 bg-primary/20 text-primary text-[10px] font-medium rounded">免费</span>
|
||||
<span class="material-icons text-gray-600 dark:text-gray-500 text-xs">chevron_right</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between group">
|
||||
<div class="flex items-center gap-3 overflow-hidden">
|
||||
<div class="w-2 h-2 rounded-full bg-gray-400 dark:bg-gray-600 flex-shrink-0"></div>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-200 truncate">1.2 老墨:资源整合高手的社交方法</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<span class="text-xs text-gray-500">¥1</span>
|
||||
<span class="material-icons text-gray-600 dark:text-gray-500 text-xs">chevron_right</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between group">
|
||||
<div class="flex items-center gap-3 overflow-hidden">
|
||||
<div class="w-2 h-2 rounded-full bg-gray-400 dark:bg-gray-600 flex-shrink-0"></div>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-200 truncate">1.3 笑声背后的MBTI:为什么ENTJ适合做...</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<span class="text-xs text-gray-500">¥1</span>
|
||||
<span class="material-icons text-gray-600 dark:text-gray-500 text-xs">chevron_right</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between group">
|
||||
<div class="flex items-center gap-3 overflow-hidden">
|
||||
<div class="w-2 h-2 rounded-full bg-gray-400 dark:bg-gray-600 flex-shrink-0"></div>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-200 truncate">1.4 人性的三角结构:利益、情感、价值观</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<span class="text-xs text-gray-500">¥1</span>
|
||||
<span class="material-icons text-gray-600 dark:text-gray-500 text-xs">chevron_right</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between group">
|
||||
<div class="flex items-center gap-3 overflow-hidden">
|
||||
<div class="w-2 h-2 rounded-full bg-gray-400 dark:bg-gray-600 flex-shrink-0"></div>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-200 truncate">1.5 沟通差的问题:为什么你说的别人听...</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<span class="text-xs text-gray-500">¥1</span>
|
||||
<span class="material-icons text-gray-600 dark:text-gray-500 text-xs">chevron_right</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-500 pt-4 pb-1">第2章 | 人性困境案例</p>
|
||||
<div class="flex items-center justify-between group">
|
||||
<div class="flex items-center gap-3 overflow-hidden">
|
||||
<div class="w-2 h-2 rounded-full bg-gray-400 dark:bg-gray-600 flex-shrink-0"></div>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-200 truncate">2.1 相亲故事:你以为找的是人,实际是在找...</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<span class="px-2 py-1 bg-primary/20 text-primary text-[10px] font-medium rounded">NEW</span>
|
||||
<span class="text-xs text-gray-500">¥1</span>
|
||||
<span class="material-icons text-gray-600 dark:text-gray-500 text-xs">chevron_right</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between group">
|
||||
<div class="flex items-center gap-3 overflow-hidden">
|
||||
<div class="w-2 h-2 rounded-full bg-gray-400 dark:bg-gray-600 flex-shrink-0"></div>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-200 truncate">2.2 找工作迷茫者:为什么简历解决不了人生</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<span class="text-xs text-gray-500">¥1</span>
|
||||
<span class="material-icons text-gray-600 dark:text-gray-500 text-xs">chevron_right</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between group">
|
||||
<div class="flex items-center gap-3 overflow-hidden">
|
||||
<div class="w-2 h-2 rounded-full bg-gray-400 dark:bg-gray-600 flex-shrink-0"></div>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-200 truncate">2.3 撸运费险:小钱困住大脑的真实心理</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<span class="px-2 py-1 bg-primary/20 text-primary text-[10px] font-medium rounded">NEW</span>
|
||||
<span class="text-xs text-gray-500">¥1</span>
|
||||
<span class="material-icons text-gray-600 dark:text-gray-500 text-xs">chevron_right</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white dark:bg-card-dark rounded-2xl p-4 shadow-sm border border-gray-100 dark:border-gray-800/30 flex items-center justify-between">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-10 h-10 bg-primary rounded-xl flex items-center justify-center flex-shrink-0 text-white font-bold shadow-lg shadow-primary/30">
|
||||
二
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-bold dark:text-white text-base">真实的行业</h3>
|
||||
<p class="text-xs text-gray-500 dark:text-text-secondary-dark mt-0.5">电商、内容、传统行业解析</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-xs text-gray-500">3章</span>
|
||||
<span class="material-icons text-gray-500 text-sm">arrow_forward</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white dark:bg-card-dark rounded-2xl p-4 shadow-sm border border-gray-100 dark:border-gray-800/30 flex items-center justify-between">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-10 h-10 bg-primary rounded-xl flex items-center justify-center flex-shrink-0 text-white font-bold shadow-lg shadow-primary/30">
|
||||
三
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-bold dark:text-white text-base">真实的错误</h3>
|
||||
<p class="text-xs text-gray-500 dark:text-text-secondary-dark mt-0.5">我和别人犯过的错</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-xs text-gray-500">2章</span>
|
||||
<span class="material-icons text-gray-500 text-sm">arrow_forward</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white dark:bg-card-dark rounded-2xl p-4 shadow-sm border border-gray-100 dark:border-gray-800/30 flex items-center justify-between">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-10 h-10 bg-primary rounded-xl flex items-center justify-center flex-shrink-0 text-white font-bold shadow-lg shadow-primary/30">
|
||||
四
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-bold dark:text-white text-base">真实的赚钱</h3>
|
||||
<p class="text-xs text-gray-500 dark:text-text-secondary-dark mt-0.5">底层结构与真实案例</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-xs text-gray-500">2章</span>
|
||||
<span class="material-icons text-gray-500 text-sm">arrow_forward</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white dark:bg-card-dark rounded-2xl p-5 shadow-sm border border-gray-100 dark:border-gray-800/30">
|
||||
<h3 class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-4">附录</h3>
|
||||
<div class="space-y-4">
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm dark:text-gray-300">附录1 | Soul派对房精选对话</span>
|
||||
<span class="material-icons text-gray-500 text-sm">arrow_forward</span>
|
||||
</div>
|
||||
<div class="w-full h-[1px] bg-gray-100 dark:bg-gray-800"></div>
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm dark:text-gray-300">附录2 | 创业者自检清单</span>
|
||||
<span class="material-icons text-gray-500 text-sm">arrow_forward</span>
|
||||
</div>
|
||||
<div class="w-full h-[1px] bg-gray-100 dark:bg-gray-800"></div>
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm dark:text-gray-300">附录3 | 本书提到的工具和资源</span>
|
||||
<span class="material-icons text-gray-500 text-sm">arrow_forward</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<nav class="fixed bottom-0 left-0 right-0 bg-white dark:bg-background-dark border-t border-gray-200 dark:border-gray-800 pb-safe pt-2 px-6 flex justify-between items-center z-50 h-[80px]">
|
||||
<a class="flex flex-col items-center gap-1 text-gray-400 dark:text-gray-500" href="#">
|
||||
<span class="material-icons text-2xl">home</span>
|
||||
<span class="text-[10px]">首页</span>
|
||||
</a>
|
||||
<a class="flex flex-col items-center gap-1 text-primary" href="#">
|
||||
<span class="material-icons text-2xl">list</span>
|
||||
<span class="text-[10px]">目录</span>
|
||||
</a>
|
||||
<div class="relative -top-6">
|
||||
<button class="w-14 h-14 bg-gradient-to-br from-primary to-primary/80 rounded-full flex items-center justify-center text-white fab-shadow border-4 border-white dark:border-background-dark">
|
||||
<span class="material-icons text-2xl">groups</span>
|
||||
</button>
|
||||
<span class="absolute -bottom-5 left-1/2 transform -translate-x-1/2 text-[10px] text-gray-400 w-max">找伙伴</span>
|
||||
</div>
|
||||
<a class="flex flex-col items-center gap-1 text-gray-400 dark:text-gray-500" href="#">
|
||||
<span class="material-icons text-2xl">person</span>
|
||||
<span class="text-[10px]">我的</span>
|
||||
</a>
|
||||
</nav>
|
||||
<div class="h-8"></div>
|
||||
|
||||
</body></html>
|
||||
|
Before Width: | Height: | Size: 234 KiB |
@@ -1,215 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="dark" lang="zh-CN"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>Comprehensive Profile Editor V1</title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,typography"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
|
||||
body {
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
background-color: #000000;
|
||||
}
|
||||
.material-symbols-outlined {
|
||||
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
|
||||
}
|
||||
.custom-scrollbar::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||||
background: #2D3748;
|
||||
border-radius: 10px;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: "#4FD1C5",
|
||||
"background-dark": "#000000",
|
||||
"input-dark": "#1F2937",
|
||||
"border-dark": "#374151",
|
||||
},
|
||||
borderRadius: {
|
||||
DEFAULT: "12px",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-background-dark text-white min-h-screen flex flex-col">
|
||||
<header class="sticky top-0 z-50 bg-black/80 backdrop-blur-md px-4 py-4 flex items-center justify-between border-b border-white/10">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="material-symbols-outlined text-2xl cursor-pointer">chevron_left</span>
|
||||
<h1 class="text-lg font-semibold">编辑资料</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="flex items-center bg-gray-900 rounded-full px-3 py-1 gap-2 border border-white/10">
|
||||
<span class="material-symbols-outlined text-sm">more_horiz</span>
|
||||
<div class="w-[1px] h-3 bg-white/20"></div>
|
||||
<div class="w-3 h-3 rounded-full border-2 border-white/40"></div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<main class="flex-grow max-w-md mx-auto px-4 py-6 space-y-8 pb-32">
|
||||
<div class="bg-primary/10 border border-primary/20 p-4 rounded-xl flex items-start gap-3">
|
||||
<span class="material-symbols-outlined text-primary text-xl">info</span>
|
||||
<p class="text-sm text-primary/90 leading-relaxed font-medium">
|
||||
温馨提示:需完善手机号和微信号才能使用提现和找伙伴功能
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-col items-center gap-4">
|
||||
<div class="relative">
|
||||
<div class="w-24 h-24 rounded-full p-1 border-2 border-primary shadow-[0_0_15px_rgba(79,209,197,0.3)]">
|
||||
<img alt="User Avatar" class="w-full h-full rounded-full object-cover" src="https://lh3.googleusercontent.com/aida-public/AB6AXuByaFYqZutDoN6LuA2I7fT4RcZhrFxMFneSEUoMGyHZX55vvf-taz_AAEYDjMagOLNszcrdxJMszI1W-71DtHgK9OaVfJIW6qH0yb33bfdP8nNg9zpyE-F4ujPwa_E8AlZSX9CHISvTfkiB6aUMH8hdz1sA8ptLervlhVR4Cst5N38a4ZiB_zRETMlVJOaPZ1-Ry_XeDXTXAaZQN1xy-WIGX-1rlgs1JUDXg4Ihcv0Am5p4hgwoFat9JdcoYRQN6FfP4b5zzapLoBk"/>
|
||||
</div>
|
||||
<div class="absolute bottom-0 right-0 bg-primary text-black p-1.5 rounded-full border-2 border-background-dark flex items-center justify-center">
|
||||
<span class="material-symbols-outlined text-xs">photo_camera</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="text-primary text-sm font-medium">更换头像</button>
|
||||
</div>
|
||||
<form class="space-y-6">
|
||||
<div class="space-y-4">
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
<label class="block">
|
||||
<span class="text-sm text-gray-400 ml-1">昵称</span>
|
||||
<input class="mt-1 block w-full bg-input-dark border-border-dark rounded-lg focus:border-primary focus:ring-0 text-white placeholder-gray-500" type="text" value="乘风"/>
|
||||
</label>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<label class="block">
|
||||
<span class="text-sm text-gray-400 ml-1">MBTI</span>
|
||||
<div class="relative mt-1">
|
||||
<select class="block w-full bg-input-dark border-border-dark rounded-lg focus:border-primary focus:ring-0 text-white appearance-none py-2 px-3 pr-8">
|
||||
<option>INTJ</option>
|
||||
<option>INFP</option>
|
||||
<option>ENTP</option>
|
||||
<option>ENFJ</option>
|
||||
</select>
|
||||
<span class="material-symbols-outlined absolute right-2 top-2 text-gray-500 pointer-events-none">expand_more</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="block">
|
||||
<span class="text-sm text-gray-400 ml-1">地区</span>
|
||||
<div class="relative mt-1">
|
||||
<input class="block w-full bg-input-dark border-border-dark rounded-lg focus:border-primary focus:ring-0 text-white pr-8" type="text" value="杭州 · 余杭区"/>
|
||||
<span class="material-symbols-outlined absolute right-2 top-2 text-gray-500 text-lg">location_on</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
<label class="block">
|
||||
<span class="text-sm text-gray-400 ml-1">行业</span>
|
||||
<input class="mt-1 block w-full bg-input-dark border-border-dark rounded-lg focus:border-primary focus:ring-0 text-white placeholder-gray-600" placeholder="例如:新媒体 / 电商" type="text"/>
|
||||
</label>
|
||||
<label class="block">
|
||||
<span class="text-sm text-gray-400 ml-1">业务体量</span>
|
||||
<input class="mt-1 block w-full bg-input-dark border-border-dark rounded-lg focus:border-primary focus:ring-0 text-white placeholder-gray-600" placeholder="例如:年GMV 5000万+" type="text"/>
|
||||
</label>
|
||||
<label class="block">
|
||||
<span class="text-sm text-gray-400 ml-1">职位</span>
|
||||
<input class="mt-1 block w-full bg-input-dark border-border-dark rounded-lg focus:border-primary focus:ring-0 text-white placeholder-gray-600" placeholder="例如:创始人 / 联合创始人" type="text"/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-4 pt-4 border-t border-white/10">
|
||||
<h3 class="font-semibold text-white flex items-center gap-2">
|
||||
<span class="material-symbols-outlined text-primary text-xl">contact_phone</span>
|
||||
核心联系方式
|
||||
</h3>
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
<label class="block">
|
||||
<span class="text-sm text-gray-400 ml-1">手机号</span>
|
||||
<input class="mt-1 block w-full bg-input-dark border-border-dark rounded-lg focus:border-primary focus:ring-0 text-white placeholder-gray-600" placeholder="请输入手机号" type="tel"/>
|
||||
</label>
|
||||
<label class="block">
|
||||
<span class="text-sm text-gray-400 ml-1">微信号</span>
|
||||
<input class="mt-1 block w-full bg-input-dark border-border-dark rounded-lg focus:border-primary focus:ring-0 text-white placeholder-gray-600" placeholder="请输入微信号" type="text"/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-4 pt-4 border-t border-white/10">
|
||||
<h3 class="font-semibold text-white flex items-center gap-2">
|
||||
<span class="material-symbols-outlined text-yellow-400 text-xl">emoji_objects</span>
|
||||
个人故事
|
||||
</h3>
|
||||
<label class="block">
|
||||
<span class="text-sm text-gray-400 ml-1">你最赚钱的一个月做的是什么</span>
|
||||
<textarea class="mt-1 block w-full bg-input-dark border-border-dark rounded-lg focus:border-primary focus:ring-0 text-white placeholder:text-gray-600" placeholder="例如:2021年主导电商大促,单月GMV突破500W..." rows="3"></textarea>
|
||||
</label>
|
||||
<label class="block">
|
||||
<span class="text-sm text-gray-400 ml-1">最有成就感的一件事</span>
|
||||
<textarea class="mt-1 block w-full bg-input-dark border-border-dark rounded-lg focus:border-primary focus:ring-0 text-white placeholder:text-gray-600" placeholder="例如:帮助3个素人打造个人IP,每月稳定变现5万+" rows="3"></textarea>
|
||||
</label>
|
||||
<label class="block">
|
||||
<span class="text-sm text-gray-400 ml-1">人生的转折点</span>
|
||||
<textarea class="mt-1 block w-full bg-input-dark border-border-dark rounded-lg focus:border-primary focus:ring-0 text-white placeholder:text-gray-600" placeholder="例如:辞去大厂工作开始做自媒体..." rows="3"></textarea>
|
||||
</label>
|
||||
</div>
|
||||
<div class="space-y-4 pt-4 border-t border-white/10">
|
||||
<h3 class="font-semibold text-white flex items-center gap-2">
|
||||
<span class="material-symbols-outlined text-orange-400 text-xl">handshake</span>
|
||||
互助需求
|
||||
</h3>
|
||||
<label class="block">
|
||||
<span class="text-sm text-gray-400 ml-1">我能帮助大家什么</span>
|
||||
<input class="mt-1 block w-full bg-input-dark border-border-dark rounded-lg focus:border-primary focus:ring-0 text-white placeholder-gray-600" placeholder="例如:短视频脚本、账号冷启动、私域转化" type="text"/>
|
||||
</label>
|
||||
<label class="block">
|
||||
<span class="text-sm text-gray-400 ml-1">我需要什么帮助</span>
|
||||
<input class="mt-1 block w-full bg-input-dark border-border-dark rounded-lg focus:border-primary focus:ring-0 text-white placeholder-gray-600" placeholder="例如:寻找供应链资源、线下活动合作" type="text"/>
|
||||
</label>
|
||||
</div>
|
||||
<div class="space-y-4 pt-4 border-t border-white/10">
|
||||
<h3 class="font-semibold text-white flex items-center gap-2">
|
||||
<span class="material-symbols-outlined text-blue-400 text-xl">rocket_launch</span>
|
||||
项目介绍
|
||||
</h3>
|
||||
<label class="block">
|
||||
<textarea class="mt-1 block w-full bg-input-dark border-border-dark rounded-lg focus:border-primary focus:ring-0 text-white placeholder:text-gray-600" placeholder="详细介绍您的项目,让潜在伙伴更好地了解您..." rows="4"></textarea>
|
||||
</label>
|
||||
</div>
|
||||
<div class="pt-6 pb-12">
|
||||
<button class="w-full bg-primary hover:bg-teal-400 text-black font-bold py-4 rounded-xl text-lg transition-colors" type="submit">
|
||||
保存
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</main>
|
||||
<nav class="fixed bottom-0 left-0 right-0 bg-black border-t border-white/10 px-6 py-3 pb-6 flex justify-between items-center z-50">
|
||||
<div class="flex flex-col items-center gap-1 text-gray-500">
|
||||
<span class="material-symbols-outlined">home</span>
|
||||
<span class="text-[10px]">首页</span>
|
||||
</div>
|
||||
<div class="flex flex-col items-center gap-1 text-gray-500">
|
||||
<span class="material-symbols-outlined">list_alt</span>
|
||||
<span class="text-[10px]">目录</span>
|
||||
</div>
|
||||
<div class="flex flex-col items-center -mt-8">
|
||||
<div class="bg-gray-800 rounded-full p-3 border-4 border-black">
|
||||
<span class="material-symbols-outlined text-3xl text-gray-400">group</span>
|
||||
</div>
|
||||
<span class="text-[10px] text-gray-500 mt-1">找伙伴</span>
|
||||
</div>
|
||||
<div class="flex flex-col items-center gap-1 text-gray-500">
|
||||
<span class="material-symbols-outlined">chat_bubble</span>
|
||||
<span class="text-[10px]">消息</span>
|
||||
</div>
|
||||
<div class="flex flex-col items-center gap-1 text-primary">
|
||||
<span class="material-symbols-outlined">person</span>
|
||||
<span class="text-[10px] font-medium">我的</span>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
</body></html>
|
||||
|
Before Width: | Height: | Size: 102 KiB |
@@ -1,158 +0,0 @@
|
||||
<!DOCTYPE html><html class="dark" lang="zh-CN"><head>
|
||||
<meta charset="utf-8">
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||
<title>Simplified Info Completion Popup</title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,typography,container-queries"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet">
|
||||
<style type="text/tailwindcss">
|
||||
:root {
|
||||
--primary-color: #4FD1C5;
|
||||
--bg-dark: #000000;
|
||||
--card-dark: #1A1A1A;
|
||||
--input-bg: #262626;
|
||||
--border-color: #333333;
|
||||
}
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
|
||||
body {
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
background-color: var(--bg-dark);
|
||||
}
|
||||
.material-symbols-outlined {
|
||||
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
|
||||
}
|
||||
.modal-overlay {
|
||||
background-color: rgba(0, 0, 0, 0.85);
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: "#4FD1C5",
|
||||
"background-dark": "#000000",
|
||||
"input-dark": "#1F2937",
|
||||
"border-dark": "#374151",
|
||||
},
|
||||
borderRadius: {
|
||||
DEFAULT: "12px",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-background-dark text-white min-h-screen flex flex-col relative overflow-hidden">
|
||||
<header class="sticky top-0 z-40 bg-black/80 backdrop-blur-md px-4 py-4 flex items-center justify-between border-b border-white/10">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="material-symbols-outlined text-2xl cursor-pointer" style="">chevron_left</span>
|
||||
<h1 class="text-lg font-semibold" style="">编辑资料</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="flex items-center bg-gray-900 rounded-full px-3 py-1 gap-2 border border-white/10">
|
||||
<span class="material-symbols-outlined text-sm" style="">more_horiz</span>
|
||||
<div class="w-[1px] h-3 bg-white/20"></div>
|
||||
<div class="w-3 h-3 rounded-full border-2 border-white/40"></div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<main class="flex-grow max-w-md mx-auto px-4 py-6 space-y-8 pb-32 opacity-50 pointer-events-none">
|
||||
<div class="bg-primary/10 border border-primary/20 p-4 rounded-xl flex items-start gap-3">
|
||||
<span class="material-symbols-outlined text-primary text-xl" style="">info</span>
|
||||
<p class="text-sm text-primary/90 leading-relaxed font-medium" style="">
|
||||
温馨提示:需完善手机号和微信号才能使用提现和找伙伴功能
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-col items-center gap-4">
|
||||
<div class="relative">
|
||||
<div class="w-24 h-24 rounded-full p-1 border-2 border-primary shadow-[0_0_15px_rgba(79,209,197,0.3)]">
|
||||
<img alt="User Avatar" class="w-full h-full rounded-full object-cover" src="https://lh3.googleusercontent.com/aida-public/AB6AXuByaFYqZutDoN6LuA2I7fT4RcZhrFxMFneSEUoMGyHZX55vvf-taz_AAEYDjMagOLNszcrdxJMszI1W-71DtHgK9OaVfJIW6qH0yb33bfdP8nNg9zpyE-F4ujPwa_E8AlZSX9CHISvTfkiB6aUMH8hdz1sA8ptLervlhVR4Cst5N38a4ZiB_zRETMlVJOaPZ1-Ry_XeDXTXAaZQN1xy-WIGX-1rlgs1JUDXg4Ihcv0Am5p4hgwoFat9JdcoYRQN6FfP4b5zzapLoBk" style="">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form class="space-y-6">
|
||||
<div class="space-y-4">
|
||||
<label class="block" style="">
|
||||
<span class="text-sm text-gray-400 ml-1" style="">昵称</span>
|
||||
<input class="mt-1 block w-full bg-input-dark border-border-dark rounded-lg text-white" type="text" value="乘风">
|
||||
</label>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<label class="block" style="">
|
||||
<span class="text-sm text-gray-400 ml-1" style="">MBTI</span>
|
||||
<input class="mt-1 block w-full bg-input-dark border-border-dark rounded-lg text-white" type="text" value="INTJ">
|
||||
</label>
|
||||
<label class="block" style="">
|
||||
<span class="text-sm text-gray-400 ml-1" style="">地区</span>
|
||||
<input class="mt-1 block w-full bg-input-dark border-border-dark rounded-lg text-white" type="text" value="杭州">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</main>
|
||||
<div class="fixed inset-0 z-[60] flex items-center justify-center px-6 modal-overlay">
|
||||
<div class="w-full max-w-sm bg-[#1A1A1A] rounded-[24px] overflow-hidden border border-white/10 shadow-2xl">
|
||||
<div class="px-6 pt-10 pb-6 space-y-6">
|
||||
<div class="text-center">
|
||||
<h2 class="text-xl font-bold text-white tracking-wide" style="">请完善联系方式</h2>
|
||||
</div>
|
||||
<div class="space-y-4">
|
||||
<div class="space-y-1.5">
|
||||
<label class="text-xs font-medium text-gray-400 ml-1" style="">手机号</label>
|
||||
<div class="relative">
|
||||
<span class="material-symbols-outlined absolute left-3 top-1/2 -translate-y-1/2 text-gray-500 text-lg" style="">smartphone</span>
|
||||
<input class="w-full bg-[#262626] border-transparent rounded-xl py-3 pl-10 pr-4 text-white placeholder:text-gray-600 focus:ring-1 focus:ring-primary focus:border-primary transition-all text-sm" placeholder="请输入您的手机号" type="tel">
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-1.5">
|
||||
<label class="text-xs font-medium text-gray-400 ml-1" style="">微信号</label>
|
||||
<div class="relative">
|
||||
<span class="material-symbols-outlined absolute left-3 top-1/2 -translate-y-1/2 text-gray-500 text-lg" style="">chat</span>
|
||||
<input class="w-full bg-[#262626] border-transparent rounded-xl py-3 pl-10 pr-4 text-white placeholder:text-gray-600 focus:ring-1 focus:ring-primary focus:border-primary transition-all text-sm" placeholder="请输入您的微信号" type="text">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-2">
|
||||
<button class="w-full bg-primary hover:bg-[#45BCB0] text-black font-bold py-3.5 rounded-xl text-base transition-all active:scale-[0.98] shadow-lg shadow-primary/20" style="">
|
||||
保存
|
||||
</button>
|
||||
<button class="w-full mt-3 text-gray-500 text-sm font-medium py-2" style="">
|
||||
取消
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="fixed bottom-0 left-0 right-0 bg-black border-t border-white/10 px-6 py-3 pb-6 flex justify-between items-center z-50 opacity-50 pointer-events-none">
|
||||
<div class="flex flex-col items-center gap-1 text-gray-500">
|
||||
<span class="material-symbols-outlined" style="">home</span>
|
||||
<span class="text-[10px]" style="">首页</span>
|
||||
</div>
|
||||
<div class="flex flex-col items-center gap-1 text-gray-500">
|
||||
<span class="material-symbols-outlined" style="">list_alt</span>
|
||||
<span class="text-[10px]" style="">目录</span>
|
||||
</div>
|
||||
<div class="flex flex-col items-center -mt-8">
|
||||
<div class="bg-gray-800 rounded-full p-3 border-4 border-black">
|
||||
<span class="material-symbols-outlined text-3xl text-gray-400" style="">group</span>
|
||||
</div>
|
||||
<span class="text-[10px] text-gray-500 mt-1" style="">找伙伴</span>
|
||||
</div>
|
||||
<div class="flex flex-col items-center gap-1 text-gray-500">
|
||||
<span class="material-symbols-outlined" style="">chat_bubble</span>
|
||||
<span class="text-[10px]" style="">消息</span>
|
||||
</div>
|
||||
<div class="flex flex-col items-center gap-1 text-primary">
|
||||
<span class="material-symbols-outlined" style="">person</span>
|
||||
<span class="text-[10px] font-medium" style="">我的</span>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
</body></html>
|
||||
|
Before Width: | Height: | Size: 76 KiB |
@@ -1,206 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>Profile with Hidden Info Icons</title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<script>
|
||||
tailwind.config = {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
accent: "#5EEAD4",
|
||||
"background-dark": "#050B14",
|
||||
"card-dark": "#0F1720",
|
||||
"card-inner": "#17212F",
|
||||
"text-label": "#94A3B8",
|
||||
"text-value": "#FFFFFF",
|
||||
"highlight-gold": "#F59E0B",
|
||||
},
|
||||
fontFamily: {
|
||||
display: ['"Noto Sans SC"', "sans-serif"],
|
||||
sans: ['"Noto Sans SC"', "sans-serif"],
|
||||
},
|
||||
borderRadius: {
|
||||
DEFAULT: "0.5rem",
|
||||
'xl': '0.75rem',
|
||||
'2xl': '1rem',
|
||||
'3xl': '1.5rem',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style type="text/tailwindcss">
|
||||
html { scroll-behavior: smooth; }
|
||||
::-webkit-scrollbar { width: 0px; background: transparent; }
|
||||
body { -webkit-tap-highlight-color: transparent; }
|
||||
.border-subtle {
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-background-dark font-display text-gray-100 min-h-screen flex flex-col antialiased pb-32">
|
||||
<header class="fixed top-0 w-full z-50 bg-background-dark/90 backdrop-blur-md px-4 py-3 flex items-center justify-between border-b border-white/5">
|
||||
<button class="p-2 -ml-2 rounded-full hover:bg-white/10 transition-colors">
|
||||
<span class="material-symbols-outlined text-accent text-[20px]">arrow_back_ios_new</span>
|
||||
</button>
|
||||
<h1 class="text-[17px] font-bold text-white tracking-wide">个人资料</h1>
|
||||
<div class="flex items-center gap-2">
|
||||
<button class="p-2 rounded-full hover:bg-white/10 transition-colors">
|
||||
<span class="material-symbols-outlined text-white text-[24px]">more_horiz</span>
|
||||
</button>
|
||||
<button class="p-2 -mr-2 rounded-full hover:bg-white/10 transition-colors">
|
||||
<span class="material-symbols-outlined text-white text-[24px]">radio_button_checked</span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
<main class="flex-grow px-4 pt-20 w-full mx-auto space-y-4 max-w-lg">
|
||||
<div class="bg-card-dark border-subtle rounded-2xl p-8 flex flex-col items-center justify-center relative overflow-hidden shadow-lg shadow-black/20">
|
||||
<div class="absolute top-0 inset-x-0 h-32 bg-gradient-to-b from-[#1E3A45]/30 to-transparent pointer-events-none"></div>
|
||||
<div class="relative z-10 flex flex-col items-center">
|
||||
<div class="w-[88px] h-[88px] rounded-full overflow-hidden border border-white/10 mb-4 shadow-xl">
|
||||
<img alt="Profile Picture" class="w-full h-full object-cover" src="https://lh3.googleusercontent.com/aida-public/AB6AXuAkEMaAvAMloIMKdLUz6H3J7wK8hsWRTMPvWXscytVPPy0JGqD0z780NFUWH-LxpGJFc0zhWr-x_dlFJQjPP1TnCUVPzLpGMIS8Rvt7Tas75-TkbQqteNl_6BxURNsrKRf3_9nK2ucsTeFrF20Z9HcbubIYiUwL-55uX5lJV7xfS2GvSxPycZHm7A62PLGxA0eoMAnZwmmgMKOPsQkmTu4W6_1RBXHWFkf1Znjgl9Lsr4dDyIZF3dsbOgJTjudl1i4SRH8Q-6WbGJo"/>
|
||||
</div>
|
||||
<h2 class="text-xl font-bold text-white mb-3 tracking-wide">乘风</h2>
|
||||
<div class="flex items-center justify-center gap-3 text-xs font-medium">
|
||||
<span class="px-3 py-1 bg-[#134E4A] text-accent rounded-full border border-accent/20">INFP</span>
|
||||
<span class="px-3 py-1 bg-[#1F2937] text-gray-300 rounded-full border border-white/10 flex items-center gap-1.5 pl-2">
|
||||
<span class="material-symbols-outlined text-red-500 text-[14px] -ml-0.5">push_pin</span> 杭州
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<section class="bg-card-dark border-subtle rounded-2xl p-5 shadow-lg shadow-black/20">
|
||||
<div class="flex items-center gap-2.5 mb-5">
|
||||
<span class="material-symbols-outlined text-gray-400 text-[20px]">person</span>
|
||||
<h3 class="text-[15px] font-bold text-white tracking-wide">基本信息</h3>
|
||||
</div>
|
||||
<div class="space-y-6">
|
||||
<div>
|
||||
<p class="text-[13px] text-text-label mb-2">行业</p>
|
||||
<p class="text-[15px] font-medium text-text-value">新媒体 / 电商</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-[13px] text-text-label mb-2">职位</p>
|
||||
<p class="text-[15px] font-medium text-text-value">创始人</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-[13px] text-text-label mb-2">业务体量</p>
|
||||
<p class="text-[15px] font-medium text-text-value">年GMV 5000万+</p>
|
||||
</div>
|
||||
<div class="h-px bg-white/5 w-full"></div>
|
||||
<div>
|
||||
<p class="text-[13px] text-text-label mb-2">我擅长</p>
|
||||
<p class="text-[15px] font-medium text-text-value leading-relaxed">
|
||||
短视频制作、IP打造、私域运营
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-[13px] text-text-label mb-2">联系方式</p>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-[15px] font-mono text-text-value tracking-wide">139****02</span>
|
||||
<span class="material-symbols-outlined text-text-label text-[18px] opacity-60">visibility_off</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-[13px] text-text-label mb-2">微信号</p>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-[15px] font-mono text-text-value tracking-wide">wxid_****abc</span>
|
||||
<span class="material-symbols-outlined text-text-label text-[18px] opacity-60">visibility_off</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="bg-card-dark border-subtle rounded-2xl p-5 shadow-lg shadow-black/20">
|
||||
<div class="flex items-center gap-2.5 mb-5">
|
||||
<span class="material-symbols-outlined text-[#FCD34D] text-[20px]">lightbulb</span>
|
||||
<h3 class="text-[15px] font-bold text-white tracking-wide">个人故事</h3>
|
||||
</div>
|
||||
<div class="space-y-6">
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="text-base">🏆</span>
|
||||
<h4 class="text-[13px] font-medium text-text-label">最赚钱的一个月做的是什么</h4>
|
||||
</div>
|
||||
<p class="text-[14px] text-text-value leading-relaxed text-gray-200">
|
||||
旅游账号30天涨粉10万,带货佣金收入12万
|
||||
</p>
|
||||
</div>
|
||||
<div class="h-px bg-white/5 w-full"></div>
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="text-base">⭐️</span>
|
||||
<h4 class="text-[13px] font-medium text-text-label">最有成就感的一件事</h4>
|
||||
</div>
|
||||
<p class="text-[14px] text-text-value leading-relaxed text-gray-200">
|
||||
帮助3个素人打造个人IP,每个月稳定变现5万+
|
||||
</p>
|
||||
</div>
|
||||
<div class="h-px bg-white/5 w-full"></div>
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="material-symbols-outlined text-blue-400 text-[18px]">restart_alt</span>
|
||||
<h4 class="text-[13px] font-medium text-text-label">人生的转折点</h4>
|
||||
</div>
|
||||
<p class="text-[14px] text-text-value leading-relaxed text-gray-200">
|
||||
辞去互联网大厂工作开始做自媒体,第三个月就超过原薪资
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="bg-card-dark border-subtle rounded-2xl p-5 shadow-lg shadow-black/20">
|
||||
<div class="flex items-center gap-2.5 mb-5">
|
||||
<span class="text-[20px]">🤝</span>
|
||||
<h3 class="text-[15px] font-bold text-white tracking-wide">互助需求</h3>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<div class="bg-card-inner rounded-lg p-4 border border-white/5">
|
||||
<span class="inline-block px-2 py-0.5 mb-2 text-[11px] font-medium text-accent bg-[#112D2A] rounded">
|
||||
我能帮你
|
||||
</span>
|
||||
<p class="text-[13px] text-text-value leading-relaxed tracking-wide">
|
||||
短视频脚本、账号冷启动、私域转化设计
|
||||
</p>
|
||||
</div>
|
||||
<div class="bg-card-inner rounded-lg p-4 border border-white/5">
|
||||
<span class="inline-block px-2 py-0.5 mb-2 text-[11px] font-medium text-[#F59E0B] bg-[#2D1F0D] rounded">
|
||||
我需要帮助
|
||||
</span>
|
||||
<p class="text-[13px] text-text-value leading-relaxed tracking-wide">
|
||||
寻找供应链资源和线下活动合作
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="bg-card-dark border-subtle rounded-2xl p-5 mb-6 shadow-lg shadow-black/20">
|
||||
<div class="flex items-center gap-2.5 mb-3">
|
||||
<span class="material-symbols-outlined text-gray-400 text-[20px]">rocket_launch</span>
|
||||
<h3 class="text-[15px] font-bold text-white tracking-wide">项目介绍</h3>
|
||||
</div>
|
||||
<p class="text-[14px] text-text-value leading-relaxed text-gray-200">
|
||||
旅游+生活方式自媒体矩阵,全网粉丝50万+
|
||||
</p>
|
||||
</section>
|
||||
</main>
|
||||
<div class="fixed bottom-0 left-0 right-0 p-4 bg-background-dark/95 backdrop-blur border-t border-white/5 z-40 pb-10">
|
||||
<div class="max-w-lg mx-auto">
|
||||
<button class="w-full bg-transparent text-[#F59E0B] font-medium py-4 rounded-full border border-[#F59E0B]/30 text-[15px] active:scale-[0.98] transition-all duration-200 flex items-center justify-center gap-2 tracking-wide">
|
||||
成为超级个体 <span class="material-symbols-outlined text-[18px]">arrow_forward</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body></html>
|
||||
|
Before Width: | Height: | Size: 139 KiB |
@@ -1,227 +0,0 @@
|
||||
<!DOCTYPE html><html lang="zh-CN" class="dark"><head>
|
||||
<meta charset="utf-8">
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||
<title>Mentor Detail Profile</title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,typography"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<script>
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: "#4FD1C5", // Teal as requested
|
||||
"primary-dark": "#38B2AC",
|
||||
"background-light": "#F7FAFC",
|
||||
"background-dark": "#000000",
|
||||
"surface-dark": "#121212",
|
||||
"surface-light": "#FFFFFF",
|
||||
"card-dark": "#1E1E1E",
|
||||
"card-light": "#FFFFFF",
|
||||
"text-primary-dark": "#FFFFFF",
|
||||
"text-secondary-dark": "#A0AEC0",
|
||||
"text-primary-light": "#1A202C",
|
||||
"text-secondary-light": "#718096",
|
||||
"highlight-orange": "#ED8936",
|
||||
},
|
||||
fontFamily: {
|
||||
display: ["Noto Sans SC", "sans-serif"],
|
||||
},
|
||||
borderRadius: {
|
||||
DEFAULT: "0.5rem",
|
||||
'xl': "1rem",
|
||||
'2xl': "1.5rem",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Noto Sans SC', sans-serif;
|
||||
}.no-scrollbar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
.no-scrollbar {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-background-light dark:bg-background-dark text-text-primary-light dark:text-text-primary-dark transition-colors duration-200">
|
||||
<div class="fixed top-0 left-0 right-0 z-50 bg-background-light/90 dark:bg-background-dark/90 backdrop-blur-md px-4 py-3 flex justify-between items-center border-b border-gray-200 dark:border-gray-800">
|
||||
<button class="text-text-primary-light dark:text-white p-1 rounded-full hover:bg-gray-100 dark:hover:bg-gray-800" style="">
|
||||
<span class="material-icons" style="">arrow_back</span>
|
||||
</button>
|
||||
<h1 class="text-lg font-medium" style="">导师详情</h1>
|
||||
<button class="text-text-primary-light dark:text-white p-1 rounded-full hover:bg-gray-100 dark:hover:bg-gray-800" style="">
|
||||
<span class="material-icons" style="">more_horiz</span>
|
||||
</button>
|
||||
</div>
|
||||
<main class="pt-16 pb-24 px-4 max-w-md mx-auto">
|
||||
<div class="flex flex-col items-center mt-6 mb-8 text-center">
|
||||
<div class="relative mb-4">
|
||||
<div class="w-24 h-24 rounded-full overflow-hidden border-2 border-primary p-0.5">
|
||||
<img alt="Mentor Avatar" class="w-full h-full object-cover rounded-full" src="https://lh3.googleusercontent.com/aida-public/AB6AXuBVtV-57bHdDZe8NP5PbMvnWgtUspxsIEcFOkdZox4jI68GfvFx_cGJi11ZL_iCIhnVxLcFXbRRvgodW1ZtkdJ6N75N_-C7C_Vzoagoh5Ovc-GUD3_Z_uDC1TO9XEA1Mo0CYKykpNzigJbpSL5a2fx93sUEC3PV-Dh8H0mGoI8H7Xu-AHgxEfkULmJHEUnEVoc9yEYBBPQvEGZR6z7KEY_i_QtWjZIG8scxH7VxpSUuuN02PA_UyVyD3pgEEpZTn_w8f63O7i149ak" style="">
|
||||
</div>
|
||||
</div>
|
||||
<h2 class="text-2xl font-bold mb-1" style="">卡若</h2>
|
||||
<p class="text-primary text-sm font-medium mb-4" style="">结构判断型咨询 · Decision > Execution</p>
|
||||
<div class="bg-card-light dark:bg-card-dark rounded-xl p-4 shadow-sm border-l-4 border-primary">
|
||||
<p class="text-sm text-text-secondary-light dark:text-gray-300 leading-relaxed text-left" style="">
|
||||
大多数人失败,不是因为不努力,而是把精力投进了一个一开始就不该参与的结构里。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-8">
|
||||
<div class="flex items-center mb-4">
|
||||
<span class="bg-primary text-black text-xs font-bold px-2 py-0.5 rounded-full mr-2" style="">01</span>
|
||||
<h3 class="font-bold text-lg" style="">为什么找卡若?</h3>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 gap-3">
|
||||
<div class="bg-card-light dark:bg-surface-dark p-3 rounded-lg text-center shadow-sm">
|
||||
<p class="font-bold text-sm mb-1" style="">做事的人</p>
|
||||
<p class="text-xs text-text-secondary-light dark:text-gray-500" style="">方向始终不对</p>
|
||||
</div>
|
||||
<div class="bg-card-light dark:bg-surface-dark p-3 rounded-lg text-center shadow-sm">
|
||||
<p class="font-bold text-sm mb-1" style="">犹豫的人</p>
|
||||
<p class="text-xs text-text-secondary-light dark:text-gray-500" style="">始终不敢决定</p>
|
||||
</div>
|
||||
<div class="bg-card-light dark:bg-surface-dark p-3 rounded-lg text-center shadow-sm">
|
||||
<p class="font-bold text-sm mb-1" style="">已投入的人</p>
|
||||
<p class="text-xs text-text-secondary-light dark:text-gray-500" style="">越投越不确定</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-center text-primary text-xs mt-3 font-medium" style="">共同问题不是能力,而是缺乏一次高质量的判断</p>
|
||||
</div>
|
||||
<div class="mb-8">
|
||||
<div class="flex items-center mb-2">
|
||||
<span class="bg-primary text-black text-xs font-bold px-2 py-0.5 rounded-full mr-2" style="">02</span>
|
||||
<h3 class="font-bold text-lg" style="">提供什么?</h3>
|
||||
</div>
|
||||
<p class="text-xs text-text-secondary-light dark:text-gray-500 mb-4 ml-8" style="">不做激励,不做陪伴 · 专注「决策前的结构判断」</p>
|
||||
<div class="space-y-4">
|
||||
<div class="bg-card-light dark:bg-card-dark rounded-xl p-4 shadow-sm border-l-2 border-primary relative overflow-hidden">
|
||||
<div class="flex items-center mb-2">
|
||||
<div class="bg-primary/20 text-primary w-5 h-5 flex items-center justify-center rounded-full text-xs font-bold mr-2" style="">1</div>
|
||||
<h4 class="font-bold" style="">项目结构判断</h4>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2 pl-7">
|
||||
<span class="text-xs bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded text-text-secondary-light dark:text-gray-400" style="">是否真实存在赚钱结构</span>
|
||||
<span class="text-xs bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded text-text-secondary-light dark:text-gray-400" style="">回报是否可持续</span>
|
||||
<span class="text-xs bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded text-text-secondary-light dark:text-gray-400" style="">普通人成功概率</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-card-light dark:bg-card-dark rounded-xl p-4 shadow-sm border-l-2 border-primary relative overflow-hidden">
|
||||
<div class="flex items-center mb-2">
|
||||
<div class="bg-primary/20 text-primary w-5 h-5 flex items-center justify-center rounded-full text-xs font-bold mr-2" style="">2</div>
|
||||
<h4 class="font-bold" style="">人 × 项目匹配</h4>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2 pl-7">
|
||||
<span class="text-xs bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded text-text-secondary-light dark:text-gray-400" style="">性格资源阶段是否匹配</span>
|
||||
<span class="text-xs bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded text-text-secondary-light dark:text-gray-400" style="">最大优势与致命短板</span>
|
||||
<span class="text-xs bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded text-text-secondary-light dark:text-gray-400" style="">最可能失败节点</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-card-light dark:bg-card-dark rounded-xl p-4 shadow-sm border-l-2 border-primary relative overflow-hidden">
|
||||
<div class="flex items-center mb-2">
|
||||
<div class="bg-primary/20 text-primary w-5 h-5 flex items-center justify-center rounded-full text-xs font-bold mr-2" style="">3</div>
|
||||
<h4 class="font-bold" style="">风险止损判断</h4>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2 pl-7">
|
||||
<span class="text-xs bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded text-text-secondary-light dark:text-gray-400" style="">哪一步是不可逆风险</span>
|
||||
<span class="text-xs bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded text-text-secondary-light dark:text-gray-400" style="">什么时候必须停</span>
|
||||
<span class="text-xs bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded text-text-secondary-light dark:text-gray-400" style="">避免沉没成本陷阱</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-8">
|
||||
<div class="flex items-center mb-4">
|
||||
<span class="bg-primary text-black text-xs font-bold px-2 py-0.5 rounded-full mr-2" style="">03</span>
|
||||
<h3 class="font-bold text-lg" style="">收费标准</h3>
|
||||
</div>
|
||||
<div class="bg-card-light dark:bg-card-dark rounded-xl overflow-hidden shadow-sm">
|
||||
<div class="grid grid-cols-4 bg-primary text-black font-bold text-xs p-3">
|
||||
<div class="col-span-2" style="">咨询项目</div>
|
||||
<div class="text-center" style="">时长</div>
|
||||
<div class="text-right" style="">价格</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-4 p-4 border-b border-gray-100 dark:border-gray-800 items-center">
|
||||
<div class="col-span-2 font-medium text-sm" style="">单次咨询</div>
|
||||
<div class="text-center text-xs text-text-secondary-light dark:text-gray-400" style="">1小时</div>
|
||||
<div class="text-right font-bold text-primary" style="">¥980</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-4 p-4 border-b border-gray-100 dark:border-gray-800 items-center bg-gray-50 dark:bg-surface-dark/30">
|
||||
<div class="col-span-2 font-medium text-sm" style="">半年咨询</div>
|
||||
<div class="text-center text-xs text-text-secondary-light dark:text-gray-400" style="">-</div>
|
||||
<div class="text-right">
|
||||
<div class="text-[10px] text-text-secondary-light dark:text-gray-500 line-through" style="">98000</div>
|
||||
<div class="font-bold text-primary text-sm" style="">¥19,800</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-4 p-4 items-center">
|
||||
<div class="col-span-2 font-medium text-sm" style="">年度咨询</div>
|
||||
<div class="text-center text-xs text-text-secondary-light dark:text-gray-400" style="">-</div>
|
||||
<div class="text-right">
|
||||
<div class="text-[10px] text-text-secondary-light dark:text-gray-500 line-through" style="">196000</div>
|
||||
<div class="font-bold text-primary text-sm" style="">¥29,800</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap justify-center gap-2 mt-4">
|
||||
<span class="text-[10px] bg-primary/10 text-primary px-2 py-1 rounded" style="">项目/副业决策</span>
|
||||
<span class="text-[10px] bg-primary/10 text-primary px-2 py-1 rounded" style="">转型选择</span>
|
||||
<span class="text-[10px] bg-primary/10 text-primary px-2 py-1 rounded" style="">投资判断</span>
|
||||
<span class="text-[10px] bg-primary/10 text-primary px-2 py-1 rounded" style="">关键节点</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-10">
|
||||
<div class="flex items-center mb-4">
|
||||
<span class="bg-primary text-black text-xs font-bold px-2 py-0.5 rounded-full mr-2" style="">04</span>
|
||||
<h3 class="font-bold text-lg" style="">判断风格</h3>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-3">
|
||||
<div class="bg-card-light dark:bg-card-dark border border-gray-100 dark:border-gray-700 px-4 py-2 rounded-full text-sm font-medium shadow-sm" style="">
|
||||
冷静
|
||||
</div>
|
||||
<div class="bg-card-light dark:bg-card-dark border border-gray-100 dark:border-gray-700 px-4 py-2 rounded-full text-sm font-medium shadow-sm" style="">
|
||||
克制
|
||||
</div>
|
||||
<div class="bg-card-light dark:bg-card-dark border border-gray-100 dark:border-gray-700 px-4 py-2 rounded-full text-sm font-medium shadow-sm" style="">
|
||||
偏风险视角
|
||||
</div>
|
||||
<div class="bg-card-light dark:bg-card-dark border border-gray-100 dark:border-gray-700 px-4 py-2 rounded-full text-sm font-medium shadow-sm" style="">
|
||||
偏长期主义
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-center text-[10px] text-text-secondary-light dark:text-gray-600 mb-8" style=""><br></p>
|
||||
</main>
|
||||
<div class="fixed bottom-0 left-0 right-0 bg-background-light dark:bg-background-dark border-t border-gray-200 dark:border-gray-800 p-4 safe-area-pb">
|
||||
<div class="max-w-md mx-auto flex gap-3">
|
||||
<button class="w-full bg-primary hover:bg-primary-dark text-black font-bold py-3 px-4 rounded-xl shadow-lg shadow-primary/20 flex items-center justify-center gap-2" style="">
|
||||
<span class="material-icons text-sm" style="">chat_bubble</span>
|
||||
链接导师
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="h-6 w-full bg-background-light dark:bg-background-dark"></div>
|
||||
<script>
|
||||
// Force dark mode for this demo as requested by user context "dark UI style of Reference Image 1"
|
||||
// But keeping the capability to toggle if needed.
|
||||
document.documentElement.classList.add('dark');
|
||||
</script>
|
||||
|
||||
</body></html>
|
||||
|
Before Width: | Height: | Size: 161 KiB |
@@ -1,312 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>Mentor Detail Profile</title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,typography"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<script>
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: "#4FD1C5", // Teal as requested
|
||||
"primary-dark": "#38B2AC",
|
||||
"background-light": "#F7FAFC",
|
||||
"background-dark": "#000000",
|
||||
"surface-dark": "#121212",
|
||||
"surface-light": "#FFFFFF",
|
||||
"card-dark": "#1E1E1E",
|
||||
"card-light": "#FFFFFF",
|
||||
"text-primary-dark": "#FFFFFF",
|
||||
"text-secondary-dark": "#A0AEC0",
|
||||
"text-primary-light": "#1A202C",
|
||||
"text-secondary-light": "#718096",
|
||||
"highlight-orange": "#ED8936", // Keeping the orange from Ref 2 for contrast if needed, or mapping to Teal
|
||||
},
|
||||
fontFamily: {
|
||||
display: ["Noto Sans SC", "sans-serif"],
|
||||
},
|
||||
borderRadius: {
|
||||
DEFAULT: "0.5rem",
|
||||
'xl': "1rem",
|
||||
'2xl': "1.5rem",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Noto Sans SC', sans-serif;
|
||||
}.no-scrollbar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
.no-scrollbar {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-background-light dark:bg-background-dark text-text-primary-light dark:text-text-primary-dark transition-colors duration-200 relative">
|
||||
<div class="fixed top-0 left-0 right-0 z-40 bg-background-light/90 dark:bg-background-dark/90 backdrop-blur-md px-4 py-3 flex justify-between items-center border-b border-gray-200 dark:border-gray-800">
|
||||
<button class="text-text-primary-light dark:text-white p-1 rounded-full hover:bg-gray-100 dark:hover:bg-gray-800">
|
||||
<span class="material-icons">arrow_back</span>
|
||||
</button>
|
||||
<h1 class="text-lg font-medium">导师详情</h1>
|
||||
<button class="text-text-primary-light dark:text-white p-1 rounded-full hover:bg-gray-100 dark:hover:bg-gray-800">
|
||||
<span class="material-icons">more_horiz</span>
|
||||
</button>
|
||||
</div>
|
||||
<main class="pt-16 pb-24 px-4 max-w-md mx-auto blur-sm select-none pointer-events-none">
|
||||
<div class="flex flex-col items-center mt-6 mb-8 text-center">
|
||||
<div class="relative mb-4">
|
||||
<div class="w-24 h-24 rounded-full overflow-hidden border-2 border-primary p-0.5">
|
||||
<img alt="Mentor Avatar" class="w-full h-full object-cover rounded-full" src="https://lh3.googleusercontent.com/aida-public/AB6AXuBVtV-57bHdDZe8NP5PbMvnWgtUspxsIEcFOkdZox4jI68GfvFx_cGJi11ZL_iCIhnVxLcFXbRRvgodW1ZtkdJ6N75N_-C7C_Vzoagoh5Ovc-GUD3_Z_uDC1TO9XEA1Mo0CYKykpNzigJbpSL5a2fx93sUEC3PV-Dh8H0mGoI8H7Xu-AHgxEfkULmJHEUnEVoc9yEYBBPQvEGZR6z7KEY_i_QtWjZIG8scxH7VxpSUuuN02PA_UyVyD3pgEEpZTn_w8f63O7i149ak"/>
|
||||
</div>
|
||||
</div>
|
||||
<h2 class="text-2xl font-bold mb-1">卡若</h2>
|
||||
<p class="text-primary text-sm font-medium mb-4">结构判断型咨询 · Decision > Execution</p>
|
||||
<div class="bg-card-light dark:bg-card-dark rounded-xl p-4 shadow-sm border-l-4 border-primary">
|
||||
<p class="text-sm text-text-secondary-light dark:text-gray-300 leading-relaxed text-left">
|
||||
大多数人失败,不是因为不努力,而是把精力投进了一个一开始就不该参与的结构里。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-8">
|
||||
<div class="flex items-center mb-4">
|
||||
<span class="bg-primary text-black text-xs font-bold px-2 py-0.5 rounded-full mr-2">01</span>
|
||||
<h3 class="font-bold text-lg">为什么找卡若?</h3>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 gap-3">
|
||||
<div class="bg-card-light dark:bg-surface-dark p-3 rounded-lg text-center shadow-sm">
|
||||
<p class="font-bold text-sm mb-1">做事的人</p>
|
||||
<p class="text-xs text-text-secondary-light dark:text-gray-500">方向始终不对</p>
|
||||
</div>
|
||||
<div class="bg-card-light dark:bg-surface-dark p-3 rounded-lg text-center shadow-sm">
|
||||
<p class="font-bold text-sm mb-1">犹豫的人</p>
|
||||
<p class="text-xs text-text-secondary-light dark:text-gray-500">始终不敢决定</p>
|
||||
</div>
|
||||
<div class="bg-card-light dark:bg-surface-dark p-3 rounded-lg text-center shadow-sm">
|
||||
<p class="font-bold text-sm mb-1">已投入的人</p>
|
||||
<p class="text-xs text-text-secondary-light dark:text-gray-500">越投越不确定</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-center text-primary text-xs mt-3 font-medium">共同问题不是能力,而是缺乏一次高质量的判断</p>
|
||||
</div>
|
||||
<div class="mb-8">
|
||||
<div class="flex items-center mb-2">
|
||||
<span class="bg-primary text-black text-xs font-bold px-2 py-0.5 rounded-full mr-2">02</span>
|
||||
<h3 class="font-bold text-lg">提供什么?</h3>
|
||||
</div>
|
||||
<p class="text-xs text-text-secondary-light dark:text-gray-500 mb-4 ml-8">不做激励,不做陪伴 · 专注「决策前的结构判断」</p>
|
||||
<div class="space-y-4">
|
||||
<div class="bg-card-light dark:bg-card-dark rounded-xl p-4 shadow-sm border-l-2 border-primary relative overflow-hidden">
|
||||
<div class="flex items-center mb-2">
|
||||
<div class="bg-primary/20 text-primary w-5 h-5 flex items-center justify-center rounded-full text-xs font-bold mr-2">1</div>
|
||||
<h4 class="font-bold">项目结构判断</h4>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2 pl-7">
|
||||
<span class="text-xs bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded text-text-secondary-light dark:text-gray-400">是否真实存在赚钱结构</span>
|
||||
<span class="text-xs bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded text-text-secondary-light dark:text-gray-400">回报是否可持续</span>
|
||||
<span class="text-xs bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded text-text-secondary-light dark:text-gray-400">普通人成功概率</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-card-light dark:bg-card-dark rounded-xl p-4 shadow-sm border-l-2 border-primary relative overflow-hidden">
|
||||
<div class="flex items-center mb-2">
|
||||
<div class="bg-primary/20 text-primary w-5 h-5 flex items-center justify-center rounded-full text-xs font-bold mr-2">2</div>
|
||||
<h4 class="font-bold">人 × 项目匹配</h4>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2 pl-7">
|
||||
<span class="text-xs bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded text-text-secondary-light dark:text-gray-400">性格资源阶段是否匹配</span>
|
||||
<span class="text-xs bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded text-text-secondary-light dark:text-gray-400">最大优势与致命短板</span>
|
||||
<span class="text-xs bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded text-text-secondary-light dark:text-gray-400">最可能失败节点</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-card-light dark:bg-card-dark rounded-xl p-4 shadow-sm border-l-2 border-primary relative overflow-hidden">
|
||||
<div class="flex items-center mb-2">
|
||||
<div class="bg-primary/20 text-primary w-5 h-5 flex items-center justify-center rounded-full text-xs font-bold mr-2">3</div>
|
||||
<h4 class="font-bold">风险止损判断</h4>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2 pl-7">
|
||||
<span class="text-xs bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded text-text-secondary-light dark:text-gray-400">哪一步是不可逆风险</span>
|
||||
<span class="text-xs bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded text-text-secondary-light dark:text-gray-400">什么时候必须停</span>
|
||||
<span class="text-xs bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded text-text-secondary-light dark:text-gray-400">避免沉没成本陷阱</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-8">
|
||||
<div class="flex items-center mb-4">
|
||||
<span class="bg-primary text-black text-xs font-bold px-2 py-0.5 rounded-full mr-2">03</span>
|
||||
<h3 class="font-bold text-lg">收费标准</h3>
|
||||
</div>
|
||||
<div class="bg-card-light dark:bg-card-dark rounded-xl overflow-hidden shadow-sm">
|
||||
<div class="grid grid-cols-4 bg-primary text-black font-bold text-xs p-3">
|
||||
<div class="col-span-2">咨询项目</div>
|
||||
<div class="text-center">时长</div>
|
||||
<div class="text-right">价格</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-4 p-4 border-b border-gray-100 dark:border-gray-800 items-center">
|
||||
<div class="col-span-2 font-medium text-sm">单次咨询</div>
|
||||
<div class="text-center text-xs text-text-secondary-light dark:text-gray-400">1小时</div>
|
||||
<div class="text-right font-bold text-primary">¥980</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-4 p-4 border-b border-gray-100 dark:border-gray-800 items-center bg-gray-50 dark:bg-surface-dark/30">
|
||||
<div class="col-span-2 font-medium text-sm">半年咨询</div>
|
||||
<div class="text-center text-xs text-text-secondary-light dark:text-gray-400">-</div>
|
||||
<div class="text-right">
|
||||
<div class="text-[10px] text-text-secondary-light dark:text-gray-500 line-through">98000</div>
|
||||
<div class="font-bold text-primary text-sm">¥19,800</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-4 p-4 items-center">
|
||||
<div class="col-span-2 font-medium text-sm">年度咨询</div>
|
||||
<div class="text-center text-xs text-text-secondary-light dark:text-gray-400">-</div>
|
||||
<div class="text-right">
|
||||
<div class="text-[10px] text-text-secondary-light dark:text-gray-500 line-through">196000</div>
|
||||
<div class="font-bold text-primary text-sm">¥29,800</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap justify-center gap-2 mt-4">
|
||||
<span class="text-[10px] bg-primary/10 text-primary px-2 py-1 rounded">项目/副业决策</span>
|
||||
<span class="text-[10px] bg-primary/10 text-primary px-2 py-1 rounded">转型选择</span>
|
||||
<span class="text-[10px] bg-primary/10 text-primary px-2 py-1 rounded">投资判断</span>
|
||||
<span class="text-[10px] bg-primary/10 text-primary px-2 py-1 rounded">关键节点</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-10">
|
||||
<div class="flex items-center mb-4">
|
||||
<span class="bg-primary text-black text-xs font-bold px-2 py-0.5 rounded-full mr-2">04</span>
|
||||
<h3 class="font-bold text-lg">判断风格</h3>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-3">
|
||||
<div class="bg-card-light dark:bg-card-dark border border-gray-100 dark:border-gray-700 px-4 py-2 rounded-full text-sm font-medium shadow-sm">
|
||||
冷静
|
||||
</div>
|
||||
<div class="bg-card-light dark:bg-card-dark border border-gray-100 dark:border-gray-700 px-4 py-2 rounded-full text-sm font-medium shadow-sm">
|
||||
克制
|
||||
</div>
|
||||
<div class="bg-card-light dark:bg-card-dark border border-gray-100 dark:border-gray-700 px-4 py-2 rounded-full text-sm font-medium shadow-sm">
|
||||
偏风险视角
|
||||
</div>
|
||||
<div class="bg-card-light dark:bg-card-dark border border-gray-100 dark:border-gray-700 px-4 py-2 rounded-full text-sm font-medium shadow-sm">
|
||||
偏长期主义
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-primary/5 dark:bg-card-dark rounded-2xl p-6 text-center border border-primary/20 mb-8">
|
||||
<h4 class="font-bold mb-4 text-primary">扫码预约咨询</h4>
|
||||
<div class="w-32 h-32 bg-white mx-auto rounded-lg flex items-center justify-center mb-3">
|
||||
<span class="material-icons text-6xl text-gray-800">qr_code_2</span>
|
||||
</div>
|
||||
<p class="text-xs text-text-secondary-light dark:text-gray-500">卡若 | 结构判断咨询</p>
|
||||
</div>
|
||||
<p class="text-center text-[10px] text-text-secondary-light dark:text-gray-600 mb-8">
|
||||
判断的价值,往往体现在你"没做"的那一步
|
||||
</p>
|
||||
</main>
|
||||
<div class="fixed bottom-0 left-0 right-0 bg-background-light dark:bg-background-dark border-t border-gray-200 dark:border-gray-800 p-4 safe-area-pb z-30 blur-sm pointer-events-none select-none">
|
||||
<div class="max-w-md mx-auto flex gap-3">
|
||||
<button class="flex-1 bg-surface-dark dark:bg-surface-dark border border-gray-300 dark:border-gray-700 text-text-primary-light dark:text-white font-bold py-3 px-4 rounded-xl flex items-center justify-center gap-2">
|
||||
<span class="material-icons text-sm">share</span>
|
||||
分享
|
||||
</button>
|
||||
<button class="flex-[2] bg-primary hover:bg-primary-dark text-black font-bold py-3 px-4 rounded-xl shadow-lg shadow-primary/20 flex items-center justify-center gap-2">
|
||||
<span class="material-icons text-sm">chat_bubble</span>
|
||||
联系导师
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="h-6 w-full bg-background-light dark:bg-background-dark z-30 blur-sm"></div>
|
||||
<div class="fixed inset-0 z-50 flex items-end justify-center sm:items-center p-4 bg-black/70 backdrop-blur-sm animate-fade-in">
|
||||
<div class="bg-surface-dark w-full max-w-sm rounded-t-2xl sm:rounded-2xl overflow-hidden shadow-2xl ring-1 ring-white/10 animate-slide-up">
|
||||
<div class="px-6 pt-6 pb-4 flex items-center justify-between border-b border-gray-800">
|
||||
<h3 class="text-xl font-bold text-white">选择咨询项目</h3>
|
||||
<button class="text-gray-400 hover:text-white transition-colors">
|
||||
<span class="material-icons">close</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="p-6 space-y-3">
|
||||
<label class="block relative group cursor-pointer">
|
||||
<input checked="" class="peer sr-only" name="service" type="radio"/>
|
||||
<div class="p-4 rounded-xl bg-card-dark border border-gray-700 peer-checked:border-primary peer-checked:bg-primary/5 transition-all">
|
||||
<div class="flex justify-between items-center mb-1">
|
||||
<span class="font-bold text-white text-base">单次咨询</span>
|
||||
<div class="w-5 h-5 rounded-full border border-gray-500 peer-checked:border-primary peer-checked:bg-primary flex items-center justify-center">
|
||||
<div class="w-2.5 h-2.5 bg-black rounded-full opacity-0 peer-checked:opacity-100 transition-opacity"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between items-end">
|
||||
<span class="text-xs text-gray-400">1小时深度沟通</span>
|
||||
<span class="text-lg font-bold text-primary">¥980</span>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
<label class="block relative group cursor-pointer">
|
||||
<input class="peer sr-only" name="service" type="radio"/>
|
||||
<div class="p-4 rounded-xl bg-card-dark border border-gray-700 peer-checked:border-primary peer-checked:bg-primary/5 transition-all">
|
||||
<div class="flex justify-between items-center mb-1">
|
||||
<span class="font-bold text-white text-base">半年咨询</span>
|
||||
<div class="w-5 h-5 rounded-full border border-gray-500 peer-checked:border-primary peer-checked:bg-primary flex items-center justify-center">
|
||||
<div class="w-2.5 h-2.5 bg-black rounded-full opacity-0 peer-checked:opacity-100 transition-opacity"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between items-end">
|
||||
<span class="text-xs text-gray-400">不限次数 · 关键节点陪伴</span>
|
||||
<div class="text-right">
|
||||
<span class="text-xs text-gray-500 line-through mr-1">¥98,000</span>
|
||||
<span class="text-lg font-bold text-primary">¥19,800</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
<label class="block relative group cursor-pointer">
|
||||
<input class="peer sr-only" name="service" type="radio"/>
|
||||
<div class="p-4 rounded-xl bg-card-dark border border-gray-700 peer-checked:border-primary peer-checked:bg-primary/5 transition-all">
|
||||
<div class="flex justify-between items-center mb-1">
|
||||
<span class="font-bold text-white text-base">年度咨询</span>
|
||||
<span class="ml-2 text-[10px] bg-highlight-orange text-white px-1.5 py-0.5 rounded">推荐</span>
|
||||
<div class="w-5 h-5 rounded-full border border-gray-500 peer-checked:border-primary peer-checked:bg-primary flex items-center justify-center ml-auto">
|
||||
<div class="w-2.5 h-2.5 bg-black rounded-full opacity-0 peer-checked:opacity-100 transition-opacity"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between items-end">
|
||||
<span class="text-xs text-gray-400">全年度战略顾问</span>
|
||||
<div class="text-right">
|
||||
<span class="text-xs text-gray-500 line-through mr-1">¥196,000</span>
|
||||
<span class="text-lg font-bold text-primary">¥29,800</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="p-6 pt-2 pb-8 bg-surface-dark border-t border-gray-800">
|
||||
<button class="w-full bg-primary hover:bg-primary-dark text-black font-bold py-3.5 px-4 rounded-xl shadow-lg shadow-primary/20 transition-colors flex items-center justify-center gap-2">
|
||||
确认选择
|
||||
<span class="material-icons text-sm">arrow_forward</span>
|
||||
</button>
|
||||
<p class="text-center text-[10px] text-gray-500 mt-3">点击确认即代表同意 <a class="text-gray-400 underline" href="#">服务协议</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// Force dark mode for this demo as requested by user context "dark UI style of Reference Image 1"
|
||||
document.documentElement.classList.add('dark');
|
||||
</script>
|
||||
|
||||
</body></html>
|
||||
|
Before Width: | Height: | Size: 103 KiB |
@@ -1,200 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="dark" lang="zh-CN"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>导师列表页</title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,typography,container-queries"></script>
|
||||
<script>
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: "#2DD4BF",
|
||||
"background-dark": "#000000",
|
||||
"card-dark": "#1C1C1E",
|
||||
"nav-dark": "#1C1C1E",
|
||||
"subtext-dark": "#A1A1AA",
|
||||
"tag-bg": "#2C2C2E",
|
||||
"tag-text": "#E5E7EB",
|
||||
},
|
||||
fontFamily: {
|
||||
display: ["PingFang SC", "Heiti SC", "SF Pro Display", "Roboto", "sans-serif"],
|
||||
body: ["PingFang SC", "Heiti SC", "SF Pro Text", "Roboto", "sans-serif"],
|
||||
},
|
||||
borderRadius: {
|
||||
DEFAULT: "0.5rem",
|
||||
'xl': '1rem',
|
||||
'2xl': '1.5rem',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&display=swap" rel="stylesheet"/>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Noto Sans SC', sans-serif;
|
||||
}
|
||||
.scrollbar-hide::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
.scrollbar-hide {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
.safe-area-bottom {
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-background-dark text-gray-100 min-h-screen font-body antialiased selection:bg-primary selection:text-white">
|
||||
<div class="sticky top-0 z-50 bg-background-dark/95 backdrop-blur-md px-4 pt-12 pb-2 border-b border-gray-800">
|
||||
<div class="relative flex items-center justify-between h-11 mb-2">
|
||||
<button class="flex items-center justify-center w-8 h-8 -ml-1 text-white hover:text-gray-300 transition-colors">
|
||||
<span class="material-symbols-outlined text-[24px]">arrow_back</span>
|
||||
</button>
|
||||
<h1 class="absolute left-1/2 transform -translate-x-1/2 text-[17px] font-medium text-white tracking-wide">选择导师</h1>
|
||||
<button class="flex items-center justify-center w-8 h-8 -mr-1 text-white hover:text-gray-300 transition-colors">
|
||||
<span class="material-symbols-outlined text-[24px]">more_horiz</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="relative">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<span class="material-symbols-outlined text-gray-500 text-[20px]">search</span>
|
||||
</div>
|
||||
<input class="block w-full pl-10 pr-3 py-3 border-none rounded-xl bg-card-dark text-white placeholder-gray-500 focus:outline-none focus:ring-1 focus:ring-primary/50 shadow-sm text-sm" placeholder="搜索导师、技能或行业..." type="text"/>
|
||||
</div>
|
||||
<div class="flex gap-3 overflow-x-auto scrollbar-hide mt-4 pb-2">
|
||||
<button class="whitespace-nowrap px-4 py-1.5 rounded-full bg-primary text-black font-semibold text-xs">全部</button>
|
||||
<button class="whitespace-nowrap px-4 py-1.5 rounded-full bg-card-dark border border-gray-800 text-gray-300 font-medium text-xs hover:border-gray-600 transition-colors">项目结构判断</button>
|
||||
<button class="whitespace-nowrap px-4 py-1.5 rounded-full bg-card-dark border border-gray-800 text-gray-300 font-medium text-xs hover:border-gray-600 transition-colors">产品架构</button>
|
||||
<button class="whitespace-nowrap px-4 py-1.5 rounded-full bg-card-dark border border-gray-800 text-gray-300 font-medium text-xs hover:border-gray-600 transition-colors">BP梳理</button>
|
||||
</div>
|
||||
</div>
|
||||
<main class="px-4 pb-8 space-y-4 pt-4 safe-area-bottom">
|
||||
<div class="flex justify-between items-end mb-2">
|
||||
<h2 class="text-base font-bold text-gray-200">推荐导师</h2>
|
||||
<a class="text-xs text-primary font-medium hover:opacity-80 flex items-center" href="#">查看全部 <span class="material-symbols-outlined text-[16px] ml-0.5">chevron_right</span></a>
|
||||
</div>
|
||||
<div class="bg-card-dark rounded-2xl p-4 shadow-sm border border-gray-800 relative overflow-hidden group hover:border-gray-700 transition-all">
|
||||
<div class="flex gap-4">
|
||||
<div class="flex-shrink-0 relative">
|
||||
<img alt="Mentor Profile" class="w-14 h-14 rounded-full object-cover border border-gray-700 shadow-md" src="https://lh3.googleusercontent.com/aida-public/AB6AXuB8f2js-gZTCIf5XMw7hgLz3DoqdqAR5N8rUvWrDHBs_4YlILiWPBK1kEQFcMNQZ47g9PT70QUwm2URAAOhr4tUQv_ckcnlsgorXbxw7wehqOJ7e5FUp2zcLvuVBj0WE_nKVNHiv5-Gpvz6qDJnDwL3_JnV4TzY1x1Mz-0lGUqkYWldPfLllwdrpgthJ2hGbaNDIXYbkSrDL5nJhWNrHIB0tVNHzuOLI3-JEY1jATxRTrjhZn4c0fAFRXYIPgjD3PNW0cOfi0GwXRA"/>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="flex justify-between items-start">
|
||||
<div>
|
||||
<h3 class="text-base font-bold text-white leading-tight">卡若</h3>
|
||||
<p class="text-xs text-subtext-dark mt-1">结构判断型咨询 · Decision > Execution</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2 mt-3">
|
||||
<span class="px-2 py-1 rounded-md text-[10px] font-medium bg-tag-bg text-tag-text border border-gray-700/50">项目结构判断</span>
|
||||
<span class="px-2 py-1 rounded-md text-[10px] font-medium bg-tag-bg text-tag-text border border-gray-700/50">风险止损</span>
|
||||
<span class="px-2 py-1 rounded-md text-[10px] font-medium bg-tag-bg text-tag-text border border-gray-700/50">人×项目匹配</span>
|
||||
</div>
|
||||
<div class="flex justify-between items-center mt-4 border-t border-gray-800 pt-3">
|
||||
<div class="flex items-baseline gap-1">
|
||||
<span class="text-lg font-bold text-primary">¥980</span>
|
||||
<span class="text-xs font-normal text-gray-500">起 / 单次咨询</span>
|
||||
</div>
|
||||
<button class="bg-white text-black px-4 py-1.5 rounded-full text-xs font-bold hover:opacity-90 transition-opacity">预约</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-card-dark rounded-2xl p-4 shadow-sm border border-gray-800 relative overflow-hidden group hover:border-gray-700 transition-all">
|
||||
<div class="flex gap-4">
|
||||
<div class="flex-shrink-0 relative">
|
||||
<img alt="Mentor Profile" class="w-14 h-14 rounded-full object-cover border border-gray-700 shadow-md" src="https://lh3.googleusercontent.com/aida-public/AB6AXuCHmRfkFR5OClBawJnpt7pU_9LygmMV2dM8eqjbmJourDUDo4WOoMhXVw7B1EPq40Qp5ENcR0Wkz3T4DgS8Wmvzz739wvo2VVn98H8vjJYqWW1WWzkXo3LiSWy78IhoE3nt0uIxFvx8BiBohPcIlqCSr6orLvUdA781O75du-RfI7a_gPWsSt29awOyyVO5RDpXQ9vhqdulaZA5LBlKa0_ZzaFCGq5eqiKV8WXTRUnNJunGsou7HEs31q8RncKHqyhPhqqGu1Un9qk"/>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="flex justify-between items-start">
|
||||
<div>
|
||||
<h3 class="text-base font-bold text-white leading-tight">林晓雯</h3>
|
||||
<p class="text-xs text-subtext-dark mt-1">资深产品经理 · 10年互联网经验</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2 mt-3">
|
||||
<span class="px-2 py-1 rounded-md text-[10px] font-medium bg-tag-bg text-tag-text border border-gray-700/50">产品架构</span>
|
||||
<span class="px-2 py-1 rounded-md text-[10px] font-medium bg-tag-bg text-tag-text border border-gray-700/50">MVP落地</span>
|
||||
</div>
|
||||
<div class="flex justify-between items-center mt-4 border-t border-gray-800 pt-3">
|
||||
<div class="flex items-baseline gap-1">
|
||||
<span class="text-lg font-bold text-primary">¥1,200</span>
|
||||
<span class="text-xs font-normal text-gray-500">起 / 单次咨询</span>
|
||||
</div>
|
||||
<button class="bg-white text-black px-4 py-1.5 rounded-full text-xs font-bold hover:opacity-90 transition-opacity">预约</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-card-dark rounded-2xl p-4 shadow-sm border border-gray-800 relative overflow-hidden group hover:border-gray-700 transition-all">
|
||||
<div class="flex gap-4">
|
||||
<div class="flex-shrink-0 relative">
|
||||
<img alt="Mentor Profile" class="w-14 h-14 rounded-full object-cover border border-gray-700 shadow-md" src="https://lh3.googleusercontent.com/aida-public/AB6AXuAxI32u0vnwLDLLpyu7oE9BwN_vgFHbOARwqczhJZ8YacePvj_rSo7yD2DCv1eKyh6eR21QQtCYhccxg1VT-VXpG4LwuXNGFjcN_Q6UMf44_7cjVTGlo0ccINiljCY7UNybGtL99zlNj6bqhI27XFT7BDbBq0EDOhCoBuQI3jUzc_ge-GcQb7EdfXXx0wVm4B715gQo67--eH1_cyHoHOSaFYHqaUffpmWEiyL7qseQ9m_nlPawgzN_vi0fEZG_PWLXK84bKcxyxJg"/>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="flex justify-between items-start">
|
||||
<div>
|
||||
<h3 class="text-base font-bold text-white leading-tight">张伟</h3>
|
||||
<p class="text-xs text-subtext-dark mt-1">连续创业者 · 融资顾问</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2 mt-3">
|
||||
<span class="px-2 py-1 rounded-md text-[10px] font-medium bg-tag-bg text-tag-text border border-gray-700/50">BP梳理</span>
|
||||
<span class="px-2 py-1 rounded-md text-[10px] font-medium bg-tag-bg text-tag-text border border-gray-700/50">股权设计</span>
|
||||
<span class="px-2 py-1 rounded-md text-[10px] font-medium bg-tag-bg text-tag-text border border-gray-700/50">路演辅导</span>
|
||||
</div>
|
||||
<div class="flex justify-between items-center mt-4 border-t border-gray-800 pt-3">
|
||||
<div class="flex items-baseline gap-1">
|
||||
<span class="text-lg font-bold text-primary">¥2,500</span>
|
||||
<span class="text-xs font-normal text-gray-500">起 / 单次咨询</span>
|
||||
</div>
|
||||
<button class="bg-white text-black px-4 py-1.5 rounded-full text-xs font-bold hover:opacity-90 transition-opacity">预约</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-card-dark rounded-2xl p-4 shadow-sm border border-gray-800 relative overflow-hidden group hover:border-gray-700 transition-all">
|
||||
<div class="flex gap-4">
|
||||
<div class="flex-shrink-0 relative">
|
||||
<img alt="Mentor Profile" class="w-14 h-14 rounded-full object-cover border border-gray-700 shadow-md" src="https://lh3.googleusercontent.com/aida-public/AB6AXuCGZYHocKCph6QWMbGW_jomr8o5Nb4IkALRSDYXilrMR6RZaVREGYZrQul5r2ILFWGycCwzAEILQltE4HrkmTohyETRNu-D-fHv-UvP8KxnyCzm8KjCMiMkhWeFsdWqoIQpxoaBXAkfRoF3M4n2IddKUo9k1EyUaNPzhnTtqCQwYO6UKHp7AyJeoI0-Y17vbwTvp2wFjHBhGfBSCMqbPzoKyGJYxo0MNBTrHVWnbJsv7NfGzENkg01G2SAlSXrGG691wAVnDfQwH3E"/>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="flex justify-between items-start">
|
||||
<div>
|
||||
<h3 class="text-base font-bold text-white leading-tight">Sarah Chen</h3>
|
||||
<p class="text-xs text-subtext-dark mt-1">跨国企业HRD · 职业规划</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2 mt-3">
|
||||
<span class="px-2 py-1 rounded-md text-[10px] font-medium bg-tag-bg text-tag-text border border-gray-700/50">职业转型</span>
|
||||
<span class="px-2 py-1 rounded-md text-[10px] font-medium bg-tag-bg text-tag-text border border-gray-700/50">面试辅导</span>
|
||||
</div>
|
||||
<div class="flex justify-between items-center mt-4 border-t border-gray-800 pt-3">
|
||||
<div class="flex items-baseline gap-1">
|
||||
<span class="text-lg font-bold text-primary">¥600</span>
|
||||
<span class="text-xs font-normal text-gray-500">起 / 单次咨询</span>
|
||||
</div>
|
||||
<button class="bg-white text-black px-4 py-1.5 rounded-full text-xs font-bold hover:opacity-90 transition-opacity">预约</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<script>
|
||||
document.documentElement.classList.add('dark');
|
||||
</script>
|
||||
|
||||
</body></html>
|
||||
|
Before Width: | Height: | Size: 210 KiB |
@@ -1,269 +0,0 @@
|
||||
<!DOCTYPE html><html class="dark" lang="zh-CN"><head>
|
||||
<meta charset="utf-8">
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||
<title>Clean Home with Contact Author Link</title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,typography"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet">
|
||||
<script>
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: "#4FD1C5", // Teal accent
|
||||
"background-dark": "#000000", // Pure black background
|
||||
"card-dark": "#1C1C1E", // Dark gray card background
|
||||
"text-primary": "#FFFFFF",
|
||||
"text-secondary": "#A0AEC0",
|
||||
"accent-orange": "#F6AD55",
|
||||
},
|
||||
fontFamily: {
|
||||
sans: ['"Noto Sans SC"', 'sans-serif'],
|
||||
},
|
||||
borderRadius: {
|
||||
DEFAULT: "0.75rem",
|
||||
xl: "1rem",
|
||||
'2xl': "1.5rem",
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style type="text/tailwindcss">
|
||||
.hide-scrollbar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
.hide-scrollbar {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
background-color: #000000;
|
||||
}
|
||||
.material-symbols-outlined {
|
||||
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-background-dark text-text-primary font-sans antialiased">
|
||||
<div class="max-w-md mx-auto min-h-screen relative pb-24">
|
||||
<header class="pt-6 px-4 pb-2 flex items-center justify-between">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-10 h-10 bg-primary rounded-xl flex items-center justify-center text-black font-bold text-lg shadow-lg shadow-primary/20" style="">
|
||||
S
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex items-center gap-2">
|
||||
<h1 class="text-xl font-bold text-white" style="">Soul创业派对</h1>
|
||||
<div class="flex items-center bg-card-dark rounded-full pr-2 pl-0.5 py-0.5 border border-gray-800">
|
||||
<img alt="Author" class="w-5 h-5 rounded-full object-cover mr-1.5" src="https://lh3.googleusercontent.com/aida-public/AB6AXuDt0LPVk4rpoGURC14aewQDlOdPLCY-WBgu-orJ7EKJzZsYaiK2eSxQEL4l36LMFzK-fXWmWyX-xfhB4NQqEOhNM1Sc0tLIJmyRFNSgeitHN4Do7Beo9rKT-kQPmKSZGq6ae4XzpkJGoq9ymqfPqgqgpgSDicCKajZrR-MHh3Xz8NvKAlVKsRWo0HKv79WIo8muyOqz7C1j1X_bb3JJm3dKGi2Ls2UBiRvTj2W5F7vejrW3iHsazchJaXEa9tzgARzYKLUICz7nY0k" style="">
|
||||
<button class="text-[10px] font-bold text-primary active:scale-95 transition-transform" style="">
|
||||
点击链接卡若</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-text-secondary mt-0.5" style="">来自派对房的真实故事</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-card-dark px-2 py-1 rounded-md text-xs font-medium text-primary" style="">
|
||||
73章
|
||||
</div>
|
||||
</header>
|
||||
<div class="px-4 mt-4">
|
||||
<div class="relative">
|
||||
<span class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<span class="material-symbols-outlined text-gray-500 text-sm" style="">search</span>
|
||||
</span>
|
||||
<input class="block w-full pl-10 pr-3 py-3 rounded-xl bg-card-dark border-none text-sm placeholder-gray-500 text-white focus:ring-1 focus:ring-primary transition-all" placeholder="搜索章节标题或内容..." type="text">
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-4 mt-6">
|
||||
<div class="bg-gradient-to-br from-[#1a2e2c] to-black rounded-2xl p-6 relative overflow-hidden border border-gray-800">
|
||||
<div class="absolute -right-10 -top-10 w-40 h-40 bg-primary/5 rounded-full blur-3xl"></div>
|
||||
<span class="inline-block bg-primary text-black text-[10px] font-bold px-2 py-1 rounded-md mb-3" style="">最新更新</span>
|
||||
<h2 class="text-2xl font-bold text-white mb-1" style="">流量红利的终局</h2>
|
||||
<p class="text-text-secondary text-sm mb-6" style="">第五篇 真实的社会</p>
|
||||
<a class="inline-flex items-center text-primary font-medium text-sm hover:text-white transition-colors" href="#" style="">
|
||||
开始阅读 <span class="material-symbols-outlined text-sm ml-1" style="">arrow_forward</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-4 mt-4">
|
||||
<div class="bg-card-dark rounded-2xl p-4 shadow-sm">
|
||||
<div class="flex justify-between items-center mb-3">
|
||||
<h3 class="font-bold text-sm text-white" style="">我的阅读</h3>
|
||||
<span class="text-xs text-text-secondary" style="">2/73章</span>
|
||||
</div>
|
||||
<div class="w-full bg-black h-1.5 rounded-full mb-4 overflow-hidden">
|
||||
<div class="bg-primary h-1.5 rounded-full" style="width: 3%"></div>
|
||||
</div>
|
||||
<div class="grid grid-cols-4 gap-2 text-center">
|
||||
<div>
|
||||
<div class="text-lg font-bold text-white" style="">2</div>
|
||||
<div class="text-xs text-text-secondary" style="">已读</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-lg font-bold text-white" style="">71</div>
|
||||
<div class="text-xs text-text-secondary" style="">待读</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-lg font-bold text-white" style="">5</div>
|
||||
<div class="text-xs text-text-secondary" style="">篇章</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-lg font-bold text-white" style="">11</div>
|
||||
<div class="text-xs text-text-secondary" style="">章节</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-8">
|
||||
<div class="flex justify-between items-center px-4 mb-3">
|
||||
<h3 class="text-lg font-bold text-white" style="">超级个体</h3>
|
||||
<a class="text-primary text-xs flex items-center" href="#" style="">查看全部 <span class="material-symbols-outlined text-[12px] ml-0.5" style="">chevron_right</span></a>
|
||||
</div>
|
||||
<div class="flex overflow-x-auto px-4 gap-4 hide-scrollbar pb-2">
|
||||
<div class="flex flex-col items-center min-w-[70px]">
|
||||
<div class="w-14 h-14 rounded-full bg-card-dark flex items-center justify-center mb-2 overflow-hidden border border-gray-800">
|
||||
<span class="material-symbols-outlined text-gray-500 text-3xl" style="">person</span>
|
||||
</div>
|
||||
<span class="text-[10px] text-center text-text-secondary w-full truncate" style="">微信用户RBEY</span>
|
||||
</div>
|
||||
<div class="flex flex-col items-center min-w-[70px]">
|
||||
<div class="w-14 h-14 rounded-full bg-teal-900/20 flex items-center justify-center mb-2 overflow-hidden border border-gray-800">
|
||||
<span class="material-symbols-outlined text-primary/40 text-3xl" style="">person</span>
|
||||
</div>
|
||||
<span class="text-[10px] text-center text-text-secondary w-full truncate" style="">微信用户HciA</span>
|
||||
</div>
|
||||
<div class="flex flex-col items-center min-w-[70px]">
|
||||
<div class="w-14 h-14 rounded-full bg-amber-500/10 text-amber-500 font-bold flex items-center justify-center mb-2 border border-amber-500/20 shadow-md" style="">
|
||||
版
|
||||
</div>
|
||||
<span class="text-[10px] text-center text-text-secondary w-full truncate" style="">好版登小程序顾问</span>
|
||||
</div>
|
||||
<div class="flex flex-col items-center min-w-[70px]">
|
||||
<div class="w-14 h-14 rounded-full bg-card-dark flex items-center justify-center mb-2 overflow-hidden border border-gray-800">
|
||||
<img alt="Profile of user" class="w-full h-full object-cover" src="https://lh3.googleusercontent.com/aida-public/AB6AXuDt0LPVk4rpoGURC14aewQDlOdPLCY-WBgu-orJ7EKJzZsYaiK2eSxQEL4l36LMFzK-fXWmWyX-xfhB4NQqEOhNM1Sc0tLIJmyRFNSgeitHN4Do7Beo9rKT-kQPmKSZGq6ae4XzpkJGoq9ymqfPqgqgpgSDicCKajZrR-MHh3Xz8NvKAlVKsRWo0HKv79WIo8muyOqz7C1j1X_bb3JJm3dKGi2Ls2UBiRvTj2W5F7vejrW3iHsazchJaXEa9tzgARzYKLUICz7nY0k" style="">
|
||||
</div>
|
||||
<span class="text-[10px] text-center text-text-secondary w-full truncate" style="">乘风</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-6 px-4">
|
||||
<div class="flex justify-between items-center mb-3">
|
||||
<h3 class="text-lg font-bold text-white" style="">精选推荐</h3>
|
||||
<a class="text-primary text-xs flex items-center" href="#" style="">查看全部 <span class="material-symbols-outlined text-[12px] ml-0.5" style="">chevron_right</span></a>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<div class="bg-card-dark p-4 rounded-2xl flex items-center justify-between group active:scale-[0.98] transition-all">
|
||||
<div class="flex-1 pr-4">
|
||||
<div class="flex items-center gap-2 mb-1">
|
||||
<span class="text-primary text-sm font-bold" style="">1.1</span>
|
||||
<span class="bg-accent-orange/10 text-accent-orange text-[10px] font-bold px-1.5 py-0.5 rounded" style="">热门</span>
|
||||
</div>
|
||||
<h4 class="font-medium text-sm text-white line-clamp-1" style="">荷包:电动车出租的被动收入模式</h4>
|
||||
<p class="text-xs text-text-secondary mt-1" style="">第一篇 真实的人</p>
|
||||
</div>
|
||||
<span class="material-symbols-outlined text-gray-600 group-hover:text-primary transition-colors text-lg" style="">chevron_right</span>
|
||||
</div>
|
||||
<div class="bg-card-dark p-4 rounded-2xl flex items-center justify-between group active:scale-[0.98] transition-all">
|
||||
<div class="flex-1 pr-4">
|
||||
<div class="flex items-center gap-2 mb-1">
|
||||
<span class="text-primary text-sm font-bold" style="">1.2</span>
|
||||
<span class="bg-primary/10 text-primary text-[10px] font-bold px-1.5 py-0.5 rounded" style="">推荐</span>
|
||||
</div>
|
||||
<h4 class="font-medium text-sm text-white line-clamp-1" style="">老墨:资源整合高手的社交方法</h4>
|
||||
<p class="text-xs text-text-secondary mt-1" style="">第一篇 真实的人</p>
|
||||
</div>
|
||||
<span class="material-symbols-outlined text-gray-600 group-hover:text-primary transition-colors text-lg" style="">chevron_right</span>
|
||||
</div>
|
||||
<div class="bg-card-dark p-4 rounded-2xl flex items-center justify-between group active:scale-[0.98] transition-all">
|
||||
<div class="flex-1 pr-4">
|
||||
<div class="flex items-center gap-2 mb-1">
|
||||
<span class="text-primary text-sm font-bold" style="">9.17</span>
|
||||
<span class="bg-primary/10 text-primary text-[10px] font-bold px-1.5 py-0.5 rounded" style="">精选</span>
|
||||
</div>
|
||||
<h4 class="font-medium text-sm text-white line-clamp-1" style="">第104场 | 婚恋、AI客服与一个微信</h4>
|
||||
<p class="text-xs text-text-secondary mt-1" style="">第四篇 真实的赚钱</p>
|
||||
</div>
|
||||
<span class="material-symbols-outlined text-gray-600 group-hover:text-primary transition-colors text-lg" style="">chevron_right</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-8 px-4 pb-28">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h3 class="text-lg font-bold text-white" style="">最新新增</h3>
|
||||
<span class="bg-accent-orange text-black text-[10px] font-bold px-2 py-0.5 rounded-full shadow-lg shadow-accent-orange/20" style="">+10</span>
|
||||
</div>
|
||||
<div class="relative pl-3 space-y-6 before:content-[''] before:absolute before:left-3 before:top-2 before:bottom-2 before:w-[1px] before:bg-gray-800">
|
||||
<div class="relative pl-6 flex items-start group">
|
||||
<div class="absolute left-[-4.5px] top-1.5 w-2.5 h-2.5 rounded-full bg-primary ring-4 ring-black"></div>
|
||||
<div class="flex-1 pb-4 border-b border-gray-900">
|
||||
<div class="flex justify-between items-start mb-1">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="bg-accent-orange/10 text-accent-orange text-[9px] px-1 rounded font-bold border border-accent-orange/20" style="">NEW</span>
|
||||
<h4 class="text-sm font-medium text-white line-clamp-1 group-hover:text-primary transition-colors" style="">流量红利的终局</h4>
|
||||
</div>
|
||||
<div class="flex flex-col items-end pl-2">
|
||||
<span class="text-accent-orange font-bold text-sm" style="">¥1</span>
|
||||
<span class="text-[10px] text-text-secondary" style="">2/24</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-text-secondary line-clamp-1" style="">深入分析当前市场的流量趋势与未来走向...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative pl-6 flex items-start group">
|
||||
<div class="absolute left-[-4.5px] top-1.5 w-2.5 h-2.5 rounded-full bg-gray-800 ring-4 ring-black group-hover:bg-primary transition-colors"></div>
|
||||
<div class="flex-1 pb-4 border-b border-gray-900">
|
||||
<div class="flex justify-between items-start mb-1">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="bg-accent-orange/10 text-accent-orange text-[9px] px-1 rounded font-bold border border-accent-orange/20" style="">NEW</span>
|
||||
<h4 class="text-sm font-medium text-white line-clamp-1 group-hover:text-primary transition-colors" style="">9.18 第105场 | 创业社群</h4>
|
||||
</div>
|
||||
<div class="flex flex-col items-end pl-2">
|
||||
<span class="text-accent-orange font-bold text-sm" style="">¥1</span>
|
||||
<span class="text-[10px] text-text-secondary" style="">2/24</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-text-secondary line-clamp-1" style="">社群运营的核心逻辑与直播实战技巧分享...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fixed bottom-6 left-4 right-4 bg-card-dark/90 backdrop-blur-md rounded-full shadow-2xl z-50 px-6 py-3 border border-gray-800">
|
||||
<div class="flex justify-between items-center relative">
|
||||
<button class="flex flex-col items-center gap-1 text-primary" style="">
|
||||
<span class="material-symbols-outlined text-2xl font-variation-fill-1" style="">home</span>
|
||||
<span class="text-[10px] font-medium" style="">首页</span>
|
||||
</button>
|
||||
<button class="flex flex-col items-center gap-1 text-gray-500 hover:text-primary transition-colors" style="">
|
||||
<span class="material-symbols-outlined text-2xl" style="">list</span>
|
||||
<span class="text-[10px] font-medium" style="">目录</span>
|
||||
</button>
|
||||
<div class="relative -top-8 group">
|
||||
<button class="w-14 h-14 bg-primary rounded-full flex items-center justify-center shadow-lg shadow-primary/20 transform transition-transform active:scale-95" style="">
|
||||
<span class="material-symbols-outlined text-black text-2xl font-bold" style="">groups</span>
|
||||
</button>
|
||||
<span class="absolute -bottom-6 w-full text-center text-[10px] font-medium text-gray-500" style="">找伙伴</span>
|
||||
</div>
|
||||
<button class="flex flex-col items-center gap-1 text-gray-500 hover:text-primary transition-colors" style="">
|
||||
<span class="material-symbols-outlined text-2xl" style="">person</span>
|
||||
<span class="text-[10px] font-medium" style="">我的</span>
|
||||
</button>
|
||||
<div class="w-2"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body></html>
|
||||
|
Before Width: | Height: | Size: 192 KiB |
@@ -1,183 +0,0 @@
|
||||
<!DOCTYPE html><html class="dark" lang="zh-CN"><head>
|
||||
<meta charset="utf-8">
|
||||
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport">
|
||||
<title>Premium Membership Landing</title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,typography,container-queries"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet">
|
||||
<script>
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: "#FFBD2E",
|
||||
teal: {
|
||||
accent: "#4FD1C5",
|
||||
},
|
||||
background: {
|
||||
light: "#F8FAFC",
|
||||
dark: "#000000",
|
||||
},
|
||||
card: {
|
||||
dark: "#121212",
|
||||
}
|
||||
},
|
||||
fontFamily: {
|
||||
display: ["Inter", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "sans-serif"],
|
||||
},
|
||||
borderRadius: {
|
||||
DEFAULT: "12px",
|
||||
'xl': "16px",
|
||||
'2xl': "24px",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style type="text/tailwindcss">
|
||||
:root {
|
||||
--gold-gradient: linear-gradient(135deg, #FFD700 0%, #FFB000 100%);
|
||||
--footer-bg: #000000;
|
||||
}
|
||||
body {
|
||||
font-family: 'Inter', "PingFang SC", sans-serif;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
background-color: #000000;
|
||||
}
|
||||
.premium-card-glow {
|
||||
background: linear-gradient(135deg, #132F2C 0%, #0D0D0D 100%);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.premium-card-glow::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -50%;
|
||||
right: -20%;
|
||||
width: 80%;
|
||||
height: 150%;
|
||||
background: radial-gradient(circle, rgba(79, 209, 197, 0.12) 0%, transparent 70%);
|
||||
transform: rotate(-15deg);
|
||||
}
|
||||
.gold-btn-gradient {
|
||||
background: var(--gold-gradient);
|
||||
}
|
||||
.benefit-card {
|
||||
background: #141414;
|
||||
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-background-dark text-slate-100 min-h-screen flex flex-col">
|
||||
<nav class="fixed top-0 left-0 right-0 z-50 flex items-center justify-between px-5 py-3 bg-background-dark/90 backdrop-blur-md border-b border-white/5">
|
||||
<button class="flex items-center justify-center w-8 h-8 rounded-full bg-zinc-900 text-white" style="">
|
||||
<span class="material-symbols-outlined text-xl" style="">chevron_left</span>
|
||||
</button>
|
||||
<h1 class="text-sm font-semibold tracking-tight" style="">卡若创业派对</h1>
|
||||
<div class="flex items-center bg-zinc-900 px-3 py-1 rounded-full border border-white/5">
|
||||
<span class="material-symbols-outlined text-sm mr-2" style="">more_horiz</span>
|
||||
<div class="w-[1px] h-3 bg-zinc-700 mr-2"></div>
|
||||
<span class="material-symbols-outlined text-sm" style="">radio_button_checked</span>
|
||||
</div>
|
||||
</nav>
|
||||
<main class="pt-20 pb-40 px-4 max-w-lg mx-auto w-full space-y-8">
|
||||
<section class="premium-card-glow rounded-2xl border border-zinc-800/50 p-6 shadow-2xl relative">
|
||||
<div class="inline-flex items-center px-2 py-0.5 rounded bg-teal-accent/10 border border-teal-accent/20 mb-4">
|
||||
<span class="text-[9px] font-bold text-teal-accent tracking-widest uppercase" style="">卡若创业派对</span>
|
||||
</div>
|
||||
<div class="space-y-1">
|
||||
<h2 class="text-2xl font-bold leading-tight" style="">加入卡若的</h2>
|
||||
<h2 class="text-2xl font-bold leading-tight text-primary" style="">创业派对 会员</h2>
|
||||
</div>
|
||||
<p class="mt-3 text-zinc-400 text-xs font-medium tracking-wide" style="">一次加入 尊享终身陪伴与成长</p>
|
||||
</section>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<section class="space-y-3">
|
||||
<div class="flex items-center gap-1.5 px-1 mb-2">
|
||||
<span class="w-1 h-3 bg-teal-accent rounded-full"></span>
|
||||
<h3 class="text-teal-accent font-bold text-xs tracking-wider uppercase" style="">内容权益</h3>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<div class="benefit-card p-3 rounded-xl flex flex-col gap-2">
|
||||
<span class="material-symbols-outlined text-teal-accent text-lg" style="">auto_stories</span>
|
||||
<div>
|
||||
<h4 class="font-bold text-[13px] text-white" style="">解锁全部章节</h4>
|
||||
<p class="text-[10px] text-zinc-500 mt-0.5 leading-tight" style="">365天全案精读</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="benefit-card p-3 rounded-xl flex flex-col gap-2">
|
||||
<span class="material-symbols-outlined text-teal-accent text-lg" style="">database</span>
|
||||
<div>
|
||||
<h4 class="font-bold text-[13px] text-white" style="">案例库</h4>
|
||||
<p class="text-[10px] text-zinc-500 mt-0.5 leading-tight" style="">100+创业实战案例</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="benefit-card p-3 rounded-xl flex flex-col gap-2">
|
||||
<span class="material-symbols-outlined text-teal-accent text-lg" style="">psychology</span>
|
||||
<div>
|
||||
<h4 class="font-bold text-[13px] text-white" style="">智能纪要</h4>
|
||||
<p class="text-[10px] text-zinc-500 mt-0.5 leading-tight" style="">AI每日精华推送</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="benefit-card p-3 rounded-xl flex flex-col gap-2">
|
||||
<span class="material-symbols-outlined text-teal-accent text-lg" style="">folder_open</span>
|
||||
<div>
|
||||
<h4 class="font-bold text-[13px] text-white" style="">会议纪要库</h4>
|
||||
<p class="text-[10px] text-zinc-500 mt-0.5 leading-tight" style="">往期完整沉淀</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="space-y-3">
|
||||
<div class="flex items-center gap-1.5 px-1 mb-2">
|
||||
<span class="w-1 h-3 bg-primary rounded-full"></span>
|
||||
<h3 class="text-primary font-bold text-xs tracking-wider uppercase" style="">社交权益</h3>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<div class="benefit-card p-3 rounded-xl flex flex-col gap-2">
|
||||
<span class="material-symbols-outlined text-primary text-lg" style="">group_add</span>
|
||||
<div>
|
||||
<h4 class="font-bold text-[13px] text-white" style="">匹配创业伙伴</h4>
|
||||
<p class="text-[10px] text-zinc-500 mt-0.5 leading-tight" style="">精准人脉匹配</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="benefit-card p-3 rounded-xl flex flex-col gap-2">
|
||||
<span class="material-symbols-outlined text-primary text-lg" style="">leaderboard</span>
|
||||
<div>
|
||||
<h4 class="font-bold text-[13px] text-white" style="">创业老板排行</h4>
|
||||
<p class="text-[10px] text-zinc-500 mt-0.5 leading-tight" style="">项目曝光展示</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="benefit-card p-3 rounded-xl flex flex-col gap-2">
|
||||
<span class="material-symbols-outlined text-primary text-lg" style="">hub</span>
|
||||
<div>
|
||||
<h4 class="font-bold text-[13px] text-white" style="">链接资源</h4>
|
||||
<p class="text-[10px] text-zinc-500 mt-0.5 leading-tight" style="">深度私域资源池</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="benefit-card p-3 rounded-xl flex flex-col gap-2">
|
||||
<span class="material-symbols-outlined text-primary text-lg" style="">verified</span>
|
||||
<div>
|
||||
<h4 class="font-bold text-[13px] text-white" style="">专属VIP标识</h4>
|
||||
<p class="text-[10px] text-zinc-500 mt-0.5 leading-tight" style="">金色尊享光圈</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
<footer class="fixed bottom-0 left-0 right-0 z-50 bg-black/95 backdrop-blur-sm border-t border-white/5 pb-[calc(1.5rem+env(safe-area-inset-bottom))] px-5 pt-5">
|
||||
<div class="max-w-lg mx-auto">
|
||||
<button class="w-full gold-btn-gradient hover:brightness-110 active:scale-[0.98] transition-all py-4 rounded-full text-black font-bold text-base shadow-[0_8px_30px_rgb(255,188,46,0.15)]" style="">
|
||||
¥1980/年 加入创业派对
|
||||
</button>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body></html>
|
||||
|
Before Width: | Height: | Size: 309 KiB |
@@ -1,221 +0,0 @@
|
||||
<html lang="zh-CN"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>Updated Community Profile Screen</title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,typography,container-queries"></script>
|
||||
<script>
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: "#4FD1C5",
|
||||
"background-light": "#F3F4F6",
|
||||
"background-dark": "#121212",
|
||||
"card-light": "#FFFFFF",
|
||||
"card-dark": "#1A1A1A",
|
||||
"card-inner": "#252525",
|
||||
"text-light": "#1F2937",
|
||||
"text-dark": "#E5E7EB",
|
||||
"secondary-light": "#9CA3AF",
|
||||
"secondary-dark": "#6B7280",
|
||||
"vip-gold": "#C8A146",
|
||||
},
|
||||
fontFamily: {
|
||||
display: ["Inter", "system-ui", "-apple-system", "sans-serif"],
|
||||
},
|
||||
borderRadius: {
|
||||
DEFAULT: "0.75rem",
|
||||
xl: "1rem",
|
||||
'2xl': "1.5rem",
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet"/>
|
||||
<style type="text/tailwindcss">
|
||||
body {
|
||||
font-family: 'Inter', sans-serif;
|
||||
min-height: max(884px, 100dvh);
|
||||
background-color: #121212;
|
||||
}
|
||||
.scrollbar-hide::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
.scrollbar-hide {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
.material-symbols-outlined {
|
||||
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
|
||||
}
|
||||
.avatar-glow {
|
||||
box-shadow: 0 0 12px rgba(200, 161, 70, 0.4);
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-background-dark text-text-dark antialiased min-h-screen flex flex-col relative pb-24">
|
||||
<div class="px-6 py-3 flex justify-between items-center text-sm font-medium z-10 sticky top-0 bg-background-dark bg-opacity-90 backdrop-blur-sm">
|
||||
<span class="text-white">9:41</span>
|
||||
<div class="flex items-center space-x-2">
|
||||
<span class="material-symbols-outlined text-[18px] text-white">signal_cellular_alt</span>
|
||||
<span class="material-symbols-outlined text-[18px] text-white">wifi</span>
|
||||
<span class="material-symbols-outlined text-[18px] text-white">battery_full</span>
|
||||
</div>
|
||||
</div>
|
||||
<header class="px-5 pt-2 pb-6 flex flex-col relative">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h1 class="text-xl font-bold text-[#4FD1C5]">我的</h1>
|
||||
<div class="flex items-center">
|
||||
<button class="p-2 rounded-full hover:bg-gray-800 transition">
|
||||
<span class="material-symbols-outlined text-gray-300">settings</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
<div class="relative">
|
||||
<div class="w-[72px] h-[72px] rounded-full bg-[#1C2524] overflow-hidden border-[2.5px] border-[#C8A146] avatar-glow flex items-center justify-center">
|
||||
<img alt="User Avatar" class="w-full h-full object-cover rounded-full" src="https://lh3.googleusercontent.com/aida-public/AB6AXuBo2PHq2d-8F1vMun8MHr81-HxHRvAL3uAlT1_pEGiX6oUcRR_1hgwzwmN4LBMwu3808aUN6wHKR6Ks2JsjXY5xnUSldONlmVaC_2H9sHl_ZZO_tz0gTqfqsTWb82LeQFet6BO5g4MCXjE22pK0Kxvhl5xYrvLBbh1YzHl9ZH2FcpUmCcq7P0FhGS5WkbeojWMT0uEdndmeSBkgTmLwjXuJk1KRUMn3UYd1h5eC9QjoScBWwCFl_5zRVnWeqOGXwHxziIbrzizqrqY"/>
|
||||
</div>
|
||||
<div class="absolute -bottom-1 -right-0.5 bg-gradient-to-r from-[#E6B84D] to-[#D4A017] rounded-[4px] px-1.5 py-0.5 flex items-center justify-center shadow-lg">
|
||||
<span class="text-[9px] font-black text-black leading-none italic">VIP</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center gap-3">
|
||||
<h2 class="text-[28px] font-bold text-white tracking-wide">卡若</h2>
|
||||
<div class="flex gap-1.5 ml-1">
|
||||
<span class="text-[10px] text-[#C8A146] border border-[#C8A146] rounded-[4px] px-1.5 py-0.5 bg-[#C8A146]/10">会员</span>
|
||||
<span class="text-[10px] text-[#C8A146] border border-[#C8A146] rounded-[4px] px-1.5 py-0.5 bg-[#C8A146]/10">匹配</span>
|
||||
<span class="text-[10px] text-[#C8A146] border border-[#C8A146] rounded-[4px] px-1.5 py-0.5 bg-[#C8A146]/10">排行</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2 text-sm text-gray-500 font-medium">
|
||||
ID: ogpTW5Wbbo...6EGc-g
|
||||
</div>
|
||||
<div class="mt-1 text-[11px] text-gray-500">
|
||||
会员到期时间:2025-12-31
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<main class="flex-1 px-4 space-y-4">
|
||||
<div class="bg-card-dark rounded-xl p-5 shadow-sm border border-gray-800/50">
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<span class="material-symbols-outlined text-primary">account_balance_wallet</span>
|
||||
<h3 class="font-bold text-white">分享收益</h3>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 gap-2 text-center divide-x divide-gray-800">
|
||||
<div class="flex flex-col items-center">
|
||||
<span class="text-xl font-bold text-primary">0</span>
|
||||
<span class="text-xs text-secondary-dark mt-1">推荐好友</span>
|
||||
</div>
|
||||
<div class="flex flex-col items-center">
|
||||
<span class="text-xl font-bold text-primary">0.00</span>
|
||||
<span class="text-xs text-secondary-dark mt-1">我的收益</span>
|
||||
</div>
|
||||
<div class="flex flex-col items-center">
|
||||
<span class="text-xl font-bold text-primary">--</span>
|
||||
<span class="text-xs text-secondary-dark mt-1">可提现金额</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-card-dark rounded-xl p-5 shadow-sm border border-gray-800/50">
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<span class="material-symbols-outlined text-primary">visibility</span>
|
||||
<h3 class="font-bold text-white">阅读统计</h3>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 gap-3">
|
||||
<div class="bg-card-inner rounded-lg p-3 flex flex-col items-center justify-center aspect-[4/3]">
|
||||
<span class="material-symbols-outlined text-primary mb-2 text-2xl">menu_book</span>
|
||||
<span class="text-xl font-bold text-white">2</span>
|
||||
<span class="text-[10px] text-gray-500 mt-1">已读章节</span>
|
||||
</div>
|
||||
<div class="bg-card-inner rounded-lg p-3 flex flex-col items-center justify-center aspect-[4/3]">
|
||||
<span class="material-symbols-outlined text-primary mb-2 text-2xl">timer</span>
|
||||
<span class="text-xl font-bold text-white">97</span>
|
||||
<span class="text-[10px] text-gray-500 mt-1">阅读分钟</span>
|
||||
</div>
|
||||
<div class="bg-card-inner rounded-lg p-3 flex flex-col items-center justify-center aspect-[4/3]">
|
||||
<span class="material-symbols-outlined text-primary mb-2 text-2xl">group</span>
|
||||
<span class="text-xl font-bold text-white">0</span>
|
||||
<span class="text-[10px] text-gray-500 mt-1">匹配伙伴</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-card-dark rounded-xl p-5 shadow-sm border border-gray-800/50">
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<span class="material-symbols-outlined text-primary">history_edu</span>
|
||||
<h3 class="font-bold text-white">最近阅读</h3>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<div class="flex items-center justify-between p-3 rounded-lg bg-card-inner">
|
||||
<div class="flex items-center gap-3 overflow-hidden">
|
||||
<span class="text-gray-500 font-mono text-sm">1</span>
|
||||
<span class="text-sm text-gray-200 truncate">章节 preface</span>
|
||||
</div>
|
||||
<a class="text-xs text-primary font-medium hover:underline shrink-0 ml-2" href="#">继续阅读</a>
|
||||
</div>
|
||||
<div class="flex items-center justify-between p-3 rounded-lg bg-card-inner">
|
||||
<div class="flex items-center gap-3 overflow-hidden">
|
||||
<span class="text-gray-500 font-mono text-sm">2</span>
|
||||
<span class="text-sm text-gray-200 truncate">章节 1.1</span>
|
||||
</div>
|
||||
<a class="text-xs text-primary font-medium hover:underline shrink-0 ml-2" href="#">继续阅读</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-card-dark rounded-xl overflow-hidden shadow-sm border border-gray-800/50 mb-6">
|
||||
<a class="flex items-center justify-between p-4 hover:bg-card-inner transition-colors border-b border-gray-800" href="#">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-6 h-6 rounded-full bg-teal-900/30 flex items-center justify-center">
|
||||
<span class="material-symbols-outlined text-teal-400 text-sm">inventory_2</span>
|
||||
</div>
|
||||
<span class="text-sm text-gray-200 font-medium">我的订单</span>
|
||||
</div>
|
||||
<span class="material-symbols-outlined text-gray-400 text-sm">chevron_right</span>
|
||||
</a>
|
||||
<a class="flex items-center justify-between p-4 hover:bg-card-inner transition-colors border-gray-100 last:border-0" href="#">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-6 h-6 rounded-full bg-blue-900/30 flex items-center justify-center">
|
||||
<span class="material-symbols-outlined text-blue-400 text-sm">info</span>
|
||||
</div>
|
||||
<span class="text-sm text-gray-200 font-medium">关于作者</span>
|
||||
</div>
|
||||
<span class="material-symbols-outlined text-gray-400 text-sm">chevron_right</span>
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
<nav class="fixed bottom-0 left-0 right-0 bg-card-dark border-t border-gray-800 pb-safe pt-2 px-6 flex justify-between items-end z-50 h-[84px]">
|
||||
<a class="flex flex-col items-center space-y-1 w-16 mb-2 group" href="#">
|
||||
<span class="material-symbols-outlined text-gray-500 group-hover:text-primary transition-colors text-2xl">home</span>
|
||||
<span class="text-[10px] text-gray-500 group-hover:text-primary font-medium">首页</span>
|
||||
</a>
|
||||
<a class="flex flex-col items-center space-y-1 w-16 mb-2 group" href="#">
|
||||
<span class="material-symbols-outlined text-gray-500 group-hover:text-primary transition-colors text-2xl">list</span>
|
||||
<span class="text-[10px] text-gray-500 group-hover:text-primary font-medium">目录</span>
|
||||
</a>
|
||||
<a class="relative -top-6 flex flex-col items-center group" href="#">
|
||||
<div class="w-14 h-14 rounded-full bg-primary shadow-lg shadow-primary/30 flex items-center justify-center transform group-hover:scale-105 transition-transform border-4 border-background-dark">
|
||||
<span class="material-symbols-outlined text-white text-3xl">people</span>
|
||||
</div>
|
||||
<span class="text-[10px] text-primary font-medium mt-1">找伙伴</span>
|
||||
</a>
|
||||
<a class="flex flex-col items-center space-y-1 w-16 mb-2 group" href="#">
|
||||
<span class="material-symbols-outlined text-primary transition-colors text-2xl">person</span>
|
||||
<span class="text-[10px] text-primary font-medium">我的</span>
|
||||
</a>
|
||||
</nav>
|
||||
<div class="h-24"></div>
|
||||
<script>
|
||||
document.documentElement.classList.add('dark');
|
||||
</script>
|
||||
|
||||
</body></html>
|
||||
|
Before Width: | Height: | Size: 146 KiB |
413
开发文档/api_v1.md
Normal file
@@ -0,0 +1,413 @@
|
||||
# 对外获客线索上报接口文档(V1)
|
||||
|
||||
## 一、接口概述
|
||||
|
||||
- **接口名称**:对外获客线索上报接口
|
||||
- **接口用途**:供第三方系统向【存客宝】上报客户线索(手机号 / 微信号等),用于后续的跟进、标签管理和画像分析。
|
||||
- **接口协议**:HTTP
|
||||
- **请求方式**:`POST`
|
||||
- **请求地址**: `https://ckbapi.quwanzhi.com/v1/api/scenarios`
|
||||
|
||||
> 具体 URL 以实际环境配置为准。
|
||||
|
||||
- **数据格式**:
|
||||
- 推荐:`application/json`
|
||||
- 兼容:`application/x-www-form-urlencoded`
|
||||
- **字符编码**:`UTF-8`
|
||||
|
||||
---
|
||||
|
||||
## 二、鉴权与签名
|
||||
|
||||
### 2.1 必填鉴权字段
|
||||
|
||||
| 字段名 | 类型 | 必填 | 说明 |
|
||||
|-------------|--------|------|---------------------------------------|
|
||||
| `apiKey` | string | 是 | 分配给第三方的接口密钥(每个任务唯一)|
|
||||
| `sign` | string | 是 | 签名值 |
|
||||
| `timestamp` | int | 是 | 秒级时间戳(与服务器时间差不超过 5 分钟) |
|
||||
|
||||
### 2.2 时间戳校验
|
||||
|
||||
服务器会校验 `timestamp` 是否在当前时间前后 **5 分钟** 内:
|
||||
|
||||
- 通过条件:`|server_time - timestamp| <= 300`
|
||||
- 超出范围则返回:`请求已过期`
|
||||
|
||||
### 2.3 签名生成规则
|
||||
|
||||
接口采用自定义签名机制。**签名字段为 `sign`,生成步骤如下:**
|
||||
|
||||
假设本次请求的所有参数为 `params`,其中包括业务参数 + `apiKey` + `timestamp` + `sign` + 可能存在的 `portrait` 对象。
|
||||
|
||||
#### 第一步:移除特定字段
|
||||
|
||||
从 `params` 中移除以下字段:
|
||||
|
||||
- `sign` —— 自身不参与签名
|
||||
- `apiKey` —— 不参与参数拼接,仅在最后一步参与二次 MD5
|
||||
- `portrait` —— 整个画像对象不参与签名(即使内部还有子字段)
|
||||
|
||||
> 说明:`portrait` 通常是一个 JSON 对象,字段较多,为避免签名实现复杂且双方难以对齐,统一不参与签名。
|
||||
|
||||
#### 第二步:移除空值字段
|
||||
|
||||
从剩余参数中,移除值为:
|
||||
|
||||
- `null`
|
||||
- 空字符串 `''`
|
||||
|
||||
的字段,这些字段不参与签名。
|
||||
|
||||
#### 第三步:按参数名升序排序
|
||||
|
||||
对剩余参数按**参数名(键名)升序排序**,排序规则为标准的 ASCII 升序:
|
||||
|
||||
```text
|
||||
例如: name, phone, source, timestamp
|
||||
```
|
||||
|
||||
#### 第四步:拼接参数值
|
||||
|
||||
将排序后的参数 **只取“值”**,按顺序直接拼接为一个字符串,中间不加任何分隔符:
|
||||
|
||||
- 示例:
|
||||
排序后参数为:
|
||||
|
||||
```text
|
||||
name = 张三
|
||||
phone = 13800000000
|
||||
source = 微信广告
|
||||
timestamp = 1710000000
|
||||
```
|
||||
|
||||
则拼接:
|
||||
|
||||
```text
|
||||
stringToSign = "张三13800000000微信广告1710000000"
|
||||
```
|
||||
|
||||
#### 第五步:第一次 MD5
|
||||
|
||||
对上一步拼接得到的字符串做一次 MD5:
|
||||
|
||||
\[
|
||||
\text{firstMd5} = \text{MD5}(\text{stringToSign})
|
||||
\]
|
||||
|
||||
#### 第六步:拼接 apiKey 再次 MD5
|
||||
|
||||
将第一步的结果与 `apiKey` 直接拼接,再做一次 MD5,得到最终签名值:
|
||||
|
||||
\[
|
||||
\text{sign} = \text{MD5}(\text{firstMd5} + \text{apiKey})
|
||||
\]
|
||||
|
||||
#### 第七步:放入请求
|
||||
|
||||
将第六步得到的 `sign` 填入请求参数中的 `sign` 字段即可。
|
||||
|
||||
> 建议:
|
||||
> - 使用小写 MD5 字符串(双方约定统一即可)。
|
||||
> - 请确保参与签名的参数与最终请求发送的参数一致(包括是否传空值)。
|
||||
|
||||
### 2.4 签名示例(PHP 伪代码)
|
||||
|
||||
```php
|
||||
$params = [
|
||||
'apiKey' => 'YOUR_API_KEY',
|
||||
'timestamp' => '1710000000',
|
||||
'phone' => '13800000000',
|
||||
'name' => '张三',
|
||||
'source' => '微信广告',
|
||||
'remark' => '通过H5落地页留资',
|
||||
// 'portrait' => [...], // 如有画像,这里会存在,但不参与签名
|
||||
// 'sign' => '待生成',
|
||||
];
|
||||
|
||||
// 1. 去掉 sign、apiKey、portrait
|
||||
unset($params['sign'], $params['apiKey'], $params['portrait']);
|
||||
|
||||
// 2. 去掉空值
|
||||
$params = array_filter($params, function($value) {
|
||||
return !is_null($value) && $value !== '';
|
||||
});
|
||||
|
||||
// 3. 按键名升序排序
|
||||
ksort($params);
|
||||
|
||||
// 4. 拼接参数值
|
||||
$stringToSign = implode('', array_values($params));
|
||||
|
||||
// 5. 第一次 MD5
|
||||
$firstMd5 = md5($stringToSign);
|
||||
|
||||
// 6. 第二次 MD5(拼接 apiKey)
|
||||
$apiKey = 'YOUR_API_KEY';
|
||||
$sign = md5($firstMd5 . $apiKey);
|
||||
|
||||
// 将 $sign 作为字段发送
|
||||
$params['sign'] = $sign;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、请求参数说明
|
||||
|
||||
### 3.1 主标识字段(至少传一个)
|
||||
|
||||
| 字段名 | 类型 | 必填 | 说明 |
|
||||
|-----------|--------|------|-------------------------------------------|
|
||||
| `wechatId`| string | 否 | 微信号,存在时优先作为主标识 |
|
||||
| `phone` | string | 否 | 手机号,当 `wechatId` 为空时用作主标识 |
|
||||
|
||||
### 3.2 基础信息字段
|
||||
|
||||
| 字段名 | 类型 | 必填 | 说明 |
|
||||
|------------|--------|------|-------------------------|
|
||||
| `name` | string | 否 | 客户姓名 |
|
||||
| `source` | string | 否 | 线索来源描述,如“百度推广”、“抖音直播间” |
|
||||
| `remark` | string | 否 | 备注信息 |
|
||||
| `tags` | string | 否 | 逗号分隔的“微信标签”,如:`"高意向,电商,女装"` |
|
||||
| `siteTags` | string | 否 | 逗号分隔的“站内标签”,用于站内进一步细分 |
|
||||
|
||||
|
||||
### 3.3 用户画像字段 `portrait`(可选)
|
||||
|
||||
`portrait` 为一个对象(JSON),用于记录用户的行为画像数据。
|
||||
|
||||
#### 3.3.1 基本示例
|
||||
|
||||
```json
|
||||
"portrait": {
|
||||
"type": 1,
|
||||
"source": 1,
|
||||
"sourceData": {
|
||||
"age": 28,
|
||||
"gender": "female",
|
||||
"city": "上海",
|
||||
"productId": "P12345",
|
||||
"pageUrl": "https://example.com/product/123"
|
||||
},
|
||||
"remark": "画像-基础属性",
|
||||
"uniqueId": "user_13800000000_20250301_001"
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.3.2 字段详细说明
|
||||
|
||||
| 字段名 | 类型 | 必填 | 说明 |
|
||||
|-----------------------|--------|------|----------------------------------------|
|
||||
| `portrait.type` | int | 否 | 画像类型,枚举值:<br>0-浏览<br>1-点击<br>2-下单/购买<br>3-注册<br>4-互动<br>默认值:0 |
|
||||
| `portrait.source` | int | 否 | 画像来源,枚举值:<br>0-本站<br>1-老油条<br>2-老坑爹<br>默认值:0 |
|
||||
| `portrait.sourceData` | object | 否 | 画像明细数据(键值对,会存储为 JSON 格式)<br>可包含任意业务相关的键值对,如:年龄、性别、城市、商品ID、页面URL等 |
|
||||
| `portrait.remark` | string | 否 | 画像备注信息,最大长度100字符 |
|
||||
| `portrait.uniqueId` | string | 否 | 画像去重用唯一 ID<br>用于防止重复记录,相同 `uniqueId` 的画像数据在半小时内会被合并统计(count字段累加)<br>建议格式:`{来源标识}_{用户标识}_{时间戳}_{序号}` |
|
||||
|
||||
#### 3.3.3 画像类型(type)说明
|
||||
|
||||
| 值 | 类型 | 说明 | 适用场景 |
|
||||
|---|------|------|---------|
|
||||
| 0 | 浏览 | 用户浏览了页面或内容 | 页面访问、商品浏览、文章阅读等 |
|
||||
| 1 | 点击 | 用户点击了某个元素 | 按钮点击、链接点击、广告点击等 |
|
||||
| 2 | 下单/购买 | 用户完成了购买行为 | 订单提交、支付完成等 |
|
||||
| 3 | 注册 | 用户完成了注册 | 账号注册、会员注册等 |
|
||||
| 4 | 互动 | 用户进行了互动行为 | 点赞、评论、分享、咨询等 |
|
||||
|
||||
#### 3.3.4 画像来源(source)说明
|
||||
|
||||
| 值 | 来源 | 说明 |
|
||||
|---|------|------|
|
||||
| 0 | 本站 | 来自本站的数据 |
|
||||
| 1 | 老油条 | 来自"老油条"系统的数据 |
|
||||
| 2 | 老坑爹 | 来自"老坑爹"系统的数据 |
|
||||
|
||||
#### 3.3.5 sourceData 数据格式说明
|
||||
|
||||
`sourceData` 是一个 JSON 对象,可以包含任意业务相关的键值对。常见字段示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"age": 28,
|
||||
"gender": "female",
|
||||
"city": "上海",
|
||||
"province": "上海市",
|
||||
"productId": "P12345",
|
||||
"productName": "商品名称",
|
||||
"category": "女装",
|
||||
"price": 299.00,
|
||||
"pageUrl": "https://example.com/product/123",
|
||||
"referrer": "https://www.baidu.com",
|
||||
"device": "mobile",
|
||||
"browser": "WeChat"
|
||||
}
|
||||
```
|
||||
|
||||
> **注意**:
|
||||
> - `sourceData` 中的数据类型可以是字符串、数字、布尔值等
|
||||
> - 嵌套对象会被序列化为 JSON 字符串存储
|
||||
> - 建议根据实际业务需求定义字段结构
|
||||
|
||||
#### 3.3.6 uniqueId 去重机制说明
|
||||
|
||||
- **作用**:防止重复记录相同的画像数据
|
||||
- **规则**:相同 `uniqueId` 的画像数据在 **半小时内** 会被合并统计,`count` 字段会自动累加
|
||||
- **建议格式**:`{来源标识}_{用户标识}_{时间戳}_{序号}`
|
||||
- 示例:`site_13800000000_1710000000_001`
|
||||
- 示例:`wechat_wxid_abc123_1710000000_001`
|
||||
- **注意事项**:
|
||||
- 如果不传 `uniqueId`,系统会为每条画像数据创建新记录
|
||||
- 如果需要在半小时内多次统计同一行为,应使用相同的 `uniqueId`
|
||||
- 如果需要在半小时后重新统计,应使用不同的 `uniqueId`(建议修改时间戳部分)
|
||||
|
||||
> **重要提示**:`portrait` **整体不参与签名计算**,但会参与业务处理。系统会根据 `uniqueId` 自动处理去重和统计。
|
||||
|
||||
---
|
||||
|
||||
## 四、请求示例
|
||||
|
||||
### 4.1 JSON 请求示例(无画像)
|
||||
|
||||
```json
|
||||
{
|
||||
"apiKey": "YOUR_API_KEY",
|
||||
"timestamp": 1710000000,
|
||||
"phone": "13800000000",
|
||||
"name": "张三",
|
||||
"source": "微信广告",
|
||||
"remark": "通过H5落地页留资",
|
||||
"tags": "高意向,电商",
|
||||
"siteTags": "新客,女装",
|
||||
"sign": "根据签名规则生成的MD5字符串"
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 JSON 请求示例(带微信号与画像)
|
||||
|
||||
```json
|
||||
{
|
||||
"apiKey": "YOUR_API_KEY",
|
||||
"timestamp": 1710000000,
|
||||
"wechatId": "wxid_abcdefg123",
|
||||
"phone": "13800000001",
|
||||
"name": "李四",
|
||||
"source": "小程序落地页",
|
||||
"remark": "点击【立即咨询】按钮",
|
||||
"tags": "中意向,直播",
|
||||
"siteTags": "复购,高客单",
|
||||
"portrait": {
|
||||
"type": 1,
|
||||
"source": 0,
|
||||
"sourceData": {
|
||||
"age": 28,
|
||||
"gender": "female",
|
||||
"city": "上海",
|
||||
"pageUrl": "https://example.com/product/123",
|
||||
"productId": "P12345"
|
||||
},
|
||||
"remark": "画像-点击行为",
|
||||
"uniqueId": "site_13800000001_1710000000_001"
|
||||
},
|
||||
"sign": "根据签名规则生成的MD5字符串"
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 JSON 请求示例(多种画像类型)
|
||||
|
||||
#### 4.3.1 浏览行为画像
|
||||
|
||||
```json
|
||||
{
|
||||
"apiKey": "YOUR_API_KEY",
|
||||
"timestamp": 1710000000,
|
||||
"phone": "13800000002",
|
||||
"name": "王五",
|
||||
"source": "百度推广",
|
||||
"portrait": {
|
||||
"type": 0,
|
||||
"source": 0,
|
||||
"sourceData": {
|
||||
"pageUrl": "https://example.com/product/456",
|
||||
"productName": "商品名称",
|
||||
"category": "女装",
|
||||
"stayTime": 120,
|
||||
"device": "mobile"
|
||||
},
|
||||
"remark": "商品浏览",
|
||||
"uniqueId": "site_13800000002_1710000000_001"
|
||||
},
|
||||
"sign": "根据签名规则生成的MD5字符串"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、响应说明
|
||||
|
||||
### 5.1 成功响应
|
||||
|
||||
**1)新增线索成功**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "新增成功",
|
||||
"data": "13800000000"
|
||||
}
|
||||
```
|
||||
|
||||
**2)线索已存在**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "已存在",
|
||||
"data": "13800000000"
|
||||
}
|
||||
```
|
||||
|
||||
> `data` 字段返回本次线索的主标识 `wechatId` 或 `phone`。
|
||||
|
||||
### 5.2 常见错误响应
|
||||
|
||||
```json
|
||||
{ "code": 400, "message": "apiKey不能为空", "data": null }
|
||||
{ "code": 400, "message": "sign不能为空", "data": null }
|
||||
{ "code": 400, "message": "timestamp不能为空", "data": null }
|
||||
{ "code": 400, "message": "请求已过期", "data": null }
|
||||
|
||||
{ "code": 401, "message": "无效的apiKey", "data": null }
|
||||
{ "code": 401, "message": "签名验证失败", "data": null }
|
||||
|
||||
{ "code": 500, "message": "系统错误: 具体错误信息", "data": null }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
## 六、常见问题(FAQ)
|
||||
|
||||
### Q1: 如果同一个用户多次上报相同的行为,会如何处理?
|
||||
|
||||
**A**: 如果使用相同的 `uniqueId`,系统会在半小时内合并统计,`count` 字段会累加。如果使用不同的 `uniqueId`,会创建多条记录。
|
||||
|
||||
### Q2: portrait 字段是否必须传递?
|
||||
|
||||
**A**: 不是必须的。`portrait` 字段是可选的,只有在需要记录用户画像数据时才传递。
|
||||
|
||||
### Q3: sourceData 中可以存储哪些类型的数据?
|
||||
|
||||
**A**: `sourceData` 是一个 JSON 对象,可以存储任意键值对。支持字符串、数字、布尔值等基本类型,嵌套对象会被序列化为 JSON 字符串。
|
||||
|
||||
### Q4: uniqueId 的作用是什么?
|
||||
|
||||
**A**: `uniqueId` 用于防止重复记录。相同 `uniqueId` 的画像数据在半小时内会被合并统计,避免重复数据。
|
||||
|
||||
### Q5: 画像数据如何与用户关联?
|
||||
|
||||
**A**: 系统会根据请求中的 `wechatId` 或 `phone` 自动匹配 `traffic_pool` 表中的用户,并将画像数据关联到对应的 `trafficPoolId`。
|
||||
|
||||
---
|
||||