1224 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
			
		
		
	
	
			1224 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
| <?php
 | ||
| 
 | ||
| namespace app\controller\api;
 | ||
| 
 | ||
| use app\exception\ApiRedirectException;
 | ||
| use app\exception\RepositoryException;
 | ||
| use app\exception\TraitException;
 | ||
| use app\model\Account;
 | ||
| use app\model\AccountCoupon;
 | ||
| use app\model\AccountDataLog;
 | ||
| use app\model\AccountRecord;
 | ||
| use app\model\AccountWithdrawalCommission;
 | ||
| use app\model\Message;
 | ||
| use app\repository\AccountRepository;
 | ||
| use app\repository\ArchivesRepository;
 | ||
| use app\repository\OrderRepository;
 | ||
| use app\repository\SpuRepository;
 | ||
| use app\service\File;
 | ||
| use app\service\Jwt;
 | ||
| use app\service\Math;
 | ||
| use app\service\wx\WechatApplets;
 | ||
| use app\validate\User as UserValidate;
 | ||
| use EasyWeChat\Kernel\Exceptions\InvalidConfigException;
 | ||
| use Endroid\QrCode\Builder\Builder;
 | ||
| use Endroid\QrCode\Encoding\Encoding;
 | ||
| use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelHigh;
 | ||
| use Endroid\QrCode\RoundBlockSizeMode\RoundBlockSizeModeMargin;
 | ||
| use Endroid\QrCode\Writer\PngWriter;
 | ||
| use Exception;
 | ||
| use Intervention\Image\Image;
 | ||
| use Intervention\Image\ImageManagerStatic;
 | ||
| use think\db\exception\DataNotFoundException;
 | ||
| use think\db\exception\DbException;
 | ||
| use think\db\exception\ModelNotFoundException;
 | ||
| use think\facade\Config as CConfig;
 | ||
| use think\facade\Db;
 | ||
| use think\facade\Log;
 | ||
| use think\response\Json;
 | ||
| 
 | ||
| class User extends Base
 | ||
