Browse Source

fix:合在一起

super-yimizi 19 hours ago
parent
commit
0145b630eb

+ 16 - 0
application/admin/view/commission/config/index.html

@@ -183,6 +183,22 @@
                         </div>
                     </div>
 
+                    <div class="form-group">
+                        <label class="control-label col-xs-12 col-sm-2">海报背景图:</label>
+                        <div class="col-xs-12 col-sm-8">
+                            <div class="input-group">
+                                <input id="c-poster_background_image" class="form-control" size="50" name="row[poster_background_image]" type="text" value="{$commissionConfig.poster_background_image|default=''}" placeholder="请选择或上传海报背景图">
+                                <div class="input-group-addon no-border no-padding">
+                                    <span><button type="button" id="plupload-poster_background_image" class="btn btn-danger plupload" data-input-id="c-poster_background_image" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp" data-multiple="false" data-preview-id="p-poster_background_image"><i class="fa fa-upload"></i> 上传</button></span>
+                                    <span><button type="button" id="fachoose-poster_background_image" class="btn btn-primary fachoose" data-input-id="c-poster_background_image" data-mimetype="image/*" data-multiple="false"><i class="fa fa-list"></i> 选择</button></span>
+                                </div>
+                                <span class="msg-box n-right" for="c-poster_background_image"></span>
+                            </div>
+                            <ul class="row list-inline plupload-preview" id="p-poster_background_image"></ul>
+                            <span class="help-block">分销海报的背景图,用于分销商生成邀请海报</span>
+                        </div>
+                    </div>
+
                     <hr class="hr-line-solid">
 
                     <div class="form-group">

+ 14 - 4
application/api/controller/Share.php

@@ -3,8 +3,9 @@
 namespace app\api\controller;
 
 use think\Db;
-use app\common\model\Share as ShareModel;
+use app\common\model\user\Share as ShareModel;
 use app\api\validate\ShareValidate;
