From 217b97b430ced6526b5dbf478a4739318d213218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Thu, 16 Jul 2026 23:24:25 +0800 Subject: [PATCH] =?UTF-8?q?=3D=3D=3D=3D=3D=3D=3D=20V3.0.1=20=E7=A8=B3?= =?UTF-8?q?=E5=AE=9A=E7=89=88=20=3D=3D=3D=3D=3D=3D=3D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 481 +++++++++++++++++++++++++---------------- login_recover.patch | 90 -------- overview.md | 41 ---- register_recover.patch | 71 ------ 4 files changed, 294 insertions(+), 389 deletions(-) delete mode 100644 login_recover.patch delete mode 100644 overview.md delete mode 100644 register_recover.patch diff --git a/README.md b/README.md index c1a4e7a..bece6de 100644 --- a/README.md +++ b/README.md @@ -1,151 +1,257 @@ -# Shop-Taro - 项目框架 +# 小程序商城 (shop-taro) -基于 Taro 4.0.8 + React 18.3.1 + TypeScript 5.7.2 的跨端开发框架 +> 基于 Taro + React + TypeScript 的微信小程序商城系统,支持多门店、VIP 会员、拼团秒杀、积分商城、分销裂变等完整电商业务场景。 -## 📦 技术栈 +**作者**: 科技小王子 +**版本**: 1.0.0 +**License**: MIT -### 核心框架 -- **Taro**: `4.0.8` - 跨端开发框架 -- **React**: `18.3.1` - UI 框架 -- **TypeScript**: `5.7.2` - 类型系统 +--- -### UI 组件库 -- **NutUI React Taro**: `2.7.4` - 京东风格的 Taro React 组件库 -- **NutUI Icons**: `^1.0.0` - 图标库 +## 技术栈 -### 样式方案 -- **Sass**: `^1.81.0` - CSS 预处理器 -- **TailwindCSS**: `3.4.17` - 原子化 CSS 框架 +| 分类 | 技术 | 版本 | 说明 | +|------|------|------|------| +| 跨端框架 | Taro | 4.1.11 | 支持微信/H5/支付宝等多端编译 | +| UI 框架 | React | 18.3.1 | 函数组件 + Hooks | +| 类型系统 | TypeScript | 5.7.2 | 严格模式 | +| 组件库 | NutUI React Taro | 2.7.4 | 京东风格组件库 | +| 原子化 CSS | TailwindCSS | 3.4.17 | 含 weapp-tailwindcss 适配 | +| CSS 预处理 | Sass | ^1.81.0 | | +| 日期处理 | Day.js | ^1.11.13 | | +| 加密 | Crypto-js | ^4.2.0 | AES / MD5 | +| 图表 | ECharts Taro3 React | ^1.0.13 | 数据可视化 | +| 二维码 | weapp-qrcode | ^1.0.0 | 小程序码生成 | -### 状态管理 -- **React Hooks** - 内置 Hooks -- **Context API** - 跨组件状态共享 +> **Node 版本要求**: >= 18 -### 工具库 -- **Day.js**: `^1.11.13` - 日期处理 -- **Crypto-js**: `^4.2.0` - 加密解密 -- **React Router DOM**: `^6.28.0` - 路由管理 +--- -## 🚀 快速开始 +## 核心业务功能 + +### 商城交易 +- 商品浏览 / 搜索 / 分类筛选 +- 商品详情 + 多规格 SKU 选择 +- 购物车(合并加购、批量操作) +- 下单结算(普通订单 / 拼团 / 秒杀) +- 订单管理(待付款 / 待发货 / 待收货 / 已完成) +- 售后退款申请与进度跟踪 +- 发票申请与抬头管理 + +### 会员体系 +- 手机号授权登录(微信一键 + 短信验证码降级) +- VIP 会员申请与审核(门店店员审核) +- VIP 专享价(dealerPrice) +- 会员权益包兑换 +- 积分系统(签到 / 积分商品兑换 / 积分明细) +- 用户余额(充值 / 消费 / 提现) + +### 分销与裂变 +- 邀请下级注册 +- 分销佣金记录 +- 分享海报(Canvas 绘制 + 小程序码) +- 朋友圈分享 / 复制链接 +- 邀请归因追踪 + +### 门店管理(店员端) +- 门店中心(订单 / 商品 / 用户管理) +- VIP 审核(通过 / 驳回) +- 订单修改金额与备注 +- 上传发货凭证 +- 门店会员管理(搜索 / 筛选 / 禁用启用) + +### 营销活动 +- 拼团(单独成团 / 参团) +- 秒杀(限时抢购) +- 优惠券(领取中心 / 下单核销) +- 赛事报名 +- 预约订单 +- 礼品卡(购买 / 兑换 / 余额查询) +- 文章资讯 / 公告通知 + +### 其他 +- 浏览历史记录(服务端去重累加) +- 商品收藏 +- 客服会话 +- 数据统计看板(销售 / 用户) +- 微信隐私协议授权弹窗 +- 订阅消息推送(新订单提醒) + +--- + +## 快速开始 ### 安装依赖 ```bash -# 使用 npm -npm install - -# 使用 yarn -yarn install - -# 使用 pnpm pnpm install ``` ### 开发模式 ```bash -# 微信小程序 -npm run dev:weapp +# 微信小程序(主要目标平台) +pnpm dev:weapp # H5 -npm run dev:h5 - -# 支付宝小程序 -npm run dev:alipay - -# 百度小程序 -npm run dev:swan - -# 字节跳动小程序 -npm run dev:tt - -# QQ 小程序 -npm run dev:qq +pnpm dev:h5 ``` ### 生产构建 ```bash -# 微信小程序 -npm run build:weapp - -# H5 -npm run build:h5 - -# 其他平台类似 -npm run build:[platform] +pnpm build:weapp +pnpm build:h5 ``` -## 📁 项目结构 +### 代码检查 + +```bash +# ESLint 修复 +pnpm lint + +# TypeScript 类型检查 +pnpm type-check +``` + +> 构建产物在 `dist/` 目录,使用微信开发者工具打开该目录进行预览和调试。 + +--- + +## 项目结构 ``` shop-taro/ -├── config/ # Taro 配置文件 -│ ├── index.ts # 主配置 -│ ├── dev.ts # 开发配置 -│ └── prod.ts # 生产配置 -├── src/ # 源代码 -│ ├── app.config.ts # 应用配置(页面路由、tabBar等) -│ ├── app.tsx # 应用入口 -│ ├── app.scss # 全局样式 -│ ├── pages/ # 页面目录 -│ │ ├── index/ # 首页 -│ │ │ ├── index.tsx -│ │ │ ├── index.scss -│ │ │ └── index.config.ts -│ │ └── home/ # 个人中心页 -│ │ ├── home.tsx -│ │ ├── home.scss -│ │ └── home.config.ts -│ ├── components/ # 自定义组件 -│ ├── contexts/ # Context API -│ │ └── AppContext.tsx # 应用上下文 -│ ├── hooks/ # 自定义 Hooks -│ │ └── useAppContext.ts -│ ├── utils/ # 工具函数 -│ │ └── index.ts # 常用工具(日期、加密、防抖节流等) -│ ├── types/ # TypeScript 类型定义 -│ │ └── global.d.ts # 全局类型声明 -│ ├── styles/ # 样式文件 -│ └── assets/ # 静态资源 -│ └── tabbar/ # tabBar 图标 -├── package.json # 项目依赖 -├── tsconfig.json # TypeScript 配置 -├── tailwind.config.js # TailwindCSS 配置 -├── postcss.config.js # PostCSS 配置 -├── project.config.json # 小程序项目配置 -└── README.md # 项目说明 +├── config/ # Taro 编译配置 +│ ├── index.ts # 主配置 +│ ├── dev.ts # 开发环境 +│ └── prod.ts # 生产环境 +├── src/ +│ ├── app.tsx # 应用入口 +│ ├── app.config.ts # 路由 / tabBar / 全局配置 +│ ├── app.scss # 全局样式 +│ ├── pages/ # 页面目录 +│ │ ├── index/ # 首页(tabBar) +│ │ ├── shop/ # 商城(分类/详情/购物车/结算/拼团/秒杀) +│ │ ├── user/ # 用户中心(tabBar) +│ │ ├── points/ # 积分商城 +│ │ ├── order/ # 订单管理 +│ │ ├── store/ # 门店管理(店员端) +│ │ ├── after-sale/ # 售后退款 +│ │ ├── activity/ # 营销活动 +│ │ ├── event/ # 赛事报名 +│ │ ├── booking/ # 预约订单 +│ │ ├── message/ # 消息通知 +│ │ ├── gift-card/ # 礼品卡 +│ │ ├── invoice/ # 发票 +│ │ ├── share/ # 分享返利 +│ │ ├── rebate/ # 返利记录 +│ │ └── statistics/ # 数据统计 +│ ├── passport/ # 登录/注册/短信登录/扫码登录 +│ ├── components/ # 公共组件 +│ │ ├── business/ # 业务组件 +│ │ ├── common/ # 通用组件 +│ │ ├── layout/ # 布局组件 +│ │ ├── NavBar/ # 导航栏 +│ │ ├── SharePoster/ # 分享海报 +│ │ ├── PrivacyModal/ # 隐私协议弹窗 +│ │ └── ErrorBoundary.tsx # 错误边界 +│ ├── contexts/ # 全局状态 Context +│ │ ├── AppContext.tsx # 应用上下文 +│ │ ├── UserContext.tsx # 用户信息 +│ │ └── CartContext.tsx # 购物车 +│ ├── hooks/ # 自定义 Hooks +│ │ ├── useUser.ts # 用户信息 +│ │ ├── useVipStatus.ts # VIP 状态(响应式) +│ │ ├── useShare.ts # 分享/朋友圈/复制链接 +│ │ ├── usePayment.ts # 支付 +│ │ ├── useAddress.ts # 收货地址 +│ │ ├── useNewOrderDetector.ts # 新订单轮询检测 +│ │ ├── useCountDown.ts # 倒计时 +│ │ ├── usePagination.ts # 分页 +│ │ ├── useRequest.ts # 请求封装 +│ │ └── ... +│ ├── api/ # 后端接口封装 +│ │ ├── shop/ # 商城业务接口(50+ 模块) +│ │ ├── system/ # 系统接口(文件上传等) +│ │ ├── passport/ # 认证接口 +│ │ ├── cms/ # 内容管理 +│ │ └── share.ts # 分享相关 +│ ├── utils/ # 工具函数 +│ │ ├── request.ts # 网络请求封装 +│ │ ├── auth.ts # 用户禁用拦截 +│ │ ├── vip.ts # VIP 状态判断 +│ │ ├── privacy.ts # 隐私授权管理 +│ │ ├── invite.ts # 邀请参数解析 +│ │ ├── server.ts # 服务器地址 +│ │ ├── image.ts # 图片处理 +│ │ ├── geofence.ts # 地理围栏 +│ │ └── common.ts # 通用工具 +│ ├── types/ # TypeScript 类型定义 +│ ├── styles/ # 全局样式 +│ └── assets/ # 静态资源(tabBar 图标等) +├── package.json +├── tsconfig.json +├── tailwind.config.js +├── postcss.config.js +├── project.config.json # 小程序项目配置 +└── README.md ``` -## ✨ 特性 +--- -### 1. 主题切换 -- 支持浅色/深色模式切换 -- 使用 Context API 管理主题状态 -- 暗黑模式适配 +## tabBar 配置 -### 2. NutUI 组件库 -- 已集成 @nutui/nutui-react-taro@2.7.4 -- 支持按需引入 -- 中文国际化配置 +| Tab | 页面路径 | 图标 | 说明 | +|-----|---------|------|------| +| 首页 | `pages/index/index` | home | 商城首页、Banner、快捷入口 | +| 分类 | `pages/shop/index` | category | 商品分类与列表 | +| 购物车 | `pages/shop/cart` | cart | 购物车管理 | +| 我的 | `pages/user/user` | user | 个人中心 | -### 3. TailwindCSS 集成 -- 支持原子化 CSS 编写 -- 暗黑模式支持(dark mode) -- 自定义主题色配置 +--- -### 4. 工具函数封装 -- **日期处理**: 基于 Day.js 的格式化 -- **加密解密**: MD5、AES 加密 -- **性能优化**: 防抖、节流函数 -- **数据操作**: 深拷贝等工具 +## 关键技术实现 -### 5. TypeScript 支持 -- 完整的类型定义 -- 路径别名配置 `@/*` -- 严格模式开启 +### VIP 会员价格体系 -## 🎨 代码示例 +商品价格字段约定: + +| 字段 | 含义 | +|------|------| +| `product.price` | 到手价(主价格) | +| `product.salePrice` | 市场价(划线价) | +| `product.dealerPrice` | VIP 会员专享价 | +| `product.memberStorePrice` | 会员价 | + +- 使用 `useVipStatus` Hook 实现响应式 VIP 状态更新 +- VIP 状态通过异步校验缓存,组件挂载时自动刷新 + +### 微信隐私协议(基础库 3.16.1+) + +- 调用 `chooseImage` / `getPhoneNumber` 等敏感 API 前预检授权 +- `app.tsx` 注册 `onNeedPrivacyAuthorization` 回调 +- `PrivacyModal` 组件展示授权弹窗 + +### 手机号登录降级方案 + +- 微信 `getPhoneNumber` 被拒绝后自动降级到短信验证码登录 +- 统一错误处理弹窗,引导跳转短信登录页 + +### 分享裂变 + +- `useShare` Hook 一次注册 `useShareAppMessage` + `useShareTimeline` +- 分享链接自动追加 `inviter` 参数做归因 +- `SharePoster` 组件用 Canvas 2D 绘制海报 + 小程序码 + +### 用户禁用机制 + +- `User.status` 字段:`0` 正常 / `1` 禁用 +- 多层级拦截:UserContext 启动校验 + 登录检查 + 页面入口检查 + +--- + +## 代码示例 ### 使用 NutUI 组件 @@ -156,9 +262,7 @@ export default function MyPage() { return ( - + ) } @@ -167,97 +271,100 @@ export default function MyPage() { ### 使用 TailwindCSS ```tsx - - - 暗黑模式适配文本 - + + 商品名称 ``` -### 使用 Context 管理状态 +### 使用 VIP 状态 Hook ```tsx -import { useAppContext } from '@/hooks/useAppContext' +import { useVipStatus } from '@/hooks/useVipStatus' -export default function MyPage() { - const { theme, toggleTheme } = useAppContext() - - return ( - - ) +export default function ProductCard({ product }) { + const { isVip } = useVipStatus() + + const displayPrice = isVip ? product.dealerPrice : product.price + + return ¥{displayPrice} } ``` -### 使用工具函数 +### 使用分享 Hook ```tsx -import { formatDate, md5, debounce } from '@/utils' +import { useShare } from '@/hooks/useShare' -// 日期格式化 -const dateStr = formatDate(new Date()) - -// MD5 加密 -const encrypted = md5('hello world') - -// 防抖 -const handleSearch = debounce((keyword) => { - console.log(keyword) -}, 500) +export default function ProductDetail({ product }) { + useShare({ + title: product.name, + path: '/pages/shop/product-detail', + query: { id: product.id }, + enableTimeline: true, + enableCopyUrl: true, + }) + // ... +} ``` -## 📝 开发规范 +### 网络请求 -### 文件命名 -- 页面目录: `kebab-case` (如 `user-profile/`) -- 组件文件: `PascalCase` (如 `UserProfile.tsx`) -- 工具文件: `camelCase` (如 `formatDate.ts`) +```tsx +import { getShopOrderList } from '@/api/shop/shopOrder' -### 代码风格 -- 使用 ESLint + @typescript-eslint 进行代码检查 -- 使用 2 空格缩进 -- 分号结尾 -- 单引号优先 - -### 提交规范 +const { data } = await getShopOrderList({ status: 'pending', page: 1 }) ``` -feat: 新功能 -fix: 修复 bug -docs: 文档更新 -style: 代码格式调整 -refactor: 重构 -test: 测试相关 -chore: 构建/工具配置 -``` - -## 🔧 常见问题 - -### 1. TailwindCSS 样式不生效? -检查 `postcss.config.js` 配置,确保已安装 `postcss-nested`。 - -### 2. NutUI 组件样式丢失? -确保在 `app.scss` 中引入了 NutUI 样式: -```scss -@import '@nutui/nutui-react-taro/dist/styles/vitamin.css'; -``` - -### 3. TypeScript 路径别名报错? -检查 `tsconfig.json` 的 `paths` 配置,并确保 IDE 正确识别。 - -## 📚 相关文档 - -- [Taro 官方文档](https://taro-docs.jd.com/) -- [React 官方文档](https://react.dev/) -- [NutUI React 文档](https://nutui.jd.com/react-taro/) -- [TailwindCSS 文档](https://tailwindcss.com/docs) -- [TypeScript 文档](https://www.typescriptlang.org/docs/) - -## 📄 License - -MIT --- -**构建时间**: 2026-05-10 -**作者**: Senior Developer +## 开发规范 + +### 文件命名 +- 页面目录:`kebab-case`(如 `product-detail/`) +- 组件文件:`PascalCase`(如 `ProductCard.tsx`) +- 工具文件:`camelCase`(如 `formatDate.ts`) + +### 代码风格 +- 2 空格缩进 +- 单引号优先 +- 分号结尾 +- ESLint + @typescript-eslint 检查 + +### 提交规范 + +``` +feat: 新功能 +fix: 修复 bug +docs: 文档更新 +style: 代码格式调整 +refactor: 代码重构 +test: 测试相关 +chore: 构建/工具配置 +``` + +--- + +## 常见问题 + +### TailwindCSS 样式在小程序中不生效? +检查 `postcss.config.js` 和 `tailwind.config.js` 配置,确保已安装 `weapp-tailwindcss` 并正确配置 content 路径。 + +### NutUI 组件样式丢失? +确保在 `app.scss` 中引入了 NutUI 样式文件。 + +### TypeScript 路径别名 `@/*` 报错? +检查 `tsconfig.json` 的 `paths` 配置,并确保 IDE(VS Code)正确识别。 + +### 隐私协议报错 `errno:112`? +小程序后台需配置用户隐私保护指引,声明相册/摄像头/手机号等权限。 + +--- + +## 相关文档 + +- [Taro 官方文档](https://docs.taro.zone/) +- [React 官方文档](https://react.dev/) +- [NutUI React Taro 文档](https://nutui.jd.com/taro/react/2x/) +- [TailwindCSS 文档](https://tailwindcss.com/docs) +- [TypeScript 文档](https://www.typescriptlang.org/docs/) +- [微信小程序文档](https://developers.weixin.qq.com/miniprogram/dev/framework/) diff --git a/login_recover.patch b/login_recover.patch deleted file mode 100644 index 6be5002..0000000 --- a/login_recover.patch +++ /dev/null @@ -1,90 +0,0 @@ ---- a/src/passport/login.tsx 2026-07-16 15:54:54.000000000 +0800 -+++ b/src/passport/login.tsx 2026-07-16 15:53:09.000000000 +0800 -@@ -4,9 +4,8 @@ - import { TenantId } from '@/config/app' - import { getWxOpenId } from '@/api/layout' - import { getUserInfo } from '@/api/layout' --import { saveStorageByLoginUser, SERVER_API_URL } from '@/utils/server' -+import { saveStorageByLoginUser } from '@/utils/server' - import { isUserDisabled } from '@/utils/auth' --import request from '@/utils/request' - import { - checkAndHandleInviteRelation, - hasPendingInvite, -@@ -73,21 +72,22 @@ - } - } - --/** 获取用户信息(使用临时 token,避免本地 storage 尚未写入) */ -+/** 获取用户信息 */ - async function fetchUserInfo(token: string) { - try { -- const res: any = await request.get( -- `${SERVER_API_URL}/auth/user`, -- {}, -- { -- header: { -- Authorization: `Bearer ${token}`, -- }, -- showError: false, -- } -- ) -- if (res?.code === 0 && res?.data) { -- return res.data -+ const serverUrl = 'https://server.websoft.top' -+ const res: any = await Taro.request({ -+ url: `${serverUrl}/api/auth/user`, -+ method: 'GET', -+ header: { -+ Authorization: `Bearer ${token}`, -+ 'content-type': 'application/json', -+ TenantId: String(TenantId), -+ }, -+ }) -+ -+ if (res.data?.code === 0 && res.data?.data) { -+ return res.data.data - } - return null - } catch (e) { -@@ -215,21 +215,23 @@ - const inviteParams = parseInviteParams({ query: router?.params }) - const refereeId = inviteParams?.inviter ? parseInt(inviteParams.inviter, 10) : 0 - -- const res: any = await request.post( -- `${SERVER_API_URL}/wx-login/loginByMpWxPhone`, -- { -+ const serverUrl = 'https://server.websoft.top' -+ const res: any = await Taro.request({ -+ url: `${serverUrl}/api/wx-login/loginByMpWxPhone`, -+ method: 'POST', -+ data: { - code: phoneCode, - notVerifyPhone: true, - refereeId, - sceneType: 'save_referee', - tenantId: Number(TenantId), - }, -- { showError: false } -- ) -+ header: { 'content-type': 'application/json', TenantId: String(TenantId) }, -+ }) - -- if (res?.code === 0 && res?.data?.access_token) { -- const token = res.data.access_token -- let user = res.data.user -+ if (res.data?.code === 0 && res.data?.data?.access_token) { -+ const token = res.data.data.access_token -+ let user = res.data.data.user - - // 获取最新的用户信息 - const freshUserInfo = await fetchUserInfo(token) -@@ -260,7 +262,7 @@ - Taro.showToast({ title: '登录成功', icon: 'success' }) - setTimeout(() => navigateAfterLogin(), 800) - } else { -- Taro.showToast({ title: res?.message || '登录失败', icon: 'none' }) -+ Taro.showToast({ title: res.data?.message || '登录失败', icon: 'none' }) - } - } catch (e: any) { - console.error('微信登录失败:', e) diff --git a/overview.md b/overview.md deleted file mode 100644 index 3e6f818..0000000 --- a/overview.md +++ /dev/null @@ -1,41 +0,0 @@ -# 手机号授权登录修复概述 - -## 修复内容 - -1. **隐私协议授权流程修复**(`src/app.tsx`) - - 原代码在 `onNeedPrivacyAuthorization` 中直接 `resolve({ event: 'agree' })`,在基础库 3.16.1+ 下无法通过微信校验。 - - 新增 `src/components/PrivacyModal`,使用原生 Button 的 `open-type="agreePrivacyAuthorization"` 触发真正的隐私授权;`Taro.showModal` 的按钮无法被微信识别。 - -2. **登录/注册页不再主动预检隐私协议** - - 移除 `src/passport/login.tsx` 和 `src/passport/register.tsx` 中 `useDidShow` 主动调用 `ensurePrivacyAuthorized()` 的逻辑。 - - 进入登录页本身不再主动弹出隐私授权框;仅在用户点击手机号登录按钮,且微信检测到未授权时,才由微信强制触发 `onNeedPrivacyAuthorization`。 - -3. **门店中心上传图片前预检隐私协议** - - 门店商品管理(`src/pages/store/goods/index.tsx`)通过 `uploadFile()` 上传图片,该接口内部已调用 `ensurePrivacyAuthorized()`,点击上传时自动触发隐私授权。 - - 门店订单管理(`src/pages/store/orders/index.tsx`)直接调用 `Taro.chooseImage` 上传凭证,已在其 `chooseProofImage` 中增加 `ensurePrivacyAuthorized()` 预检。 - -4. **统一接口调用** - - 登录/注册页统一使用 `request.post` + `SERVER_API_URL` 调用 `/wx-login/loginByMpWxPhone`。 - - 修复 `register.tsx` 原本错误使用 `https://shop-api.websoft.top` 的问题。 - -5. **顺手修复构建错误** - - `src/passport/pay/index.tsx` 引用了不存在的 `@/api/passport/wx-login`,改为使用 `@/api/layout` 中的 `getWxOpenId` / `loginByOpenId`。 - -## 验证 - -`npx taro build --type weapp` 构建成功。 - -## 需要你确认的后台配置 - -- 小程序管理后台 → 设置 → 第三方设置 → 用户隐私保护指引 → 添加「开发者收集你的手机号」声明。 -- 确认小程序已开通「手机号快速验证组件」能力,且调用额度充足。 - -## 测试前清理 - -由于之前 `Taro.showModal` 的授权无效,微信可能已缓存该状态。重新上传后请先在开发者工具或真机中清理小程序缓存,再重新进入登录页,触发新的 PrivacyModal。 - -## 重要说明 - -- 微信基础库 3.16.1+ 强制要求:调用 `getPhoneNumber`、`chooseImage` 等敏感 API 前,用户必须先同意《用户隐私保护指引》。 -- 即使登录页不再主动预检,当用户点击「手机号快捷登录」且未授权时,微信仍会强制弹出隐私授权框。这是微信机制,无法绕过。 -- 如果用户已同意隐私协议但手机号登录仍失败,请重点检查后台是否已开通「手机号快速验证组件」能力,以及隐私指引中是否包含「手机号」声明。 diff --git a/register_recover.patch b/register_recover.patch deleted file mode 100644 index d5cdf1e..0000000 --- a/register_recover.patch +++ /dev/null @@ -1,71 +0,0 @@ ---- a/src/passport/register.tsx 2026-07-16 15:55:24.000000000 +0800 -+++ b/src/passport/register.tsx 2026-07-16 15:54:30.000000000 +0800 -@@ -4,9 +4,8 @@ - import { Button, Checkbox } from '@nutui/nutui-react-taro' - import { TenantId } from '@/config/app' - import { getUserInfo, getWxOpenId } from '@/api/layout' --import { saveStorageByLoginUser, SERVER_API_URL } from '@/utils/server' -+import { saveStorageByLoginUser } from '@/utils/server' - import { isUserDisabled } from '@/utils/auth' --import request from '@/utils/request' - import { - getStoredInviteParams, - parseInviteParams, -@@ -26,6 +25,17 @@ - detail: GetPhoneNumberDetail - } - -+interface LoginResponse { -+ data: { -+ code?: number -+ message?: string -+ data?: { -+ access_token: string -+ user: any -+ } -+ } -+} -+ - async function getWeappLoginCode(): Promise { - try { - const res = await new Promise<{ code?: string }>((resolve, reject) => { -@@ -181,9 +191,10 @@ - // 获取小程序登录 code(用于后续绑定 openid) - const wxLoginCode = await getWeappLoginCode() - -- const res: any = await request.post( -- `${SERVER_API_URL}/wx-login/loginByMpWxPhone`, -- { -+ const res = (await Taro.request({ -+ url: 'https://shop-api.websoft.top/api/wx-login/loginByMpWxPhone', -+ method: 'POST', -+ data: { - code: phoneCode, - encryptedData, - iv, -@@ -192,16 +203,19 @@ - sceneType: 'save_referee', - tenantId: TenantId, - }, -- { showError: false } -- ) -+ header: { -+ 'content-type': 'application/json', -+ TenantId, -+ }, -+ })) as unknown as LoginResponse - -- if (res?.code === 1) { -- Taro.showToast({ title: res.message || '登录失败', icon: 'none' }) -+ if ((res as any)?.data?.code === 1) { -+ Taro.showToast({ title: res.data.message || '登录失败', icon: 'none' }) - return - } - -- const token = res?.data?.access_token -- const user = res?.data?.user -+ const token = res?.data?.data?.access_token -+ const user = res?.data?.data?.user - if (!token || !user?.userId) { - Taro.showToast({ title: '登录失败,请重试', icon: 'none' }) - return