From f94089b5663d1411ee9aecf5e23b7eda1942cafc Mon Sep 17 00:00:00 2001
From: Billy <641833868@qq.com>
Date: Wed, 29 Oct 2025 12:01:14 +0800
Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=82=80=E8=AF=B7=E7=A0=81?=
=?UTF-8?q?=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
addons/shopro/controller/Ccblife.php | 3 +
addons/shopro/controller/Invite.php | 91 ++++++
addons/shopro/library/InviteHelper.php | 149 ++++++++++
addons/shopro/service/order/OrderCreate.php | 17 +-
database/migrations/FRONTEND_CHANGES.md | 271 ++++++++++++++++++
.../commission/components/commission-info.vue | 48 +++-
frontend/pages/order/confirm.vue | 69 ++++-
frontend/sheep/api/index.js | 2 +
frontend/sheep/api/invite.js | 29 ++
9 files changed, 675 insertions(+), 4 deletions(-)
create mode 100644 addons/shopro/controller/Invite.php
create mode 100644 addons/shopro/library/InviteHelper.php
create mode 100644 database/migrations/FRONTEND_CHANGES.md
create mode 100644 frontend/sheep/api/invite.js
diff --git a/addons/shopro/controller/Ccblife.php b/addons/shopro/controller/Ccblife.php
index 2d3136b..cd95fe9 100644
--- a/addons/shopro/controller/Ccblife.php
+++ b/addons/shopro/controller/Ccblife.php
@@ -242,6 +242,9 @@ class Ccblife extends Common
}
$user = Db::name('user')->where('id', $userId)->find();
+
+ // 新用户注册后自动生成邀请码
+ $inviteCode = \addons\shopro\library\InviteHelper::generateCode($userId);
}
}
diff --git a/addons/shopro/controller/Invite.php b/addons/shopro/controller/Invite.php
new file mode 100644
index 0000000..82e6de9
--- /dev/null
+++ b/addons/shopro/controller/Invite.php
@@ -0,0 +1,91 @@
+invite_code) {
+ $inviteCode = InviteHelper::generateCode($user->id);
+ } else {
+ $inviteCode = $user->invite_code;
+ }
+
+ // 统计邀请人数
+ $inviteCount = UserModel::where('parent_user_id', $user->id)->count();
+
+ $this->success('获取成功', [
+ 'invite_code' => $inviteCode,
+ 'invite_count' => $inviteCount,
+ 'share_text' => "我的邀请码:{$inviteCode},下单时填写即可!"
+ ]);
+ }
+
+ /**
+ * 验证邀请码
+ */
+ public function validate()
+ {
+ $inviteCode = $this->request->param('invite_code', '');
+
+ if (empty($inviteCode)) {
+ $this->error('请输入邀请码');
+ }
+
+ $result = InviteHelper::validate($inviteCode);
+
+ if ($result['code'] != 1) {
+ $this->error($result['msg']);
+ }
+
+ $this->success('邀请码有效', $result['data']);
+ }
+
+ /**
+ * 绑定邀请码
+ */
+ public function bind()
+ {
+ $user = auth_user();
+ $inviteCode = $this->request->param('invite_code', '');
+
+ if (empty($inviteCode)) {
+ $this->error('请输入邀请码');
+ }
+
+ $result = InviteHelper::bind($inviteCode, $user->id);
+
+ if ($result['code'] != 1) {
+ $this->error($result['msg']);
+ }
+
+ $this->success($result['msg'], $result['data']);
+ }
+
+ /**
+ * 我邀请的用户列表
+ */
+ public function myInvites()
+ {
+ $user = auth_user();
+
+ $list = UserModel::where('parent_user_id', $user->id)
+ ->field(['id', 'nickname', 'avatar', 'mobile', 'jointime', 'invite_code_used'])
+ ->order('id desc')
+ ->paginate($this->request->param('list_rows', 10));
+
+ $this->success('获取成功', $list);
+ }
+}
diff --git a/addons/shopro/library/InviteHelper.php b/addons/shopro/library/InviteHelper.php
new file mode 100644
index 0000000..b233d3b
--- /dev/null
+++ b/addons/shopro/library/InviteHelper.php
@@ -0,0 +1,149 @@
+invite_code) {
+ return $user->invite_code;
+ }
+
+ // 生成唯一邀请码(排除易混淆字符)
+ $chars = 'ABCDEFGHJKMNPQRSTUVWXYZ23456789';
+ $maxAttempts = 50;
+
+ for ($i = 0; $i < $maxAttempts; $i++) {
+ $code = '';
+ for ($j = 0; $j < 6; $j++) {
+ $code .= $chars[mt_rand(0, strlen($chars) - 1)];
+ }
+
+ // 检查是否重复
+ if (!UserModel::where('invite_code', $code)->find()) {
+ $user->invite_code = $code;
+ $user->save();
+ return $code;
+ }
+ }
+
+ // 兜底:用MD5
+ $code = strtoupper(substr(md5($userId . time() . mt_rand()), 0, 6));
+ $user->invite_code = $code;
+ $user->save();
+
+ return $code;
+ }
+
+ /**
+ * 验证邀请码
+ * @param string $inviteCode 邀请码
+ * @return array
+ */
+ public static function validate($inviteCode)
+ {
+ $inviteCode = strtoupper(trim($inviteCode));
+
+ if (strlen($inviteCode) !== 6) {
+ return ['code' => 0, 'msg' => '邀请码格式错误'];
+ }
+
+ $inviter = UserModel::where('invite_code', $inviteCode)
+ ->where('status', 'normal')
+ ->field(['id', 'nickname', 'avatar', 'invite_code'])
+ ->find();
+
+ if (!$inviter) {
+ return ['code' => 0, 'msg' => '邀请码不存在'];
+ }
+
+ return [
+ 'code' => 1,
+ 'msg' => '邀请码有效',
+ 'data' => [
+ 'user_id' => $inviter->id,
+ 'invite_code' => $inviter->invite_code,
+ 'inviter' => [
+ 'id' => $inviter->id,
+ 'nickname' => $inviter->nickname,
+ 'avatar' => $inviter->avatar
+ ]
+ ]
+ ];
+ }
+
+ /**
+ * 绑定上下级关系
+ * @param string $inviteCode 邀请码
+ * @param int $userId 被邀请人ID
+ * @return array
+ */
+ public static function bind($inviteCode, $userId)
+ {
+ $inviteCode = strtoupper(trim($inviteCode));
+ $user = UserModel::find($userId);
+
+ if (!$user) {
+ return ['code' => 0, 'msg' => '用户不存在'];
+ }
+
+ // 已绑定过上级
+ if ($user->parent_user_id !== null) {
+ return ['code' => 0, 'msg' => '您已有推荐人,无法修改'];
+ }
+
+ // 验证邀请码
+ $validateResult = self::validate($inviteCode);
+ if ($validateResult['code'] != 1) {
+ return $validateResult;
+ }
+
+ $inviterUserId = $validateResult['data']['user_id'];
+
+ // 不能邀请自己
+ if ($inviterUserId == $userId) {
+ return ['code' => 0, 'msg' => '不能使用自己的邀请码'];
+ }
+
+ // 绑定
+ $user->parent_user_id = $inviterUserId;
+ $user->invite_code_used = $inviteCode;
+ $user->save();
+
+ \think\Log::info("邀请码绑定: 邀请人[{$inviterUserId}] -> 被邀请人[{$userId}] 邀请码[{$inviteCode}]");
+
+ // 触发分销业绩统计
+ $agent = new \addons\shopro\service\commission\Agent($userId);
+ $agent->createAsyncAgentUpgrade($userId);
+
+ // 添加分销推广记录
+ \app\admin\model\shopro\commission\Log::add(
+ $inviterUserId,
+ 'share',
+ ['user' => $user, 'type' => 'invite_code']
+ );
+
+ return [
+ 'code' => 1,
+ 'msg' => '绑定成功',
+ 'data' => $validateResult['data']
+ ];
+ }
+}
diff --git a/addons/shopro/service/order/OrderCreate.php b/addons/shopro/service/order/OrderCreate.php
index 53786a9..b30146e 100755
--- a/addons/shopro/service/order/OrderCreate.php
+++ b/addons/shopro/service/order/OrderCreate.php
@@ -144,9 +144,9 @@ class OrderCreate
$this->activity_id = $params['activity_id'] ?? 0;
// $groupon_id = $groupon_id ?? 0; // 拼团的 团 id
// $buy_type = $buy_type ?? 'alone'; // 拼团的 购买方式: alone=单独购买,groupon=开团
-
+
$this->goodsList = $params['goods_list'] ?? [];
-
+
$this->address_id = $params['address_id'] ?? 0;
$this->invoice_id = $params['invoice_id'] ?? 0;
@@ -155,6 +155,9 @@ class OrderCreate
$this->money = (isset($params['money']) && $params['money'] > 0) ? $params['money'] : 0;
+ // 邀请码
+ $this->invite_code = $params['invite_code'] ?? '';
+
// 获取商品信息
$this->goodsListInit();
}
@@ -1238,6 +1241,16 @@ class OrderCreate
];
\think\Hook::listen('order_create_after', $hookData);
+ // 处理邀请码绑定
+ if (!empty($this->invite_code) && $this->user->parent_user_id === null) {
+ $bindResult = \addons\shopro\library\InviteHelper::bind($this->invite_code, $this->user->id);
+ if ($bindResult['code'] == 1) {
+ \think\Log::info("订单[{$order->id}]使用邀请码[{$this->invite_code}]绑定成功");
+ } else {
+ \think\Log::warning("订单[{$order->id}]邀请码绑定失败: " . $bindResult['msg']);
+ }
+ }
+
return $order;
});
diff --git a/database/migrations/FRONTEND_CHANGES.md b/database/migrations/FRONTEND_CHANGES.md
new file mode 100644
index 0000000..9d6a850
--- /dev/null
+++ b/database/migrations/FRONTEND_CHANGES.md
@@ -0,0 +1,271 @@
+# 前端修改说明
+
+## 📝 修改文件清单
+
+```
+✅ 已修改的文件(3个):
+frontend/
+├── pages/order/confirm.vue # 订单确认页(+40行)
+├── pages/commission/components/
+│ └── commission-info.vue # 分销中心个人信息(+30行)
+└── sheep/api/
+ ├── invite.js # 新增邀请码API(新建)
+ └── index.js # 注册邀请码API(+2行)
+```
+
+## 🎯 功能说明
+
+### 1. 订单确认页 - 邀请码输入框
+
+**位置**: 订单备注下方
+
+**功能**:
+- ✅ 仅未绑定上级的用户显示(`v-if="!userInfo.parent_user_id"`)
+- ✅ 非必填,6位大写字母+数字
+- ✅ 失焦自动验证(调用 `/invite/validate` 接口)
+- ✅ 验证成功显示绿色勾号
+- ✅ 提交订单时自动携带 `invite_code` 参数
+
+**代码片段**:
+```vue
+
+```
+
+**验证逻辑**:
+```javascript
+async function onValidateInvite() {
+ const code = state.inviteCode.trim().toUpperCase();
+ if (code.length !== 6) {
+ sheep.$helper.toast('邀请码格式错误');
+ return;
+ }
+
+ const { code: resCode } = await sheep.$api.invite.validate({ invite_code: code });
+ if (resCode === 1) {
+ state.inviteValidated = true;
+ sheep.$helper.toast('邀请码验证成功');
+ }
+}
+```
+
+**提交订单**:
+```javascript
+if (state.inviteValidated && state.inviteCode) {
+ state.orderPayload.invite_code = state.inviteCode;
+}
+const { code, data } = await sheep.$api.order.create(state.orderPayload);
+```
+
+---
+
+### 2. 个人中心 - 显示邀请码
+
+**位置**: 分销中心个人信息卡片,等级标签下方
+
+**功能**:
+- ✅ 自动获取邀请码(`/invite/myCode`)
+- ✅ 点击复制邀请码到剪贴板
+- ✅ 复制成功提示
+
+**代码片段**:
+```vue
+
+ 我的邀请码:
+ {{ state.inviteCode }}
+
+
+```
+
+**逻辑**:
+```javascript
+// 页面加载时获取邀请码
+async function getInviteCode() {
+ const { code, data } = await sheep.$api.invite.myCode();
+ if (code === 1) {
+ state.inviteCode = data.invite_code;
+ }
+}
+
+// 复制邀请码
+function onCopyCode() {
+ sheep.$helper.copyText(state.inviteCode);
+ sheep.$helper.toast('邀请码已复制');
+}
+
+onMounted(() => {
+ getInviteCode();
+});
+```
+
+---
+
+## 🔌 API 接口
+
+### 新增 `sheep.$api.invite` 模块
+
+```javascript
+// 1. 获取我的邀请码
+sheep.$api.invite.myCode()
+// 响应: { code: 1, data: { invite_code: "ABC123", invite_count: 5 } }
+
+// 2. 验证邀请码
+sheep.$api.invite.validate({ invite_code: "ABC123" })
+// 响应: { code: 1, msg: "邀请码有效", data: { ... } }
+
+// 3. 我邀请的用户列表
+sheep.$api.invite.myInvites({ page: 1 })
+// 响应: { code: 1, data: { total: 10, data: [...] } }
+```
+
+---
+
+## 🎨 样式调整
+
+### 订单确认页样式
+```scss
+.invite-input-box {
+ position: relative;
+
+ .validate-tag {
+ margin-left: 10rpx;
+ font-size: 32rpx;
+ }
+}
+```
+
+### 个人中心样式
+```scss
+.invite-code-box {
+ margin-top: 12rpx;
+ padding: 4rpx 12rpx;
+ background: rgba(255, 255, 255, 0.2);
+ border-radius: 20rpx;
+ border: 1rpx solid rgba(255, 255, 255, 0.3);
+
+ .invite-code {
+ font-size: 26rpx;
+ font-weight: bold;
+ color: #fff;
+ letter-spacing: 2rpx;
+ }
+}
+```
+
+---
+
+## 🧪 测试步骤
+
+### 测试1: 订单页邀请码输入
+
+```bash
+# 1. 登录建行生活用户(未绑定上级)
+# 2. 加入购物车,进入订单确认页
+# 3. 查看是否显示"邀请码"输入框
+# 4. 输入邀请码(如:ABC123)
+# 5. 失焦后查看是否显示验证成功图标
+# 6. 提交订单
+# 7. 后台检查是否绑定成功:
+SELECT parent_user_id, invite_code_used FROM user WHERE id = 新用户ID;
+```
+
+### 测试2: 个人中心显示邀请码
+
+```bash
+# 1. 进入分销中心页面
+# 2. 查看个人信息卡片,等级标签下方
+# 3. 确认显示"我的邀请码: XXXXXX"
+# 4. 点击邀请码
+# 5. 确认提示"邀请码已复制"
+# 6. 粘贴验证是否成功复制
+```
+
+### 测试3: 已绑定用户不显示输入框
+
+```bash
+# 1. 登录已有上级的用户
+# 2. 进入订单确认页
+# 3. 确认不显示"邀请码"输入框
+```
+
+---
+
+## 🐛 常见问题
+
+### 问题1: 邀请码输入框不显示
+
+**检查**:
+```javascript
+// 确认用户是否已绑定
+console.log(userInfo.parent_user_id); // 应为 null
+```
+
+### 问题2: 验证失败
+
+**检查**:
+```bash
+# 查看API响应
+curl -X POST http://your-domain/invite/validate -d "invite_code=ABC123"
+
+# 查看后端日志
+tail -f runtime/log/$(date +%Y%m)/$(date +%d).log | grep "邀请码"
+```
+
+### 问题3: 个人中心不显示邀请码
+
+**检查**:
+```javascript
+// 检查API是否成功
+const res = await sheep.$api.invite.myCode();
+console.log(res);
+
+// 检查用户是否有邀请码
+SELECT invite_code FROM user WHERE id = 你的用户ID;
+```
+
+---
+
+## 📱 界面预览
+
+### 订单确认页
+
+```
+┌────────────────────────────────┐
+│ 商品信息 │
+├────────────────────────────────┤
+│ 订单备注 [建议留言前先与商家沟通]│
+├────────────────────────────────┤
+│ 邀请码 [选填(6位大写字母+数字)] ✓│ ← 新增
+└────────────────────────────────┘
+```
+
+### 个人中心
+
+```
+┌────────────────────────────────┐
+│ 👤 张三 │
+│ 🏷️ 分销商等级 │
+│ 📋 我的邀请码: ABC123 📋 │ ← 新增
+└────────────────────────────────┘
+```
+
+---
+
+## ✅ 完成检查清单
+
+- [x] 订单页显示邀请码输入框
+- [x] 邀请码验证功能正常
+- [x] 订单提交携带邀请码参数
+- [x] 个人中心显示邀请码
+- [x] 点击复制邀请码功能正常
+- [x] 已绑定用户不显示输入框
+- [x] API接口注册成功
+
+---
+
+**最后更新**: 2024-01-15
+**维护人员**: Billy
diff --git a/frontend/pages/commission/components/commission-info.vue b/frontend/pages/commission/components/commission-info.vue
index e18790d..cee381a 100644
--- a/frontend/pages/commission/components/commission-info.vue
+++ b/frontend/pages/commission/components/commission-info.vue
@@ -23,6 +23,12 @@
+
+
+ 我的邀请码:
+ {{ state.inviteCode }}
+
+
@@ -31,7 +37,7 @@
@@ -122,5 +147,26 @@
}
}
}
+
+ .invite-code-box {
+ margin-top: 12rpx;
+ padding: 4rpx 12rpx;
+ background: rgba(255, 255, 255, 0.2);
+ border-radius: 20rpx;
+ border: 1rpx solid rgba(255, 255, 255, 0.3);
+
+ .invite-label {
+ font-size: 22rpx;
+ color: rgba(255, 255, 255, 0.8);
+ margin-right: 8rpx;
+ }
+
+ .invite-code {
+ font-size: 26rpx;
+ font-weight: bold;
+ color: #fff;
+ letter-spacing: 2rpx;
+ }
+ }
}
diff --git a/frontend/pages/order/confirm.vue b/frontend/pages/order/confirm.vue
index c17188d..8d87b7e 100644
--- a/frontend/pages/order/confirm.vue
+++ b/frontend/pages/order/confirm.vue
@@ -30,7 +30,7 @@
-
+
订单备注
+
+
+
+ 邀请码
+
+
+
+
+
+
+
@@ -185,8 +208,12 @@
showCoupon: false,
couponInfo: [],
showDiscount: false,
+ inviteCode: '',
+ inviteValidated: false,
});
+ const userInfo = computed(() => sheep.$store('user').userInfo);
+
// 立即兑换(立即兑换无需跳转收银台)
const exchangeNow = computed(
() => state.orderPayload.order_type === 'score' && state.orderInfo.pay_fee == 0,
@@ -254,8 +281,38 @@
}
}
+ // 验证邀请码
+ async function onValidateInvite() {
+ const code = state.inviteCode.trim().toUpperCase();
+ if (!code) {
+ state.inviteValidated = false;
+ return;
+ }
+
+ if (code.length !== 6) {
+ sheep.$helper.toast('邀请码格式错误');
+ state.inviteValidated = false;
+ return;
+ }
+
+ const { code: resCode, msg } = await sheep.$api.invite.validate({ invite_code: code });
+ if (resCode === 1) {
+ state.inviteCode = code;
+ state.inviteValidated = true;
+ sheep.$helper.toast('邀请码验证成功');
+ } else {
+ state.inviteValidated = false;
+ sheep.$helper.toast(msg || '邀请码无效');
+ }
+ }
+
// 创建订单&跳转
async function submitOrder() {
+ // 添加邀请码参数
+ if (state.inviteValidated && state.inviteCode) {
+ state.orderPayload.invite_code = state.inviteCode;
+ }
+
const { code, data } = await sheep.$api.order.create(state.orderPayload);
if (code === 1) {
// 更新购物车列表
@@ -310,6 +367,16 @@