+use app\common\Service\Share\ShareService;
 
 class Share extends Base
 {
@@ -16,16 +17,25 @@ class Share extends Base
     {
         $params = $this->request->only(['shareId', 'spm', 'page', 'query', 'from', 'platform']);
 
+        // 验证参数
         $validate = new ShareValidate();
         if (!$validate->scene('add')->check($params)) {
             $this->error($validate->getError());
         }
 
-        $userId = $this->auth->id;
+        $user = auth_user();
+        if (!$user) {
+            $this->error('用户未登录');
+        }
 
-       // $shareInfo = ShareModel::log($userId, $params);
+        // 使用服务类添加分享记录
+        $shareInfo = ShareService::addShareLog($user, $params);
 
-        $this->success("");
+        if ($shareInfo) {
+            $this->success('添加分享记录成功', $shareInfo);
+        } else {
+            $this->error('添加分享记录失败');
+        }
     }
 
     /**

+ 130 - 0
application/api/controller/commission/Agent.php

@@ -11,6 +11,11 @@ use app\common\model\Goods as GoodsModel;
 use app\common\Service\Wallet;
 use app\common\Enum\AgentType;
 use app\common\library\BcMath;
+use app\common\Enum\PageTypeEnum;
+use app\common\Service\Third\Wechat\Wechat as WechatService;
+use app\common\Enum\ChannelEnum;
+use app\common\Enum\ShareEnum;
+use app\common\Service\ShopConfigService;
 
 
 class Agent extends Commission
@@ -266,6 +271,131 @@ class Agent extends Commission
         
         $this->success('提现成功');
     }
+
+    /**
+     * 生成分销海报微信小程序码
+     */
+    public function posterQrcode()
+    {
+        // 验证当前用户是否为分销商
+        $agent = $this->service->agent;
+        if (!$agent) {
+            $this->error('您还不是分销商');
+        }
+        
+        // 获取当前用户ID作为分享者
+        $shareUserId = $this->service->user->id;
+        
+        // 从请求头获取platform参数
+        $requestPlatform = $this->request->header('platform', '');
+        if (!$requestPlatform) {
+            $this->error('缺少platform参数');
+        }
+        
+        // 将ChannelEnum映射到ShareEnum平台常量
+        $shareEnumPlatform = $this->mapChannelToSharePlatform($requestPlatform);
+        
+        // 使用ShareEnum获取平台ID (1=H5,2=微信公众号网页,3=微信小程序,4=App)
+        $platformId = ShareEnum::getPlatformId($shareEnumPlatform);
+        $fromPlatformId = $platformId; // 来源平台同当前平台
+        
+        try {
+            // 初始化微信服务 - 固定使用微信小程序平台生成小程序码
+            $wechatPlatform = ChannelEnum::CHANNEL_WECHAT_MINI_PROGRAM;
+            $payload = [];
+            $wechat = new WechatService($wechatPlatform, $payload);
+            $mp = $wechat->getApp();
+            
+            // 构造spm参数: shareId.page.query.platform.from
+            // shareId: 分享者用户ID
+            // page: 页面类型 (分销海报页面 = 6)
+            // query: 代理商ID (使用分享者ID)
+            // platform: 从请求头获取的平台ID  
+            // from: 来源平台ID
+            $spmParams = sprintf('%s.%s.%s.%s.%s', 
+                $shareUserId,
+                PageTypeEnum::AGENT_POSTER,
+                $shareUserId,
+                $platformId, // 使用映射后的平台ID
+                $fromPlatformId  // 来源平台ID
+            );
+            
+            // 固定跳转到分销海报页面,携带smp参数
+            $page = 'pages/me/edit'; // 分销海报页面路径
+            $scene = 'spm=' . $spmParams;
+            
+            // 生成小程序码
+            $content = $mp->app_code->getUnlimit($scene, [
+                'page' => $page,
+                'is_hyaline' => true,
+                'env_version' => 'trial',
+                'check_path' => false
+            ]);
+            
+            if ($content instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
+                // 将小程序码转换为base64
+                $qrcodeBase64 = base64_encode($content->getBody());
+                
+                // 构建返回数据
+                $result = [
+                    'qrcode_base64' => 'data:image/png;base64,' . $qrcodeBase64,
+                    'invite_code' =>$agent->invite_code? $agent->invite_code : '',
+                    'poster_background' => $this->getPosterBackground()
+                ];
+                
+                $this->success('生成成功', $result);
+            } else {
+                // 小程序码获取失败
+                $msg = $content['errcode'] ?? '-';
+                $msg .= $content['errmsg'] ?? '';
+                $this->error('小程序码生成失败:' . $msg);
+            }
+            
+        } catch (\Exception $e) {
+            $this->error('小程序码生成失败:' . $e->getMessage());
+        }
+    }
+
+    /**
+     * 将ChannelEnum的平台常量映射到ShareEnum的平台常量
+     * @param string $channelPlatform ChannelEnum平台常量
+     * @return string ShareEnum平台常量
+     */
+    private function mapChannelToSharePlatform($channelPlatform)
+    {
+        $channelToShareMap = [
+            ChannelEnum::CHANNEL_H5 => ShareEnum::PLATFORM_H5,
+            ChannelEnum::CHANNEL_WECHAT_OFFICIAL_ACCOUNT => ShareEnum::PLATFORM_WECHAT_OFFICIAL_ACCOUNT,
+            ChannelEnum::CHANNEL_WECHAT_MINI_PROGRAM => ShareEnum::PLATFORM_WECHAT_MINI_PROGRAM,
+            ChannelEnum::CHANNEL_IOS_APP => ShareEnum::PLATFORM_APP,
+            ChannelEnum::CHANNEL_ANDROID_APP => ShareEnum::PLATFORM_APP,
+        ];
+
+        return $channelToShareMap[$channelPlatform] ?? ShareEnum::PLATFORM_WECHAT_MINI_PROGRAM; // 默认微信小程序
+    }
+
+    /**
+     * 获取海报背景图
+     * @return string
+     */
+    private function getPosterBackground()
+    {
+        try {
+            // 获取分销配置
+            $commissionConfig = ShopConfigService::getConfigs('shop.commission');
+            
+            // 获取海报背景图
+            $backgroundImage = $commissionConfig['poster_background_image'] ?? '';
+            
+            if (!empty($backgroundImage)) {
+                return cdnurl($backgroundImage, true);
+            }
+            
+            return '';
+        } catch (\Exception $e) {
+            return '';
+        }
+    }
     
    
     

+ 1 - 0
application/api/controller/commission/Configuration.php

@@ -53,6 +53,7 @@ class Configuration extends Base
                 'share_title' => $commissionConfig['share_title'] ?? '我发现了一个好商品',
                 'share_description' => $commissionConfig['share_description'] ?? '快来看看这个优质商品,价格优惠,质量保证!',
                 'share_image' => !empty($commissionConfig['share_image']) ? cdnurl($commissionConfig['share_image'], true) : '',
+                'poster_background_image' => !empty($commissionConfig['poster_background_image']) ? cdnurl($commissionConfig['poster_background_image'], true) : '',
             ];
             
             $this->success('获取成功', $config);

