From d83f3d8419713d65564e8d9efd3c124e763f7daf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B9=98=E9=A3=8E?= Date: Thu, 5 Feb 2026 14:50:25 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=AE=A2=E5=8D=95=E6=8E=A8?= =?UTF-8?q?=E8=8D=90=E4=BA=BA=E5=92=8C=E9=82=80=E8=AF=B7=E7=A0=81=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=8C=E4=BC=98=E5=8C=96=E6=94=AF=E4=BB=98=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E4=B8=AD=E7=9A=84=E8=AE=A2=E5=8D=95=E6=8F=92=E5=85=A5?= =?UTF-8?q?=E9=80=BB=E8=BE=91=EF=BC=8C=E7=A1=AE=E4=BF=9D=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E5=87=86=E7=A1=AE=E3=80=82=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E5=B0=8F=E7=A8=8B=E5=BA=8F=E6=94=AF=E4=BB=98=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=EF=BC=8C=E6=94=AF=E6=8C=81=E4=BC=A0=E9=80=92=E9=82=80=E8=AF=B7?= =?UTF-8?q?=E7=A0=81=E4=BB=A5=E4=BE=BF=E4=BA=8E=E5=88=86=E9=94=80=E5=BD=92?= =?UTF-8?q?=E5=B1=9E=E5=92=8C=E5=AF=B9=E8=B4=A6=E3=80=82=E5=90=8C=E6=97=B6?= =?UTF-8?q?=EF=BC=8C=E8=B0=83=E6=95=B4=E6=95=B0=E6=8D=AE=E5=BA=93=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E4=BB=A5=E6=94=AF=E6=8C=81=E6=96=B0=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=EF=BC=8C=E6=8F=90=E5=8D=87=E7=B3=BB=E7=BB=9F=E7=9A=84=E7=A8=B3?= =?UTF-8?q?=E5=AE=9A=E6=80=A7=E5=92=8C=E7=94=A8=E6=88=B7=E4=BD=93=E9=AA=8C?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG-小程序同步.md | 260 ----------------- deploy_miniprogram.py | 225 --------------- package.json | 2 +- scripts/Web转小程序并上传-提示词.md | 166 ----------- scripts/check_chunks.py | 46 --- scripts/check_nginx.py | 24 -- scripts/check_server_logs.py | 41 --- scripts/check_static_files.py | 102 ------- scripts/devlop.py | 4 +- scripts/fix_port_issue.py | 60 ---- scripts/restart_pm2.py | 29 -- scripts/restart_soul_correctly.py | 79 ------ scripts/sync_order_status.py | 240 ---------------- 开发文档/8、部署/soul域名访问问题排查.md | 160 +++++++++++ 转换提示词.md | 345 ----------------------- 15 files changed, 163 insertions(+), 1620 deletions(-) delete mode 100644 CHANGELOG-小程序同步.md delete mode 100644 deploy_miniprogram.py delete mode 100644 scripts/Web转小程序并上传-提示词.md delete mode 100644 scripts/check_chunks.py delete mode 100644 scripts/check_nginx.py delete mode 100644 scripts/check_server_logs.py delete mode 100644 scripts/check_static_files.py delete mode 100644 scripts/fix_port_issue.py delete mode 100644 scripts/restart_pm2.py delete mode 100644 scripts/restart_soul_correctly.py delete mode 100644 scripts/sync_order_status.py create mode 100644 开发文档/8、部署/soul域名访问问题排查.md delete mode 100644 转换提示词.md diff --git a/CHANGELOG-小程序同步.md b/CHANGELOG-小程序同步.md deleted file mode 100644 index ff195949..00000000 --- a/CHANGELOG-小程序同步.md +++ /dev/null @@ -1,260 +0,0 @@ -# 小程序功能同步更新日志 - -## [1.0.0] - 2026-02-04 - -### 🎉 重大更新 - -本次更新完成了 Next.js 功能到微信小程序的完整同步,实现了 **1:1 功能复刻**。 - ---- - -## ✨ 新增功能 - -### 1. 目录页搜索按钮 -- 导航栏右上角添加搜索按钮 -- 点击跳转到搜索页 -- 样式与 Next.js 完全一致 - -**影响文件:** -- `pages/chapters/chapters.wxml` -- `pages/chapters/chapters.wxss` -- `pages/chapters/chapters.js` - ---- - -### 2. 我的页收益卡片艺术化 -- 深蓝渐变背景 (#1a1a2e → #16213e → #0f3460) -- 背景装饰圆(金色右上、青色左下) -- 收益金额使用金色渐变文字 -- 推广按钮使用金色渐变背景 -- 增强视觉冲击力 - -**影响文件:** -- `pages/my/my.wxml` -- `pages/my/my.wxss` - -**视觉效果:** -``` -┌─────────────────────────────┐ -│ 我的收益 推广中心 ↗│ -│ │ -│ 累计收益 可提现 │ -│ ¥8.91 ¥0.00 │ -│ │ -│ 🎁 推广中心 / 提现 │ -└─────────────────────────────┘ -``` - ---- - -### 3. 地址管理模块(完整新建) - -#### 3.1 地址列表页 -- 地址卡片展示(姓名、手机、地址) -- 默认地址标签 -- 编辑、删除操作 -- 新增地址按钮 -- 空状态提示 - -**新增文件:** -- `pages/addresses/addresses.js` -- `pages/addresses/addresses.wxml` -- `pages/addresses/addresses.wxss` -- `pages/addresses/addresses.json` - -#### 3.2 地址编辑页 -- 表单输入(姓名、手机号、详细地址) -- 省市区三级联动选择器 -- 设为默认地址开关 -- 表单验证 -- 保存功能 - -**新增文件:** -- `pages/addresses/edit.js` -- `pages/addresses/edit.wxml` -- `pages/addresses/edit.wxss` -- `pages/addresses/edit.json` - -#### 3.3 设置页入口 -- 在设置页添加「收货地址」入口 -- 点击「管理」跳转到地址列表 - -**影响文件:** -- `pages/settings/settings.wxml` -- `pages/settings/settings.wxss` -- `pages/settings/settings.js` - ---- - -### 4. CSS 变量系统 - -在全局样式中添加 CSS 变量,便于统一管理: - -```css -page { - /* 品牌色 */ - --app-brand: #00CED1; - --app-brand-light: rgba(0, 206, 209, 0.1); - - /* 背景色 */ - --app-bg-primary: #000000; - --app-bg-secondary: #1c1c1e; - --app-bg-tertiary: #2c2c2e; - - /* 文字色 */ - --app-text-primary: #ffffff; - --app-text-secondary: rgba(255, 255, 255, 0.7); - --app-text-tertiary: rgba(255, 255, 255, 0.4); - - /* iOS 系统色 */ - --ios-indigo: #5856D6; - --ios-green: #30d158; - - /* 其他辅助色 */ - --gold: #FFD700; - --pink: #E91E63; - --purple: #7B61FF; -} -``` - -**影响文件:** -- `app.wxss` - ---- - -## 🔄 功能优化 - -### 1. 推广中心(已有功能验证) -- ✅ 绑定用户列表 Tab切换 -- ✅ 过期提醒横幅 -- ✅ 用户状态标签 -- ✅ 分享按钮组 -- ✅ 提现功能 - -### 2. 搜索功能(已有功能验证) -- ✅ 搜索输入框 -- ✅ 热门关键词 -- ✅ 热门章节推荐 -- ✅ 搜索结果列表 - -### 3. 海报生成(已有功能验证) -- ✅ Canvas 绘制 -- ✅ 小程序码集成 -- ✅ 保存到相册 - ---- - -## 📐 样式统一 - -### 颜色规范 -- 背景: #000000 → 统一使用纯黑 -- 品牌色: #00CED1 → 所有页面统一 -- 卡片背景: #1c1c1e / #2c2c2e -- 文字颜色: #ffffff / rgba(255,255,255,0.7) / rgba(255,255,255,0.4) - -### 圆角规范 -- 小标签: 8rpx -- 中等卡片: 24rpx -- 大卡片: 32rpx -- 圆形: 50% - -### 间距规范 -- 页面边距: 32rpx -- 卡片padding: 32rpx -- 元素间距: 24rpx -- 小间距: 16rpx - ---- - -## 📊 代码统计 - -### 新增代码 -- 新增文件: 10个 -- 新增代码行数: ~1200行 - -### 修改代码 -- 修改文件: 7个 -- 修改代码行数: ~150行 - -### 文档 -- 新增文档: 4个 - - `功能同步完成报告.md` - - `样式检查清单.md` - - `交付清单.md` - - `快速测试指南.md` - ---- - -## 🔗 相关文档 - -| 文档 | 位置 | 说明 | -|-----|------|-----| -| 转换提示词 | `转换提示词.md` | 原始需求和执行计划 | -| 完成报告 | `miniprogram/功能同步完成报告.md` | 详细完成情况 | -| 样式检查 | `miniprogram/样式检查清单.md` | 样式统一性检查 | -| 交付清单 | `miniprogram/交付清单.md` | 交付成果清单 | -| 测试指南 | `miniprogram/快速测试指南.md` | 测试指引 | -| 开发约束 | `开发文档/0、Mycontent-book 项目总览.md` | 开发策略约束 | - ---- - -## 🚨 重要说明 - -### 开发约束(2026-02-04 起生效) - -``` -┌────────────────┬──────────┬─────────────────────────┐ -│ 微信小程序 │ ✅ 活跃 │ 所有C端新功能在此开发 │ -│ Next.js C端 │ 🔒 冻结 │ app/view/ 不再新增功能 │ -│ Next.js 管理端 │ ✅ 活跃 │ app/admin/ 继续开发 │ -│ API 接口 │ ✅ 活跃 │ 小程序和管理端共用 │ -└────────────────┴──────────┴─────────────────────────┘ -``` - -### 登录体系差异 - -- **小程序**: 保持微信一键登录(不复刻 Next.js 登录页) -- **Next.js**: 保持手机号+密码登录 -- **统一**: 后端以手机号为唯一标识 - ---- - -## 📋 下一步计划 - -### 短期(本周) -- [ ] 完成功能测试 -- [ ] 修复发现的 Bug -- [ ] 优化用户体验细节 - -### 中期(本月) -- [ ] 性能优化(首屏加载、图片懒加载) -- [ ] 动画优化(更流畅的过渡) -- [ ] 数据缓存策略 - -### 长期(持续) -- [ ] 用户反馈收集 -- [ ] 功能迭代 -- [ ] 数据分析优化 - ---- - -## 👥 贡献者 - -- **执行**: AI Assistant -- **审核**: 待定 -- **测试**: 待定 - ---- - -## 📜 版本历史 - -### v1.0.0 (2026-02-04) -- ✅ 完成 Next.js 功能同步 -- ✅ 新增地址管理模块 -- ✅ 优化收益卡片设计 -- ✅ 添加搜索按钮 -- ✅ 统一全局样式 - ---- - -*本次更新标志着小程序功能达到与 Next.js Web端同等水平。* diff --git a/deploy_miniprogram.py b/deploy_miniprogram.py deleted file mode 100644 index 5dc37915..00000000 --- a/deploy_miniprogram.py +++ /dev/null @@ -1,225 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -Soul创业派对 - 小程序一键部署脚本 -功能: -1. 打开微信开发者工具 -2. 自动编译小程序 -3. 上传到微信平台 -4. 显示审核指引 -""" - -import os -import sys -import time -import subprocess -from pathlib import Path - -# 修复Windows控制台编码问题 -if sys.platform == 'win32': - import io - sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') - sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8') - -# 配置信息 -CONFIG = { - 'appid': 'wxb8bbb2b10dec74aa', - 'project_path': Path(__file__).parent / 'miniprogram', - 'version': '1.0.1', - 'desc': 'Soul创业派对 - 1:1完整还原Web功能' -} - -# 微信开发者工具可能的路径 -DEVTOOLS_PATHS = [ - r"D:\微信web开发者工具\微信开发者工具.exe", - r"C:\Program Files (x86)\Tencent\微信web开发者工具\微信开发者工具.exe", - r"C:\Program Files\Tencent\微信web开发者工具\微信开发者工具.exe", -] - - -def print_banner(): - """打印横幅""" - print("\n" + "=" * 70) - print(" 🚀 Soul创业派对 - 小程序一键部署") - print("=" * 70 + "\n") - - -def find_devtools(): - """查找微信开发者工具""" - print("🔍 正在查找微信开发者工具...") - - for devtools_path in DEVTOOLS_PATHS: - if os.path.exists(devtools_path): - print(f"✅ 找到微信开发者工具: {devtools_path}\n") - return devtools_path - - print("❌ 未找到微信开发者工具") - print("\n请确保已安装微信开发者工具") - print("下载地址: https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html\n") - return None - - -def open_devtools(devtools_path): - """打开微信开发者工具""" - print("📱 正在打开微信开发者工具...") - - try: - # 使用项目路径打开开发者工具 - subprocess.Popen([devtools_path, str(CONFIG['project_path'])]) - print("✅ 微信开发者工具已打开\n") - print("⏳ 等待开发者工具启动(10秒)...") - time.sleep(10) - return True - except Exception as e: - print(f"❌ 打开失败: {e}") - return False - - -def check_private_key(): - """检查上传密钥""" - key_path = CONFIG['project_path'] / 'private.key' - - if not key_path.exists(): - print("\n" + "⚠" * 35) - print("\n❌ 未找到上传密钥文件 private.key\n") - print("📥 获取密钥步骤:") - print(" 1. 访问 https://mp.weixin.qq.com/") - print(" 2. 登录小程序后台") - print(" 3. 开发管理 → 开发设置 → 小程序代码上传密钥") - print(" 4. 点击「生成」,下载密钥文件") - print(" 5. 将下载的 private.*.key 重命名为 private.key") - print(f" 6. 放到目录: {CONFIG['project_path']}") - print("\n💡 温馨提示:") - print(" - 密钥只能生成一次,请妥善保管") - print(" - 如需重新生成,需要到后台重置密钥") - print("\n" + "⚠" * 35 + "\n") - return False - - print(f"✅ 找到密钥文件: private.key\n") - return True - - -def upload_miniprogram(): - """上传小程序""" - print("\n" + "-" * 70) - print("📦 准备上传小程序到微信平台...") - print("-" * 70 + "\n") - - print(f"📂 项目路径: {CONFIG['project_path']}") - print(f"🆔 AppID: {CONFIG['appid']}") - print(f"📌 版本号: {CONFIG['version']}") - print(f"📝 描述: {CONFIG['desc']}\n") - - # 检查密钥 - if not check_private_key(): - return False - - # 切换到miniprogram目录执行上传脚本 - upload_script = CONFIG['project_path'] / '上传小程序.py' - - if not upload_script.exists(): - print(f"❌ 未找到上传脚本: {upload_script}") - return False - - print("⏳ 正在执行上传脚本...\n") - - try: - result = subprocess.run( - [sys.executable, str(upload_script)], - cwd=CONFIG['project_path'], - capture_output=False, # 直接显示输出 - text=True - ) - - return result.returncode == 0 - except Exception as e: - print(f"❌ 上传出错: {e}") - return False - - -def show_next_steps(): - """显示后续步骤""" - print("\n" + "=" * 70) - print("✅ 部署完成!") - print("=" * 70 + "\n") - - print("📱 后续操作:") - print("\n1️⃣ 在微信开发者工具中:") - print(" - 查看编译结果") - print(" - 使用模拟器或真机预览测试") - print(" - 确认所有功能正常") - - print("\n2️⃣ 提交审核:") - print(" - 访问 https://mp.weixin.qq.com/") - print(" - 登录小程序后台") - print(" - 版本管理 → 开发版本") - print(" - 选择刚上传的版本 → 提交审核") - - print("\n3️⃣ 审核材料准备:") - print(" - 小程序演示视频(可选)") - print(" - 测试账号(如有登录功能)") - print(" - 功能说明(突出核心功能)") - - print("\n4️⃣ 审核通过后:") - print(" - 在后台点击「发布」") - print(" - 用户即可在微信中搜索使用") - - print("\n" + "=" * 70 + "\n") - - -def main(): - """主函数""" - print_banner() - - # 1. 查找微信开发者工具 - devtools_path = find_devtools() - if not devtools_path: - print("💡 请先安装微信开发者工具,然后重新运行本脚本") - return False - - # 2. 打开微信开发者工具 - if not open_devtools(devtools_path): - print("❌ 无法打开微信开发者工具") - return False - - print("\n✅ 微信开发者工具已打开,项目已加载") - print("\n💡 现在你可以:") - print(" 1. 在开发者工具中查看和测试小程序") - print(" 2. 使用模拟器或扫码真机预览") - print(" 3. 确认功能正常后,准备上传\n") - - # 3. 询问是否立即上传 - print("-" * 70) - user_input = input("\n是否立即上传到微信平台?(y/n,默认n): ").strip().lower() - - if user_input == 'y': - if upload_miniprogram(): - show_next_steps() - return True - else: - print("\n❌ 上传失败") - print("\n💡 你可以:") - print(" 1. 检查 private.key 是否正确") - print(" 2. 确保已开启开发者工具的「服务端口」") - print(" 3. 或在开发者工具中手动点击「上传」按钮\n") - return False - else: - print("\n✅ 开发者工具已就绪,你可以:") - print(" 1. 在开发者工具中测试小程序") - print(" 2. 准备好后,运行本脚本并选择上传") - print(" 3. 或直接在开发者工具中点击「上传」按钮\n") - return True - - -if __name__ == '__main__': - try: - success = main() - sys.exit(0 if success else 1) - except KeyboardInterrupt: - print("\n\n⚠️ 用户取消操作") - sys.exit(1) - except Exception as e: - print(f"\n❌ 发生错误: {e}") - import traceback - traceback.print_exc() - sys.exit(1) diff --git a/package.json b/package.json index 3b4ac018..4cdee5cd 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "private": true, "scripts": { "build": "next build", - "dev": "next dev -p 30006", + "dev": "next dev -p 3006", "lint": "eslint .", "start": "node scripts/start-standalone.js" }, diff --git a/scripts/Web转小程序并上传-提示词.md b/scripts/Web转小程序并上传-提示词.md deleted file mode 100644 index 66e3782a..00000000 --- a/scripts/Web转小程序并上传-提示词.md +++ /dev/null @@ -1,166 +0,0 @@ -# Web 转小程序 - 完整流程提示词 - -> **用法**:在对话中 @ 本文件(`scripts/Web转小程序并上传-提示词.md`),请 AI 按本提示词执行:**先枚举要转换的页面 → 按规则 100% 转为小程序 → 自检清单逐项通过 → 可选打开微信开发者工具**。 - ---- - -## 一、你的任务(当被 @ 本文件时) - -按**顺序**执行: - -1. **枚举页面**:扫描 `app/` 下所有 `**/page.tsx`(排除 `app/api/`、`app/admin/`),得到需上小程序的页面列表及对应小程序路径(见二)。 -2. **转换**:将上述每个 Web 页面**完整、一致**转为小程序代码到 `miniprogram/`,**样式、按钮、布局、交互、图标零丢失**(见三、四)。 -3. **检查**:按「六、自检清单」逐项自检,确保可运行且与 Web 逐页对照无遗漏。 -4. **打开微信开发者工具**(可选):若用户未说「仅转换」,则执行 `start miniprogram`(Windows)或 `open miniprogram`(Mac),或调用微信开发者工具 CLI 打开 `miniprogram/`。 - -**触发约定**:用户只说「转换」或「只转」→ 只做 1~3;用户说「完整流程」或仅 @ 本文件 → 做 1~4。 - ---- - -## 二、项目结构对照(按规则推导,不写死页面) - -**先扫描 `app/` 得到页面列表,再按规则生成小程序路径与四件套;新增 Web 页面时同样适用。** - -1. **Web 路由 → 小程序页面路径** - - 通用:`app//page.tsx` → `pages//`,`` 取该路由**最后一层目录名**。 - - 特例: - - `app/page.tsx` → `pages/index/index`。 - - 动态路由 `app//[id]/page.tsx` → `pages//`,参数在 `onLoad(options)` 中取 `options.id` 等。 - - 嵌套路由(如 `app/my/referral/page.tsx`)→ 单层页面 `pages/referral/referral`,避免深层路径。 - - **新增**:每增加一个需上小程序的 `app/xxx/page.tsx`,就在 `miniprogram/pages/` 下新增 `pages/xxx/xxx` 四件套(.js/.json/.wxml/.wxss),并在 `app.json` 的 `pages` 中追加 `"pages/xxx/xxx"`。 - -2. **枚举要转换的页面** - - 遍历 `app/` 下所有含 `page.tsx` 的路径,**排除**:`app/api/`、`app/admin/` 及仅 Web/后台用的路由。 - - 对每个需上小程序的页面,按上条得到路径,确保 `miniprogram/pages//` 存在四件套且已在 `app.json` 的 `pages` 中注册。 - -3. **API** - - `app/api/*` 不转为小程序代码;小程序用 `wx.request` 调**同域名**接口(与 `miniprogram/utils`、baseURL 一致),**不写死 localhost**。接口路径、参数、返回格式与 `app/api/` 保持一致。 - -4. **tabBar** - - 仅首页、目录、找伙伴、我的等需底部 tab 的页面配置 `app.json` 的 `tabBar.list`;其余为普通页面。新增 tab 时在 `tabBar.list` 与 `pages` 中同步追加。 - ---- - -## 三、转换规则(Web → 小程序) - -**原则**:以 Web 为唯一真相来源,逐块对照,不猜测、不省略;无法 1:1 处用最接近实现并注释说明。 - -### 3.1 完整性要求(零丢失) - -- **样式**:颜色、字体、字号、行高、间距、圆角、阴影、背景、边框与 Web 一致,在 WXSS 中完整实现。 -- **按钮与可点击**:每个按钮、链接、可点击区域保留,文案、图标、跳转/弹窗/提交与 Web 一致;禁用态、加载态需体现。 -- **布局与结构**:区块划分、顺序、折叠/展开、列表/卡片与 Web 一致,不漏模块。 -- **图片与图标**:Web 中出现的图片、图标、占位图在小程序侧存在并正确引用;**菜单、列表、统计、标签、按钮等处图标逐项对照补全**(可用 emoji 或图片),路径用 `miniprogram/images/` 或 assets。 -- **表单**:输入框、选择器、校验、提交与 Web 一致,不丢字段与校验。 - -### 3.2 组件与语法 - -- **React/JSX → WXML**:`wx:if`、`wx:for`、`bindtap` 等;**禁止在 WXML 中写 JS 方法**(见 4.1)。 -- **Tailwind/CSS → WXSS**:逐条对照 Web 样式,可保留 class 名,视觉效果一致;主题色/字体与 `globals.css` 或设计一致。 -- **状态与生命周期**:`useState`/`useEffect` → Page 的 `data`、`onLoad`、`onShow` 等。 -- **路由**:`useRouter`/`Link` → `wx.navigateTo`、`wx.switchTab`(tab 页用 switchTab)。 -- **接口**:`wx.request` + 项目 baseURL;路径、参数、返回与 `app/api/` 一致。图片放 `miniprogram/images/` 或 assets,引用用相对路径或 `/images/xxx`。 - ---- - -## 四、踩坑与必做项(必须遵守) - -以下为实际转换中的踩坑总结,转换与检查时**必须**按此处理,否则会出现编译错误、模拟器启动失败或界面被遮挡。 - -### 4.1 WXML 禁止在模板里调用 JS 方法 - -- **禁止**:WXML 中不得出现任何 JS 方法调用,例如:`{{ (user.earnings || 0).toFixed(2) }}`、`{{ user.nickname.charAt(0) }}`、`{{ user.id.slice(-8) }}`、`{{ authorInfo.name.charAt(0) }}`,会报「unexpected token」等编译错误。 -- **必须**:在对应页的 `.js` 中(`onLoad`、`onShow`、`syncUser`、数据更新处)**预先计算**展示用字符串,写入 `data`,WXML 只引用 data 变量。推荐命名示例: - - 金额两位小数 → `earningsText`、`balanceText` 等; - - 用户/作者首字 → `userInitial`、`authorInitial`; - - 用户 ID 后几位 → `userIdSuffix`。 - -### 4.2 启动不阻塞、不因网络报错导致模拟器启动失败 - -- **问题**:`App.onLaunch` 里若依赖异步请求(如 `loadFeatureConfig`、`loadBookData`)且未处理好,或对无返回值的函数链式调用 `.catch()`,会导致「模拟器启动失败 / TypeError: Failed to fetch」或「Cannot read property 'catch' of undefined」。 -- **做法**: - - `onLaunch` 中**不要 await** 异步请求;只调用 `loadFeatureConfig().catch(() => {})`(仅对**返回 Promise** 的方法链式 catch),`loadBookData()` 内部已有 catch 则**不要**写 `loadBookData().catch()`(避免对 undefined 调 catch)。 - - `request` 的 `fail` 回调里统一打日志并 reject 友好错误,不把未捕获异常抛到启动流程。 - - 本地调试可在 `project.config.json` 的 `setting` 中设 `"urlCheck": false`,避免域名未配置时请求被拦截;正式发布前再按需改回。 - -### 4.3 底部「找伙伴」Tab 默认不显示,避免闪一下再隐藏 - -- **问题**:若 custom-tab-bar 里「找伙伴」初始为 `hidden: false`,等接口返回 `matchEnabled: false` 后再隐藏,会先显示再消失,观感差。 -- **做法**:custom-tab-bar 的 `list` 里「找伙伴」项**默认 `hidden: true`**;在 `attached` 里先执行一次 `syncMatchEnabled()`(用当前 `globalData.matchEnabled`),再 `app.loadFeatureConfig().then(() => this.syncMatchEnabled())`,仅当接口返回 `matchEnabled === true` 时把该项设为 `hidden: false`。 - -### 4.4 顶部安全区:状态栏 + 胶囊会遮挡,必须预留 - -- **问题**:`navigationStyle: "custom"` 时,**状态栏**和**胶囊按钮**会覆盖页面顶部,标题、返回、按钮被遮挡或点不到。 -- **必须**: - - **占位高度**:统一使用 **`navBarHeight`**(不用固定 `statusBarHeight + 44`)。在 `App.getSystemInfo` 中用 `wx.getSystemInfoSync()` + `wx.getMenuButtonBoundingClientRect()` 计算 `navBarHeight`(状态栏 + 胶囊区域总高),无菜单按钮时回退 `statusBarHeight + 44`。每页占位条高度设为 `{{ navBarHeight }}px`,`onLoad`/`onShow` 从 `getApp().globalData` 取 `navBarHeight`、`statusBarHeight` 写入页面 `data`。 - - **头部右侧留白**:所有带标题/按钮的头部容器加 `.safe-header-right`(`app.wxss` 中定义 `padding-right: 200rpx; box-sizing: border-box;`),或使用 `globalData.capsulePaddingRight` 内联,避免被胶囊遮挡。 - - **占位页统一模板**:无复杂导航的页面(如 `address-edit`、`address-list`、`purchases`、`referral`、`settings`)必须使用**同一套**顶部安全区:顶部占位条高度 `navBarHeight`,其内 `padding-top: {{ statusBarHeight || 44 }}px`,导航容器使用 `display: flex; flex-direction: column; justify-content: flex-end; box-sizing: border-box;`,并加 `safe-header-right`,保证标题与返回按钮不被遮挡且右侧留白一致。 - -### 4.5 图标与样式逐页对照,不得遗漏 - -- **问题**:转换后容易漏掉搜索图标、菜单图标、统计/标签图标、返回箭头等,导致与 Web 不一致。 -- **做法**:逐页对照 Web(如 `components/bottom-nav.tsx`、各 `app/**/page.tsx`): - - **底部 Tab**:每个 tab 有图标(如 🏠📋👥👤 或图片),「找伙伴」若居中凸起需保留样式。 - - **首页**:搜索栏左侧有搜索图标;Banner/卡片/列表中的箭头、标签与 Web 一致。 - - **我的**:用户卡片「创业伙伴」旁有星标;收益卡片有收益图标;菜单项(订单、推广、关于、设置)各有图标;概览/我的足迹 Tab 及阅读统计、最近阅读、匹配记录等区块有对应图标或标题图标。 - - **关于**:作者首字用 data 中的 `authorInitial`;标签(直播时间、平台)带图标;统计四项带图标;「加入派对群」按钮带图标;返回为「← 返回」。 - - **阅读/搜索/目录/找伙伴**:返回、分享、锁、类型图标等与 Web 一致。所有导航返回统一用「← 返回」等可识别样式。 - -### 4.6 卡片与按钮布局错位(如「我的收益」与「推广中心」按钮) - -- **问题**:卡片内标题行(如「我的收益」+「推广中心 ›」)与底部全宽按钮(如「推广中心 / 提现」)出现错位、溢出或与卡片边缘不对齐,与 Web 不一致。 -- **做法**: - - **盒子模型**:页面根容器与所有卡片统一加 `box-sizing: border-box`,避免 padding 导致总宽度超出或视觉偏移。 - - **卡片内标题行**:若为 flex 布局(如左侧标题 + 右侧链接),给容器加 `gap`、`min-width: 0`;左侧标题区加 `flex-shrink: 0`、`min-width: 0`,标题与链接加 `white-space: nowrap`,右侧链接加 `flex-shrink: 0`、`white-space: nowrap`,防止挤压、换行或重叠错位。 - - **全宽按钮**:卡片内的「全宽」按钮使用 `display: block`、`width: 100%`、`box-sizing: border-box`,保证与卡片内容区同宽、与上方内容左右对齐;不得因缺 box-sizing 或未 block 导致宽度计算错误而错位。 - -### 4.7 「我的」-「我的足迹」-「匹配记录」需随 matchEnabled 控制 - -- **要求**:与 Web 一致,当全局配置 `matchEnabled === false` 时,「我的」页「我的足迹」Tab 下的「匹配记录」区块**不展示**;仅当 `matchEnabled === true` 时展示。小程序侧从 `getApp().globalData.matchEnabled` 读取,在 WXML 中用 `wx:if="{{ matchEnabled }}"` 控制该区块显隐,并在 `onShow` 或数据刷新时同步该值到页面 `data`。 - ---- - -## 五、必须保留的小程序配置 - -- **AppID**:`wxb8bbb2b10dec74aa`(见 `miniprogram/project.config.json`、`.cursorrules`)。 -- **app.json**:`pages`、`window`、`tabBar`(含 `custom: true` 时保留 `custom-tab-bar`)、`permission`、`requiredPrivateInfos` 等按现有或微信规范保留。 -- **project.config.json**:保持现有编译与项目配置,不随意改 appid;本地调试可设 `urlCheck: false`,见 4.2。 -- **custom-tab-bar**:若使用自定义 tabBar,保留 `custom-tab-bar` 组件实现,并遵守 4.3 的「找伙伴」默认隐藏规则。 - ---- - -## 六、转换完成后的自检清单 - -- [ ] **页面注册**:`app.json` 的 `pages` 与 `miniprogram/pages/` 下目录、四件套一一对应,无缺页。 -- [ ] **组件引用**:各页 `.json` 的 `usingComponents` 与自定义组件路径正确(若有)。 -- [ ] **WXML 合规**:无语法错误;**WXML 中无 `.toFixed()`、`.charAt()`、`.slice()` 等 JS 方法**,展示用数值/字符串均已预先写入 data 并在模板中引用。 -- [ ] **接口**:baseURL 为线上或配置项,非 localhost(仅本地调试可例外)。 -- [ ] **tabBar**:与 Web 一级入口一致;**「找伙伴」项默认 `hidden: true`,仅当接口返回 `matchEnabled === true` 后显示**(见 4.3)。 -- [ ] **顶部安全区**:所有自定义头部页使用 `navBarHeight` 占位,头部容器加 `safe-header-right`;占位页(address-edit、address-list、purchases、referral、settings)使用统一顶部安全区模板(见 4.4)。 -- [ ] **卡片与按钮**:含标题行+链接+全宽按钮的卡片使用 `box-sizing: border-box`,标题行防挤压/换行,全宽按钮 `display: block`、`width: 100%`、`box-sizing: border-box`,与内容区左右对齐无错位(见 4.6)。 -- [ ] **「我的足迹」-「匹配记录」**:该区块随 `globalData.matchEnabled` 显隐,`matchEnabled === false` 时不展示(见 4.7)。 -- [ ] **完整性**:逐页对照 Web,样式、按钮、链接、图片、**图标**、表单、列表/卡片无遗漏;无法 1:1 处已用最接近实现并注释说明。 - ---- - -## 七、转换完成后的步骤 - -转换完成后,**打开微信开发者工具**: - -- **方式一**:执行 `start miniprogram`(Windows)或 `open miniprogram`(Mac)打开文件夹,将 `miniprogram` 文件夹拖入微信开发者工具导入项目。 -- **方式二**:若已安装微信开发者工具 CLI,可直接调用其打开项目(如 Windows:`"C:\Program Files (x86)\Tencent\微信web开发者工具\cli.bat" open --project miniprogram`)。 - -在微信开发者工具中可预览、调试;需要上传时,使用工具内的「上传」功能,或执行 `python scripts/autosysc-weixin.py`。 - ---- - -## 八、参考文件位置 - -- **Web 对照**:`app/**/page.tsx`、`components/`;接口路径、参数、返回格式参照 `app/api/`,保证与 Web 一致。 -- **小程序结构**:`miniprogram/app.json`、`miniprogram/pages/`、`miniprogram/utils/`、`miniprogram/custom-tab-bar/`、`miniprogram/app.js`。 -- **上传**:`scripts/autosysc-weixin.py`(项目根运行,需先配置 `miniprogram/private.key`)。 -- **配置说明**:`miniprogram/小程序快速配置指南.md`、`miniprogram/小程序部署说明.md`。 - ---- - -**当你被 @ 本文件时**:按「一、你的任务」顺序执行(枚举页面 → 转换 → 自检 → 可选打开开发者工具),并**严格遵循**二(结构对照)、三(转换规则)、四(踩坑必做项)、五(配置保留)、六(自检清单);四、六中的条目为必做项,不可省略。 diff --git a/scripts/check_chunks.py b/scripts/check_chunks.py deleted file mode 100644 index c5d4b9c0..00000000 --- a/scripts/check_chunks.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -import paramiko - -client = paramiko.SSHClient() -client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) -client.connect('42.194.232.22', port=22022, username='root', password='Zhiqun1984', timeout=15) - -print("=== 检查 chunks 目录文件(前20个)===") -cmd = "ls -la /www/wwwroot/soul/.next/static/chunks/ 2>/dev/null | head -25" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -print(result if result else "目录不存在") - -print("\n=== 是否有 turbopack 文件 ===") -cmd = "find /www/wwwroot/soul/.next/static -name '*turbopack*' 2>/dev/null" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -print(result if result else "无 turbopack 文件(正常,这是生产模式)") - -print("\n=== 检查请求的具体文件 ===") -files_to_check = [ - "a954454d2ab1d3ca.css", - "6a98f5c6b2554ef3.js", - "turbopack-0d89ab930ad9d74d.js", -] -for f in files_to_check: - cmd = "find /www/wwwroot/soul/.next/static -name '%s' 2>/dev/null" % f - stdin, stdout, stderr = client.exec_command(cmd, timeout=10) - result = stdout.read().decode('utf-8', errors='replace').strip() - status = "[OK] 存在" if result else "[X] 不存在" - print("%s: %s" % (f, status)) - -print("\n=== 检查实际可用的 css 文件 ===") -cmd = "ls /www/wwwroot/soul/.next/static/css/ 2>/dev/null | head -10" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -print(result if result else "无 css 文件") - -print("\n=== 构建模式检查 ===") -cmd = "head -5 /www/wwwroot/soul/.next/BUILD_ID 2>/dev/null" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -print("BUILD_ID: %s" % (result if result else "不存在")) - -client.close() diff --git a/scripts/check_nginx.py b/scripts/check_nginx.py deleted file mode 100644 index c21028b1..00000000 --- a/scripts/check_nginx.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -import paramiko - -client = paramiko.SSHClient() -client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) -client.connect('42.194.232.22', port=22022, username='root', password='Zhiqun1984', timeout=15) - -print("=== soul.quwanzhi.com.conf ===") -stdin, stdout, stderr = client.exec_command('cat /www/server/panel/vhost/nginx/soul.quwanzhi.com.conf 2>/dev/null', timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -print(result if result else "文件不存在") - -print("\n=== 检查 include 配置 ===") -stdin, stdout, stderr = client.exec_command('ls -la /www/server/panel/vhost/nginx/ | grep soul', timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -print(result if result else "无 soul 相关配置") - -print("\n=== node_soul.conf ===") -stdin, stdout, stderr = client.exec_command('cat /www/server/panel/vhost/nginx/node_soul.conf 2>/dev/null', timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -print(result if result else "文件不存在") - -client.close() diff --git a/scripts/check_server_logs.py b/scripts/check_server_logs.py deleted file mode 100644 index 21905b3d..00000000 --- a/scripts/check_server_logs.py +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -import paramiko - -client = paramiko.SSHClient() -client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) -client.connect('42.194.232.22', port=22022, username='root', password='Zhiqun1984', timeout=15) - -print("=== PM2 soul 日志(最后 50 行)===") -cmd = "pm2 logs soul --lines 50 --nostream 2>&1 | tail -50" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -result = result.encode('ascii', errors='replace').decode('ascii') -print(result) - -print("\n=== PM2 soul 错误日志 ===") -cmd = "pm2 logs soul --err --lines 30 --nostream 2>&1 | tail -30" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -result = result.encode('ascii', errors='replace').decode('ascii') -print(result) - -print("\n=== 检查 server.js 文件 ===") -cmd = "ls -lh /www/wwwroot/soul/server.js" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -print(result) - -print("\n=== 检查 .next 目录结构 ===") -cmd = "ls -lh /www/wwwroot/soul/.next/ | head -20" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -print(result) - -print("\n=== 检查端口 30006 ===") -cmd = "curl -I http://127.0.0.1:30006 2>&1 | head -10" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -print(result) - -client.close() diff --git a/scripts/check_static_files.py b/scripts/check_static_files.py deleted file mode 100644 index 2137a753..00000000 --- a/scripts/check_static_files.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -快速检查服务器上静态资源是否存在 -用于排查管理端 404 问题 -""" - -import os -import sys - -try: - import paramiko -except ImportError: - print("请安装: pip install paramiko") - sys.exit(1) - -# 配置(与 devlop.py 一致) -DEPLOY_PROJECT_PATH = os.environ.get("DEPLOY_PROJECT_PATH", "/www/wwwroot/soul") -DEVLOP_DIST_PATH = "/www/wwwroot/auto-devlop/soul/dist" -DEFAULT_SSH_PORT = int(os.environ.get("DEPLOY_SSH_PORT", "22022")) - -def get_cfg(): - return { - "host": os.environ.get("DEPLOY_HOST", "42.194.232.22"), - "user": os.environ.get("DEPLOY_USER", "root"), - "password": os.environ.get("DEPLOY_PASSWORD", "Zhiqun1984"), - "ssh_key": os.environ.get("DEPLOY_SSH_KEY", ""), - "project_path": os.environ.get("DEPLOY_PROJECT_PATH", DEPLOY_PROJECT_PATH), - } - -def check_static_files(): - cfg = get_cfg() - client = paramiko.SSHClient() - client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - - try: - print("正在连接服务器...") - if cfg.get("ssh_key") and os.path.isfile(cfg["ssh_key"]): - client.connect(cfg["host"], port=DEFAULT_SSH_PORT, username=cfg["user"], key_filename=cfg["ssh_key"], timeout=15) - else: - client.connect(cfg["host"], port=DEFAULT_SSH_PORT, username=cfg["user"], password=cfg["password"], timeout=15) - - print("\n=== 检查静态资源目录 ===") - - # 检查多个可能的路径(deploy 模式和 devlop 模式) - checks = [ - ("%s/.next/static" % DEVLOP_DIST_PATH, "devlop 模式 dist 目录"), - ("%s/.next/static" % DEPLOY_PROJECT_PATH, "deploy 模式项目目录"), - ("%s/server.js" % DEVLOP_DIST_PATH, "devlop server.js"), - ("%s/server.js" % DEPLOY_PROJECT_PATH, "deploy server.js"), - ] - - for path, desc in checks: - # 检查文件或目录是否存在 - cmd = "test -e '%s' && echo 'EXISTS' || echo 'NOT_FOUND'" % path - stdin, stdout, stderr = client.exec_command(cmd, timeout=10) - result = stdout.read().decode("utf-8", errors="replace").strip() - status = "[OK]" if "EXISTS" in result else "[X]" - print("%s %s" % (status, desc)) - print(" 路径: %s" % path) - - if "EXISTS" in result and "static" in path: - # 列出文件数量 - cmd2 = "find '%s' -type f 2>/dev/null | wc -l" % path - stdin2, stdout2, stderr2 = client.exec_command(cmd2, timeout=10) - file_count = stdout2.read().decode("utf-8", errors="replace").strip() - print(" 文件数: %s" % file_count) - - print("\n=== 检查 PM2 项目配置 ===") - cmd = "pm2 describe soul 2>/dev/null | grep -E 'cwd|script|status' | head -5 || echo 'PM2 soul 不存在'" - stdin, stdout, stderr = client.exec_command(cmd, timeout=10) - pm2_info = stdout.read().decode("utf-8", errors="replace").strip() - print(pm2_info) - - print("\n=== 检查端口监听 ===") - cmd = "ss -tlnp | grep 30006 || echo '端口 30006 未监听'" - stdin, stdout, stderr = client.exec_command(cmd, timeout=10) - port_info = stdout.read().decode("utf-8", errors="replace").strip() - print(port_info) - - print("\n=== 检查 Nginx 反向代理 ===") - cmd = "grep -r 'proxy_pass' /www/server/panel/vhost/nginx/*soul* 2>/dev/null | head -3 || echo '未找到 soul Nginx 配置'" - stdin, stdout, stderr = client.exec_command(cmd, timeout=10) - nginx_info = stdout.read().decode("utf-8", errors="replace").strip() - print(nginx_info) - - print("\n" + "=" * 50) - print("诊断建议:") - print("1. devlop 模式部署后,PM2 的 cwd 应为: %s" % DEVLOP_DIST_PATH) - print("2. .next/static 必须在 PM2 的 cwd 目录下") - print("3. Nginx 必须整站反代(location /),不能只反代 /api") - print("4. 浏览器强刷: Ctrl+Shift+R 清除缓存") - - except Exception as e: - print("错误: %s" % str(e)) - import traceback - traceback.print_exc() - finally: - client.close() - -if __name__ == "__main__": - check_static_files() diff --git a/scripts/devlop.py b/scripts/devlop.py index bfc7999f..b4ca59f1 100644 --- a/scripts/devlop.py +++ b/scripts/devlop.py @@ -34,9 +34,9 @@ except ImportError: # ==================== 配置 ==================== -# 端口统一从环境变量 DEPLOY_PORT 读取,未设置时使用此默认值 +# 端口统一从环境变量 DEPLOY_PORT 读取,未设置时使用此默认值(需与 Nginx proxy_pass、ecosystem.config.cjs 一致) DEPLOY_PM2_APP = "soul" -DEFAULT_DEPLOY_PORT = 3888 +DEFAULT_DEPLOY_PORT = 30006 DEPLOY_PROJECT_PATH = "/www/wwwroot/soul" DEPLOY_SITE_URL = "https://soul.quwanzhi.com" # SSH 端口(支持环境变量 DEPLOY_SSH_PORT,未设置时默认为 22022) diff --git a/scripts/fix_port_issue.py b/scripts/fix_port_issue.py deleted file mode 100644 index 46ef777f..00000000 --- a/scripts/fix_port_issue.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -import paramiko -import time - -client = paramiko.SSHClient() -client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) -client.connect('42.194.232.22', port=22022, username='root', password='Zhiqun1984', timeout=15) - -print("=== 1. 检查端口占用 ===") -cmd = "ss -tlnp | grep ':300' | head -10" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -print(result if result else "无 300x 端口监听") - -print("\n=== 2. 检查 server.js 中的端口配置 ===") -cmd = "grep -n 'PORT\\|port\\|3006\\|30006' /www/wwwroot/soul/server.js | head -10" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -print(result) - -print("\n=== 3. 检查环境变量配置 ===") -cmd = "cat /www/wwwroot/soul/.env 2>/dev/null | grep -i port || echo '无 .env 文件'" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -print(result) - -print("\n=== 4. 停止 PM2 soul ===") -cmd = "pm2 stop soul 2>&1" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -result = result.encode('ascii', errors='replace').decode('ascii') -print(result) - -time.sleep(2) - -print("\n=== 5. 杀死占用 3006 端口的进程 ===") -cmd = "lsof -ti:3006 | xargs kill -9 2>/dev/null || echo '无进程占用 3006'" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -print(result) - -print("\n=== 6. 杀死占用 30006 端口的进程 ===") -cmd = "lsof -ti:30006 | xargs kill -9 2>/dev/null || echo '无进程占用 30006'" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -print(result) - -time.sleep(1) - -print("\n=== 7. 确认端口已释放 ===") -cmd = "ss -tlnp | grep ':300'" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -print(result if result else "[OK] 端口已全部释放") - -client.close() - -print("\n" + "=" * 60) -print("下一步:修复 server.js 的端口配置为 30006") diff --git a/scripts/restart_pm2.py b/scripts/restart_pm2.py deleted file mode 100644 index 5a3eb9d6..00000000 --- a/scripts/restart_pm2.py +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -import paramiko -import time - -client = paramiko.SSHClient() -client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) -client.connect('42.194.232.22', port=22022, username='root', password='Zhiqun1984', timeout=15) - -print("=== PM2 restart soul ===") -stdin, stdout, stderr = client.exec_command('pm2 restart soul 2>&1', timeout=30) -result = stdout.read().decode('utf-8', errors='replace') -# 移除可能导致编码问题的特殊字符 -result = result.encode('ascii', errors='replace').decode('ascii') -print(result) - -print("\n=== 等待 3 秒 ===") -time.sleep(3) - -print("=== PM2 status ===") -stdin, stdout, stderr = client.exec_command('pm2 status soul 2>&1', timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -result = result.encode('ascii', errors='replace').decode('ascii') -print(result) - -client.close() - -print("\n" + "=" * 50) -print("请在浏览器按 Ctrl+Shift+R 强制刷新页面!") diff --git a/scripts/restart_soul_correctly.py b/scripts/restart_soul_correctly.py deleted file mode 100644 index 83bb68bc..00000000 --- a/scripts/restart_soul_correctly.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -import paramiko -import time - -client = paramiko.SSHClient() -client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) -client.connect('42.194.232.22', port=22022, username='root', password='Zhiqun1984', timeout=15) - -print("=== 1. 杀死所有相关进程 ===") -cmd = "kill -9 1822 2>/dev/null || echo 'Process 1822 already killed'" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -print(result) - -time.sleep(1) - -print("\n=== 2. 确认端口清理完成 ===") -cmd = "ss -tlnp | grep ':300' || echo '[OK] All ports cleared'" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -print(result) - -print("\n=== 3. 删除 PM2 soul 配置 ===") -cmd = "pm2 delete soul 2>&1" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -result = result.encode('ascii', errors='replace').decode('ascii') -print(result) - -time.sleep(1) - -print("\n=== 4. 使用正确配置重新启动 ===") -cmd = """cd /www/wwwroot/soul && PORT=30006 pm2 start server.js --name soul --update-env 2>&1""" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -result = result.encode('ascii', errors='replace').decode('ascii') -print(result) - -time.sleep(3) - -print("\n=== 5. 检查 PM2 状态 ===") -cmd = "pm2 status soul 2>&1" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -result = result.encode('ascii', errors='replace').decode('ascii') -print(result) - -print("\n=== 6. 确认端口 30006 监听 ===") -cmd = "ss -tlnp | grep ':30006'" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -print(result if result else "[X] Port 30006 not listening!") - -print("\n=== 7. 测试 HTTP 响应 ===") -cmd = "curl -I http://127.0.0.1:30006 2>&1 | head -5" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -print(result) - -print("\n=== 8. 查看最新日志 ===") -cmd = "pm2 logs soul --lines 10 --nostream 2>&1 | tail -15" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -result = result.encode('ascii', errors='replace').decode('ascii') -print(result) - -print("\n=== 9. 保存 PM2 配置 ===") -cmd = "pm2 save 2>&1" -stdin, stdout, stderr = client.exec_command(cmd, timeout=10) -result = stdout.read().decode('utf-8', errors='replace') -result = result.encode('ascii', errors='replace').decode('ascii') -print(result) - -client.close() - -print("\n" + "=" * 60) -print("完成!请在浏览器访问: https://soul.quwanzhi.com") -print("如果仍是空白,按 Ctrl+Shift+R 强制刷新") diff --git a/scripts/sync_order_status.py b/scripts/sync_order_status.py deleted file mode 100644 index ee807e6e..00000000 --- a/scripts/sync_order_status.py +++ /dev/null @@ -1,240 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -订单状态同步任务(兜底机制) - -功能: -1. 定时查询 'created' 状态的订单 -2. 调用微信支付接口查询真实状态 -3. 同步订单状态(paid / expired) -4. 更新用户购买记录 - -运行方式: - - 手动: python scripts/sync_order_status.py - - 定时: crontab -e 添加 "*/5 * * * * python /path/to/sync_order_status.py" - - Node.js: 使用 node-cron 定时调用 -""" - -import sys -import os -import json -import time -import hashlib -import random -import string -from datetime import datetime, timedelta - -try: - import pymysql - import requests -except ImportError: - print("[ERROR] 缺少依赖库,请安装:") - print(" pip install pymysql requests") - sys.exit(1) - -# 数据库配置 -DB = { - "host": "56b4c23f6853c.gz.cdb.myqcloud.com", - "port": 14413, - "user": "cdb_outerroot", - "password": "Zhiqun1984", - "database": "soul_miniprogram", - "charset": "utf8mb4", - "cursorclass": pymysql.cursors.DictCursor, - "connect_timeout": 15, -} - -# 微信支付配置(从环境变量或配置文件读取) -WECHAT_PAY_CONFIG = { - "appid": os.environ.get("WECHAT_APPID", "wxb8bbb2b10dec74aa"), - "mch_id": os.environ.get("WECHAT_MCH_ID", "1318592501"), - "api_key": os.environ.get("WECHAT_API_KEY", "YOUR_API_KEY_HERE"), # 需要配置真实的 API Key -} - -# 订单超时时间(分钟) -ORDER_TIMEOUT_MINUTES = 30 - -def log(message, level="INFO"): - """统一日志输出""" - timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") - print(f"[{timestamp}] [{level}] {message}") - -def generate_nonce_str(length=32): - """生成随机字符串""" - return ''.join(random.choices(string.ascii_letters + string.digits, k=length)) - -def create_sign(params, api_key): - """生成微信支付签名""" - # 1. 参数排序 - sorted_params = sorted(params.items()) - - # 2. 拼接字符串 - string_a = '&'.join([f"{k}={v}" for k, v in sorted_params if v]) - string_sign_temp = f"{string_a}&key={api_key}" - - # 3. MD5 加密并转大写 - sign = hashlib.md5(string_sign_temp.encode('utf-8')).hexdigest().upper() - - return sign - -def query_wechat_order_status(out_trade_no): - """ - 查询微信支付订单状态 - 文档: https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_2 - """ - url = "https://api.mch.weixin.qq.com/pay/orderquery" - - params = { - "appid": WECHAT_PAY_CONFIG["appid"], - "mch_id": WECHAT_PAY_CONFIG["mch_id"], - "out_trade_no": out_trade_no, - "nonce_str": generate_nonce_str(), - } - - # 生成签名 - params["sign"] = create_sign(params, WECHAT_PAY_CONFIG["api_key"]) - - # 构建 XML 请求体 - xml_data = "" - for key, value in params.items(): - xml_data += f"<{key}>{value}" - xml_data += "" - - try: - response = requests.post(url, data=xml_data.encode('utf-8'), headers={'Content-Type': 'application/xml'}, timeout=10) - - # 解析 XML 响应(简单处理,生产环境建议用 xml.etree.ElementTree) - resp_text = response.text - - # 提取关键字段 - if '' in resp_text: - if '' in resp_text: - return 'SUCCESS' - elif '' in resp_text: - return 'NOTPAY' - elif '' in resp_text: - return 'CLOSED' - elif '' in resp_text: - return 'REFUND' - else: - return 'UNKNOWN' - else: - log(f"查询订单失败: {resp_text}", "WARN") - return 'ERROR' - - except Exception as e: - log(f"查询微信订单异常: {e}", "ERROR") - return 'ERROR' - -def sync_order_status(): - """同步订单状态(主函数)""" - log("========== 订单状态同步任务开始 ==========") - - conn = pymysql.connect(**DB) - cursor = conn.cursor() - - try: - # 1. 查询所有 'created' 状态的订单(最近 2 小时内创建的) - two_hours_ago = datetime.now() - timedelta(hours=2) - - cursor.execute(""" - SELECT id, order_sn, user_id, product_type, product_id, amount, created_at - FROM orders - WHERE status = 'created' AND created_at >= %s - ORDER BY created_at DESC - """, (two_hours_ago,)) - - pending_orders = cursor.fetchall() - - if not pending_orders: - log("没有需要同步的订单") - return - - log(f"找到 {len(pending_orders)} 个待同步订单") - - synced_count = 0 - expired_count = 0 - - for order in pending_orders: - order_sn = order['order_sn'] - created_at = order['created_at'] - - # 2. 判断订单是否超时(超过 30 分钟) - time_diff = datetime.now() - created_at - - if time_diff > timedelta(minutes=ORDER_TIMEOUT_MINUTES): - # 超时订单:标记为 expired - log(f"订单 {order_sn} 超时 ({time_diff.seconds // 60} 分钟),标记为 expired") - - cursor.execute(""" - UPDATE orders - SET status = 'expired', updated_at = NOW() - WHERE order_sn = %s - """, (order_sn,)) - - expired_count += 1 - continue - - # 3. 查询微信支付状态(跳过,因为需要真实 API Key) - # 生产环境中取消下面的注释 - """ - log(f"查询订单 {order_sn} 的微信支付状态...") - - wechat_status = query_wechat_order_status(order_sn) - - if wechat_status == 'SUCCESS': - # 微信支付成功,更新本地订单为 paid - log(f"订单 {order_sn} 微信支付成功,更新为 paid") - - cursor.execute(''' - UPDATE orders - SET status = 'paid', updated_at = NOW() - WHERE order_sn = %s - ''', (order_sn,)) - - # 更新用户购买记录 - if order['product_type'] == 'fullbook': - cursor.execute(''' - UPDATE users - SET has_full_book = 1 - WHERE id = %s - ''', (order['user_id'],)) - - synced_count += 1 - - elif wechat_status == 'NOTPAY': - log(f"订单 {order_sn} 尚未支付,保持 created 状态") - - elif wechat_status == 'CLOSED': - log(f"订单 {order_sn} 已关闭,标记为 cancelled") - - cursor.execute(''' - UPDATE orders - SET status = 'cancelled', updated_at = NOW() - WHERE order_sn = %s - ''', (order_sn,)) - - else: - log(f"订单 {order_sn} 查询失败或状态未知: {wechat_status}", "WARN") - """ - - # 测试环境:模拟查询(跳过微信接口) - log(f"[TEST] 订单 {order_sn} 跳过微信查询(需配置 API Key)") - - conn.commit() - - log(f"同步完成: 同步 {synced_count} 个,超时 {expired_count} 个") - - except Exception as e: - conn.rollback() - log(f"同步失败: {e}", "ERROR") - import traceback - traceback.print_exc() - - finally: - cursor.close() - conn.close() - log("========== 订单状态同步任务结束 ==========\n") - -if __name__ == "__main__": - sync_order_status() diff --git a/开发文档/8、部署/soul域名访问问题排查.md b/开发文档/8、部署/soul域名访问问题排查.md new file mode 100644 index 00000000..dfc8694a --- /dev/null +++ b/开发文档/8、部署/soul域名访问问题排查.md @@ -0,0 +1,160 @@ +# soul.quwanzhi.com 更新后仍显示旧站/报错 — 原因分析与排查 + +> 现象:宝塔里站点源码已更新,但访问 https://soul.quwanzhi.com 仍显示旧站点或「哎呀, 出错了」;要求域名在 Node 界面访问且后台不出错。 + +--- + +## 一、可能原因概览 + +| 原因 | 说明 | 优先级 | +|------|------|--------| +| **1. 端口不一致** | 部署脚本或 PM2 使用端口 3888,Nginx 反代 30006 → 请求到不了 Node | 高 | +| **2. 未重启 Node** | 代码已更新到服务器,但 PM2 未重启,进程仍在跑旧代码 | 高 | +| **3. 运行目录与更新目录不一致** | 默认 `devlop` 模式跑的是 `auto-devlop/soul/dist`,你改的是 `/www/wwwroot/soul` | 高 | +| **4. Nginx 未反代整站** | 只反代了 `/api`,`/_next/static` 等未到 Node → 静态 404 → 页面报错 | 中 | +| **5. PM2 工作目录错误** | 项目路径填成 `.next/standalone` 或错误目录,缺少 `.next/static` → 404/报错 | 中 | +| **6. 浏览器/CDN/Nginx 缓存** | 旧 HTML 引用已不存在的 chunk,或 CDN 缓存旧页面 | 中 | + +下面按「原因 → 如何确认 → 怎么修」说明。 + +--- + +## 二、原因 1:端口不一致(脚本曾用 3888) + +**说明**:`scripts/devlop.py` 此前默认端口为 **3888**,而 Nginx 与文档约定为 **30006**。若通过脚本创建/更新了宝塔 Node 项目,PM2 可能被配成 `PORT=3888`,应用只监听 3888;Nginx 把请求转到 30006,没有进程监听 → 502 或连接失败,页面上可能看到「出错了」或旧页。 + +**如何确认**(SSH 到服务器): + +```bash +# 应用应在 30006 监听 +ss -tlnp | grep 30006 + +# 若只有 3888 在监听,说明端口不一致 +ss -tlnp | grep 3888 +``` + +**修复**: + +- 本项目已把 `scripts/devlop.py` 的默认端口改为 **30006**,与 Nginx、`ecosystem.config.cjs` 一致。 +- 若你本机已改过环境变量,部署时请统一使用 30006: + - Windows: `set DEPLOY_PORT=30006` + - 然后执行: `python scripts/devlop.py`(或 `--mode deploy`) +- 宝塔 PM2 里为 soul 项目添加环境变量:`PORT=30006`,并重启。 + +--- + +## 三、原因 2:代码更新后未重启 Node + +**说明**:Node 进程会把代码加载进内存。只更新服务器上的文件而不重启 PM2,运行的仍是旧版本,所以你会看到「旧站」或旧逻辑触发的错误。 + +**如何确认**:看文件修改时间 vs 进程启动时间(例如 `pm2 list`、`pm2 describe soul`)。 + +**修复**: + +- 每次更新代码后必须重启 Node: + - 宝塔:PM2 管理器 → 找到 soul → 重启; + - 或 SSH:`pm2 restart soul` +- 使用部署脚本时不要加 `--no-api`,这样上传后会自动调宝塔 API 重启。 + +--- + +## 四、原因 3:运行目录与更新目录不一致(devlop vs deploy) + +**说明**:`python scripts/devlop.py` **默认是 devlop 模式**,部署目标是: + +- 上传到:`/www/wwwroot/auto-devlop/soul/dist2` +- 切换后实际运行目录:`/www/wwwroot/auto-devlop/soul/dist` +- PM2 的「项目路径」应为上述 **dist**,而不是 `/www/wwwroot/soul`。 + +如果你在宝塔文件管理里看到并更新的是 **`/www/wwwroot/soul`**,而线上跑的是 **auto-devlop/soul/dist**,那么你改的目录根本不在跑,所以「源码更新了但访问还是旧站」。 + +**如何确认**: + +- 宝塔 PM2 管理器:看 soul 项目的「项目路径」是 `.../soul` 还是 `.../auto-devlop/soul/dist`。 +- SSH:`pm2 describe soul` 看 `cwd`。 + +**修复(二选一)**: + +- **要用 devlop 模式(dist 切换)**:以后只通过 `python scripts/devlop.py` 部署,不要手动改 `/www/wwwroot/soul`;确认 PM2 项目路径为 `.../auto-devlop/soul/dist`,端口 30006。 +- **要直接更新 /www/wwwroot/soul**:用 **deploy 模式** 部署到该目录,并让 PM2 从该目录启动: + ```bash + python scripts/devlop.py --mode deploy + ``` + 并确认宝塔里 soul 的项目路径为 `/www/wwwroot/soul`,环境变量 `PORT=30006`。 + +--- + +## 五、原因 4:Nginx 未把整站反代到 Node + +**说明**:Next 的前台、后台、`/_next/static/*` 都由同一 Node 服务提供。若 Nginx 只配置了 `location /api` 反代到 30006,而 `location /` 指向静态目录或别的后端,则 HTML 可能来自旧静态或错误源,`/_next/static/...` 请求不到 Node → 404,页面报错「出错了」。 + +**如何确认**:看 Nginx 配置里是否有 `location /` 反代到 `http://127.0.0.1:30006`。 + +**修复**:保证整站走 Node,例如: + +```nginx +location / { + proxy_pass http://127.0.0.1:30006; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_cache_bypass $http_upgrade; +} +``` + +然后重载 Nginx。 + +--- + +## 六、原因 5:PM2 工作目录错误 + +**说明**:standalone 下 `server.js` 从**当前工作目录**读 `.next/static`、`public`。若 PM2 的「项目路径」填成 `.next/standalone` 或其它错误目录,会找不到静态资源 → 404 或运行时报错,页面上可能显示「出错了」。 + +**修复**:宝塔 PM2 里 soul 的项目路径必须是「解压后包含 `server.js`、`.next/static`、`public` 的那一层」: + +- deploy 模式:`/www/wwwroot/soul` +- devlop 模式:`/www/wwwroot/auto-devlop/soul/dist` + +不要填成 `.../soul/.next/standalone`。 + +--- + +## 七、原因 6:缓存(浏览器 / CDN / Nginx) + +**说明**:构建后 chunk 文件名会变,若浏览器或 CDN 仍用旧 HTML(引用旧 chunk),会 404 或报错。 + +**修复**: + +- 浏览器:强刷 `Ctrl+Shift+R` / `Cmd+Shift+R`,或开发者工具 Network 勾选 Disable cache 再刷新。 +- 若用了 Nginx 的 `proxy_cache` 或 CDN:对 soul 站点 purge 缓存或暂时关缓存再试。 + +--- + +## 八、推荐自检顺序(保证域名走 Node 且后台不出错) + +1. **端口**:服务器上 `ss -tlnp | grep 30006` 应有 Node 在监听;宝塔 soul 项目环境变量 `PORT=30006`。 +2. **运行目录**:PM2 的 soul 项目路径 = 你实际更新并希望生效的目录(deploy 用 `/www/wwwroot/soul`,devlop 用 `.../auto-devlop/soul/dist`)。 +3. **重启**:每次改代码或重新部署后执行一次 `pm2 restart soul`(或宝塔里重启)。 +4. **Nginx**:`location /` 反代到 `http://127.0.0.1:30006`,重载 Nginx。 +5. **静态资源**:`ls /www/wwwroot/soul/.next/static/chunks`(或当前运行目录下的 `.next/static`)应有文件;若 404 先看 [管理端静态资源404排查.md](./管理端静态资源404排查.md)。 +6. **缓存**:强刷、必要时清 CDN/Nginx 缓存。 + +使用项目提供的检查脚本(需能 SSH): + +```bash +python scripts/check_static_files.py +python scripts/check_nginx.py +``` + +--- + +## 九、总结 + +- **「源码更新了但访问还是旧站/报错」** 最常见三种情况:**端口不一致**(Node 听 3888、Nginx 转 30006)、**更新了错误目录**(改的是 soul 目录但跑的是 auto-devlop/soul/dist)、**未重启 Node**。 +- 保证 **soul.quwanzhi.com 在 Node 界面访问且后台不出错**:端口 30006、Nginx 整站反代到 30006、PM2 工作目录正确且每次发布后重启、无静态 404(正确部署 `.next/static`)。 + +脚本默认端口已改为 30006;若你之前用默认 3888 部署过,请在宝塔里把 soul 的 `PORT` 改为 30006 并重启,再按上面顺序自检一遍。 diff --git a/转换提示词.md b/转换提示词.md deleted file mode 100644 index cdf64c2a..00000000 --- a/转换提示词.md +++ /dev/null @@ -1,345 +0,0 @@ -# 微信小程序功能同步提示词 - -> **执行状态**: ✅ 所有任务已完成 (2026-02-04) -> **完成报告**: 详见 `miniprogram/功能同步完成报告.md` -> **样式检查**: 详见 `miniprogram/样式检查清单.md` - -> **重要约束**:2026-02-04 起,所有 C 端新功能只在小程序开发,Next.js `app/view/` 冻结维护。 -> 详见 `开发文档/0、Mycontent-book 项目总览.md` 第5节。 - ---- - -## 📊 执行总结 - -**任务完成率**: 10/10 (100%) -**新增文件**: 10个 -**修改文件**: 5个 -**代码质量**: ✅ 符合规范 -**样式一致性**: ✅ 1:1 复刻 - -## 一、功能对比分析报告 - -### 1. 开发策略说明 - -| 端 | 状态 | 说明 | -|---|------|-----| -| **微信小程序** | ✅ 活跃开发 | 所有 C 端新功能在此开发 | -| **Next.js C端** | 🔒 冻结 | `app/view/` 不再新增功能,仅作参考 | -| **Next.js 管理端** | ✅ 活跃 | `app/admin/` 继续开发 | - -### 2. 登录体系差异(不需要同步) - -| 端 | 登录方式 | 处理方式 | -|---|---------|---------| -| 小程序 | 微信一键登录 / 手机号快速授权 | **保持现状**,不复刻 Next.js 登录页 | -| Next.js | 手机号 + 密码 | 保持现状 | -| 账号统一 | 以手机号为唯一标识 | 后端处理,两端数据互通 | - -### 3. 需要同步的功能(参考 Next.js 样式和交互) - -| 页面/功能 | Next.js 参考路径 | 小程序状态 | 同步优先级 | -|---------|------|---------|-----------| -| 目录 | `/view/chapters/page.tsx` | ⚠️ 缺少搜索按钮 | P1 | -| 我的 | `/view/my/page.tsx` | ⚠️ 缺少收益卡片艺术化设计 | P1 | -| 推广中心 | `/view/my/referral/page.tsx` | ⚠️ 功能不完整 | P1 | -| 设置 | `/view/my/settings/page.tsx` | ⚠️ 缺少收货地址入口 | P2 | -| 地址管理 | `/view/my/addresses/` | ❌ 缺少整个模块 | P2 | -| 首页 | `/view/page.tsx` | ✅ 基本完整 | P3 样式微调 | -| 匹配 | `/view/match/page.tsx` | ✅ 基本完整 | P3 动画优化 | - -### 4. 不需要同步的功能 - -| 功能 | 原因 | -|-----|------| -| 登录页 (`pages/login/login`) | 小程序使用微信一键登录,体验更好 | -| 忘记密码页 (`pages/forgot/forgot`) | 小程序无密码登录,不需要 | -| docs/documentation 页面 | Web 专属文档页,小程序不需要 | - -### 5. 待完善的组件 - -- [ ] SearchModal - 搜索弹窗组件 -- [ ] PosterModal - 海报生成弹窗优化 -- [ ] WithdrawalModal - 提现弹窗 -- [ ] AutoWithdrawModal - 自动提现设置弹窗 - ---- - -## 二、功能同步转换提示词 - -### 使用说明 -将以下提示词复制给AI助手,逐步执行功能同步任务。 - ---- - -### 【提示词正文】 - -``` -你是一个资深的微信小程序开发专家,现在需要将 Next.js 项目的功能完整同步到微信小程序。 - -## 项目背景 -- Next.js 源码位置: `@Mycontent/app/view/` -- 小程序源码位置: `@Mycontent/miniprogram/` -- 技术栈: Next.js 14 + TypeScript → 微信小程序原生开发 -- 设计要求: **1:1 完全复刻**,样式、交互、功能不能有任何丢失 - -## 核心原则 - -### 1. 样式转换规则 -- Tailwind CSS → WXSS (需要逐一转换每个类名) -- `className="text-white"` → `color: #ffffff;` -- `className="bg-black"` → `background-color: #000000;` -- `className="rounded-2xl"` → `border-radius: 32rpx;` -- `className="px-4 py-3"` → `padding: 24rpx 32rpx;` -- `px` 单位转 `rpx` (1px = 2rpx) -- 渐变色、阴影、backdrop-blur 需要完整保留 -- CSS变量 `var(--app-brand)` 等需要在 app.wxss 定义 - -### 2. 组件转换规则 -- React组件 → 小程序Page或Component -- `useState` → `this.data` + `this.setData()` -- `useEffect` → `onLoad` / `onShow` / `onReady` -- `useRouter` → `wx.navigateTo` / `wx.switchTab` / `wx.redirectTo` -- `onClick` → `bindtap` -- `onChange` → `bindinput` / `bindchange` -- `framer-motion` 动画 → `wx.createAnimation()` 或 CSS animation - -### 3. 图标转换规则 -- lucide-react 图标 → 使用相同名称的 iconfont 或 SVG -- 保持图标大小、颜色完全一致 -- 可以使用小程序 image 组件 + base64 SVG - -### 4. API 调用规则 -- `fetch` → `wx.request` 或 封装的 `app.request` -- 保持接口路径一致 -- 错误处理逻辑一致 - -## 执行任务清单 - -> **执行状态**: ✅ 所有任务已完成 (2026-02-04) -> **完成报告**: 详见 `miniprogram/功能同步完成报告.md` - -### 第一阶段:完善现有页面功能(P1 优先级) - -#### ✅ 任务1: 完善目录页 -对比 `@Mycontent/app/view/chapters/page.tsx` 和 `@Mycontent/miniprogram/pages/chapters/` -- 添加右上角搜索按钮(点击跳转搜索页或弹出搜索组件) -- 样式细节对齐(卡片圆角、间距、颜色) - -> 注:版本标签切换(基础版/最新版)可选,根据业务需要决定是否添加 - -#### ✅ 任务2: 完善我的页面 -对比 `@Mycontent/app/view/my/page.tsx` 和 `@Mycontent/miniprogram/pages/my/` -- 收益卡片艺术化设计(渐变背景、装饰元素、毛玻璃效果) -- 设置按钮入口 - -#### ✅ 任务3: 完善推广中心 -对比 `@Mycontent/app/view/my/referral/page.tsx` 和 `@Mycontent/miniprogram/pages/referral/` -需要添加: -- 过期提醒横幅(有即将过期用户时显示) -- 绑定用户列表 Tab切换 (绑定中/已付款/已过期) -- 用户列表展示(头像、昵称、绑定时间、状态标签) -- 分销规则说明卡片 -- 分享按钮组(海报/朋友圈/更多分享方式) -- 收益明细列表 - -### 第二阶段:新建缺失页面(P2 优先级) - -#### ✅ 任务4: 完善设置页 -对比 `@Mycontent/app/view/my/settings/page.tsx` 和 `@Mycontent/miniprogram/pages/settings/` -- 添加收货地址管理入口 -- 绑定状态图标(已绑定显示勾选) -- 账号绑定卡片样式优化 - -#### ✅ 任务5: 创建地址管理模块 -读取 `@Mycontent/app/view/my/addresses/` 目录下所有文件,创建: -- `miniprogram/pages/addresses/addresses.js/wxml/wxss/json` (地址列表) -- `miniprogram/pages/addresses/edit.js/wxml/wxss/json` (编辑地址) - -要求: -- 地址卡片样式参考 Next.js -- 编辑、删除按钮交互一致 -- 使用小程序原生省市区选择器 - -### 第三阶段:组件优化(P3 优先级) - -#### ✅ 任务6: 优化搜索功能 -参考 `@Mycontent/components/search-modal.tsx` -- 可以使用独立搜索页 `pages/search/search`(已有) -- 或创建 `miniprogram/components/search-modal/` 弹窗组件 - -#### ✅ 任务7: 优化海报生成功能 -参考 `@Mycontent/components/modules/referral/poster-modal.tsx` -优化现有 `pages/read/read.js` 中的海报生成功能 -- 样式更精美 -- 支持保存到相册 - -#### ✅ 任务8: 创建提现弹窗组件 -参考 `@Mycontent/components/modules/referral/withdrawal-modal.tsx` -在推广中心页面添加提现功能弹窗 - -### 第四阶段:样式统一 - -#### ✅ 任务9: 统一全局样式变量 -在 `miniprogram/app.wxss` 添加: -```css -page { - --app-brand: #00CED1; - --app-brand-light: rgba(0, 206, 209, 0.1); - --app-bg-primary: #000000; - --app-bg-secondary: #1c1c1e; - --app-bg-tertiary: #2c2c2e; - --app-text-primary: #ffffff; - --app-text-secondary: rgba(255, 255, 255, 0.7); - --app-text-tertiary: rgba(255, 255, 255, 0.4); - --app-separator: rgba(255, 255, 255, 0.05); - --ios-indigo: #5856D6; - --ios-green: #30d158; -} -``` - -#### ✅ 任务10: 逐页样式核对 -每个页面对比 Next.js 和小程序的样式: -- 字体大小 (font-size) -- 颜色值 (color, background) -- 间距 (padding, margin) -- 圆角 (border-radius) -- 阴影 (box-shadow) -- 渐变 (linear-gradient) - -## ✅ 检查清单(已完成) - -完成所有任务后的检查结果: - -### 功能检查 -- [x] 目录页搜索入口可用 ✅ -- [x] 我的页收益卡片显示正常 ✅ -- [x] 推广中心绑定用户列表可用(3种状态Tab)✅ -- [x] 设置页收货地址入口可用 ✅ -- [x] 地址管理增删改查可用 ✅ -- [x] 所有弹窗组件正常显示和关闭 ✅ -- [x] 微信一键登录流程正常 ✅ - -### 样式检查 -- [x] 所有页面背景色一致 (黑色 #000000) ✅ -- [x] 品牌色一致 (#00CED1 青绿色) ✅ -- [x] 卡片样式一致 (圆角、背景、边框) ✅ -- [x] 按钮样式一致 (圆角、颜色、大小) ✅ -- [x] 图标大小和颜色一致 ✅ -- [x] 字体大小层级一致 ✅ - -### 交互检查 -- [x] 点击反馈一致 (active状态) ✅ -- [x] 加载状态一致 (loading动画) ✅ -- [x] 错误提示一致 (toast/modal) ✅ -- [x] 页面切换动画流畅 ✅ - -**检查结论**: ✅ 所有检查项通过,详见 `miniprogram/样式检查清单.md` - -## 注意事项 - -1. **小程序优先原则** - 所有 C 端新功能只在小程序开发 -2. **保持登录体验** - 不要把 Next.js 的手机号密码登录复刻到小程序,保持微信一键登录 -3. **样式参考不照搬** - Next.js 样式作为参考,但要适配小程序特性 -4. **API路径保持一致** - 方便统一后端接口 -5. **测试每个功能** - 完成后逐一测试确保可用 - -## 执行顺序 - -按照优先级和任务编号顺序执行: -1. **P1 任务 (1-3)**: 完善现有页面核心功能 -2. **P2 任务 (4-5)**: 新建缺失页面 -3. **P3 任务 (6-8)**: 组件优化 -4. **P4 任务 (9-10)**: 样式统一 - -每完成一个任务,立即测试验证,然后继续下一个。 - -现在开始执行任务1:完善目录页。 -``` - ---- - -## 三、样式对照表 - -### 常用 Tailwind → WXSS 转换 - -| Tailwind | WXSS | -|----------|------| -| `text-white` | `color: #ffffff;` | -| `text-gray-500` | `color: rgba(255,255,255,0.5);` | -| `text-[#00CED1]` | `color: #00CED1;` | -| `bg-black` | `background-color: #000000;` | -| `bg-[#1c1c1e]` | `background-color: #1c1c1e;` | -| `rounded-xl` | `border-radius: 24rpx;` | -| `rounded-2xl` | `border-radius: 32rpx;` | -| `rounded-full` | `border-radius: 50%;` | -| `px-4` | `padding-left: 32rpx; padding-right: 32rpx;` | -| `py-3` | `padding-top: 24rpx; padding-bottom: 24rpx;` | -| `gap-3` | `gap: 24rpx;` (需要flex) | -| `flex` | `display: flex;` | -| `flex-col` | `flex-direction: column;` | -| `items-center` | `align-items: center;` | -| `justify-between` | `justify-content: space-between;` | -| `border border-white/5` | `border: 1rpx solid rgba(255,255,255,0.05);` | -| `shadow-lg` | `box-shadow: 0 10rpx 15rpx -3rpx rgba(0,0,0,0.1);` | -| `backdrop-blur-xl` | `backdrop-filter: blur(24px);` | -| `transition-all` | `transition: all 0.3s ease;` | - -### 渐变色转换示例 - -```css -/* Tailwind */ -bg-gradient-to-br from-[#00CED1] to-[#20B2AA] - -/* WXSS */ -background: linear-gradient(135deg, #00CED1 0%, #20B2AA 100%); -``` - ---- - -## 四、app.json 页面注册 - -完成新页面后,需要在 `app.json` 中注册: - -```json -{ - "pages": [ - "pages/index/index", - "pages/chapters/chapters", - "pages/match/match", - "pages/my/my", - "pages/read/read", - "pages/about/about", - "pages/purchases/purchases", - "pages/referral/referral", - "pages/settings/settings", - "pages/search/search", - "pages/addresses/addresses", - "pages/addresses/edit" - ] -} -``` - -> 注:不需要登录页(login)和忘记密码页(forgot),小程序使用微信一键登录。 - ---- - -## 五、执行建议 - -1. **遵循开发约束**: 所有 C 端新功能只在小程序开发,Next.js `app/view/` 已冻结 -2. **分阶段执行**: 按 P1→P2→P3→P4 优先级顺序执行 -3. **逐页对比**: 打开 Next.js 页面作为样式参考(但不照搬登录逻辑) -4. **实时测试**: 使用微信开发者工具实时预览效果 -5. **保持原生体验**: 小程序登录保持微信一键登录,不要改成手机号密码 - ---- - -## 六、相关文档 - -- 开发约束详情: `开发文档/0、Mycontent-book 项目总览.md` 第5节 -- 小程序部署: `开发文档/8、部署/` 目录下相关文档 -- API 接口: `开发文档/5、接口/API接口.md` - ---- - -*文档生成时间: 2026-02-04* -*文档更新: 移除登录页/忘记密码页任务,添加开发约束说明*