From 5da7d1b2ada6685022b7becee6cfd2362afe27c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Fri, 5 Sep 2025 16:58:49 +0800 Subject: [PATCH] =?UTF-8?q?feat(invitation):=20=E6=B7=BB=E5=8A=A0=E9=82=80?= =?UTF-8?q?=E8=AF=B7=E6=B3=A8=E5=86=8C=E5=8A=9F=E8=83=BD=E5=B9=B6=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=B0=8F=E7=A8=8B=E5=BA=8F=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增邀请注册功能,允许管理员生成邀请链接和二维码 - 支持网页注册和小程序码注册两种方式 - 实现自动建立推荐关系的功能 - 添加邀请统计和自定义小程序页面等扩展功能 - 优化用户体验和错误处理 --- .env.development | 2 +- docs/invitation-feature.md | 201 +++++ src/api/miniprogram/index.ts | 50 ++ src/router/routes.ts | 5 + src/views/passport/dealer/register.vue | 844 ++++++++++++++++++ src/views/passport/register/index.vue | 43 +- .../__tests__/invitation-modal.test.ts | 172 ++++ .../shopAdmin/components/invitation-modal.vue | 217 ++++- 8 files changed, 1459 insertions(+), 75 deletions(-) create mode 100644 docs/invitation-feature.md create mode 100644 src/api/miniprogram/index.ts create mode 100644 src/views/passport/dealer/register.vue create mode 100644 src/views/shop/shopAdmin/components/__tests__/invitation-modal.test.ts diff --git a/.env.development b/.env.development index b8ccd8b..47e6eb1 100644 --- a/.env.development +++ b/.env.development @@ -1,6 +1,6 @@ VITE_APP_NAME=后台管理(开发环境) #VITE_API_URL=http://127.0.0.1:9200/api -#VITE_SERVER_API_URL=http://127.0.0.1:8000/api +VITE_SERVER_API_URL=http://127.0.0.1:8000/api #VITE_API_URL=https://cms-api.s209.websoft.top/api diff --git a/docs/invitation-feature.md b/docs/invitation-feature.md new file mode 100644 index 0000000..29f7fb6 --- /dev/null +++ b/docs/invitation-feature.md @@ -0,0 +1,201 @@ +# 邀请注册功能使用说明 + +## 功能概述 + +邀请注册功能允许管理员生成邀请链接和二维码,邀请新用户注册并自动建立推荐关系。支持网页二维码和小程序码两种方式。 + +## 功能特点 + +- ✅ **简单易用**:基于现有推荐关系功能,无需复杂配置 +- ✅ **双重支持**:支持网页注册和小程序注册 +- ✅ **自动关联**:用户注册后自动建立推荐关系 +- ✅ **多种分享**:支持链接复制、二维码下载等分享方式 + +## 使用流程 + +### 管理员操作 + +1. **进入管理页面** + - 访问 `/shop/admin` 商店管理员页面 + - 点击"邀请注册"按钮 + +2. **生成邀请码** + - 弹窗会自动生成包含当前用户ID的邀请链接 + - 选择二维码类型:网页二维码或小程序码 + +3. **分享邀请** + - 复制邀请链接发送给用户 + - 下载二维码图片分享 + - 让用户直接扫描屏幕上的二维码 + +### 用户注册 + +#### 网页注册流程 +1. 用户点击邀请链接或扫描网页二维码 +2. 进入注册页面,会显示邀请提示信息 +3. 填写注册信息完成注册 +4. 系统自动建立与邀请人的推荐关系 + +#### 小程序注册流程 +1. 用户扫描小程序码进入小程序 +2. 小程序自动识别邀请参数 +3. 用户在小程序内完成注册 +4. 系统自动建立推荐关系 + +## 技术实现 + +### 邀请链接格式 +``` +网页注册: https://domain.com/register?inviter=123 +小程序码: scene参数为 invite_123 +``` + +### 核心文件 + +1. **邀请弹窗组件** + ``` + src/views/shop/shopAdmin/components/invitation-modal.vue + ``` + +2. **小程序码API** + ``` + src/api/miniprogram/index.ts + ``` + +3. **注册页面优化** + ``` + src/views/passport/register/index.vue + ``` + +### API接口 + +#### 生成小程序码 +```typescript +// 生成邀请注册小程序码 +generateInviteRegisterCode(inviterId: number): Promise + +// 参数说明 +{ + page: 'pages/register/index', // 小程序注册页面 + scene: 'invite_123', // 邀请参数 + width: 180, // 二维码宽度 + envVersion: 'trial' // 环境版本 +} +``` + +#### 建立推荐关系 +```typescript +// 绑定推荐关系 +bindUserReferee(data: UserReferee): Promise + +// 参数说明 +{ + dealerId: 123, // 邀请人ID + userId: 456, // 被邀请人ID + level: 1 // 推荐层级 +} +``` + +## 配置说明 + +### 小程序码配置 + +在 `src/api/miniprogram/index.ts` 中可以配置: + +```typescript +// 基础URL配置 +const BaseUrl = SERVER_API_URL; + +// 小程序页面配置 +const MINIPROGRAM_PAGES = { + register: 'pages/register/index', // 注册页面 + index: 'pages/index/index' // 首页 +}; + +// 环境配置 +const ENV_VERSION = 'trial'; // release | trial | develop +``` + +### 注册页面配置 + +在注册页面中,系统会自动检测URL参数: +- `inviter`: 邀请人ID +- 检测到邀请参数时显示邀请提示 + +## 错误处理 + +### 常见问题 + +1. **小程序码加载失败** + - 检查小程序码生成接口是否正常 + - 确认 `BaseUrl` 配置正确 + - 查看网络连接状态 + +2. **推荐关系建立失败** + - 检查用户ID是否正确获取 + - 确认推荐关系API接口正常 + - 查看控制台错误日志 + +3. **邀请链接无效** + - 确认URL参数格式正确 + - 检查注册页面参数解析逻辑 + +### 调试方法 + +1. **开启控制台日志** + ```javascript + // 在浏览器控制台查看 + localStorage.setItem('debug', 'true'); + ``` + +2. **检查网络请求** + - 打开浏览器开发者工具 + - 查看Network标签页的API请求 + +3. **验证参数传递** + ```javascript + // 检查邀请参数 + const urlParams = new URLSearchParams(window.location.search); + console.log('邀请人ID:', urlParams.get('inviter')); + ``` + +## 扩展功能 + +### 自定义小程序页面 +可以根据需要修改小程序码跳转的页面: + +```typescript +export async function generateCustomInviteCode(inviterId: number, page: string) { + return generateMiniProgramCode({ + page: page, + scene: `invite_${inviterId}`, + width: 180, + checkPath: true, + envVersion: 'trial' + }); +} +``` + +### 添加邀请统计 +可以扩展功能添加邀请统计: + +```typescript +// 统计邀请成功数量 +export async function getInviteStats(inviterId: number) { + // 查询推荐关系表统计数据 + return listUserReferee({ dealerId: inviterId }); +} +``` + +## 注意事项 + +1. **权限控制**:确保只有管理员可以生成邀请码 +2. **参数验证**:注册时需要验证邀请人ID的有效性 +3. **重复注册**:防止同一用户重复建立推荐关系 +4. **小程序配置**:确保小程序端正确处理scene参数 + +## 更新日志 + +- **v1.0.0**: 基础邀请注册功能 +- **v1.1.0**: 添加小程序码支持 +- **v1.2.0**: 优化用户体验和错误处理 diff --git a/src/api/miniprogram/index.ts b/src/api/miniprogram/index.ts new file mode 100644 index 0000000..8cfbbc9 --- /dev/null +++ b/src/api/miniprogram/index.ts @@ -0,0 +1,50 @@ +import {MODULES_API_URL} from '@/config/setting'; + +/** + * 小程序码参数 + */ +export interface MiniProgramCodeParam { + page?: string; + scene: string; + width?: number; + checkPath?: boolean; + envVersion?: 'release' | 'trial' | 'develop'; +} + +/** + * 生成小程序码 + */ +export async function generateMiniProgramCode(data: MiniProgramCodeParam) { + try { + const url = '/wx-login/getOrderQRCodeUnlimited/' + data.scene; + const fullUrl = MODULES_API_URL + `${url}`; + + console.log('生成小程序码URL:', fullUrl); + console.log('小程序码参数:', data); + console.log('scene 参数:', data.scene); + + // 直接返回URL,让浏览器处理图片加载 + // scene 参数中包含了租户ID信息 + return fullUrl; + } catch (error: any) { + console.error('生成小程序码失败:', error); + throw new Error(error.message || '生成小程序码失败'); + } +} + +/** + * 生成邀请小程序码 + */ +export async function generateInviteCode(inviterId: number) { + const scene = `uid_${inviterId}`; + + console.log('生成邀请小程序码 scene:', scene); + + return generateMiniProgramCode({ + page: 'pages/index/index', + scene: scene, + width: 180, + checkPath: true, + envVersion: 'trial' + }); +} diff --git a/src/router/routes.ts b/src/router/routes.ts index 57038bc..1b85804 100644 --- a/src/router/routes.ts +++ b/src/router/routes.ts @@ -30,6 +30,11 @@ export const routes = [ component: () => import('@/views/bszx/bszxPayCert/index.vue'), meta: { title: '查看证书' } }, + { + path: '/dealer/register', + component: () => import('@/views/passport/dealer/register.vue'), + meta: { title: '邀请注册' } + }, // { // path: '/forget', // component: () => import('@/views/passport/forget/index.vue'), diff --git a/src/views/passport/dealer/register.vue b/src/views/passport/dealer/register.vue new file mode 100644 index 0000000..d1eee1f --- /dev/null +++ b/src/views/passport/dealer/register.vue @@ -0,0 +1,844 @@ + + + + + diff --git a/src/views/passport/register/index.vue b/src/views/passport/register/index.vue index d1eee1f..6877f7a 100644 --- a/src/views/passport/register/index.vue +++ b/src/views/passport/register/index.vue @@ -14,6 +14,7 @@ config.sysLogo || 'https://oss.wsdns.cn/20240822/0252ad4ed46449cdafe12f8d3d96c2ea.svg' " + alt="登录页面LOGO" class="logo" />

{{ config.siteName }}

@@ -35,14 +36,6 @@ >