+ 2 - 0
application/api/controller/third/Wechat.php

@@ -153,6 +153,8 @@ class Wechat extends Base
     {
         $mp = $this->wechat->getApp();
         $path = $this->payload['path'];
+        
+        // 这里要处理下 如果没有穿$path  默认 pages/me/edit  spm的参数是 
         list($page, $scene) = explode('?', $path);
         $content = $mp->app_code->getUnlimit($scene, [
             'page' => substr($page, 1),

+ 48 - 0
application/common/Enum/PageTypeEnum.php

@@ -0,0 +1,48 @@
+<?php
+
+namespace app\common\Enum;
+
+/**
+ * 页面类型枚举
+ */
+class PageTypeEnum
+{
+    // 页面类型常量
+    const HOME = 1;              // 首页(默认)
+    const GOODS = 2;             // 商品页
+    const GROUP_GOODS = 3;       // 拼团商品
+    const SECKILL_GOODS = 4;     // 秒杀商品
+    const INVITE_GROUP = 5;      // 邀请参团
+    const AGENT_POSTER = 6;      // 分销海报页
+
+    /**
+     * 获取页面类型列表
+     */
+    public static function getPageTypeList()
+    {
+        return [
+            self::HOME => '首页',
+            self::GOODS => '商品页',
+            self::GROUP_GOODS => '拼团商品',
+            self::SECKILL_GOODS => '秒杀商品',
+            self::INVITE_GROUP => '邀请参团',
+            self::AGENT_POSTER => '分销海报页',
+        ];
+    }
+
+    /**
+     * 获取页面类型文本
+     */
+    public static function getPageTypeText($type)
+    {
+        return self::getPageTypeList()[$type] ?? '未知页面类型';
+    }
+
+    /**
+     * 验证页面类型是否有效
+     */
+    public static function isValidPageType($type)
+    {
+        return array_key_exists($type, self::getPageTypeList());
+    }
+}

+ 99 - 0
application/common/Enum/ShareEnum.php

@@ -0,0 +1,99 @@
+<?php
+
+namespace app\common\Enum;
+
+/**
+ * 分享枚举类
+ */
+class ShareEnum
+{
+    // 分享来源类型
+    const FROM_FORWARD = 'forward';
+    const FROM_POSTER = 'poster';
+    const FROM_LINK = 'link';
+
+    // 分享平台类型
+    const PLATFORM_H5 = 'H5';
+    const PLATFORM_WECHAT_OFFICIAL_ACCOUNT = 'WechatOfficialAccount';
+    const PLATFORM_WECHAT_MINI_PROGRAM = 'WechatMiniProgram';
+    const PLATFORM_APP = 'App';
+
+    /**
+     * 获取分享来源列表
+     */
+    public static function getFromList()
+    {
+        return [
+            self::FROM_FORWARD => '直接转发',
+            self::FROM_POSTER => '识别海报',
+            self::FROM_LINK => '分享链接',
+        ];
+    }
+
+    /**
+     * 获取分享平台列表
+     */
+    public static function getPlatformList()
+    {
+        return [
+            self::PLATFORM_H5 => 'H5网页',
+            self::PLATFORM_WECHAT_OFFICIAL_ACCOUNT => '微信公众号网页',
+            self::PLATFORM_WECHAT_MINI_PROGRAM => '微信小程序',
+            self::PLATFORM_APP => 'APP',
+        ];
+    }
+
+    /**
+     * 获取分享来源文本
+     */
+    public static function getFromText($from)
+    {
+        return self::getFromList()[$from] ?? $from;
+    }
+
+    /**
+     * 获取分享平台文本
+     */
+    public static function getPlatformText($platform)
+    {
+        return self::getPlatformList()[$platform] ?? $platform;
+    }
+
+    /**
+     * 验证分享来源是否有效
+     */
+    public static function isValidFrom($from)
+    {
+        return array_key_exists($from, self::getFromList());
+    }
+
+    /**
+     * 验证分享平台是否有效
+     */
+    public static function isValidPlatform($platform)
+    {
+        return array_key_exists($platform, self::getPlatformList());
+    }
+
+    /**
+     * 平台映射到数字ID (与前端buildSpmQuery保持一致)
+     * 1=H5,2=微信公众号网页,3=微信小程序,4=App
+     */
+    public static function getPlatformIdMap()
+    {
+        return [
+            self::PLATFORM_H5 => 1,
+            self::PLATFORM_WECHAT_OFFICIAL_ACCOUNT => 2,
+            self::PLATFORM_WECHAT_MINI_PROGRAM => 3,
+            self::PLATFORM_APP => 4,
+        ];
+    }
+
+    /**
+     * 根据平台获取数字ID
+     */
+    public static function getPlatformId($platform)
+    {
+        return self::getPlatformIdMap()[$platform] ?? 3; // 默认微信小程序
+    }
+}

+ 0 - 2
application/common/Enum/UserShareEnum.php

@@ -25,6 +25,4 @@ class UserShareEnum
     {
         return self::getFromList()[$from] ?? '未知';
     }
-
-    public static function getFromList()
 }

+ 194 - 0
application/common/Service/Share/ShareService.php

@@ -0,0 +1,194 @@
+<?php
+
+namespace app\common\Service\Share;
+
+use think\Model;
+use app\common\model\user\Share as ShareModel;
+use app\common\model\User as UserModel;
+use app\common\model\Goods as GoodsModel;
+use app\common\Enum\ShareEnum;
+use app\common\Enum\PageTypeEnum;
+
+class ShareService
+{
+    /**
+     * 添加分享记录
+     * @param object $user 当前用户对象
+     * @param array $params 分享参数
+     * @return mixed
+     */
+    public static function addShareLog($user, $params)
+    {
+        // 错误的分享参数
+        if (empty($params['spm'])) {
+            return false;
+        }
+
+        // 解析spm参数: shareId.page.query.platform.from
+        $spmParts = explode('.', $params['spm']);
+        if (count($spmParts) < 5) {
+            return false;
+        }
+
+        list($shareId, $pageType, $query, $platform, $from) = $spmParts;
+
+        // 分享用户为空
+        if ($shareId <= 0) {
+            return false;
+        }
+
+        // 不能分享给本人
+        if ($shareId == $user->id) {
+            return false;
+        }
+
+        // 新用户不能分享给老用户 按需打开
+        // if($user->id < $shareId) {
+        //   return false;
+        // }
+
+        $shareUser = UserModel::where('id', $shareId)->find();
+        // 分享人不存在
+        if (!$shareUser) {
+            return false;
+        }
+
+        // 5分钟内相同的分享信息不保存,防止冗余数据
+        $lastShareLog = ShareModel::where([
+            'user_id' => $user->id
+        ])->where('createtime', '>', time() - 300)->order('id desc')->find();
+
+        if ($lastShareLog && $lastShareLog->spm === $params['spm']) {
+            return $lastShareLog;
+        }
+
+        // 根据页面类型构造页面路径和描述
+        $pageInfo = self::getPageInfo($pageType, $query);
+        
+        $memoText = '通过' . ShareEnum::getFromText($params['from']) . '访问了' . $pageInfo['description'];
+
+        $ext = [
+            'image' => $pageInfo['image'] ?? "",
+            'memo' => $memoText
+        ];
+
+        $shareInfo = ShareModel::create([
+            'user_id' => $user->id,
+            'share_id' => $shareId,
+            'spm' => $params['spm'],
+            'page' => $pageInfo['path'],
+            'query' => $query,
+            'platform' => $params['platform'],
+            'from' => $params['from'],
+            'ext' => $ext
+        ]);
+
+        $data = ['shareInfo' => $shareInfo];
+        \think\Hook::listen('user_share_after', $data);
+
+        return $shareInfo;
+    }
+
+    /**
+     * 根据页面类型获取页面信息
+     * @param int $pageType 页面类型
+     * @param string $query 查询参数
+     * @return array
+     */
+    private static function getPageInfo($pageType, $query)
+    {
+        $pageInfo = [
+            'path' => '',
+            'description' => '',
+            'image' => ''
+        ];
+
+        switch ($pageType) {
+            case PageTypeEnum::HOME:
+                $pageInfo['path'] = '/pages/index/index';
+                $pageInfo['description'] = '首页';
+                break;
+                
+            case PageTypeEnum::GOODS:
+                $pageInfo['path'] = '/pages/goods/index';
+                $pageInfo['description'] = '商品';
+                $pageInfo = self::appendGoodsInfo($pageInfo, $query);
+                break;
+                
+            case PageTypeEnum::GROUP_GOODS:
+                $pageInfo['path'] = '/pages/goods/groupon';
+                $pageInfo['description'] = '拼团商品';
+                $pageInfo = self::appendGoodsInfo($pageInfo, $query);
+                break;
+                
+            case PageTypeEnum::SECKILL_GOODS:
+                $pageInfo['path'] = '/pages/goods/seckill';
+                $pageInfo['description'] = '秒杀商品';
+                $pageInfo = self::appendGoodsInfo($pageInfo, $query);
+                break;
+                
+            case PageTypeEnum::INVITE_GROUP:
+                $pageInfo['path'] = '/pages/activity/groupon/detail';
+                $pageInfo['description'] = '拼团活动';
+                break;
+                
+            case PageTypeEnum::AGENT_POSTER:
+                $pageInfo['path'] = '/pages/agent/poster';
+                $pageInfo['description'] = '分销海报页';
+                break;
+                
+            default:
+                $pageInfo['path'] = '/pages/index/index';
+                $pageInfo['description'] = '未知页面';
+                break;
+        }
+
+        return $pageInfo;
+    }
+
+    /**
+     * 为商品页面添加商品信息
+     * @param array $pageInfo 页面信息
+     * @param string $goodsId 商品ID
+     * @return array
+     */
+    private static function appendGoodsInfo($pageInfo, $goodsId)
+    {
+        if (!empty($goodsId)) {
+            $goods = GoodsModel::find($goodsId);
+            if ($goods) {
+                $pageInfo['description'] .= "[{$goods->title}]";
+                $pageInfo['image'] = $goods->image;
+            }
+        }
+
+        return $pageInfo;
+    }
+
+    /**
+     * 解析spm参数
+     * @param string $spm smp参数
+     * @return array|false
+     */
+    public static function parseSpm($spm)
+    {
+        if (empty($spm)) {
+            return false;
+        }
+
+        $spmParts = explode('.', $spm);
+        if (count($spmParts) < 5) {
+            return false;
+        }
+
+        list($shareId, $pageType, $query, $platform, $from) = $spmParts;
+
+        return [
+            'shareId' => intval($shareId),
+            'pageType' => intval($pageType),
+            'query' => $query,
+            'platform' => intval($platform),
+            'from' => intval($from)
+        ];
+    }
+}

+ 123 - 17
application/common/model/user/Share.php

@@ -3,30 +3,136 @@
 namespace app\common\model\user;
 
 use think\Model;
-use traits\model\SoftDelete;
-
+use app\common\Enum\ShareEnum;
+use app\common\model\User as UserModel;
+use app\common\model\Goods as GoodsModel;
 class Share extends Model
-{
-
-    use SoftDelete;
-
-    
+{    
 
     // 表名
     protected $name = 'shop_user_share';
     
-    // 自动写入时间戳字段
-    protected $autoWriteTimestamp = 'integer';
-
-    // 定义时间戳字段名
-    protected $createTime = 'createtime';
-    protected $updateTime = 'updatetime';
-    protected $deleteTime = 'deletetime';
-
-    // 追加属性
+    protected $type = [
+        'ext' => 'json'
+    ];
+    
     protected $append = [
-
+        'platform_text',
+        'from_text'
     ];
+
+    public function getPlatformTextAttr($value, $data)
+    {
+        $value = $value ?: ($data['platform'] ?? null);
+        return ShareEnum::getPlatformText($value);
+    }
+
+    public function getFromTextAttr($value, $data)
+    {
+        $value = $value ?: ($data['from'] ?? null);
+        return ShareEnum::getFromText($value);
+    }
+
+    public static function log(Object $user, $params)
+    {
+
+        // 错误的分享参数
+        if (empty($params['spm'])) {
+            return false;
+        }
+
+        $shareId = $params['shareId'];
+        // 分享用户为空
+        if ($shareId <= 0) {
+            return false;
+        }
+
+        // 不能分享给本人
+        if ($shareId == $user->id) {
+            return false;
+        }
+
+        // 新用户不能分享给老用户 按需打开
+        // if($user->id < $shareId) {
+        //   return false;
+        // }
+
+        $shareUser = UserModel::where('id', $shareId)->find();
+        // 分享人不存在
+        if (!$shareUser) {
+            return false;
+        }
+
+        // 5分钟内相同的分享信息不保存,防止冗余数据
+        $lastShareLog = self::where([
+            'user_id' => $user->id
+        ])->where('createtime', '>', time() - 300)->order('id desc')->find();
+
+        if ($lastShareLog && $lastShareLog->spm === $params['spm']) {
+            return $lastShareLog;
+        }
+
+        $memoText = '通过' . ShareEnum::getFromText($params['from']) . '访问了';
+        if ($params['page'] == '/pages/index/index') {
+            $memoText .= '首页';
+        }
+        if ($params['page'] === '/pages/goods/index') {
+            $memoText .= '商品';
+            $goodsId = $params['query']['id'];
+        }
+        if ($params['page'] === '/pages/goods/groupon') {
+            $memoText .= '拼团商品';
+            $goodsId = $params['query']['id'];
+        }
+        if ($params['page'] === '/pages/goods/seckill') {
+            $memoText .= '秒杀商品';
+            $goodsId = $params['query']['id'];
+        }
+        if ($params['page'] === '/pages/activity/groupon/detail') {
+            $memoText .= '拼团活动';
+        }
+
+        if (!empty($goodsId)) {
+            $goods = GoodsModel::find($goodsId);
+            if ($goods) {
+                $memoText .= "[{$goods->title}]";
+            }
+        }
+
+        $ext = [
+            'image' => $goods->image ?? "",
+            'memo' => $memoText
+        ];
+
+        $shareInfo = self::create([
+            'user_id' => $user->id,
+            'share_id' => $shareId,
+            'spm' => $params['spm'],
+            'page' => $params['page'],
+            'query' => http_build_query($params['query']),
+            'platform' => $params['platform'],
+            'from' => $params['from'],
+            'ext' => $ext
+        ]);
+
+        $data = ['shareInfo' => $shareInfo];
+        \think\Hook::listen('user_share_after', $data);
+
+        return $shareInfo;
+    }
+
+
+    // -- commission code start --
+    public function agent()
+    {
+        return $this->belongsTo(\app\common\model\commission\Agent::class, 'share_id', 'user_id');
+    }
+    // -- commission code end --
+
+    public function user()
+    {
+        return $this->belongsTo(UserModel::class, 'user_id', 'id');
+    }