性能优化
This commit is contained in:
@@ -1,8 +1,13 @@
|
||||
# 产品经理 经验记录 - 2026-03-17
|
||||
|
||||
## 新版管理端迁移到稳定版(会议:实施方案确认)
|
||||
## 稳定版源码质量优化(会议:2026-03-17)
|
||||
|
||||
- **需求基准**:以稳定版小程序为准,管理端支撑余额、代付、VIP、规则引擎等
|
||||
- **内容管理**:以稳定版为主,不采纳新版
|
||||
- **新版独有**:API 文档、OSS、编辑禁用、鉴权 → 全部吸纳(用户决议「新版有的就迁移」)
|
||||
- **待确认**:RFM、用户旅程、神射手是否继续使用
|
||||
- **验收标准**:优化后现有功能行为不变,三端联调通过
|
||||
- **优先级**:高优(安全)→ 中优(可维护)→ 低优(性能/结构)
|
||||
- **原则**:源码质量优化按安全→可维护→性能分批,用户无感知
|
||||
|
||||
---
|
||||
|
||||
## 会议收尾(2026-03-17)
|
||||
|
||||
- 10 项优化全部完成;测试流程与报告模板已定稿;开发文档已同步
|
||||
|
||||
@@ -33,3 +33,17 @@
|
||||
|
||||
- **router 补齐**:迁移前注册 5 个路由:`db.GET("/users/rfm")`、`db.GET("/users/journey-stats")`、`admin.GET("/shensheshou/query")`、`admin.POST("/shensheshou/enrich")`、`admin.POST("/shensheshou/ingest")`
|
||||
- **待确认**:/api/admin/settings 是否已支持 ossConfig,若不支持需补充
|
||||
|
||||
---
|
||||
|
||||
## 稳定版源码质量优化(会议:2026-03-17)
|
||||
|
||||
- **敏感配置**:生产环境(MODE=release)强制校验,缺敏感 env 则 Fatal
|
||||
- **user/track 鉴权**:新增 GET /api/admin/user/track + AdminAuth,原 /api/user/track 保留给小程序 POST 埋点
|
||||
- **AdminWithdrawTest**:非 develop 环境返回 404 或拒绝
|
||||
|
||||
---
|
||||
|
||||
## 会议收尾(2026-03-17)
|
||||
|
||||
- 源码优化 10 项全部完成;开发环境测试 10 通过 2 跳过
|
||||
|
||||
@@ -35,3 +35,16 @@
|
||||
- 管理端开发工程师:主导迁移
|
||||
- 后端开发:router 补齐、ossConfig 确认
|
||||
- 测试人员:迁移后验收
|
||||
|
||||
---
|
||||
|
||||
## 稳定版源码质量优化(会议:2026-03-17)
|
||||
|
||||
- **原则**:增量修复、不改功能逻辑;高优安全项优先,中优可维护项次之,低优可后续迭代
|
||||
- **影响角色**:后端、管理端、小程序、测试
|
||||
|
||||
---
|
||||
|
||||
## 会议收尾(2026-03-17)
|
||||
|
||||
- 源码优化 10 项全部完成;功能测试流程定稿;开发环境测试 10 通过 2 跳过
|
||||
|
||||
@@ -1,40 +1,15 @@
|
||||
# 小程序 - 2026-03-17
|
||||
# 小程序开发工程师 经验记录 - 2026-03-17
|
||||
|
||||
## 代付美团式流程改造
|
||||
## 稳定版源码质量优化(会议:2026-03-17)
|
||||
|
||||
### 场景
|
||||
|
||||
用户希望代付流程类似美团:先进入代付页面,再分享给好友,而非在阅读页弹窗分享。
|
||||
|
||||
### 实现
|
||||
|
||||
1. **读页「找好友代付」**:创建请求后 `wx.navigateTo` 跳转 `/pages/gift-pay/detail?requestSn=xxx`,移除弹窗
|
||||
2. **代付详情页双态**:
|
||||
- 发起人(`detail.initiatorUserId === 当前用户ID`):标题「找朋友代付」,主按钮「分享给好友」(`open-type="share"`)
|
||||
- 好友:标题「帮他付款」,主按钮「帮他付款」
|
||||
3. **后端**:detail 接口返回 `initiatorUserId` 供前端区分
|
||||
|
||||
### 经验
|
||||
|
||||
- 代付分享入口:优先「进入代付页再分享」而非「弹窗分享」,符合用户心智
|
||||
- 同一页面根据 `initiatorUserId` 与当前用户比对,展示不同 UI
|
||||
- **payment.js**:确认无引用可删除(read.js 直接调 /api/miniprogram/pay)
|
||||
- **goToMatch**:my.js 重复定义,删除一个
|
||||
- **备份文件**:删除 read.js.backup、referral.wxss.backup
|
||||
- **appId 等**:优先从 config 的 mpConfig 读取,保留兜底
|
||||
- **totalSections**:从 book/stats 或 all-chapters 动态获取,保留 62 兜底
|
||||
|
||||
---
|
||||
|
||||
## 代付统一到代付页(禁止阅读页代付)
|
||||
## 会议收尾(2026-03-17)
|
||||
|
||||
### 规则
|
||||
|
||||
代付必须在代付页完成,禁止在阅读页代付。代付页可显示部分文章信息。
|
||||
|
||||
### 实现
|
||||
|
||||
- 读页:`gift=1&ref=requestSn` 打开时,`redirectTo` 到 gift-pay/detail,不展示阅读页
|
||||
- 代付页:已展示 description(章节标题等)、金额、发起人昵称
|
||||
|
||||
---
|
||||
|
||||
## 目录页 loading、首页最新新增
|
||||
|
||||
- 目录页:`book/parts` 加载时 `partsLoading: true`,展示旋转圈 +「加载目录中...」
|
||||
- 首页最新新增:默认 5 条、折叠状态,`>5` 时显示「展开更多」
|
||||
- 源码优化 5 项全部完成;开发环境测试通过
|
||||
|
||||
9
.cursor/agent/开发助理/evolution/2026-03-17.md
Normal file
9
.cursor/agent/开发助理/evolution/2026-03-17.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# 开发助理 经验记录 - 2026-03-17
|
||||
|
||||
## 会议收尾(2026-03-17)
|
||||
|
||||
- **纪要**:2026-03-17_会议收尾-源码优化完成与测试流程定稿.md
|
||||
- **经验入库**:各角色 evolution 已追加收尾经验
|
||||
- **项目索引**:后端、管理端、小程序、测试、助理橙子已更新
|
||||
- **会议索引**:README.md 已追加
|
||||
- **开发文档**:运营与变更第十七部分已追加
|
||||
@@ -50,6 +50,7 @@
|
||||
| 2026-03-16 | 开发助理 | 交互习惯分析 | - | 乘风读取 agent-transcripts 抽样分析:角色触发词、表达方式、工作流程、沟通风格、技术偏好、Agent 响应建议 |
|
||||
| 2026-03-17 | 小程序、后端、团队 | 业务规则/bug 修复 | - | 代付美团式:读页→代付页→分享;PayNotify beneficiaryUserID 权益归发起人;detail 返回 initiatorUserId;目录 loading、最新新增 5 条折叠 |
|
||||
| 2026-03-17 | 小程序 | 业务规则 | - | 代付统一到代付页:gift=1&ref 打开 read 时 redirectTo 代付页,禁止在阅读页代付 |
|
||||
| 2026-03-17 | 软件测试 | 流程定稿 | testing SKILL | 功能测试流程:成功 ☑️、失败列问题、最终报告;scripts/test/功能测试流程.md、测试报告-环境与用例清单.md |
|
||||
|
||||
---
|
||||
|
||||
@@ -60,4 +61,4 @@
|
||||
|
||||
---
|
||||
|
||||
**最后更新**:2026-03-17(代付美团式与 PayNotify 完善)
|
||||
**最后更新**:2026-03-17(会议收尾:源码优化完成与测试流程定稿)
|
||||
|
||||
@@ -23,9 +23,10 @@ Soul 创业派对产品定位:面向创业者的社区/工具型小程序。
|
||||
| 2026-03-11 | 以界面定需求文档建立;需求基准以《以界面定需求》为准 | 已完成 |
|
||||
| 2026-03-16 | 乘风发起例行开发进度同步 | 已完成 |
|
||||
| 2026-03-16 | 会议:new-soul 新需求与当前项目差异分析 | 已完成 |
|
||||
| 2026-03-17 | 会议:稳定版源码质量优化;验收标准功能不变、三端联调通过 | 待续 |
|
||||
|
||||
> **格式说明**:每次开发后在此追加一行,日期格式 YYYY-MM-DD,状态用:已完成 / 进行中 / 待续 / 搁置
|
||||
|
||||
---
|
||||
|
||||
**最后更新**:2026-03-16
|
||||
**最后更新**:2026-03-17
|
||||
|
||||
@@ -23,9 +23,10 @@
|
||||
| 2026-03-17 | 乘风吸收经验与交互:迁移完成度与待办清单、运营与变更第十二部分 | 已完成 |
|
||||
| 2026-03-17 | 吸收新需求:代付统一到代付页(gift=1&ref redirectTo)→ 需求汇总、找朋友代付流程、运营与变更 | 已完成 |
|
||||
| 2026-03-17 | 会议收尾:新版管理端迁移到稳定版实施方案确认;纪要、各角色经验入库、项目索引更新 | 已完成 |
|
||||
| 2026-03-17 | 会议收尾:源码优化完成与测试流程定稿;纪要、经验入库、开发文档同步 | 已完成 |
|
||||
|
||||
> **格式说明**:每次开发后在此追加一行,日期格式 YYYY-MM-DD,状态用:已完成 / 进行中 / 待续 / 搁置
|
||||
|
||||
---
|
||||
|
||||
**最后更新**:2026-03-17(会议收尾:新版管理端迁移实施方案)
|
||||
**最后更新**:2026-03-17(会议收尾:源码优化完成与测试流程定稿)
|
||||
|
||||
@@ -33,6 +33,8 @@ soul-api(Go + Gin + GORM + MySQL)提供三组路由:`/api/miniprogram/*`
|
||||
| 2026-03-16 | 会议:new-soul 新需求与当前项目差异分析;content_upload.py 与 chapters 一致性待核对 | 待续 |
|
||||
| 2026-03-17 | 代付 PayNotify 权益归属修复:beneficiaryUserID(代付=发起人);gift-pay detail 返回 initiatorUserId | 已完成 |
|
||||
| 2026-03-17 | 会议:新版管理端迁移;router 补齐 users/rfm、journey-stats、shensheshou 共 5 个;确认 ossConfig | 进行中 |
|
||||
| 2026-03-17 | 会议:稳定版源码质量优化;敏感配置生产强制校验、新增 /api/admin/user/track、AdminWithdrawTest 环境限制 | 已完成 |
|
||||
| 2026-03-17 | 会议收尾:源码优化 10 项全部完成;开发环境测试 10 通过 2 跳过 | 已完成 |
|
||||
|
||||
> **格式说明**:每次开发后在此追加一行,日期格式 YYYY-MM-DD,状态用:已完成 / 进行中 / 待续 / 搁置
|
||||
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
| 2026-03-17 | 代付美团式:读页→创建请求→跳转代付详情页;详情页双态(发起人分享/好友帮他付款);目录 loading、首页最新新增 5 条折叠 | 已完成 |
|
||||
| 2026-03-17 | 代付统一到代付页:gift=1&ref 打开 read 时 redirectTo 代付页,禁止在阅读页代付 | 已完成 |
|
||||
| 2026-03-17 | 代付页营销:章节标题+20%内容预览;我的代付列表点击进详情;页面协调 | 已完成 |
|
||||
| 2026-03-17 | 会议:稳定版源码质量优化;删除 payment.js、goToMatch 重复、备份文件;config 读取、totalSections 动态化 | 已完成 |
|
||||
| 2026-03-17 | 会议收尾:源码优化 5 项全部完成;开发环境测试通过 | 已完成 |
|
||||
|
||||
> **格式说明**:每次开发后在此追加一行,日期格式 YYYY-MM-DD,状态用:已完成 / 进行中 / 待续 / 搁置
|
||||
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
| 2026-03-16 | pytest 架构、配置从项目读取、运行前显示测试环境 | 已完成 |
|
||||
| 2026-03-16 | 文章 @某人 自动创建存客宝:用例编写、执行、报告;归档规则 | 已完成 |
|
||||
| 2026-03-16 | 会议:new-soul 新需求与当前项目差异分析;引入派对AI 时回归文章上传/飞书推送/小程序展示 | 已完成 |
|
||||
| 2026-03-17 | 会议:稳定版源码质量优化;每项小回归、全部完成后完整三端联调 | 待续 |
|
||||
| 2026-03-17 | 会议收尾:功能测试流程定稿、测试报告模板、开发环境 10 通过 2 跳过 | 已完成 |
|
||||
|
||||
---
|
||||
|
||||
**最后更新**:2026-03-16
|
||||
**最后更新**:2026-03-17
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
| 2026-03-17 | 会议:新版管理端迁移到稳定版实施方案确认;新版独有全部吸纳,内容管理以稳定版为主 | 已完成 |
|
||||
| 2026-03-17 | 吸收新版管理端定义(new-soul/soul-admin);迁移 ApiDocsPage 完整版、OSS region、鉴权失败 clearAdminToken | 已完成 |
|
||||
| 2026-03-17 | 修复 DistributionPage Order.description;用户余额人工调整(后端 adjust API + 用户详情入口);代付列表页(后端 gift-pay-requests + 推广中心 Tab) | 已完成 |
|
||||
| 2026-03-17 | 会议:稳定版源码质量优化;UserDetailModal 改 /api/admin/user/track、RichEditor HTML 转义 | 已完成 |
|
||||
| 2026-03-17 | 会议收尾:源码优化已落地;开发环境测试通过 | 已完成 |
|
||||
|
||||
> **格式说明**:每次开发后在此追加一行,日期格式 YYYY-MM-DD,状态用:已完成 / 进行中 / 待续 / 搁置
|
||||
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
# 管理端开发工程师 经验记录 - 2026-03-17
|
||||
|
||||
## 新版管理端迁移到稳定版(会议:实施方案确认)
|
||||
## 稳定版源码质量优化(会议:2026-03-17)
|
||||
|
||||
### 迁移策略
|
||||
- **UserDetailModal**:改为调用 `/api/admin/user/track`(后端新增后同步改)
|
||||
- **RichEditor**:@mention 弹窗对 `item.name`、`item.label` 做 HTML 转义,防 XSS,不改 @mention 行为
|
||||
|
||||
- **内容管理**:以稳定版为主,不采纳新版,ContentPage 及关联组件不覆盖
|
||||
- **新版独有全部吸纳**:API 文档 Tab、api-docs 独立页、OSS 配置、编辑时手机号禁用、鉴权逻辑
|
||||
- **必须保留**:用户详情余额、订单支付方式/代付、RechargeAlert、LinkedMp、用户规则、超级个体
|
||||
---
|
||||
|
||||
### 实施任务
|
||||
## 会议收尾(2026-03-17)
|
||||
|
||||
1. 从 new-soul/soul-admin 迁移:ApiDocsPage、OSS 配置、api-docs 路由、编辑时手机号禁用、鉴权逻辑
|
||||
2. 以稳定版为基准合并,内容管理不覆盖
|
||||
3. 按模块分批:Layout/Dashboard/设置 → 用户/订单/推广/提现/找伙伴
|
||||
- 源码优化已落地;开发环境测试通过
|
||||
|
||||
@@ -6,3 +6,18 @@
|
||||
- **回归范围**:提现、分销、找伙伴、导师、设置等
|
||||
- **风险**:合并时避免误覆盖稳定版独有逻辑,建议 diff 逐模块核对
|
||||
- **三端联调**:管理端 ↔ soul-api 重点验证;用户规则、订单、余额展示
|
||||
|
||||
---
|
||||
|
||||
## 稳定版源码质量优化(会议:2026-03-17)
|
||||
|
||||
- **回归重点**:支付流程、管理端用户详情行为轨迹、我的页找伙伴/推广/搜索、首页目录搜索
|
||||
- **策略**:每项优化完成后小回归,全部完成后完整三端联调
|
||||
|
||||
---
|
||||
|
||||
## 会议收尾(2026-03-17)
|
||||
|
||||
- **功能测试流程定稿**:`scripts/test/功能测试流程.md` — 成功 ☑️、失败列问题、最终报告
|
||||
- **测试报告模板**:`scripts/test/测试报告-环境与用例清单.md` — 环境、用例、结果记录
|
||||
- **开发环境测试**:10 通过、2 跳过、0 失败
|
||||
|
||||
90
.cursor/meeting/2026-03-17_会议收尾-源码优化完成与测试流程定稿.md
Normal file
90
.cursor/meeting/2026-03-17_会议收尾-源码优化完成与测试流程定稿.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# 会议收尾 - 2026-03-17 | 源码优化完成与测试流程定稿
|
||||
|
||||
> 本文件由**助理橙子**在会议结束后自动生成。对应会议:2026-03-17 稳定版源码质量优化方案讨论与开发安排。
|
||||
|
||||
---
|
||||
|
||||
## 基本信息
|
||||
|
||||
- **时间**:2026-03-17
|
||||
- **议题**:会议收尾 — 源码质量优化完成、开发环境测试、功能测试流程定稿、开发文档同步
|
||||
- **触发方式**:结束会议、沉淀经验、开发部门同步需求
|
||||
- **参与角色**:产品经理、后端开发、管理端开发工程师、小程序开发工程师、测试人员、助理橙子
|
||||
|
||||
---
|
||||
|
||||
## 收尾结论
|
||||
|
||||
### 1. 源码质量优化(10 项全部完成)
|
||||
|
||||
| 端 | 任务 | 状态 |
|
||||
|----|------|------|
|
||||
| 后端 | 敏感配置生产环境强制校验(config.go) | ☑️ 已完成 |
|
||||
| 后端 | 新增 GET /api/admin/user/track + AdminAuth | ☑️ 已完成 |
|
||||
| 后端 | AdminWithdrawTest 环境限制 | ☑️ 已完成 |
|
||||
| 管理端 | UserDetailModal 改为 /api/admin/user/track | ☑️ 已完成 |
|
||||
| 管理端 | RichEditor name/label HTML 转义 | ☑️ 已完成 |
|
||||
| 小程序 | 删除 payment.js | ☑️ 已完成 |
|
||||
| 小程序 | 删除 goToMatch 重复定义 | ☑️ 已完成 |
|
||||
| 小程序 | 删除 read.js.backup、referral.wxss.backup | ☑️ 已完成 |
|
||||
| 小程序 | appId 等从 config 读取 | ☑️ 已完成 |
|
||||
| 小程序 | totalSections 动态获取 | ☑️ 已完成 |
|
||||
|
||||
### 2. 开发环境测试
|
||||
|
||||
- **环境**:local (http://localhost:8080)
|
||||
- **结果**:10 通过、2 跳过、0 失败
|
||||
- **跳过**:test_dev_login_as(需 SOUL_MINIPROGRAM_DEV_USER_ID)、test_backfill_persons_ckb_api_key(需 CKB 配置)
|
||||
|
||||
### 3. 测试流程与文档
|
||||
|
||||
| 产出 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| 功能测试流程 | scripts/test/功能测试流程.md | 环境准备→自动化→手工验证→问题汇总→报告;成功 ☑️,失败列问题 |
|
||||
| 测试报告模板 | scripts/test/测试报告-环境与用例清单.md | 环境、用例清单、结果记录、归档说明 |
|
||||
|
||||
### 4. 开发文档同步
|
||||
|
||||
- **运营与变更**:新增第十七部分「源码优化完成与测试流程定稿」
|
||||
- **需求汇总**:源码优化为内部质量项,无新增需求条目
|
||||
|
||||
---
|
||||
|
||||
## 问题与作答区
|
||||
|
||||
| # | 问题 | 责任角色 | 作答 |
|
||||
|---|------|---------|------|
|
||||
| 1 | 生产环境判断:是否以 MODE=release 为准? | 后端开发 | (待补充) |
|
||||
| 2 | dev/login-as 后端限制方案:环境变量 or IP 白名单? | 后端开发 | (待补充) |
|
||||
|
||||
---
|
||||
|
||||
## 各角色经验与业务理解更新
|
||||
|
||||
### 产品经理
|
||||
|
||||
- 源码质量优化验收:10 项全部完成,功能不变;测试流程与报告模板已定稿
|
||||
|
||||
### 后端开发
|
||||
|
||||
- 源码优化已落地:config 生产校验、admin/user/track、AdminWithdrawTest 环境限制
|
||||
|
||||
### 管理端开发工程师
|
||||
|
||||
- UserDetailModal、RichEditor 优化已落地;开发环境测试通过
|
||||
|
||||
### 小程序开发工程师
|
||||
|
||||
- payment.js 删除、goToMatch 去重、备份清理、config 读取、totalSections 动态化已落地
|
||||
|
||||
### 测试人员
|
||||
|
||||
- 功能测试流程定稿:☑️ 成功、失败列问题、最终报告;开发环境 10 通过 2 跳过
|
||||
|
||||
### 助理橙子
|
||||
|
||||
- 会议收尾:纪要、经验入库、项目索引、会议索引、开发文档同步
|
||||
|
||||
---
|
||||
|
||||
*会议收尾由助理橙子执行 | 各角色经验已同步至 agent/{角色}/evolution/2026-03-17.md*
|
||||
113
.cursor/meeting/2026-03-17_稳定版源码质量优化方案讨论与开发安排.md
Normal file
113
.cursor/meeting/2026-03-17_稳定版源码质量优化方案讨论与开发安排.md
Normal file
@@ -0,0 +1,113 @@
|
||||
# 会议纪要 - 2026-03-17 | 稳定版源码质量优化方案讨论与开发安排
|
||||
|
||||
> 本文件由**助理橙子**在会议结束后自动生成。
|
||||
|
||||
---
|
||||
|
||||
## 基本信息
|
||||
|
||||
- **时间**:2026-03-17
|
||||
- **议题**:稳定版源码质量优化方案讨论与开发安排(基于源码质量分析报告,不影响现有功能)
|
||||
- **触发方式**:开会讨论
|
||||
- **参与角色**:产品经理、后端开发、管理端开发工程师、小程序开发工程师、测试人员
|
||||
|
||||
---
|
||||
|
||||
## 各角色发言
|
||||
|
||||
### 【产品经理】
|
||||
|
||||
从需求与业务角度,本次优化聚焦**安全与可维护性**,不涉及新功能,用户无感知。建议按优先级分批处理:高优(安全)→ 中优(代码质量)→ 低优(性能/结构)。验收标准:优化后现有功能行为不变,三端联调通过。
|
||||
|
||||
### 【后端开发】
|
||||
|
||||
高优:1)敏感配置在 `config.go` 中,生产环境(MODE=release)强制校验,缺则 Fatal;2)新增 `GET /api/admin/user/track` 并加 AdminAuth,原 `/api/user/track` 保留给小程序 POST 埋点。中优:AdminWithdrawTest 加环境限制。低优:DBUsersList 拆分可后续做。
|
||||
|
||||
### 【管理端开发工程师】
|
||||
|
||||
中优:1)后端提供 `/api/admin/user/track` 后,UserDetailModal 改为调用新路径;2)RichEditor 对 name/label 做 HTML 转义防 XSS。低优:上传逻辑抽公共方法可后续做。
|
||||
|
||||
### 【小程序开发工程师】
|
||||
|
||||
高优:1)payment.js 确认无引用可删除;2)goToMatch 重复定义删除一个;3)删除 read.js.backup、referral.wxss.backup。中优:appId 等从 config 读取、totalSections 动态获取。dev/login-as 由后端限制即可。
|
||||
|
||||
### 【测试人员】
|
||||
|
||||
回归重点:支付流程、管理端用户详情行为轨迹、我的页找伙伴/推广/搜索、首页目录搜索。建议每项完成后小回归,全部完成后完整三端联调。
|
||||
|
||||
---
|
||||
|
||||
## 讨论过程
|
||||
|
||||
- 后端确认 `/api/admin/user/track` 参数与现 `/api/user/track` 一致(userId、phone、limit),管理端仅改 URL 即可
|
||||
- 小程序确认 payment.js 无 require 引用,可安全删除
|
||||
- 产品确认按优先级分批,低优可放入后续迭代
|
||||
|
||||
---
|
||||
|
||||
## 会议决议
|
||||
|
||||
1. **高优(本周完成)**:后端敏感配置生产强制校验、新增 `/api/admin/user/track`;管理端 UserDetailModal 改路径;小程序删除 payment.js、goToMatch 重复、备份文件
|
||||
2. **中优(下周完成)**:后端 AdminWithdrawTest 环境限制;管理端 RichEditor 转义;小程序 config 读取、totalSections 动态化
|
||||
3. **低优(后续迭代)**:DBUsersList 拆分、上传逻辑抽公共、config 缓存
|
||||
4. **原则**:所有改动为增量修复,不改现有功能逻辑;每项完成后小回归,全部完成后完整联调
|
||||
|
||||
---
|
||||
|
||||
## 待办事项
|
||||
|
||||
| 责任角色 | 任务 | 优先级 | 截止建议 |
|
||||
|---------|------|--------|---------|
|
||||
| 后端开发 | 敏感配置生产环境强制校验(config.go) | 高 | 本周 |
|
||||
| 后端开发 | 新增 GET /api/admin/user/track + AdminAuth | 高 | 本周 |
|
||||
| 后端开发 | AdminWithdrawTest 环境限制 | 中 | 下周 |
|
||||
| 管理端开发工程师 | UserDetailModal 改为 /api/admin/user/track | 高 | 本周 |
|
||||
| 管理端开发工程师 | RichEditor name/label HTML 转义 | 中 | 下周 |
|
||||
| 小程序开发工程师 | 删除 payment.js | 高 | 本周 |
|
||||
| 小程序开发工程师 | 删除 goToMatch 重复定义 | 高 | 本周 |
|
||||
| 小程序开发工程师 | 删除 read.js.backup、referral.wxss.backup | 高 | 本周 |
|
||||
| 小程序开发工程师 | appId 等从 config 读取 | 中 | 下周 |
|
||||
| 小程序开发工程师 | totalSections 动态获取 | 中 | 下周 |
|
||||
| 测试人员 | 每项完成后小回归 | - | 持续 |
|
||||
| 测试人员 | 全部完成后三端联调 | - | 下周 |
|
||||
|
||||
---
|
||||
|
||||
## 问题与作答区
|
||||
|
||||
| # | 问题 | 责任角色 | 作答 |
|
||||
|---|------|---------|------|
|
||||
| 1 | 生产环境判断:是否以 MODE=release 为准? | 后端开发 | (待补充) |
|
||||
| 2 | dev/login-as 后端限制方案:环境变量 or IP 白名单? | 后端开发 | (待补充) |
|
||||
|
||||
---
|
||||
|
||||
## 各角色经验与业务理解更新
|
||||
|
||||
### 产品经理
|
||||
|
||||
- 源码质量优化按安全→可维护→性能分批,验收标准为功能不变、三端联调通过
|
||||
|
||||
### 后端开发
|
||||
|
||||
- 敏感配置生产环境缺则 Fatal;user/track 查询迁至 admin 组并加鉴权;AdminWithdrawTest 非 develop 拒绝
|
||||
|
||||
### 管理端开发工程师
|
||||
|
||||
- UserDetailModal 调用 /api/admin/user/track;RichEditor @mention 需对 name/label 做 HTML 转义防 XSS
|
||||
|
||||
### 小程序开发工程师
|
||||
|
||||
- payment.js 废弃可删;goToMatch 去重;备份文件清理;appId 等优先从 config 读取;totalSections 动态获取
|
||||
|
||||
### 测试人员
|
||||
|
||||
- 源码优化类改动需每项小回归 + 全部完成后完整三端联调,重点覆盖支付、用户详情、我的页、搜索
|
||||
|
||||
### 团队共享
|
||||
|
||||
- 源码质量优化原则:增量修复、不改功能逻辑;高优安全项优先,中优可维护项次之,低优可后续迭代
|
||||
|
||||
---
|
||||
|
||||
*会议纪要由助理橙子生成 | 各角色经验已同步至 `agent/{角色}/evolution/2026-03-17.md`*
|
||||
@@ -76,3 +76,5 @@ YYYY-MM-DD_会议主题.md
|
||||
| 2026-03-16 | 链接人与事与存客宝对接优化 | 管理端、后端、团队 | [2026-03-16_链接人与事与存客宝对接优化.md](2026-03-16_链接人与事与存客宝对接优化.md) |
|
||||
| 2026-03-16 | new-soul 新需求与当前项目差异分析 | 产品、后端、管理端、小程序、测试 | [2026-03-16_new-soul新需求与当前项目差异分析.md](2026-03-16_new-soul新需求与当前项目差异分析.md) |
|
||||
| 2026-03-17 | 新版管理端迁移到稳定版实施方案确认 | 产品、后端、管理端、小程序、测试 | [2026-03-17_新版管理端迁移到稳定版实施方案确认.md](2026-03-17_新版管理端迁移到稳定版实施方案确认.md) |
|
||||
| 2026-03-17 | 稳定版源码质量优化方案讨论与开发安排 | 产品、后端、管理端、小程序、测试 | [2026-03-17_稳定版源码质量优化方案讨论与开发安排.md](2026-03-17_稳定版源码质量优化方案讨论与开发安排.md) |
|
||||
| 2026-03-17 | 会议收尾:源码优化完成与测试流程定稿 | 产品、后端、管理端、小程序、测试、助理橙子 | [2026-03-17_会议收尾-源码优化完成与测试流程定稿.md](2026-03-17_会议收尾-源码优化完成与测试流程定稿.md) |
|
||||
|
||||
@@ -35,8 +35,7 @@ miniprogram/
|
||||
│ ├── purchases/ # 订单页
|
||||
│ └── settings/ # 设置页
|
||||
├── utils/
|
||||
│ ├── util.js # 工具函数
|
||||
│ └── payment.js # 支付工具
|
||||
│ └── util.js # 工具函数
|
||||
├── assets/
|
||||
│ └── icons/ # 图标资源
|
||||
├── project.config.json # 项目配置
|
||||
|
||||
@@ -92,6 +92,8 @@ App({
|
||||
|
||||
// 加载书籍数据
|
||||
this.loadBookData()
|
||||
// 加载 mpConfig(appId、mchId、withdrawSubscribeTmplId 等,失败时保留默认值)
|
||||
this.loadMpConfig()
|
||||
|
||||
// 检查更新
|
||||
this.checkUpdate()
|
||||
@@ -320,6 +322,7 @@ App({
|
||||
if (res && (res.data || res.chapters)) {
|
||||
const chapters = res.data || res.chapters || []
|
||||
this.globalData.bookData = chapters
|
||||
this.globalData.totalSections = (chapters && chapters.length) ? chapters.length : 62
|
||||
wx.setStorageSync('bookData', chapters)
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -327,6 +330,21 @@ App({
|
||||
}
|
||||
},
|
||||
|
||||
// 加载 mpConfig(appId、mchId、withdrawSubscribeTmplId 等),失败时保留 globalData 默认值
|
||||
async loadMpConfig() {
|
||||
try {
|
||||
const res = await this.request({ url: '/api/miniprogram/config', silent: true })
|
||||
const mp = (res && res.mpConfig) || (res && res.configs && res.configs.mp_config)
|
||||
if (mp && typeof mp === 'object') {
|
||||
if (mp.appId) this.globalData.appId = mp.appId
|
||||
if (mp.mchId) this.globalData.mchId = mp.mchId
|
||||
if (mp.withdrawSubscribeTmplId) this.globalData.withdrawSubscribeTmplId = mp.withdrawSubscribeTmplId
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[App] loadMpConfig 失败,使用默认值:', e?.message || e)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 小程序更新检测(基于 wx.getUpdateManager)
|
||||
* - 启动时检测;从后台切回前台时也检测(间隔至少 5 分钟,避免频繁请求)
|
||||
|
||||
@@ -812,11 +812,6 @@ Page({
|
||||
wx.navigateTo({ url: '/pages/referral/referral' })
|
||||
},
|
||||
|
||||
// 跳转到找伙伴
|
||||
goToMatch() {
|
||||
wx.switchTab({ url: '/pages/match/match' })
|
||||
},
|
||||
|
||||
// 退出登录
|
||||
handleLogout() {
|
||||
wx.showModal({
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,379 +0,0 @@
|
||||
/* ???????? - 1:1??Web?? */
|
||||
.page { min-height: 100vh; background: #000; padding-bottom: 64rpx; }
|
||||
|
||||
/* ??? */
|
||||
.nav-bar { position: fixed; top: 0; left: 0; right: 0; z-index: 100; background: rgba(0,0,0,0.9); backdrop-filter: blur(40rpx); display: flex; align-items: center; justify-content: space-between; padding: 0 32rpx; height: 88rpx; }
|
||||
.nav-left { display: flex; gap: 16rpx; align-items: center; }
|
||||
.nav-back { width: 64rpx; height: 64rpx; background: #1c1c1e; border-radius: 50%; display: flex; align-items: center; justify-content: center; }
|
||||
.nav-icon { width: 40rpx; height: 40rpx; display: block; filter: brightness(0) saturate(100%) invert(60%) sepia(0%) saturate(0%) hue-rotate(0deg) brightness(95%) contrast(85%); }
|
||||
.nav-title { font-size: 34rpx; font-weight: 600; color: #fff; flex: 1; text-align: center; }
|
||||
.nav-right-placeholder { width: 144rpx; }
|
||||
.nav-btn { width: 64rpx; height: 64rpx; background: #1c1c1e; border-radius: 50%; display: flex; align-items: center; justify-content: center; }
|
||||
|
||||
.content { padding: 24rpx; width: 100%; box-sizing: border-box; }
|
||||
|
||||
/* ?????? */
|
||||
.expiring-banner { display: flex; align-items: center; gap: 24rpx; padding: 24rpx; background: rgba(255,165,0,0.1); border: 2rpx solid rgba(255,165,0,0.3); border-radius: 24rpx; margin-bottom: 24rpx; }
|
||||
.banner-icon { width: 80rpx; height: 80rpx; background: rgba(255,165,0,0.2); border-radius: 50%; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
|
||||
.icon-bell-warning { width: 40rpx; height: 40rpx; display: block; filter: brightness(0) saturate(100%) invert(64%) sepia(89%) saturate(1363%) hue-rotate(4deg) brightness(101%) contrast(102%); }
|
||||
.banner-content { flex: 1; }
|
||||
.banner-title { font-size: 28rpx; font-weight: 500; color: #fff; display: block; }
|
||||
.banner-desc { font-size: 24rpx; color: rgba(255,165,0,0.8); margin-top: 4rpx; display: block; }
|
||||
|
||||
/* ???? - ?? Next.js */
|
||||
.earnings-card { position: relative; background: rgba(28, 28, 30, 0.8); backdrop-filter: blur(40rpx); border: 2rpx solid rgba(255,255,255,0.1); border-radius: 32rpx; padding: 48rpx; margin-bottom: 24rpx; overflow: hidden; width: 100%; box-sizing: border-box; }
|
||||
.earnings-bg { position: absolute; top: 0; right: 0; width: 256rpx; height: 256rpx; background: rgba(0,206,209,0.15); border-radius: 50%; filter: blur(100rpx); }
|
||||
.earnings-main { position: relative; }
|
||||
.earnings-header { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 32rpx; }
|
||||
.earnings-left { display: flex; align-items: center; gap: 16rpx; }
|
||||
.wallet-icon { width: 80rpx; height: 80rpx; background: rgba(0,206,209,0.2); border-radius: 20rpx; display: flex; align-items: center; justify-content: center; }
|
||||
.icon-wallet { width: 40rpx; height: 40rpx; display: block; filter: brightness(0) saturate(100%) invert(72%) sepia(54%) saturate(2933%) hue-rotate(134deg) brightness(101%) contrast(101%); }
|
||||
.earnings-info { display: flex; flex-direction: column; gap: 8rpx; }
|
||||
.earnings-label { font-size: 24rpx; color: rgba(255,255,255,0.6); }
|
||||
.commission-rate { font-size: 24rpx; color: #00CED1; font-weight: 500; }
|
||||
.earnings-right { text-align: right; }
|
||||
.earnings-value { font-size: 60rpx; font-weight: 700; color: #fff; display: block; line-height: 1; }
|
||||
.pending-text { font-size: 24rpx; color: rgba(255,255,255,0.5); margin-top: 8rpx; display: block; }
|
||||
|
||||
.withdraw-btn { padding: 28rpx; background: linear-gradient(135deg, #00CED1 0%, #20B2AA 100%); color: #fff; font-size: 32rpx; font-weight: 600; text-align: center; border-radius: 24rpx; box-shadow: 0 8rpx 24rpx rgba(0,206,209,0.3); }
|
||||
.withdraw-btn.btn-disabled { background: rgba(0,206,209,0.2); color: rgba(255,255,255,0.3); box-shadow: none; }
|
||||
|
||||
/* ???? - ?? Next.js 4??? */
|
||||
.stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8rpx; margin-bottom: 24rpx; width: 100%; box-sizing: border-box; }
|
||||
.stat-card { background: rgba(28, 28, 30, 0.8); backdrop-filter: blur(40rpx); border: 2rpx solid rgba(255,255,255,0.1); border-radius: 24rpx; padding: 24rpx 12rpx; text-align: center; }
|
||||
.stat-value { font-size: 40rpx; font-weight: 700; color: #fff; display: block; }
|
||||
.stat-value.orange { color: #FFA500; }
|
||||
.stat-label { font-size: 20rpx; color: rgba(255,255,255,0.6); margin-top: 8rpx; display: block; }
|
||||
|
||||
/* ????? */
|
||||
.visit-stat { display: flex; align-items: center; justify-content: center; gap: 12rpx; padding: 20rpx 32rpx; background: rgba(255,255,255,0.05); border-radius: 16rpx; margin-bottom: 24rpx; }
|
||||
.visit-label { font-size: 24rpx; color: rgba(255,255,255,0.5); }
|
||||
.visit-value { font-size: 32rpx; font-weight: 700; color: #00CED1; }
|
||||
.visit-tip { font-size: 24rpx; color: rgba(255,255,255,0.5); }
|
||||
|
||||
/* ???? - ?? Next.js */
|
||||
.rules-card { background: rgba(0,206,209,0.05); border: 2rpx solid rgba(0,206,209,0.2); border-radius: 24rpx; padding: 32rpx; margin-bottom: 24rpx; width: 100%; box-sizing: border-box; }
|
||||
.rules-header { display: flex; align-items: center; gap: 16rpx; margin-bottom: 16rpx; }
|
||||
.rules-icon { width: 64rpx; height: 64rpx; background: rgba(0,206,209,0.2); border-radius: 16rpx; display: flex; align-items: center; justify-content: center; }
|
||||
.icon-alert { width: 32rpx; height: 32rpx; display: block; filter: brightness(0) saturate(100%) invert(72%) sepia(54%) saturate(2933%) hue-rotate(134deg) brightness(101%) contrast(101%); }
|
||||
.rules-title { font-size: 28rpx; font-weight: 500; color: #fff; }
|
||||
.rules-list { padding-left: 8rpx; }
|
||||
.rule-item { font-size: 24rpx; color: rgba(255,255,255,0.6); line-height: 2; display: block; margin-bottom: 4rpx; }
|
||||
.rule-item .gold { color: #FFD700; font-weight: 500; }
|
||||
.rule-item .brand { color: #00CED1; font-weight: 500; }
|
||||
.rule-item .orange { color: #FFA500; font-weight: 500; }
|
||||
|
||||
/* ?????? - ?? Next.js */
|
||||
.binding-card { background: rgba(28, 28, 30, 0.8); backdrop-filter: blur(40rpx); border: 2rpx solid rgba(255,255,255,0.1); border-radius: 32rpx; overflow: hidden; margin-bottom: 24rpx; width: 100%; box-sizing: border-box; }
|
||||
.binding-header { display: flex; align-items: center; justify-content: space-between; padding: 28rpx 32rpx; border-bottom: 2rpx solid rgba(255,255,255,0.05); }
|
||||
.binding-title { display: flex; align-items: center; gap: 12rpx; }
|
||||
.binding-icon-img { width: 40rpx; height: 40rpx; display: block; filter: brightness(0) saturate(100%) invert(72%) sepia(54%) saturate(2933%) hue-rotate(134deg) brightness(101%) contrast(101%); }
|
||||
.title-text { font-size: 30rpx; font-weight: 600; color: #fff; }
|
||||
.binding-count { font-size: 26rpx; color: rgba(255,255,255,0.5); }
|
||||
.toggle-icon { font-size: 24rpx; color: rgba(255,255,255,0.5); }
|
||||
|
||||
/* Tab?? */
|
||||
.binding-tabs { display: flex; border-bottom: 2rpx solid rgba(255,255,255,0.05); }
|
||||
.tab-item { flex: 1; padding: 24rpx 0; text-align: center; font-size: 26rpx; color: rgba(255,255,255,0.5); position: relative; }
|
||||
.tab-item.tab-active { color: #00CED1; }
|
||||
.tab-item.tab-active::after { content: ''; position: absolute; bottom: 0; left: 50%; transform: translateX(-50%); width: 80rpx; height: 4rpx; background: #00CED1; border-radius: 4rpx; }
|
||||
|
||||
/* ???? */
|
||||
.binding-list { max-height: 640rpx; overflow-y: auto; }
|
||||
.empty-state { padding: 80rpx 0; text-align: center; }
|
||||
.empty-icon { font-size: 64rpx; display: block; margin-bottom: 16rpx; }
|
||||
.empty-text { font-size: 26rpx; color: rgba(255,255,255,0.5); }
|
||||
|
||||
.binding-item { display: flex; align-items: center; padding: 24rpx 32rpx; border-bottom: 2rpx solid rgba(255,255,255,0.05); }
|
||||
.binding-item:last-child { border-bottom: none; }
|
||||
.user-avatar { width: 80rpx; height: 80rpx; border-radius: 50%; background: rgba(0,206,209,0.2); display: flex; align-items: center; justify-content: center; font-size: 28rpx; font-weight: 600; color: #00CED1; margin-right: 24rpx; flex-shrink: 0; }
|
||||
.user-avatar.avatar-converted { background: rgba(76,175,80,0.2); color: #4CAF50; }
|
||||
.user-avatar.avatar-expired { background: rgba(158,158,158,0.2); color: #9E9E9E; }
|
||||
.user-info { flex: 1; }
|
||||
.user-name { font-size: 28rpx; color: #fff; font-weight: 500; display: block; }
|
||||
.user-time { font-size: 22rpx; color: rgba(255,255,255,0.5); margin-top: 4rpx; display: block; }
|
||||
.user-status { text-align: right; }
|
||||
.status-amount { font-size: 28rpx; color: #4CAF50; font-weight: 600; display: block; }
|
||||
.status-order { font-size: 22rpx; color: rgba(255,255,255,0.5); }
|
||||
.status-tag { font-size: 22rpx; padding: 8rpx 16rpx; border-radius: 16rpx; }
|
||||
.status-tag.tag-green { background: rgba(76,175,80,0.2); color: #4CAF50; }
|
||||
.status-tag.tag-orange { background: rgba(255,165,0,0.2); color: #FFA500; }
|
||||
.status-tag.tag-red { background: rgba(244,67,54,0.2); color: #F44336; }
|
||||
|
||||
/* ????? - ?? Next.js */
|
||||
.invite-card { background: rgba(28, 28, 30, 0.8); backdrop-filter: blur(40rpx); border: 2rpx solid rgba(255,255,255,0.1); border-radius: 32rpx; padding: 40rpx; margin-bottom: 24rpx; width: 100%; box-sizing: border-box; }
|
||||
.invite-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 24rpx; }
|
||||
.invite-title { font-size: 30rpx; font-weight: 600; color: #fff; }
|
||||
.invite-code-box { background: rgba(0,206,209,0.2); padding: 12rpx 24rpx; border-radius: 16rpx; }
|
||||
.invite-code { font-size: 28rpx; font-weight: 600; color: #00CED1; font-family: 'Courier New', monospace; letter-spacing: 2rpx; }
|
||||
.invite-tip { font-size: 24rpx; color: rgba(255,255,255,0.6); line-height: 1.5; display: block; }
|
||||
.invite-tip .gold { color: #FFD700; }
|
||||
.invite-tip .brand { color: #00CED1; }
|
||||
|
||||
/* ?????? - ?? Next.js */
|
||||
.earnings-detail-card { background: rgba(28, 28, 30, 0.8); backdrop-filter: blur(40rpx); border: 2rpx solid rgba(255,255,255,0.1); border-radius: 32rpx; overflow: hidden; margin-bottom: 24rpx; width: 100%; box-sizing: border-box; }
|
||||
.detail-header { padding: 40rpx 40rpx 24rpx; border-bottom: 2rpx solid rgba(255,255,255,0.05); }
|
||||
.detail-title { font-size: 30rpx; font-weight: 600; color: #fff; }
|
||||
.detail-list { max-height: 480rpx; overflow-y: auto; }
|
||||
.detail-item { display: flex; align-items: center; justify-content: space-between; padding: 32rpx 40rpx; border-bottom: 2rpx solid rgba(255,255,255,0.05); }
|
||||
.detail-item:last-child { border-bottom: none; }
|
||||
.detail-left { display: flex; align-items: center; gap: 24rpx; flex: 1; }
|
||||
.detail-icon { width: 80rpx; height: 80rpx; border-radius: 20rpx; background: rgba(0,206,209,0.2); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
|
||||
.icon-gift { width: 40rpx; height: 40rpx; display: block; filter: brightness(0) saturate(100%) invert(72%) sepia(54%) saturate(2933%) hue-rotate(134deg) brightness(101%) contrast(101%); }
|
||||
.detail-info { flex: 1; }
|
||||
.detail-type { font-size: 28rpx; color: #fff; font-weight: 500; display: block; }
|
||||
.detail-time { font-size: 24rpx; color: rgba(255,255,255,0.5); margin-top: 4rpx; display: block; }
|
||||
.detail-amount { font-size: 30rpx; font-weight: 600; color: #00CED1; }
|
||||
|
||||
/* ???? - ?? Next.js */
|
||||
.share-section { display: flex; flex-direction: column; gap: 12rpx; width: 100%; margin-bottom: 24rpx; }
|
||||
.share-item { display: flex; align-items: center; background: rgba(28, 28, 30, 0.8); backdrop-filter: blur(40rpx); border: 2rpx solid rgba(255,255,255,0.1); border-radius: 24rpx; padding: 32rpx; border: none; margin: 0; text-align: left; width: 100%; box-sizing: border-box; }
|
||||
.share-item::after { border: none; }
|
||||
.share-icon { width: 96rpx; height: 96rpx; border-radius: 20rpx; display: flex; align-items: center; justify-content: center; margin-right: 24rpx; flex-shrink: 0; }
|
||||
.share-icon.poster { background: rgba(103,58,183,0.2); }
|
||||
.share-icon.wechat { background: rgba(7,193,96,0.2); }
|
||||
.share-icon.link { background: rgba(158,158,158,0.2); }
|
||||
.icon-share-btn { width: 48rpx; height: 48rpx; display: block; }
|
||||
.share-icon.poster .icon-share-btn { filter: brightness(0) saturate(100%) invert(37%) sepia(73%) saturate(2296%) hue-rotate(252deg) brightness(96%) contrast(92%); }
|
||||
.share-icon.wechat .icon-share-btn { filter: brightness(0) saturate(100%) invert(58%) sepia(91%) saturate(1255%) hue-rotate(105deg) brightness(96%) contrast(97%); }
|
||||
.share-icon.link .icon-share-btn { filter: brightness(0) saturate(100%) invert(60%) sepia(0%) saturate(0%) hue-rotate(0deg) brightness(95%) contrast(85%); }
|
||||
.share-info { flex: 1; text-align: left; }
|
||||
.share-title { font-size: 28rpx; color: #fff; font-weight: 500; display: block; text-align: left; }
|
||||
.share-desc { font-size: 22rpx; color: rgba(255,255,255,0.5); margin-top: 4rpx; display: block; text-align: left; }
|
||||
.share-arrow-icon { width: 40rpx; height: 40rpx; display: block; flex-shrink: 0; filter: brightness(0) saturate(100%) invert(60%) sepia(0%) saturate(0%) hue-rotate(0deg) brightness(95%) contrast(85%); }
|
||||
.share-btn-wechat { line-height: normal; font-size: inherit; padding: 24rpx 32rpx !important; margin: 0 !important; width: 100% !important; }
|
||||
|
||||
/* ?????????????? + ???? + ???????? */
|
||||
/* ???????? backdrop-filter??????????????? */
|
||||
.modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.8); display: flex; align-items: center; justify-content: center; z-index: 1000; padding: 32rpx; box-sizing: border-box; }
|
||||
|
||||
.poster-dialog { width: 686rpx; border-radius: 24rpx; overflow: hidden; position: relative; background: transparent; }
|
||||
.poster-close { position: absolute; top: 20rpx; right: 20rpx; width: 56rpx; height: 56rpx; border-radius: 28rpx; background: rgba(0,0,0,0.25); color: rgba(255,255,255,0.9); display: flex; align-items: center; justify-content: center; z-index: 5; font-size: 28rpx; }
|
||||
|
||||
/* ???? */
|
||||
.poster-card { position: relative; background: linear-gradient(135deg, #0a1628 0%, #0f2137 50%, #1a3a5c 100%); color: #fff; padding: 44rpx 40rpx 36rpx; }
|
||||
.poster-inner { position: relative; z-index: 2; display: flex; flex-direction: column; align-items: center; text-align: center; }
|
||||
|
||||
/* ???? */
|
||||
/* ???????? filter: blur ??????????????? + ???? */
|
||||
.poster-glow { position: absolute; width: 320rpx; height: 320rpx; border-radius: 50%; opacity: 0.6; z-index: 1; }
|
||||
.poster-glow-left { top: -120rpx; left: -160rpx; background: rgba(0,206,209,0.12); box-shadow: 0 0 140rpx 40rpx rgba(0,206,209,0.18); }
|
||||
.poster-glow-right { bottom: -140rpx; right: -160rpx; background: rgba(255,215,0,0.10); box-shadow: 0 0 160rpx 50rpx rgba(255,215,0,0.14); }
|
||||
.poster-ring { position: absolute; width: 520rpx; height: 520rpx; border-radius: 50%; border: 2rpx solid rgba(0,206,209,0.06); left: 50%; top: 50%; transform: translate(-50%, -50%); z-index: 1; }
|
||||
|
||||
/* ???? */
|
||||
.poster-badges { display: flex; gap: 16rpx; margin-bottom: 24rpx; }
|
||||
.poster-badge { padding: 10rpx 22rpx; font-size: 20rpx; font-weight: 700; border-radius: 999rpx; border: 2rpx solid transparent; }
|
||||
.poster-badge-gold { background: rgba(255,215,0,0.18); color: #FFD700; border-color: rgba(255,215,0,0.28); }
|
||||
.poster-badge-brand { background: rgba(0,206,209,0.18); color: #00CED1; border-color: rgba(0,206,209,0.28); }
|
||||
|
||||
/* ?? */
|
||||
.poster-title { margin-bottom: 8rpx; }
|
||||
.poster-title-line1 { display: block; font-size: 44rpx; font-weight: 900; line-height: 1.1; color: #00CED1; }
|
||||
.poster-title-line2 { display: block; font-size: 44rpx; font-weight: 900; line-height: 1.1; color: #fff; margin-top: 6rpx; }
|
||||
.poster-subtitle { display: block; font-size: 22rpx; color: rgba(255,255,255,0.6); margin-bottom: 28rpx; }
|
||||
|
||||
/* ???? */
|
||||
.poster-stats { width: 100%; display: flex; gap: 16rpx; justify-content: center; margin-bottom: 24rpx; }
|
||||
.poster-stat { flex: 1; max-width: 190rpx; background: rgba(255,255,255,0.05); border: 2rpx solid rgba(255,255,255,0.10); border-radius: 16rpx; padding: 18rpx 10rpx; }
|
||||
.poster-stat-value { display: block; font-size: 44rpx; font-weight: 900; line-height: 1; }
|
||||
.poster-stat-label { display: block; font-size: 20rpx; color: rgba(255,255,255,0.5); margin-top: 8rpx; }
|
||||
.poster-stat-gold { color: #FFD700; }
|
||||
.poster-stat-brand { color: #00CED1; }
|
||||
.poster-stat-pink { color: #E91E63; }
|
||||
|
||||
/* ?? */
|
||||
.poster-tags { display: flex; flex-wrap: wrap; justify-content: center; gap: 10rpx; margin: 0 24rpx 26rpx; }
|
||||
.poster-tag { font-size: 20rpx; color: rgba(255,255,255,0.7); background: rgba(255,255,255,0.05); border: 2rpx solid rgba(255,255,255,0.10); border-radius: 12rpx; padding: 6rpx 14rpx; }
|
||||
|
||||
/* ??? */
|
||||
.poster-recommender { display: flex; align-items: center; gap: 12rpx; background: rgba(0,206,209,0.10); border: 2rpx solid rgba(0,206,209,0.20); border-radius: 999rpx; padding: 12rpx 22rpx; margin-bottom: 22rpx; }
|
||||
.poster-avatar { width: 44rpx; height: 44rpx; border-radius: 22rpx; background: rgba(0,206,209,0.30); display: flex; align-items: center; justify-content: center; }
|
||||
.poster-avatar-text { font-size: 20rpx; font-weight: 800; color: #00CED1; }
|
||||
.poster-recommender-text { font-size: 22rpx; color: #00CED1; }
|
||||
|
||||
/* ??? */
|
||||
.poster-discount { width: 100%; background: linear-gradient(90deg, rgba(255,215,0,0.10) 0%, rgba(233,30,99,0.10) 100%); border: 2rpx solid rgba(255,215,0,0.20); border-radius: 18rpx; padding: 18rpx 18rpx; margin-bottom: 26rpx; }
|
||||
.poster-discount-text { font-size: 22rpx; color: rgba(255,255,255,0.80); }
|
||||
.poster-discount-highlight { color: #00CED1; font-weight: 800; }
|
||||
|
||||
/* ??? */
|
||||
.poster-qr-wrap { background: #fff; padding: 14rpx; border-radius: 16rpx; margin-bottom: 12rpx; box-shadow: 0 16rpx 40rpx rgba(0,0,0,0.35); }
|
||||
.poster-qr-img { width: 240rpx; height: 240rpx; display: block; }
|
||||
.poster-qr-tip { font-size: 20rpx; color: rgba(255,255,255,0.40); margin-bottom: 8rpx; }
|
||||
.poster-code { font-size: 22rpx; font-family: monospace; letter-spacing: 2rpx; color: rgba(0,206,209,0.80); }
|
||||
|
||||
/* ??????? */
|
||||
.poster-footer { background: #fff; padding: 28rpx 28rpx 32rpx; display: flex; flex-direction: column; gap: 18rpx; }
|
||||
.poster-footer-tip { font-size: 22rpx; color: rgba(0,0,0,0.55); text-align: center; }
|
||||
.poster-footer-btn { height: 72rpx; border-radius: 18rpx; border: 2rpx solid rgba(0,0,0,0.15); display: flex; align-items: center; justify-content: center; font-size: 28rpx; color: rgba(0,0,0,0.75); background: #fff; }
|
||||
|
||||
| ||||