| {
 | ||
|     protected $noNeedLogin = [
 | ||
|         'login',
 | ||
|         'tempLogin',
 | ||
|         'feedbackTypes',
 | ||
|         'shareUsers',
 | ||
|         'homeCoupon',
 | ||
|         'getCoupon',
 | ||
|         'signByQr',
 | ||
|     ];
 | ||
| 
 | ||
|     public function index(): Json
 | ||
|     {
 | ||
|         $userId = $this->request->user['user_id'] ?? 0;
 | ||
|         return json(['code' => 0, 'msg' => 'Index page , I am '.$userId]);
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 登录  成功返回token及用户信息
 | ||
|      *
 | ||
|      * @return Json
 | ||
|      * @throws InvalidConfigException
 | ||
|      */
 | ||
|     public function login(): Json
 | ||
|     {
 | ||
|         $params = $this->request->param();
 | ||
| 
 | ||
|         Log::error('进入参数');
 | ||
|         Log::error($params);
 | ||
|         Log::error('参数结束');
 | ||
|         $validate = new UserValidate();
 | ||
|         if (!$validate->scene('wx_applets')->check($params)) {
 | ||
|             return $this->json(4000, $validate->getError());
 | ||
|         }
 | ||
|         $minApp = WechatApplets::getInstance();
 | ||
|         $jsCode = $params['code'];
 | ||
|         $wxUser = $minApp->auth->session($jsCode);
 | ||
| 
 | ||
|         if (isset($wxUser['errcode']) && $wxUser['errcode'] != 0) {
 | ||
|             return $this->json(4001, $wxUser['errcode'].';'.$wxUser['errmsg'] ?? '登录失败');
 | ||
|         }
 | ||
|         // $wxUser success has [session_key, openid, unionid]
 | ||
|         // 有效期2小时
 | ||
|         $wxUser['expire_time'] = time() + 7200;
 | ||
|         $wxUser['session_key'] = $wxUser['session_key'] ?? '';
 | ||
|         $openID                = $wxUser['openid'];
 | ||
|         $unionid               = $wxUser['unionid'] ?? '';
 | ||
| 
 | ||
|         if (empty($openID) && empty($unionid)) {
 | ||
|             return $this->json(4002, '登录失败');
 | ||
|         }
 | ||
|         $isActive    = $params['is_active'] ?? 0;
 | ||
|         $isActive    = (is_numeric($isActive) && $isActive > 0) ? AccountRepository::BOOL_TRUE : AccountRepository::BOOL_FALSE;
 | ||
|         $phoneActive = $params['phone_active'] ?? 0;
 | ||
|         $phoneActive = (is_numeric($phoneActive) && $phoneActive > 0) ? AccountRepository::BOOL_TRUE : AccountRepository::BOOL_FALSE;
 | ||
| 
 | ||
|         try {
 | ||
|             $repo    = AccountRepository::getInstance();
 | ||
|             $account = $repo->findByOpenID($openID);
 | ||
|             if (!$account && !empty($unionid)) {
 | ||
|                 $account = $repo->findByUnionId($unionid);
 | ||
|             }
 | ||
|             $inviteCode = $params['invite_code'] ?? '';
 | ||
| 
 | ||
|             $now = date('Y-m-d H:i:s');
 | ||
|             if (!$account) {
 | ||
| 
 | ||
|                 if(empty($params['nickname'])||empty($params['headimgurl'] )){
 | ||
|                     return $this->json(4002, '登录失败');
 | ||
|                 }
 | ||
|                 // 自动注册
 | ||
|                 $inviterAid       = 0;
 | ||
|                 $inviterParentAid = 0;
 | ||
|                 $inviter          = null;
 | ||
| 
 | ||
|                 // 存在邀请人
 | ||
|                 if (!empty($inviteCode)) {
 | ||
|                     $inviter = $repo->findByInviteCode($inviteCode);
 | ||
|                     if ($inviter) {
 | ||
|                         $inviterAid       = $inviter['id'];
 | ||
|                         $inviterParentAid = $inviter['inviter_account_id'];
 | ||
|                     }
 | ||
|                 }
 | ||
| 
 | ||
|                 $account = $repo->create([
 | ||
|                     'unionid'            => $unionid ?? '',
 | ||
|                     'openid'             => $openID,
 | ||
|                     'last_login'         => $now,
 | ||
|                     'login_ip'           => $this->request->ip(),
 | ||
|                     'created_at'         => $now,
 | ||
|                     'nickname'           => $params['nickname'] ?? '',
 | ||
|                     'headimgurl'         => $params['headimgurl'] ?? '',
 | ||
|                     'country'            => $params['country'] ?? '',
 | ||
|                     'province'           => $params['province'] ?? '',
 | ||
|                     'city'               => $params['city'] ?? '',
 | ||
|                     'county'             => $params['county'] ?? '',
 | ||
|                     'gender'             => $params['gender'] ?? 0,
 | ||
|                     'language'           => $params['language'] ?? 'zh_CN',
 | ||
|                     'mobile'             => $params['mobile'] ?? '',
 | ||
|                     'status'             => AccountRepository::STATUS_NORMAL,
 | ||
|                     'inviter_account_id' => $inviterAid,
 | ||
|                     'inviter_parent_id'  => $inviterParentAid,
 | ||
|                     'is_active'          => $isActive,
 | ||
|                     'phone_active'       => $phoneActive,
 | ||
|                     'session_key'        => $wxUser['session_key'] ?? '',
 | ||
|                 ]);
 | ||
| 
 | ||
|                 $regAccountId = $account->id ?? 0;
 | ||
| 
 | ||
|                 // 存在邀请人
 | ||
|                 if ($inviter) {
 | ||
|                     $repo->addShareRegLog($regAccountId, $inviterAid, $inviterParentAid);
 | ||
|                 }
 | ||
| 
 | ||
|                 AccountRecord::record($regAccountId, AccountRecord::TYPE_OTHER, AccountRecord::ACTION_REGISTER);
 | ||
| 
 | ||
|             } else {
 | ||
|                 $updateData     = [
 | ||
|                     'last_login'  => date('Y-m-d H:i:s'),
 | ||
|                     'login_ip'    => $this->request->ip(),
 | ||
|                     'session_key' => $wxUser['session_key'] ?? '',
 | ||
|                     'language'    => $params['language'] ?? 'zh_CN',
 | ||
|                 ];
 | ||
|                 $phoneActiveOld = $account['phone_active'];
 | ||
| 
 | ||
|                 // 更新资料
 | ||
|                 $modifyStringList = ['headimgurl', 'nickname', 'mobile', 'country', 'province', 'city', 'county'];
 | ||
|                 foreach ($modifyStringList as $modifyKey) {
 | ||
|                     if (isset($account[$modifyKey]) && empty($account[$modifyKey])) {
 | ||
|                         $updateData[$modifyKey] = $params[$modifyKey] ?? '';
 | ||
|                     }
 | ||
|                 }
 | ||
|                 if (empty($account['gender'])) {
 | ||
|                     $updateData['gender'] = $params['gender'] ?? 0;
 | ||
|                 }
 | ||
|                 if (isset($account['is_active']) && $account['is_active'] == AccountRepository::BOOL_FALSE) {
 | ||
|                     $updateData['is_active'] = $isActive;
 | ||
|                 }
 | ||
|                 if (isset($account['phone_active']) && $account['phone_active'] == AccountRepository::BOOL_FALSE) {
 | ||
|                     $updateData['phone_active'] = $phoneActive;
 | ||
|                 }
 | ||
| 
 | ||
|                 $repo->update($updateData, ['id' => $account['id']]);
 | ||
| 
 | ||
|                 $account = $repo->findById($account['id']);
 | ||
| 
 | ||
|                 // 授权手机号后才能算有效激活用户,并更新相关业务数据
 | ||
|                 if ($phoneActiveOld == AccountRepository::BOOL_FALSE && $account['phone_active'] == AccountRepository::BOOL_TRUE) {
 | ||
|                     $repo->activeShareRegLog($account['id']);
 | ||
|                 }
 | ||
|             }
 | ||
|         } catch (RepositoryException | Exception $e) {
 | ||
|             return $this->json(4003, '登录失败!'.$e->getMessage());
 | ||
|         }
 | ||
| 
 | ||
|         $account = $account->toArray();
 | ||
|         $jwtData = [
 | ||
|             'user_id'     => $account['id'],
 | ||
|             'open_id'     => $openID,
 | ||
|             'session_key' => $wxUser['session_key'],
 | ||
|             'expire_time' => $wxUser['expire_time'],
 | ||
|         ];
 | ||
| 
 | ||
|         $account['headimgurl'] = File::convertCompleteFileUrl($account['headimgurl']);
 | ||
|         $fields                = [
 | ||
|             'coding', 'real_name', 'nickname', 'headimgurl', 'gender', 'mobile',
 | ||
|             'province', 'city', 'county', 'country', 'birthday',
 | ||
|             'score', 'status', 'position', 'invite_code', 'is_active', 'phone_active'
 | ||
|         ];
 | ||
| 
 | ||
|         $accountData = arrayKeysFilter($account, $fields);
 | ||
|         $data        = [
 | ||
|             'account_id' => $account['id'],
 | ||
|             'token'      => Jwt::generate($jwtData),
 | ||
|             'expire'     => $wxUser['expire_time'],
 | ||
|             'openid'     => $openID,
 | ||
|         ];
 | ||
|         $data        = array_merge($data, $accountData);
 | ||
| 
 | ||
|         return $this->json(0, 'success', $data);
 | ||
|     }
 | ||
| 
 | ||
| 
 | ||
|     /**
 | ||
|      * 获取用户信息
 | ||
|      *
 | ||
|      * @return Json
 | ||
|      */
 | ||
|     public function info(): Json
 | ||
|     {
 | ||
|         try {
 | ||
|             $accountId = $this->request->user['user_id'] ?? 0;
 | ||
| 
 | ||
|             $fields = [
 | ||
|                 'id', 'coding', 'real_name', 'nickname', 'headimgurl', 'mobile',
 | ||
|                 //                'province', 'city', 'county', 'country', 'birthday', 'gender'
 | ||
|                 'score', 'status', 'invite_code', 'channel',
 | ||
|                 'is_active', "continuity_sign", "last_sign_online", 'phone_active','address','contacts'
 | ||
|             ];
 | ||
|             $repo   = AccountRepository::getInstance();
 | ||
|             $user   = $repo->findById($accountId, $fields);
 | ||
| 
 | ||
| 
 | ||
|             if (empty($user)) {
 | ||
|                 return $this->json(4004, '没有相关的用户记录');
 | ||
|             }
 | ||
| 
 | ||
|             $user->headimgurl = File::convertCompleteFileUrl($user->headimgurl ?? '');
 | ||
| 
 | ||
|             /**
 | ||
|              * 补充信息:
 | ||
|              * 文章收藏量、分享注册用户量(包含2级)
 | ||
|              */
 | ||
| //            $user->collects        = $repo->countRecordByAction(AccountRecord::TYPE_CONTENT, AccountRecord::ACTION_COLLECT, $accountId);
 | ||
| //            $user->share_users     = $repo->shareAccountCount($accountId);
 | ||
| //            $user->unread_messages = $repo->countUnReadMessage($accountId);
 | ||
| 
 | ||
|             $user = $user->toArray();
 | ||
|             $user = arrayNullToString($user);
 | ||
| 
 | ||
|             $user['order_count'] = OrderRepository::getInstance()->orderCount($accountId);
 | ||
| 
 | ||
|             return $this->json(0, 'success', $user);
 | ||
| 
 | ||
|         } catch (Exception $e) {
 | ||
|             return $this->json(4000, '没有相关的用户记录'.$e->getMessage());
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 首页优惠券
 | ||
|      *
 | ||
|      * @return Json
 | ||
|      * @throws DataNotFoundException
 | ||
|      * @throws DbException
 | ||
|      * @throws ModelNotFoundException
 | ||
|      */
 | ||
|     public function homeCoupon(): Json
 | ||
|     {
 | ||
|         $accountId = $this->request->user['user_id'] ?? 0;
 | ||
| 
 | ||
|         //是否有可领取的推荐优惠券(进入首页时弹出)
 | ||
|         $homeCoupon          = AccountCoupon::homeCoupon($accountId);
 | ||
|         $data['has_coupon']  = (int) !empty($homeCoupon);
 | ||
|         $data['home_coupon'] = $homeCoupon;
 | ||
|         return $this->json(0, 'success', $data);
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 修改用户资料
 | ||
|      * 修改内容范围:姓名、昵称、联系电话、性别、地址(省、市、区/县)
 | ||
|      * array $params 键值对形式
 | ||
|      */
 | ||
|     public function editInfo(): Json
 | ||
|     {
 | ||
|         if (!$this->request->isPost()) {
 | ||
|             return $this->json(4000, '无效请求');
 | ||
|         }
 | ||
| 
 | ||
|         $params   = $this->request->param();
 | ||
|         $validate = new UserValidate();
 | ||
|         if (!$validate->scene('edit')->check($params)) {
 | ||
|             return $this->json(4001, $validate->getError());
 | ||
|         }
 | ||
| 
 | ||
|         $accountId = $this->request->user['user_id'] ?? 0;
 | ||
|         try {
 | ||
|             AccountRepository::getInstance()->accountEditInfo($accountId, $params);
 | ||
|         } catch (RepositoryException $e) {
 | ||
|             return $this->json(4002, $e->getMessage());
 | ||
|         } catch (Exception $e) {
 | ||
|             return $this->json(5000, '资料修改失败');
 | ||
|         }
 | ||
|         return $this->json();
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 临时登录  通过openid登录 仅用于接口测试阶段
 | ||
|      *
 | ||
|      * @return Json
 | ||
|      * @throws DataNotFoundException
 | ||
|      * @throws DbException
 | ||
|      * @throws ModelNotFoundException
 | ||
|      */
 | ||
|     public function tempLogin(): Json
 | ||
|     {
 | ||
|         $params = $this->request->param();
 | ||
| 
 | ||
|         if (!isset($params['openid'])) {
 | ||
|             return $this->json(4001, '参数错误');
 | ||
|         }
 | ||
| 
 | ||
|         if (!$user = AccountRepository::getInstance()->findByOpenID($params['openid'])) {
 | ||
|             return $this->json(4004, '账号不存在');
 | ||
|         }
 | ||
| 
 | ||
|         $data = [
 | ||
|             'token'  => Jwt::generate(['user_id' => $user['id'], 'nickname' => $user['nickname']]),
 | ||
|             'expire' => Jwt::expire()
 | ||
|         ];
 | ||
| 
 | ||
|         return $this->json(0, 'success', $data);
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 个人分享中心
 | ||
|      * 统计:累计积分、累计绑定的客户数量(包含2级分销)
 | ||
|      */
 | ||
|     public function shareCount(): Json
 | ||
|     {
 | ||
|         $accountId = $this->request->user['user_id'] ?? 0;
 | ||
| 
 | ||
|         $res = [
 | ||
|             'score'       => 0,
 | ||
|             'user_count'  => [
 | ||
|                 'first'  => 0,
 | ||
|                 'second' => 0,
 | ||
|                 'total'  => 0,
 | ||
|             ],
 | ||
|             'order_count' => 0,
 | ||
|         ];
 | ||
| 
 | ||
|         try {
 | ||
|             $repo    = AccountRepository::getInstance();
 | ||
|             $account = $repo->findById($accountId);
 | ||
|             if (!empty($account)) {
 | ||
|                 $res['score']      = $account['score'] ?? 0;
 | ||
|                 $res['user_count'] = $repo->shareAccountCount($accountId);
 | ||
| 
 | ||
|             }
 | ||
|         } catch (Exception $e) {
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
|         return $this->json(0, 'success', $res);
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 查看分享绑定用户的信息
 | ||
|      */
 | ||
|     public function shareUsers(): Json
 | ||
|     {
 | ||
|         $accountId = $this->request->user['user_id'] ?? 2;
 | ||
|         $page      = $this->request->param('page/d', 1);
 | ||
|         $size      = $this->request->param('size/d', 10);
 | ||
|         $grade     = $this->request->param('grade/s', 'first'); // 层级[first|second]
 | ||
| 
 | ||
|         $grade = $grade ?: 'first';
 | ||
| 
 | ||
|         if (!in_array($grade, [AccountRepository::SHARE_GRADE_FIRST, AccountRepository::SHARE_GRADE_SECOND])) {
 | ||
|             return $this->json(4001, '层级参数错误');
 | ||
|         }
 | ||
| 
 | ||
|         $page = $page <= 0 ? 1 : $page;
 | ||
|         $size = $size <= 0 ? 10 : $size;
 | ||
| 
 | ||
|         $list = AccountRepository::getInstance()->shareUsers($accountId, $grade, $page, $size);
 | ||
| 
 | ||
|         return $this->json(0, 'success', $list);
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 生成用户个人海报 使用intervention/image库
 | ||
|      */
 | ||
|     public function personalPoster(): Json
 | ||
|     {
 | ||
|         $accountId = $this->request->user['user_id'] ?? 0;
 | ||
|         $bgImg     = $this->request->param('bg_src/s', '');
 | ||
|         $bgImg     = empty($bgImg) ? '' : File::convertCompleteFileUrl($bgImg);
 | ||
| 
 | ||
|         try {
 | ||
|             $account = AccountRepository::getInstance()->findById($accountId);
 | ||
|             if (empty($account)) {
 | ||
|                 return $this->json(4000, '无效请求');
 | ||
|             }
 | ||
| 
 | ||
|             $domain     = $this->request->domain();
 | ||
|             $inviteCode = $account['invite_code'] ?: md5($account['id']);
 | ||
|             $inviteUrl  = $domain.'/share?invite_code='.$inviteCode;
 | ||
|             $logoImg    = app()->getRootPath().'public/static/images/icon-logo.jpg';
 | ||
| 
 | ||
|             $result = Builder::create()
 | ||
|                 ->writer(new PngWriter())
 | ||
|                 ->writerOptions([])
 | ||
|                 ->data($inviteUrl)
 | ||
|                 ->encoding(new Encoding('UTF-8'))
 | ||
|                 ->errorCorrectionLevel(new ErrorCorrectionLevelHigh())
 | ||
|                 ->size(275)
 | ||
|                 ->margin(10)
 | ||
|                 ->roundBlockSizeMode(new RoundBlockSizeModeMargin())
 | ||
|                 ->logoPath($logoImg)
 | ||
|                 ->logoResizeToHeight(100)
 | ||
|                 ->logoResizeToWidth(100)
 | ||
|                 ->logoPunchoutBackground(true)
 | ||
|                 ->build();
 | ||
| 
 | ||
|             $qrBase64 = $result->getDataUri();
 | ||
|             $bgImg    = $bgImg ?: app()->getRootPath().'public/static/images/poster-bg1.png';
 | ||
|             $headimg  = $account['headimgurl'] ?? app()->getRootPath().'public/static/images/icon-logo.jpg';
 | ||
|             $name     = mb_substr($account['nickname'], 0, 4);
 | ||
|             $name     = $name ?: '商城';
 | ||
|             // 圆形头像
 | ||
|             $head   = $this->getCircleImg($headimg, 60, 60);
 | ||
|             $poster = (string) ImageManagerStatic::make($bgImg)
 | ||
|                 ->insert($qrBase64, 'bottom-right', 10, 100)
 | ||
|                 ->insert($head, 'bottom-left', 30, 80)
 | ||
|                 ->text($name.'...邀您关注', 100, 1080, function ($font) {
 | ||
|                     $font->file('./static/bb4171.ttf');
 | ||
|                     $font->size(36);
 | ||
|                     $font->color('#000000');
 | ||
|                     $font->align('left');
 | ||
|                     $font->valign('top');
 | ||
|                 })
 | ||
|                 ->encode('data-url');
 | ||
|             //                ->save('aaa.png');
 | ||
|             return $this->json(0, 'success', ['poster' => $poster]);
 | ||
|         } catch (Exception $e) {
 | ||
|             AccountRepository::log('个人海报生成失败', $e);
 | ||
|             return $this->json(5000, '个人海报生成失败');
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 圆形头像.
 | ||
|      *
 | ||
|      * @see https://github.com/Intervention/image/issues/223
 | ||
|      *
 | ||
|      * @param $img
 | ||
|      * @param  int  $width
 | ||
|      * @param  int  $height
 | ||
|      * @return Image
 | ||
|      */
 | ||
|     protected function getCircleImg($img, int $width, int $height): Image
 | ||
|     {
 | ||
|         $avatar_img = ImageManagerStatic::make($img)->resize($width, $height);
 | ||
|         $r          = $width / 2;
 | ||
|         $temp_image = ImageManagerStatic::canvas(185, 185);
 | ||
| 
 | ||
|         for ($x = 0; $x < $avatar_img->width(); $x++) {
 | ||
|             for ($y = 0; $y < $avatar_img->height(); $y++) {
 | ||
|                 if (((($x - $r) * ($x - $r) + ($y - $r) * ($y - $r)) < ($r * $r))) {
 | ||
|                     $c = $avatar_img->pickColor($x, $y, 'array');
 | ||
|                     $temp_image->pixel($c, $x, $y);
 | ||
|                 }
 | ||
|             }
 | ||
|         }
 | ||
|         return $temp_image;
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 用户操作记录 分享、咨询
 | ||
|      *
 | ||
|      * @return Json
 | ||
|      * @throws Exception
 | ||
|      */
 | ||
|     public function record(): Json
 | ||
|     {
 | ||
|         if (!$this->request->isPost()) {
 | ||
|             return $this->json(4000, '无效请求');
 | ||
|         }
 | ||
| 
 | ||
|         $accountId = $this->request->user['user_id'] ?? 0;
 | ||
|         $params    = input('post.');
 | ||
| 
 | ||
|         $rules = [
 | ||
|             'type|操作类型' => 'require|in:content,other,spu,activity',
 | ||
|             'action|操作' => 'require',
 | ||
|         ];
 | ||
| 
 | ||
|         if (isset($params['type']) && $params['type'] == AccountRecord::TYPE_CONTENT) {
 | ||
|             $rules['id|ID'] = 'require';
 | ||
|         }
 | ||
| 
 | ||
|         $validate = $this->validateByApi($params, $rules, ['type.in' => '类型错误', 'id.require' => '此类型 ID必传']);
 | ||
| 
 | ||
|         if ($validate !== true) {
 | ||
|             return $validate;
 | ||
|         }
 | ||
| 
 | ||
|         try {
 | ||
|             $relationId = $params['id'] ?? 0;
 | ||
|             $relationId = is_numeric($relationId) ? $relationId : 0;
 | ||
|             AccountRecord::record($accountId, $params['type'], $params['action'], $relationId);
 | ||
|         } catch (Exception $e) {
 | ||
|             AccountRepository::log('记录用户操作失败', $e);
 | ||
|             return $this->json(5001, '操作失败');
 | ||
|         }
 | ||
| 
 | ||
|         return $this->json();
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 个人二维码
 | ||
|      */
 | ||
|     public function personalQr(): Json
 | ||
|     {
 | ||
|         $accountId = $this->request->user['user_id'] ?? 0;
 | ||
|         try {
 | ||
|             $account = AccountRepository::getInstance()->findById($accountId);
 | ||
|             if (empty($account)) {
 | ||
|                 return $this->json(4000, '无效请求');
 | ||
|             }
 | ||
| 
 | ||
|             $nonceStr  = uniqid();
 | ||
|             $qrDataStr = json_encode([
 | ||
|                 'user_coding' => $account['coding'],
 | ||
|                 'nonce_str'   => $nonceStr,
 | ||
|             ]);
 | ||
|             $logoImg   = File::convertCompleteFileUrl($account['headimgurl']);
 | ||
|             if (empty($logoImg)) {
 | ||
|                 $logoImg = app()->getRootPath().'public/static/images/icon-logo.jpg';
 | ||
|             }
 | ||
| 
 | ||
|             $result = Builder::create()
 | ||
|                 ->writer(new PngWriter())
 | ||
|                 ->writerOptions([])
 | ||
|                 ->data($qrDataStr)
 | ||
|                 ->encoding(new Encoding('UTF-8'))
 | ||
|                 ->errorCorrectionLevel(new ErrorCorrectionLevelHigh())
 | ||
|                 ->size(300)
 | ||
|                 ->margin(10)
 | ||
|                 ->roundBlockSizeMode(new RoundBlockSizeModeMargin())
 | ||
|                 ->logoPath($logoImg)
 | ||
|                 ->logoResizeToHeight(100)
 | ||
|                 ->logoResizeToWidth(100)
 | ||
|                 ->logoPunchoutBackground(true)
 | ||
|                 ->build();
 | ||
| 
 | ||
|             $dataUri = $result->getDataUri();
 | ||
| 
 | ||
|             return $this->json(0, 'success', ['qr' => $dataUri, 'nonce_str' => $nonceStr]);
 | ||
|         } catch (Exception $e) {
 | ||
|             AccountRepository::log('个人二维码生成失败', $e);
 | ||
|             return $this->json(5000, '个人二维码生成失败');
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 提交反馈意见
 | ||
|      */
 | ||
|     public function addFeedback(): Json
 | ||
|     {
 | ||
|         if (!$this->request->isPost()) {
 | ||
|             return $this->json(4000, '无效请求');
 | ||
|         }
 | ||
| 
 | ||
|         $accountId = $this->request->user['user_id'] ?? 0;
 | ||
|         $params    = [
 | ||
|             'type_id'    => $this->request->param('type_id/d', 0),
 | ||
|             'content'    => postFilter($this->request->param('content/s', '')),
 | ||
|             'user_name'  => postFilter($this->request->param('user_name/s', '')),
 | ||
|             'user_phone' => postFilter($this->request->param('user_phone/s', '')),
 | ||
|         ];
 | ||
| 
 | ||
|         try {
 | ||
|             AccountRepository::getInstance()->addFeedback($accountId, $params);
 | ||
|         } catch (TraitException $e) {
 | ||
|             return $this->json(4001, $e->getMessage());
 | ||
|         }
 | ||
| 
 | ||
|         return $this->json(0, '您已提交成功,感谢您的反馈!');
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 用户消息
 | ||
|      */
 | ||
|     public function messages(): Json
 | ||
|     {
 | ||
|         $accountId = $this->request->user['user_id'] ?? 0;
 | ||
|         $page      = $this->request->param('page/d', 1);
 | ||
|         $size      = $this->request->param('size/d', 10);
 | ||
|         $type      = $this->request->param('type/s', '');
 | ||
| 
 | ||
|         $page = $page <= 0 ? 1 : $page;
 | ||
|         $size = $size <= 0 ? 10 : $size;
 | ||
| 
 | ||
|         $repo     = AccountRepository::getInstance();
 | ||
|         $whereMap = [];
 | ||
|         $fields   = [
 | ||
|             'id', 'type', 'target', 'title', 'summary', 'content', 'status',
 | ||
|             'sort', 'created_at', 'send_at'
 | ||
|         ];
 | ||
|         $orders   = ['sort' => 'desc', 'id' => 'desc'];
 | ||
|         $regTime  = '';
 | ||
|         $account  = $repo->findById($accountId);
 | ||
|         if ($account) {
 | ||
|             $regTime = $account['created_at'] ?? '';
 | ||
|         }
 | ||
| 
 | ||
|         if ($type) {
 | ||
|             if ($type == 'message') {
 | ||
|                 $whereMap[] = ['type', 'in', [Message::TYPE_NOTICE, Message::TYPE_SYSTEM]];
 | ||
|             } else {
 | ||
|                 $whereMap[] = ['type', '=', $type];
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         $resp = $repo->messageList($whereMap, $fields, $page, $size, function ($q) use ($accountId, $regTime) {
 | ||
|             return $q->whereTime('send_at', '<=', date('Y-m-d H:i:s'))
 | ||
|                 ->when(!empty($regTime), function ($q3) use ($regTime) {
 | ||
|                     $q3->whereTime('send_at', '>=', $regTime);
 | ||
|                 })
 | ||
|                 ->where(function ($q3) use ($accountId) {
 | ||
|                     $q3->whereRaw('(target = "part" and find_in_set("'.$accountId.'", target_list)) or target <> "part"');
 | ||
|                 });
 | ||
|         }, $orders);
 | ||
| 
 | ||
|         $msgIds          = $resp['list']->column('id');
 | ||
|         $hadReadMsgIds   = $repo->getHadReadMessageIds($accountId, $msgIds);
 | ||
|         $msgTypeTextList = $repo->messageTypeTextList();
 | ||
|         foreach ($resp['list'] as $item) {
 | ||
|             $item['type_text'] = $msgTypeTextList[$item['type']] ?? '';
 | ||
|             $item['is_read']   = in_array($item['id'], $hadReadMsgIds) ? AccountRepository::BOOL_TRUE : AccountRepository::BOOL_FALSE;
 | ||
|         }
 | ||
| 
 | ||
|         // todo 获取列表后更新阅览日志记录
 | ||
|         $repo->addReadLogs($accountId, $msgIds);
 | ||
| 
 | ||
|         return $this->json(0, 'success', $resp);
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 查看消息详情
 | ||
|      * 添加阅览日志记录
 | ||
|      */
 | ||
|     public function messageInfo(): Json
 | ||
|     {
 | ||
|         $accountId = $this->request->user['user_id'] ?? 0;
 | ||
|         $msgId     = $this->request->param('message_id/d', 0);
 | ||
| 
 | ||
|         $repo    = AccountRepository::getInstance();
 | ||
|         $fields  = [
 | ||
|             'id', 'type', 'target', 'title', 'summary', 'content', 'target_list',
 | ||
|             'status', 'sort', 'created_at', 'send_at'
 | ||
|         ];
 | ||
|         $message = $repo->messageInfo($msgId, $fields);
 | ||
|         if (empty($message)) {
 | ||
|             return $this->json(4004, '没有相关的消息记录');
 | ||
|         }
 | ||
| 
 | ||
|         if ($message['target'] == Message::TARGET_PART) {
 | ||
|             $targetList = empty($message['target_list']) ? [] : explode(',', $message['target_list']);
 | ||
|             if (!in_array($accountId, $targetList)) {
 | ||
|                 return $this->json(4001, '没有查看权限');
 | ||
|             }
 | ||
|         } elseif (!empty($message['send_at']) && strtotime($message['send_at']) > time()) {
 | ||
|             return $this->json(4001, '没有查看权限');
 | ||
|         }
 | ||
| 
 | ||
|         $repo->addReadLogs($accountId, [$msgId]);
 | ||
| 
 | ||
|         $msgTypeTextList      = $repo->messageTypeTextList();
 | ||
|         $message['type_text'] = $msgTypeTextList[$message['type']] ?? '';
 | ||
|         $message['is_read']   = AccountRepository::BOOL_TRUE;
 | ||
|         unset($message['target_list']);
 | ||
| 
 | ||
|         return $this->json(0, 'success', $message);
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 客户列表
 | ||
|      *
 | ||
|      * @return Json
 | ||
|      * @throws Exception
 | ||
|      */
 | ||
|     public function customer(): Json
 | ||
|     {
 | ||
|         $accountId = $this->request->user['user_id'] ?? 0;
 | ||
|         $type      = input('type/s', 'all');
 | ||
|         $keyword   = input('keyword/s', '');
 | ||
|         $page      = input('page/d', 1);
 | ||
|         $size      = input('size/d', 20);
 | ||
| 
 | ||
|         try {
 | ||
|             if ($accountId == 0) {
 | ||
|                 return $this->json(6001, '请先登录');
 | ||
|             }
 | ||
| 
 | ||
|             $where = [];
 | ||
|             if ($type !== 'all') {
 | ||
|                 $where[] = ['channel', '=', $type];
 | ||
|             }
 | ||
| 
 | ||
|             if (!empty($keyword)) {
 | ||
|                 $where[] = ['nickname|real_name|mobile', 'like', '%'.$keyword.'%'];
 | ||
|             }
 | ||
|             $where[]      = ['phone_active', '=', Account::COMMON_ON];
 | ||
|             $field        = ['id', 'nickname', 'real_name', 'headimgurl', 'mobile', 'channel', 'created_at', 'customer_service', 'coin_total'];
 | ||
|             $data         = AccountRepository::getInstance()->getAndHandleAccountList($where, $field, $page, $size);
 | ||
|             $data['list'] = $data['list']->each(function ($item) {
 | ||
|                 $item->real_name = $item->real_name ?? '';
 | ||
|                 unset($item->tags);
 | ||
|             });
 | ||
|             return $this->json(0, 'success', $data);
 | ||
|         } catch (RepositoryException $e) {
 | ||
|             return $this->json(4001, $e->getMessage());
 | ||
|         } catch (Exception $e) {
 | ||
|             ArchivesRepository::log($e->getMessage(), $e);
 | ||
|             return $this->json(5000, '操作失败');
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 绑定手机
 | ||
|      *
 | ||
|      * @return bool|Json
 | ||
|      * @throws Exception
 | ||
|      */
 | ||
|     public function bindPhone()
 | ||
|     {
 | ||
|         if (!$this->request->isPost()) {
 | ||
|             return $this->json(4000, '无效请求');
 | ||
|         }
 | ||
| 
 | ||
|         $accountId = $this->request->user['user_id'] ?? 0;
 | ||
|         $params    = input('post.');
 | ||
| 
 | ||
|         $rules = [
 | ||
|             'encryptedData|加密数据' => 'require',
 | ||
|             'iv|IV'              => 'require',
 | ||
|         ];
 | ||
| 
 | ||
|         $validate = $this->validateByApi($params, $rules);
 | ||
| 
 | ||
|         if ($validate !== true) {
 | ||
|             return $validate;
 | ||
|         }
 | ||
| 
 | ||
|         try {
 | ||
|             if (!$account = Account::findById($accountId)) {
 | ||
|                 return $this->json(4000, '用户不存在');
 | ||
|             }
 | ||
| 
 | ||
|             $oldPhoneActive = $account['phone_active'];
 | ||
|             // 解密手机相关数据  若存在手机则覆盖
 | ||
|             $minApp      = WechatApplets::getInstance();
 | ||
|             $sessionKey  = $this->request->user['session_key'] ?? '';
 | ||
|             $decryptData = $minApp->encryptor->decryptData($sessionKey, $params['iv'], $params['encryptedData']);
 | ||
|             $phone       = $decryptData['phoneNumber'] ?? ''; // 通过iv和加密数据 解密出手机号
 | ||
| 
 | ||
|             if (Account::where('id', '<>', $accountId)->where('mobile', $phone)->count() > 0) {
 | ||
|                 return $this->json(4000, '该手机已被绑定,若有绑定错误,请联系客服');
 | ||
|             }
 | ||
| 
 | ||
|             if ($phone) {
 | ||
|                 $account->save(['mobile' => $phone, 'phone_active' => Account::COMMON_ON]);
 | ||
|             }
 | ||
| 
 | ||
|             if ($oldPhoneActive == Account::COMMON_OFF) {
 | ||
|                 AccountRepository::getInstance()->activeShareRegLog($account['id']);
 | ||
|             }
 | ||
| 
 | ||
|             return $this->json(0, 'success', ['phone' => $phone]);
 | ||
|         } catch (Exception $e) {
 | ||
|             AccountRepository::log('手机绑定失败', $e);
 | ||
|             return $this->json(5001, '手机绑定失败');
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 领取优惠券
 | ||
|      *
 | ||
|      * @return Json
 | ||
|      * @throws Exception
 | ||
|      */
 | ||
|     public function getCoupon(): Json
 | ||
|     {
 | ||
|         $accountId = $this->request->user['user_id'] ?? 0;
 | ||
|         $couponID  = input('coupon_id/d', 0);
 | ||
| 
 | ||
|         try {
 | ||
|             AccountRepository::getInstance()->getCoupon($accountId, $couponID);
 | ||
|             return $this->json();
 | ||
|         } catch (ApiRedirectException $e) {
 | ||
|             return $this->json(302, $e->getMessage());
 | ||
|         } catch (RepositoryException $e) {
 | ||
|             return $this->json(4000, $e->getMessage());
 | ||
|         } catch (Exception $e) {
 | ||
|             AccountRepository::log('领取优惠券失败', $e);
 | ||
|             return $this->json(5001, '领取优惠券失败');
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 展示体验券 生成token
 | ||
|      *
 | ||
|      * @return Json
 | ||
|      * @throws Exception
 | ||
|      */
 | ||
|     public function exhibitionExperienceCoupon(): Json
 | ||
|     {
 | ||
|         $accountId = $this->request->user['user_id'] ?? 0;
 | ||
|         $couponID  = input('coupon_id/d', 0);
 | ||
|         try {
 | ||
|             $coupon = AccountRepository::getInstance()->userCouponInfo($accountId, $couponID);
 | ||
|             $time   = time();
 | ||
|             //不存在
 | ||
|             if (empty($coupon) || !isset($coupon['coupon'])) {
 | ||
|                 return $this->json(4002, "优惠券不存在");
 | ||
|             }
 | ||
|             //状态异常
 | ||
|             if ($coupon['status'] != AccountCoupon::STATUS_NORMAL) {
 | ||
|                 return $this->json(4002, "优惠券状态已经不能使用");
 | ||
|             }
 | ||
|             //未开始
 | ||
|             if (strtotime($coupon['coupon']["begin_at"]) > $time) {
 | ||
|                 return $this->json(4002, "优惠券还未到开始使用时间");
 | ||
|             }
 | ||
|             //过期
 | ||
| 
 | ||
|             if (strtotime($coupon['coupon']["end_at"]) < $time) {
 | ||
|                 return $this->json(4002, "优惠券已过期");
 | ||
|             }
 | ||
| 
 | ||
|             if ($coupon['is_taste'] != AccountCoupon::COMMON_ON) {
 | ||
|                 return $this->json(4002, "优惠券不是体验券");
 | ||
|             }
 | ||
| 
 | ||
|             $secret = AccountRepository::getInstance()->createExperienceCouponQR($accountId, $couponID);
 | ||
| 
 | ||
|             $url = ($this->request->domain()."/api/staff/coupon/write-off-experience-coupon?account_id=$accountId&&coupon_id=$couponID&&secret=$secret");
 | ||
| 
 | ||
|             return $this->json(0, "success", ["url" => $url, "secret" => $secret]);
 | ||
|         } catch (ApiRedirectException $e) {
 | ||
|             return $this->json(302, $e->getMessage());
 | ||
|         } catch (RepositoryException $e) {
 | ||
|             return $this->json(4000, $e->getMessage());
 | ||
|         } catch (Exception $e) {
 | ||
|             AccountRepository::log('获取优惠券失败', $e);
 | ||
|             return $this->json(5001, '获取优惠券失败');
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 获取优惠券列表
 | ||
|      *
 | ||
|      * @return Json
 | ||
|      * @throws Exception
 | ||
|      */
 | ||
|     public function getCouponList(): Json
 | ||
|     {
 | ||
|         $accountId = $this->request->user['user_id'] ?? 0;
 | ||
|         $status    = input('status/s', AccountCoupon::STATUS_NORMAL);
 | ||
|         $page      = input('page/d', 1);
 | ||
|         $size      = input('size/d', 0);
 | ||
| 
 | ||
|         try {
 | ||
|             $data = AccountRepository::getInstance()->couponList($status, $accountId, $page, $size);
 | ||
|             return $this->json(0, 'success', $data);
 | ||
|         } catch (Exception $e) {
 | ||
|             AccountRepository::log('获取优惠券列表失败', $e);
 | ||
|             return $this->json(5001, '获取优惠券列表失败');
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 获取地址列表
 | ||
|      *
 | ||
|      * @return Json
 | ||
|      * @throws DataNotFoundException
 | ||
|      * @throws DbException
 | ||
|      * @throws ModelNotFoundException
 | ||
|      */
 | ||
|     public function address(): Json
 | ||
|     {
 | ||
|         $userId = $this->request->user['user_id'] ?? 0;
 | ||
|         $list   = AccountRepository::getInstance()->findAddressByUid($userId);
 | ||
| 
 | ||
|         return $this->json(0, 'success', $list);
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 保存地址
 | ||
|      *
 | ||
|      * @return Json
 | ||
|      */
 | ||
|     public function addressSave(): Json
 | ||
|     {
 | ||
|         $userId            = $this->request->user['user_id'] ?? 0;
 | ||
|         $params            = $this->request->param();
 | ||
|         $validate          = new UserValidate();
 | ||
|         $params['user_id'] = $userId;
 | ||
| 
 | ||
|         if (!$validate->scene('address')->check($params)) {
 | ||
|             return $this->json(4000, $validate->getError());
 | ||
|         }
 | ||
| 
 | ||
|         AccountRepository::getInstance()->saveAddress($params);
 | ||
| 
 | ||
|         return $this->json();
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 地址详情
 | ||
|      *
 | ||
|      * @return Json
 | ||
|      * @throws DataNotFoundException
 | ||
|      * @throws DbException
 | ||
|      * @throws ModelNotFoundException
 | ||
|      */
 | ||
|     public function addressInfo(): Json
 | ||
|     {
 | ||
|         if (!$id = input('id/d', 0)) {
 | ||
|             return $this->json(4000, '参数错误');
 | ||
|         }
 | ||
| 
 | ||
|         $info = AccountRepository::getInstance()->findAddressById($id);
 | ||
| 
 | ||
|         return $this->json(0, 'success', $info);
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 地址删除
 | ||
|      *
 | ||
|      * @return Json
 | ||
|      */
 | ||
|     public function addressDel(): Json
 | ||
|     {
 | ||
|         if (!$id = input('id/d', 0)) {
 | ||
|             return $this->json(4000, '参数错误');
 | ||
|         }
 | ||
| 
 | ||
|         AccountRepository::getInstance()->delAddress($id);
 | ||
| 
 | ||
|         return $this->json();
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 积分收支记录
 | ||
|      *
 | ||
|      * @return Json
 | ||
|      * @throws Exception
 | ||
|      */
 | ||
|     public function scoreLog(): Json
 | ||
|     {
 | ||
|         $page      = input('page/d', 1);
 | ||
|         $limit     = input('size/d', 10);
 | ||
|         $type      = input("type/s", "in"); //in=收入 out=支出  默认in
 | ||
|         $accountId = $this->request->user['user_id'] ?? 0;
 | ||
| 
 | ||
|         $where   = [];
 | ||
|         $where[] = ["account_id", "=", $accountId];
 | ||
|         $where[] = ["type", "=", AccountDataLog::TYPE_SCORE];
 | ||
|         if ($type == 'in') {
 | ||
|             $where[] = ["num", ">", 0];
 | ||
|         }
 | ||
|         if ($type == 'out') {
 | ||
|             $where[] = ["num", "<", 0];
 | ||
|         }
 | ||
|         $items = AccountDataLog::findList($where, [], $page, $limit, null, ['id' => 'desc']);
 | ||
| 
 | ||
|         return $this->json(0, '操作成功', $items);
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 我的订单
 | ||
|      *
 | ||
|      * @return Json
 | ||
|      * @throws RepositoryException
 | ||
|      */
 | ||
|     public function order(): Json
 | ||
|     {
 | ||
|         $userId = $this->request->user['user_id'] ?? 0;
 | ||
|         $page   = $this->request->param('page/d', 1);
 | ||
|         $size   = $this->request->param('size/d', 20);
 | ||
|         $tag    = $this->request->param('tag/s', 'all');
 | ||
|         $domain = $this->request->domain();
 | ||
| 
 | ||
|         $res         = OrderRepository::getInstance()->mine($userId, $tag, $page, $size);
 | ||
|         $orderStatusTextList  = OrderRepository::getInstance()->orderStatusTextList();
 | ||
|         $res['list'] = $res['list']->each(function ($item) use ($domain,$orderStatusTextList) {
 | ||
|             $item->skus->each(function ($sku) use ($domain,$orderStatusTextList) {
 | ||
|                 if (!$sku->spec_text) {
 | ||
|                     $sku->spec_text = [];
 | ||
|                     $sku->spec_info = [];
 | ||
|                 } else {
 | ||
|                     $specArr = json_decode($sku->spec_text, true);
 | ||
|                     $sku->spec_text = $specArr;
 | ||
|                     $sku->spec_info = SpuRepository::getInstance()->convertSpecInfo($specArr);
 | ||
|                 }
 | ||
|                 $sku->spu_cover     = resourceJoin($sku->spu_cover, $domain);
 | ||
|                 $sku->sku_cover     = resourceJoin($sku->sku_cover, $domain);
 | ||
| 
 | ||
|             });
 | ||
|             $item->status_text   = $orderStatusTextList[$item["status"]];
 | ||
|         });
 | ||
|         return $this->json(0, 'success', $res);
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 立即免拼  需要单人开团允许
 | ||
|      *
 | ||
|      * @return Json
 | ||
|      */
 | ||
|     public function openOne(): Json
 | ||
|     {
 | ||
|         $userId = $this->request->user['user_id'] ?? 0;
 | ||
|         $coding = input('order_coding/s');
 | ||
| 
 | ||
|         try {
 | ||
|             if (empty($coding)) {
 | ||
|                 return $this->json(4001, '参数错误');
 | ||
|             }
 | ||
|             OrderRepository::getInstance()->openOne($userId, $coding);
 | ||
|             return $this->json();
 | ||
|         } catch (RepositoryException $e) {
 | ||
|             return $this->json(4000, $e->getMessage());
 | ||
|         } catch (Exception $e) {
 | ||
|             AccountRepository::log('立即免拼失败', $e);
 | ||
|             return $this->json(5001, '立即免拼失败');
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 订单详情
 | ||
|      *
 | ||
|      * @return Json
 | ||
|      * @throws RepositoryException
 | ||
|      */
 | ||
|     public function orderDetail(): Json
 | ||
|     {
 | ||
|         $id     = input('id/d', 0);
 | ||
|         $userId = $this->request->user['user_id'] ?? 0;
 | ||
|         $domain = $this->request->domain();
 | ||
| 
 | ||
|         $res = OrderRepository::getInstance()->detail($id);
 | ||
|         $res["status_text"] = OrderRepository::getInstance()->orderStatusTextList()[$res["status"]];
 | ||
|         $res->skus->each(function ($sku) use ($domain) {
 | ||
|             $specArr = json_decode($sku->spec_text, true);
 | ||
|             $sku->spec_text = $specArr;
 | ||
|             $sku->spec_info = SpuRepository::getInstance()->convertSpecInfo($specArr);
 | ||
| 
 | ||
|             if (!empty($sku->spu_cover) && !isHttpUrl($sku->spu_cover)) {
 | ||
|                 $sku->spu_cover = $domain.$sku->spu_cover;
 | ||
|             }
 | ||
| 
 | ||
|             if (!empty($sku->sku_cover) && !isHttpUrl($sku->sku_cover)) {
 | ||
|                 $sku->sku_cover = $domain.$sku->sku_cover;
 | ||
|             }
 | ||
|         });
 | ||
|         if (!$res) {
 | ||
|             return $this->json(4000, '订单不存在');
 | ||
|         }
 | ||
| 
 | ||
|         if ($res['account_id'] !== $userId) {
 | ||
|             return $this->json(4000, '不是您的订单');
 | ||
|         }
 | ||
| 
 | ||
|         return $this->json(0, 'success', $res);
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 发起提现【佣金】
 | ||
|      *
 | ||
|      * @return Json
 | ||
|      * @throws DataNotFoundException
 | ||
|      * @throws DbException
 | ||
|      * @throws ModelNotFoundException
 | ||
|      */
 | ||
|     public function commissionWithdrawal(): Json
 | ||
|     {
 | ||
|         $commission = input("commission/f", 0);//单位元
 | ||
|         $wechat     = input("wechat/s");//微信号
 | ||
|         $accountId  = $this->request->user['user_id'];
 | ||
|         $account    = Account::findById($accountId, [], function ($q) {
 | ||
|             return $q->lock(true);
 | ||
|         });
 | ||
| 
 | ||
|         if (empty($commission) || empty($wechat)) {
 | ||
|             return $this->json(4001, '参数错误');
 | ||
|         }
 | ||
| 
 | ||
|         if (empty($account)) {
 | ||
|             return $this->json(6001, '未登录');
 | ||
|         }
 | ||
| 
 | ||
|         CConfig::load('extra/commission_withdrawal', 'commission');
 | ||
|         // 提现最低限制
 | ||
|         $config     = config('commission');
 | ||
|         $limitCount = $config['limit_withdraw_commission'] ?? 0;
 | ||
| 
 | ||
|         if ($commission < $limitCount) {
 | ||
|             return $this->json(4000, '提现佣金不能小于'.$limitCount);
 | ||
|         }
 | ||
| 
 | ||
|         //换算出 1元 = 多少佣金
 | ||
|         try {
 | ||
|             //本次提现共计金额
 | ||
|             $totalMoney = AccountWithdrawalCommission::convertCommissionOrMoney($commission * 100, 'money');
 | ||
|             $totalMoney = $totalMoney / 100;//分转元
 | ||
|             if ($account['commission'] < $commission) {
 | ||
|                 return $this->json(4004, '佣金不足');
 | ||
|             }
 | ||
|         } catch (RepositoryException $e) {
 | ||
|             return $this->json(4000, $e->getMessage());
 | ||
|         } catch (Exception $e) {
 | ||
|             Log::error('发起提现失败 MSG:'.$e->getMessage().' Line:'.$e->getLine().' File:'.$e->getFile());
 | ||
|             return $this->json(5000, '提现失败');
 | ||
|         }
 | ||
| 
 | ||
|         //条件满足  开始写入提现
 | ||
|         Db::startTrans();
 | ||
|         try {
 | ||
|             //写入日志
 | ||
|             AccountDataLog::log($account['id'],
 | ||
|                 "提现-扣除佣金",
 | ||
|                 $commission * -1,
 | ||
|                 AccountDataLog::TYPE_COMMISSION,
 | ||
|                 AccountDataLog::ACTION_WITHDRAWAL,
 | ||
|                 Math::sub($account[AccountDataLog::TYPE_COMMISSION], $commission)
 | ||
|             );
 | ||
| 
 | ||
|             $rate = $config['withdrawal_proportion'] ?? [];
 | ||
|             //写入提现记录
 | ||
|             $insert = [
 | ||
|                 "account_id" => $account['id'],
 | ||
|                 "number"     => $commission,
 | ||
|                 "role"       => '',
 | ||
|                 "money"      => $totalMoney,
 | ||
|                 "proportion" => $rate['commission'].":".$rate['money'],
 | ||
|                 "status"     => AccountWithdrawalCommission::$status_default,
 | ||
|                 "created_at" => date("Y-m-d H:i:s"),
 | ||
|                 "remarks"    => '微信号:'.$wechat
 | ||
|             ];
 | ||
|             AccountWithdrawalCommission::create($insert);
 | ||
| 
 | ||
|             //扣除佣金
 | ||
|             $account->save(["commission" => Db::raw('`commission` - '.$commission)]);
 | ||
|             Db::commit();
 | ||
|             return $this->json();
 | ||
|         } catch (Exception $e) {
 | ||
|             Db::rollback();
 | ||
|             Log::error('发起提现失败 MSG:'.$e->getMessage().' Line:'.$e->getLine().' File:'.$e->getFile());
 | ||
|             return $this->json(5000, "发起提现失败");
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 佣金详情
 | ||
|      *
 | ||
|      * @return Json
 | ||
|      * @throws RepositoryException
 | ||
|      */
 | ||
|     public function commission(): Json
 | ||
|     {
 | ||
|         $page   = input('page/d', 1);
 | ||
|         $size   = input('size/d', 10);
 | ||
|         $userId = $this->request->user['user_id'] ?? 0;
 | ||
|         $repo   = AccountRepository::getInstance();
 | ||
| 
 | ||
|         if (!$account = $repo->findById($userId, ['id', 'commission'])) {
 | ||
|             return $this->json(6001, '请先登录');
 | ||
|         }
 | ||
| 
 | ||
|         $data = [
 | ||
|             'commission'        => $account['commission'],
 | ||
|             'invite_count'      => $repo->getInviteCount($userId),
 | ||
|             'commission_total'  => $repo->getCommissionTotal($userId),//累计佣金 元
 | ||
|             'withdrawal_total'  => $repo->getCommissionWithdrawalTotal($userId),//累计提现 元
 | ||
|             'withdrawing_total' => $repo->getCommissionWithdrawalIngTotal($userId),//提现中 元
 | ||
|             'log'               => $repo->getCommissionLog($userId, $page, $size)
 | ||
|         ];
 | ||
| 
 | ||
|         return $this->json(0, 'success', $data);
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 获取佣金兑换金额 单位元
 | ||
|      *
 | ||
|      * @throws RepositoryException
 | ||
|      */
 | ||
|     public function commission2money(): Json
 | ||
|     {
 | ||
|         $num = input('num/f', 0); //元
 | ||
|         CConfig::load('extra/commission_withdrawal', 'commission_withdrawal');
 | ||
|         $config       = config('commission_withdrawal')['withdrawal_proportion'] ?? [];
 | ||
|         $res['money'] = Math::fen2Yuan(AccountWithdrawalCommission::convertCommissionOrMoney($num * 100, 'money'));
 | ||
| 
 | ||
|         $res['rate']['commission'] = $config['commission'] ?? '比例未设置';
 | ||
|         $res['rate']['money']      = $config['money'] ?? '比例未设置';
 | ||
|         return $this->json(0, 'success', $res);
 | ||
|     }
 | ||
| }
 |